This is an old revision of the document!


TP 5 - Parser

Microsoft Teams: TP 5

  • username: votre username de fils.curs.pub.ro (username@stud.fils.upb.ro)
  • password: votre mot de passe de fils.curs.pub.ro

Selectez channel TP 5 - Parser et appuyez sur le boutton Join.

Les archives avec les exercices seront envoyées à l'adresse diana.ghindaoanu@stud.fils.upb.ro

Video avec les solutions

Fichier de jetons (tokens) et grammaire

Le jison se compose de deux parties: une partie de description de jetons (tokens)(fichier.l) et une partie de description de grammaire (fichier.y).

Dans les fichiers Jison (.l et .y), le caractère échappant peut être fait avec ”” ou \

example.l
Ws         \s+
Digit      [0-9]
 
%%
"-"        { return '-'; }
"+"        { return '+'; }
{Ws}       { /* empty space */ }
{Digit}+   { return 'NUMBER'; }
example.y
// when it is ambiguous, derive the left part
%left '+' '-'
 
%{
	    // javascript code
        // use this to declare global  
        // javascript code that your parser uses
%}
 
%% 
start: expr { 
                 return $$; 
            };
 
expr: expr '+' expr	{ 
				console.log ('rule expr + expr'); 
				console.log ($1 + ' + ' + $3); 
			}
      | expr '-' expr 	{ 
      				console.log ('rule expr - expr');
      				console.log ($1 + ' - ' + $3); 
      			}
      | NUMBER 	{ 
	  		console.log ('rule NUMBER');
	  		console.log ('number '+$1); 
	  		$$ = $1; 
	  	};

Actions

La forme d'une règle de grammaire est

rule: alternative1 { action statements }
      | alternative2 { action statements }
      | alternative3 { action statements }
      ...
      | alternativen { action statements };

Ici vous pouvez écrire du code JavaScript.

Les caractères spéciaux sont

  • $$ : La valeur par laquelle la règle sera remplacée
  • $1 : La valeur du premier élément de la règle (peut être la valeur d'une autre règle calculée)
  • $2 : La valeur du second élément de la règle (peut être la valeur d'une autre règle calculée)
  • $3 …
  • $n - La valeur du nème élément de la règle (peut être la valeur d'une autre règle calculée)

Si “return” est utilisé dans n'importe quelle action, cela arrêtera le parser et renverra cette valeur dans le code javascript qui a exécuté parse ().

La règle de début renvoie généralement une valeur.

Les Erreurs

Si le parser ne comprend pas un jeton ou une règle, il lancera une exception.

L'exception a le format suivant

  • message - Le message d'erreur
  • hash - Un dictionnaire contenant des informations sur l'erreur
    • text - Le texte (token) qui a provoqué l'erreur
    • token - Le jeton (token) qui a provoqué l'erreur
    • line - Le numéro de ligne où l'erreur est (en commençant par 0)
    • loc - Des détails sur la position où l'erreur est
      • first_line
      • last_line
      • first_column
      • last_column
    • expected - Une liste de jetons (tokens) attendus

Générer le parser

Pour générer le parser, exécutez jison en utilisant les fichiers .l et .y

jison example.y example.l

Cela générera un fichier JavaScript que vous pouvez utiliser pour diviser un texte en jetons et le parser en utilisant les jetons et la grammaire décrits dans le fichier jison.

Utilisation du parser généré

Pour utiliser le parser généré, importez le fichier de parser et utilisez l'objet parser. Cet objet a une fonction parse qui reçoit un string et le parse. Au moment de l'analyse, il exécute les actions définies dans le fichier jison et retourne la valeur renvoyée par l'action de règle de démarrage.

main.js
"use strict";
 
// import the generated Parser
var parser = require ('./example.js').parser;
 
// add a text to the parser
try
{
        // run the parser using a string
	parser.parse ('22+3-4+6');
}
catch (e)
{
        // display the error message and data
	console.log (e.message);
	console.log (e.hash);
}

L'arbre de parse

L'arbre d'analyse doit être généré manuellement. Cela signifie qu'au lieu de définir une valeur sur $$, nous définissons un objet qui est en fait un nœud dans l'arbre de parse.

...
 
start: expr  { 
                  return {
                    type: 'start', // type of node
                    items: [$$] // array of children - here just one
                  } 
             };
 
expr: expr '+' expr  { 
                        $$ = {
                           type: 'expr', // type of node
                           items: [$1, $2, $3] // array of children - here just one
                        } 
                     };
 
 
...

Exercises

int a <- 2;
double b <- 5.5;
string c <- "alf";
  1. Telechargez la structure du TP, disponible sur git.Écrivez les fichiers jison (.y et .l) pour la declaration des variables, qui a le format de l'exemple precedent. Attention! Vous devez compléter le fichier .l avec les règles pour les jetons, ainsi que le fichier .y qui contient la description de cette grammaire.(2p)
  2. Ajoutez dans le fichier jison les expressions mathématiques (+, -, *, /, %). Affichez le message 'No errors' si la grammaire a été analysée avec succès.(1.5)
    1. La grammaire doit refléter l'ordre mathématique (ordre d'exécution des opérations mathématiques). (1p)
    2. Pour les chaînes de caractères on ne peut utiliser que l'opérateur + (concaténation). (0.5p)
  3. Faites le calcul des expressions de l'exercice précédent. Par exemple, pour l'expression 2 + 3 * 5 , le programme doit afficher la valeur 17 apres l'analyse de la grammaire. (1.5p)
    1. S'il n'y a pas de variables, affichez le résultat. (0.5p)
    2. Si l'expression contient des variables, affichez le message: “The expression contains variables: var1, var2, var3, …”, où var1, var2 et var3 sont les noms des variables trouvées. (1p)
  4. Ajoutez les parantheses () aux expressions de l'exercice 2 et écrivez la règle pour qu'elles soient acceptées. Par exemple, pour l'expression (2 + 3) * 5 votre programme doit afficher la valeur 25.(1p)
  5. Affichez les erreurs en format texte, en donnant des explications en ce qui les concerne à l'utilisateur. (1p)
  6. Faites la grammaire accepter plus d'une expression. Les expressions sont séparées par ;. Le programme affichera la valeur de chaque expression. Les expressions seront lues à partir d'un fichier donné comme paramètre dans la ligne de commande. (1p)
  7. Pour chaque opération, affichez aussi les opérandes et l'opérateur. (1p)
    2 + 3 * 5;
    /*
    Operator: *
    Operands: 3, 5
    15
    Operator: +
    Operands: 2, 15
    17
    */
  8. Ajoutez aussi des variables booléenes et les opérations logiques ||, && et ! (ou, et et non). (1p)
  9. Bonus: Changez la grammaire pour que les variables puissent être déclarées en utilisant des expressions. (1p)
    int a <- 2 + 3 * 5;

Solutions

alf/laboratoare/05.1584979181.txt.gz · Last modified: 2020/03/23 17:59 by alexandru.radovici
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