Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI) email:...

22
Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI) www.zegour.uuuq.com email: [email protected]

Transcript of Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI) email:...

Page 1: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Analyse lexicale

Pr ZEGOUR DJAMEL EDDINE

Ecole Supérieure d’Informatique (ESI)

www.zegour.uuuq.com

email: [email protected]

Page 2: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Analyse lexicaleTaches d‘un scanner

Grammaires Régulières et Automates finis

Implémentation des scanners

Page 3: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Taches d’un scanner

1. Délivre les symboles terminaux (unités lexicales)

i f ( x = 3 )=

Source

scanner IF, LPAR, IDENT, EQ, NUMBER, RPAR, ..., EOF

Unités lexicales

Les unités lexicales ont une structure syntaxique

ident = letter { letter | digit }.number = digit { digit }.if = "i" "f".eql = "=" "="....

2. Saute les caractères non significatifs• blancs• Caractères de tabulation• Caractères de fin de lignes (CR, LF)• Commentaires

Page 4: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Pourquoi la phase lexicale est séparée de la phase syntaxique?Entrainerait une analyse syntaxique plus compliquée(Ex. distinction difficile entre les mots clés et les identificateurs)

Statement = ident "=" Expr ";"| "if" "(" Expr ")" ... .

On doit écrire ceci comme suit

Statement = "i" ( "f" "(" Expr ")" ...| letter {letter | digit} "=" Expr ";")

Le scanner doit éliminer les caractères non significatifsCes caractères peuvent apparaître partout => conduiraient vers des grammaires très complexes)

Statement = "if" {Blank} "(" {Blank} Expr {Blank} ")" {Blank} ... .Blank = " " | "\r" | "\n" | "\t" | Comment.

Les unités lexicales peuvent être decrites à l‘aide de grammaires régulières(Plus simple et plus efficace que les grammaires à contexte libre)

Page 5: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Analyse lexicaleTaches d‘un scanner

Grammaires Régulières et Automates finis

Implémentation des scanners

Page 6: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Grammaires régulières

DéfinitionUne grammaire est dite régulière si elle peut être décrite par des productions de la forme:

A = a.A = b B.

a, b des TSA, B des NTS

Exemple Grammaire pour les identificateurs

Ident = letter| letter Rest.

Rest = letter| digit| letter Rest| digit Rest.

Ex., dérivation de xy3

Ident => letter Rest => letter letter Rest => letter letter digit

Autre définitionUne grammaire est dite régulière si elle peut être décrite par une simple non récursive production EBNF.

Exemple Grammaire pour les identificateurs

Ident = letter { letter | digit }.

Page 7: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Exemples

Peut-on transformer la grammaire suivante en une grammaire régulière?

E = T { "+" T }.T = F { "*" F }.F = id.

Après substitution de F dans T

T = id { "*" id }.

Peut-on transformer la grammaire suivante en une grammaire régulière?

E = F { "*" F }.F = id | "(" E ")".

Après substitution de F dans E

E = ( id | "(" E ")" ) { "*" ( id | "(" E ")" ) }.

Substituer E dans E ne mène à rien.Récursion centrale ne peut être éliminée.La grammaire est non régulière.

Après substitution de T dans E

E = id { "*" id } { "+" id { "*" id } }.

La grammaire est régulière

Page 8: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Limitations des grammaires régulières

Les grammaires régulières ne traitent pas les structures emboîtéesRaison : ne peut éliminer la récursion centrale!

La récursion centrale est importante dans les langages de programmation.

Class => "class" "{" ... Class ... "}"

• Expressions emboîtées

• Instructions emboîtées

• Classes emboîtées

Expr => ... "(" Expr ")" ...

Statement => "do" Statement "while" "(" Expr ")"

Solution : utilisation des grammaires à contexte libre.

Les structures lexicales sont généralement régulièresnom letter { letter | digit }nombres digit { digit }

chaînes "\"" { pas de quote } "\""

Mot-clés letter { letter }

opérateurs ">" "="

Exception: commentaires emboîtés

/* ..... /* ... */ ..... */

Le scanner doit les traiter comme casspécial

Page 9: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Expressions régulièresAutre notation pour les grammaires régulières

Définition

1. (la chaîne vide) est une expression régulière

2. Un symbole terminal est une expression régulière

3. Si et sont des expressions régulières, les expressions suivantes sont régulières:

( | )()? | ()* | | | | ...()+ | | | ...

Exemples

"w" "h" "i" "l" "e" whileletter ( letter | digit )* namesdigit+ numbers

Page 10: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Automate Fini Déterministique (DFA)

