【问题标题】:unary minus in shunting yard expression parser调车场表达式解析器中的一元减号
【发布时间】:2013-05-07 17:57:48
【问题描述】:

这是我使用调车场算法的表达式解析器 它按预期工作,除了在一种情况下,当我像在 -2*3 中使用一元减号时它不会工作(我认为它不应该,因为我在算法中没有找到任何东西来处理这个) 有没有一种简单的方法可以解决这个问题? (这是一个简单的解析器,我只需要 () + - * / ^ ) 问候 佩德拉姆

#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] = '\0' ;

                    }
            }
        }

    }

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] = '\0' ;
/*******************************
**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]='\0' ;
        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 << "\n\tANS= " << eval(exp)  ;
    cout << endl ;
    system("PAUSE");
    return 0;
} 

【问题讨论】:

标签: c++ parsing unary-operator shunting-yard


【解决方案1】:

上面的选项是正确的,但它会变得非常麻烦和错误。 考虑案例2*-(1+2)^-(2+5*-(2+4))。 如您所见,您需要考虑很多事情。此外,例如,每当您找到 *-( 时,您就会知道您将用 *(0-(... 替换它,这将被编码在一个繁琐的递归函数中。

最好的解决方案要容易得多。解析运算符时,请考虑以下情况:运算符为-,并且它前面有另一个运算符,或者前面有左括号,或者它是输入的第一个字符(这些情况意味着它是一个一元减号而不是二元)。在这种情况下,您将其更改为另一个字符,例如 u(这是我的情况),并使其优先级与 ^ 的优先级相同。

此外,将其视为数字文字的一部分也有其问题。想象一下-2^4这样的案例。在 Wolfram Alpha 中,你会得到 -16,而不是 16

并考虑使用堆栈。它们会让您的生活更轻松。

让我解释一下我的意思。考虑给你输入:

2 / - 7 + ( - 9 * 8 ) * 2 ^ - 9 - 5

按照我的建议进行替换,它会变成这样:

2 / u 7 + (u 9 * 8 ) * 2 ^ u 9 - 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 ;
}

当然,您需要进行更改以支持此一元运算符。

【讨论】:

  • 太好了,谢谢。我想补充一点,在检查前面的运算符时,请确保该运算符不是一元否定的。这可以防止 -1 - 4 变为 -1 -4 并产生错误。它还会阻止 ---4 工作(这是合理的行为,因为 ---4 不是正确的数学语法。-(-(-4)) 仍然可以工作)。
【解决方案2】:

如果第一个字符是“-”,一个选项是在前面放一个 0。当 - 在 (.

更好的是实现一元减号运算符或将其视为数字文字的一部分。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 2016-07-19
  • 2012-05-20
  • 1970-01-01
相关资源
最近更新 更多