COMPILATION Mohamed BOUHDADI & Faissal OUARDI Théorie des langages et COMPILATION des langages de programmations impératifs Syntaxe & Sémantique de traduction des langages de programmation impératifs Introduction et vue d’ensemble Fonction et Spécification d’un compilateur Erreurs Programme dans un langage source Compilateur Programme équivalent dans un langage cible ( ou exécutable) 1- Vérifier si le programme source ∊ au langage source : ANALYSE - ANALYSEUR 2- Traduire un programme bien formé en son programme équivalent dans un langage cible (exécutable) : SYNTHÈSE ou TRADUCTION ; SYNTHÉTISEUR - TRADUCTEUR SPÉCIFICATION d’un COMPILATEUR : 1- Comment spécifier le langage source ? Théorie des langages (trois type de langages) 2- Comment spécifier le langage cible ? 3- Comment vérifier l’appartenance d’une chaîne de caractères au langage source ? Théorie des automates : (Trois sous-fonctions ) 4- Comment traduire ou synthétiser une chaîne de caractères (un programme) bien formée en son équivalent (unique) dans le langage cible. (Trois sous fonctions ) SYNTAXE et SÉMANTIQUE La syntaxe d’un langage de programmation détermine ce qui constitue un programme valide du point de vue de la forme du texte. Quelles séquences de caractères constituent des programmes ? Théorie des langages et des automates : Classification de Chomsky LA FORME DES CONCATÉNATIONS La sémantique définit la signification d’un programme, c’est-`a-dire ce qu’il calcule, comment il le calcule. Dans le cas de la compilation il s’agit d’une sémantique de traduction : translational semantics Sémantiques formelles: théories de la programmation La sémantique formelle est l’étude de la signification des programmes informatiques vue en tant qu’objets mathématiques Les objets mathématiques dépendent des propriétés à connaître du programme. L’objectif d’une sémantique formelle est de prouver qu’un programme est correct Sémantiques usuelles d’un langage de programmation Sémantique opérationnelle : la signification d’un programme est la suite des états de la machine qui exécute le programme. Un programme est considéré comme la description d’un système de transition d’états. Sémantique dénotationnelle : Une fonction mathématique appelée dénotation est associée à chaque programme, et représente en quelque sorte son effet, sa signification. Cette fonction prend par exemple pour argument l’état de la mémoire avant exécution, et a pour résultat l’état après exécution. Ce type de sémantique joue un rôle très important en compilation Sémantique axiomatique : Le programme n’est plus qu’un transformateur de propriétés logiques sur l’état de la mémoire. si on a p vrai avant exécution, alors on a q vrai après. On ne s’intéresse plus à l’état précis de la mémoire tant que l’on sait dire si la propriété tient. Sémantique algébrique : est une forme de sémantique axiomatique qui se base sur les lois algébriques pour la description et le raisonnement liés au sens d’un programme de façon formelle Tendance actuelle : Vers un cadre unique pour les différentes sémantiques : UTP : Unifying Theories of Programming Langages de Spécification formels Un langage de spécification est un langage formel utilisé pour décrire un système à un niveau beaucoup plus élevé qu'un langage de programmation, qui est utilisé pour produire un code exécutable pour un système. Domaines d’utilisations : - Ingénierie des protocoles de communications : Vérification et validation - Conception électronique - Les systèmes qualifiés de « critiques » : Une panne peut avoir des conséquences dramatiques : des morts ou des blessés graves, des dégâts matériels importants, ou des conséquences graves pour l’environnement ● les systèmes de transport : pilotage des avions, des trains, logiciels embarqués embarqués automobiles ● la production d'énergie : contrôle des centrales nucléaires; ● la santé: chaînes de production de médicaments, appareil médicaux (à rayonnement ou contrôle de dosages) ● le système financier : paiement électronique ; ● les applications militaires. Exemples de langages de spécification formels : Z, Object-Z, CSP (Calculus of Sequential Processes), T-CSP (Timed-CSP), TCOZ ( T-CSP Object-Z) Calculus of Communicating Systems ( CCS ) Language Of Temporal Ordering Specification ( LOTOS ) SDL (Specification and Description Language), Estelle, Esterel B, Event-B Paradigmes et Langages de programmation Un langage de programmation est une notation conventionnelle destinée à formuler des algorithmes et produire des programmes informatiques qui les appliquent. Un langage de programmation est composé d'un alphabet, d'un vocabulaire, de règles de grammaire et de significations Un paradigme de programmation est une façon d'approcher la programmation informatique et de traiter les solutions aux problèmes et leur formulation dans un langage de programmation approprié. Un paradigme de programmation fournit (et détermine) la vue qu’a le développeur de l’exécution de son programme Programmation impérative La programmation impérative est un paradigme de programmation qui décrit les opérations en séquences d'instructions exécutées par l'ordinateur pour modifier l'état du programme. L'état du programme à un instant donné est défini par le contenu de la mémoire centrale à cet instant. La programmation impérative s'appuie sur le modèle des machines à états avec une mémoire centrale et des instructions qui modifient son état grâce à des affectations successives. ( Machine de Turing et Architecture de von Neumann), Exemples : le langage machine, Fortran, Algol, Cobol, Basic, Pascal, C, ADA, Smalltalk, C++, Objective C, Perl, Python, Php, Java, Javascript Programmation fonctionnelle La programmation fonctionnelle est un paradigme de type déclaratif qui considère le calcul en tant qu'évaluation de fonctions mathématiques. Le paradigme fonctionnel n'utilise pas de machines à états pour décrire un programme, mais un emboîtement de fonctions qui agissent comme des « boîtes noires » que l'on peut imbriquer les unes dans les autres. Exemples : Lisp, ML, Haskell, OCaml, Programmation logique La programmation logique définit les applications à l'aide d'un ensemble de faits élémentaires les concernant et de règles de logique leur associant des conséquences plus ou moins directes. Ces faits et ces règles sont exploités par un démonstrateur de théorème ou moteur d'inférence, en réaction à une question ou requête. Exemples : Prolog, Oz, Python : PyPy Et bien d’autres paradigmes Programmation concurrente, Programmation par contraintes, Programmation distribuée, Programmation génétique, métaprogrammation, etc SYNTAXE : Théorie des langages et des automates La hiérarchie ou classification de Noam Chomsky TYPE 3 : Langages rationnels (réguliers) TYPE 2 : Langages algébriques (indépendant du contexte) Contexte-free TYPE 1 : Langages contextuels (Contexte-sensitive) TYPE 0 : Langages récursivement énumérables TYPE 3 ⊊ TYPE 2 ⊊ TYPE 1 ⊊ TYPE 0 QUESTION : Les langages de programmation sont de quel type ? REPONSE : Ils sont contextuels mais ILs contiennent des sous langages qui sont indépendants du contexte et des sous langages qui sont réguliers Langages impératifs : Instructions Une Instruction est soit : 1- une entrée ou une sortie (input/output) 2- une séquence d’instructions : instruction ; instruction 3- une instruction d’assignement ( l’affectation) : Identificateur ← Expression 4 - une instruction d’alternative (choix conditionnel) : si ( Expression ) alors Instruction sinon Instruction ; 5 - une instruction de répétition (bouclage ou itération) : Tant que ( Expression ) faire Instruction ; 6- Appel de fonction ( déclaration et définition) : Identificateur ( liste de paramètres effectifs) ; La séquence, l’affectation, le choix et la répétition sont suffisantes pour implémenter toutes les solutions informatiques possibles Ces 4 instructions constituent un système Turing Complet Information - donnée ( types ) Types de base ou types primitifs : alphabet, entiers, réels, booléens Constructeurs de types : 1- Structure 2- Tableaux 3- Adresses : de données et de fonctions LANGAGE DES IDENTIFICATEURS Alphabet : ensemble fini de symboles ou lettres ou caractères, ou TERMINAUX exemples : ASCII, {0,1}, {a, b, c }, { bleu, rouge, vert } sont des alphabets. La seule information dont on dispose est l’ordre de chaque terminal Opérations sur un alphabet : la concaténation notée . , l’union notée + ou * ( zéro ou pusieurs ) a.(a | b).(a+b)* , (a+b).(a+b)*.b sont des langages répétition notée * (a | b)*, | et la LANGAGE DES IDENTIFICATEURS Question : Comment peut on définir un exemple de langage pour les identificateurs ? Exemple : un identificateur est chaine de caractères qui commence par une lettre suivie de zéro ou plusieurs lettres ou chiffres et terminée par le symbole $ On peut introduire de nouveaux symboles NON-TERMINAUX pour simplifier la définition du langage des identificateurs ID : lettre ⟶ {a,b, ..z, A, B, ..Z } Chiffre ⟶ {0,1,..,9} // // ⟺ [a..z,A..Z] ⟺ [0..9] ID ⟶ lettre.( lettre | chiffre).*$ // * signifie zéro ou plusieurs Notation : Une partie gauche suivie d’une flèche suivie d’une partie droite NomDUnLangage ⟶ FormeDesMotsDeCeLangage La partie gauche est un symbole non-terminal ( c’est à dire ∉ à l’alphabet ) La partie droite est une expression résultant de l’application des trois opérations sur l’union l’ensemble des terminaux ( symboles ∈ à l’alphabet) et l’ensemble des non-terminaux ( symboles ∉ à l’alphabet ). Une substitution des nouveaux symboles par ce qu’ils désignent ( parties droites) donne : ID * ⟶ {a,b, ..,z, A, B, ..Z } . ( {a,b, ..z, A, B, ..Z } | {0,1,..,9} ) $ Les identificateurs (les mots du langage ID ) sont définis indépendamment les uns des autres. Pas de relation entre eux. Le langage ID est défini en utilisant uniquement les symboles de l’alphabet (les terminaux). Ce type de langage est dit langage régulier ou rationnel Le langage qui permet de décrire les langages réguliers : les grammaires régulières Les entiers, les réels, les opérateurs arithmétiques, les opérateurs logiques, les opérateurs relationnels sont des langages réguliers Une question s'impose : Etant donnée une expression spécifiant un langage régulier, et étant donné un mot, comment répondre à la question : Ce mot appartient-il au non au langage spécifié par cette expression ? Comment analyser un langage régulier ? ID : lettre.( lettre | chiffre)*.$ Départ Acceptation Un mot a un début et une fin : le premier caractère et le dernier caractère Le premier pointeur Départ désigne la situation où on doit être avant la lecture du premier caractère du mot. Le pointeur Arrivée ou Acceptation désigne la situation finale, là on on doit etre après la lecture du dernier caractère du mot L’expression peut être spécifiée par un ensemble de situations dont deux types sont particulières : situations de départ et situations d’arrivée. Le diagramme de situations pour l’expression dénotant le langage ID : lettre | chiffre lettre ID : ⟲ $ Situation de départ est marquée par une flèche entrante Situation d’acceptation est marquée par une flèche sortante. Il s’agit de gérer deux avancées ( deux mouvements) : - une avancée dans le mot en entrée : variable caractère et une avancé dans dans le modèle des mots : variable situation Initialization : On pointe sur la situation de départ, et on pointe sur le premier caractère en entrée, A chaque étape, l'action consiste à comparer le caractère courant avece l’étiquette (chacune des étiquettes) de la flèche sortant de la situation courante. Si ces deux symboles coïncident on avance dans l’entrée ( on lit le prochain caractère) et on avance dans le modèle ( on change de situation). Sinon le mot en entrée n’est pas un identificateur Si après la lecture de tous les caractères formant le mot en entrée, on atteint une situation d’acceptation, alors le mot appartient au langage dénoté par l’expression. Sion il ne lui appartient pas. Les mots a$, a1A$, Ba1?ad, 12a sont-ils des identificateurs ? lettre | chiffre lettre ID : q1 q0 ⟲ $ q2 a$ q0,a,q1,$,q2 a$ ∊ a1A$ q0,a,q1,1,q1,A,q1,$,q2 a1A$ ∊ Ba1?ad q0 ,B,q1,a,q1,1,q1, ?, ∅ ID ID Ba1?ad ∉ ID Analyse linéaire : structure d’automates à états finis lettre | chiffre lettre ID : q1 q0 ⟲ $ q2 a$ q0,a,q1,$,q2 a$ ∊ a1A$ q0,a,q1,1,q1,A,q1,$,q2 a1A$ ∊ Ba1?ad q0 ,B,q1,a,q1,1,q1, ?, ∅ ID ID Ba1?ad ∉ ID Analyse linéaire : structure d’automates à états finis Le langage des expressions arithmétiques sur N: E : ensemble des expressions arithmétiques ∀ nb ∊ N : nb ∊ E ∀ e1,e2 ∊ E : (e1 + e2 ) ∊ E et ( e1 * e2 ) ∊ E NOTATION : E ne peut être défini que de façon récursive E ⟶ nb | E⟶ E + E | E⟶ E * E L’alphabet = {nb, +, *} , E : non terminal et désigne un langage, Les parties droites désignent les concaténations de terminaux et non terminaux définissant la forme des expressions. Elles sont dites parties droites des Productions E Formalisme : < Terminaux, Non Terminaux, Non-Terminal Principal, Productions> E E: 0 2 1 E E: E + 4 3 E * 5 6 7 nb E: 8 9 mot = nb + nb * nb ⋲ E ? ↑↑ ↑ ? E ⟹ E + E ⟹ nb + E ⟹ nb + E * E ⟹ nb + nb * E ⟹ nb + nb * nb ↑ ↑ ↑ ↑↑ ↑ ↑ ↑↑ ↑ La séquence d’états : 0, 8, 9, 1, 2, 4, 8, 9, 5, 6, 8, 9, 7, 3 On a besoin de sauvegarder l’état à partir duquel on va continuer l’analyse : Structure arborescente - Automate + Pile Arbre syntaxique E E Arbre abstrait + + E * nb nb E nb * E nb nb nb E ⟹ E * E ⟹ E + E * E ⟹ nb + E * E ⟹ nb + nb * E ⟹ nb + nb * nb Arbre syntaxique Arbre abstrait E * E * E + nb E + E nb nb nb nb nb Deux choix doivent être faits : - Choix concernant le sens de lecture de la chaîne en entrée : de la gauche vers la droite ou l'inverse : left to right - Choix concernant l’utilisation des productions : de la gauche vers la droite ( Dérivation ) ou de la droite vers la gauche ( Réduction) . Approche descendante ( top-down ) : L’arbre syntaxique est construit du haut vers le bas . Approche ascendante (Bottom-Up) L’arbre est construit du bas vers le haut Analyse descendante et analyse ascendante LL(1) : Left to Right Scanning of the Input LeftMost Derivation 1 lookahead ( un seul de prévision) LR(1) : Left to Right Scanning of the Input Rightmost Derivation in Reverse 1 lookahead Souvent, on utilise les deux approches Le langage des expressions arithmétiques, des expressions logiques, des instructions, des parenthèses équilibrées ne peuvent être définis que de façon récursive Ils sont dits langages algébriques ou indépendants du contexte (contexte-free) et sont décrits par des grammaires algébriques ou grammaires indépendantes du contexte (contexte sensitive) Formalisme de grammaires indépendantes du contexte ou algébriques : < Terminaux : T, Non Terminaux : N, Non-Terminal Principal : S, Productions> : P T : ensemble de symboles définissant l’alphabet N : ensemble de symboles définissant des langagaes (sous-langages) S : le symble de départ (ou axiome) :Start P: ensemble de productions définissant les différents sous-langages T∩N=∅ S∈N P ⊆ { ( X , 𝞪 ) | X N , 𝞪 ∈ ( N ⋃ T )* } La partie gauche d’une production doit etre un non-terminal et la partie droite peut contenir à la fois des terminaux et des non-terminaux Les différents langages X ∈ N sont définis indépendamment les uns des autres : Pas de relation longue distance Les suites de symboles sont des chaînes. Une chaîne 𝝱 est directement dérivable d’une chaîne 𝝰 ce qui s’écrit 𝝰 ⟹ 𝝱 si et seulement s’il existe les chaînes 𝞭₁, 𝞭₂ et 𝞬 et un non-terminal X ∈ N, tels que 𝝰 =𝞭₁ X 𝞭₂, 𝝱 =𝞭₁ X 𝞭₂, (X,𝞬 ) ∈ P Si nous avons une chaîne et remplaçons un non-terminal X qu’elle contient par sa partie droite 𝞬 dans une production, nous obtenons une chaîne directement dérivable de X Cette substitution est appelée étape de dérivation Une chaîne 𝝱 est dérivable d’une chaîne 𝝰 ce qui s’écrit 𝝰 ⟹* 𝝱 si et seulement si 𝝰 = 𝝱, ou il existe une chaîne 𝞬 telle que 𝝰 ⟹* 𝞬 et 𝞬 ⟹ 𝝱 Une chaîne est dérivable d’une autre si nous pouvons atteindre la deuxième chaîne depuis la première par zéro, un ou plusieurs pas de dérivation. Le langage 𝖫 engendré par une grammaire G est défini par L(G) = { 𝝰 | ( S ⟹* 𝝰 ) ∧ ( 𝝰 ∈ T*) } Langages de programmation sont contextuels (contexte-sensitive) Deux exemples de contraintes contextuelles : 1- Chaque identificateur doit être déclaré avant d’être utilisé. { 𝞪𝞪 | 𝞪 ∈ ∑* } , ∑ un alphabet n’est indépendant du contexte 2- Chaque appel de fonction doit être conforme à la déclaration en terme de nombre et types de paramètres : { aⁿ bⁱ cⁿ dⁱ | n, i ≥ 1 } X désigne un langage. X est un langage contextuel si X admet une production dont la forme est : 𝝰X𝝱 ⟶𝝰𝜸 𝝱 𝝰, 𝝱 et 𝜸 sont des concaténations de terminaux et de non terminaux Les mots de X ont la forme 𝜸 à condition que le contexte à droite et celui à gauche de S sont respectivement 𝝰 et 𝝱. Hiérarchie de Chomsky TYPE 3 : Langages rationnels - Grammaires régulières - Automate fini TYPE 2 : Langages algébriques - Grammaires algébriques - Automate à pile TYPE 1 : Langages contextuels - Grammaires contextuels - Automate linéairement borné ( Grammaires attribuées ) TYPE 0 : Langages récursivement énumérables - Machine de Turing Principes de Conception d’un Compilateur (phase d’analyse) La conception d’un compilateur se base sur la classification de Chomsky pour la spécification des langages de programmation et pour automatiser la construction de leurs analyseurs. Le sous-langage régulier (LE LEXIQUE) : analyse lexicale (micro-syntaxe) Le sous-langage indépendant du contexte ( LA SYNTAXE) : analyse syntaxique (macro-syntaxe) Le sous langage contextuel ( LE CONTEXTE ): analyse sémantique ou analyse du contexte Analyse lexicale (micro-syntaxe) Les identificateurs, les entiers, les réels, les opérateurs arithmétiques, les opérateurs logiques, les opérateurs relationnels .. Analyse syntaxique (macro-syntaxe) Les expressions arithmétiques, les expressions logiques, les instructions, les types, les parenthèses équilibrées. Analyse sémantique ou du contexte - Analyse des identificateurs ( noms) - durée de vie - scope - les types. Grammaires attribuées : Compléter par l’information liée au contexte et contrôler les contraintes contextuelles et ... Erreurs chaîne de caractères Analyseur Lexical Lexème : une chaîne de lexèmes Représentation Analyseur Syntaxique Arbre syntaxique ou abstrait Classe lexicale L’analyse lexicale transforme un flot de caractères en un flot de lexèmes (mot , classe) ; L’analyse syntaxique transforme un flot de classes de lexèmes en un arbre d’analyse, ou, probablement en un arbre abstrait. Un arbre abstrait est une version de l’arbre syntaxique dans laquelle on ne conserve que les noeuds sémantiquement importants Un analyseur lexical est reconnaisseur de modèles, qui découpe le flot d’entrée en lexèmes reconnus par les modèles de lexèmes du langage source La forme des lexèmes est décrite par des modèles dans un formalisme spécial, appelés expressions régulières Le travail de base d’un analyseur lexical est : étant donné un ensemble S de descriptions de lexèmes et une position P dans le flot d’entrée, de déterminer quelle expression régulière dans S reconnaît un segment de donnée commençant en P, et quel est ce segment. S’il y a plus d’un tel segment, l’analyseur lexical doit avoir une règle pour lever l'ambiguïté ; le segment le plus long est celui qu’on veut. Si le segment le plus long est reconnu par plus d’une expression régulière, on se repose sur l’ordre textuel dans lequel les descriptions de lexèmes sont données. Spécifier les descriptions de lexèmes les plus spécifiques avant les moins spécifiques Si toute suite de lettres sauf xyzzy est un identificateur ce qui suit suffira : symbole_magique identificateur xyzzy [a-z ]⁺ Un analyseur représente ses connaissances par un ensemble de situations. Une situation est une expression régulière nommée avec un point quelque part. .xyzzy x.yzzy xy.zzy xyz.zy xyzz.y xyzzy. La partie avant le point correspond à la dernière partie de l’entrée déjà examinée La partie après le point doit reconnaître la première partie du reste de l’entrée pour que la situation réussisse. Situation pointée Cₙ Cₙ₊₁ entrée T . 𝝰 𝝱 Déjà reconnu par 𝝰 Pas encore reconnu par 𝝱 L’examen d’un caractère a pour effet qu’une situation est transformée en zéro, une ou plusieurs nouvelles situations. Cette transition est un avancement. T . 𝝰 c𝝱 c ⟹ c T . 𝝰c 𝝱 L’ensemble des situations sont des états, les transformations sont des transitions d’états. Une situation avec un point à la fin, appelée situation de réduction (utilisation de productions de la droite vers la gauche), signale qu’on vient de trouver un lexème possible, mais la fin de lexème le plus long est peut être plus loin. ID Entier lettre.( lettre | chiffre)* chiffre . chiffre* lettre | chiffre lettre ID : q0 ⟲ q1 Reconnaît tous les identificateurs chiffre chiffre Entier : q2 ⟲ q3 Reconnaît tous les entiers Règle de la correspondance la plus longue : - Changer la nature des situations finales ( les états d’acceptation ou états finaux) : ne sont plus états d’acceptation - Continuer à avancer tant qu’il s’agit de préfixes du même lexème lettre | chiffre ⟲ lettre ID : q0 chiffre Entier : ni lettre, ni chiffre q1 chiffre q2 Exemple : entrée : a1b3d?a12a.123a ⟲ q3 ACTION q4 ACTION autre que chiffre q5 sortie : ? Nous avons besoins de deux pointeurs pour délimiter la représentation de chaque type de lexème son début et sa fin a 1 b 3 d ? a 1 2 a !1 2 3 a a début 1 b fin fin 3 fin d fin ? fin a 1 2 a ! 1 2 3 a fin On explore le modèle des identificateurs en premier puis si nécessaire celui des entiers : deux variables pour parcourir les modèles : L’état initial courant et l’état courant : Initial ← état ← q0 (état, a) ⟶ q1 (q1, ?) ⟶ q4 (q1, 1) ⟶ q1 (q1, b) ⟶ q1 (q1, 3) ⟶ q1 (q1, d ) ⟶ q1 ∈ F = ensemble des états finaux Reconnaître que le mot situé entre début et fin moins 1 est un identificateur ; et traiter le reste de l’entrée : debut ← fin (refaire le même traitement ) a 1 b 3 d ? a début 1 2 a . 1 2 3 a fin Initial ← état ← q0 (état, ?) ⟶ ∅ : Ce modèle ID ne peut accepter de mot commençant par ce caractère { ACTION : Acceptation } ⟲ lettre ID : q0 q1 ni lettre, ni chiffre q4 autre que lettre ∅ { ACTION : annuler les mouvements et explorer l’automate suivant } Annuler les mouvements dans la chaîne d’entrée et explorer le modèle suivant s’il en reste fin ← début Initial ← état ← q2 (état, ?) ⟶ ∅ Aucun modèle ne peut reconnaître un mot commençant par le caractère ? On ignore ce symbole : debut ← debut +1; fin ← début ; a 1 b 3 d Initial ← état ← q0 (état, a) ⟶ q1 (q1, .) ⟶ q4 ? a 1 début fin fin (q1, 1) ⟶ q1 2 a fin fin (q1, 2) ⟶ q1 ! 1 2 3 fin (q1, a) ⟶ q1 ∈ F = ensemble des états finaux a a 1 b 3 d ? a 1 début fin fin 2 a fin fin ! 1 2 3 a fin Initial ← état ← q0 (état, a) ⟶ q1 (q1, .) ⟶ q4 a 1 b (q1, 1) ⟶ q1 (q1, 2) ⟶ q1 (q1, a) ⟶ q1 ∈ F = ensemble des états finaux : a12a ∈ id 3 d ? a 1 2 a ! début 1 fin 2 3 a a 1 b 3 d ? a 1 2 a ! 1 2 début fin fin 3 a fin fin état = q5 : 123 est un entier a 1 b 3 d ? a 1 2 a ! 1 2 3 début a fin a 1 b 3 d entrée : a1b3d?a12a.123a sortie : ( a1b3d , ID ) ( a12a , ID ) ( 123, Entier ) ( a, ID ) ? a 1 2 a ! 1 2 3 début a fin L'analyseur lexical initialise une structure de donnée appelée Table de symboles ou tables des noms. Chaque entrée correspond à une déclaration d’un nom. Ce qui signifie qu’ à chaque reconnaissance d’un mot on teste s’il existe dans “ la table ”. Si oui on fait rien sinon on l’insère ainsi que sa classe. Une table de symboles est un tableau extensible d'articles, indexé par des chaînes. La chaîne est l’identificateur, et l’article correspondant contient toutes les informations à son sujet Représentation Classe a1b3d ID a12a ID 123 Entier a ID Table de Symboles L’analyseur lexical est un programme qui gère quatres variables : - deux pointeurs pour délimiter la représentation de chaque lexème en entrée : son début et et sa fin ; - deux états pour parcourir les différents modèles de lexèmes état initial courant ( initial ): pour sauvegarder l’automate en cours d’exploration, et état courant pour sauvegarder l’état où on est. - Pour chaque état on associe un fragment de code qui consiste en des comparaisons du caractère en entrée courant avec les différents étiquettes des différents transitions sortant de cet état, et on transfère le contrôle. - Initialise la table des symboles deux fonctions : rechercher et insérer Erreurs chaîne de caractères Analyseur Lexical Lexème : une chaîne de lexèmes Analyseur Syntaxique Représentation Arbre syntaxique ou abstrait Classe Table de symboles ou table des noms E ⟹ E + E ⟹ nb + E ⟹ nb + E * E ⟹ nb + nb * E ⟹ nb + nb * nb Arbre syntaxique E Arbre abstrait E + E + * nb nb E nb * E nb nb nb Un analyseur construit l’arbre syntaxique correspondant à une suite donné de lexèmes Construire l’arbre syntaxique signifie que l’on crée un arbre de noeuds et que ces noeuds sont étiquetés par les symboles grammaticaux, de telle manière que : - les noeuds feuilles sont étiquetés par des terminaux, et les noeuds internes par des non-terminaux ; - le noeud racine est étiqueté par le symbole de départ de la grammaire ; - les fils d’un noeud interne X correspondent aux membres d’un des choix de X, dans le même ordre que dans le choix ; - les terminaux étiquetant les noeuds feuilles correspondent à la suite de lexèmes, dans le même ordre que dans l’entrée. - Un analyseur syntaxique est un analyseur lexical dans le sens ou ils font la même chose, la différence réside dans les formes des mots qu’ils reconnaissent - - Pour l'analyseur lexical l’alphabet est l’ensemble des caractères ; et pour l’analyseur syntaxique l’alphabet est l’ensemble des classes de lexèmes. L’analyseur syntaxique est le programme principal qui appelles (ou invoque) l’analyseur lexicale pour lui retourner la prochaine unité lexicale : lexème_suivant ( ) Erreurs lexème_suivant chaîne de caractères Analyseur Syntaxique Analyseur Lexical Lexème mot classe Table des symboles Arbre syntaxique ou abstrait Erreurs chaîne de caractères lexème Analyseur Lexical Analyseur Syntaxique Lexème_suivant Mot Unité Lexicale Table des symboles Type Arbre syntaxique ou abstrait Erreurs lexeme_suivant chaîne de caractères Analyseur Lexical Arbre abstrait lexème Mot Analyseur contextuel Analyseur Syntaxique Unité Lexicale Type Arbre Abstrait décoré Table des symboles Principes de Conception d’un Compilateur (phase de synthèse) - Le code doit être indépendant de toute machine (Unité centrale) et de tout système d’exploitation : code intermédiaire ( codes à trois adresses, C--) - Le code doit être optimisé : Analyse de la complexité algorithmique Gestion des variables Temporaires (évaluations des expressions) Optimisation des boucles imbriquées Principes de Conception d’un Compilateur (phase de synthèse) Arbre Abstrait Décoré générateur du code intermédiaire Optimisation du code Code intermédiaire Générateur du code cible Code optimisé Code cible Sommaire : Chapitre 2 - Contexte et traduction des constituants de langages de programmation impératifs Chapitre 3 - Les langages réguliers - Algorithmes ( de transformations) : Expression régulière ⋳-NFA DFA ⋳-NFA - Automate Minimal - Lemme de l’étoile : caractérisation des langages réguliers - Analyseurs lexicaux manuels et automatiques ( l'outil flex) Chapitre 4- Langages algébriques (context free) - Grammaires algébriques - langages algébriques - Analyse par descente récursive : LL(1) - Analyse automatique et Interprétation (l’outil BISON)