TP 3 - Introduction à ANTLR4. Lexer

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.

ANTLR4

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.

Configuration

L'outil nécessaire pour générer du code TypeScript à partir d'ANTLR4 est écrit en Java. Pour utiliser pleinement la cible ANTLR4 TypeScript (y compris la possibilité de régénérer le code à partir d'un fichier après les modifications), un environnement d'exécution Java (JRE) doit être installé sur la machine du développeur. Le code généré lui-même utilise plusieurs fonctionnalités nouvelles de TypeScript 2.0.

Installation globale

  1. Installer une version de Java 1.6+ (on recommande 1.8+). Vous pouvez vérifier l'installation à l'aide de la commande suivante:
  2. Télécharger le runtime complet d'antlr4 pour Java, ainsi que l'archive pour JavaScript depuis ce lien. Le fichier .jar et le dossier decompressé pour JavaScript doivent etre sauvegardés dans un dossier spécial que vous devrez créer sur votre ordinateur, C:\Javalib. runtime.jpg
  3. Ajouter antlr-4.9-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.
  4. Créer 2 fichiers batch.
    1. Le fichier 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 %.
    2. Le fichier 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 %*.
  5. Ajouter le dossier C:\Javalib a la variable d'environnement PATH.
  6. Vérifier l'installation en tapant antlr4 dans le Command Prompt.

Pour plus d'informations, vous pouvez consulter ce tutoriel.

Installation pour TypeScript

  1. Créer un nouveau projet en Visual Studio Code et initialisez le fichier package.json avec la commande npm init.
  2. Installer antlr4ts en tant que dépendance d'exécution (runtime dependency) depuis le Terminal de VSCode.
    npm install antlr4ts --save
  3. Installer antlr4ts-cli en tant que dépendance de développement depuis le Terminal de VSCode.
    npm install antlr4ts-cli --save-dev
  4. Installer l'extension d'ANTLR4 depuis le navigateur web ou directement du MarketPlace de Visual Studio Code. antlr4-extension.jpg
  5. Redemarrer Visual Studio Code
  6. Ajouter un nouveau script dans le fichier package.json avec le contenu
    "scripts": {
      // ...
      "antlr4ts": "antlr4ts -visitor path/to/Alf.g4"
    }

    packagejson.jpg

  7. Configurer le fichier tsconfig.json.
    {
        "compilerOptions": {
            "target": "es2016",
            "module": "commonjs",
            "strict": true,
            "esModuleInterop": true,
            "skipLibCheck": true,
            "forceConsistentCasingInFileNames": true,
            "lib": ["es2016"],
            "moduleResolution": "node"
        }
    }
  8. Télécharger les dépendences suivantes:
    npm install --save-dev @types/node
    npm install --save-dev typescript

Vous pouvez lire plus de détails sur la configuration d'ANTLR4 pour TypeScript ici.

Lexer

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:

  • Ecrire un programme qui utilise des expressions régulières et faire correspondre ces expressions régulières à aux jetons
  • Utilisez un générateur de lexer qui reçoit les expressions régulières et écrit le lexer pour vous

Rappel - Expressions régulières

Mathematique

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)

JavaScript

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]+/;

Lexer en ANTLR4

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:

  • Lexer: les règles de lexer sont destinées à créer des objets token correspondants
  • Parser: les règles de parser sont responsables pour l'analyse du langage
  • Listener: fournit des méthodes appelées indépendamment par un objet walker fourni par ANTLR
  • Visitor: contient des méthodes qui doivent accompagner (walk) leurs enfants avec des appels de visite explicites

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();

ATTENTION! Après chaque modification dans le fichier main.js, vous devez exécuter les commandes suivantes dans le Terminal de Visual Studio Code:

  • npx tsc - pour exécuter le compilateur TypeScript
  • node main.js - pour exécuter le fichier principal JavaScript généré

Après chaque modification apportée à la grammaire (fichier Alf.g4), vous devez exécuter la commande suivante pour enregistrer les changements:

npm run antlr4ts

Exercices

  1. Traitez le tableau ci-dessous a l'aide des expressions régulières de sorte que chaque livre devienne un objet de type Book, avec les suivantes propriétés: titre (string), ISBN (number), et date de publication (string). (1p)
     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'
    ];
  2. Installez ANTLR4 globalement, ainsi que la version pour TypeScript. Attachez une capture d'écran avec l'exécution de la commande 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)
  3. Créez le programme complet présenté dans le tutoriel de ce TP (fichiers de configuration, fichier Alf.g4, fichier main.ts) et assurez-vous que son exécution est réalisée sans d'erreurs. (1p)
  4. Affichez la liste des tokens: (1p)
    1. A l'aide des fonctions pour les strings, traitez le fichier 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' }
    2. Parcourez et affichez la liste des tokens (pour chaque token, affichez son nom et sa valeur comme dans l'exemple. Indice: Pour pouvoir afficher la liste des tokens, vous devrez inspecter la classe BufferedTokenStream et choisir une méthode qui retourne cette liste. Vous aurez aussi besoin de la fonction nextToken() pour parcourir le buffer de données. (0.5)
      [{ '10': 'INT', '\n': 'NEWLINE', '20': 'INT' }
  5. Ajoutez a votre fichier 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)
  6. Utilisez votre lexer pour analyser les jetons du fichier text_and_numbers.txt. Pour chaque ligne de ce fichier affichez le texte du jeton, le type, et la ligne du fichier ou il a été trouvé. (1p)
  7. Ecrivez un lexer qui reconnaît un sous-ensemble du langage Python. Pour chaque point de cet exercice, utilisez comme exemple une chaîne quelconque correspondant au langage Python, pour voir si votre programme peut: (3p)
    1. Reconnaître les mots-clés suivants: for, if, while, else, def, break, class
    2. Reconnaître les noms des fonctions: ils commencent par une lettre ou _ et sont suivis de n'importe quelle lettre ou chiffre
    3. Reconnaître les nombres entiers
    4. Reconnaître les nombres à reels
    5. Reconnaître les variables
    6. Reconnaître les opérateurs: ( ) , ; : + - * / = % { } [ ]
  8. Utilisez le lexer de l'exercice précédent pour le fichier program.py. Ecrivez chaque type de jeton, le texte qui lui correspond et la ligne où il a été trouvé. (1p)
  9. Bonus: Modifiez le lexer de l'exercice 7 pour qu'il reconnaisse aussi des chaînes de caractères (texte encapsulé entre ” ou '). (1p)
alf/laboratoare/03.txt · Last modified: 2022/03/20 21:22 by diana.ghindaoanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0