CSC4251_4252 — Compilation : du langage de haut niveau à l'assembleur

Portail informatique

Mémento JAVA

Ce mémento résume les concepts et idiomes JAVA ainsi que les patrons de conception utilisés dans le module.

Patron de conception Visiteur

Pour présenter le patron de conception Visiteur, on prend l'exemple de l'exercice CUP intitulé « Calculatrice et première visite ».

Le diagramme de classe qui suit présente la plupart des classes JAVA utilisées dans la spécification CUP (nommément, Exp, ExpAff, ExpEntier, ExpFmax, ExpOpBin, ExpVar). Pour rappel, dans un diagramme de classes, il n'est pas obligatoire de présenter toutes les classes, tous les attributs, et toutes les opérations.


Diagramme de classes pour l'exercice CUP intitulé « Calculatrice et première visite »

Avec la chaîne de caractères « max((2*21+1)/4, a=max(42, 2), b=c=4*a/42)\n », l'analyseur syntaxique exécutera la règle de production suivante :

ligne ::= expr:e {: new VisiteurCompteurOpBin(e); System.out.println("AST Eval=" + e.eval()); System.out.println(e.toPrint()); :}
Autrement dit, le caractère « \n » à la fin de la chaîne de caractères provoque la réduction de la règle de production pour une ligne (complète), et dans le code de l'action associée, un objet visiteur VisiteurCompteurOpBin est créé, qui évalue l'expression, c'est-à-dire qui exécute une visite de l'AST de l'expression. Ensuite, le nœud e est évalué avec l'instruction e.eval() pour calculer la valeur ou résultat de l'expression. Enfin, l'AST du nœud e est affiché. Cela donne l'affichage qui suit :
Reading standard input Calculatrice avec évaluation sur AST (et location) > Nombre d'opérateurs binaire = 5 AST Eval=42 ExpFmax[1/1(1)-1/41(41)] \-AstList[1/5(5)-1/40(40)] |-ExpOpBin[1/5(5)-1/15(15)](/) | |-ExpOpBin[1/5(5)-1/13(13)](+) | | |-ExpOpBin[1/6(6)-1/10(10)](*) | | | |-ExpEntier[1/6(6)-1/7(7)](2) | | | \-ExpEntier[1/8(8)-1/10(10)](21) | | \-ExpEntier[1/11(11)-1/12(12)](1) | \-ExpEntier[1/14(14)-1/15(15)](4) |-ExpAff[1/16(16)-1/28(28)] | |-ExpVar(a) | \-ExpFmax[1/18(18)-1/28(28)] | \-AstList[1/22(22)-1/27(27)] | |-ExpEntier[1/22(22)-1/24(24)](42) | \-ExpEntier[1/26(26)-1/27(27)](2) \-ExpAff[1/30(30)-1/40(40)] |-ExpVar(b) \-ExpAff[1/32(32)-1/40(40)] |-ExpVar(c) \-ExpOpBin[1/34(34)-1/40(40)](/) |-ExpOpBin[1/34(34)-1/37(37)](*) | |-ExpEntier[1/34(34)-1/35(35)](4) | \-ExpVar[1/36(36)-1/37(37)](a) \-ExpEntier[1/38(38)-1/40(40)](42)

Le diagramme de séquence qui suit présente le début de la visite de l'AST de l'expression « max((2*21+1)/4, a=max(42, 2), b=c=4*a/42)\n » avec le passage par les nœuds de ExpMax, AstList, ExpOpBin conformément à l'AST affiché ci-avant. En guise d'exercice de compréhension du patron de conception Visiteur, on lira en parallèle (i) le diagramme, (ii) l'affichage de l'AST, et (iii) le code JAVA de la solution à l'exercice CUP : l'objectif est de retrouver la première incrémentation « nbOp++ ».


Diagramme de séquence du début de la visite de l'AST de l'expression « max((2*21+1)/4, a=max(42, 2), b=c=4*a/42)\n »

