L3/TL - TP 2 Expressions arithm etiques et arbres syntaxiques

La page est créée Antoine Thibault
 
CONTINUER À LIRE
L3/TL — TP 2
            Expressions arithmétiques et arbres syntaxiques

    L’objectif de ce TP est de continuer à se familiariser avec l’outil d’analyse syntaxique JavaCC
et d’aborder l’utilisation de l’outil JJTree. Les fichiers que vous aurez à modifier ou compléter au
cours de ce TP sont disponibles à l’adresse suivante :

                     http://circe.univ-fcomte.fr/Jerome-Voinot/TL/TP2/

1     Expressions arithmétiques
   Le fichier Arith.jj, fourni et reproduit dans la figure 1, contient des règles lexicales et
syntaxiques permettant de reconnaı̂tre des expressions arithmétiques constituées de constantes
(nombres), du symbole binaire + et du symbole n-aire ∗.

Exercice 1.1
    1. Compiler le fichier Arith.jj afin de générer les sources de l’analyseur correspondant.
    2. Définir une classe Java permettant de lancer l’analyseur d’expressions arithmétiques que
       vous venez de compiler (Indication : s’inspirer du TP précédent).
    3. Compiler l’ensemble des sources Java (analyseur et lanceur).
    4. Exécuter l’analyseur sur des exemples tels que 4 ∗ 3 + 2 ∗ 5, 4 + 5 ∗ 3 ou encore 4 + 5 ∗ 3 + 2
       et en déduire l’ensemble des expressions arithmétiques reconnues par cet analyseur.

Exercice 1.2
    1. Copier le fichier Arith.jj dans un autre dossier, en le renommant Arith2.jj.
    2. Ajouter et/ou modifier, dans le fichier Arith2.jj, les règles lexicales et syntaxiques pour
       reconnaı̂tre le symbole unaire − de négation, en plus de ceux déjà reconnus.
    3. Compiler le fichier Arith2.jj.
    4. Définir une nouvelle classe Java permettant de lancer l’analyseur généré à partir du fichier
       Arith2.jj et compiler l’ensemble des sources Java.
    5. Exécuter l’analyseur afin de vérifier qu’il reconnaı̂t bien des expressions telles que 4 ∗ 3 + −2
       mais pas les expressions telles que 4 − 3.

Exercice 1.3
    1. Remplacer dans le fichier Arith2.jj la règle syntaxique unElement par celle donnée dans
       la figure 2.
    2. Ajouter aux autres règles syntaxiques les instructions Java nécessaires à l’affichage de chaque
       opérateur au moment où celui-ci est reconnu.
    3. Vérifier que l’on obtient bien le bon affichage pour différentes expressions arithmétiques
       constituées de constantes (nombres), du symbole unaire −, du symbole binaire + et du
       symbole n-aire ∗.

                                                    1
/** Fichier Arith.jj
 *
 * Copyright (c) 2004-06 Universite de Franche-Comte
 * Auteurs : A. Giorgetti, J. Julliand, P.-A. Masson, J. Voinot
 */
PARSER_BEGIN(Arith)
public class Arith {
}
PARSER_END(Arith)
/* ----------------- Regles lexicales ------------------------ */
SKIP: {
    " "   |   "\r"    |  "\n" | "\t"
}
TOKEN: {
     < CONSTANT: (  )+ >
   | < DIGIT: ["0"-"9"] >
}
TOKEN: { /* OPERATEURS */
      < PLUS: "+" >
    | < MULT: "*" >
}
/* ---------------- Regles syntaxiques ---------------------- */
void axiome() : {} {
      unTerme() 
}
void unTerme() : {} {
      unProduit() [  unTerme() ]
}
void unProduit() : {} {
      unElement()
   (  unElement() )*
}

void unElement() : {} {
   
}

                                Fig. 1 – Fichier Arith.jj

void unElement() : { int x = 0; }{
    {
      try {
            x = Integer.parseInt(token.image);
      } catch (NumberFormatException ee) {
            System.err.println("Error: "
             + token.image + " is not a number.");
            x = 0;
      }
      System.out.println(x);
   }
}

                          Fig. 2 – Règle syntaxique unElement()

                                            2
