like c n C++

emma.k
An_Expression_Interpreter.pdf

An Expression Interpreter

Module 3: Impera!ve Languages—Control Flow

An Expression Interpreter

The case study for this module incorporates two of

the language features that we discussed—

expressions and assignments. The program

interprets fully parenthesized arithme!c

expressions that contain either literal values or

variables. The variables must then subsequently be

assigned values.

The grammar for the language that this interpreter

accepts is defined by the following grammar:

<program> → <exp> , <assigns> ; <exp> → ( <operand> <op> <operand> ) <operand> → <literal> | <variable> | <exp> <assigns> → <assigns> , <assign> | <assign> <assign> → <variable> = <literal> The regular expressions defining the three tokens

are the following:

<op> [+-*/] <variable> [a-zA-Z][a-zA-Z0-9]* <literal> [0-9]+ So, if you were to enter the following expression:

(x + (y * 3)), x = 2, y = 6; the interpreter would respond:

Value = 20 The interpreter itself is wri"en in C++. The

complete program consists of 10 classes. We will

present 7 of them. Your instructor may ask you to

complete this program, perhaps enhance it, and add

some error checking as one of the programming

projects.

We begin with the main func!on and one

subordinate func!on, which are contained in

module3.cpp. The main func!on reads in the

program, calls upon the sta!c func!on parse of the

SubExpression class to parse it, and builds an

arithme!c expression tree. It then calls the

subordinate func!on parseAssignments to parse

the assignments and enter them into the symbol

table, and then evaluates the expression and

displays the result. That code is shown below:

#include <iostream> #include <string> #include <vector> using namespace std;

#include "expression.h" #include "subexpression.h" #include "symboltable.h"

#include "parse.h"

SymbolTable symbolTable;

void parseAssignments();

int main() { Expression* expression; char paren, comma; cout << "Enter expression: "; cin >> paren; expression = SubExpression::parse(); cin >> comma; parseAssignments(); cout << "Value = " << expression->evaluate() << endl; return 0; }

void parseAssignments() {

char assignop, delimiter; string variable; double value; do { variable = parseName(); cin >> ws >> assignop >> value >> delimiter; symbolTable.insert(variable, value); } while (delimiter == ','); } The arithme!c expression tree is built using an

inheritance hierarchy. At the root of the hierarchy

is the abstract class Expression. The class defini!on

for Expression is contained in the file expression.h,

shown below:

class Expression { public:

virtual double evaluate() = 0; }; This abstract class has two subclasses. The first of

these is SubExpression, which defines the node of

the binary arithme!c expression tree. The class

defini!on for SubExpression is contained in the file

subexpression.h, shown below:

class SubExpression: public Expression { public: SubExpression(Expression* left, Expression* right); static Expression* parse(); protected: Expression* left; Expression* right; }; As is customary in C++, the bodies of the member

func!ons of that class are contained in the file

subexpression.cpp, shown below:

#include <iostream>

using namespace std;

#include "expression.h" #include "subexpression.h" #include "operand.h" #include "plus.h" #include "minus.h" #include "times.h" #include "divide.h"

SubExpression::SubExpression(Expres sion* left, Expression* right) { this->left = left; this->right = right; }

Expression* SubExpression::parse() { Expression* left; Expression* right; char operation, paren;

left = Operand::parse(); cin >> operation; right = Operand::parse(); cin >> paren; switch (operation) { case '+': return new Plus(left, right); case '-': return new Minus(left, right); case '*': return new Times(left, right); case '/': return new Divide(left, right); } return 0; } The SubExpression class has four subclasses. We

show one of them—Plus. The class defini!on for

Plus is contained in the file plus.h, shown below:

class Plus: public SubExpression { public: Plus(Expression* left, Expression* right): SubExpression(left, right) { } double evaluate() { return left->evaluate() + right->evaluate(); } }; Because the bodies of both member func!ons are

inline, no corresponding .cpp file is required.

The other subclass of Expression is Operand, which

defines the leaf nodes of the arithme!c expression

tree. The class defini!on for Operand is contained

in the file operand.h, shown below:

class Operand: public Expression { public: static Expression* parse(); }; The body of its only member func!on is contained

in operand.cpp, shown below:

#include <cctype> #include <iostream> #include <list> #include <string>

using namespace std;

#include "expression.h" #include "subexpression.h" #include "operand.h" #include "variable.h" #include "literal.h" #include "parse.h"

Expression* Operand::parse()

{ char paren; double value;

cin >> ws; if (isdigit(cin.peek())) { cin >> value; Expression* literal = new Literal(value); return literal; } if (cin.peek() == '(') { cin >> paren; return SubExpression::parse(); } else return new Variable(parseName()); return 0; }

The Operand class has two subclasses. The first is

Variable, which defines leaf nodes of the tree that

contain variables. The class defini!on for Variable is

contained in the file variable.h, shown below:

class Variable: public Operand { public: Variable(string name) { this->name = name; } double Variable::evaluate(); private: string name; }; The body of its member func!on evaluate is

contained in variable.cpp, shown below:

#include <strstream> #include <vector> using namespace std;

#include "expression.h"

#include "operand.h" #include "variable.h" #include "symboltable.h"

extern SymbolTable symbolTable;

double Variable::evaluate() { return symbolTable.lookUp(name); } The other subclass of Operand is Literal, which

defines leaf nodes of the tree that contain literal

values. The class defini!on for Literal is contained

in the file literal.h, shown below:

class Literal: public Operand { public: Literal(int value) { this->value = value; }

double evaluate() { return value; } private: int value; }; This interpreter uses a symbol table that is

implemented with an unsorted list defined by the

class SymbolTable. Its class defini!on is contained

in the file symboltable.h, shown below:

class SymbolTable { public: SymbolTable() {} void insert(string variable, double value); double lookUp(string variable) const; private: struct Symbol {

Symbol(string variable, double value) { this->variable = variable; this->value = value; } string variable; double value; }; vector <Symbol> elements; }; The bodies of its member func!ons are in the file

symboltable.cpp, shown below:

#include <string> #include <vector> using namespace std;

#include "symboltable.h"

void SymbolTable::insert(string

variable, double value) { const Symbol& symbol = Symbol(variable, value); elements.push_back(symbol); }

double SymbolTable::lookUp(string variable) const { for (int i = 0; i < elements.size(); i++) if (elements[i].variable == variable) return elements[i].value; return -1; } Finally, one u!lity func!on, parseName, is needed

by this program. Its func!on prototype is the file

parse.h, shown below:

string parseName();

Its body is in parse.cpp, shown below:

#include <cctype> #include <iostream> #include <string> using namespace std;

#include "parse.h"

string parseName() { char alnum; string name = "";

cin >> ws; while (isalnum(cin.peek())) { cin >> alnum; name += alnum; } return name; }