Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

30
Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux

Transcript of Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Page 1: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Analyse lexicale

Généralités

Expressions rationnelles

Automates finis

Analyseurs lexicaux

Page 2: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Rôle d'un analyseur lexical

code source

lexèmes

...analyseurlexical

analyseursyntaxique

table dessymboles

Séparer l'analyse lexicale de l'analyse syntaxique

Réduire la complexité du compilateur et la complexité de conception de ces deux modules

Augmenter la flexibilité du compilateur : portabilité, maintenabilité

Augmenter l'efficacité du compilateur

Page 3: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Méthodes de construction

Utiliser un générateur d'analyseurs lexicaux (Flex)

Ecrire l'analyseur lexical dans un langage évolué

Page 4: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Lecture du code source (1/2)

On utilise un tampon de lecture cyclique en deux moitiés

Anticiper = lire quelques caractères d'avance pour décider la valeur du lexème en cours

... a = 4 * i + 1 ...

debut

fin

Une anticipation de quelques caractères suffit

Un langage où il n'y avait pas de limite à la taille de l'anticipation : PL/1

DECLARE ( ARG1, ARG2, ... , ARGn )

Il faut attendre la fin de l'expression pour savoir si DECLARE est un mot-clé ou un nom de tableau

Page 5: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Lecture du code source (2/2)... a = 4 * i + 1 ...

debut

fin

si fin atteint la fin de la première moitié

alors { charger la deuxième moitié

fin := fin + 1 }

sinon si fin atteint la fin de la deuxième moitié

alors { charger la première moitié

fin := 0 }

sinon fin := fin + 1

Page 6: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Mots et langages formelsUn mot sur un alphabet A est une suite finie de

symboles pris dans A

A peut être l'ensemble des caractères, dans ce cas les lexèmes sont des mots

alphabet mots

code ASCII { 0, 1 } caractères

analyse lexicale caractères lexèmes

analyse syntaxique lexèmes programmes

Le mot vide est noté ε, sa longueur est 0

Un langage formel est un ensemble de mots

