Symbol coder

Wednesday, 10 August 2011

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;
}