/** file: Exp.java  - Espressioni (con assegnamento) in java */

/**
  Interprete del linguaggio generato dalla grammatica:
        Exp   ::= Exp  + Term   | Term    (PiuExp)
        Exp   ::= Exp  - Term   | Term    (MenExp)
        Term  ::= Term * Factor | Factor  (PerExp)
        Term  ::= Term / Factor | Factor  (DivExp)
        Factor::= Num                     (NumExp)
        Factor::= Ident                   (IdentExp)
        Factor::= ( Exp )                 (NumExp)
        Factor::= sqr Factor              (SqrExp)
        Factor::= sqrt Factor             (SqrtExp)
        Factor::= inv Factor              (InvExp)
        Exp   ::= Assign                  (AssignExp)
        Assign::= Ident = Exp
          
   Gerarchia delle Classi:  ([x]=classe astratta)
     [Exp]
       +---[OpExp]
       |      +-----PiuExp
       |      +-----MenExp
       |      +-----PerExp
       |      +-----DivExp
       |      +-----AssignExp
       +---[UnExp]
       |      +-----SqrExp
       |      +-----SqrtExp
       |      +-----InvExp
       +----NumExp
       +----IdentExp
              +-----IdentRefExp
*/

/** ====================================
      CLASSI per la GERARCHIA DI "EXP"
    ==================================== */
/** "EXP" e' la classe astratta da cui vengono specializzate le
    sottoclassi di operatori, numeri e identificatori. */
abstract class Exp {
  /** Accetta un Visitor (puo' generare un'eccezione) */
  public abstract void accept(ExpVisitor v) throws Exception;
} //Exp(astratta)

/** "OpExp" e' la classe astratta (che eredita da "Exp") che serve
    da "modello" per tutti gli operatori BINARI */
abstract class OpExp extends Exp {
  /** "left" e "right" servono per puntare ai due operandi dell'
      operazione contenuta in "OpExp" (nell'istanza di una delle
      sue sottoclassi). 
      Grazie al collegamento-ritardato (late-binding) queste due
      variabili sono definite come "Exp" ma possono essere
      assegnate a un'istanza di qualsivoglia sottoclasse di "Exp".*/
  Exp left,
      right;
  /** Il costruttore salva in "left" e "right" i riferimenti 
      agli oggetti "Exp" passati (che rappresentano gli operandi).*/
  public OpExp (Exp l, Exp r) {
    left=l; 
    right=r;    // SALVA puntat.a oggetti sottostanti
  }
  
  /** Accetta un "visitor". Viene definita nelle sottoclassi. */
  public abstract void accept (ExpVisitor v);

  /** Rende l'oggetto (operando) di "sinistra" */
  public Exp left()  { return left;   }
  /** Rende l'oggetto (operando) di "destra" */
  public Exp right() { return right;  }
  /** Rende l'operazione dell'oggetto */
  public String op() { return myOp(); }

  /** Rende una stringa rappresentante l'operatore
      (viene definita nelle sottoclassi). */
  protected abstract String myOp ();
  /** Rende una rappresentazione in stringa dell'oggetto */
  public String toString() {
    return left.toString() + myOp() + right.toString();
  }
} //OpExp/** Classe per l'operazione di SOMMA */
class PiuExp extends OpExp {        // operazione +
  public PiuExp (Exp l, Exp r)      { super(l,r);           }
  public String myOp ()             { return "+";           }
  public void accept (ExpVisitor v) { v.VisitaPiuExp(this); }
}
/** Classe per l'operazione di MOLTIPLICAZIONE */
class PerExp extends OpExp {        // operazione *
  public PerExp (Exp l, Exp r)      { super (l,r);          }
  public String myOp ()             { return "*";           }
  public void accept (ExpVisitor v) { v.VisitaPerExp(this); }
}
/** Classe per l'operazione di SOTTRAZIONE */
class MenExp extends OpExp {        // operazione -
  public MenExp (Exp l, Exp r)      { super (l,r);          }
  public String myOp ()             { return "-";           }
  public void accept (ExpVisitor v) { v.VisitaMenExp(this); }
}
/** Classe per l'operazione di DIVISIONE */
class DivExp   extends OpExp {      // operazione /
  public DivExp (Exp l, Exp r)      { super(l,r);           }
  public String myOp ()             { return "/";           }
  public void accept (ExpVisitor v) { v.VisitaDivExp(this); }
}