Peut être utilisé pour analyser les langages réguliers

Exemple

0 1

État final

digit

letterletter

État initial est 0 par convention

Table de transition

letter digit

s0

s1

s1 error

s1 s1

"fini", car Peut être défini explicitement

Définition

Un automate fini déterministique est un 5 tuple (S, I, , s0, F)

• S Ensemble des états• I Ensemble des symboles d‘entrée• : S x I S Fonction de transition des états• s0 État initial• F Ensemble des états finaux

Un DFA reconnaît une phrase (sentence)• S‘il est dans un état final• Et il n‘y a plus de symboles d‘entrée Ou il n‘ y a pas de transition possible avec le prochain symbole d‘entrée

Le langage reconnu par une DFA estl‘ensemble de toutes les séquences desymboles pouvant être générées de l‘état initial vers l‘un des états finaux.

Page 11: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Le Scanner comme un DFALe scanner peut être vu comme un grand DFA

0

" "

1letter

letter

digit

2digit digit

3(

4>

5=

...

Exemple

Entrée: max >= 30

s0 s1m a x • Pas de transition avec " " dans s1

• ident reconnu

> =s0 s5 • Saute les blancs au début

• Ne s‘arrête pas en s4• Pas de transition avec " " dans s5• geq reconnu

s0 s23 0 • Saute les blancs au début

• Pas de transition avec " " dans s2• number reconnu

Après chaque unité lexicale reconnue le scanner recommence à l‘état initial s0

ident

number

lpar

gtr geq

Page 12: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Transformation: grammaire régulière vers DFA

Une grammaire régulière peut être transformée en un DFA comme suit

A = b C. A Cb

A = d. A dstop

Exemple

Grammaire

A = a B | b C | c.B = b B | c.C = a C | c.

Automate

A Ba

Cb

stopc

ac

bc

Page 13: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Automate Fini Non Déterministique (NDFA)

Exemple

0 1digit

2digit

digit

hex

H3

intNum

hexNum

intNum = digit { digit }.hexNum = digit { hex } "H".digit = "0" | "1" | ... | "9".hex = digit | "A" | ... | "F".

Non déterministique carIl y a 2 possibles transitionsavec digit dans s0

Chaque NDFA peut être transformé en un DFA équivalent

0 1digit2A,B,C,D,E,F

digit hex

H3

intNum

hexNum

H

Page 14: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Implémentation d‘un DFA (Variante 1)

Implémentation de comme une matrice

int[,] delta = new int[maxStates, maxSymbols];int lastState, state = 0; // DFA starts in state 0do {

int sym = next symbol;lastState = state;state = delta[state, sym];

} while (state != undefined);assert(lastState in F); // F is set of final statesreturn recognizedToken[lastState];

Exemple pour

0 2a 1 c

b

A = a { b } c.

A

a b c

0 1 - -1 - 1 22 - - - F

int[,] delta = { {1, -1, -1}, {-1, 1, 2}, {-1, -1, -1} };

Cette implémentation pourrait être très inefficace pour un véritable scanner

Page 15: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Implémentation d‘un DFA (Variante 2)

0 2a 1 c

b A

Coder les états dans le code source

int state = 0;loop:

for (;;) {char ch = read();switch (state) {

case 0: if (ch == 'a') { state = 1; break; } else break loop;

case 1: if (ch == 'b') { state = 1; break; }else if (ch == 'c') { state = 2; break; }else break loop;

case 2: return A;}

}return errorToken;

en Java c‘est plus fatiguant:

char ch = read();s0: if (ch == 'a') { ch = read(); goto s1; }

else goto err;s1: if (ch == 'b') { ch = read(); goto s1; }

else if (ch == 'c') { ch = read(); goto s2; }else goto err;

s2: return A;err: return errorToken;

Page 16: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Analyse lexicaleTaches d‘un scanner

Grammaires Régulières et Automates finis

Implémentation des scanners

Page 17: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Interface du Scanner

class Scanner {static void Init (TextReader r) {...}static Token Next () {...}

}

Scanner.Init(new StreamReader("myProg.zs"));

Initialisation du scanner

Token t;for (;;) {

t = Scanner.Next();...

}

Lecture des unités lexicales

Page 18: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Unités lexicales

class Token { public const int NONE = 0, IDENT = 1, ….

int kind; // token codeint line; // token line (for error messages)int col; // token column (for error messages)int val; // token value (for number and charCon)string str; // token string (for numbers and identifiers)

}

