12 votes

Moins unaire dans l'analyseur d'expression de la cour shunting

Voici mon analyseur d'expressions utilisant l'algorithme de la cour de transfert. Il fonctionne bien comme prévu sauf dans une situation, lorsque j'utilise un moins unaire comme dans -2*3 cela ne fonctionne pas (je pense que cela ne devrait pas car je n'ai rien trouvé dans l'algorithme pour gérer cela) y a-t-il un moyen simple que je puisse réparer cela? (c'est un analyseur simple j'ai seulement besoin de () + - * / ^) Salutations Pedram

#include 
#include 
#include 
#include 
#include 
using namespace std;
int olaviat(char c) {
   /*************
    **Précédence de l'opérateur
    *************/
  switch(c) {
       case '-' : case '+' :
           return 1;
       case '*' : case '/' :
           return 2;
       case '^' :
           return 3;
       default :
           return 0;
  }
}
double eval(char *exp) {
    /*************
    **Conversion en notation polonaise inverse
    *************/
    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 << "Notation Polonaise Inverse" << endl ;
for (int i = 0; i < nl-1; i++){
        cout << n[i] ;
    }
cout << endl;
//n[nl+1] = '\0' ;
/*******************************
**Calcul du Résultat
*******************************/
    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 Erreur inconnue";
                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;
début :
    cin.get(exp, 99);
    cout << "\n\tANS= " << eval(exp);
    cout << endl;
    system("PAUSE");
    return 0;
}

14voto

TGO Points 1854

La option ci-dessus est correcte, mais elle deviendrait très lourde et boguée. Considérez le cas 2*-(1+2)^-(2+5*-(2+4)). Comme vous pouvez le voir, vous devez prendre en compte de nombreuses choses. De plus, chaque fois que vous trouvez *-(, par exemple, vous savez que vous allez le remplacer par *(0-(..., ce qui serait codé dans une fonction récursive compliquée.

La meilleure solution est beaucoup plus simple. Lorsque vous analysez les opérateurs, tenez compte des cas où l'opérateur est - et est précédé d'un autre opérateur, ou précédé d'une parenthèse ou lorsque c'est le premier caractère de l'entrée (ces cas signifient qu'il s'agit d'un moins unaire plutôt que binaire). Dans ce cas, vous le changez en un autre caractère, disons u (c'était mon cas), et vous faites en sorte que sa priorité soit la même que celle de ^.

De plus, le traiter comme faisant partie du littéral numérique a sa particularité. Imaginez un cas tel que -2^4. Dans Wolfram Alpha, vous obtiendriez -16, pas 16.

Et envisagez d'utiliser des piles. Elles vous faciliteront la vie.

Permettez-moi d'expliquer ce que je voulais dire. Supposez que vous ayez l'entrée suivante:

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

En faisant les remplacements que j'ai suggérés, ça ressemblerait à cela:

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

Maintenant, votre commutateur de priorité des opérateurs devrait être modifié comme suit:

switch(c)
{
       case '-' : case '+' :
           return 1 ;
       case '*' : case '/' :
           return 2 ;
       case '^' : case 'u': //notez l'opérateur 'u' que nous avons ajouté
           return 3 ;
       default :
           return 0 ;
}

Et bien sûr, vous devez apporter des modifications pour prendre en charge cet opérateur unaire.

1voto

jmihalicza Points 1382

Une option est de mettre un 0 devant si le premier caractère est '-'. Vous devez également le faire lorsque le - est après un (.

Les plus jolies sont d'implémenter soit l'opérateur moins unaire, soit de le traiter comme partie du littéral numérique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X