This shows you the differences between two versions of the page.
alf:laboratoare:04_fr_java [2023/03/27 23:39] alexandra.negoita02 created |
alf:laboratoare:04_fr_java [2023/03/28 03:27] (current) alexandra.negoita02 |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== TP 4 - Parser ====== | ====== TP 4 - Parser ====== | ||
+ | |||
+ | ====== Assignment ====== | ||
+ | <note warning> | ||
+ | Vous devez **accepter** l'assignment d'ici est travailler avec ce **repository**: [[https://classroom.github.com/a/xAFtak5C|Lab 4]] | ||
+ | </note> | ||
+ | |||
+ | |||
Le but de ce TP est d'introduire la notion de ''parser'' en ANTLR4. | Le but de ce TP est d'introduire la notion de ''parser'' en ANTLR4. | ||
Line 37: | Line 44: | ||
grammar Alf; | grammar Alf; | ||
- | declaration: type VARIABLE ';' { console.log('This is a declaration statement!'); } | + | declaration: type VARIABLE ';' { System.out.println("This is a declaration statement!"); } |
; | ; | ||
- | type : 'string' | + | type : 'String ' |
- | | 'number' | + | | 'number ' |
- | | 'boolean' | + | | 'boolean ' |
; | ; | ||
+ | VARIABLE: ([a-zA-Z]+); | ||
</code> | </code> | ||
Line 50: | Line 58: | ||
grammar Alf; | grammar Alf; | ||
- | start: expression | + | start: expression |
; | ; | ||
- | expression: left=expression op=MUL right=expression {if($left.text && $op.text && $right.text) console.log($left.text + ' ' + $op.text + ' ' + $right.text + ' ');} | + | expression: left=expression op=MUL right=expression {if(!$left.text.isEmpty() && !$op.text.isEmpty() && !$right.text.isEmpty()) System.out.println($left.text + " " + $op.text + " " + $right.text + " ");} |
- | | left=expression op=DIV right=expression {if($left.text && $op.text && $right.text) console.log($left.text + ' ' + $op.text + ' ' + $right.text + ' ');} | + | | left=expression op=DIV right=expression {if(!$left.text.isEmpty() && !$op.text.isEmpty() && !$right.text.isEmpty()) System.out.println($left.text + " " + $op.text + " " + $right.text + " ");} |
- | | left=expression op=PLUS right=expression {if($left.text && $op.text && $right.text) console.log($left.text + ' ' + $op.text + ' ' + $right.text + ' ');} | + | | left=expression op=PLUS right=expression {if(!$left.text.isEmpty() && !$op.text.isEmpty() && !$right.text.isEmpty()) System.out.println($left.text + " " + $op.text + " " + $right.text + " ");} |
- | | left=expression op=MINUS right=expression {if($left.text && $op.text && $right.text) console.log($left.text + ' ' + $op.text + ' ' + $right.text + ' ');} | + | | left=expression op=MINUS right=expression {if(!$left.text.isEmpty() && !$op.text.isEmpty() && !$right.text.isEmpty()) System.out.println($left.text + " " + $op.text + " " + $right.text + " ");} |
- | | INT | + | | INT |
; | ; | ||
Line 83: | Line 91: | ||
===== Génération du parser ===== | ===== Génération du parser ===== | ||
- | Après avoir décrit une grammaire dans un fichier ''.g4'' avec des jetons et des règles, il faut exécuter la commande suivante: | + | Après avoir décrit une grammaire dans un fichier ''.g4'' avec des jetons et des règles, il faut faire clic-droit sur le fichier et appuyer sur la commande **Generate ANTLR Recognizer**. (Pour configurer les fichiers, voir TP3) |
- | <code bash> | + | Cette commande va générer les fichiers ''.java'' correspondants, dont on va se servir pour diviser un texte en jetons et pour l'analyser a l'aide du parser. |
- | npm run antlr4ts | + | |
- | </code> | + | |
- | + | ||
- | Cette commande va générer les fichiers ''.ts'' et ''.js'' correspondants, dont on va se servir pour diviser un texte en jetons et pour l'analyser a l'aide du parser. | + | |
===== Utilisation du parser ===== | ===== Utilisation du parser ===== | ||
- | Un exemple d'utilisation du parser dans un fichier ''index.ts'': | + | Un exemple d'utilisation du parser dans un fichier ''Main.java'': |
- | <code javascript> | + | <code java> |
- | import { CharStreams, CodePointCharStream, CommonTokenStream, Token } from 'antlr4ts'; | + | // Import generated files |
- | import { AlfLexer } from './AlfLexer.js'; | + | import com.Alf.parser.AlfLexer; |
- | import { AlfParser } from './AlfParser.js'; | + | import com.Alf.parser.AlfParser; |
- | import { AlfListener } from './AlfListener.js'; | + | import org.antlr.v4.runtime.CharStreams; |
- | import { AlfVisitor } from './AlfVisitor.js'; | + | import org.antlr.v4.runtime.CommonTokenStream; |
- | import { ParseTree } from 'antlr4ts/tree/ParseTree'; | + | |
- | import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'; | + | |
- | let input: string = "1+2*4/5"; | ||
- | let inputStream: CodePointCharStream = CharStreams.fromString(input); | ||
- | let lexer: AlfLexer = new AlfLexer(inputStream); | ||
- | let tokenStream: CommonTokenStream = new CommonTokenStream(lexer); | ||
- | let parser: AlfParser = new AlfParser(tokenStream); | ||
- | // Parse the input, where `start` is whatever entry point you defined | + | public class Main { |
- | let tree = parser.start(); | + | public static void main(String[] args) { |
+ | String input = "1+2*4/5"; | ||
+ | AlfLexer lexer = new AlfLexer(CharStreams.fromString(input)); | ||
+ | AlfParser parser = new AlfParser(new CommonTokenStream(lexer)); | ||
+ | |||
+ | // Parse the input, where `start` is whatever entry point you defined | ||
+ | AlfParser.StartContext tree = parser.start(); | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
===== Visualisation de l'arbre d'analyse ===== | ===== Visualisation de l'arbre d'analyse ===== | ||
- | Dans ce TP on va ce concentrer sur la **visualisation de l'arbre** et sur sa génération pas à pas, pour comprendre comment le parser fonctionne. | + | Pour la visualisation de l'arbre d'analyse, on utilise la fontion du plug-in ANTLRv4 ''ANTLR Preview''. Clic-drot sur la premiere regle definie dans la grammaire et ecrivez en gauche le texte qu'on doit analyser. En droit, on peut voir l'arbre genere. Pour plus d'informations, voir TP3. |
- | + | ||
- | La structure de la grammaire peut etre visualisée d'une manière très intuitive à l'aide de [[https://marketplace.visualstudio.com/items?itemName=mike-lischke.vscode-antlr4|l'extension d'ANTLR4 pour VSCode]] qui a été installée dans le TP précédent. | + | |
- | On aura besoin aussi d'un fichier de configuration, qui nous aidera aussi à la vérification des erreurs et au processus de debug. | + | |
- | + | ||
- | Pour pouvoir configurer votre projet de sorte que vous puissiez visualiser la construction progressive de l'arbre d'analyse, vous devez suivre les étapes ci-dessous: | + | |
- | - Créez un nouveau projet en Visual Studio Code et assurez vous qu'il est //**le seul dossier ouvert**// | + | |
- | - Ajoutez le fichier qui contient la grammaire | + | |
- | - Créez un fichier avec l'extension ''.txt'' pour y ajouter les instructions que la grammaire doit analyser | + | |
- | - Créez un dossier spécial, appelé **.vscode** | + | |
- | - Dans le dossier ''.vscode'', créez un fichier de configuration **launch.json** avec la structure suivante: <code json> | + | |
- | { | + | |
- | "version": "0.2.0", | + | |
- | "configurations": [ | + | |
- | { | + | |
- | "name": "antlr4", | + | |
- | "type": "antlr-debug", | + | |
- | "request": "launch", | + | |
- | "input": "sample.txt", /* Le nom du fichier ou vous allez stocker les données de test */ | + | |
- | "grammar": "Alf.g4", /* Le nom du fichier de grammaire */ | + | |
- | "startRule": "start", /* Le nom de la première règle de la grammaire */ | + | |
- | "printParseTree": true, | + | |
- | "visualParseTree": true | + | |
- | } | + | |
- | ] | + | |
- | }</code> | + | |
- | - Entrez dans le fichier de grammaire et ajoutez un **Breakpoint** (il faut juste appuyer sur le point rouge derrière le numéro de la ligne) {{ :alf:laboratoare:breakpoint.jpg?500&nolink }} | + | |
- | - Dans la Palette de Commandes de la partie gauche, entrez sur la 4ème option (**Debugger**, indiqué par la flèche //rouge// dans l'image) et démarrez le Debugger en appuyant sur le bouton indiqué par la flèche verte de l'image suivante: {{ :alf:laboratoare:start-debugger.jpg?500&nolink }} | + | |
- | - Maintenant, la visualisation du ''Parse Tree'' devrait s'ouvrir à droite de la fenetre de VSCode. Pour voir la génération progressive de votre arbre d'analyse, vous devez appuyer sur le bouton **Step Into**, marqué par la fleche rouge dans l'image suivante: {{ :alf:laboratoare:step-into-tree.jpg?800&nolink }} | + | |
- | - Au fur et à mesure que vous appuyez sur **Step Into**, vous allez observer la **génération de l'arbre d'analyse** (flèche rouge), la **consommation des jetons** (flèche verte) et l'**appel des règles dans la pile** (flèche bleue) {{ :alf:laboratoare:parse-tree-generation.jpg?800&nolink }} | + | |
- | - A la fin de l'exécution, le **Parse Tree** aura la structure suivante: {{ :alf:laboratoare:parse-tree.jpg?500&nolink }} | + | |
- | + | ||
- | + | ||
+ | {{ :alf:laboratoare:antlr-tree-preview.png?600&nolink }} | ||
===== Exercices ===== | ===== Exercices ===== | ||
- | + | Pour chaque exercise, faites une capture d'ecran de l'arbre d'analyse et mettez-le dans le directoire ''ParseTree'' qui se trouve dans le Github repository. | |
- | - Suivez le tutoriel précédent (celui avec la déclaration d'une variable simple) pour la visualisation de l'arbre d'analyse. **(1p)** | + | - Ajoutez dans la grammaire d'une declaration (donnee dans le laboratoire) les instructions nécessaires pour la déclaration complexe des variables, selon le langage suivant: **(2p)** <code>int _var1 = 2; |
- | - Ajoutez dans la grammaire les instructions nécessaires pour la déclaration complexe des variables, selon le langage suivant: **(2p)** <code>int _var1 = 2; | + | |
float _var2 = 5.55; | float _var2 = 5.55; | ||
- | string _var3 = "alf"; </code> Suivez les étapes nécessaires pour visualiser l'arbre d'analyse et testez chaque règle à l'aide du fichier texte pour les données. | + | String _var3 = "alf"; </code> Suivez les étapes nécessaires pour visualiser l'arbre d'analyse et testez chaque règle à l'aide du fichier texte pour les données. |
- Ajoutez à votre grammaire des jetons et des règles pour les expressions mathématiques. Votre grammaire doit reconnaître les opérations et les opérateurs d'addition, soustraction, multiplication et division (+, -, *, /, %). Suivez les étapes nécessaires pour visualiser l'arbre d'analyse et testez la fonctionnalité du programme pour l'expression ''2+5/10-7''. **(3p)** | - Ajoutez à votre grammaire des jetons et des règles pour les expressions mathématiques. Votre grammaire doit reconnaître les opérations et les opérateurs d'addition, soustraction, multiplication et division (+, -, *, /, %). Suivez les étapes nécessaires pour visualiser l'arbre d'analyse et testez la fonctionnalité du programme pour l'expression ''2+5/10-7''. **(3p)** | ||
- Repétez l'exercice précédent en tenant compte du fait qu'une expression peut aussi contenir des variables. Comme mentionné dans le premier exercice, les variables sont de la forme ''_var1''. Vérifiez la correctitude de la grammaire en ajoutant l'expression ''15/_var1-5;'' au fichier texte pour les données.**(1p)** | - Repétez l'exercice précédent en tenant compte du fait qu'une expression peut aussi contenir des variables. Comme mentionné dans le premier exercice, les variables sont de la forme ''_var1''. Vérifiez la correctitude de la grammaire en ajoutant l'expression ''15/_var1-5;'' au fichier texte pour les données.**(1p)** | ||
- | - Ajoutez à la grammaire les jetons et les règles nécessaires pour accépter des parantheses à l'intérieur des expressions. Suivez les étapes nécessaires pour la visualisation de l'arbre et testez le programme en ajoutant l'expression ''(2+5)/3'' au fichier texte pour les données. **(1p)** | + | - Ajoutez à la grammaire les jetons et les règles nécessaires pour accépter des parantheses à l'intérieur des expressions. Suivez les étapes nécessaires pour la visualisation de l'arbre et testez le programme en ajoutant l'expression ''(2+5)/3'' au fichier texte pour les données. **(2p)** |
- Faites la grammaire accepter plus d'une expression, supposant que les expressions sont séparées par '';'', mais aussi par des lignes vides. Modifiez le contenu du fichier texte pour les données en ajoutant les expressions suivantes et visualisez l'arbre d'analyse: **(2p)** <code> | - Faites la grammaire accepter plus d'une expression, supposant que les expressions sont séparées par '';'', mais aussi par des lignes vides. Modifiez le contenu du fichier texte pour les données en ajoutant les expressions suivantes et visualisez l'arbre d'analyse: **(2p)** <code> | ||
- | string _var1 = "alf"; | + | String _var1 = "alf"; |
(2+7)/5*3; | (2+7)/5*3; | ||
</code> | </code> | ||
- **BONUS: ** Changez la grammaire pour que les variables puissent être déclarées en utilisant des expressions et visualisez l'arbre d'analyse pour l'instruction suivante: **(1.5p)** <code>int _var1 = 2 + 3 * 5;</code> | - **BONUS: ** Changez la grammaire pour que les variables puissent être déclarées en utilisant des expressions et visualisez l'arbre d'analyse pour l'instruction suivante: **(1.5p)** <code>int _var1 = 2 + 3 * 5;</code> | ||