利用编译原理中的语法分析进行表达式求值
2005-11-27 21:26
751 查看
通过语法分析进行表达式求值记得大二刚学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 implementationExprEval::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
4000
currToken;
};#endif//ExprEval.cpp#include "ExprEval.h"//class ExprEval implementationExprEval::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");
}
}
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 implementationExprEval::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
4000
currToken;
};#endif//ExprEval.cpp#include "ExprEval.h"//class ExprEval implementationExprEval::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");
}
}
相关文章推荐
- 编译原理实验2-递归下降分析–表达式求值
- 编译原理之表达式语法分析(一)——自顶向下
- 编译原理之基于扫描器的表达式语法分析+逆波兰表达式生成
- 语法分析(编译原理)
- 编译原理实验之语法分析(算符优先分析算法(C语言))
- 编译原理词/语法分析
- CSUFT 编译原理实验三 中缀表达式转逆波兰表达式求值
- 编译原理-用Bison构造语法分析程序-小小计算器
- 【编译原理】自顶向下的语法分析之递归下降分析法
- 编译原理-词法分析-语法分析-语义分析生成中间代码-python版
- 编译原理之算符优先分析语法程序
- 编译原理与技术(第四章)语法分析
- 编译原理实习(应用预测分析法LL(1)实现语法分析)
- 一个简单的自顶向下语法分析(表达式求值)
- 编译原理,自上而下非递归语法分析自上而下的语法分析
- 编译原理_常量定义语句语法分析
- Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法
- 编译原理:递归向下分析程序建立语法分析树的Java实现(一)
- 利用客户端缓存对网站进行优化的原理分析第1/2页
- python实现算术表达式的词法语法语义分析(编译原理应用)