// File: parse.C // // Parse arithmetic expressions involving +, -, *, / and (). #include #include #include "token.h" #include "parse.h" // Function prototypes for this file only // static ETree *ParseExpression(TokenStream&) ; static ETree *ParseTerm(TokenStream&) ; static ETree *ParseFactor(TokenStream&) ; // Recursively compute the value of an expression tree // int Evaluate(const ETree& T) { int left_val, right_val ; if (T.root == NULL) return 0 ; left_val = Evaluate(T.root->left) ; // value of left subtree right_val = Evaluate(T.root->right) ; // value of right subtree switch(T.root->data.kind) { case Token::NUMBER : return T.root->data.value ; case Token::PLUS : return left_val + right_val ; case Token::MINUS : return left_val - right_val ; case Token::TIMES : return left_val * right_val ; case Token::DIVIDE : return left_val / right_val ; default : return 0 ; } } // Parse the TokenStream into an expression tree. Catches exceptions. // ETree *Parse(TokenStream &tkstrm) { try { return ParseEverything(tkstrm) ; } catch(ParseError& e) { cerr << "ParseError: " << e.msg << endl ; tkstrm.error() ; return NULL ; } catch(MemoryError& e) { cerr << "MemoryError exception!" ; return NULL ; } } // Parse a TokenStream. Re-throws errors. Use this function to // catch your own expressions. // // Everything -> Expression EOL // ETree *ParseEverything(TokenStream& tkstrm) { ETree *all=NULL ; Token next ; try { all = ParseExpression(tkstrm) ; next = tkstrm.look() ; if (next.kind != Token::EOL) { throw(ParseError("Garbage at the end")) ; } return all ; } catch(...) { // catch any exception delete all ; // free up memory throw ; // rethrow the exception } } // Parse an expression. Includes mutually recursive calls to // ParseTerm and ParseFactor // // Expression -> Term + Expression // -> Term - Expression static ETree *ParseExpression(TokenStream& tkstrm) { ETree *expr=NULL, *term=NULL, *temp=NULL ; Token op ; try { expr = ParseTerm(tkstrm) ; while(1) { op = tkstrm.look() ; switch(op.kind) { case Token::UNDEF : // Bogus, bogus cerr << "Oops, caught internal error" << endl ; exit(1) ; case Token::PLUS : tkstrm.eat() ; // consume the '+' break ; case Token::MINUS : tkstrm.eat() ; // consume the '-' break ; default : return expr ; } term = ParseTerm(tkstrm) ; temp = new ETree(op, *expr, *term) ; expr = temp ; } } // end of try block catch(...) { // catch any exception delete expr ; // free up memory delete term ; delete temp ; throw ; // rethrow the exception } } // Parse a term. Includes mutually recursive calls to // ParseExpression and ParseFactor // // Term -> Factor * Term // -> Factor / Term static ETree *ParseTerm(TokenStream& tkstrm) { ETree *term=NULL, *factor=NULL, *temp=NULL ; Token op ; try { term = ParseFactor(tkstrm) ; while(1) { op = tkstrm.look() ; switch(op.kind) { case Token::UNDEF : // Bogus, bogus throw(ParseError("Unknown symbol")) ; case Token::TIMES : tkstrm.eat() ; // consume the '*' break ; case Token::DIVIDE : tkstrm.eat() ; // consume the '/' break ; default : return term ; } factor = ParseFactor(tkstrm) ; temp = new ETree(op, *term, *factor) ; term = temp ; } } // end of try block catch (...) { // catch any exception delete term ; // free up memory delete factor ; delete temp ; throw ; // rethrow the exception } } // Parse a factor. Includes mutually recursive calls to // ParseExpression and ParseTerm // // Factor -> ( Expression ) // -> Number static ETree *ParseFactor(TokenStream& tkstrm) { Token next ; ETree *factor=NULL ; try { next = tkstrm.look() ; if (next.kind == Token::NUMBER) { tkstrm.eat() ; // consume the number factor = new ETree(next) ; return factor ; } if (next.kind != Token::L_PAREN) { throw(ParseError("Expecting a number or '('")) ; } tkstrm.eat() ; // consume the '(' factor = ParseExpression(tkstrm) ; next = tkstrm.look() ; if (next.kind != Token::R_PAREN) { throw(ParseError("Expecting ')'")) ; } tkstrm.eat() ; // consume ')' return factor ; } catch(...) { // catch any exception delete factor ; // free up memory throw ; // rethrow exception } }