Créer un site internet

TP6

JO_NFP121

NFP 121 - TP6

WhileL et les Visiteurs






EnoncéEnoncé

Question 1


Le pattern visiteur est puissant car en modifiant seulement les différents visiteurs, on peut réaliser 3 objectifs différents dans l'arbre des expressions:

  • Un parcours infixe et son affichage
  • Un parcours postfixe et son affichage
  • Une valuation de l'arbre des expressions


VisiteurEvaluation :


package question1;

/**
 * La classe VisiteurEvaluation permet de parcourir un arbre d'expressions et de retourner la valeur totales
 * de ses expressions.
 */
public class VisiteurEvaluation extends VisiteurParDefaut<Integer> {

    private Contexte c;
    /**
     * constructeur du VisiteurEvaluation avec un contexte c (représente la mémoire)
     */
    public VisiteurEvaluation(Contexte c) {
        this.c = c;
    }

    /**
     * La méthode de visite d'une constante c
     * @return la valeur de cette Constante
     */
    public Integer visite(Constante c) {
        return c.valeur();
    }

    /**
     * La méthode de visite d'une variable v
     * @return la valeur de cette Variable
     */
    public Integer visite(Variable v) {
        return this.c.lire(v.nom());
    }

    /**
     * La méthode de visite d'une Division d
     * @return la valeur de cette Division
     */
    public Integer visite(Division d) {
        return  d.op1().accepter(this) / d.op2().accepter(this);
    }

    /**
     * La méthode de visite d'une Addition a
     * @return la valeur de cette Addition
     */
    public Integer visite(Addition a) {
        return a.op1().accepter(this) + a.op2().accepter(this);
    }

    /**
     * La méthode de visite d'une Multiplication m
     * @return la valeur de cette Multiplication
     */
    public Integer visite(Multiplication m) {
        return  m.op1().accepter(this) * m.op2().accepter(this);
    }

    /**
     * La méthode de visite d'une Soustraction s
     * @return la valeur de cette Soustraction
     */
    public Integer visite(Soustraction s) {
        return  s.op1().accepter(this) - s.op2().accepter(this);
    }

    /**
     * Le getter du contexte de ce visiteur
     * @return Contexte du visiteur
     */

    public Contexte contexte() {
        return c;
    }

}

De même le visiteur postfixe


VisiteurPostfixe :


package question1;

public class VisiteurPostfixe extends VisiteurParDefaut<String> {

    private Contexte c;

    public VisiteurPostfixe(Contexte c) {
        this.c = c;
    }

    public String visite(Constante c) {
        return Integer.toString(c.valeur());
    }

    public String visite(Variable v) {
        return Integer.toString(c.lire(v.nom());
    }

    public String visite(Division d) {
        return "(" + d.op2().accepter(this) + "," + d.op1().accepter(this)
        + ")"+"/";
    }

    public String visite(Addition a) {
        return "(" + a.op1().accepter(this) + "," + a.op2().accepter(this)
        + ")"+"+";
    }

    public String visite(Multiplication m) {
        return "(" + m.op2().accepter(this) + "," + m.op1().accepter(this)
        + ")"+"*";
    }

    public String visite(Soustraction s) {
        return "(" + s.op2().accepter(this) + "," + s.op1().accepter(this)
        + ")"+"-";
    }

    public Contexte contexte() {
        return c;
    }

}

Exemple de test :


Test


package question1;

public class TestsACompleter extends junit.framework.TestCase{
    private Memoire m;
    private Variable i,j;
    private VisiteurExpression<Integer> ve;
    private VisiteurExpression<String>  vp,vi;

    public void setUp(){
        m  = new Memoire();
        i  = new Variable(m,"i",3);
        j = new Variable(m,"j",5);
        ve = new VisiteurEvaluation( m);
        vi = new VisiteurInfixe( m);
        vp = new VisiteurPostfixe( m);
        assertNotNull(i);assertNotNull(j);
        assertNotNull(ve);assertNotNull(vp);assertNotNull(vi);
    }

    public void testUneAddition(){
        Expression expr = new Addition(new Constante(3), new Constante(2));
        assertEquals(" 3+2 != 5 ?, curieux ",5,expr.accepter(ve).intValue());
    }

    public void testMultiplication(){
        Expression expr = new Multiplication(new Constante(3), new Constante(2));
        assertEquals(" 3*2 != 6 ?, curieux ",6,expr.accepter(ve).intValue());
    }

    public void testSoustraction(){
        Expression expr = new Soustraction(new Constante(3), new Constante(2));
        assertEquals(" 3-2 != 1 ?, curieux ",1,expr.accepter(ve).intValue());
    }

