1 / 22

Analyse lexicale

Analyse lexicale. Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI) www.zegour.uuuq.com email: d_zegour@esi.dz. Analyse lexicale Taches d‘un scanner Grammaires Régulières et Automates finis Implémentation des scanners. 2. Saute les caractères non significatifs. blancs

lore
Télécharger la présentation

Analyse lexicale

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Analyse lexicale Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI) www.zegour.uuuq.com email: d_zegour@esi.dz

  2. Analyse lexicale Taches d‘un scanner Grammaires Régulières et Automates finis Implémentation des scanners

  3. 2. Saute les caractères non significatifs • blancs • Caractères de tabulation • Caractères de fin de lignes (CR, LF) • Commentaires Les unités lexicales ont une structure syntaxique ident = letter { letter | digit }. number = digit { digit }. if = "i" "f". eql = "=" "=". ... Taches d’un scanner 1. Délivre les symboles terminaux (unités lexicales) scanner IF, LPAR, IDENT, EQ, NUMBER, RPAR, ..., EOF i f ( x = = 3 ) Source Unités lexicales

  4. Le scanner doit éliminer les caractères non significatifs Ces 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. 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 ";" ) Les unités lexicales peuvent être decrites à l‘aide de grammaires régulières (Plus simple et plus efficace que les grammaires à contexte libre)

  5. Analyse lexicale Taches d‘un scanner Grammaires Régulières et Automates finis Implémentation des scanners

  6. 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 Exemple Grammaire pour les identificateurs Ident = letter { letter | digit }. Grammaires régulières Définition Une grammaire est dite régulière si elle peut être décrite par des productions de la forme: a, b des TS A, B des NTS A = a. A = b B. Autre définition Une grammaire est dite régulière si elle peut être décrite par une simple non récursive production EBNF.

  7. Après substitution de F dans T T = id { "*" id }. Après substitution de T dans E E = id { "*" id } { "+" id { "*" id } }. La grammaire est régulière Peut-on transformer la grammaire suivante en une grammaire régulière? Après substitution de F dans E E = F { "*" F }. F = id | "(" 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. Exemples Peut-on transformer la grammaire suivante en une grammaire régulière? E = T { "+" T }. T = F { "*" F }. F = id.

  8. Les structures lexicales sont généralement régulières Exception:commentaires emboîtés nom letter { letter | digit } /* ..... /* ... */ ..... */ Le scanner doit les traiter comme cas spécial Limitations des grammaires régulières Les grammaires régulières ne traitent pas les structures emboîtées Raison : ne peut éliminer la récursion centrale! La récursion centrale est importante dans les langages de programmation. • Expressions emboîtées • Instructions emboîtées • Classes emboîtées Expr => ... "(" Expr ")" ... Statement => "do" Statement "while" "(" Expr ")" Class => "class" "{" ... Class ... "}" Solution : utilisation des grammaires à contexte libre. nombres digit { digit } chaînes "\"" { pas de quote } "\"" Mot-clés letter { letter } opérateurs ">" "="

  9. Exemples "w" "h" "i" "l" "e" while letter ( letter | digit )* names digit+ numbers Expressions régulières Autre notation pour les grammaires régulières Définition 1. e (la chaîne vide) est une expression régulière 2. Un symbole terminal est une expression régulière 3. Si a et b sont des expressions régulières, les expressions suivantes sont régulières: a b (a | b) (a)? e | a (a)* e | a | aa | aaa | ... (a)+ a | aa | aaa | ...

  10. Table de transition d "fini", car d Peut être défini explicitement letter digit s0 s1 error s1 s1 s1 Définition • Un automate fini déterministique est un 5 tuple (S, I, d, s0, F) • S Ensemble des états • I Ensemble des symboles d‘entrée • d: S x I  S Fonction de transition des états • s0 État initial • F Ensemble des états finaux Automate Fini Déterministique (DFA) Peut être utilisé pour analyser les langages réguliers Exemple État final letter letter 0 1 État initial est 0 par convention digit Le langage reconnu par une DFA est l‘ensemble de toutes les séquences de symboles pouvant être générées de l‘état initial vers l‘un 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

  11. Exemple Entrée:max >= 30 m a x • Pas de transition avec " " dans s1 • ident reconnu s0 s1 > = • Saute les blancs au début • Ne s‘arrête pas en s4 • Pas de transition avec " " dans s5 • geq reconnu s0 s5 3 0 • Saute les blancs au début • Pas de transition avec " " dans s2 • number reconnu s0 s2 Le Scanner comme un DFA Le scanner peut être vu comme un grand DFA " " letter letter 0 1 ident digit digit digit 2 number ( 3 lpar > = 4 5 gtr geq ... Après chaque unité lexicale reconnue le scanner recommence à l‘état initial s0

  12. Exemple Grammaire Automate A = a B | b C | c. B = b B | c. C = a C | c. b c a A B a b c C c stop Transformation: grammaire régulière vers DFA Une grammaire régulière peut être transformée en un DFA comme suit b  A = b C. A C d  A = d. A stop

  13. Chaque NDFA peut être transformé en un DFA équivalent H intNum digit A,B,C,D,E,F H 0 1 2 3 hexNum hex digit Automate Fini Non Déterministique (NDFA) Exemple intNum Non déterministique car Il y a 2 possibles transitions avec digit dans s0 intNum = digit { digit }. hexNum = digit { hex } "H". digit = "0" | "1" | ... | "9". hex = digit | "A" | ... | "F". digit digit 0 1 digit H 2 3 hexNum hex

  14. Exemple pour d d a b c 0 1 - - 1 - 1 2 2 - - - F A = a { b } c. a c 0 1 2 int[,] delta = { {1, -1, -1}, {-1, 1, 2}, {-1, -1, -1} }; A b Cette implémentation pourrait être très inefficace pour un véritable scanner Implémentation d‘un DFA (Variante 1) Implémentation de d comme une matrice int[,] delta = new int[maxStates, maxSymbols]; int lastState, state = 0; // DFA starts in state 0 do { int sym = next symbol; lastState = state; state = delta[state, sym]; } while (state != undefined); assert(lastState in F); // F is set of final states return recognizedToken[lastState];

  15. en Java c‘est plus fatiguant: 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; Implémentation d‘un DFA (Variante 2) a c 0 1 2 A b Coder les états dans le code source 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;

  16. Analyse lexicale Taches d‘un scanner Grammaires Régulières et Automates finis Implémentation des scanners

  17. Initialisation du scanner Scanner.Init(new StreamReader("myProg.zs")); Lecture des unités lexicales Token t; for (;;) { t = Scanner.Next(); ... } Interface du Scanner class Scanner { static void Init (TextReader r) {...} static Token Next () {...} }

  18. Exemple de codage pour un langage particulier Erreur Classes des unités Opérateurs et caractères spéciaux Mot-clés Fin de fichier const int NONE = 0, IDENT = 1, NUMBER = 2, CHARCONST = 3, BREAK = 29, CLASS = 30, CONST = 31, ELSE = 32, IF = 33, NEW = 34, READ = 35, RETURN = 36, VOID = 37, WHILE = 38, WRITE = 39, EOF = 40; ASSIGN = 17, /* = */ PPLUS = 18, /* ++ */ MMINUS = 19, /* -- */ SEMICOLON = 20, /* ; */ COMMA = 21, /* , */ PERIOD = 22, /* . */ LPAR = 23, /* ( */ RPAR = 24, /* ) */ LBRACK = 25, /* [ */ RBRACK = 26, /* ] */ LBRACE = 27, /* { */ RBRACE = 28, /* } */ 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, /* || */ Unités lexicales class Token { public const int NONE = 0, IDENT = 1, …. int kind; // token code int 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) }

  19. 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() • ch = prochain caractère d‘entrée • retourne EOF si fin de fichier • incrémente line et col 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; } } Implémentation des Scanner Variables statiques dans le scanner static TextReader input; // input stream static 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

  20. Method Next() public static Token Next () { while (ch <= ' ') NextCh(); // skip blanks, tabs, eols Token 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és nombres unité simple unités composée commentaire caractère invalide

  21. 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 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

  22. 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); 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 important prend 20-30% du temps total de compilation

More Related