Vous êtes sur la page 1sur 5

TP de compilation JFlex

1. Introduction
JFlex est un générateur d'analyseurs lexicaux pour Java. Il génère automatiquement un programme écrit
en Java. Cette génération se fait à partir d'un fichier de spécifications qui doit suivre une certaines
syntaxe.

Analyseur lexicale
Un analyseur lexical découpe un flot d'entrée de caractères en unités lexicales (tokens), comme par
exemple les entiers, les commentaires, les mots-clés. Ces unités lexicales correspondent à des
expressions régulières.
L'analyse lexicale correspond donc à une détection de ces unités lexicales. De plus, pour chaque unité
lexicale reconnue, on retient sa classe et sa valeur qui seront utilisés dans la construction de l'arbre de
syntaxe.

Fichier de spécification Jflex


La forme d'un fichier jflex est la suivante :

Code de l'utilisateur
%%
Options et déclarations de macros
%%
Règles lexicales

 Code de l'utilisateur
La première partie contient du code Java qui se retrouvera dans le fichier généré, copié tel quel en début
de fichier. Essentiellement, le code écrit ici contiendra des chargements de packages et de librairies.

 Options et déclarations de macros


La deuxième partie contient des directives de génération du code et des déclarations de macros qui
permettent de donner des noms à des expressions régulières. Les options permettent de passer des
arguments à l'outil Jflex. En voici quelques-unes:

 %class nom; demande à Jflex de nommer le fichier produit «nom.java». La classe contenue dans
le fichier sera elle aussi nommé «nom».
 %cup; permet d'utiliser Jflex avec CUP (générateur d'analyseurs syntaxiques).
 %line et %column; permet de compter les lignes et les colonnes dans les variables yyline et
yycolum. Cela peut être utile lorsque l'on veut indiquer où se trouve une erreur dans le fichier
d'entrée.
 %standalone; permet d'utiliser Jflex seul. Ainsi, la classe généré contiendra une fonction
main.Dans la suite du TP, on utilisera toujours cette option car pour le moment on utilisera
JFLex seul.
 %eof {
code
%eof } permet de préciser le code ou le token que l'on souhaite envoyer lorsque la fin de fichier
est rencontrée ;
 %{
code
%} le code est inséré en début de la classe générée ;
Les déclarations de macros permettent des abréviations dans la définition des règles lexicales. Par
exemple : ENTIER = [0-9] +. Ainsi on pourra utiliser par la suite l'expression régulière [0-9]+ en notant
simplement ENTIER.

 Règles lexicales
La troisième partie contient les règles basés sur des expressions régulières. Une règle à base
d'expressions régulières a pour syntaxe :
expression { action }
Les actions associés aux règles correspondent à du code java exécuté lorsque la règle s'applique.
Dans l'exemple ci-dessous, l'action est simplement d'afficher le mot ENTIER lorsque un entier est lu
dans l'entrée. L'action pourrait aussi ne comporter aucune instruction, l'analyseur boucle sans rien faire
et va chercher de nouveau une règle à appliquer.
Exemple :
Le fichier suivant produit un analyseur lexicale qui affiche ENTIER pour chaque suite de chiffres
repérée, et FLECHE pour chaque suite de caractères ‘->’ :
%%
%class exo5
%unicode
%standalone

integer=[0-9]+

%%
{integer} {System.out.println("ENTIER") ;}
"->" {System.out.println("FLECHE") ;}

Pour l’instant, on affiche juste les lexèmes, mais plus tard, on connectera JFLEX à un générateur
d’analyseur syntaxique CUP.

Les expressions régulières de jflex


Les caractères
$ | ( ) { } [ ] < > \ . * + ? ^ / " sont les caractères spéciaux de jflex pour la définition des expressions
régulières. Pour représenter un caractère qui est un caractère spécial, il faut le déspécialiser en le faisant
précéder de \, ou en l'entourant de " ". Les séquences \n \t \b \r sont appelées séquences d'échappement
et représentent respectivement newline, tab, backspace et carriage return.
Les opérateurs de composition des expressions régulières sont standards, si a et b sont des expressions
régulières :
 a|b (union) est l'expression régulière « a ou b » ;
 ab (concaténation) est l'expression régulière « a suivie de b » ;
 a* (clôture de Kleene) est l'expression régulière qui représente toute répétition de a y compris
aucune ;
 a+ (itération) est équivalente à aa*;
 a? (option) est l'expression régulière « a ou rien » ;
 a{n} répétition de l'expression régulière a n fois ;
 ( a ) la même chose que l'expression régulière a mais permet d'appliquer les opérateurs plus
aisément ;
 [^a] tout sauf l'expression régulière a.

Éléments de base des expressions régulières :


 Le caractère . représente tout caractère sauf \n ;
 Notez que pour les séquences d'échappement :
o \t : le caractère tabulation ;
o \b : le retour en arrière ;
o \n : la fin de ligne ;
o \r : le retour à la ligne ;
o Une terminaison de ligne est représentée par \n sous Unix, et par \r\n sous Windows.
 Un caractère non spécial représente ce caractère (par exemple a représente le caractère 'a') ;
 Un caractère dé-spécialisé par \ perd sa spécialisation : on représente le signe + par \+, le
