Expression analyzer
According to Louden's chapter 4, I wrote this C++ class based on his standard C functions. This class performs a recursive top-down syntax parser and calculation. Basically it is based in this BNF grammar:
exp → exp opadd term | term
opadd → + | -
term → term opmult factor | factor
opmult → * | /
factor → (exp) | integer
which must be translated to EBNF to code the recursive class:
exp → term {oppadd term }
opadd → + | -
term → factor {opmult factor }
opmult → * | /
factor → (exp) | integer
Consenquently, the source code for this parser is shown below:// Integer Expression Analyzer // (C) Carlos Jiménez de Parga // Released under GPL v3.0 terms #include#include #include #include // The analyzer class class Analyzer{ private: char token; // Current analyzed token int exp_count; // Current token count std::string expr; // The analyzed expresion string void match(const char expectedToken); int term(void); int factor(void); std::string getNumber(void); // Convert string to integer public: Analyzer(const std::string &expression); ~Analyzer(); int exp() ; bool eol(); }; // Exception handling class class Exception:public std::exception{ private: std::string what_str; public: Exception(std::string excep); ~Exception() throw(){} virtual const char* what() const throw(); }; Exception::Exception(const std::string excep) { what_str = excep + "\n"; } const char* Exception::what() const throw() { return what_str.c_str(); } // Constructor Analyzer::Analyzer(const std::string &expression) { expr = expression; exp_count = 0; token = expr[exp_count++]; } // Destructor Analyzer::~Analyzer() { std::cout << "Destroyed" << std::endl; } // Convert lexem to integerstd::string Analyzer::getNumber() { std::string token_conv; --exp_count; while (isdigit(expr[exp_count])) { token_conv.push_back(expr[exp_count]); exp_count++; } return token_conv; }// Check current token and advance pointer void Analyzer::match(const char expectedToken) { if (token == expectedToken) token = expr[exp_count++]; else throw Exception("No expected token->line 74");} // First non-terminal call. Performs + and -int Analyzer::exp() { int temp = term(); while ((token=='+') || (token=='-')) switch(token) { case '+': match('+'); temp+=term(); break; case '-': match('-'); temp-=term(); break; } return temp; } // Second non-terminal call. Performs * and / int Analyzer::term() { int temp = factor(); while ((token=='*') || (token=='/')) switch(token) { case '*': match('*'); temp*=factor(); break; case '/': match('/'); temp/=factor(); break; } return temp; } // Call to terminals ( ) and integers int Analyzer::factor() { int temp; if (token=='(') { match('('); temp = exp(); match(')'); } else if (isdigit(token)) { temp = atoi(getNumber().c_str()); token = expr[exp_count++]; } else throw Exception("No item found->line 124"); return temp; } // End of line is reached bool Analyzer::eol() { return token == 0; } int main(int argc, char **argv) { int result; std::string exp,key; // Test expression int x = 22+(5)*(5/3+1)*7 -235+789*2/12+(6*(34+2)-1)+ 25/(2-123)+ 14*((1+23)/2/2/2*(1+1+(2-3)*4+1+ ((((56+12*100))))))/100+11; // Prints test expression std::cout << "The example expression is=" << x << std::endl; do // Repeat until not { std::cout << "Enter an expression with +,-,* and /" << std::endl; std::cin << exp; //exp = "22+(5)*(5/3+1)*7-235+789 *2/12+(6*(34+2)-1)+25/(2-123)+ //14*((1+23)/2/2/2*(1+1+(2-3) *4+1+((((56+12*100))))))/100+11"; // Do calculation try{ Analyzer analyzer(exp); result = analyzer.exp(); if (analyzer.eol()) // EOL is reached std::cout << "The result is = " << result << std::endl; else throw Exception("Not eol reached->line 127"); } catch(std::exception &e) { std::cerr << "Error: " << e.what(); return 1; } std::cout << "Another expresion?:"; std::cin << key; } while (key == "y"); return 0; }
