编译原理之表达式求值.docx
《编译原理之表达式求值.docx》由会员分享,可在线阅读,更多相关《编译原理之表达式求值.docx(9页珍藏版)》请在冰豆网上搜索。
编译原理之表达式求值
编译原理之表达式求值
中缀表达式a+b*(c+d)-e
前续表达式(波兰)-e+a*b+cd
后续表达式(逆波兰)abcd+*e-+
中缀转后缀
1.构建二叉树->后续遍历
2.堆栈方法:
中缀表达式到逆波兰表达式的转换及求值(ChinaDHF)
最近要写一个工资管理软件,不可避免的要用到公式的定义及求值等问题。
对于数学表达式的计算,虽然也有直接对表达式进行扫描并按照优先级逐步计算的方法,但感觉还是不如将中缀表达式转换为逆波兰表达式更容易处理。
使用逆波兰表达式,则有以下几件工作需要去做:
1.对中缀表达式进行语法分析,或称合法性检查。
2.将中缀表达式转换为逆波兰表达式。
3.计算逆波兰表达得到我们想要的值。
以下是我为实现该功能而写的一个简单的类:
usingSystem;
usingSystem.Text;
usingSystem.Collections;
usingSystem.Text.RegularExpressions;
namespaceSeaking
{
publicclassRpnExpression
{
检查中缀表达式的合法性#region检查中缀表达式的合法性
///
///检查中缀表达式是否合法。
///
///
///
publicstaticboolIsRight(stringexp)
{
stringpMatch=@"\([^\(^\)]+\)";//匹配最“内”层括号及表达式
stringnumberMatch=@"\d+(\.\d+)?
";//匹配数字
stringexMatch=@"^0([-+*/]0)*$";//匹配无括号的、用0替换所有的数字后的表达式exp=Regex.Replace(exp,numberMatch,"0");//为简化检测,用0替换所有的数字
while(Regex.IsMatch(exp,pMatch))
{
foreach(MatchmatchinRegex.Matches(exp,pMatch))
{
stringtmp=match.Value;
tmp=tmp.Substring(1,tmp.Length-2);//去掉"("和")"
if(!
Regex.IsMatch(tmp,exMatch))returnfalse;
}
exp=Regex.Replace(exp,pMatch,"0");//将最内层的括号及括号内表达式直接用一个0代替
}
returnRegex.IsMatch(exp,exMatch);
}
#endregion
生成逆波兰表达式#region生成逆波兰表达式
///
///获取逆波兰表达式。
///
///
///
publicstaticstringRpnExp(stringexp)
{
if(!
IsRight(exp))thrownewApplicationException("非法的中缀表达式。
");
StackskOp=newStack();//定义操作符堆栈
StringBuilderrpn=newStringBuilder();//逆波兰表达式
char[]charExp=exp.ToCharArray();//将中缀表达式转换为char数组
stringdigit=string.Empty;//数字字符串
for(inti=0;i{
charchr=charExp[i];
if(char.IsDigit(chr)||chr=='.')//如果是数字或小数点,添加到数字字符串中
{
digit+=chr;
}
elseif("+-*/".IndexOf(chr)>=0)//如果是运算符
{
if(digit.Length>0)
{
rpn.Append("<"+digit+">");//首先将数字添加到逆波兰表达式
digit=string.Empty;
}
//弹出操作符并添加到逆波兰表达式,直至遇到左括号或优先级较低的操作符while(skOp.Count>0)
{
charopInStack=(char)skOp.Pop();
if(opInStack=='('||Power(opInStack){
skOp.Push(opInStack);
break;
}
else
{
rpn.Append(opInStack);
}
}
skOp.Push(chr);//将当前操作符压入堆栈中
}
elseif(chr=='(')//遇到左括号,直接压入堆栈中
{
skOp.Push(chr);
}
elseif(chr==')')//遇到右括号
{
if(digit.Length>0)//先将数字添加到逆波兰表达式
{
rpn.Append("<"+digit+">");
digit=string.Empty;
}
while(skOp.Count>0)//弹出运算符并添加到逆波兰表达式,直至遇到左括号{
charopInStack=(char)skOp.Pop();
if(opInStack=='(')
{
break;
}
else
{
rpn.Append(opInStack);
}
}
}
}
//到达字符串末尾后,首先将数字添加到逆波兰表达式
if(digit.Length>0)
{
rpn.Append("<"+digit+">");
}
//弹出所有操作符并添加到逆波兰表达式
while(skOp.Count>0)
{
charopInStack=(char)skOp.Pop();
rpn.Append(opInStack);
}
returnrpn.ToString();
}
///
///获取操作符的优先级。
///
///
///
privatestaticintPower(charo)
{
switch(o)
{
case'+':
case'-':
return1;
case'*':
case'/':
return2;
default:
return0;
}
}
#endregion
计算逆波兰表达式的值#region计算逆波兰表达式的值///
///获取中缀表达式的值。
///
///
///
publicstaticdoubleGetValue(stringexp)
{
returnGetValueByRpn(RpnExp(exp));
}
///
///获取逆波兰表达式的值。
///
///
///
publicstaticdoubleGetValueByRpn(stringrpnExp)
{
Stackstack=newStack();
char[]expChar=rpnExp.ToCharArray();
stringdigit=string.Empty;
doubleresult=0;
for(inti=0;i{
charc=expChar[i];
if(c=='<')
{
digit=string.Empty;
}
elseif(c=='>')
{
stack.Push(digit);
}
elseif(char.IsDigit(c)||c=='.')
{
digit+=c.ToString();
}
elseif(c=='+'||c=='-'||c=='*'||c=='/')
{
doubled2=Convert.ToDouble(stack.Pop());
doubled1=Convert.ToDouble(stack.Pop());
result=math(d1,d2,c);
stack.Push(result);
}
}
returnresult;
}
///
///四则运算。
///
///
///
///
///
privatestaticdoublemath(doubled1,doubled2,charo){
switch(o)
{
case'+':
returnd1+d2;
case'-':
returnd1-d2;
case'*':
returnd1*d2;
case'/':
returnd1/d2;default:
return0d;
}
}
#endregion
}
}