2013-05-07 9 views
7

oto mój parser wyrażeń z użyciem algorytmu manewrowania stoczniowego działa dobrze zgodnie z oczekiwaniami, z wyjątkiem sytuacji, gdy używam unarnego minusa jak w -2 * 3 to nie działa (myślę, że powinien ponieważ nie znalazłem nic w algorytmie, aby sobie z tym poradzić) Czy istnieje prosty sposób, aby to naprawić? (jest to prosty parser tylko potrzebne() + - */^) Pozdrowienia PedramJednoargumentowy minus w paralizatorze wyliczenia jarda stoczniowego

#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

Chociaż to było inne pytanie, przedstawiam rozwiązanie w mojej odpowiedzi na http://stackoverflow.com/questions/16380234/handling-extra-operators-in-shunting-yard/16392115#16392115 – rici

Odpowiedz

6

Powyższa opcja jest poprawna, ale to zrobi.. bardzo kłopotliwy i kłopotliwy Rozważmy przypadek 2*-(1+2)^-(2+5*-(2+4)). Jak widać, musisz wziąć pod uwagę wiele rzeczy. Również gdy znajdziesz "* - (" na przykład wiesz, że zastąpisz to * (0- (..., który byłby zakodowany w kłopotliwej funkcji rekursywnej Najlepsze rozwiązanie jest o wiele łatwiejsze, przy operatorach wziąć pod uwagę przypadki, w których operator jest "-" i jest poprzedzony przez innego operatora lub poprzedzony przez lewy nawias, lub gdy jest to pierwszy znak wejścia (te przypadki oznaczają, że jest to jednoargumentowy minus, a nie binarny). W tym przypadku zmienisz go na inną postać, na przykład "u" (tak było w moim przypadku) i nadałem jej pierwszeństwo "^".

Ponadto, traktowanie go jako części literału liczbowego ma swój haczyk. Wyobraź sobie przypadek taki jak -2^4. W Wolfram Alpha uzyskasz -16, a nie 16.

Rozważ użycie stosów. Ułatwią ci życie.

Pozwól mi wyjaśnić, co miałem na myśli. Rozważ podane są dane wejściowe:

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

Dokonywanie zamienniki Zaproponowałem, by stać się tak:

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

teraz operator przełącznik pierwszeństwo powinny być zmienione na:

switch(c) 
{ 
     case '-' : case '+' : 
      return 1 ; 
     case '*' : case '/' : 
      return 2 ; 
     case '^' : case 'u': //note the 'u' operator we added 
      return 3 ; 
     default : 
      return 0 ; 
} 

Oczywiście należy wprowadzić zmiany w celu wsparcia tego jedno operatora.

+0

Świetnie, dzięki. Chciałbym dodać, że sprawdzając poprzedzającego operatora, upewnij się, że operator nie jest jednoargumentowym ujemnym. Zapobiega to -1 - 4 z -1-4 i powoduje błędy. Zatrzymuje się również --- 4 od pracy (co jest rozsądnym zachowaniem, ponieważ --- 4 nie jest poprawną składnią matematyczną - (- (- 4)) nadal będzie działać). –

1

Jedną z możliwości jest umieszczenie 0 z przodu, jeśli pierwszy znak '-'. Trzeba to zrobić także wtedy, gdy - jest po (

ładniejszych wdrażają albo jednoargumentowy operator minus lub traktując je jako część numeru dosłownym

+0

+1, ty Będą również musiały szukać unarnych '-' i' + 'pochowanych gdzie indziej w wyrażeniu, np '" 1 - (- 2) "' lub '" 1 * -2 "'. [Bracer używa wyszukiwania/zastępowania, aby rozwiązać ten problem] (https://github.com/dtitov/bracer/blob/master/src/main/java/com/autsia/bracer/BracerParser.java). – user7116

+0

Mam na myśli unarny minus wszędzie, nie tylko pierwsza postać, jak 2 * -5 2^-1, .... – PedramH