递归下降方式的运算解析器
来源:互联网 发布:linux的head命令 编辑:程序博客网 时间:2024/05/16 12:37
做了递归下降方式的运算解析器(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()
{
}
}
}
- 递归下降方式的运算解析器
- 递归下降的表达式解析器
- 递归下降的带变量的表达式解析器
- java实现递归下降的表达式解析器
- 一个递归下降的数字表达式解析器
- 递归下降的语法分析
- 递归下降的语法分析
- 两百行写一个递归下降解析器
- 70 行 Python 代码编写一个递归下降解析器
- 简单的递归下降分析
- 递归下降纯解释器编写的困惑
- 20170219C++项目班02_02递归下降算法/解析器/Scanner实现
- 关于递归运算的形态与表现方式
- 三种梯度下降的方式:批量梯度下降、小批量梯度下降、随机梯度下降
- SNL文法的递归下降语法分析器
- 递归方式解析xml文档
- 用递归方式解析XML的任意文件
- 递归下降分析程序
- More Effective C++之6
- SQL习题集(3)
- 多线程设计要点
- 很弱智的回文数问题
- 计划管理法则:PDCAR
- 递归下降方式的运算解析器
- Feeling Frustrated
- 善于认知自己--读周国平有感
- 关于软件文档 这些你知道吗?
- Windows Storage Server 2003 的 10 大优点
- 配置安全的Apache,配置带SSL加密的Apache(mod_ssl+open_ssl),自我签证的SSL证书的制作与发放
- I like small font..
- 学习netfilter/iptables的使用
- 试用iptables