2     Arbres syntaxiques
    Dans cette partie du TP, nous allons aborder à travers différents exercices l’utilisation de
l’outil JJTree. Cet outil prend en entrée des fichiers contenant la description d’une grammaire
pour JavaCC, des annotations de construction d’arbres et éventuellement d’autres actions. Dans le
cas du fichier Aritha.jjt, fourni et reproduit dans la figure 3, l’exécution du préprocesseur JJTree,
par la commande jjtree Aritha.jjt, génère un fichier .jj dont la traduction par JavaCC génère
un traducteur Java d’expressions arithmétiques en arbres syntaxiques.

Exercice 2.1
    1. Dans le fichier Aritha.jjt, ajouter et/ou modifier les règles lexicales et syntaxiques pour
       reconnaı̂tre aussi le symbole unaire − de négation.
    2. Exécuter le préprocesseur JJTree sur le fichier Aritha.jjt ainsi modifié.
    3. Exécuter JavaCC sur le fichier Aritha.jj produit par JJTree.
    4. Remplacer le fichier ASTunElement.java par celui qui est fourni, reproduit dans la figure 5.
    5. Ajouter le fichier Launcher.java, fourni et reproduit dans la figure 4. Il sert à lancer l’ana-
       lyseur généré à partir du fichier Aritha.jjt et à afficher l’arbre produit.
    6. Construire l’exécutable Launcher.class et l’exécuter sur quelques exemples afin de com-
       prendre son fonctionnement.

Indications sur le fonctionnement de JJTree
   – JJTree crée un nœud d’arbre par non-terminal en partie gauche d’une règle syntaxique, sauf
     si le nom de ce non-terminal est suivi de l’annotation #void.
   – JJTree crée un arbre avec n fils pour chaque non-terminal suivi d’une annotation #NonTermin (n),
     où NonTermin est le nom de ce non-terminal. Par exemple, dans la règle unTerme, JJTree
     crée un arbre de classe ASTAdd avec 2 fils, qui seront les 2 arbres construits par les 2 non-
     terminaux unProduit() et unTerme() en partie droite de règle.
   – La variable jjtThis est une référence sur le nœud courant.

                                                   3
/** Fichier Aritha.jjt
  * Copyright (c) 2004-06 Departement Informatique UFR ST
  * Auteurs : A. Giorgetti, J. Julliand, P.-A. Masson, J. Voinot
  *
  * Ce fichier decrit un petit analyseur syntaxique qui produit
  * une representation sous forme d’arbre de syntaxe abstraite (ASA)
  * d’une expression arithmetique en entree.
  *
  * L’option MULTI permet de typer les arbres par ASTNomArbre.
  * Par exemple, l’arbre annote’ avec #Add est de type ASTAdd.
  * Cette classe est creee automatiquement par JJTree
  * et est modifiable. Elle herite de la classe SimpleNode.
**/
options {
    MULTI=true;
}
PARSER_BEGIN(Aritha)
public class Aritha {}
PARSER_END(Aritha)
/** ----------------- Regles lexicales ------------------------ */
SKIP : { " "       |   "\r"   | "\n" | "\t" }
TOKEN : {
      < CONSTANT: (  )+ >
    | < DIGIT: ["0"-"9"] >
       /* OPERATEURS */
    | < PLUS: "+" >
    | < MULT: "*" >
}
/** ---------------- Regles syntaxiques --------------------- */
void axiome() #Exp() : {
    /* #Exp indique que l’analyse d’un axiome construit
      un ASA de classe ASTExp qui aura autant de fils que
      de non-terminaux en partie droite de regle. */
} {                            /* [ X ] abrege (epsilon | X) */
    [unTerme()] 
}
void unTerme() #void : {} {
       unProduit() [  unTerme() #Add(2) ]
}
void unProduit() #Mul() : {} {
       unElement()
    (  unElement() )*
}
void unElement() :
    /* La reconnaissance d’un non terminal unElement construit un ASA
      prédéfini, de classe ASTunElement. On modifie la définition de la
      classe prédéfinie ASTunElement en lui ajoutant une méthode qui
      permet de stocker la valeur du nombre reconnu. Voir le fichier
      ASTunElement.java fourni. */
{ int x = 0; } {
       
       {
           try { x = Integer.parseInt(token.image);
           } catch (NumberFormatException ee) {
               System.err.println("Error: "
                + token.image + " is not a number.");
               x = 0;
           }
           jjtThis.setValeur(x);
       }
}

                                           Fig. 3 – Fichier Aritha.jjt

                                                            4
