format normal
Transcription
format normal
Examen de compilation UFR IEEA Licence info, S5 1ère session COMPIL -3h- Décembre 2009 FIL Tous documents autorisés. Sujet : 3 pages Exercice 1 : Analyse ascendante Cet exercice concerne la reconnaissance des instructions produites par un locigiel de navigation embarqué. Les instructions possibles sont : tourner (TURN), éventuellement au panneau (PAN), ou avancer (GO). On considère la grammaire Gi suivante, d’axiome route et de terminaux { TURN, GO, PAN } : route → inst | inst route inst → GO | TURN panneau panneau → ǫ | PAN Cette grammaire n’est pas celle qui a été vue en TD. Q 1.1 : Donner l’automate LR-AFD de Gi . 2 Q 1.2 : Gi est-elle LR(0) ? SLR(1) ? Justifier formellement. 2 Q 1.3 : Donner la suite des piles résultant de l’analyse SLR(1) pour les mots GO GO et TURN. 2 Exercice 2 : Grammaire réduite Soit la grammaire G1 de terminaux {a, b}, d’axiome S, de non-terminaux {X1 , X2 , X3 , X4 , S} et de productions : X3 → aX3 | bX3 | X3 X4 S → X1 S | X1 X4 → X4 X4 | b X1 → X2 | bX1 X2 → b | bX2 | X3 Q 2. 1 : Donner une grammaire réduite équivalente à G1 , en donnant les détails des calculs. (attention à ne pas modifier une production par inadvertance si vous recopiez la grammaire) 2 Exercice 3 : Analyse LL(1) On s’intéresse dans cet exercice à la description des tâches dans un gestionnaire de tâches. Une tâche est décrite par un identifiant (une chaı̂ne de caractères, par exemple "tp2"), une priorité optionnelle (une chaı̂ne de caractères, par exemple "normale") et des dépendances optionnelles décrivants les tâches qui doivent être terminées avant le début de celle-ci et les tâches qui ne peuvent commencer que si celle-ci est terminée. On aura par exemple la tâche : \begin{tache} "tp2" \prio "normale" \apres "tp1" "tp1bis" \avant "tp3" \end{tache} Un gestionnaire de tâches possède un nom et une liste de tâches. On le décrit au moyen de la grammaire Gt suivante, d’axiome gestionnaire et de terminaux { GEST TACHES, DEB, FIN, STRING, PRIO, APRES, AVANT } : gestionnaire → GEST TACHES STRING listeTaches listeTaches → ǫ | listeTaches tache tache → DEB STRING description FIN description → priorite dependances priorite → PRIO STRING | ǫ dependances → apres avant apres → APRES listeIdentTaches | ǫ avant → AVANT listeIdentTaches | ǫ listeIdentTaches → STRING | STRING listeIdentTaches 1ère session COMPIL Décembre 2009 1ère session COMPIL Examen de compilation Q 3.1 : Le langage L(Gt ) est-il régulier ? Justifier intuitivement. 2 Q 3.2 : Gt n’est pas LL(1), de manière évidente, à cause des productions : listeTaches → ǫ | listeTaches tache listeIdentTaches → STRING | STRING listeIdentTaches En utilisant les techniques vues en cours, transformer ces productions pour qu’elles ne nuisent plus au caractère LL(1) de la grammaire. 2 La nouvelle grammaire est appelée G′t . La suite de l’exercice peut être réalisée même si vous n’avez pas su répondre à la question précédente (utiliser alors Gt ). Q 3.3 : Calculer les ensembles Premier et Suivant pour les non-terminaux gestionnaire, description, avant et listeIdentTaches, en explicitant les calculs intermédiaires. 2 Q 3.4 : Donner les lignes (ou les colonnes) correspondant aux non-terminaux gestionnaire, avant et description de la table d’analyse LL(1) de G′t . 2 Q 3. 5 : En utilisant les conventions du cours, et en supposant donné un type TypeSymboles contenant les valeurs abrégées { TS.GEST TACHES, TS.DEB, TS.FIN, TS.STRING, TS.PRIO, TS.APRES, TS.AVANT }, donner le code Java des méthodes description() et avant(). 2 Q 3.6 : On attribue G′t pour calculer un graphe de dépendances entre tâches et vérifier ainsi qu’il ne contient pas de cycles. Le graphe est construit lors de l’analyse descendante. Il est créé au tout début de l’analyse, hérité par listeTaches, puis synthétisé une fois complété. On aura par exemple la production suivante : gestionnaire → GEST TACHES STRING listeTaches { listeTaches.grapheH = new Graphe() gestionnaire.grapheS = listeTaches.grapheS } En utilisant les mêmes conventions que précédemment, donner le code Java de la méthode gestionnaire qui effectue les actions ci-dessus. 2 Exercice 4 : Grammaire attribuée On s’intéresse aux expressions arithmétiques à la Scheme (langage fonctionnel) engendrées par la grammaire Ge de terminaux {+, *, (, ), entier } et d’axiome E : E → entier | ( op listeE ) listeE → E listeE | ǫ op → + | * Ge engendre par exemple les mots entier, (+), (* entier), (+ (* entier entier) entier entier). Scheme évalue les expressions en partant du principe que l’élément neutre pour l’addition est 0 et l’élément neutre pour la multiplication est 1. L’interprète Scheme donne donc : > (+) > (*) > 5 0 1 5 > (+ 2) > (* 2) > (* 4 3 2) 2 2 24 > (+ 0) > (* 0) > (+ (* 4 2) 3 (* 2 2)) 0 0 15 On suppose que le terminal entier possède un attribut val de type entier qui contient sa valeur, synthétisé par l’analyseur lexical. On suppose donnée la classe Java Oper : Décembre 2009 2 Licence info, S5 1ère session COMPIL Examen de compilation public class Oper { ... /** opérateur d’addition. */ public static final Oper ADD = ... ; /** opérateur de multiplication. */ public static final Oper MULT = ... ; /** retourne le résultat de l’opération appliquée aux deux valeurs passées en paramètre. */ public int eval(int x, int y) { ... } /** retourne l’élément neutre de l’opération. */ public int valNeutre() { ... } } Q 4. 1 : Attribuez la grammaire Ge pour associer à l’axiome la valeur de l’expression reconnue en écrivant les règles sémantiques en Java. Vous préciserez pour chaque attribut à quel non-terminal il est attaché, quel est son type de données et s’il est hérité ou synthétisé. 2 Exercice 5 : TP Ava L’exercice a pour but d’envisager une partie du travail à réaliser sur le compilateur réalisé en TP pour rajouter à Ava le type flottant. Les constantes de type flottant, par exemple 823.5, 2e-12, 3.12E5, ont le format suivant : – elles commencent par une suite de chiffres non signée ; – cette suite de chiffre est suivie d’une partie réelle et d’une partie exposant, ou d’une partie exposant seule, ou d’une partie réelle seule ; – la partie réelle commence par un point suivi d’une suite de chiffres ; – la partie exposant commence par la lettre e ou E suivie d’une suite de chiffres éventuellement signée par - ou +. Les variables de type flottant sont déclarées par le mot-clé float. On aura par exemple par float x,y ;. Les opérateurs utilisés dans les expressions entières peuvent aussi être utilisés sur des valeurs de type flottant, à l’exception de l’opérateur modulo (mod). La règle de typage est la suivante : si au moins l’un des opérandes est de type flottant, alors le résultat est de type flottant. Par exemple 5/2.5 est une division sur flottant qui retourne un flottant, 5/2 est une division entière qui retourne un entier. Au niveau des impressions, on ajoute le format %f pour imprimer un flottant, par exemple writeln(%f, x+1). L’expression peut être de type entier (conversion de type implicite). De même, lors d’une affection d’une expression à une variable de type flottant, l’expression pourra être de type flottant ou entier. Q 5. 1 : Quel symboles devez-vous rajouter à votre analyseur lexical ? Donner une expression ou description régulière pour chacun d’entre eux et préciser si ce symbole est prioritaire sur l’un des symboles existants. Il n’est pas demandé d’utiliser la syntaxe de JFlex. 2 Q 5.2 : Quelles productions devez-vous ajouter à votre analyseur syntaxique ? Il n’est pas demandé d’utiliser la syntaxe de Cup. 2 Q 5. 3 : Quelles opérations de contrôle / inférence de type (incluant les types entier et booléen) devez-vous mettre en œuvre pour : – la déclaration d’un identificateur de type flottant (on supposera que Type inclut la valeur Type.FLOTTANT) ; – l’affectation ; – l’addition. Il n’est pas demandé de répondre en terme de visiteur mais seulement en terme de structure de données et de typage. 2 Décembre 2009 3 Licence info, S5