C++: Correction Evaluation d'expressions

 

Une proposition de classification 

Uploaded Image: Expression.png
 
Ce schéma montre trois classes importantes :
  • Expression : à l'exception des déclarations, toute ligne du fichier représente une expression calculable; c'est une classe abstraite utile à la spécification de l'interface commune de toute les expressions (on aura "resoudre" ou "calculer");
  • Variable : il s'agit d'une association entre un nom et une valeur; on a une variable par déclaration
  • System : représente le systeme qui peut lire et exploiter les expressions lues dans le fichier 

Une première solution (imparfaite)

Fichier à sauvegarder dans program.cpp
 
#ifndef EXPRESSION_H
#define EXPRESSION_H
 
#include <string>
#include <vector>
#include <map>
#include "stdio.h"
 
class Object;
class Expression;
class Binaryexpr;
class Unaryexpr;
class Unresolved;
class Assign;
class Div;
class Mult;
class Plus;
class Minus;
class Variable;
class VarRef;
class Integer;
 
using namespace std;
 
struct Rec
{
  char numero[128];
  char operation[128];
  char op1[128];
  char op2[128];
};
 
class System {
 public:
  void readFile (string filename);
  Expression * buildOperand(const char * );
  Object * fetchOperand(int _oid);
  void dumpVars() const;
  void dumpObjects() const;
  void compute();
 
  void addObject(Object * obj);
  void addInstruction(Expression * expr);
  void addVariable(Variable * var);
 
 protected:
  Object * objectFromRec(const Rec & r);
  vector<Object*>  objects; // tous les objets du fichier
  vector<Expression*> instructions; // toutes les instructions à executer
  map<string,Variable*> variablesIndex; // index pour acceder aux variables par leur nom
};
 
class Object {
 public:
  Object(int _oid) : oid(_oid) {}
  Object () : oid(-1) {}
  int get_oid() const { return oid; }
  virtual void updateSystem(System * sys);
  virtual void resolvesFrom(System * sys) {}
  string oidAsChars() const { char buf[512]; sprintf(buf, "%d", oid); return string(buf); }
  virtual string toString() const { return string("#") + oidAsChars(); }
 protected:
  int oid;
};
 
class Expression : public Object { 
 public:
  Expression(int _oid) : Object(_oid) {}
  Expression() {}
  virtual int value() const = 0;
  virtual void compute() {}
};
 
class BinaryExpr: public Expression {
 public:
  BinaryExpr(int _oid, Expression * _op1, Expression * _op2)
    : Expression(_oid), op1(_op1), op2(_op2) {}
  BinaryExpr(Expression * _op1, Expression * _op2)
    : op1(_op1), op2(_op2) {}
  virtual void resolvesFrom(System * sys);
 
 protected:
  Expression * op1;
  Expression * op2;
};
 
class UnaryExpr: public Expression {
};
 
class Unresolved: public Expression {
 public:
  Unresolved(int _refed) : refed(_refed) {}
  int get_referenced() const { return refed; }
  virtual int value() const { throw "Internal error: asked value to an unresolved"; }
  string refedAsChars() const { char buf[512]; sprintf(buf, "%d", refed); return string(buf); }
  virtual string toString() const { return Object::toString() + " = Unresolved(" + refedAsChars() + ")"; }
 protected:
  int refed;
};
 
class Assign: public BinaryExpr {
 public:
  Assign(int _oid, Expression * _op1, Expression * _op2)
    : BinaryExpr(_oid, _op1, _op2) {}
  virtual int value() const {  throw "Internal error: asked value to an assign"; }
  virtual void compute();
  virtual void updateSystem(System * sys);
  virtual string toString() const { 
    return Object::toString() + " = Assign (#" + op1->oidAsChars() + ", #" + op2->oidAsChars() + ")"; 
  }
};
 