PLUS = 4, /* + */MINUS = 5, /* - */TIMES = 6, /* * */SLASH = 7, /* / */REM = 8, /* % */EQ = 9, /* == */GE = 10, /* >= */GT = 11, /* > */LE = 12, /* <= */LT = 13, /* < */NE = 14, /* != */AND = 15, /* && */OR = 16, /* || */

Exemple de codage pour un langage particulier

const int

NONE = 0, IDENT = 1,NUMBER = 2,CHARCONST = 3,

ASSIGN = 17,/* = */PPLUS = 18,/* ++ */MMINUS = 19,/* -- */SEMICOLON = 20,/* ; */COMMA = 21,/* , */PERIOD = 22,/* . */LPAR = 23,/* ( */RPAR = 24,/* ) */LBRACK = 25,/* [ */RBRACK = 26,/* ] */LBRACE = 27,/* { */RBRACE = 28,/* } */

BREAK = 29,CLASS = 30,CONST = 31,ELSE = 32,IF = 33,NEW = 34,READ = 35,RETURN = 36,VOID = 37,WHILE = 38,WRITE = 39,

EOF = 40;

Erreur Classes des unités Opérateurs et caractères spéciaux Mot-clés Fin de fichier

Page 19: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Implémentation des Scanner

Variables statiques dans le scanner

static TextReader input; // input streamstatic char ch; // next input character (still unprocessed)static int line, col; // line and column number of the character ch

const int EOF = '\u0080'; // character that is returned at the end of the file

Init()

public static void Init (TextReader r) {input = r;line = 1; col = 0;NextCh(); // reads the first character into ch and increments col to 1

}

NextCh()

static void NextCh() {try {

ch = (char) input.Read(); col++;if (ch == '\n') { line++; col = 0; }else if (ch == '\uffff') ch = EOF;

} catch (IOException e) { ch = EOF; }}

• ch = prochain caractère d‘entrée• retourne EOF si fin de fichier• incrémente line et col

Page 20: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Method Next()public static Token Next () {

while (ch <= ' ') NextCh(); // skip blanks, tabs, eolsToken t = new Token(); t.line = line, t.col = col;switch (ch) {

case 'a': ... case 'z': case 'A': ... case 'Z': ReadName(t); break;case '0': case '1': ... case '9': ReadNumber(t); break;case ';': NextCh(); t.kind = Token.SEMICOLON; break;case '.': NextCh(); t.kind = Token.PERIOD; break;case EOF: t.kind = Token.EOF; break; // no NextCh() any more...case '=': NextCh();

if (ch == '=') { NextCh(); t.kind = Token.EQ; } else t.kind = Token.ASSIGN;break;

case '&': NextCh();if (ch == '&') { NextCh(); t.kind = Token.AND; } else t.kind = NONE;break;

...case '/': NextCh();

if (ch == '/') {do NextCh(); while (ch != '\n' && ch != EOF);t = Next(); // call scanner recursively

} else t.kind = Token.SLASH;break;

default: NextCh(); t.kind = Token.NONE; break;}return t;

} // ch holds the next character that is still unprocessed

nom, mot-clésnombres

unité simple

unités composée

commentaire

caractère invalide

Page 21: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Autres méthodes

static void ReadName (Token t)

• Au début ch contient la première lettre du nom

• Lit les prochaines lettres, digits et '_' et les range dans t.str

• Chercher le nom dans la table des mots clés ( hash-code ou arbre de recherche binaire )si trouvé: t.kind = code du mot clé;sinon: t.kind = Token.IDENT;

• À la fin, ch contient le premier caractère après le nom

static void ReadNumber (Token t)

• Au début ch contient le premier chiffre du nombre

• Lit les prochains digits, les range dans t.str; puis convertit la chaîne en un nombre et range lavaleur dans t.val.Si débordement: Erreur

• t.kind = Token.NUMBER;

• A la fin ch contient le premier caractère après le nombre

Page 22: Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure dInformatique (ESI)  email: d_zegour@esi.dzd_zegour@esi.dz.

Considérations d‘efficacité

Taille d‘un programme modeste

Aux environs de 1000 instructions environ 6000 unités environ 60000 caractères

La phase lexicale consomme un temps importantprend 20-30% du temps total de compilation

Faire attention à la programmation

Utiliser les variables globales :Ex.: ch est global et non un paramètre de NextCh()

Pour les grands fichiers d‘entrée, c‘est judicieux d‘utiliser des lectures bufférisées

Stream file = new FileStream("MyProg.zs");Stream buf = new BufferedStream(file);TextReader r = new StreamReader(buf);Scanner.Init(r);