/* * This file defines several classes which represent parts of an expression. * It is not unusual in C++ to put several closely-related classes into a * single file. */ #ifndef _EXPRESSION_PARTS_H_ #define _EXPRESSION_PARTS_H_ /* * Expression evaluator program. This program reads expressions of integers, * the operators +, -, *, /, % and parens, and evaluates them obeying the usual * operator precedence and paren grouping. */ #include #include using std::string; #include #include using std::shared_ptr; using std::make_shared; class expr_stack; /* * Exceptions for expression errors. */ class bad_expression: public std::runtime_error { public: bad_expression(string msg): std::runtime_error(msg) { } }; /* * Base class for items on the expression stack. The reference to * std::enable_shared_from_this does what it says: it allows the methods of * the class to make shared_ptr objects from their this pointer * by calling the standard method shared_from_this. */ class Expression_Part: public std::enable_shared_from_this { public: // What kind of thing this is. virtual bool is_operator() { return false; } virtual bool is_operand() { return false; } virtual bool is_left() { return false; } virtual bool is_right() { return false; } // Action to take when each type of item is read from input. virtual void action(expr_stack &) = 0; // How to print this this thing. virtual void print(std::ostream &s) const = 0; }; // Top-level printer. std::ostream & operator<<(std::ostream &strm, const Expression_Part &p); /* * Operands -- integers on the stack. */ class Operand: public Expression_Part { public: // Construct and extract. Operand(int i) { m_value = i; } int val() { return m_value; } // Action for reading an integer. virtual void action(expr_stack &s); // Print it. virtual void print(std::ostream &s) const { s << m_value; } // Identify its type. virtual bool is_operand() { return true; } private: // Value of the operand. int m_value; }; /* * This is +, -, *, / or %. */ class Operator: public Expression_Part { public: // Construct and abstract. Operator(int p) { m_precedence = p; } int prec() { return m_precedence; } // Identify. virtual bool is_operator() { return true; } // Combine two operands according to whatever I am. This // just does whatever arithmetic is appropriate. virtual shared_ptr operate(shared_ptr a, shared_ptr b) = 0; // What to do with a new one. virtual void action(expr_stack &s); // Print the operator. virtual void print(std::ostream&s) const { s << "op[" << m_precedence << "]"; } private: // Precedence of the operator -- how strongly it sticks to the // surrounding operands. int m_precedence; }; /* * Each of the operators, with the appropriate operate method. */ class Oper_Plus: public Operator { public: Oper_Plus(): Operator(1) { } virtual shared_ptr operate(shared_ptr a, shared_ptr b) { return make_shared(a->val() + b->val()); } }; class Oper_Minus: public Operator { public: Oper_Minus(): Operator(1) { } virtual shared_ptr operate(shared_ptr a, shared_ptr b) { return make_shared(a->val() - b->val()); } }; class Oper_Times: public Operator { public: Oper_Times(): Operator(2) { } virtual shared_ptr operate(shared_ptr a, shared_ptr b) { return make_shared(a->val() * b->val()); } }; class Oper_Div: public Operator { public: Oper_Div(): Operator(2) { } virtual shared_ptr operate(shared_ptr a, shared_ptr b) { return make_shared(a->val() / b->val()); } }; class Oper_Mod: public Operator { public: Oper_Mod(): Operator(2) { } virtual shared_ptr operate(shared_ptr a, shared_ptr b) { return make_shared(a->val() % b->val()); } }; /* * Left paren. */ class Left: public Expression_Part { public: virtual bool is_left() { return true; } virtual void print(std::ostream&s) const { s << '('; } virtual void action(expr_stack &s); }; /* Right paren. */ class Right: public Expression_Part { public: virtual bool is_right() { return true; } virtual void print(std::ostream&s) const { s << ')'; } virtual void action(expr_stack &s); }; #endif