Page 7: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Expressions rationnellesOn forme des expressions à partir des symboles (éléments de l'alphabet)

et de ε en utilisant

- l'union notée | (ou +)

- la concaténation (pas de symbole)

- l'itération notée *

On utilise souvent des opérations supplémentaires (abréviations) :+ pour l'itération au moins une fois

? pour l'option

. pour tout l'alphabet

[...] pour une union de symboles

Priorités entre opérateurs : itération, concaténation, union

Page 8: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Expressions rationnelles

Identificateurs en C

lettre = A | B | ... | Z | a | b | ... | z

chiffre = 0 | 1 | ... | 9

id = (lettre | _) (lettre | _ | chiffre)*

Nombres sans signe en C

chiffre = 0 | 1 | ... | 9

chiffres = chiffre chiffre*

frac = . chiffres

exp = (E | e) (+ | - | ε) chiffres | ε

num = (chiffres (frac | . | ε) | frac) exp

Les mêmes avec les abréviations

chiffre = 0 | 1 | ... | 9

chiffres = chiffre+

frac = . chiffres

exp = ((E | e) (+ | -) ? chiffres)?

num = (chiffres (frac | .)? | frac) exp

Page 9: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

LexèmesDéfinition des espaces blancs

delim = \b | \t | \n

ws = delim*

On dit habituellement lexème pour "catégorie de lexèmes" :

expression

lexème attribut

ws - -

if if -

else else -

id id pointeur

num num valeur

etc.

expression lexème attribut

< relop lt

<= relop le

== relop eq

!= relop ne

> relop gt

>= relop ge

Page 10: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Automates finis

Les analyseurs lexicaux utilisent des graphes appelés automates finis

- les sommets sont appelés états

- les transitions sont orientées et étiquetées

- certains états sont finaux et comportent une action

11 12 13 return(gettoken(), install)lettre_

autre

lettre | _ | chiffre

Identificateurs en C

Page 11: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Automates finis0 1 2 return(relop, lt)

<autre

Opérateurs de comparaison

5

6

8

3

10

return(relop, le)

return(relop, gt)

return(relop, ge)

return(relop, eq)

return(relop, ne)

4

7

9

=

>

==

=

!

=

autre

Page 12: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Automates finis

14

15

19chiffre autre

Nombres sans signe en C

2120

.

chiffre

16 17 18

E | e+ | - chiffre

chiffre

chiffreE | e

chiffre.

chiffre

22

23

24chiffre

autre

2625

.

chiffre

chiffre.

chiffreautre

Page 13: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Implémentation en C

Un programme C qui reconnaît dans le début d'une chaîne de caractères un des lexèmes définis par les automates

/* Recherche de l'état initial du prochain automate */

int state = 0, start = 0 ;

int lexical_value ;

int fail() {

forward = token_debut ;

switch(start) {

case 0 : start = 11 ; break ;

case 11 : start = 14 ; break ;

case 14 : start = 22 ; break ;

case 22 : recover() ; break ;

default : /* erreur */ }

return start ; }

Page 14: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

token nexttoken() {

while (1) {

switch(state) {

case 0 : c = nextchar() ;

if (c==blank||c==tab||c==newline) {

state = 0 ; debut ++ ; }

else if (c == '<') state = 1 ;

else if (c == '>') state = 4 ;

else if (c == '=') state = 7 ;

else if (c == '!') state = 9 ;

else state = fail() ;

break ;

/* ... cas 1 - 10 ... */

case 11 : c = nextchar() ;

if (isletter(c)||c=='_') state = 12 ;

else state = fail() ;

break ;

Page 15: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

case 12 : c = nextchar() ;

if (isletter(c)||c=='_') state = 12 ;

else if (isdigit(c)) state = 12 ;

else state = 13 ;

break ;

case 13 : retract(1) ; install_id() ;

return(gettoken()) ;

/* ... cas 14-26 ... */

}

}

}

Page 16: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Automates déterministes

Un automate fini est déterministe si :

- il possède au plus un état initial

- de chaque état part au plus une flèche étiquetée par un symbole donné

Exemple d'automate non déterministe :

1 2a

a

Exemple d'automate déterministe :

a | b

1 2a

ab

b

Page 17: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Automates déterministes

Un automate déterministe représentant un ensemble de mots peut être utilisé commodément pour reconnaître l'un des mots dans une chaîne de caractères : il suffit de partir de l'état initial, de suivre les flèches et de voir si l'état dans lequel on arrive est final.

Tout automate fini est équivalent à un automate fini déterministe : il existe un automate fini déterministe qui reconnaît le même langage.

Page 18: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

DéterminisationAlgorithme : on part d'un automate fini A = (Q, I, F, ). On

construit l'automate déterministe D ayant

1. comme états les parties de Q

2. comme état initial I

3. comme états finaux les parties de Q contenant au moins un élément de F

4. comme transitions les (U, a, V) si V est l'ensemble des états atteignables depuis U par une transition étiquetée a

Complexité : si A a n états, D a au plus 2n états.

Page 19: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Exemple

1 1 2 1 3a b

a

Le résultat de l'algorithme

ab

b

1 2 3a b

Un automate non déterministe

a | b

Page 20: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Généralisation

On peut admettre des transitions d'étiquette (transitions spontanées).

Pour être déterministe, un automate ne doit pas contenir de transitions spontanées.

Pour déterminiser, on adapte l'algorithme précédent :

- à l'étape 2 on prend l'ensemble des états atteignables depuis I par un chemin de transitions spontanées ;

- à l'étape 3, V est l'ensemble des états atteignables depuis U par un chemin étiqueté a

Page 21: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

La construction récursive

On peut construire un automate fini équivalent à une expression rationnelle : il reconnaît le même langage.

L'automate construit est tel que :

- il a un seul état initial i

- il a un seul état final f i

- aucune transition n'entre dans i

- aucune transition ne sort de f.

Pour et a, on prend:

a

Page 22: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

union

itération

concaténation

Page 23: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Utilisation de Flex

spécificationFlex

lex.yy.c

lexèmes

flex compilateur C

a.out

4 étapes :

- créer sous éditeur une spécification Flex (expressions rationnelles)

- traiter cette spécification par la commande flex

- compiler le programme source C obtenu

- exécuter le programme exécutable obtenu

caractères(code source)

...

Page 24: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Spécifications FlexUn programme Flex est fait de trois parties :

déclarations

%%

règles de traduction

%%

fonctions auxiliaires en C

Les règles de traduction sont de la forme

p1 { action1 }

p2 { action2 }

...

pn { actionn }

où chaque pi est une expression rationnelle et chaque action une suite d'instructions en C.

Page 25: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Exemple%{

/* Partie en langage C : définitions de constantes,

déclarations de variables globales, commentaires... */

%}

delim [ \t\n]

letter [a-zA-Z]

%%

{delim}* { /* pas d'action */ }

if { return IF ; }

then { return THEN ; }

else { return ELSE ; }

{letter}({letter}|[0-9])* { yyval = install_id() ;

return ID ; }

([0-9]+(\.[0-9]*)?|\.[0-9]+)((E|e)(\+|-)?[0-9]+)?{

yyval = install_num() ; return NUMBER ; }

Page 26: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Exemple"<" { yyval = LT ; return RELOP ; }

"<=" { yyval = LE ; return RELOP ; }

%%

install_id() {

/* fonction installant dans la table des symboles le lexème vers lequel pointe yytext et dont la longueur est yylength. Renvoie un pointeur sur l'entrée dans la table */

}

install_num() {

/* fonction calculant la valeur du lexème */

}

Page 27: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Spécifications FlexLes commentaires /* ... */ ne peuvent être insérés que dans une portion

en C :

- dans la partie déclaration, seulement entre %{ et %} ;

- dans la partie règles, seulement dans les actions ;

- dans la partie fonctions auxiliaires, n'importe où.

Dans les règles

pi { actioni }

les expressions rationnelles pi ne peuvent pas contenir d'espaces blancs (ou alors dé-spécialisés).

Dans la partie règles, si une règle commence par un espace blanc, elle est interprétée comme du langage C et est insérée dans lex.yy.c au début de la fonction qui renvoie le prochain lexème (utilisable pour déclarer des variables locales).

Page 28: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Segmentation du code sourcepar l'analyseur lexical (1/3)

L'analyseur lexical produit par Flex

- commence à chercher les lexèmes au début du code source ;

- après chaque lexème reconnu, recommence à chercher les lexèmes juste après

Exemple : si piraté est reconnu, raté n'est pas reconnu

Si aucun lexème n'est reconnu à partir d'un point du code source

l'analyseur affiche le premier caractère sur la sortie standard et recommence à chercher à partir du caractère suivant

Page 29: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Segmentation du code sourcepar l'analyseur lexical (2/3)

Si plusieurs lexèmes sont reconnus à partir d'un point du code source (conflit)

1. Deux lexèmes de longueurs différentes

C'est le plus long qui gagne

Exemple : [a-zA-Z_] [a-zA-Z_0-9]*

Page 30: Analyse lexicale Généralités Expressions rationnelles Automates finis Analyseurs lexicaux.

Segmentation du code sourcepar l'analyseur lexical (3/3)

2. Deux lexèmes de même longueur

Ils commencent au même point et terminent au même point : s'il y a conflit, c'est qu'ils sont issus de deux règles différentes. C'est la règle qui apparaît la première dans la spécification Flex qui gagne

Exemple : conflit entre [a-zA-Z_] [a-zA-Z_0-9]* et while

Mettre l'exception avant la règle

En dehors de ce cas, l'ordre des règles ne joue pas