guillemet par \, …
 Une classe de caractères est une suite de caractères non spécialisés et de séquences
d'échappement entre crochets. Elle représente n'importe quel caractère de cette classe. On peut
aussi définir des intervalles de caractères. Par exemple, [\ta-dAEIOU0-4] représente soit le
caractère tabulation soit un des caractères suivants : a b c d A E I O U 0 1 2 3 4 ;
 Une classe de caractères par complément est une suite de caractères non spéciaux et de
séquences d'échappement. Par exemple, [^ab] représente n'importe quel caractère sauf a ou b ;
 Une chaîne de caractères dé-spécialisés est une suite de caractères non vides sans ", ni \ entourée
de ". Elle représente exactement cette suite de caractères dé-spécialisés : tous les caractères
spéciaux (sauf \ et " qui sont interdits) perdent leur signification et sont considérés tels quels.
Par exemple, "/**" représente une balise ouvrante de commentaire Javadoc ;
 Si on a défini une macro mamacro par mamacro = <exprReg>, alors on peut utiliser mamacro
en l'entourant de { et} ;
 Le caractère espace termine l'expression régulière. C'est pourquoi, si on veut que le motif
contienne des espaces, on les écrira entre guillemets, ou à l'intérieur d'une classe de caractères.
Par exemple, les motifs [a bc] et a|" "|b|c sont équivalents.

Remarques : Les blancs et les tabulations sont ignorés par jflex pour la définition des
expressions régulières (on peut donc les utiliser pour rendre les expressions plus lisibles), sauf
quand ils sont entre guillemets ou crochets.

Règles lexicales
Cette dernière section associe à des expressions régulières une action que l'analyseur généré doit
effectuer quand il rencontre un symbole reconnu par une de ces expressions régulières. Une telle
association est appelée règle lexicale.

Syntaxe
Les expressions régulières utilisées sont celles introduites en section précédente. On peut faire
précéder une expression régulière par ^ pour spécifier que cette expression régulière ne doit être
reconnue qu'en début de ligne.
Une action est de la forme <code Java>. On associe une action à une expression.

Méthodes et champs utilisables dans les actions


jflex fournit les API suivantes :
 String yytext() retourne la portion de l'entrée qui a permis de reconnaître le symbole
courant ;
 yylength() retourne la longueur de la chaîne yytext() ;
 yyline retourne le numéro de la ligne du premier caractère de la portion de texte
reconnue (disponible si l'option %line a été utilisée) ;
 yycolumn retourne le numéro de la colonne du premier caractère de la portion de texte
(disponible si l'option %column a été utilisée).
 yyclose() : cette fonction ferme le fichier en cours d’analyse.
 yystate () : retourne l’état en cours de l’analyseur
 yybegin(int state) : change l’état de l’analyseur à state.

Travail à réaliser

Exercice1
En utilisant JFlex, générer un analyseur lexical qui affiche et compte le nombre d’entiers et de
réels dans un fichier texte
Exercice2
Ecrire une spécification JFlex permettant de calculer le nombre de consonnes, de voyelles et de
caractère de ponctuation dans un fichier
Exercice3
Ecrire une spécification JFlex permettant de calculer la moyenne des entiers rencontrés dans un
fichier
Exercice4
Écrire une spécification JFlex permettant de calculer le résultat d’une expression arithmétique.
On supposera que les opérateurs sont associatifs à gauche et qu’ils ont la même priorité
Exemple : 34+12*2=(34+12)*2=46*2=92
Exercice5
Créer un analyseur lexical qui supprime les commentaires commençant par //.
Exercice6
Écrire une spécification JFlex permettant de vérifier le bon parenthésage d’un fichier. On
supposera que l’on utilise que la paire ()
Exercice7
Écrire une spécification JFlex permettant de vérifier le bon parenthésage d’un fichier. On
supposera que l’on utilise que les paires (), [],{}

2. Les automates
L’analyse lexicale utilise des automates. Partant des expressions réguilères, JFlex procède en 3
étapes :
— construction d’un automate non détermiste (NFA = Non-deterministic Finite Automaton)
— déterminisation. : Obtention d’un premier DFA (Deterministic Finite Automaton)
— calcul d’un automate déterministe minimal
Lors de l’exécution de jflex, le nombre d’états de chacun des automates est d’ailleurs affiché.
Il est possible de visualiser les automates construits par JFlex en mode texte avec l’option --dump,
ou en mode graphique avec l’option --dot (dot/graphviz est un ensemble d’outils permettant la
visualisation de graphes)
Taper dans l’invite de commande : java –jar jflex-full-1.7.0.jar –dot exemple.txt pour compiler.
Travail à réaliser

Exercice8
Construire en utilisant JFLEX un automate pour l’ensemble de mots qui se termine par abb et
afficher l’automate à l’aide de l’outil GraphViz.

Exercice9
Donner un programme d’analyseur lexical qui simule l’automate ci-dessous.

Remarque : le nombre de + ne dépasse pas 20.

Exercice10
Construire un automate déterministe pour le langage L des identificateurs, composés d’une lettre
au moins, éventuellement suivie de chiffres, de lettres et de ‘_’, et sa longueur ne doit pas
dépasser 10 caractères.

Vous aimerez peut-être aussi