分流码表达式解析器中的一元减号
unary minus in shunting yard expression parser
这是我的表达式解析器使用的分流码算法它工作得很好,除了在一种情况下,当我使用一元减号像-2*3它不会工作(我认为它不应该,因为我没有找到任何算法来处理这个)有什么简单的方法可以解决这个问题吗?(这是一个简单的解析器,我只需要()+ - */^)问候Pedram
#include <cctype>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
int olaviat (char c) {
/*************
**Operator precedence
*************/
switch(c) {
case '-' : case '+' :
return 1 ;
case '*' : case '/' :
return 2 ;
case '^' :
return 3 ;
default :
return 0 ;
}
}
double eval(char *exp) {
/*************
**Convert to reverse polish
*************/
char n [50] , o[50] ;
static int nl = 0 , ol = 0 ;
while (*exp) {
while(isspace(*exp)) *exp++ ;
if(*exp == '(') {
o[ol++] = *exp++ ;
}
else if (*exp == ')'){
while(o[--ol]!='('){
n[nl++] = o[ol];
n[nl++] = ' ';
}
*exp++;
}
else if (isdigit(*exp)) {
while (isdigit(*exp)) {
n[nl++] = *exp++ ;
}
n[nl++] = ' ' ;
}
else if (strchr("+-*/^",*exp)){
if(olaviat(*exp) > olaviat(o[ol-1])) {
o[ol++] = *exp++ ;
}
else {
if(olaviat(*exp) == olaviat(o[ol-1]) && olaviat(*exp)== 3) {
o[ol++] = *exp++ ;
}else{
n[nl++] = o[ol-1] ;
n[nl++] = ' ' ;
o[--ol] = ' ' ;
}
}
}
}
for (int k = ol-1 ; k >= 0 ; k --){
n[nl++] = o[k];
n[nl++] = ' ' ;
}
/*******************************/
cout << "Reverse Polish" << endl ;
for (int i = 0 ; i < nl-1 ; i++){
cout << n[i] ;
}
cout << endl ;
//n[nl+1] = ' ' ;
/*******************************
**Calculate Result
*******************************/
double temp[50];
char *e ;
ol = 0;
int nol = 0 ;
e=n ;
int digitcount = 0;
while (*e) {
while (isspace(*e)) *e++;
if (isdigit(*e)) {
while (isdigit(*e)) {
o[ol++] =*e++ ;
digitcount++ ;
}
temp[nol++] = atof(o) ;
for (int i = 0 ; i < digitcount ; i++)
o[i]=' ' ;
ol=0;
digitcount = 0 ;
}
else if (strchr("+-*/^",*e)){
// char opr ;
double tempAns = 0;
switch (*e) {
case '+' :
tempAns = temp[nol-2] + temp [nol-1] ;
break ;
case '-' :
tempAns = temp [nol-2] - temp [nol-1] ;
break;
case '*' :
tempAns = temp [nol-2] * temp [nol-1] ;
break;
case '/' :
tempAns = temp[nol-2] / temp[nol-1];
break ;
case '^' :
tempAns = pow(temp[nol-2],temp [nol-1]);
break ;
default :
cout << "n Unknown error" ;
continue;
}
*e++ ;
nol--;
temp[nol-1] = tempAns ;
temp[nol] = NULL ;
}
else {
break ;
}
}
double ans = temp[0];
return ans ;
}
int main() {
char exp[100];
char c;
start :
cin.get (exp , 99);
cout << "ntANS= " << eval(exp) ;
cout << endl ;
system("PAUSE");
return 0;
}
上面的选项是正确的,但是它会变得非常麻烦和有bug。考虑2*-(1+2)^-(2+5*-(2+4))
的情况。正如你所看到的,你需要考虑很多事情。同样,当你找到*-(
时,例如,你知道你将用*(0-(...
代替它,这将被编码为一个麻烦的递归函数。
最好的解决方案要简单得多。在解析操作符时,请考虑以下情况:操作符是-
并且前面有另一个操作符,或者前面有左括号,或者它是输入的第一个字符(这些情况意味着它是一元减号而不是二进制)。在这种情况下,您将其更改为另一个字符,例如u
(这是我的情况),并使其优先级与^
相同。
作为数字字面量的一部分也有它的问题。想象一个-2^4
这样的例子。在Wolfram Alpha中,你会得到-16
,而不是16
。
并考虑使用堆栈。他们会让你的生活更轻松。
让我解释我的意思。假设给定输入:
2/- 7 + (- 9 * 8) * 2 ^ - 9 - 5
按照我的建议进行替换,它会变成这样:
2/u7 + (u9 * 8) * 2 ^ u9 - 5
现在你的操作符优先级开关应该改为:
switch(c)
{
case '-' : case '+' :
return 1 ;
case '*' : case '/' :
return 2 ;
case '^' : case 'u': //note the 'u' operator we added
return 3 ;
default :
return 0 ;
}
当然,您需要做一些修改来支持这个一元操作符
如果第一个字符是'-',可以在前面加一个0。当(.
)后面有-时,也必须这样做。更好的是实现一元减号运算符或将其作为数字字面量的一部分。
相关文章:
- (C++)分析树以计算返回错误值的简单算术表达式
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 提升精神:解析布尔表达式并简化为规范范式
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 使用正则表达式regex_search在字符串中查找字符串
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 概念中的cv限定符需要表达式参数列表
- 为什么constexpr的性能比正常表达式差
- 对于结构,表达式必须是可修改的ivalue
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 将fold表达式与std::一起用于两个元组
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 标记 '","' 之前的预期主表达式
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 带有用户定义类的c++折叠表达式
- 即使使用调试编译标志,表达式也是"optimized out"
- holeMenuProgram.cpp:38:1 错误:'}'令牌之前的预期主表达式
- 在Eigen中使用一元表达式的逐元素运算
- 分流码表达式解析器中的一元减号