    public void testDivision(){
        Expression expr = new Division(new Constante(6), new Constante(2));
        assertEquals(" 6/2 != 3 ?, curieux ",3,expr.accepter(ve).intValue());

        try{
            new Division(i,new Constante(0)).accepter(ve);
            fail("division par zéro ? possible ");
        }catch(ArithmeticException ae){
        }
    }

    public void testVisiteurInfixe(){
        Expression expr = new Addition(new Constante(3), new Constante(2));
        assertEquals("(3 + 2) est attendu ","(3 + 2)",expr.accepter(vi));
        expr = new Addition(expr, new Constante(2));
        assertEquals("((3 + 2) + 2) est attendu ", "((3 + 2) + 2)", expr.accepter(vi));
        assertEquals("{i=3, j=5}",m.toString());
        expr = new Soustraction(expr, expr);
        assertEquals("(((3 + 2) + 2) - ((3 + 2) + 2))", expr.accepter(vi));
        expr = new Multiplication(expr, expr);
        assertEquals("((((3 + 2) + 2) - ((3 + 2) + 2)) * (((3 + 2) + 2) - ((3 + 2) + 2)))", 
		   expr.accepter(vi));
        Expression expr2 = new Division(new Constante(15), new Constante(5));
        assertEquals("(15 / 5) est attendu ","(15 / 5)", expr2.accepter(vi));
    }

    public void testVisiteurPostfixe(){
       Expression expr = new Addition(new Constante(3), new Constante(2));
	   assertEquals("(3,2)+",expr.accepter(vp));
	   expr = new Addition(expr, new Constante(2));
	   assertEquals("((3,2)+,2)+",expr.accepter(vp));
	   assertEquals("{i=3, j=5}", m.toString());
	   expr = new Soustraction(expr, expr);
	   assertEquals("(((3,2)+,2)+,((3,2)+,2)+)-", expr.accepter(vp));
	   expr = new Multiplication(new Constante(5), new Constante(3));
       assertEquals("(3,5)*", expr.accepter(vp));
       Expression expr2 = new Division(new Constante(15), new Constante(5));
       assertEquals("(5,15)/", expr2.accepter(vp));
    }
}



Question 2.1

La question 2 permettait d'écrire les méthodes de visite dans un contexte d'évaluation booléenne et de transformation en java.

Ci dessous le visiteur BoolToJava. Visiteur d'expression booléenne de transformation en java, retournant sous forme de string.


VisiteurBoolToJava :


package question2;

import question1.VisiteurExpression;

public class VisiteurBoolToJava extends VisiteurExpressionBooleenne<String> {

    private VisiteurExpression<String> ve;
    /**
     * constructeur du VisiteurBoolToJava .
     */
    public VisiteurBoolToJava(VisiteurExpression<String> ve) {
        this.ve = ve;
    }

    /**Expression booléenne vrai.
     *@return un string "true"
     */
    public String visite(Vrai v) {
        return "true";
    }

    /**Expression booléenne faux.
     *@return un string "false"
     */
    public String visite(Faux f) {
        return "false";
    }

    /**Expression booléenne Non.
     *@return un string "!(expr)"
     */
    public String visite(Non n) {
        return "!(" + n.bop().accepter(this) + ")";
    }

    /**Expression booléenne Ou.
     *@return un string "( expr1 || expr2)"
     */
    public String visite(Ou ou) {
        return "(" + ou.bop1().accepter(this) + " || " + ou.bop2().accepter(this) + ")";
    }

    /**Expression booléenne Et.
     *@return un string "( expr1 && expr2)"
     */
    public String visite(Et et) {
        return "(" + et.bop1().accepter(this) + " && " + et.bop2().accepter(this) + ")";
    }

    /**Expression booléenne Supérieur à.
     *@return un string "( expr1 > expr2)"
     */
    public String visite(Sup sup) {
        return "(" + sup.op1().accepter(ve) + " > " + sup.op2().accepter(ve) + ")";
    }

    /**Expression booléenne Egal à.
     *@return un string "( expr1 == expr2)"
     */
    public String visite(Egal eg) {
        return "(" + eg.op1().accepter(ve) + " == " + eg.op2().accepter(ve) + ")";
    }

    /**Expression booléenne Inférieur à.
     *@return un string "( expr1 < expr2)"
     */
    public String visite(Inf inf) {
        return "(" + inf.op1().accepter(ve) + " < " + inf.op2().accepter(ve) + ")";
    }

}


Question 2.2

Ci dessous le visiteur BoolEvaluation. Visiteur d'expression booléenne d'integer.


VisiteurBoolEvaluation :


package question2;

import question1.VisiteurExpression;

public class VisiteurBoolEvaluation extends VisiteurExpressionBooleenne<Boolean> {

