This is an old revision of the document!
Ce TP est destiné à vous présenter le fonctionnement d'un lexer, son but étant de diviser un texte dans des parties identifiables, appelées jetons (tokens), comme dans l'exemple suivant.
En informatique, on va réaliser cette division à l'aide de l'outil ANTLR, spécialement créé pour traiter les textes structurés.
ANTLR (ANother Tool for Language Recognition) est un générateur d'analyseurs pour lire, traiter, exécuter ou traduire du texte structuré ou des fichiers binaires. Il est largement utilisé pour créer des langages, des outils et des frameworks. À partir d'une description de langage formel, ANTLR génère un analyseur pour ce langage qui peut automatiquement créer des arbres d'analyse, dont on va discuter dans les cours et les TPs suivants. ANTLR génère également automatiquement des arborescences qu'on peut utiliser pour visiter les nœuds de ces arbres afin d'exécuter du code spécifique à l'application.
L'outil nécessaire pour générer du code à partir d'ANTLR4 est écrit en Java. Donc, on a besoin seulement de l'archive ANTLR4 et d'un plug-in specialise pour Intelij.
.jar
doivent etre sauvegardé dans un dossier spécial que vous devrez créer sur votre ordinateur, C:\Javalib. antlr-4.11.1-complete.jar
à la variable d'environnement CLASSPATH (aussi pour les variables de systeme que pour celles de votre utilisateur). Vous pouvez lire plus sur les variables d'environnement ici. antlr4.bat
permet d'utiliser antlr4 dans la ligne de commande depuis n'importe quel fichier. Il doit contenir la commande java org.antlr.v4.Tool %.grun.bat
est utilisé pour tester le fichier d'entrée et pour afficher l'arbre d'analyse sous des formes différentes. Il doit contenir la commande java org.antlr.v4.runtime.misc.TestRig %*. antlr4
dans le Command Prompt.
"scripts": { // ... "antlr4ts": "antlr4ts -visitor path/to/Alf.g4" }
{ "compilerOptions": { "target": "es2016", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "lib": ["es2016"], "moduleResolution": "node" } }
npm install --save-dev @types/node npm install --save-dev typescript
En informatique, l'analyse lexicale, le lexing ou la tokenisation est le processus de conversion d'une séquence de caractères (comme dans un programme informatique) en une séquence de jetons (chaînes avec une signification attribuée et donc identifiée). Un programme qui effectue une analyse lexicale peut être appelé un lexer.
Un lexer est généralement combiné avec un parser, qui analysent ensemble la syntaxe des langages de programmation, des pages Web, etc. Dans ce chapitre, nous approfondirons uniquement les principes de construction d'un lexer, et nous discuterons des autres composants dans les TPs suivants.
Vous pouvez construire un lexer de deux façons:
Character | Description | Exemple |
---|---|---|
* | Zéro ou plusieurs fois | a*, (ab)* |
+ | Une ou plusieurs fois | a+, (ab)+ |
? | Zéro ou une fois | a?, (ab)? |
^ | début de string | ^ab* |
$ | fin de string | b*a$ |
. | tout symbole | . |
[ ] | Ensemble | [abc] |
\s | Espace blanc | a\sb |
[^ ] | ensemble complémentaire | [^abc] |
( ) | groupe | (abc)+ |
| | Ou | a | b, (ab) | (ba) |
Character | Description | Exemple |
---|---|---|
{n} | n fois | a{3} |
{n,m} | minimum n, maximum m | a{3,7} |
\w | alphanumérique et _ | \w |
\t | TAB | a\ta* |
\n | fin de ligne | a\nb |
\r | retour chariot | a\rb |
a(?!b) | a seulement si non suivi par b | a(?!b) |
a(?=b) | a seulement si suivi par b | a(?=b) |
( ) | group | a(ab)a |
Pour déclarer des expressions régulières, on a 2 possibilités:
// making a new RexExp object the standard way let regex = new RegExp ("[0-9]+"); // making a new RegEx object using a shortcut let regex: RegExp = /[0-9]+/;
Ayant créé le projet TypeScript + ANTLR précédent, on va y ajouter un fichier Alf.g4 avec le contenu suivant:
grammar Alf; prog:; NEWLINE : ([\r\n]+); INT : ([0-9]+);
On peut observer la définition de 2 tokens différents (à l'aide des expressions régulières), NEWLINE et INT pour les nouvelles lignes, respectivement les numéros entiers.
Après avoir créé ce fichier, on va exécuter la commande npm run antlr4ts
, qui va générer plusieurs fichiers .ts, ainsi que les fichiers .js
nécessaires:
L'étape suivante suppose la création d'un fichier main.ts où l'on doit écrire la structure du programme et gestionner le fichier d'entrée:
import { CharStreams, CodePointCharStream, CommonTokenStream } from 'antlr4ts'; import { AlfLexer } from './AlfLexer'; import { AlfParser, ProgContext } from './AlfParser'; // Create the lexer and parser let input: string = "10\n20"; 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 `prog` is whatever entry point you defined let tree:ProgContext = parser.prog();
npx tsc
- pour exécuter le compilateur TypeScriptnode main.js
- pour exécuter le fichier principal JavaScript généré
Alf.g4
), vous devez exécuter la commande suivante pour enregistrer les changements:
npm run antlr4ts
let books_array: string[] = [ 'Engineering a Compiler,9780120884780,7th February 2011', 'Modern Operating Systems 4,9780133591620,21st March 2014', 'Computer Networks,9332518742,9th January 2010' ];
antlr4
dans votre Command Prompt et une autre avec le résultat de la commande npm run antlr4ts
dans le Terminal de Visual Studio Code. (1p)Alf.tokens
créé automatiquement par ANTLR et générez un dictionnaire qui ait comme clés l'indice de vos tokens et comme valeurs leur nom. (0.5p) { '1': 'NEWLINE', '2': 'INT' }
[{ '10': 'INT', '\n': 'NEWLINE', '20': 'INT' }
Alf.g4
des expressions régulières pour les jetons suivants: WORD - tout texte contenant uniquement des lettres et PONCTUATION - différents signes de ponctuation. Utilisez le lexer créé dans l'exercice précédent pour afficher la liste des tokens pour le texte: Bonjour! Le TP d'ALF est de 8 a 10. (1p)program.py
. Ecrivez chaque type de jeton, le texte qui lui correspond et la ligne où il a été trouvé. (1p)