/** Fichier Launcher.java
 *
 * Copyright (c) 2006 Universite de Franche-Comte
 * Auteurs : A. Giorgetti
 */

public class Launcher {
  public static void main(String args[]) throws Exception {
    Aritha parser = new Aritha(System.in);
    parser.Axiome();
    System.out.println("Debut arbre");
    Node racine = parser.jjtree.rootNode();
    ((SimpleNode) racine).dump(" > ");
    System.out.println("Fin arbre");
  }
}

                                Fig. 4 – Fichier Launcher.java

Exercice 2.2
  1. Ajouter dans les fichiers AST*.java et SimpleNode.java une méthode public int eval()
     qui évalue une expression.
  2. Ajouter dans Launcher un appel à cette méthode et faire afficher son résultat. Par exemple,
     l’expression 4 + 3 devra produire l’affichage :
                                    Valeur de l’expression : 7

Indications pour l’exercice 2.2 Chaque nœud construit hérite de toutes les méthodes définies
dans l’interface Node et implantées dans la classe SimpleNode (voir le fichier SimpleNode.java ou
sa documentation). Parmi ces méthodes, utiliser :
   – int jjtGetNumChildren() qui retourne le nombre de fils d’un nœud.
   – Node jjtGetChild(i) qui retourne le (i + 1)e fils d’un nœud, les fils étant numérotés de 0
      à jjtGetNumChildren() − 1.

Exercice 2.3
  1. Ajouter dans les fichiers AST*.java, SimpleNode.java et Launcher.java une méthode
     commut() de transformation des arbres en arbres commutés, selon les règles suivantes :
       commut(Entier : n) = Entier : n
       commut(Mul x1 ... xn) = Mul commut(xn) ... commut(x1)
       commut(Add x y) = Add commut(y) commut(x)
       commut(Sub x) = Sub commut(x)

Indications pour l’exercice 2.3
   – La méthode void jjtAddChild(Node n, int i) de la classe SimpleNode ajoute le fils n en
     position i, les fils étant numérotés à partir de 0.
   – Les constructeurs d’arbres
        ASTMul(ArithTreeConstants.JJTMUL) et
        ASTAdd(ArithTreeConstants.JJTADD)
     créent respectivement un arbre de classe ASTMul et ASTAdd.
   – Les constantes statiques JJTMUL et JJTADD sont définies dans le fichier ArithTreeConstants.java.

                                                5
/**
 * Fichier ASTunElement
 *
 * Copyright (c) 2004-2006 Département Informatique UFR ST
 * Auteurs : A. Giorgetti, J. Voinot
 *
 * Ce fichier a été obtenu en complétant le fichier engendré
 * automatiquement par JJTree pour définir les arbres de classe
 * ASTunElement, qui héritent des arbres de classe
 * prédéfinie SimpleNode.
 *
 * On a ajouté :
 * - un attribut valeur de type entier qui contient la valeur
 *   de l’élément,
 * - une méthode getValeur pour lire cet attribut,
 * - une méthode setValeur pour affecter cet attribut et
 * - une méthode toString pour donner une forme textuelle à ces
 *   arbres.
 */

public class ASTunElement extends SimpleNode {
  private int valeur;

    public ASTunElement(int id){
      super(id);
    }

    public int getValeur() {
      return valeur;
    }

    public void setValeur(int n) {
      valeur = n;
    }

    public String toString() {
      return "Entier : " + valeur;
    }
}

                               Fig. 5 – Fichier ASTunElement.java

                                               6
Vous pouvez aussi lire