做了递归下降方式的运算解析器(C#),支持变量定义与运算 :
using System;
namespace ParserSpace
{
/// <summary>
/// 解析器类Parser
/// </summary>
public sealed class Parser
{
//Array for variables
private double[] vars = new double[26];
//令牌类型
enum tokenEnum{NONE,DELIMITER,VARIABLE,NUMBER};
//语法错误类型
int SYNTAX=0;
int UNBALPARENS=1;
int NOEXP=2;
int DIVBYZERO=3;
//表达式完
string EOE="/0";
public string exp; //表达式
int expIdx; //表达式当前指针
public string token;//当前的令牌
tokenEnum tokType; //当前的令牌类型
//取得下一个令牌
public void getToken()
{
tokType=tokenEnum.NONE;
token="";
//检查表达式是否取完
if(expIdx==exp.Length)
{
token=EOE;
return;
}
//如果是空格则跳过
while(expIdx<exp.Length&&(exp[expIdx]==' '))++expIdx;
//是不是空格完了命令行也完成了
if(expIdx==exp.Length)
{
token=EOE;
return;
}
if(exp[expIdx]==':') //如果冒号
{
token+=exp[expIdx];
expIdx++;
tokType=tokenEnum.DELIMITER;
}
else
if (isDelim(exp[expIdx])) //如果是操作符
{
token+=exp[expIdx];
expIdx++;
tokType=tokenEnum.DELIMITER;
}
else if((('a'<=exp[expIdx])&&('z'>=exp[expIdx]))||
(('A'<=exp[expIdx])&&('Z'>=exp[expIdx])))
//如果是变量
{
while(!isDelim(exp[expIdx]))
{
token+=exp[expIdx];
expIdx++;
if(expIdx>=exp.Length)
break;
}
tokType=tokenEnum.VARIABLE;
}
else if (('0'<=exp[expIdx])&&('9'>=exp[expIdx])) //如果是数字
{
while(!isDelim(exp[expIdx]))
{
token+=exp[expIdx];
expIdx++;
if(expIdx>=exp.Length)
break;
}
tokType=tokenEnum.NUMBER;
}
else //不可识别的终结表达式
{
token=EOE;
return ;
}
}
//如果是一个分隔符则返回真值
private bool isDelim(char c)
{
if ((" +-/*%^=()".IndexOf(c)!=-1))
return true;
return false;
}
//解析器入口程序
public double evaluate(string expstr)
{
double result=0.0;
exp=expstr;
expIdx=0;
getToken();
if(token.Equals(EOE))
handleErr(NOEXP); //表示没有表达式
//解析并计算表达式
result=evalExp1();
if(!token.Equals(EOE))
handleErr(SYNTAX);
return result;
}
//处理赋值
private double evalExp1()
{
double result;
int varIdx;
tokenEnum ttokType;
string temptoken;
if (tokType==tokenEnum.VARIABLE)
{
//保存旧值
temptoken=token;
ttokType=tokType;
//计算变量的索引
varIdx=char.ToUpper(token[0])-'A';
getToken();
if (token.Equals('='))
{
putBack(); //返回当前的令牌
//恢复老的令牌 (非赋值)
token=temptoken;
tokType=ttokType;
}
else
{
getToken(); //取得表达式的下一部分
result=evalExp2();
vars[varIdx]=result;
return result;
}
}
return evalExp2();
}
//两个项的加减
private double evalExp2()
{
char op;
double result;
double partialResult;
result=evalExp3();
while((op=token[0])=='+'||op=='-')
{
getToken();
partialResult=evalExp3();
switch(op)
{
case '-':
result=result-partialResult;
break;
case '+':
result= result+partialResult;
break;
}
}
return result;
}
//两个项的乘或除
private double evalExp3()
{
char op;
double result;
double partialResult;
result=evalExp4();
while((op=token[0])=='*'||op=='/'||op=='%')
{
getToken();
partialResult=evalExp4();
switch(op)
{
case '*':
result=result * partialResult;
break;
case '/':
if (partialResult==0.0)
handleErr(DIVBYZERO);
result=result / partialResult;
break;
case '%':
if(partialResult==0.0)
handleErr(DIVBYZERO);
result= result % partialResult;
break;
}
}
return result;
}
//指数运算
private double evalExp4()
{
double result;
double partialResult;
double ex;
result=evalExp5();
if(token.Equals('^'))
{
getToken();
partialResult=evalExp4();
ex=result;
if(partialResult==0.0) //指数为零
{
result=1.0;
}
else
for(int t=(int)partialResult-1;t>0;t--)
result=result*ex;
}
return result;
}
//计算一元的加减运算
private double evalExp5()
{
double result;
string op;
op="";
if((tokType==tokenEnum.DELIMITER)&& token.Equals('+')||token.Equals('-'))
{
op=token;
getToken();
}
result=evalExp6();
if(op.Equals('-'))
result=-result;
return result;
}
//处理加括号的表达式
private double evalExp6()
{
double result;
if(token.Equals('('))
{
getToken();
result=evalExp2();
if(!token.Equals(')'))
handleErr(UNBALPARENS);
getToken();
}
else
result=atom();
return result;
}
//读取数字
private double atom()
{
double result=0.0;
switch(tokType)
{
case tokenEnum.NUMBER:
try{
result=Double.Parse(token);
}
catch(FormatException exc)
{
handleErr(SYNTAX);
}
getToken();
break;
case tokenEnum.VARIABLE:
result=findVar(token);
getToken();
break;
default:
handleErr(SYNTAX);
break;
}
return result;
}
//处理错误
private void handleErr(int error)
{
string[] err={
"语法错误",
"括号缺失(不对称)",
"没有表达式",
"被除数为零"
};
throw new ParserException(err[error]);
}
//返回变量的值
private double findVar(string vname)
{
if ((vname[0]>='a')&&(vname[0]<='Z'))
{
handleErr(SYNTAX);
return 0.0;
}
return vars[char.ToUpper(vname[0])-'A'];
}
//返回令牌到输入字符串流中
private void putBack()
{
if (token==EOE)return;
for (int i = 0; i < token.Length; i++)
expIdx--;
}
public Parser()
{
}
}
}