class Div: public BinaryExpr {
 public:
  Div(int _oid, Expression * _op1, Expression * _op2)
    : BinaryExpr(_oid, _op1, _op2) {}
  virtual int value() const;
  virtual string toString() const { 
    return Object::toString() + " = Div (#" + op1->oidAsChars() + ", #" + op2->oidAsChars() + ")"; 
  }
};
 
class Mult: public BinaryExpr {
 public:
  Mult(int _oid, Expression * _op1, Expression * _op2)
    : BinaryExpr(_oid, _op1, _op2) {}
  virtual int value() const;
  virtual string toString() const { 
    return Object::toString() + " = Mult (#" + op1->oidAsChars() + ", #" + op2->oidAsChars() + ")"; 
  }
};
 
class Plus: public BinaryExpr {
 public:
  Plus(int _oid, Expression * _op1, Expression * _op2)
    : BinaryExpr(_oid, _op1, _op2) {}
  virtual int value() const;
  virtual string toString() const { 
    return Object::toString() + " = Plus (#" + op1->oidAsChars() + ", #" + op2->oidAsChars() + ")"; 
  }
};
 
class Minus: public BinaryExpr {
 public:
  Minus(int _oid, Expression * _op1, Expression * _op2)
    : BinaryExpr(_oid, _op1, _op2) {}
  virtual int value() const;
  virtual string toString() const { 
    return Object::toString() + " = Minus (#" + op1->oidAsChars() + ", #" + op2->oidAsChars() + ")"; 
  }
};
 
class Variable : public Object{
  friend ostream & operator << (ostream & out, const Variable &);
 public:
  Variable(int _oid, string _name) : Object(_oid), name(_name) {}
  string get_name() const { return name; }
  int get_val() const { return val; }
  void set_val(int _val) { val = _val; }
  virtual void updateSystem(System * sys);
  virtual string toString() const { 
    return Object::toString() + " = Variable (" + name + ")"; 
  }
 protected:
  string name;
  int val;
};
 
class VarRef: public Expression {
 public:
  VarRef(Variable * _var) : var(_var) {}
  virtual int value() const { return var->get_val(); }
  void set_value(int _val) { var->set_val(_val); }
  virtual string toString() const { 
    return Object::toString() + " = VarRef ( " + var->get_name() + " )"; 
  }
 protected:
  Variable * var;
};
 
class Integer: public UnaryExpr {
 public:
  Integer(int _val) : val(_val) {}
  virtual int value() const { return val; }
  string valAsChars() const { char buf[512]; sprintf(buf, "%d", val); return string(buf); }
  virtual string toString() const { 
    return Object::toString() + " = Integer ( " + valAsChars() + " )"; 
  }
 protected:
  int val;
};
 
#endif
 
 
#include <assert.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <typeinfo>
 
static 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();
}
 
static void LireFichier(istream & in, vector<Rec> & recs)
{
  Rec buf;
  while (LireRec(in, buf)) {
    recs.push_back(buf);
  }
}
 
void Object::
updateSystem(System * sys)
{
  sys->addObject(this);
}
 
void Assign::
updateSystem(System * sys)
{
  Object::updateSystem(sys);
  sys->addInstruction(this);
}
 
void Variable::
updateSystem(System * sys)
{
  Object::updateSystem(sys);
  sys->addVariable(this);
}
 
void System::
addObject(Object * obj) 
  objects.push_back(obj); 
}
 
void System::
addInstruction(Expression * expr) 
  instructions.push_back(expr); 
}
 
void System::
addVariable(Variable * var) 
  variablesIndex[var->get_name()] = var; 
}
 
Object * System::
fetchOperand(int _oid)
{
  for (int i = 0; i < objects.size(); i++) {
    if (objects[i]->get_oid() == _oid) return (Object*) objects[i];
  }
  return 0;
}
 
Expression * System::
buildOperand(const char *oidAsChars)
{
  if (*oidAsChars == '#') {
    Expression * op = (Expression*)fetchOperand(atoi(oidAsChars+1));
    if (op == 0) { 
      op =  new Unresolved(atoi(oidAsChars+1)); 
    }
    return op;
  } 
  return new Integer(atoi(oidAsChars));
}
 
