IFT 313 Introduction aux langages formels ric Beaudry
IFT 313 – Introduction aux langages formels Éric Beaudry Département d’informatique Université de Sherbrooke Grammaires attribuées: un aperçu
Objectifs • Se familiariser avec la notion de grammaire attribuée. • Mieux connaître la suite au cours (analyse sémantique). IFT 313 / 2010 E (C) Éric Beaudry 2
Objectifs du cours IFT 313 – Introduction aux langage formels Analyse Lexicale Analyse syntaxique Analyse sémantique (JFlex, …) (Java. CC, Java. CUP, …) (adhoc ou ag, …) Code source (Graph 313, Scheme, …) IFT 580 – Compilation et interprétation des langages IFT 313 / 2010 E (C) Éric Beaudry Interpréteur (itératif ou récursif) Génération du code Code exécutable ou Intermédiare (. exe, . class) 3
Grammaires attribuées • Les grammaires attribuées sont utiles pour l’analyse sémantique. • Pour chaque type de nœud, on attache des attributs. • Chaque attribut a un nom et un type. • Un attribut peut être synthétique (calculé) ou hérité (valeur copiée d’un enfant ou parent). IFT 313 / 2010 E (C) Éric Beaudry 4
Grammaires attribuées • Il faut un « évaluateur d’attributs » . • Arbre syntaxique abstrait, ou Abstract Syntax Tree (AST). • Arbre « décoré » . IFT 313 / 2010 E (C) Éric Beaudry 5
Data Flow pour le calcul des attributs Règle de production : A B C D Attributs hérités de A A Attributs synthétisés de A Règles d’évaluation d’attributs Hér. IFT 313 / 2010 E B synthé. Hér. C synthé. (C) Éric Beaudry Hér. D synthé. 6
Attributs déterminés par l’analyseur lexical • Par exemple, pour un lexème de type nombre, on peut calculer certains attributs au moment de l’analyse lexicale. • Attributs d’un nombre: – Type : {Réel, Entier, Long. Double, …) – Valeur • • Nombre = [0 -9]+ // entier ordinaire 32 bits Nombre = [0 -9]+L // entier long (64 bits) Nombre = [0 -9]*. [0 -9]+ // réel double (64 bits) Nombre = [0 -9]*. [0 -9]+f // réel float (32 bits) IFT 313 / 2010 E (C) Éric Beaudry 7
Attributs déterminés par l’analyseur lexical Texte: int a = (int) 304. 29; Lexèmes: <Int. KW> <identifier> <EQ> <LPAREN> <Int. KW> <RPAREN> <Nombre> Lexèmes attribués: <Int. KW> <identifier, name=‘a’> <EQ> <LPAREN> <Int. KW> <RPAREN> <Nombre, type=Réel, value=304. 29> <EOF> IFT 313 / 2010 E (C) Éric Beaudry 8
Attributs calculés par des règles de la grammaire • E E + E • Un attribut de E pourrait être son « type » (entier, réel, etc. ). • • Quel est le type de E si : 1 + 2 ? Quel est le type de E si : 1. 0 + 2 ? 1+2. 0 ? Quel est le type de E si : 1 / 2. 0 ? 1. 0 / 2 ? • En général, les langages comme C/C++ et Java ne font que de la conversion de type quand cela est nécessaire, c’est-à-dire quand il y a une opération avec des types différents (le type le plus précis a priorité). IFT 313 / 2010 E (C) Éric Beaudry 9
Attributs calculés par des règles de la grammaire Grammaire: • E E op E • E num • op + | - | * | / Chaine: 2. 1 * 2 E Type=réel, value=4. 2 op E num IFT 313 / 2010 E Type=réel, value=2. 1 (C) Éric Beaudry E num Type=entier, value=2 10
Calculs des attributs • Parfois, il faut plusieurs passes (itérations) pour calculer les attributs. – Par exemple, pour propager des tables de symboles, des adresses de branchement (JUMP), etc. • Il faut donc des grammaires attribuées acycliques. • … IFT 580 IFT 313 / 2010 E (C) Éric Beaudry 11
Attributs dans Java. CC • Java. CC ne fait pas que valider la syntaxe. • Il peut permettre d’effectuer des calculs à la volé (ex. : calc). • Il peut aussi charger un AST de façon – manuelle (ex. : calc. Tree); – automatique avec l’outil JJTree. • Des attributs sont utilisés. • Limites avec Java. CC: – un seul attribut par symbole. – une seule passe d’évalutation. • Pour aller au-delà, il faut utiliser d’autres outils ou des méthodes adhoc pour évaluer les attributs. IFT 313 / 2010 E (C) Éric Beaudry 12
EXEMPLES AVEC JAVACC IFT 313 / 2010 E (C) Éric Beaudry 13
Calc. Syntax PARSER_BEGIN(Parser) package calcsyntax; import java. io. *; public class Parser { public static void main(String args[]) throws Exception { Parser parser; String. Buffer str. Buffer; if (args. length==0) parser = new Parser(System. in); else { /* First collect all arguments into a single string buffer */ str. Buffer = new String. Buffer(); for (int i = 0; i < args. length; i++) str. Buffer. append(args[i]). append(" "); /* Now create a parser from a String. Reader of the sring buffer */ parser = new Parser(new String. Reader(str. Buffer. to. String())); } parser. Expr_list(); } } PARSER_END(Parser) SKIP : { " " | "t" | "n" | "r" } TOKEN : { <NUM: ( ["0"-"9"] )+ > | <LPAREN: "("> | <RPAREN: ")"> | <PLUS: "+"> | <TIMES: "*"> | <SEMI: "; "> } void Expr_list () : {} {(E() <SEMI>)* <EOF> } void E () : {} {T() ( <PLUS> T () ) *} void T () : {} {F() (<TIMES> F())*} void F () : {} {<NUM> | <LPAREN> E() <RPAREN>} IFT 313 / 2010 E (C) Éric Beaudry 14
Calc void Expr_list() : { int a; System. out. println("Please type in an arithmetic expression followed by a "; " or ^D to quit: " + "n"); } { ( a=E() <SEMI> { System. out. println(" =" + a + "n"); System. out. println("Please type in another expression followed by a "; " or ^D to quit: " + "n"); } )* <EOF> } int E () : { int a, i; } { a=T() (<PLUS> i=T() { a = a + i; })* { return a; } } int T() : { int a, i; } { a=F() (<TIMES> i=F() { a = a * i; })* { return a; } } int F() : { Token t; int a = 0; } { t=<NUM> { return Integer. parse. Int(t. image); } | <LPAREN> a=E() <RPAREN> { return a; } } IFT 313 / 2010 E (C) Éric Beaudry 15
void Expr_list() : { Exp e; System. out. println("Please type in an arithmetic expression followed by a "; " or ^D to quit: " + "n"); } { ( e=E() <SEMI> { System. out. println(" =" + e. eval() + "n"); System. out. println("Please type in another expression followed by a "; " or ^D to quit: " + "n"); } )* <EOF> } Exp E () : { Exp e 1, e 2; } { e 1=T() ( <PLUS> e 2=T() { e 1 = new Plus. Exp(e 1, e 2); } | <MINUS> e 2=T() { e 1 = new Minus. Exp(e 1, e 2); } )* { return e 1; } } Exp T() : { Exp e 1, e 2; } { e 1=F() ( <TIMES> e 2=F() { e 1 = new Times. Exp(e 1, e 2); } | <DIVIDE> e 2=F() { e 1 = new Divide. Exp(e 1, e 2); } )* { return e 1; } } Exp F() : { Token t; Exp e; } { t=<NUM> { return new Number. Literal(t. image); } | <LPAREN> e=E() <RPAREN> { return e; } } IFT 313 / 2010 E (C) Éric Beaudry Calc. Tree 16
EXEMPLES AVEC JAVACUP IFT 313 / 2010 E (C) Éric Beaudry 17
Java. CUP • Java. CUP est un générateur de parseur ascendant (LALR) contrairement à Java. CC qui est un générateur de parseurs descendant (LL). • Java. CUP peut aussi construire un AST à l’aide d’attributs. IFT 313 / 2010 E (C) Éric Beaudry 18
/* The grammar */ expr_list : : = expr_list expr_part | expr_part; Java. CUP / calc expr_part : : = expr: e {: System. out. println("= " + e); : } SEMI ; expr : : = expr: e 1 PLUS expr: e 2 {: RESULT = new Integer(e 1. int. Value() + e 2. int. Value()); : } | expr: e 1 MINUS expr: e 2 {: RESULT = new Integer(e 1. int. Value() - e 2. int. Value()); : } | expr: e 1 TIMES expr: e 2 {: RESULT = new Integer(e 1. int. Value() * e 2. int. Value()); : } | expr: e 1 DIVIDE expr: e 2 {: RESULT = new Integer(e 1. int. Value() / e 2. int. Value()); : } | expr: e 1 MOD expr: e 2 {: RESULT = new Integer(e 1. int. Value() % e 2. int. Value()); : } | NUMBER: n {: RESULT = n; : } | MINUS expr: e {: RESULT = new Integer(0 - e. int. Value()); : } %prec UMINUS | LPAREN expr: e RPAREN {: RESULT = e; : } ; IFT 313 / 2010 E (C) Éric Beaudry 19
Travaux pratiques 5 et 7 • Les TP 5 et 7 consisteront justement à construire un AST pour le langage Graph 313. • TP 5 : Java. CC. • TP 7 : Java. CUP (réutilisation de l’analyseur lexical du TP 2#3). IFT 313 / 2010 E (C) Éric Beaudry 20
Conclusion • Les attributs dans une grammaire sont utiles pour faire l’analyse sémantique. • Dans ce cours, nous limiterons à des cas simple, soit d’interprété directement une expression (calc) ou en construisant un arbre syntaxique abstrait (calc. Tree et TPs 5 et 7). • Ces utilisations se font en une seule passe. IFT 313 / 2010 E (C) Éric Beaudry 21
- Slides: 21