利用编译原理中的语法分析进行表达式求值

来源:互联网 发布:剑三毒萝莉捏脸数据 编辑:程序博客网 时间:2024/05/16 00:54

通过语法分析进行表达式求值

记得大二刚学C++时,老师给的表达式求值作业,当时括号都没有要求,后来学数据结构,表达式求值用的是算符优先法,后来学了编译原理,真是深深地佩服计算机科学的前辈们,我觉得编译原理中的自动机和自下而上的语法分析方法非常厉害,刚开始学C,完全就是靠自己的那点机灵去琢磨程序,后来学了数据结构,可以说对思想是一个洗礼,不管解决什么问题,首先想到的都是数据结构,然后再是算法,而不像以前那样毫无章法。现在学了编译原理,可以说对自己又是一个很大的提高。下面是仿照《The C++ Programming Language》中的Desk Caculator利用语法分析写的一个简单的表达式求值的类:
Program:
        Expression End
Expression:
        Expression + term | Expression - term | term
term:
       term / operand | term *operand|operand
operand:
       NUMBER|-operand|+operand|(Expression)

代码:

#ifndef EXPREVAL_H
#define EXPREVAL_H

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

//TokenValue enumeration declaration
enum TokenValue
{
 START, END, NUMBER, NAME,
 ASSIGN = '=', LP = '(', RP = ')',
 PLUS = '+', MINUS = '-', MUL = '*', DIV = '/'
};

class ExprEvalException
{
public:
 ExprEvalException() { strMsg.assign("unknown error"); }
 ExprEvalException(const string& msg) { strMsg.assign(msg); }
 string getMessage() const { return strMsg; }
private:
 string strMsg;
};

//class ExprEval declaration
class ExprEval
{
public:
 ExprEval(const char*);   //constructor initialized with char*
 ExprEval(const string&); //constructor initialized with string
 virtual ~ExprEval();
 double getValue() const; //

private:
 double evalulation(); //plus and minus
 double term(); //multiply and divide
 double getOperand(); //get operand
 TokenValue getToken(); //get next token
 double getNumber(); //get number 

private:
 string strExpr;
 istringstream* pInput;
 double numberValue;
 double result;
 TokenValue currToken;
};

#endif

//ExprEval.cpp

#include "ExprEval.h"

//class ExprEval implementation

ExprEval::ExprEval(const char* expr)
{
 if(NULL == expr)
 {
  throw ExprEvalException("Null pointer in ExprEval::ExprEval");
 }
 strExpr.assign(expr);
 numberValue = 0;
 currToken = START;
 pInput = new istringstream(strExpr);
 result = evalulation();
}

ExprEval::ExprEval(const string& expr)
{
 strExpr.assign(expr);
 numberValue = 0;
 currToken = START;
 pInput = new istringstream(strExpr);
 result = evalulation();
}

ExprEval::~ExprEval()
{
 delete pInput;
}

double ExprEval::getValue() const
{
 return result;
}

double ExprEval::evalulation()
{
 double left = term();
 while(1) //loop: term() + term() + term() - term() ...;
 {
  switch(currToken)
  {
  case PLUS:
   left += term();
   break;
  case MINUS:
   left -= term();
   break;
  default:
   return left;
  }
 }
}