/** "UnExp" e' la classe astratta (che eredita da "Exp") che serve
    da "modello" per tutti gli operatori UNARI  */
abstract class UnExp extends Exp {
  /** "ahead" serve per puntare all'unico operando dell'operazione
      contenuta in "UnExp" (nell'istanza di una delle sue 
      sottoclassi).  */
  Exp ahead;

  public UnExp (Exp a) {
    ahead=a;      // SALVA puntat.a oggetto sottostante
  }
  
  /** Accetta un "visitor". Viene definita nelle sottoclassi. */
  public abstract void accept (ExpVisitor v);

  /** Rende l'oggetto (operando) puntato */
  public Exp ahead()  { return ahead; }
  /** Rende l'operazione dell'oggetto */
  public String op() { return myOp(); }

  /** Rende una stringa rappresentante l'operatore
      (viene definita nelle sottoclassi). */
  protected abstract String myOp ();
  /** Rende una rappresentazione in stringa dell'oggetto */
  public String toString() {
    return myOp() + ahead.toString();
  }
} //UnExp

/** Classe per l'operazione di QUADRATO */
class SqrExp extends UnExp {        // operazione sqr
  public SqrExp (Exp a)             { super(a);             }
  public String myOp ()             { return "sqr";         }
  public void accept (ExpVisitor v) { v.VisitaSqrExp(this); }
}
/** Classe per l'operazione di RADICE QUADRATA */
class SqrtExp extends UnExp {       // operazione sqrt
  public SqrtExp (Exp a)            { super(a);             }
  public String myOp ()             { return "sqrt";        }
  public void accept (ExpVisitor v) { v.VisitaSqrtExp(this);}
}
/** Classe per l'operazione di INVERSO */
class InvExp extends UnExp {       // operazione inv
  public InvExp (Exp a)             { super(a);             }
  public String myOp ()             { return "inv";         }
  public void accept (ExpVisitor v) { v.VisitaInvExp(this); }
}


/** Classe per memorizzare un NUMERO (double).
    "NumExp" e' una sottoclasse di "Exp". */
class NumExp extends Exp {          // un numero (intero)
  /** "val" serve per mantenere memorizzato il proprio valore */
  protected double MioVal;
  public NumExp (double v)          { MioVal = v;           }
  /** Rende il valore dell'oggetto */
  public double  Val ()             { return MioVal;        }
  /** Stampa il valore (senza eventuale ".0") */
  public String toString () {   // toglie il ".0" se c'e'
    if (MioVal != Math.floor(MioVal))  // floor=approssima per difetto
      return MioVal+"";
    else {
      int IVal = (new Double(MioVal)).intValue();
      return IVal+"";
    }
  }
  public void accept(ExpVisitor v)  { v.VisitaNumExp(this); }
}

/** Classe per l'operazione di ASSEGNAZIONE */
class AssignExp extends OpExp {     // Assegnazione
  public AssignExp (Exp l, Exp r)   { super (l,r);            }
  public String myOp ()             { return "=";             }
  public void accept (ExpVisitor v) { v.VisitaAssignExp(this);}
}
/** Classe per memorizzare un IDENTIFICATORE */
class IdentExp extends Exp {
  /** Stringa per memorizzare il nome dell'indentificatore */
  protected String MioIDStr;
  public IdentExp (String v)        { MioIDStr = v;           }
  public String Val ()              { return MioIDStr;        }
  public String toString ()         { return MioIDStr;        }
  public void accept (ExpVisitor v) throws Exception
                                    { v.VisitaIdentExp(this); }
}
/** Classe per memorizzare il VALORE di un IDENTIFICATORE */
class IdentRefExp extends IdentExp {
  public IdentRefExp (String v)     { super(v);                 }
  public void accept (ExpVisitor v) throws Exception
                                    { v.VisitaIdentRefExp(this);}
}

//*FINE FILE*