Compilation Introduction à la compilation

publicité
Enseignants :
Stéphane Talbot
Miguel Tomasena
Compilation
Volume horaire : 10.5 C / 12 TD / 12 TP
Contenu :
Introduction à la compilation
Analyse Lexicale
Analyse Syntaxique
Traduction dirigée par la syntaxe
Analyse Sémantique
Production de code
Optimisation
Traduction
Programme en
langage cible
Programme en
langage source
1
2
Compilation
Références :
Introduction à la
compilation
• Compilers : Principles, Techniques and Tools (dragon book).
Alfred V. Aho, Ravi Sethi, Jeffrey. D. Ullman, Addison-Wesley,
2ème édition 2007.
• Programming Language processors in Java. D. Watt & D.
Brown, Prentice-Hall, 2000.
Termes
Phases d'un compilateur
Importance des grammaires
• Cours de compilation. Luc Maranget. Sur le Web.
• JFlex - The Fast Scanner Generator for Java. Sur le Web.
Méthodes d'analyse
• CUP Parser Generator for Java. Sur le Web.
3
4
Termes
Termes
Terminologie :
Compilateur : programme qui traduit d'un langage source vers un
langage cible, en signalant d‘éventuelles erreurs
La Syntaxe régit la forme, la structure d'une phrase. Exemple :
if (3+5 ==9) print ("bravo ")
Deux niveaux syntaxiques peuvent être cités :
– Lexique : forme des symboles terminaux (les mots)
– Syntaxique : forme d’une suite de terminaux
La compilation concerne :
• Langages informatiques
• Architecture de machines
• Théorie des langages
• Algorithmique
5
La Sémantique régit la signification. Exemple d’erreur
sémantique :
if (3 == false) print ("bravo ")
6
Termes
Termes
Interpréteur : interpréter c’est parcourir un graphe (structure de
données) dont les nœuds sont les instructions.
Un interprète exécute lui même les instruction du programme.
Compilateur : Un compilateur est un traducteur qui permet de
transformer un programme écrit dans un langage L1 (source) en
un autre programme écrit dans L2 (cible).
L1
L2 peut être un langage intermédiaire, assembleur ou un langage
d’une machine abstraite.
Les langages interprétés sont souvent plus simples et flexibles que
les langages compilés.
Exemples de langages compilés : C, C++, ADA, Pascal, Java.
Exemples de langages interprétées : JavaScript, PHP, BASIC,
scheme, CaML, LISP, Perl, Python, Prolog.
7
L2
8
Termes
Objectifs d'un Compilateur
Le P-code concerne à la fois la compilation et l’interprétation
Qu’attend-on d’un compilateur ?
Le code source est traduit (compilé) dans une forme binaire
compacte (pseudo-code ou p-code) qui n'est pas encore du code
machine. Lors de l’exécution le P-code est interprété.
La correction : le programme compilé doit représenter le même
calcul que le programme original. Il est équivalent.
Par exemple en Java le source est compilé pour obtenir un fichier
(.class) "byte code" qui sera interprété par une machine virtuelle.
L’efficacité : le compilateur doit produire un code qui s’exécutera
aussi rapidement que possible.
Les interpréteurs de P-code peuvent être relativement petits et
rapides, le P-code peut s'exécuter presque aussi rapidement que du
binaire.
9
10
Objectifs d'un Compilateur
Ecriture d'un compilateur : Bootstrap
Qu’attend-on d’un compilateur ?
L’écriture d’un compilateur est une tâche complexe, le
programmeur a intérêt à utiliser un langage de haut niveau.
La détection des erreurs. Exemples d'erreurs :
– Identificateurs mal formés, commentaires non fermés . . .
– Constructions syntaxiques incorrectes
– Identificateurs non déclarés
– Expressions mal typées : if 3 then "toto" else 4.5
– Références non instanciées
La plupart des compilateurs sont écrits en langage de haut niveau et
non en assembleur.
Si on ne dispose pas d’un langage de haut niveau, alors la stratégie
de « programme amorce » (bootstrap) peut s’appliquer.
Erreurs de Syntaxe. Erreurs détectées à la compilation, de nature
statique.
Erreurs d'exécution. Erreurs détectées à l’exécution, de nature
dynamiques (division par zéro, dépassement des bornes d'un
tableau, etc).
11
12
Compilation
Bootstrap
Stratégie de bootstrap. Si on veut un compilateur de L, on écrit
d’abord un compilateur pour le sous-ensemble L’ avec
l’assembleur M.
T-diagramme schématisant un traducteur de L’ vers M réalisé en M :
L’  M
M
Phases d'un compilateur
Le compilateur ainsi réalisé servira à la construction d’un
compilateur de L.
L  M
L’
Résultat
L  M
M
L’  M
M
13
14
Structure d’un compilateur
Structure d’un compilateur
Phases d'un compilateur :
Programme en
langage source
Analyse
lexicale
• Analyse sémantique : analyse l’arbre de syntaxe abstraite pour
calculer de nouvelles informations permettant de :
– Rejeter des programmes incorrects (portée, typage. . . )
– Préparer la phase de génération de code (organisation de
l’environnement, construction de la table de symboles,
résolution de la surcharge . . . )
Programme en
langage cible
Analyse
syntaxique
Analyse
sémantique
Génération
de code
• Génération de code : transformation l'arbre syntaxique abstrait
enrichi d'informations sémantiques en code machine ou
assembleur.
– Choix des instructions à émettre.
– Allocation de registres : association entre les idéntifiants et les
registres du processeur.
– Optimisation.
Gestion de
la table des
symboles
15
• Analyse lexicale : traduit une suite de caractères en suite de mots,
tokens, ou unités lexicales.
• Analyse syntaxique (ou grammaticale) : transforme une suite
d'unités lexicales en un arbre représentant la structure de la
Arbre de syntaxe abstraite :
phrase.
Structure intermédiaire avant l'analyse sémantique .
Représente les dépendances sémantiques.
16
Phases de compilation, exemple
Phases de compilation, exemple
Exemple :
Table de symboles. Le compilateur doit garder trace des noms de
variables et les information correspondantes :
• mémoire réservée,
• type,
• portée,
• pour les sous-programmes : nombre et type des paramètres,
mode de transmission de chacun, type du résultat.
let p = i + v * 60
Analyse lexicale consiste à identifier les tokens ou unités lexicales.
Token
let
position
=
initial
+
vitesse
+
60
17
Unité lexicale
mot clé
identificateur (id1)
let p = i + v * 60
affectation
Table de symboles
identificateur (id2)
Adresse
Symbole
Informations
identificateur (id3)
id1
p
int
produit
id2
i
int
entier
id3
v
int
…
…
…
addition
18
Phases de compilation, exemple
Phases de compilation, exemple
Analyse syntaxique (parser) vérifie que l’ordre des unités lexicales
correspond au langage (à sa grammaire) et produit un arbre
syntaxique (de dérivation).
Arbre de dérivation :vs: arbre abstrait
• L’arbre de dérivation produit par l’analyse syntaxique
possède de nombreux nœuds superflus. La grammaire peut
comporter de règles dont le but est de simplifier l’analyse
syntaxique.
let p = i + v * 60
expr
let
IDENT
expr 
LET IDENT '=' expr
expr
=
• Un arbre abstrait constitue une structure plus naturelle entre
l’analyse syntaxique et l’analyse sémantique, il ne garde que
les parties nécessaires.
p
opbin
expr
terme
expr
+
expr
opbin
expr
• L’arbre abstrait peut se construire lors de l’analyse
syntaxique, en associant à toute règle de la grammaire une
action sémantique.
Ou bien à partir de l'arbre de dérivation.
IDENT
terme
*
nb
i
IDENT
60
v
19
20
Phases de compilation, exemple
Arbre abstrait
affectation
Phases de compilation, exemple
Génération de code intermédiaire.
let p = i + v * 60
Description d'une machine à registres :
• 8 registres (eax, ebx, ecx, edx, epb, esp, eflags, eip) :
• eax, ebx, ecx, edx sont des registres généraux :
• ebp et esp servent à gérer la pile (base et sommet de la pile) .
• eflags registre d’état.
• eip pointeur d’instruction.
Les types sont cohérent
+
p
*
i
i, vi,sont
v sont
desdéjà
entiers
précédemment
initialisées (déclarés)
déclarés
v
60
Analyse sémantique :
• Résolution des noms. Construction d'une table des symboles
en associant des étiquettes aux identifiants.
• Vérification de la cohérence de types.
• Vérification des initialisations. Certains compilateurs
signalent comme erreur la non-affectation initiale d'une
21
variable locale.
• Instructions de la forme :
• op dest,source
• op dest
• op
• Qqs instructions : add, sub, mul, div, mov, push, pop, jmp, jl, etc.
22
Code généré, exemple :
23
DATA
DATA SEGMENT
SEGMENT
p
p DD
DD
i DD
let p = i + v * 60
i
v
DD
i DD
v
DD
Instructions
précédentes.
DATA
déclaration
de données
v ENDS
DD
On mets i dans la pile
DATA
CODE
SEGMENT
DATA ENDS
ENDS
*
CODE
SEGMENT
...
CODE
SEGMENT
...
push
... eax,i
mov
mov eax,i
eax,v
eax,i
v
push
push eax
eax
mov
eax,v
mov eax,60
push
push eax
eax
multiplication
mov
pop eax,60
ebx
push
eax
pop eax
pop
mul ebx
eax,ebx
pop
pusheax
eax
mul eax,ebx
push eax
pop ebx
pop eax
affectation
add eax, ebx
push eax
pop eax
mov p, eax
CODE ENDS
Phases de compilation, exemple
Optimisation. Il existe une grande diversité de types d'optimisation.
Par exemple, dans le code précédent, il est inutile d'empiler pour
dépiler par la suite :
60
. . .
pop ebx
pop eax
add eax, ebx
push eax
pop eax
mov p, eax
. . .
24
. .
pop
pop
add
mov
. .
.
ebx
eax
eax, ebx
p, eax
.
Regroupement de phases
Autre phases de compilation
Partie frontale ou d’Analyse.
Phases qui dépendent du langage source : lexicale,
syntaxique.
Préprocesseur. Transformations sur un code source, avant la
compilation. Prise en compte de macros (#define) et des inclusions
de fichiers (#include).
Partie finale ou de Synthèse.
Phases qui dépendent de la machine cible.
Assembleur. Certain compilateurs produisent du code en langage
d’assembleur. Il faut donc produire du code machine
"translatable".
Programme en
langage source
Partie
frontale
(analyse)
code
intermédiaire
Partie
finale
(synthèse)
Programme en
langage cible
Chargeur. Le code "translatable" est modifié à absolu et placé en
mémoire aux emplacements appropriés.
--> On peut être amené a écrire seulement une de ces deux parties.
Relieur (éditeur des liens). Il permet de constituer un programme
unique à partir de plusieurs fichiers contenant du code
"translatable".
25
Passes : nombre de lectures du fichier source (une en général).
Compromis entre nombre de passes et la mémoire nécessaire.
26
Compilation
Traduction dirigée par la syntaxe
Partie frontale d’un compilateur
Description d’un langage source :
• Syntaxe : grammaire non contextuelle.
• Sémantique : descriptions plus ou moins formelles ou des
exemples.
Importance des grammaires
Une grammaire non contextuelle permet de :
• Spécifier la syntaxe
• Guider la traduction : traduction dirigée par la syntaxe.
Très utile pour organiser la partie frontale.
La traduction dirigée par la syntaxe est une combinaison d’un
analyseur syntaxique et d’un générateur de code intermédiaire.
27
28
Grammaire
Expression
suite de
caractères
Analyse
lexicale
suite
d’unités
lexicales
Grammaire
Traduction
dirigée par
la syntaxe
Une phrase générée par la grammaire G est obtenue en partant du
symbole initial et en appliquant des productions P jusqu'à
l'obtention des terminaux.
Représentation
intermédiaire
Le langage L(G) est l’ensemble de toutes les phrases que l’on peut
générer avec G. Formellement, on écrit :
L’ensemble de phrases syntaxiquement correctes d’un langage est
décrit par une grammaire.
* w}
L(G) = { w  Vt* | S0 
Une grammaire est un quadruplet G = (VT,VN, S0, P) où
29
•
VT est l’ensemble de symboles terminaux (unités lexicales),
•
VN est l’ensemble de symboles non terminaux,
•
S0  VN est l’axiome ou symbole de départ,
•
P est l’ensemble de productions (règles de grammaire) de la
forme 
30
Exemple
• VT = {il, elle, est, boit, vite, beau}
• VN = {<pronom>, <verbe>, <adj>, <phrase>}
• S0 = <phrase>
• P = { <phrase> <pronom> <verbe> <adj> ,
<pronom> il | elle ,
<verbe>  est | boit ,
Rmq : certaines phrases
<adj>
 vite | beau } n’ont pas de sens (il boit beau)
Grammaire
Grammaire et arbre syntaxique
Exemple de notation :
<bloc> begin <liste_opt_instr> end
<liste_opt_instr>  <liste_instr> | 
Chaîne vide
<liste_instr>
 <liste_instr> ; <intr> | <intr>
Hiérarchie des grammaires (Chomsky).
type
nom
grammaire
forme des
règles
structures
produites
exemple
typique
modèle
équivalent
3
régulières ou
rationnelle
A→wB
A→w
peignes
an
automate
fini
non contextuelle
ou algébrique
A →
arbres
2
anbn
réseau de
transition
récursif
anbncn
existe mais
compliqué
Voir l'exemple précédant
1
contextuelle
A→
0
générale
→
où
31
quelconque
dérivation :- application de
plusieurs productions successives
Arbre syntaxique (ou de dérivation)
• Illustre la manière dont l’axiome se dérive en une chaîne du
langage.
• Représentation graphique d’une suite de dérivations
machines de
Turing
A et B sont des non terminaux
Exercice : écrire les grammaires
et les automates correspondants
w est un terminal
,  et  sont des séquences de terminaux ou non terminaux et ≠ε
32
Propriétés d’un Arbre syntaxique :
1. La racine est étiquetée par l’axiome
2. Chaque feuille est étiquetée par un terminal (u.lexicale) ou par 
3. Chaque nœud intérieur est étiqueté par un non-terminal
4. Si A est le non-terminal d’un nœud et ses fils sont X1, .., Xn alors
A  X1, ..,Xn est une production
Grammaire et arbre syntaxique
Grammaire et arbre syntaxique
Grammaire ambiguë :
s'il existe plus d'un arbre pour une même phrase.
Règles pour résoudre l’ambiguïté :
1. Associativité des opérateurs : convention d'évaluation
Dans la compilation on besoin de grammaires non ambigües (ou des
règles pour résoudre l’ambigüité).
On peut être amené à réécrire une grammaire pour éviter les ambigüités.
Ex d'opérateurs : +, -, *, /
Ex d'opérateurs : =, **, &&, ||
Règle associative à gauche :
<expr> <expr> + <chiffre> |
<chiffre>
<chiffre>  0 | 1 | . . . | 9
Règle associative à droite :
<affect> <lettre> = <affect> |
<lettre>
<lettre>  a | b | c | . . . | z
Associativité à gauche
Exemple de grammaire ambiguë :
<chaîne> <chaîne> + <chaîne> | <chaîne> - <chaîne> |
0|1|2|...|9
Arbres pour 9 – 5 + 2
<chaîne>
<chaîne>
33
9
-
+
<chaîne>
-
<chaîne>
<chaîne>
+
<chaîne>
<chaîne>
2
9
5
<expr>
<chaîne>
5
<affect>
<expr>
<expr>
<chaîne>
<chaîne>
Associativité à droite
<chiffre>
2
34
Grammaire et arbre syntaxique
+
+
<chiffre>
<chiffre>
2
5
<lettre>
a
=
<affect>
<lettre>
=
<affect>
<lettre>
b
c
9
Grammaire et arbre syntaxique
Règles pour résoudre l’ambiguïté :
Démarche de la construction d'une grammaire non ambiguë des
expressions arithmétiques :
2. Priorité des opérateurs : convention d'évaluation.
1. On définit une table synthétisant l'associativité et la priorité des
opérateurs :
9 + 5 * 2 s'évalue 9 + (5 * 2)
associativité à gauche : + -
l'ordre correspond
à la priorité
associativité à gauche : * /
On dit que * a une priorité supérieure à + car il 'applique avant.
2. On introduit deux non-terminaux <expr> et <terme>
correspondant aux deux niveaux de priorité.
3. On introduit un autre non-terminal <factor> pour les unités de
base (impossible à éclater) : chiffres et expressions parenthèses.
35
36
Résultat :
<expr> <expr> + <terme> | <expr> - <terme> | <terme>
<terme> <terme> * <factor> | <terme> / <factor> | <facteur>
Arbre syntaxique
<factor> <chiffre> | (<expr>)
9+5*2
??
Grammaire et arbre syntaxique
Grammaire et arbre syntaxique
Exercice à faire
en cours
La grammaire précédente est ambiguë à cause du conditionnel.
Exercice écrire une grammaire pour un sous-ensemble des instructions
Java : <instr> et <instrs>.
Remarques :
• Considérez 7 types de <instr> : affectation, deux conditionnels,
while, do while, bloc d'instructions et instruction vide ( ).
La définition de <instr> repose sur :
<instr>, <instrs>,<bool> et <expr>
• Terminaux : id if else while do = ; ( ) { }
• Le point-virgule doit apparaître à la fin des productions qui ne
finissent pas par <instr>.
• La définition de <instrs> (liste de instructions) repose sur :
<instrs> et <instr>
37
<instr> if (<bool>) <instr> else <instr> |
if (<bool>) <instr> |
autres instructions
L'instruction if (estX) if (estY) a=x; else a=y;
admet deux arbres syntaxiques :
<instr>
if
estX
if ( <bool> )<instr>
estX
<instr>
if ( <bool>)<instr> else <instr>
estY
38
Traduction dirigée par la syntaxe
Ré-écriture de la grammaire pour enlever l'ambiguïté :
La traduction dirigée par la syntaxe est réalisée en attachant des règles
(ou programmes) à des productions.
<instr> <instr_close> | <instr_non_close>
<instr_non_close> if (<bool>) <instr> |
if (<bool>) <instr_close> else <instr_non_close>
<instr_close> if (<bool>) <instr_close> else <instr_close> |
autres instructions
Exemple :
<expr> <expr1> + <terme>
traduire <expr> peut se faire avec le pseudo-code suivant :
traduire expr1;
reconnaître "+"
traduire terme;
traiter addition;
L'instruction if (estX) if (estY) a=x; else a=y; admet un arbre
syntaxique :
<instr>
<instr_non_close>
if ( <bool> )
Le pseudo-code peut servir à construire un arbre abstrait pour expr,
ou bien pour un traitement plus simple comme par exemple la
traduction en postfix.
<instr>
<instr_close>
estX
if ( <bool> ) <instr_close>
else
<instr_close>
estY
40
Traduction dirigée par la syntaxe
Traduction dirigée par la syntaxe
Un Attribut : information associée aux unités (nœuds) syntaxiques.
Par exemple : chaîne de caractères; valeur, adresse mémoire, etc.
Deux manières d'associer les règles ou actions sémantiques à la
grammaire :
1. Définition dirigée par la syntaxe : chaque production est
accompagné d'une règle sémantique.
Une production peut avoir un ensemble de règles ou actions
sémantiques pour calculer la valeur des attributs.
2. Schémas de traduction : on insère des instruction (programmes) à
l'intérieur des productions. On parle d'actions sémantiques.
X.a dénote la valeur de l'attribut a du nœud X.
On dit que l'attribut est synthétisé quand la valeur remonte (est
calculée) à partir des attributs fils.
On parle d'attribut hérité dans le cas contraire, quand la valeur
provienne des nœuds ancêtres.
41
<instr> else <instr>
estY
Grammaire et arbre syntaxique
39
( <bool> )
<instr>
if ( <bool> )
42
Traduction dirigée par la syntaxe
Traduction dirigée par la syntaxe
1. Définition dirigée par la syntaxe.
Chaque production est accompagné d'une règle sémantique.
concaténation
Exemple traduire une expression en postfixe :
Production
Règle sémantique
L'arbre "décoré" est l'arbre syntaxique représentant explicitement les
valeurs des attributs pour chaque nœud.
L'arbre "décoré" correspondant à l'analyse de 9 + 2 * 4
<expr> <expr1> + <terme>
expr.t = expr1.t + terme.t + "+"
<expr> <expr1> - <terme>
<expr> <terme>
expr.t = expr1.t + terme.t + "-"
<terme> <terme1> * <factor>
<terme> <terme1> / <factor>
terme.t = terme1.t + facteur.t + "*"
terme.t = "9"
terme.t = "2" *
terme.t = terme1.t + facteur.t + "/"
facteur.t = "9"
facteur.t = "2"
<terme> <factor>
terme.t = facteur.t
<factor> (<expr>)
<factor> 0
facteur.t = expr.t
expr.t = "9 2 4 * +"
expr.t = terme.t
facteur.t = "9"
facteur.t = "0"
facteur.t = "1"
<factor> 1
...
43
44
Traduction dirigée par la syntaxe
2. Schémas de traduction. On insère des programmes (actions
sémantiques) à l'intérieur des productions.
<expr> <expr1> - <terme> {print("-")}
<expr> <terme>
<terme> <terme1> * <factor> {print("*")}
<terme> <terme1> / <factor> {print("/")}
<terme> <factor>
<factor> (<expr>)
<factor> 0 {print("0")}
Arbre syntaxique correspondant au schéma de traduction :
reste
{print("+")}
<factor> 1 {print("1")}
...
reste1
45
Les règles sémantiques ont été évaluées en faisant un parcours en
profondeur d'abord. On évalue après avoir visité tous les fils.
Les attributs sont synthétisés
<expr> <expr1> + <terme> {print("+")}
+ <terme> {print("+")} <reste1>
terme
2
Production
action sémantique
+
4
Traduction dirigée par la syntaxe
Par la suite on utilisera des schémas de traduction.
<reste> -->
facteur.t = "4"
Schémas de traduction pour traduire vers postfixe :
Similaire à une définition dirigée par la syntaxe, excepté que l'ordre
d'évaluation des actions sémantiques est donné explicitement.
Exemple :
9
terme.t = "2 4 *"
+
expr.t = "9"
terme.t = terme1.t + facteur.t + "*"
46
Compilation
Appliquez le schéma de traduction à l'expression : 9 + 2 * 4
Analyse syntaxique descendante
Deux méthodes d'analyse :
• Descendante : programmation facile, on part de l'axiome (racine)
• Ascendante : s'applique à des grammaires plus générales.
Des outils logiciels tendent à utiliser des méthodes ascendantes.
Méthodes d'analyse
Analyse descendante. On commence par l'axiome, en réalisant de
manière répétitive les deux étapes suivantes :
1. Au nœud n, étiqueté par un non-terminal A, choisir une production
de A et construire les fils de n avec les symboles de la partie
droite de la production.
Choisir selon le
symbole de prévision
2 . Choisir le prochain nœud où un sous-arbre doit être construit.
47
48
Choisir le nœud le plus à gauche :
dérivation gauche
Analyse syntaxique descendante
Analyse syntaxique descendante
Exemple d'application de l'analyse descendante :
Exemple de chaîne d'entrée : while (i<=6) a=a+1;
Sous-ensemble d'instructions de Java.
Au départ, le terminal while est le symbole de pré-vision.
<instr>  id = <expr> ;
|
if (<expr>) <instr>
|
while (<bool>) <instr> |
...
Entrée
while (i<=6) a=a+1;
Arbre
<inst>
<instr>
<inst>
while (
while (
49
Si le symbole de pré-vision nous signale une seule production
possible, alors on peut appliquer une analyse syntaxique prédictive
sans besoin de retour-arrière.
ou Analyse Descendante
Déterministe
50
Analyse syntaxique prédictive
•
•
Une procédure est associée à chaque non terminal.
Le symbole de pré-vision (preVis) permet de sélectionner de
manière définitive la production à appliquer.
Pseudo-code :
<instr>  id = <expr> ; |
51
if (<expr>) <instr> |
public void instr() {
while (<bool>) <instr> |<expr> ; |
switch (preVis){
...
case ID :
accepter(ID); accepter(AFFECT); expr( );
accepter(PV); break;
case IF :
accepter(IF); accepter(PG); expr();
accepter(PD); instr(); break;
case WHILE :
accepter(WHILE); accepter(PG); bool();
accepter(PD); instr(); break;
case : . . . break; // autres instructions
case default :
print("erreur syntaxe");
ID, AFFECT, PV, IF, PG, PD, WHILE
}
sont des terminaux, des unités lexicales
}
Analyse syntaxique prédictive
S'il existe plus d'une production pour un nœud A, par exemple
A  et A  . On choisi d'appliquer A  si :
1. a  PREMIER() où a est le symbole de pré-vision et
2. PREMIER()  PREMIER() = 
Associativité
Récursivité à gauche. Notez la production suivante
gauche
<expr> <expr> + <terme>
Une analyse syntaxique prédictive ne peut pas s'appliquer à une
telle production. Dans ce cas il faut ré-écrire la production pour
éliminer la récursivité à gauche.
L'analyse syntaxique prédictive sera abordée plus
en détail dans le chapitre Analyse Syntaxique
53
<intr>
<instr>
<instr>  while (<bool>) <instr>
Pour certaines grammaires, les étapes peuvent être appliquées sans
avoir besoin de faire des retour-arrière (de manière déterministe).
Au cours de l'analyse, le terminal d'entrée courant est appelé symbole
de pré-vision.
<bool> )
<bool> )
Analyse syntaxique prédictive
Suite pseudo-code :
public void accepter(Terminal t) {
if (preVis == t)
preVis = uniteSuivante(); // appel analyse lexical
else
print("erreur syntaxe");
}
Définition PREMIER() = ensemble des terminaux pouvant
apparaître au début d’une dérivation de .
Exemples : PREMIER(instr) = {id, if, while, …}
PREMIER(expr) = {id, chiffre, . ..}
52
Téléchargement