Skip to content

Instantly share code, notes, and snippets.

@chrert
Created October 18, 2012 17:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrert/ae6ebe58a286d6cfd847 to your computer and use it in GitHub Desktop.
Save chrert/ae6ebe58a286d6cfd847 to your computer and use it in GitHub Desktop.
simple dc
#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