Analyse (lexicale, syntaxique) — L3 miage Analyse lexicale

publicité
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>
Téléchargement