double ExprEval::term()
{
 double left = getOperand();
 double right;
 while(1) //loop: getOperand() * getOperand() / getOperand()
 {
  switch(currToken)
  {
  case MUL:
   left *= getOperand();
   break;
  case DIV:
   right = getOperand();
   if(right == 0)
   {
    throw ExprEvalException("Divided by 0");
   }
   left /= right;
   break;
  default:
   return left;  
  }
 }

//get next operand, return it and get the next TokenValue;
double ExprEval::getOperand() 
{
 double v;

 currToken = getToken();
 
 switch(currToken)
 {
 case NUMBER:
  currToken = getToken();
  return numberValue;
 case PLUS:
  return getOperand();
 case MINUS:
  return -getOperand();
 case LP:
  //recursion invoking to evalulate the expression between LP and RP
  v = evalulation();
  
  //ensure RP
  if(currToken != RP)  
  {
   throw ExprEvalException("Lack of RP");
  }
  getToken();
  return v;
 default:
  throw ExprEvalException("Operand needed"); 
   
 }

TokenValue ExprEval::getToken()
{  
 char c = 0;
 (*pInput) >> c;
 
 switch(c)
 {
 case 0:
  return currToken = END;
 case '*':
 case '/':
 case '-':
 case '+':
 case '(':
 case ')':
 case '=':
  return currToken = TokenValue(c);
 case '0': case '1': case '2': case '3': case '4':
 case '5': case '6': case '7': case '8': case '9':
  (*pInput).putback(c);
  (*pInput) >> numberValue;
  return currToken = NUMBER;
 default:
  throw ExprEvalException("illegal character");  
 }    

 
  

#ifndef EXPREVAL_H
#define EXPREVAL_H

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

//TokenValue enumeration declaration
enum TokenValue
{
 START, END, NUMBER, NAME,
 ASSIGN = '=', LP = '(', RP = ')',
 PLUS = '+', MINUS = '-', MUL = '*', DIV = '/'
};

class ExprEvalException
{
public:
 ExprEvalException() { strMsg.assign("unknown error"); }
 ExprEvalException(const string& msg) { strMsg.assign(msg); }
 string getMessage() const { return strMsg; }
private:
 string strMsg;
};

//class ExprEval declaration
class ExprEval
{
public:
 ExprEval(const char*);   //constructor initialized with char*
 ExprEval(const string&); //constructor initialized with string
 virtual ~ExprEval();
 double getValue() const; //

private:
 double evalulation(); //plus and minus
 double term(); //multiply and divide
 double getOperand(); //get operand
 TokenValue getToken(); //get next token
 double getNumber(); //get number 

private:
 string strExpr;
 istringstream* pInput;
 double numberValue;
 double result;
 TokenValue currToken;
};

#endif

//ExprEval.cpp

#include "ExprEval.h"

//class ExprEval implementation

ExprEval::ExprEval(const char* expr)
{
 if(NULL == expr)
 {
  throw ExprEvalException("Null pointer in ExprEval::ExprEval");
 }
 strExpr.assign(expr);
 numberValue = 0;
 currToken = START;
 pInput = new istringstream(strExpr);
 result = evalulation();
}

ExprEval::ExprEval(const string& expr)
{
 strExpr.assign(expr);
 numberValue = 0;
 currToken = START;
 pInput = new istringstream(strExpr);
 result = evalulation();
}

ExprEval::~ExprEval()
{
 delete pInput;
}

double ExprEval::getValue() const
{
 return result;
}

double ExprEval::evalulation()
{
 double left = term();
 while(1) //loop: term() + term() + term() - term() ...;
 {
  switch(currToken)
  {
  case PLUS:
   left += term();
   break;
  case MINUS:
   left -= term();
   break;
  default:
   return left;
  }
 }
}

double ExprEval::term()
{
 double left = getOperand();
 double right;
 while(1) //loop: getOperand() * getOperand() / getOperand()
 {
  switch(currToken)
  {
  case MUL:
   left *= getOperand();
   break;
  case DIV:
   right = getOperand();
   if(right == 0)
   {
    throw ExprEvalException("Divided by 0");
   }
   left /= right;
   break;
  default:
   return left;  
  }
 }

//get next operand, return it and get the next TokenValue;
double ExprEval::getOperand() 
{
 double v;

 currToken = getToken();
 
 switch(currToken)
 {
 case NUMBER:
  currToken = getToken();
  return numberValue;
 case PLUS:
  return getOperand();
 case MINUS:
  return -getOperand();
 case LP:
  //recursion invoking to evalulate the expression between LP and RP
  v = evalulation();
  
  //ensure RP
  if(currToken != RP)  
  {
   throw ExprEvalException("Lack of RP");
  }
  getToken();
  return v;
 default:
  throw ExprEvalException("Operand needed"); 
   
 }

TokenValue ExprEval::getToken()
{  
 char c = 0;
 (*pInput) >> c;
 
 switch(c)
 {
 case 0:
  return currToken = END;
 case '*':
 case '/':
 case '-':
 case '+':
 case '(':
 case ')':
 case '=':
  return currToken = TokenValue(c);
 case '0': case '1': case '2': case '3': case '4':
 case '5': case '6': case '7': case '8': case '9':
  (*pInput).putback(c);
  (*pInput) >> numberValue;
  return currToken = NUMBER;
 default:
  throw ExprEvalException("illegal character");  
 }    

 
  

原创粉丝点击