Object * System::
objectFromRec(const Rec & r) 
{
  int oid = atoi(r.numero+1);
  if (strcmp(r.operation, "DECLARATION") == 0) {
    string name(r.op1);
    return new Variable(oid, name);
  }
 
  // Ici, on a forcement deux operandes. 
  Expression * op1 = buildOperand(r.op1);
  Expression * op2 = buildOperand(r.op2);
 
  if (strcmp(r.operation, "AFFECTATION") == 0) {
    return new Assign(oid, op1, op2);
  }
  if (strcmp(r.operation, "PLUS") == 0) {
    return new Plus(oid, op1, op2);
  }
  if (strcmp(r.operation, "MOINS") == 0) {
    return new Minus(oid, op1, op2);
  }
  if (strcmp(r.operation, "MULT") == 0) {
    return new Mult(oid, op1, op2);
  }
  if (strcmp(r.operation, "DIV") == 0) {
    return new Div(oid, op1, op2);
  }
  throw "Unknown operation";
  return NULL;
}
 
 
void System::
readFile(string filename)
{
  ifstream istrim(filename.c_str());
  if (!istrim) throw "Unable to read input file";
  vector<Rec> recs;
  LireFichier(istrim, recs);
  for (int i = 0; i < recs.size(); i++) {
    Object * found = objectFromRec(recs[i]);
    found->updateSystem(this);
  }
  for (int i = 0; i < objects.size(); i++) {
    objects[i]->resolvesFrom(this);
  }
}
 
void System::
compute()
{
  for (int i = 0; i < instructions.size(); i++) {
    instructions[i]->compute();
  }
}
 
void System::
dumpVars() const
{
  for (map<string,Variable*>::const_iterator itor = variablesIndex.begin();
       itor != variablesIndex.end();
       itor++) {
    cout << *(*itor).second << endl;
  }
}
 
void System::
dumpObjects() const
{
  for (int i = 0; i < objects.size(); i++) {
    cout << objects[i]->toString() << endl;
  }
}
 
ostream & operator << (ostream & _out, const Variable & _var)
{
  return _out << _var.get_name() << " : " << _var.get_val();
}
 
 
void BinaryExpr::
resolvesFrom(System * sys)
{
  Expression * resolved;
  if (typeid(*op1) == typeid(Unresolved)) {
    Unresolved * unres = (Unresolved*) op1;
    resolved = (Expression*)sys->fetchOperand(unres->get_referenced());
    if (!resolved) { throw "Unable to resolve one operand"; }
    delete op1;
    op1 = resolved;
  }
  if (typeid(*op1) == typeid(Variable)) {
      op1 = new VarRef((Variable*)op1);
  }
  if (typeid(*op2) == typeid(Unresolved)) {
    Unresolved * unres = (Unresolved*) op2;
    resolved = (Expression*)sys->fetchOperand(unres->get_referenced());
    if (!resolved) { throw "Unable to resolve one operand"; }
    delete op2;
    op2 = resolved;
  }
  if (typeid(*op2) == typeid(Variable)) {
    op2 = new VarRef((Variable*)resolved);
  }
}
 
int Div::
value() const 
{
  return op1->value() / op2->value();
}
 
int Mult::
value() const 
{
  return op1->value() * op2->value();
}
 
int Plus::
value() const 
{
  return op1->value() + op2->value();
}
 
int Minus::
value() const 
{
  return op1->value() - op2->value();
}
 
void Assign::
compute()
{
  assert (typeid(*op1) == typeid(VarRef));
  VarRef * vr = (VarRef*) op1;
  vr->set_value(op2->value());
}
 
main() {
  try {
    System sys;
    sys.readFile("expr.step");
    sys.dumpObjects();
    sys.compute();
    sys.dumpVars();
  } catch (const char * err) {
    cout << err << endl;
  }
}