2013-05-07 11 views
7

ecco il mio parser di espressioni usando l'algoritmo di shunting-yard funziona bene come previsto tranne in una situazione, quando uso unario meno come in -2 * 3 non funzionerà (penso che non dovrebbe perché non ho trovato nulla nell'algoritmo per gestirlo) c'è un modo semplice per risolvere il problema? (Questo è un semplice parser ho solo bisogno() + - */^) Saluti Pedramunario meno nel parser di espressione del piazzale di smistamento

#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

Anche se era una domanda diversa, ho delineato una soluzione nella mia risposta a http://stackoverflow.com/questions/16380234/handling-extra-operators-in-shunting-yard/16392115#16392115 – rici

risposta

6

L'opzione di cui sopra è corretta, ma sarebbe.. Considerate il caso 2*-(1+2)^-(2+5*-(2+4)). Come potete vedere dovete tenere conto di molte cose, anche quando trovate "* - (" per esempio sapete che lo sostituirete con * (0- (...., che sarebbe codificato in una funzione ricorsiva ingombrante La soluzione migliore è molto più semplice: agli operatori, prendi in considerazione i casi in cui l'operatore è "-" ed è preceduto da un altro operatore, o preceduto da una parentesi a sinistra, o quando è il primo carattere dell'input (questi casi significano che è un unario meno piuttosto che binario). In questo caso, lo si cambia in un altro carattere, dite 'u' (questo era il mio caso), e la sua precedenza è la stessa di quella di '^'.

Inoltre, il trattamento come parte del numero letterale ha la sua presa. Immagina un caso come -2^4. In Wolfram Alpha riceverai -16, non 16.

E considera l'utilizzo di pile. Ti renderanno la vita più facile.

Lasciami spiegare cosa intendevo. Prendere in considerazione si è data l'ingresso:

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

Rendere le sostituzioni che ho suggerito, diventerebbe in questo modo:

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

Ora lo switch precedenza degli operatori dovrebbe essere cambiata a:

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

E, naturalmente, è necessario apportare modifiche per supportare questo operatore unario.

+0

Grande, grazie. Vorrei aggiungere che quando si verifica un operatore precedente, assicurarsi che l'operatore non sia unario negativo. Ciò impedisce a -1 - 4 di diventare -1 -4 e di produrre errori. Si ferma anche --- 4 dal funzionamento (che è un comportamento ragionevole, perché --- 4 non è corretta sintassi matematica - (- (- 4)) continuerà a funzionare). –

1

Una possibilità è quella di mettere un 0 davanti se il primo carattere è '-'. Devi fare questo anche quando il - è dopo un (

Nicer quelli stanno attuando sia l'operatore meno unario o trattandolo come parte del numero letterale

+0

+1, tu Dovremo cercare anche unario '-' e' + 'sepolto altrove nell'espressione, ad es '" 1 - (- 2) "' o '" 1 * -2 "'. [Bracer usa search/replace per risolvere questo problema] (https://github.com/dtitov/bracer/blob/master/src/main/java/com/autsia/bracer/BracerParser.java). – user7116

+0

Voglio dire unario meno dappertutto non solo il primo carattere come 2 * -5 2^-1, .... – PedramH