From affe74088563507a3616cbcde5a836778a7ffeaa Mon Sep 17 00:00:00 2001 From: Jakub Vojvoda Date: Fri, 23 Sep 2016 00:04:37 +0200 Subject: [PATCH] add Interpreter pattern --- interpreter/Interpreter.cpp | 115 ++++++++++++++++++++++++++++++++++++ interpreter/README.md | 10 ++++ 2 files changed, 125 insertions(+) create mode 100644 interpreter/Interpreter.cpp create mode 100644 interpreter/README.md diff --git a/interpreter/Interpreter.cpp b/interpreter/Interpreter.cpp new file mode 100644 index 0000000..fc58a86 --- /dev/null +++ b/interpreter/Interpreter.cpp @@ -0,0 +1,115 @@ +/* + * C++ Design Patterns: Interpreter + * Author: Jakub Vojvoda [github.com/JakubVojvoda] + * 2016 + * + * Source code is licensed under MIT License + * (for more details see LICENSE) + * + */ + +#include +#include + +/* + * Context + * contains information that's global to the interpreter + */ +class Context { +public: + void set(std::string var, bool value) { + vars.insert(std::pair(var, value)); + } + + bool get(std::string exp) { + return vars[exp]; + } + // ... + +private: + std::map vars; + // ... +}; + +/* + * Abstract Expression + * declares an abstract Interpret operation that is common to all nodes + * in the abstract syntax tree + */ +class AbstractExpression { +public: + virtual ~AbstractExpression() {} + virtual bool interpret(Context *) { + return false; + } + // ... +}; + +/* + * Terminal Expression + * implements an Interpret operation associated with terminal symbols + * in the grammar (an instance is required for every terminal symbol + * in a sentence) + */ +class TerminalExpression : public AbstractExpression { +public: + TerminalExpression(std::string val) + : value(val) {} + + ~TerminalExpression() {} + + bool interpret(Context *context) { + return context->get(value); + } + // ... + +private: + std::string value; + // ... +}; + +/* + * Nonterminal Expression + * implements an Interpret operation for nonterminal symbols + * in the grammar (one such class is required for every rule in the grammar) + */ +class NonterminalExpression : public AbstractExpression { +public: + NonterminalExpression(AbstractExpression *left, AbstractExpression *right) + : lop(left), rop(right) {} + + ~NonterminalExpression() { + delete lop; + delete rop; + } + + bool interpret(Context *context) { + return lop->interpret(context) && rop->interpret(context); + } + // ... + +private: + AbstractExpression *lop; + AbstractExpression *rop; + // ... +}; + + +int main() +{ + // An example of very simple expression tree + // that corresponds to expression (A AND B) + AbstractExpression *A = new TerminalExpression("A"); + AbstractExpression *B = new TerminalExpression("B"); + AbstractExpression *exp = new NonterminalExpression(A, B); + + Context context; + context.set("A", true); + context.set("B", false); + + std::cout << context.get("A") << " AND " << context.get("B"); + std::cout << " = " << exp->interpret(&context) << std::endl; + + delete exp; + return 0; +} diff --git a/interpreter/README.md b/interpreter/README.md new file mode 100644 index 0000000..2b875ae --- /dev/null +++ b/interpreter/README.md @@ -0,0 +1,10 @@ +## Interpreter + +Given a language, the pattern defines a represention for its grammar along with an +interpreter that uses the representation to interpret sentences in the language. +The Interpreter pattern has behavioral purpose and applies to the classes. + +### When to use + +* when the grammar is simple (in case of complex grammars, there are better alternatives) +* efficiency is not a critical concern \ No newline at end of file