/*
* 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 <iostream>
#include <string>
using std::string;
#include <stdexcept>
#include <memory>
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<Operand> objects from their this pointer
* by calling the standard method shared_from_this.
*/
class Expression_Part: public std::enable_shared_from_this<Expression_Part>
{
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<Operand> operate(shared_ptr<Operand> a,
shared_ptr<Operand> 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<Operand> operate(shared_ptr<Operand> a,
shared_ptr<Operand> b) {
return make_shared<Operand>(a->val() + b->val());
}
};
class Oper_Minus: public Operator
{
public:
Oper_Minus(): Operator(1) { }
virtual shared_ptr<Operand> operate(shared_ptr<Operand> a,
shared_ptr<Operand> b) {
return make_shared<Operand>(a->val() - b->val());
}
};
class Oper_Times: public Operator
{
public:
Oper_Times(): Operator(2) { }
virtual shared_ptr<Operand> operate(shared_ptr<Operand> a,
shared_ptr<Operand> b) {
return make_shared<Operand>(a->val() * b->val());
}
};
class Oper_Div: public Operator
{
public:
Oper_Div(): Operator(2) { }
virtual shared_ptr<Operand> operate(shared_ptr<Operand> a,
shared_ptr<Operand> b) {
return make_shared<Operand>(a->val() / b->val());
}
};
class Oper_Mod: public Operator
{
public:
Oper_Mod(): Operator(2) { }
virtual shared_ptr<Operand> operate(shared_ptr<Operand> a,
shared_ptr<Operand> b) {
return make_shared<Operand>(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