    private VisiteurExpression<Integer> ve;
    /**
     * constructeur du VisiteurBoolEvaluation .
     */
    public VisiteurBoolEvaluation(VisiteurExpression<Integer> ve) {
        this.ve = ve;
    }

    /**Expression booléenne vrai.
     *@return true
     */
    public Boolean visite(Vrai v) {
        return true; 
    }

    /**Expression booléenne faux.
     *@return false
     */
    public Boolean visite(Faux f) {
        return false; 
    }

    /**Expression booléenne non.
     *@return !n.bop()
     */
    public Boolean visite(Non n) { 
        return ! n.bop().accepter(this); 
    }

    /**Expression booléenne ou.
     *@return ou.bop1() || ou.bop2()
     */
    public Boolean visite(Ou ou) {
        return  ou.bop1().accepter(this) || ou.bop2().accepter(this);
    }

    /**Expression booléenne et.
     *@return et.bop1() && et.bop2()
     */
    public Boolean visite(Et et) {
        return  et.bop1().accepter(this) && et.bop2().accepter(this);
    }

    /**Expression booléenne Supérieur.
     *@return sup.op1() > sup.op2()
     */
    public Boolean visite(Sup sup) {
        return  sup.op1().accepter(ve) > sup.op2().accepter(ve);
    }

    /**Expression booléenne Egal à.
     *@return eg.op1() == eg.op2()
     */
    public Boolean visite(Egal eg) {
        return  eg.op1().accepter(ve) == eg.op2().accepter(ve);
    }

    /**Expression booléenne Inférieur à.
     *@return inf.op1() < inf.op2()
     */
    public Boolean visite(Inf inf) {
        return  inf.op1().accepter(ve) < inf.op2().accepter(ve);
    }

}



Question 3.1

Le langage est construit de différentes briques à l'aide des deux questions précédentes qui sont les plus petites feuilles de l'architecture. Les éléments d'expression numerique ou booléenne dans une structure donnée forment des séquences d'instructions.
Dans notre cas toutes ces formes héritent d'une classe abstraite instruction.

 Une instruction peut être:
  • Une séquence d'instruction - contient 2 instructions
  • Une selection - constituée d'une condition et d'une ou deux instructions
  • Une affectation - qui change en mémoire la valeur(Expression numérique) d'une variable
  • Une assertion - qui comporte une condition et un message
  • Une itération - avec deux classes filles
    - l'itération "tant que"
    - l'itération "pour"

l'exercice consistait à remplir les deux visiteurs qui parcours les instructions. Le premier est un visiteur d'évaluation et le second est un visiteur de transformation en java. Chaque visiteur contient un visiteur d'expression booléenne et un visiteur d'expression numérique.

Néanmoins, quelques heures ont été nécessaires afin de bien comprendre ce langage et son fonctionnement


VisiteurInstEvaluation :


package question3;

import question1.*;
import question2.*;
/**
 * Visisteur d'instruction, chaque classe concrète possède une implémentation de la visite
 * 
 */
public class VisiteurInstEvaluation extends VisiteurInstruction<Contexte>{

    private VisiteurExpression<Integer> vi;
    private VisiteurExpressionBooleenne<Boolean> vb;

    /** Création d'un visiteur d'instructions
     * @param vi le visiteur d'expressions arithmétiques
     * @param vb le visiteur d'expression booléennes
     */
    public VisiteurInstEvaluation(VisiteurExpression<Integer> vi, VisiteurExpressionBooleenne<Boolean> vb){
        this.vi = vi;
        this.vb = vb;
    }

    /** obtention du contexte, ici celui du visiteur d'expression arithmétiques 
     * @return le contexte ici de vi(le visiteur d'expression)
     */
    public Contexte contexte(){
        return this.vi.contexte();
    }

    /** Visite d'une instance de la classe Affectation.
     * 
     * l'affectation, X = Exp, Exp est une expression arithmétique <br> 
     * <code>
     * 
     *     M,Exp -interprete-> N       <br>      
     * ________________________________<br>               
     * M, X = Exp -interprete-> M[X]=N <br>
     * </code>
     * 
     * @param a  une affectation
     * @return la mémoire résultante 
     */
    public Contexte visite(Affectation a){
        this.vi.contexte().ecrire(a.v().nom(), a.exp().accepter(this.vi));

        return this.vi.contexte();
    }

