Analyse (lexicale, syntaxique) L3 MIAGE Analyse lexicale Université de Lille, France 2014-2015
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
Rôle de l analyse lexicale Rôle de l analyse lexicale Texte source caractères découpe et regroupe les caractères d entrée en jetons ou lexèmes analyse lexicale lexèmes analyse syntaxique analyse sémantique représentation sémantique
Outils Outils pour l analyse lexicale outils théoriques : langages réguliers automates d états finis outils logiciels génériques (Lex, Flex etc)
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
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 : = : puis = "bonjour" chaîne de caractère "bon jour chaîne de caractère mais différente! caseine identificateur 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 identificateur (erroné) caseine
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
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
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
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
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)
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 n 2 pour analyser une chaîne de n lexèmes a n arrive généralement pas en pratique, mais attention!
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
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>
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.
Structure d un fichier d entrée JFLex Un fichier JFLEX 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 : un générateur d analyseurs lexicaux Le filtre JFLEX 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 JFLEX sur notre exemple.
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 JFLEX à 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.
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.
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
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é
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 est_fin = false ; public boolean est_debut = false ; public boolean est_association = false ; public boolean est_entier = false ; public boolean est_nom = 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.
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.
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.
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>") ;
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).
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>