2013-05-07 24 views
7

這裏是我的表達式分析器使用分流碼算法 它工作得很好,除了在一種情況下,當我使用一元減號像在-2 * 3它不會工作(我認爲它應該't因爲我沒有找到任何算法來處理這個問題) 有沒有一種簡單的方法可以解決這個問題? (這是一個簡單的解析器我只需要()+ - */^) 問候 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] = '\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; 
} 
+0

雖然這是一個不同的問題,但我在回答http://stackoverflow.com/questions/16380234/handling-extra-operators-in-shunting-yard/16392115#16392115 – rici 2013-05-07 18:21:56

回答

6

以上選項是正確的,但它會。如果你發現你需要考慮許多事情,並且每當你發現「* - (」例如你知道你會用*替換它(0- (...,它將被編碼成一個繁瑣的遞歸函數 最好的解決方案要容易得多。在操作員中,要考慮操作符是「 - 」的情況,並且在前面有另一個操作員,或先於通過左括號,或者當它是輸入的第一個字符(這些情況意味着它是一元減號而不是二元)。在這種情況下,您將其更改爲另一個字符,比如'u'(這是我的情況),並將其優先級與'^'的優先級相同。

此外,將它作爲數字字面量的一部分有其不足之處。設想一個例如-2^4的情況。在Wolfram Alpha中,你會得到-16,而不是16.

並考慮使用堆棧。他們會讓你的生活更輕鬆。

讓我解釋一下我的意思。考慮你給出的輸入:

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

使我所建議的替代品,它會變成這個樣子:

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

而且,當然,您需要進行更改以支持此一元運算符。

+0

太好了,謝謝。我想補充一點,在檢查前面的操作符時,確保操作符不是一元負數。這可以防止-1 - 4變成-1 -4併產生錯誤。它也停止--- 4從工作(這是合理的行爲,因爲--- 4是不正確的數學語法。 - ( - ( - 4))將仍然工作)。 – 2016-10-27 16:29:00

1

一種選擇是把0在前面,如果第一個字符是 ' - '。你必須要做到這一點也當 - 是後(

一些好的那些正在實施或者一元減運算符或把它當作文字數字的一部分

+0

+1時列出了一個解決方案,您還必須尋找表達式中別處埋有的一元'-'和'+,例如'「1 - ( - 2)」或「1 * -2」'。 [Bracer使用搜索/替換來解決這個問題](https://github.com/dtitov/bracer/blob/master/src/main/java/com/autsia/bracer/BracerParser.java)。 – user7116 2013-05-07 18:11:38

+0

我的意思是一元減去無處不只是第一個字符像2 * -5 2^-1,.... – PedramH 2013-05-07 18:38:18