    /** Visite d'une séquence seq(I1,I2) <br>
     * <code>
     * 
     *    M,I1 -interprete-> M1        <br>
     *    M1,I2 -interprete-> M2       <br>
     * ________________________________<br>
     *    M,seq(I,I2)-interprete-> M2  <br>
     *</code>
     * 
     * @param seq  une séquence
     * @return la mémoire résultante 
     */
    public Contexte visite(Sequence seq){
        seq.i1().accepter(this);
        seq.i2().accepter(this);
        return this.vi.contexte();
    }

    /** Visiste d'une sélection si (Bexp) alors I1 sinon I2 fsi <br>
     * ou si (Bexp) alors I1 fsi <br>
     *
     * <code>
     * 
     *      M,Bexp-interprete-> vrai             <br>
     *      M,I1 -interprete-> M1                <br>
     * _________________________________________ <br>               
     * M,si(Bexp)alorsI1 sinon I2-interprete-> M1<br>
     * 
     *      M,Bexp -interprete-> faux            <br>
     *      M,I2 -interprete-> M2                <br>
     * __________________________________________<br>
     * M,si(Bexp)alorsI1 sinon I2-interprete->M2 <br>
     * </code>
     * 
     * @param sel  une sélection
     * @return la mémoire résultante 
     */
    public Contexte visite(Selection sel){
        if(sel.cond().accepter(this.vb)){
            sel.i1().accepter(this);
        }else{
            if (sel.i2() != null)  {
                sel.i2().accepter(this);
            }
        }
        return this.vi.contexte(); 
    }

    /** La boucle tantque(Bexp,I1)<br>
     * <code>
     * 
     *     M,Bexp -interprete->faux              <br>
     * _________________________________________ <br>
     * M,tantque(Bexp) faire I1-interprete-> M   <br>
     * <br>
     * M,Bexp -interprete-> vrai                          <br>
     * M,seq(I1,tantque(Bexp)faire I1)-interprete-> M1    <br>
     * ___________________________________________________<br>                 
     * M,tantque(Bexp)faire I1-interprete-> M1
     * </code>
     * 
     * @param tq  une itération de la classe tantque
     * @return la mémoire résultante 
     */
    public Contexte visite(TantQue tq){
        new Selection(tq.cond(),
            new Sequence(
                tq.i1(),
                new TantQue( tq.cond(), tq.i1() )
            )
        ).accepter(this);
        return this.vi.contexte();
    }

    /** La boucle pour(init,Bexp,inc)I1<br>
     * <code>
     * M,seq(init,tantque(Bexp)seq(I1,inc))-visite->faux <br>
     * _____________________________________________________ <br>
     * M,pour(init,Bexp,inc) faire I1-visite-> M         <br>
     * </code>
     * 
     * @param pour  une itération de la classe Pour
     * @return la mémoire résultante 
     */  
    public Contexte visite(Pour pour){

        pour.init().accepter(this);
        new TantQue(pour.cond(),
                            new Sequence(pour.i1(), pour.inc())   
                       ).accepter(this);

        
        return this.vi.contexte();

    }

    /** L'affichage<br>
     * <code>
     *     
     *    M,Exp-visite-> n                              <br>
     * ________________________________System.out.print(n)<br>                 
     * M,afficher(Exp)-visite-> M
     * </code>
     * 
     * @param a  une instruction d'affichage d'une expression arithmétique
     * @return la mémoire intacte 
     */
    public Contexte visite(Afficher a){
        System.out.println(a.exp().accepter(this.vi));
        return this.vi.contexte();
    }

    /** Une assertion, 
     * si celle-ci échoue une exception est levée, 
     * emploi de la clause <a href=http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html>
				assert</a> Expr : "un Message";
     * 
     * @param a  une assertion
     * @return la mémoire intacte 
     * @throws une exception AssertionError
     */
    public Contexte visite(Assertion a) {
        if(!a.cond().accepter(this.vb)){
            throw new AssertionError();
        }
        return this.vi.contexte(); 
    }

}

Ce qui était compliqué dans le visiteur de transformation en java, était la notion de fin d'instruction. Car les instructions qui sont des feuilles de la structure doivent avoir un ";" , or le cas de la boucle for nous montre que ce n'est pas toujours le cas.


VisiteurInstToJava :


package question3;

import java.io.*;

import question1.*;
import question2.*;

/**
 * 
 */
public class VisiteurInstToJava extends VisiteurInstruction<String> {

    private final static int TAB = 2;
    private static final String lineSeparator = System.getProperties().getProperty("line.separator");

    private VisiteurExpression<String> vi;
    private VisiteurExpressionBooleenne<String> vb;

    private int tabulations;

