-
-
Save chrert/ae6ebe58a286d6cfd847 to your computer and use it in GitHub Desktop.
simple dc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <iomanip> | |
#include <string> | |
#include <sstream> | |
#include <vector> | |
#include <stdexcept> | |
#include <cmath> | |
typedef long double Operand; | |
typedef std::vector<Operand> OperandStack; | |
//------------------------------------------------------------------------------ | |
// OPERATORS | |
//------------------------------------------------------------------------------ | |
class NotEnoughOperands : public std::logic_error | |
{ | |
public: | |
NotEnoughOperands(const std::string& name, unsigned int need, | |
unsigned int got) : std::logic_error("") | |
{ | |
std::stringstream ss; | |
ss << name << " needs " << need << " operands, but got only " << got; | |
static_cast<std::logic_error&>(*this) = std::logic_error(ss.str()); | |
} | |
}; | |
class Operator | |
{ | |
private: | |
std::string _name; | |
protected: | |
OperandStack& _operand_stack; | |
public: | |
short opcode; | |
Operator(const std::string& name, OperandStack& stack) | |
: _name(name), _operand_stack(stack) | |
{} | |
virtual bool execute() = 0; | |
const std::string& name() const | |
{ | |
return _name; | |
} | |
virtual ~Operator() | |
{} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorClearStack : public Operator | |
{ | |
public: | |
OperatorClearStack(const std::string& name, OperandStack& stack) | |
: Operator(name, stack) | |
{} | |
virtual bool execute() | |
{ | |
_operand_stack.clear(); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorPrint : public Operator | |
{ | |
protected: | |
std::ostream& _stream; | |
public: | |
OperatorPrint(const std::string& name, OperandStack& stack, | |
std::ostream& stream) | |
: Operator(name, stack), _stream(stream) | |
{} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorPrintTop : public OperatorPrint | |
{ | |
public: | |
OperatorPrintTop(const std::string& name, OperandStack& stack, | |
std::ostream& stream) | |
: OperatorPrint(name, stack, stream) | |
{} | |
virtual bool execute() | |
{ | |
if (! _operand_stack.empty()) | |
{ | |
Operand op = _operand_stack.back(); | |
_stream << op << std::endl; | |
return true; | |
} | |
else | |
{ | |
throw (NotEnoughOperands(name(), 1, _operand_stack.size())); | |
} | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorPrintTopPop : public OperatorPrint | |
{ | |
public: | |
OperatorPrintTopPop(const std::string& name, OperandStack& stack, | |
std::ostream& stream) | |
: OperatorPrint(name, stack, stream) | |
{} | |
virtual bool execute() | |
{ | |
if (! _operand_stack.empty()) | |
{ | |
Operand op = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_stream << op << std::endl; | |
return true; | |
} | |
else | |
{ | |
throw (NotEnoughOperands(name(), 1, _operand_stack.size())); | |
} | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorPrintStack : public OperatorPrint | |
{ | |
public: | |
OperatorPrintStack(const std::string&name, OperandStack& stack, | |
std::ostream& stream) | |
: OperatorPrint(name, stack, stream) | |
{} | |
virtual bool execute() | |
{ | |
OperandStack::const_iterator it; | |
for (it = _operand_stack.begin(); it != _operand_stack.end(); it++) | |
_stream << *it << " "; | |
_stream << std::endl; | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorAdd : public Operator | |
{ | |
public: | |
OperatorAdd(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 2) | |
throw (NotEnoughOperands(name(), 2, _operand_stack.size())); | |
Operand op1 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
Operand op2 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(op1 + op2); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorSub : public Operator | |
{ | |
public: | |
OperatorSub(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 2) | |
throw (NotEnoughOperands(name(), 2, _operand_stack.size())); | |
Operand op1 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
Operand op2 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(op2 - op1); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorMul : public Operator | |
{ | |
public: | |
OperatorMul(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 2) | |
throw (NotEnoughOperands(name(), 2, _operand_stack.size())); | |
Operand op1 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
Operand op2 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(op1 * op2); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorDiv : public Operator | |
{ | |
public: | |
OperatorDiv(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 2) | |
throw (NotEnoughOperands(name(), 2, _operand_stack.size())); | |
Operand op1 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
Operand op2 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(op2 / op1); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorSqrt : public Operator | |
{ | |
public: | |
OperatorSqrt(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 1) | |
throw (NotEnoughOperands(name(), 1, _operand_stack.size())); | |
Operand op = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(sqrt(op)); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorPow : public Operator | |
{ | |
public: | |
OperatorPow(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 2) | |
throw (NotEnoughOperands(name(), 2, _operand_stack.size())); | |
Operand op1 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
Operand op2 = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(pow(op1, op2)); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
class OperatorNeg : public Operator | |
{ | |
public: | |
OperatorNeg(const std::string& name, OperandStack& stack) : Operator(name, stack) | |
{} | |
virtual bool execute() throw (NotEnoughOperands) | |
{ | |
if (_operand_stack.size() < 1) | |
throw (NotEnoughOperands(name(), 1, _operand_stack.size())); | |
Operand op = _operand_stack.back(); | |
_operand_stack.pop_back(); | |
_operand_stack.push_back(- op); | |
return true; | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
// INTERPRETER / TOKEN | |
//------------------------------------------------------------------------------ | |
class Token | |
{ | |
public: | |
enum Type | |
{ | |
OPERATOR, | |
OPERAND | |
}; | |
Token(Type type, double value, short opcode = -1) | |
: type(type), value(value), opcode(opcode) | |
{} | |
Type type; | |
Operand value; | |
short opcode; | |
}; | |
class UnknownOperator : public std::logic_error | |
{ | |
public: | |
UnknownOperator(short opcode) : std::logic_error("") | |
{ | |
std::stringstream ss; | |
ss << "Unknow Operator with opcode " << opcode; | |
static_cast<std::logic_error&>(*this) = std::logic_error(ss.str()); | |
} | |
UnknownOperator(const std::string& name) : | |
std::logic_error("Unknown operator with name " + name) | |
{} | |
}; | |
typedef std::vector<Token*> TokenVector; | |
class Interpreter | |
{ | |
typedef std::vector<Operator*> OperatorVector; | |
private: | |
OperatorVector _registered_operators; | |
public: | |
OperandStack operand_stack; | |
bool execute(TokenVector::iterator tkBegin, TokenVector::iterator tkEnd) | |
throw (UnknownOperator, NotEnoughOperands) | |
{ | |
Operator* op; | |
for (; tkBegin != tkEnd; tkBegin++) | |
{ | |
switch ((*tkBegin)->type) | |
{ | |
case Token::OPERATOR: | |
op = getOperator((*tkBegin)->opcode); | |
op->execute(); | |
break; | |
case Token::OPERAND: | |
operand_stack.push_back((*tkBegin)->value); | |
break; | |
} | |
} | |
return true; | |
} | |
void registerOperator(Operator* op) | |
{ | |
_registered_operators.push_back(op); | |
short new_opcode = _registered_operators.size() - 1; | |
op->opcode = new_opcode; | |
} | |
Operator* getOperator(short opcode) const throw (UnknownOperator) | |
{ | |
try | |
{ | |
return _registered_operators.at(opcode); | |
} | |
catch (std::out_of_range& ex) | |
{ | |
UnknownOperator ex(opcode); | |
throw (ex); | |
} | |
} | |
Operator* getOperator(const std::string& name) const throw (UnknownOperator) | |
{ | |
OperatorVector::const_iterator it; | |
for (it = _registered_operators.begin(); it != _registered_operators.end(); it++) | |
{ | |
if ((*it)->name().compare(name) == 0) | |
return *it; | |
} | |
throw UnknownOperator(name); | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
// MAIN-PROGRAM | |
//------------------------------------------------------------------------------ | |
int main(int argc, char* argv[]) | |
{ | |
// print additional features | |
std::cout << "ADDITIONAL FEATURES:" << std::endl; | |
std::cout << "There's a prompt for doing more thand one command. EOF stops the prompt" << std::endl; | |
std::cout << "Print top of stack with \"p\"" << std::endl; | |
std::cout << "Print top of stack and pop it with \"n\"" << std::endl; | |
std::cout << "Print current stack with \"stack\"" << std::endl; | |
std::cout << "Clear current stack with \"clear\"" << std::endl << std::endl; | |
Interpreter interpreter; | |
Operator* add = new OperatorAdd("add", interpreter.operand_stack); | |
interpreter.registerOperator(add); | |
Operator* sub = new OperatorSub("sub", interpreter.operand_stack); | |
interpreter.registerOperator(sub); | |
Operator* mul = new OperatorMul("mul", interpreter.operand_stack); | |
interpreter.registerOperator(mul); | |
Operator* div = new OperatorDiv("div", interpreter.operand_stack); | |
interpreter.registerOperator(div); | |
Operator* pow = new OperatorPow("pow", interpreter.operand_stack); | |
interpreter.registerOperator(pow); | |
Operator* sqrt = new OperatorSqrt("sqrt", interpreter.operand_stack); | |
interpreter.registerOperator(sqrt); | |
Operator* neg = new OperatorNeg("neg", interpreter.operand_stack); | |
interpreter.registerOperator(neg); | |
Operator* printTop = new OperatorPrintTop("p", interpreter.operand_stack, | |
std::cout); | |
interpreter.registerOperator(printTop); | |
Operator* printTopPop = new OperatorPrintTopPop("n", interpreter.operand_stack, | |
std::cout); | |
interpreter.registerOperator(printTopPop); | |
Operator* printStack = new OperatorPrintStack("stack", interpreter.operand_stack, | |
std::cout); | |
interpreter.registerOperator(printStack); | |
Operator* clearStack = new OperatorClearStack("clear", interpreter.operand_stack); | |
interpreter.registerOperator(clearStack); | |
TokenVector tokens; | |
while (! std::cin.eof()) | |
{ | |
std::stringstream ss; | |
std::string cmd; | |
Operand operand; | |
Token* token; | |
try | |
{ | |
std::getline(std::cin, cmd, '\n'); | |
ss << cmd; | |
while (! ss.eof() && ! std::cin.eof()) | |
{ | |
std::string op; | |
if (ss >> operand) | |
token = new Token(Token::OPERAND, operand); | |
else | |
{ | |
ss.clear(); | |
ss >> op; | |
token = new Token(Token::OPERATOR, -1, interpreter.getOperator(op)->opcode); | |
} | |
tokens.push_back(token); | |
} | |
interpreter.execute(tokens.begin(), tokens.end()); | |
std::cout << std::setprecision(10); | |
/* | |
if (! interpreter.operand_stack.empty()) | |
{ | |
OperandStack::const_iterator it; | |
for (it = interpreter.operand_stack.begin(); | |
it != interpreter.operand_stack.end(); it++) | |
std::cout << *it << " "; | |
std::cout << std::endl; | |
} | |
*/ | |
} | |
catch (std::logic_error& ex) | |
{ | |
std::cerr << "Error: " << ex.what() << std::endl; | |
} | |
while (! tokens.empty()) | |
{ | |
delete tokens.back(); | |
tokens.pop_back(); | |
} | |
} | |
delete add; | |
delete sub; | |
delete mul; | |
delete div; | |
delete pow; | |
delete sqrt; | |
delete neg; | |
delete printTop; | |
delete printTopPop; | |
delete printStack; | |
delete clearStack; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment