This shows you the differences between two versions of the page.
alf:laboratoare:04 [2020/03/07 12:24] diana.ghindaoanu |
alf:laboratoare:04 [2021/03/26 19:43] (current) diana.ghindaoanu |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== TP 4 - Lexer ====== | + | ====== TP 4 - Parser ====== |
+ | Le but de ce TP est d'introduire la notion de ''parser'' en ANTLR4. | ||
- | Un lexer est un logiciel qui transforme un texte en jetons (tokens). On peut associer cette transformation à la division d'un paragraphe dans des mots. Ce traitement est réalisé en utilisant des expressions régulières. | + | Un **parser** représente la partie d'un compilateur qui reconnaît des jetons (//tokens//) ordonnés et spécifiés par un ensemble de règles d'analyse. Cet ensemble de règles décrit un "langage" source reçu par le parser sous la forme d'instructions séquentielles du programme source, des entrées de la ligne de commande, de balises ou d'autres. |
- | Vous pouvez construire un lexer de deux façons: | + | L'analyseur généré fait correspondre les jetons d'entrée (tokens définis par le lexer) aux règles, émettant un **arbre de syntaxe abstraite (AST)**, dont on va discuter plus dans les TPs suivants. Cet arbre représente la sortie de l'analyseur. |
- | * 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 | + | |
- | ===== Expressions régulières ===== | + | {{ :alf:laboratoare:parser.png?800&nolink }} |
- | ==== 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) | | ||
+ | ===== Règles du parser ===== | ||
+ | La règle la plus simple est juste un nom de règle suivi d'une seule alternative terminée par un point-virgule, comme on l'a vu dans le TP précédent: | ||
+ | <code> | ||
+ | grammar Alf; | ||
- | ==== JavaScript ==== | + | start:; |
- | ^ 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: | + | |
- | <code javascript> | + | |
- | + | ||
- | // making a new RexEx object the standard way | + | |
- | var regex = new RegEx ("[0-9]+"); | + | |
- | + | ||
- | // making a new RegEx object using a shortcut | + | |
- | var regex = /[0-9]+/; | + | |
</code> | </code> | ||
- | ==== Fonctions ==== | + | Lorsqu'une règle se compose de plusieurs aternatives, on utilise le séparateur ''|'' pour les différencier: |
- | + | <code> | |
- | === RegEx === | + | grammar Alf; |
- | + | ||
- | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec|regex.exec(str)]]// - Recherche dans un string un sous-string qui suit l'expression régulière | + | |
- | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test|regex.test(str)]]// - Recherche dans une chaîne une sous-chaîne qui suit l'expression régulière et renvoie //true// ou //false// | + | |
- | + | ||
- | Pour plus de fonctions, lisez la [[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp|documentation RegEx complète]]. | + | |
- | + | ||
- | === String === | + | |
- | * //[[https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/split|str.split(separatorRegex, limit)]]// - Divise le string dans un array avec des éléments séparés par //separatorRegex// | + | |
- | * //[[https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/match|str.match(regex)]]// - Recherche dans le string //str// un sous-string qui respecte l'expression régulière //regex// | + | |
- | <code javascript> | + | |
- | var regex = /([0-9]+);([A-Za-z-\. ]+);([0-9]{3,4}[A-Za-z]+)/; | + | |
- | + | ||
- | var match = regex.exec ('1;ANDRONIE S. Manuela - Bianca;1220F extra text'); | + | |
- | /* | + | start: expression ';' ; |
- | match: | + | |
- | [ '1;ANDRONIE S. Manuela - Bianca;1220F', // the full match | + | |
- | '1', // the first group | + | |
- | 'ANDRONIE S. Manuela - Bianca', // the second group | + | |
- | '1220F', // the third group | + | |
- | index: 0, // the position | + | |
- | input: '1;ANDRONIE S. Manuela - Bianca;1220F extra text' ] // the full string | + | |
- | */ | + | |
+ | expression: addition | ||
+ | | subtraction | ||
+ | | multiplication | ||
+ | | division | ||
+ | ; | ||
</code> | </code> | ||
- | * //[[https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/search|str.search(regex)]]// - Recherche un sous-string en //str// qui correspond à l'expression régulière et renvoie l'index de celle-ci ou -1. | ||
- | Pour en savoir plus, lisez la [[https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String|documentation String complète]]. | ||
- | ===== Exemple de création d'un lexer ===== | + | ==== Actions et attributs ==== |
+ | Les **actions** représentent des blocs de texte écrits dans le langage de programmation cible et délimités par des accolades ''{}''. Elles sont déclenchées selon leur position dans la grammaire. | ||
- | Le lexer général ressemblerait à | + | <code> |
- | + | grammar Alf; | |
- | <code javascript> | + | |
- | var number = /^[0-9]+(\.?[0-9]*)/; | + | |
- | var whitespace = /^\s+/; | + | |
- | var identifier = /^[A-Za-z_][A-Za-z0-9_]*/; | + | |
- | + | ||
- | var str = "the text you want to lex is this one"; | + | |
- | + | ||
- | var error = false; | + | |
- | + | ||
- | var tokens = []; | + | |
- | + | ||
- | while (str.length > 0 && error === false) | + | |
- | { | + | |
- | // take each regular expression and try to match it | + | |
- | var match = []; | + | |
- | // try to match the first regular expression | + | |
- | // match number | + | |
- | match = number.exec (str); | + | |
- | if (match.length > 0) // we matched something | + | |
- | { | + | |
- | // delete the matched part from the string | + | |
- | str = str.substring (0, match[0].length); | + | |
- | // add the token | + | |
- | tokens.push ({type: 'NUMBER', value: match[0]}); | + | |
- | // go to the next while iteration | + | |
- | continue; | + | |
- | } | + | |
- | // match whitespace | + | |
- | match = whitespace.exec (str); | + | |
- | if (match.length > 0) // we matched something | + | |
- | { | + | |
- | // delete the matched part from the string | + | |
- | str = str.substring (0, match[0].length); | + | |
- | // ignore whitespace, don;t add it to the tokens | + | |
- | // go to the next while iteration | + | |
- | continue; | + | |
- | } | + | |
- | // match idetifier | + | |
- | match = identifier.exec (str); | + | |
- | if (match.length > 0) // we matched something | + | |
- | { | + | |
- | // delete the matched part from the string | + | |
- | str = str.substring (0, match[0].length); | + | |
- | // add the token | + | |
- | tokens.push ({type: 'IDENTIFIER', value: match[0]}); | + | |
- | // go to the next while iteration | + | |
- | continue; | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | console.log (tokens); | + | |
+ | declaration: type VARIABLE ';' { console.log('This is a declaration statement!'); } | ||
+ | ; | ||
+ | type : 'string' | ||
+ | | 'number' | ||
+ | | 'boolean' | ||
+ | ; | ||
</code> | </code> | ||
- | Comme vous pouvez le voir, le code est assez long pour seulement trois expressions régulières. Les langages de programmation ont un contenu plus complexe, alors c'est pourquoi nous voulons utiliser un générateur de lexer. | + | Dans la plupart des cas, les actions sont utilisées pour accéder aux attributs des tokens et aux références des regles qu'on a définies. Par exemple, dans la grammaire suivant, on va afficher pour chaque type d'expression la valeur numérique des opérants et le token pour l'opérateur: |
- | ===== Jison ===== | + | <code> |
+ | grammar Alf; | ||
- | Jason est un générateur de parser qui comprend un générateur de lexer. Pour ce TP, nous n'utiliserons que le fichier fichier.l - la partie génératrice lexer. | + | start: expression |
- | Pour plus de documentation, vous pouvez accéder au [[https://gerhobbelt.github.io/jison/|site web]] de Jison. | + | ; |
- | ==== Installation ==== | + | expression: left=expression op=MUL right=expression {if($left.text && $op.text && $right.text) console.log($left.text + ' ' + $op.text + ' ' + $right.text + ' ');} |
- | Nous devons d'abord installer Jison globalement | + | | left=expression op=DIV 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 && $op.text && $right.text) console.log($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 + ' ');} | ||
+ | | INT | ||
+ | ; | ||
- | <code bash> | + | WS : ([' ']+) -> skip; /* Skip whitespaces */ |
- | npm install -g jison-gho | + | NEWLINE : ([\r\n]+); |
+ | INT : ([0-9]+) ; | ||
+ | MUL : ('*'); | ||
+ | DIV : ('/'); | ||
+ | PLUS : ('+'); | ||
+ | MINUS : ('-'); | ||
</code> | </code> | ||
- | ==== Fichiers de jetons (tokens) et grammaire ==== | + | Tous les jetons (tokens) incluent un ensemble d'**attributs** prédéfinis, read-only, qui décrivent des propriétés utiles pour les tokens et auxquels les actions peuvent accéder a travers l'instruction ''$label.attribute'', où //label// représente le nom du jeton/de la règle et //attribute// le nom de l'attribut. |
+ | === Token Attributes === | ||
+ | * **text**: string - Le texte correspondant au jeton; peut être traduit dans un appel de fonction ''getText()''. Exemple: **%%$%%ID.text**. | ||
+ | * **type**: number - Le type du jeton (nombre entier différent de 0), tel que INT; peut être traduit dans un appel de fonction ''getType()''. Exemple: **%%$%%ID.type**. | ||
+ | * **line**: number - Le numéro de la ligne ou le jeton peut etre trouvé, commençant par 1; peut être traduit dans un appel de la fonction ''getLine()''. Exemple: **%%$ID.line%%**. | ||
+ | * **pos**: number - La position ou le premier caractère du jeton se trouve dans une ligne, commençant par 0; peut être traduit dans un appel de la fonction ''togetCharPositionInLine()''. Example: **%%$%%ID.pos**. | ||
+ | * **index**: number: L'indice général d'un token dans le flux des jetons, commençant par 0; peut être traduit dans un appel de la fonction ''getTokenIndex()''. Example: **%%$%%ID.index**. | ||
+ | * **int**: number - La valeur entière du texte d'un jeton, supposant que le texte est une valeur numerique valide; peut être traduit dans un appel de la fonction ''Integer.valueOf(text-of-token)''. Example: **%%$%%INT.int**. | ||
- | <note> | ||
- | Dans les fichier .l et .y, le caractère échappant peut être fait avec "" ou \ | ||
- | </note> | ||
- | <code jison example.l> | ||
- | /* .l example file */ | ||
+ | ===== 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: | ||
- | Letter [A-Za-z] | + | <code bash> |
- | WS \s+ | + | npm run antlr4ts |
- | + | ||
- | %% | + | |
- | + | ||
- | {Letter}+ { print(yytext, yylineno); return 'Letter'} | + | |
- | + | ||
- | {WS}+ {/* whitespace separates tokens */} | + | |
- | + | ||
- | %% | + | |
- | + | ||
- | function print(text, line) { | + | |
- | console.log('token ' + text + ' line ' + line); | + | |
- | } | + | |
</code> | </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. | ||
- | <code jison example.y> | ||
- | /* .y example file */ | ||
- | %% | + | ===== Utilisation du parser ===== |
+ | Un exemple d'utilisation du parser dans un fichier ''index.ts'': | ||
- | start:; | + | <code javascript> |
+ | import { CharStreams, CodePointCharStream, CommonTokenStream, Token } from 'antlr4ts'; | ||
+ | import { AlfLexer } from './AlfLexer.js'; | ||
+ | import { AlfParser } from './AlfParser.js'; | ||
+ | import { AlfListener } from './AlfListener.js'; | ||
+ | import { AlfVisitor } from './AlfVisitor.js'; | ||
+ | import { ParseTree } from 'antlr4ts/tree/ParseTree'; | ||
+ | import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'; | ||
- | </code> | + | 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); | ||
- | ==== Générer le lexer ==== | + | // Parse the input, where `start` is whatever entry point you defined |
- | + | let tree = parser.start(); | |
- | Pour générer le lexer, exécutez jison en utilisant les deux fichiers (example.l et example.y) | + | |
- | + | ||
- | <code bash> | + | |
- | jison example.y example.l | + | |
</code> | </code> | ||
- | Cela générera un fichier JavaScript (example.js) que vous pouvez utiliser pour diviser un texte en jetons et pour parser ce texte en utilisant les jetons et la grammaire décrits dans le fichier jison. | + | ===== Visualisation de l'arbre d'analyse ===== |
- | ==== Utilisation du lexer généré ==== | + | 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. |
- | <code javascript main.js> | + | 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. |
- | "use strict"; | + | On aura besoin aussi d'un fichier de configuration, qui nous aidera aussi à la vérification des erreurs et au processus de debug. |
- | // import the generated Parser | + | 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: |
- | var Parser = require ('./example.js').Parser; | + | - 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 }} | ||
- | // use the lexer from the generated Parser | ||
- | var lexer = new Parser ().lexer; | ||
- | // add a text to the lexer | ||
- | lexer.setInput ('alf text example'); | ||
- | var s = null; | ||
- | var tokens = []; | + | ===== Exercices ===== |
- | + | ||
- | // repeat while you get an EOF token | + | |
- | do | + | |
- | { | + | |
- | try | + | |
- | { | + | |
- | // get the next token | + | |
- | s = lexer.next (); | + | |
- | } | + | |
- | catch (e) | + | |
- | { | + | |
- | // if there is an error | + | |
- | // print the line number (lexer.yylineno+1) | + | |
- | // print the error position (lexer.showPosition ()) | + | |
- | console.log ('Error line '+(lexer.yylineno+1)+'\n'+lexer.showPosition()); | + | |
- | process.exit (-1); | + | |
- | } | + | |
- | if (s && s!== lexer.EOF) | + | |
- | { | + | |
- | // print the token (s) | + | |
- | // print the token text (lexer.yytext) | + | |
- | console.log (s+' '+lexer.yytext); | + | |
- | // add them to an array | + | |
- | tokens.push ({type: s, value: lexer.yytext}); | + | |
- | } | + | |
- | } while (s !== lexer.EOF); | + | |
- | + | ||
- | console.log (tokens); | + | |
+ | - 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 les instructions nécessaires pour la déclaration complexe des variables, selon le langage suivant: **(2p)** <code>int _var1 = 2; | ||
+ | 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. | ||
+ | - 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)** | ||
+ | - 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)** | ||
+ | - 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"; | ||
+ | (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> | |
- | ===== Exercices ===== | + | |
- | - Soit le tableau suivant: (**1p**) <code javascript> | + | |
- | var films = [ | + | |
- | 'The Shawshank Redemption,1994,9.2', | + | |
- | 'The Dark Knight,2008,9.0', | + | |
- | 'Pulp Fiction,1994,8.9', | + | |
- | 'Fight Club,1999,8.8' | + | |
- | ]; | + | |
- | </code> Pour chaque film de la liste, affichez les informations sous la forme suivante: Nom: <nom du film>, Année: <année d'apparition>, Note: <note>. Utilisez des expressions régulières pour résoudre cet exercice. | + | |
- | - Clonez [[https://github.com/UPB-FILS/alf|le depot git (git repository)]]. Entrez dans TP/TP4 et utilisez les fichiers qui sont deja la pour les exercices suivantes. Générez un lexer qui reconnaît les jetons suivants: NUMBERS - nombres, WORDS - tout texte contenant uniquement des lettres, PONCTUATION - signes de ponctuation (**2p**) | + | |
- | - Installez Jison (**0.5p**) | + | |
- | - Ecrivez le fichier alf.l (**1p**) | + | |
- | - Générez le lexer décrit dans les fichiers alf.l et alf.y à l'aide de la commande jison. (**0.5p**) | + | |
- | - Utilisez le lexer de l'exercice no.2 pour le texte //Hello, the ALF TP is from 12 PM to 2 PM.//. (**1p**) | + | |
- | - Utilisez le lexer de l'exercice no.2 pour le fichier [[https://github.com/alexandruradovici/alf2018/blob/master/TP/TP4/text_and_numbers.txt|text_and_numbers.txt]]. Affichez chaque type de jeton (token), le texte correspondant (yytext) et la ligne où le jeton est trouvé (yylineno). (**1p**) | + | |
- | - Ecrivez un lexer qui reconnaît un sous-ensemble du langage PHP. Pour chaque point de cet exercices, utilisez comme exemple une chaîne quelconque correspondant au langage PHP, pour voir si votre programme peut: (**3p**) | + | |
- | - Reconnaître les mots-clés suivants: //for//, //if//, //while//, //else//, //function// | + | |
- | - Reconnaître les identifiants : ils commencent par une lettre ou _ et sont suivis de n'importe quelle lettre ou chiffre ou _. | + | |
- | - Reconnaître les nombres entiers | + | |
- | - Reconnaître les nombres à virgule flottante | + | |
- | - Reconnaître les variables: elles commencent par un $ suivi de n'importe quelle lettre ou chiffre. | + | |
- | - Reconnaître les opérateurs: ( ) , ; + - * / = % { } | + | |
- | - Utilisez le lexer de l'exercice no.5 pour le fichier [[https://github.com/alexandruradovici/alf2018/blob/master/TP/TP4/program.php|program.php]]. Ecrire chaque type de jeton, le texte qui lui correspond et la ligne où il a été trouvé. (**1p**) | + | |
- | - Ajoutez les jetons de l'exercice 6 à un tableau d'objets. Chaque objet contiendra le type de jeton, le texte et le numéro de ligne. Écrivez ce tableau dans un fichier JSON. (indice: JSON.stringify). (**1p**) | + | |
- | - **Bonus** Modifiez l'exercice 5 pour qu'il reconnaisse les chaînes de caractères (texte encapsulé entre " ou '). (**1p**) | + | |
- | + | ||
- | + | ||
- | ==== Solutions ==== | + | |
- | + | ||
- | [[https://github.com/UPB-FILS/alf/tree/master/TP/TP4|Solutions]] | + | |
- | + | ||
- | + | ||