Interpreter - shoonie/StudyingDesignPattern GitHub Wiki
Given a language, define a represention for its grammar along with an interpreter that uses the representation to interpret sentence in the language.
- It's easy to change and extend the grammar
- Implementing the grammar is easy, too
- Complex grammars are hard to maintain.
- Adding new ways to interpret expressions.
- Creating the abstract syntax tree.
- Defining the Interpret operation.
- Sharing terminal symbols with the Flyweight pattern.
//https://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns/Behavioral_Patterns
#include <iostream>
#include <string>
#include <map>
#include <list>
namespace wikibooks_design_patterns
{
// based on the Java sample around here
using String = std::string;
class Expression;
using Map = std::map<String, Expression*>;
using Stack = std::list<Expression*>;
class Expression {
public:
virtual int interpret(Map variables) = 0;
virtual ~Expression() {}
};
class Number : public Expression {
private:
int number;
public:
Number(int number) { this->number = number; }
int interpret(Map variables) { return number; }
};
class Plus : public Expression {
Expression* leftOperand;
Expression* rightOperand;
public:
Plus(Expression* left, Expression* right) {
leftOperand = left;
rightOperand = right;
}
~Plus() {
delete leftOperand;
delete rightOperand;
}
int interpret(Map variables) {
return leftOperand->interpret(variables) + rightOperand->interpret(variables);
}
};
class Minus : public Expression {
Expression* leftOperand;
Expression* rightOperand;
public:
Minus(Expression* left, Expression* right) {
leftOperand = left;
rightOperand = right;
}
~Minus() {
delete leftOperand;
delete rightOperand;
}
int interpret(Map variables) {
return leftOperand->interpret(variables) - rightOperand->interpret(variables);
}
};
class Variable : public Expression {
String name;
public:
Variable(String name) { this->name = name; }
int interpret(Map variables) {
if (variables.end() == variables.find(name))
return 0;
return variables[name]->interpret(variables);
}
};
// While the interpreter pattern does not address parsing, a parser is provided for completeness.
class Evaluator : public Expression {
Expression* syntaxTree;
public:
Evaluator(String expression) {
Stack expressionStack;
size_t last = 0;
for (size_t next = 0; String::npos != last; last = (String::npos == next) ? next : (1 + next)) {
next = expression.find(' ', last);
String token(expression.substr(last, (String::npos == next) ? (expression.length() - last) : (next - last)));
if (token == "+") {
Expression* right = expressionStack.back(); expressionStack.pop_back();
Expression* left = expressionStack.back(); expressionStack.pop_back();
Expression* subExpression = new Plus(right, left);
expressionStack.push_back(subExpression);
}
else if (token == "-") {
// it's necessary remove first the right operand from the stack
Expression* right = expressionStack.back(); expressionStack.pop_back();
// ..and after the left one
Expression* left = expressionStack.back(); expressionStack.pop_back();
Expression* subExpression = new Minus(left, right);
expressionStack.push_back(subExpression);
}
else
expressionStack.push_back(new Variable(token));
}
syntaxTree = expressionStack.back(); expressionStack.pop_back();
}
~Evaluator() {
delete syntaxTree;
}
int interpret(Map context) {
return syntaxTree->interpret(context);
}
};
}
void main()
{
using namespace wikibooks_design_patterns;
Evaluator sentence("w x z - +");
static
const int sequences[][3] = {
{ 5, 10, 42 },{ 1, 3, 2 },{ 7, 9, -5 },
};
for (size_t i = 0; sizeof(sequences) / sizeof(sequences[0]) > i; ++i) {
Map variables;
variables["w"] = new Number(sequences[i][0]);
variables["x"] = new Number(sequences[i][1]);
variables["z"] = new Number(sequences[i][2]);
int result = sentence.interpret(variables);
for (Map::iterator it = variables.begin(); variables.end() != it; ++it)
delete it->second;
std::cout << "Interpreter result: " << result << std::endl;
}
}