C++: Evaluation d'expressions

 

Le problème

Enoncé

Un logiciel de calcul scientifique dans un domaine X dispose d'une fonctionnalité de sauvegarde de programmes mathématiques dans des fichiers texte. L'objectif est de développer le module capable de relire ce type de fichier et calculer la valeur des variables.
Pour cet exercice, nous nous contentons des opérations entières simples : l'addition, la soustraction, la divison et la multiplication. Un fichier texte produit contient des enregistrements de la forme :
 
#<num> = DECLARATION ( variable );
#<num> = operateur-binaire ( op1 , op2 );
 
avec :
  • num : nombre entier représentant le numero d'enregistrement,
  • DECLARATION : symbole représentant un enregistrement pour une déclaration de variable;
  • variable : le nom d'une variable;
  • operateur-binaire : un symbole (un code) représentant le type d'opération à effectuer soit PLUS, MOINS, MULT, DIV ou AFFECTATION;
  • op1, op2 : soit une valeur entière, soit la référence à un autre enregistrement, soit la référence à une variable; pour référencer un enregistrement ou une variable, on utilise le caratère '#' suivit du numéro d'enregistrement. 
NB : Pour faciliter la lecture, les blancs qui séparent les différentes parties d'un enregistrement sont effectivement obligatoirement présents dans le fichier.
 

Des exemples

Votre programme doit être capable de lire et de calculer les exemples suivants:

Exemple 1

#0 = DECLARATION ( a );
#1 = MULT ( 2 , 3 );  
#2 = AFFECTATION ( #0 , #1 );
 
Le résultat dans a est 2*3 donc 6.

Exemple 2

#0 = DECLARATION ( b );
#1 = MULT ( 2 , #2 );
#2 = PLUS ( 4 , 1 );
#3 = AFFECTATION ( #0 , #1 );
 
Le résultat dans b est 2*(4 + 1) soit 10.

Exemple 3

#0 = DECLARATION ( c );
#1 = MULT ( 2 , #2 );
#2 = PLUS ( #3 , #4 );
#3 = DIV ( 10 , 2 );
#4 = MOINS ( 8 , 2 );
#5 = AFFECTATION ( #0 , #1 );
 
 
Le résultat dans c est 2*((10/2) + (8 - 2)) soit 22.
 

Plan de travail

Analyse
Spécifier rapidement la ou les hiérarchies de classes devant être développées pour la lecture des fichiers, le calcul des expressions et l'affectation.
Mise en oeuvre
Interpréteur
 
Développer le module de lecture et de calcul d'expressions et d'affectation : après la lecture d'un fichier, le programme demande à l'utilisateur le nom de la variable, et le programme doit afficher sa valeur.
 
Générateur de C
 
Développer un module capable de générer du code C à partir du code produit par le logiciel scientifique.
 

Fournitures

Voici deux versions de la fonction LireRec qui permet de lire un enregistrement dans un stream ou dans un FILE.
 
Attention : LireRec permet de lire un fichier contenant par exemple :
 
#0 = DECLARATION ( a );
#1 = MULT ( 2 , 3 );  
#2 = AFFECTATION ( #0 , #1 );
 
 
Ces deux fonctions remplissent des buffer de caractères : la structure Rec représente uniquement un buffer de lecture (ne l'utiliser que pour la lecture du fichier).
 
#include <iostream.h>
#include <fstream.h>
#include <stdio.h>
 
struct Rec
{
  char numero[128];
  char operation[128];
  char op1[128];
  char op2[128];
};
 
bool LireRec(istream & in, Rec & r)
{
  if (in.good()) {
    char sbuf[128];
    in >> r.numero;
    in >> sbuf; // pour le '='
    in >> r.operation;
    in >> sbuf; // pour la '('
    in >> r.op1;
    in >> sbuf; // pour la ',' ou ');'
    if (sbuf[0] == ',') {
      in >> r.op2;
      in >> sbuf; // pour ');'
    } else {
      r.op2[0] = 0; // pas d'op2
    }
  }
  return in.good() && !in.eof();
}
 
bool LireRec(FILE * in, Rec & r)
{
  char sbuf[128];
  if ((fscanf(in, "%s%s%s%s%s%s", r.numero, sbuf, r.operation, sbuf, r.op1, sbuf)) == 6) {
    if (sbuf[0] == ',') {
      fscanf(in, "%s%s", r.op2, sbuf);
    } else {
      r.op2[0] = 0;
    }
    return true;
  }
  return false;
}
 
#ifdef TEST
 
main()
{
  cerr << "Un premier test avec les stream" << endl;
  ifstream istrim("rec.data");
  Rec r;
  while (LireRec(istrim, r)) {
    cerr << r.numero << ' ' << r.operation << ' ' << r.op1 << ' ' <<  r.op2 << endl;
  }
 
  cerr << endl << "Un deuxieme test avec un FILE *" << endl;
  FILE * ifile = fopen("rec.data", "r");
  while (LireRec(ifile, r)) {
    fprintf(stderr, "%s %s %s %s\n",  r.numero, r.operation, r.op1, r.op2);
  }
  fclose(ifile);
  exit(0);
  return 1;
}
 
#endif