    /**
     * Création d'un visiteur d'instructions
     * 
     * @param vi
     *            le visiteur d'expressions arithmétiques
     * @param vb
     *            le visiteur d'expression booléennes
     * @param tabulations
     *            tabulations initiales
     */
    public VisiteurInstToJava(VisiteurExpression<String> vi, VisiteurExpressionBooleenne<String> vb, int tabulations) {
        this.vi = vi;
        this.vb = vb;
        this.tabulations = tabulations;
    }

    /**
     * Création d'un visiteur d'instructions
     * 
     * @param vi
     *            le visiteur d'expressions arithmétiques
     * @param vb
     *            le visiteur d'expression booléennes
     */
    public VisiteurInstToJava(VisiteurExpression<String> vi, VisiteurExpressionBooleenne<String> vb) {
        this(vi, vb, 0);
    }

    /**
     * obtention du contexte, ici celui du visiteur d'expression arithmétiques
     * 
     * @return le contexte ici de vi(le visiteur d'expression)
     */
    public Contexte contexte() {
        return this.vi.contexte();
    }

    /**
     * Visite d'une instance de la classe Affectation.
     * 
     * 
     * @param a
     *            une affectation
     * @return a := exp
     */
    public String visite(Affectation a) {
        return a.v().accepter(this.vi) + "=" + a.exp().accepter(this.vi);
    }

    /**
     * Visiste d'une séquence seq(I1,I2) <br>
     * 
     * @param seq
     *            une séquence
     * @return i1;i2
     */
    public String visite(Sequence seq) {
        String str = tab(0)+seq.i1().accepter(this);
        if (seq.i1() instanceof Affectation){
            str+=";";
        }
        str += tab(0)+seq.i2().accepter(this);
        
        return str;
    }

    public String visite(Selection sel) {
        String str = "if" + sel.cond().accepter(this.vb)+"{"+tab(1)+ sel.i1().accepter(this)+";"+tab(-1)+"}";
        if (sel.i2() != null) str = str +tab(0)+"else {" + tab(1)+sel.i2().accepter(this)+";"+tab(-1)+"}";
        
        return str;
    }

    
    public String visite(TantQue tq) {
       return tab(0)+"while"+ tq.cond().accepter(this.vb) +"{"+ 
                            tab(1)+tq.i1().accepter(this)  +";"+tab(-1)
                    +"}";
    }

    public String visite(Pour pour) {
        String str = tab(0)+"for(" + pour.init().accepter(this) + ";" 
                                   + pour.cond().accepter(this.vb) + ";"
                                   + pour.inc().accepter(this) + ") {" +  tab(1) + pour.i1().accepter(this);
       if (pour.i1() instanceof Affectation){
            str+=";";
        }
        str = str +tab(-1)+"}";   
       return str;
    }

    public String visite(Afficher a) {
        return "System.out.println(" + a.exp().accepter(this.vi) + ");"; 
       
    }

    public String visite(Assertion a) {
        return "assert(" + a.cond().accepter(this.vb) + ");"; 
       
    }

    private String tab(int n) {
        String str = new String();

        str = str + lineSeparator;
        for (int i = 0; i < this.tabulations + n; i++) {
            str = str + " ";
        }
        this.tabulations += n;
        return str;
    }

}



Question 3.2

Classe Pour:


package question3;

import question2.ExpressionBooleenne;

public class Pour extends Iteration {

	private Instruction init, inc;

	public Pour(Instruction init, ExpressionBooleenne cond, Instruction i1,
			Instruction inc) {
		super(cond, i1);
		this.init = init;
		this.inc = inc;
	}

	public <T> T accepter(VisiteurInstruction<T> vi) {
		return vi.visite(this);
	}

	public Instruction init() {
		return init;
	}

	public Instruction inc() {
		return inc;
	}
	
}

Méthode pour:


/** La boucle pour(init,Bexp,inc)I1<br>
     * <code>
     * M,seq(init,tantque(Bexp)seq(I1,inc))-visite->faux <br>
     * _____________________________________________________ <br>
     * M,pour(init,Bexp,inc) faire I1-visite-> M         <br>
     * </code>
     * 
     * @param pour  une itération de la classe Pour
     * @return la mémoire résultante 
     */  
    public Contexte visite(Pour pour){

        pour.init().accepter(this);
        new TantQue(pour.cond(),
                            new Sequence(pour.i1(), pour.inc())   
                       ).accepter(this);

        
        return this.vi.contexte();

    }



Question 3.3

Voir les classes de tests de la question 3.1



Conclusion, biliographie et remarques :

...

Commentaires

Ajouter un commentaire

 
×