Gnrateurs de compilateurs Pr ZEGOUR DJAMEL EDDINE Ecole

  • Slides: 30
Download presentation
Générateurs de compilateurs Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI) www. zegour. uuuq.

Générateurs de compilateurs Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI) www. zegour. uuuq. com email: d_zegour@esi. dz

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Fonctionnement des générateurs de compilateurs Ils génèrent les parties d’un compilateur à partir d’une

Fonctionnement des générateurs de compilateurs Ils génèrent les parties d’un compilateur à partir d’une spécification concise (Parties générées : scanner, analyseur syntaxico-sémantique, générateur de code , . . . ) générateur scanner Spécification du scanner Ex. grammaire régulière) Spécification sémantique (Ex. grammaire d’attribut) générateur de l’analyseur Générateur De compilateurs Exemples Yacc Lex Coco/R. . . scanner Analyseur compilateur & éditeur de liens Classes utilisateur • Table des symboles • Générateur de code • Programme principal • . . . générateur d’analyseur syntaxique et sémantique pour C et Java générateur de scanner pour C, Java et C# générateur de scanner et d’analyseur pour Java, C#, Modula-2, Oberon, . . . compilateur généré

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Yacc - Yet another compiler Histoire 1975 développé aux laboratoires Bell ( ensemble avec

Yacc - Yet another compiler Histoire 1975 développé aux laboratoires Bell ( ensemble avec C et Unix) • Génère des analyseurs LALR(1) • À l’origine sous Unix, Aujourd'hui aussi sous Windows, Linux • A l’origine pour C, Aujourd'hui pour Java Utilisation sample. y Nous décrivons ici la version de Java Yacc parser. javac Versions actuelles Bison version GNU de Yacc http: //www. gnu. org/software/bison. html Byacc Berkeley Yacc http: //byaccj. sourceforge. net/ parser. class

Langage d’entrée pour Yacc Format général %{package Java et les lignes ‘import’ %} Déclarations

Langage d’entrée pour Yacc Format général %{package Java et les lignes ‘import’ %} Déclarations Yacc (unités, règles de précédence des opérateurs, . . . ) %% productions %% Déclarations Java (champs, méthodes) Traduit vers class parser {. . . public void yyparse() {. . . parser. . . } }

Yacc — Productions et actions sémantiques Productions Grammar Production Alternative Sem. Action NT T

Yacc — Productions et actions sémantiques Productions Grammar Production Alternative Sem. Action NT T = {Production}. = NT ": " Alternative {"|" Alternative} "; " = {NT | T} [Sem. Action]. = "{". . . arbitrary Java statements. . . "}". = ident | char. Const. Exemple expr: term { $$ = $1; } | expr '+' term { $$. ival = $1. ival + $3. ival; } ; Actions Sémantiques • Peuvent contenir des instructions Java • Peuvent apparaître seulement à la fin d’une alternative • Les attributs sont dénotés par des noms spéciaux: $$ attribut du coté gauche NTS $i attribut du i-ème symbole du coté droit ($1 = attr. du premier symbole, $2 = attr. du second symbole, . . . )

Yacc — Attributs Pour les symboles terminaux • Sont délivrés par le scanner (scanner

Yacc — Attributs Pour les symboles terminaux • Sont délivrés par le scanner (scanner développé manuellement ou généré avec Lex) • Chaque unité lexicale a un attribut de type parserval class parserval { int ival; // token value if the token should have an int attribute double dval; // token value if the token should have a double attribute String sval; // token value, e. g. for ident and string Object obj; // token value for more complex tokens parserval(int val) {. . . } // constructors parserval(double val) {. . . } parserval(String val) {. . . } parserval(Obj val) {. . . } } • Le scanner retourne les attributs dans la variable globale yylval Scanner yylval = new parserval(n); Accès dans une action sémantique {. . . $1. ival. . . } Pour les symboles non terminaux • Chaque NTS a un attribut $$ de type parserval ( valeurs plus complexes rangées dans $$. obj) • Chaque affectation à $$ empile l’attribut du NTS dans une pile d’attributs. Les accès à $1, $2 se font en dépilant les attributs de la pile

Yacc — Variables et Méthodes Java Sont déclarées après le second %% %{. .

Yacc — Variables et Méthodes Java Sont déclarées après le second %% %{. . . imports. . . %}. . . Unités. . . %%. . . Productions. . . %%. . . Déclarations Java. . . • Deviennent des champs et des méthodes pour l’analyseur • Peuvent être utilisées dans les actions sémantiques Au moins les méthodes suivantes doivent être implémentées dans les déclarations Java void yyerror(String msg) {. . . } Pour afficher les messages d’erreur int yylex() {. . . } Scanner (retourne les codes unités et remplit yylval) public static void main(String[] arg) {. . . initializations for yylex. . . yyparse(); } Programme principal

Exemple: Compilateur pour les expressions /* declaration of all tokens which are not strings

Exemple: Compilateur pour les expressions /* declaration of all tokens which are not strings */ %token number %% /* productions: first NTS is the start symbol */ input: expr { System. out. println($1. ival); } ; expr: term | expr '+' term { $$ = $1; } { $$. ival = $1. ival + $3. ival; } ; term: factor | term '*' factor { $$ = $1; } { $$. ival = $1. ival * $3. ival; } ; factor: number | '(' expr ')' { $$ = $1; } { $$ = $2; } ; %% int yylex() {. . . } void yyerror(string msg) {. . . } public static void main(String[] arg) {. . . } arithmétiques Conventions de codage des unités • eof == 0 • Code des unités ‘caractère’ : leurs valeurs Ascii (Par exemple '+' == 43) • YYERRCODE == 256 • Autres unités sont numérotées consécutivement commençant par 257 (Par exemple. nombre == 257); elles peuvent être accédées dans les productions et dans yylex() utilisant leur nom déclaré.

Yacc — Précédence des opérateurs La grammaire suivante spécifie explicitement la précédence des opérateurs

Yacc — Précédence des opérateurs La grammaire suivante spécifie explicitement la précédence des opérateurs expr: term | expr '+' term ; term: factor | term '*' factor ; factor: number | '(' expr ')' ; • '*' a une précédence sur '+' • Les opérateurs sont associatifs à gauche: a*b*c == (a*b)*c On peut aussi l’exprimer comme suit en Yacc: %token number %left '+' %left '*' • %left : l’opérateur est associatif gauche a+b+c == (a+b)+c input: expr • Les opérateurs sont déclarés en ordre ascendant de priorité: '*' a une précédence sur '+' { System. out. println($1. ival); } ; expr: number | expr '+' expr | expr '*' expr | '(' expr ')' { $$ = $1; } { $$. ival = $1. ival + $3. ival; } { $$. ival = $1. ival * $3. ival; } { $$ = $2; } %% %%. . . • Cette grammaire ne spécifie aucune précédence d’opérateurs • La précédence est spécifiée par %left ou %right

Yacc — Traitement des erreurs Les alternatives ‘error’ Pour certains NTS (EX: Instructions, Expression,

Yacc — Traitement des erreurs Les alternatives ‘error’ Pour certains NTS (EX: Instructions, Expression, . . . ) l’utilisateur doit spécifier Les alternatives ‘error’ A: . . . | error a {. . . } ; a. . . Séquence quelconque de symboles T et NT Signification: S’il existe une erreur dans A l’analyseur effectue les actions suivantes: • Il dépile des états de la pile jusqu’à l’obtention d’un état dans lequel une action ‘décaler’ avec l’unité error est valide • ‘Décaler’ error • Il saute les unités d’entrée jusqu’à ce qu’il détecte une séquence d’unités qui peut être réduite à a ( le sommet de pile contient alors : error a) • Il réduit error a à A et exécute l’action sémantique correspondante Exemple Statement =. . . | error '; ' ; Saute tout jusqu’au prochain '; '

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Lex — Générateur de scanner Histoire 1975 développé aux laboratoires Bell • génère un

Lex — Générateur de scanner Histoire 1975 développé aux laboratoires Bell • génère un scanner en forme de DFA • A l’origine un outil de Unix, aujourd'hui aussi pour Windows • A l’origine pour C, Aujourd’hui aussi pour Java • Coopère généralement avec Yacc Utilisation Nous decrivons ici la version C sample. l Lex sample. yy. c sample. y Yacc sample. tab. c include C-Compiler Versions actuelles flex version GNU de Lex (pour C) http: //www. gnu. org/software/flex/ JLex version Java avec légère différence dans la syntaxe d’entrée; incompatible avec Bison ou Byacc http: //www. cs. princeton. edu/~appel/modern/java/JLex/ version C# , dérivé de JLex http: //www. cybercom. net/~zbrad/Dot. Net/Lex Cs. Lex sample. o

Exemple de description Lex %{. . . e. g. include directives for token numbers

Exemple de description Lex %{. . . e. g. include directives for token numbers exported by the parser. . . %} /* macros */ delim [ tn] /* blank, tab, eol */ ws {delim}+ /* {. . . }. . . use of a macro */ letter [A-Za-z] digit [0 -9] id {letter} ({letter} | {digit})* number {digit}+ %% /* token declarations described as regular expressions */ {ws} {} /* no action */ if { return IF; } /* constants like IF are imported from the parser */ then { return THEN; } else { return ELSE; } {id} { yylval = store. Id(yytext, yyleng); return ID; } {number} { yylval = convert(yytext, yyleng); return number; } < { return yytext[0]; } > { return yytext[0]; }. {} /*. denotes any character */ %% /* semantic routines */ int store. Id(char* text, int len) {. . . } int convert(char* text, int len) {. . . }

Scanner généré La spécification du scanner est convertie en une fonction int yylex() {.

Scanner généré La spécification du scanner est convertie en une fonction int yylex() {. . . } qui est incluse dans l’analyseur yylex() retourne aussi les attributs d’unités comme variables globales int yylval; char* yytext; int yyleng; int yylineno; /* attribute if the token has a numeric value */ /* token text (attribute of ident, string, . . . ) */ /* lengh of the token text */ /* line number of the token */ L’analyseur déclare (et exporte) les codes unités %token IF %token THEN. . .

Expressions régulières dans Lex Éléments des expressions régulières abc. x* x+ x? (. .

Expressions régulières dans Lex Éléments des expressions régulières abc. x* x+ x? (. . . |. . . ) [. . . ] {. . . } ^ $ udddd la chaîne "abc"; tout caractère sauf ()[]{}*+? |^$. dénote lui-même Tout caractère sauf n (fin de ligne) 0 ou plusieurs répétitions de x 1 ou plusieurs répétitions de x 0 ou 1 occurrence de x ( occurrence optionnelle) pour grouper des alternatives ensemble de tous les caractères entre les crochets (Ex. [A-Za-z 0 -9$]) Utilise d’une macro ligne début ligne fin caractère en Unicode

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Générateurs de compilateurs Introduction Yacc Lex Coco/R

Coco/R – Compilateur de compilateur / Descente Récursive Histoire 1980 développé à l’université de

Coco/R – Compilateur de compilateur / Descente Récursive Histoire 1980 développé à l’université de Linz (Rechenberg, Mössenböck) • génère un scanner et un analyseur à partir d’une grammaire d’attribut - scanner comme un DFA - Analyseur sous forme de ‘descente récursive’ • Il existe des versions pour C#, Java, C/C++, Delphi, Modula-2, Oberon, Python, . . . • Publié sous GPL: http: //www. ssw. uni-linz. ac. at/Research/Projects/Coco/ Utilisation main grammaire d’attribut parser Coco/R scanner Classes utilisateurs (Ex. Table des symboles csc

Exemple: Compilateur pour les Expressions arithmétiques COMPILER Calc /* grammar name = start symbol

Exemple: Compilateur pour les Expressions arithmétiques COMPILER Calc /* grammar name = start symbol */ CHARACTERS /* character sets used in token declarations */ digit = '0'. . '9'. tab = 't'. cr = 'r'. lf = 'n'. TOKENS /* declaration of all tokens which are not literals */ number = digit {digit}. COMMENTS /* declaration of comments */ FROM "//" TO cr lf FROM "/*" TO "*/" NESTED IGNORE tab cr lf /* these characters are ignored as white space */ PRODUCTIONS Calc (. int x; . ) = "CALC" Expr<out x> (. System. Console. Write. Line(x); . ). Expr<out int x> = Term<out x> { '+' Term<out y> }. (. int y; . ) Term<out int x> = Factor<out x> { '*' Factor<out y> }. (. int y; . ) Factor<out int x> = number | '(' Expr<out x> ')'. END Calc. (. x = x + y; . ) (. x = x * y; . ) (. x = Convert. To. Int 32(t. val); . )

Coco/R — les attributs Les symboles terminaux • Les symboles terminaux n’ont pas d’attribut

Coco/R — les attributs Les symboles terminaux • Les symboles terminaux n’ont pas d’attribut explicite • Leurs valeurs peuvent être accédées dans les actions sémantiques utilisant les variables suivantes Token t; l’unité la plus récente reconnue Token la; la prochaine unité (lookahead) (non encore reconnue) Exemple Factor<out int x> = number class Token { int kind; string val; int pos; int line; int col; } (. x = Convert. To. Int 32(t. val); . ) // token code // token value // token position in the source text (starting at 0) // token line (starting at 1) // token column (starting at 0) Les symboles non terminaux • Les NTS peuvent avoir des attributs d’entrée Attr. formels: A<int x, char c> =. . Attr réels. : . . . A<y, 'a'>. . . • Les NTS peuvent avoir des attributs de sortie B<out int x, out int y> =. . . . B<out z, out n>. . .

Coco/R — Traitement sémantique Actions sémantiques • code Java entre (. et. ) •

Coco/R — Traitement sémantique Actions sémantiques • code Java entre (. et. ) • Peuvent apparaître n’importe où dans les productions • Dans le coté gauche d’une production elles sont considérée comme des déclarations Term<out int x> = Factor<out x> { '*' Factor<out y> }. (. int y; . ) déclaration (. x = x * y; . ) action sémantique Déclarations sémantiques • Apparaissent au début de la spécification du compilateur • Sont utilisées pour déclarer les champs et les méthodes de l’analyseur • Les ‘import’ peuvent aussi être spécifiés COMPILER Sample using System. Collections; static IList my. List; static void Add. To. List (int x) {. . . } CHARACTERS. . . Bien sûr, les actions sémantiques peuvent aussi accéder aux champs et méthodes de classes autre que ceux de l'analyseur.

Coco/R – les méthodes d’analyse Chaque production est traduite en une méthode de l’analyseur

Coco/R – les méthodes d’analyse Chaque production est traduite en une méthode de l’analyseur Expr<out int x> = Term<out x> { '+' Term<out y> }. (. int y; . ) (. x += y; . ) devient static void Expr (out int x) { int y; Term(out x); while (la. kind == plus) { Scan(); Term(out y); x += y; } }

Coco/R – Traitement des erreurs syntaxiques L’analyseur utilise la technique des ‘ancres spéciaux’ Point

Coco/R – Traitement des erreurs syntaxiques L’analyseur utilise la technique des ‘ancres spéciaux’ Point de synchronisation Doivent être marqués par SYNC Statement = SYNC ( Assignment | If. Satement |. . . ). if la. kind dans Suivant(SYNC) une erreur est reportée et des unités sont sautées jusqu’à la. kind dans Suivant(SYNC) Inter {eof} Les faux messages d'erreur sont supprimés si moins de 3 unités ont été reconnues depuis la dernière erreur. Séparateurs faibles Les séparateurs au début d’une itération peuvent être marqués comme Weak (faibles) Formal. Pars = "(" Param { WEAK ', ' Param } ')'. Si le séparateur manque ou est mal écrit, la boucle n'est pas terminée prématurément, mais l'analyseur synchronise avec Premier(Param) Inter Suivant({. . . }) Inter {eof}

Coco/R — Tests de grammaire Test LL(1) A = a [B] C d |

Coco/R — Tests de grammaire Test LL(1) A = a [B] C d | B a. B = a b. C = a [d]. Coco/R affiche les avertissements suivants LL 1 warning in A: a is start & successor of deletable structure LL 1 warning in A: a is start of several alternatives LL 1 warning in C: d is start & successor of deletable structure Test de complétude Existe-il une production pour chaque NTS? Test de non-redondance Est-ce que la grammaire contient des productions non atteintes? Test de Dérivabilité Est-ce que chaque NTS peut être dérivé en une chaîne de symboles terminaux? Test de Non-circularité Y a t-il des NTS qui peuvent être dérivé (directement ou indirectement)en eux-mêmes?

Coco/R — Pragmas (Directives de compilation) Pragmas sont des symboles terminaux • Qui peuvent

Coco/R — Pragmas (Directives de compilation) Pragmas sont des symboles terminaux • Qui peuvent apparaître n’importe où dans l’entrée • Qui ne font pas partie de la syntaxe • Qui doivent être traités sémantiquement Ex. options du compilateur COMPILER X CHARACTERS. . . TOKENS. . . PRAGMAS Print. Option = "$print". Dbg. Option = "$debug". . (. option[print] = true; . ) (. option[debug] = true; . ) Quand la string $print apparaît dans le texte d’entrée l’action sémantique option[print] = true; est exécutée

Coco/R — le symbole ‘ANY’ Dans la déclaration des ensembles de caractères Il décrit

Coco/R — le symbole ‘ANY’ Dans la déclaration des ensembles de caractères Il décrit des ensemble de caractères complémentaires CHARACTERS letter = 'A'. . 'Z' + 'a'. . 'z'. no. Letter = ANY - letter. . Tous les caractères qui ne sont pas des lettres Dans les productions Il décrit tout unité qui ne peut être produite par les autres alternatives Place. Holder = ident | ANY. Tout unité qui n’est pas ident ou eof Sem. Action = "(. " { ANY } ". )". Tout unité qui n’est pas ". )" ou eof

Coco/R — Résolution des conflits LL(1) Résolution de conflit par un by a multi-symbol

Coco/R — Résolution des conflits LL(1) Résolution de conflit par un by a multi-symbol lookahead Statement = IF (Is. Assignment()) Designator "=" Expr "; " | Designator "(" Actual. Params ")" "; " |. . static boolean Is. Assignment () { Token x = la; while (x. kind != _assign && x. kind != _lpar) x = Scanner. Peek(); return x. kind == _assign; } Scanner. Peek(). . . Lit les unités sans les enlever de l’entrée Les noms d’unités (_assign, _lpar, . . . ) sont générés à partir des sections TOKENS Résolution de conflit par une vérification sémantique Factor = IF (Is. Cast()) '(' ident ')' Factor /* type cast */ | '(' Expr ')' /* nested expression */ |. . static boolean Is. Cast () { Token x = Scanner. Peek(); if (x. kind == _ident) { Symbol s = Tab. Find(x. val); return s. kind == Symbol. Kinds. Type; } else return false; }

Coco/R — les frames Le scanner et l’analyseur sont générés à partir de frames

Coco/R — les frames Le scanner et l’analyseur sont générés à partir de frames (fichier texte ordinaire) Ex. Scanner. frame public class Scanner { const char EOL = 'n'; const int eof. Sym = 0; -->declarations. . . static Token Next. Token () { while (ignore[ch]) Next. Ch(); -->scan 1 t = new Token(); t. pos = pos; t. col = pos - line. Start + 1; t. line = line; int state = start[ch]; String. Builder buf = new String. Builder(16); -->scan 2. . . } Coco/R insère le code à ces positions En modifiant les frames le scanner et l’analyseur peuvent être adaptés aux besoins de l’utilisateur (à un certain degré)

Coco/R — Interfaces Scanner public class Scanner { public static void Init (string source.

Coco/R — Interfaces Scanner public class Scanner { public static void Init (string source. File. Name) {. . . } public static void Init (Stream s) {. . . } public static Token Scan () {. . . } public static Token Peek () {. . . } public static void Reset. Peek () {. . . } } Parser public class Parser { public static Token t; public static Token la; public static void Parse () {. . . } public static void Sem. Err (string msg) {. . . } } Error message class public class Errors { public static int public static string public static void } count = 0; err. Msg. Format = "-- line {0} col {1}: {2}"; Syn. Err (int line, int col, int n); Sem. Err (int line, int col, int n); Error (int line, int col, string msg); Exception (string msg);