Rappels Mise en oeuvre Analyse (lexicale, syntaxique) — L3 MIAGE Analyse lexicale Université de Lille, France 2014-2015 JFLEX Rappels Mise en oeuvre 1 Rappels Rôle de l’analyse lexicale Outils 2 Mise en oeuvre Lexème Vers l’analyseur syntaxique Codage d’un analyseur lexical 3 JFLEX JFLEX Rappels Mise en oeuvre JFLEX Rôle de l’analyse lexicale Rôle de l’analyse lexicale découpe et regroupe les caractères d’entrée en jetons ou lexèmes Texte source caractères analyse lexicale lexèmes analyse syntaxique analyse sémantique représentation sémantique Rappels Mise en oeuvre Outils Outils pour l’analyse lexicale outils théoriques : langages réguliers automates d’états finis outils logiciels génériques (Lex, Flex etc) JFLEX Rappels Mise en oeuvre Lexème 1 Rappels Rôle de l’analyse lexicale Outils 2 Mise en oeuvre Lexème Vers l’analyseur syntaxique Codage d’un analyseur lexical 3 JFLEX JFLEX Rappels Mise en oeuvre Lexème Qu’est ce qu’un lexème ? Si l’insertion d’un séparateur (e.g. espace) au milieu change le sens d’une chaîne de caractère, c’est un lexème. := affectation 6= : = : puis = "bonjour" chaîne de caractère 6= "bon jour” chaîne de caractère mais différente ! caseine identificateur 6= case ine mot clé identificateur a=a+1 = a = a + 1 : plusieurs lexèmes ! Toujours prendre le plus long préfixe possible pour effectuer la séparation des lexèmes. ... si ça ne suffit pas : régles de priorités ex : interdit de préfixer un identificateur par un mot clé : caseine : mot clé case + identificateur ine 6= identificateur (erroné) caseine JFLEX Rappels Mise en oeuvre Lexème Vocabulaire Une unité lexicale est une suite de caractères qui a une signification collective : identificateur, entier, opérateur etc Un modèle est une régle associée à une unité lexicale qui décrit l’ensemble des chaînes qui peuvent correspondre à cette unité lexicale : expression régulière On appel lexème toute suite de caractères d’une source qui concorde avec le modèle d’une unité lexicale JFLEX Rappels Mise en oeuvre Vers l’analyseur syntaxique Quelles informations transmettre à l’analyseur syntaxique ? L’analyse lexicale est la seule à travailler sur le texte source ⇒ toute information non transmise à l’analyseur syntaxique est perdue ! Descripteur de lexème : classe du lexème/unité lexicale : identificateur, entier, les mots clés etc valeur du lexème : chaîne de caractères représentant le lexème numéro de ligne/caractère de début : message d’erreur JFLEX Rappels Mise en oeuvre Vers l’analyseur syntaxique Comment transmettre les lexèmes ? unique appel à une méthode produisant une liste de lexèmes appels répétés par l’analyseur syntaxique à une méthode produisant un lexème à la fois JFLEX Rappels Mise en oeuvre Vers l’analyseur syntaxique Sous quelle forme transmettre les lexèmes ? A la sortie de l’automate effectuant l’analyse lexicale une phase de crible ou identification lexicale peut être mise en oeuvre : reconnaissance de directives de compilation élimination des symboles inutiles (espaces, commentaires) calcul des valeurs numériques ("123” → 123) reconnaissance et codage des mots clés et des identificateurs : → table des symboles : (e.g. table de hachage) une entrée par lexème : e.g. descripteur unique par identificateur enrichissement du descripteur à chaque occurrence seul le couple (classe de lexème, pointeur vers descripteur dans la table) est transmis dans le flot de lexèmes JFLEX Rappels Mise en oeuvre Codage d’un analyseur lexical Codage d’un analyseur lexical Construire et optimiser un AFD un peu modifié à la main : reconnaissance du plus long préfixe priorités (e.g. caseine : case prioritaire sur caseine) mémorisation du dernier état final traversé + sous-mot associé retour en arrière possibles → tout recommencer en cas de modification des symboles Utiliser un outil de génération d’analyseur (lex, flex, jflex etc) JFLEX Rappels Mise en oeuvre Codage d’un analyseur lexical Retour en arrière et complexité de l’analyse Reconnaissance du plus long préfixe : parfois n’abouti pas ! Exemple : aaaaa et mots reconnus par a + a? b → l’analyseur doit reconnaître 5 a successifs 1 plus long préfixe : cherche a? b 2 lire les a suivants pour voir qu’il n’y a pas de b 3 l’analyseur doit retourner dans le dernier état final rencontré (un a seul) ⇒ a reconnu comme a seul → les autres a lus doivent retourner dans le flot d’entrée 4 retourner à 1 pour les a suivants → complexité en n2 pour analyser une chaîne de n lexèmes a → n’arrive généralement pas en pratique, mais attention ! JFLEX Rappels Mise en oeuvre 1 Rappels Rôle de l’analyse lexicale Outils 2 Mise en oeuvre Lexème Vers l’analyseur syntaxique Codage d’un analyseur lexical 3 JFLEX JFLEX Rappels Mise en oeuvre Exemple Supposons que vous notiez vos contributions aux personnels de l’université dans un fichier : <Sedoglavic,200> <Voge:10> <Charpentier:200> <Je ne sais plus qui,74> <Lesmele,100> <Mahiddine,500> . Vous souhaitez écrire un programme qui transforme ce fichier en un tableau HTML : <TABLE BORDER=1> <TR> <TD>Sedoglavic</TD> <TD>200 euros</TD> </TR> <TR> <TD>Voge</TD> <TD>10 euros</TD> </TR> <TR> <TD>Charpentier</TD> <TD>200 euros</TD> </TR> <TR> <TD>Je ne sais plus qui</TD> <TD>74 euros</TD> </TR> <TR> <TD>Lesmele</TD> <TD>100 euros</TD> </TR> <TR> <TD>Mahiddine</TD> <TD>500 euros</TD> </TR> </TABLE> JFLEX Rappels Mise en oeuvre Fichiers utiles pour la mise en oeuvre Quatre fichiers sont à produire soi même : fichier de données à convertir : 2014-2015.input et wrong.input programme principal qui utilise l’analyseur lexical pour produire le code html : Contribution2HTML.java modèle JFlex pour construire l’automate de l’analyseur lexical : mytry.jflex classe des lexèmes : représentation souhaitée en sortie de l’automate : Yytoken.java (nom traditionnel) Le fichier Analyseur2Contribution.java contenant la classe de l’automate sera produit par Jflex en plus de tous les .class produits par javac. JFLEX Rappels Mise en oeuvre Structure d’un fichier d’entrée JFLex Un fichier JFL EX est composé de 3 sections séparées par %% : 1 le code utilisateur : cette section est incluse telle quelle dans le fichier java engendré. 2 les options et déclarations : cette section influence la classe engendrée. Par exemple, %class foo engendre un fichier java foo.java contenant une classe foo. 3 les règles lexicales : cette section associe à des expressions régulières une action que l’analyseur engendré effectue quand il rencontre un lexème reconnu par une de ces expressions (une telle association est une règle lexicale). JFLEX Rappels Mise en oeuvre JFLex : un générateur d’analyseurs lexicaux Le filtre JFL EX prend en entrée un fichier de description de l’analyseur lexical et engrendre un fichier Java contenant une classe implantant l’automate de l’analyseur. La méthode principale de cette classe extrait du texte source le prochain lexème. L’utilisateur doit fournir la représentation des lexèmes (cf. Yytoken infra) et le code qui les manipule (cf. Contribution2html infra). Nous allons illustrer le fonctionnement de JFL EX sur notre exemple. JFLEX Rappels Mise en oeuvre Les composantes de votre filtre Notre programme de conversion Contribution2html se base sur : un analyseur lexicale Analyseur2Contribution — implanté dans une classe java — qui va être produit par JFL EX à partir d’un fichier de description de l’analyseur ; une classe Yytoken permettant de représenter et de manipuler les lexèmes que l’analyseur lexicale vous retourne ; le format de votre fichier d’entrée : . représente la fin du fichier ; < représente le début d’une entrée ; > représente la fin d’une entrée ; : représente une séparation entre le nom et la somme. JFLEX Rappels Mise en oeuvre Description de l’analyseur lexical (fichier.jflex) : déclarations La première section est vide dans notre exemple. Dans la section des options et des déclarations, on peut spécifier le nom de notre analyseur lexical : %class Analyseur2Contribution ainsi que différentes modèles (classes de lexèmes) : Debut = \< Nom = [A-Z][a-z ]* Association = [:,] Contribution = [0-9]* Fin = \> Blanc = [ \r\n\t\f] PointFinal = \. représentant des expressions régulières décrivant les différentes classes de vos lexèmes. JFLEX Rappels Mise en oeuvre JFLEX Description de l’analyseur lexical (fichier.jflex) : régles lexicales Section des règles lexicales : on indique quoi faire lorsque l’on rencontre une chaîne de caractères reconnue par l’une de ces expressions régulières : {PointFinal } { return null ; } {Blanc} { /* les blancs sont ignor\’es */ } {Debut} { return new Yytoken(’<’) ; } {Nom} { return new Yytoken(yytext()) ; } {Association} { return new Yytoken(’:’) ; } {Contribution} { return new Yytoken(Integer.parseInt(yytext())) ; } {Fin} { return new Yytoken(’>’) ; } Par exemple, en cas de terminaison (.), le token retourné est null que notre programme de conversion Contribution2html utilisera pour sortir de sa boucle d’analyse des différents lexèmes. La classe java Yytoken le format de sortie des lexèmes reconnus par les expression régulières. Dans ce code pour chaque lexème rencontré, on retourne un objet de classe Rappels Mise en oeuvre Fichier JFLex d’entré Au final, on obtient le fichier décrivant l’analyseur lexical : %% %class Analyseur2Contribution Debut = \< Nom = [A-Z][a-z ]* Association = [:,] Contribution = [0-9]* Fin = \> Blanc = [ \r\n\t\f] PointFinal = \. %% {PointFinal } { return null ; } {Blanc} { /* les blancs sont ignor\’es */ } {Debut} { return new Yytoken(’<’) ; } {Nom} { return new Yytoken(yytext()) ; } {Association} { return new Yytoken(’:’) ; } {Contribution} { return new Yytoken(Integer.parseInt(yytext())) ; } {Fin} { return new Yytoken(’>’) ; } Notez que l’ordre dans cette dernière section défini un ordre de priorité (une chaîne de caractères décrites par plusieurs expressions régulières provoquera la première action associé JFLEX Rappels Mise en oeuvre Classe java des lexèmes : différent champs du lexèmes nécessaires Dans notre implantation, un lexèmes est donc un objet de type : public class Yytoken { public boolean public boolean public boolean public boolean public boolean est_fin est_debut est_association est_entier est_nom = = = = = false false false false false ; ; ; ; ; public int contribution = 0 ; public String nom = null ; /* les constructeurs devraient \^etre ici ..... */ } Il ne nous reste plus qu’à fournir les différents constructeurs utilisés dans l’analyseur lexical selon les cas de figure. JFLEX Rappels Mise en oeuvre JFLEX Constructeurs de lexèmes : caractères Les lexèmes se réduisant à un caractère sont de 3 types : public Yytoken(char c) { if (c==’:’) this.est_association = true ; else if (c==’<’) this.est_debut = true ; else if (c==’>’) this.est_fin= true ; } et nous n’avons pas besoin de stocker les caractères en question puisqu’ils ne sont pas utilisés/affichés. Rappels Mise en oeuvre Constructeurs de lexèmes : noms et entiers Les autres lexèmes possibles sont des chaînes de caractères qui sont soit des noms, soit converties en entiers (cf. le fichier de description de l’analyseur lexical) : public Yytoken(String corruptible) { this.est_nom = true ; this.nom = corruptible ; } public Yytoken(int montant) { this.est_entier = true ; this.contribution = montant ; } Il ne nous reste plus qu’à recoller les différents morceaux. JFLEX Rappels Mise en oeuvre JFLEX Votre programme principal proprement dit Le programme principal extrait des lexèmes grâce à la méthode yylex fourni par l’analyseur Analyseur2Contribution et les utilise. import java.io.* ; public class Contribution2HTML { public static void main(String args[]) throws Exception { Analyseur2Contribution lexer ; lexer=new Analyseur2Contribution(new BufferedReader(new FileReader(args[0]))); Yytoken token = null; System.out.println("<TABLE BORDER=1>") ; while(true) { /* on extrait le lex\‘eme suivant */ token = lexer.yylex(); if (token == null) break ; /* sa conversion se fait lors de l’affichage */ if (token.est_debut) System.out.print( "<TR>" ); else if (token.est_fin) System.out.print( "</TR>\n") ; else if(token.est_nom) System.out.print( "<TD>"+token.nom+"</TD>") ; else if(token.est_association) System.out.print( " " ); else if(token.est_entier) System.out.print("<TD>"+token.contribution+"euros</TD>" ); } System.out.println("</TABLE>") ; } } Rappels Mise en oeuvre Production du convertisseur interprétable prompt > jflex description_analyseur.jflex Reading "description_analyseur.jflex" Constructing NFA : 22 states in NFA Converting NFA to DFA : ........ 10 states before minimization, 8 states in minimized DFA Old file "Analyseur2Contribution.java" saved as "Analyseur2Contribution.java~" Writing code to "Analyseur2Contribution.java" prompt > javac Yytoken.java prompt > javac Analyseur2Contribution.java prompt > javac Contribution2HTML.java prompt > ls *.class Analyseur2Contribution.class Contribution2HTM.class Yytoken.class prompt > java Contribution2HTML 2014-15.input > 2014-15.html prompt > Dans notre exemple, nous avons insisté sur l’analyse lexicale tout en n’évoquant pas l’analyse syntaxique (l’exploitation de la syntaxe du fichier d’entrée 2014-15.input). JFLEX Rappels Mise en oeuvre JFLEX L’analyse est uniquement lexicale ! prompt > cat wrong.input <<<Voge <>, 200 . prompt > java Contribution2HTML wrong.input>wrong.html prompt > cat wrong.html <TABLE BORDER=1> <TR><TR><TR><TD>Voge </TD><TR></TR> <TD>200 euros</TD></TABLE>