Records et patron de conception Fabrique (Factory)

Records


Lors de l'analyse syntaxique, l'arbre de syntaxe abstrait est consruit avec des nœuds qui sont des instances de classes réalisant l'interface AstNode. Par ailleurs, une fois construit, ces nœuds n'ont pas vocation à être modifiés : ils sont dits « immuables », c'est-à-dire leurs attributs sont mis final en JAVA.

On se plaint souvent que JAVA est trop « verbeux ». Cet inconvénient est particulièrement visible dans le contexte de la construction d'arbres avec des nœuds immuables. Ces classes qui modélisent des tuples contiennent beaucoup de code répétitif et sujet aux erreurs : des constructeurs, des accesseurs (getXxx), ainsi que les méthodes equals, hashCode, et toString.

Depuis la version 16 de JAVA, le concept de « record » permet d'écrire simplement des tuples de données. Selon la JEP 395, les objectifs de l'introduction des records comme nouveau type de classes sont les suivants 

  • une construction orientée objet qui exprime une simple agrégation de valeurs,
  • une modélisation de données immuables plutôt que sur un comportement extensible,
  • une mise œuvre automatique des méthodes axées sur les données, telles que les égalités et les accesseurs.

Le projet MiniJAVA comprend beaucoup de classes qui sont des records :

  • pour l'analyse syntaxique, dans le paquetage phase/b_syntax, et dans l'ordre alphabétique, les classes AstList, Axiom, ExprArrayLength, ExprArrayLookup,
  • pour l'analyse sémantique, la classe phase.c_semantic.SemanticTree;
  • pour la génération de la réprésentation intermédiaire, la classe phase.d_intermediate.IntermediateRepresentation, et dans le paquetage phase.d_intermediate.ir et dans l'ordre alphabétique, les classes IRconst.java, IRlabel.java, IRtempo.java, QAssignArrayFrom.java.

Patron de conception Fabrique (Factory)


Pour ce qui concerne les records pour la construction de l'AST, c'est-à-dire pour ceux du paquetage phase/b_syntax, les attributs sont classiquement composés de trois ensembles : le label du nœud, les enfants, la position du token dans le texte analysé, puis les attributs spécifiques au nœud (par exemple, le nom de la variable pour la classe ExprIdent), et enfin les attributs repérant les enfants du nœud.

On remarque aussitôt que le passage du paramètre correspondant aux enfants du nœud de l'AST est peu pratique à écrire, par exemple :

new ExprOpBin(ExprOpBin.class.getSimpleName(), Arrays.asList(expr1, expr2), new AstLocations(), expr1, op, expr2);

C'est le rôle du patron de conception Fabrique d'aider à cette difficulté. Par exemple, dans chacune des classes des nœuds de l'AST, nous ajoutons « méthode fabrique », dont le rôle est de créer une instance de la classe. Cette méthode permet de simplifier la création d'une instance en appelant new ; on ne trouvera pas d'utilisation de new ailleurs dans le code pour créer des instances de cette classe. Par convention, le nom de cette méthode est create. Voici la méthode fabrique pour le record ExprOpBin :

public static ExprOpBin create(final Expr expr1, final EnumOper op, final Expr expr2) { return new ExprOpBin(ExprOpBin.class.getSimpleName(), Arrays.asList(expr1, expr2), new AstLocations(), expr1, op, expr2); }

Avec cette méthode fabrique, on écrite la création d'un nœud de type ExprOpBin comme suit :

RESULT = ExprOpBin.create(a, main.EnumOper.AND, z);

On devine dans le dernier extrait de code que c'est du code écrit dans la spécification CUP, donc dans le fichier src/main/resources/specifications/minijava.cup, c'est-à-dire dans un fichier écrit sans utiliser un éditeur de code JAVA, ce qui renforce l'intérêt de simplifier l'écriture de la création d'un objet.

Ce patron de conception est utilisé dans MiniJAVA de manière systématique pour les classes qui sont des records.