Cours PPT - zegour djamel eddine

publicité
Vue générale
Pr ZEGOUR DJAMEL EDDINE
Ecole Supérieure d’Informatique (ESI)
http://zegour.esi.dz/
email: [email protected]
Vue générale
Motivation
Structure d‘un compilateur
Grammaires
Arbres Syntaxiques et Ambiguïté
Classification de Chomsky
Présentation Z#
Histoire (Construction des compilateurs)
Autrefois " un mystère ", aujourd'hui l‘une des branches les plus maîtrisées
En informatique.
1957
Fortran
Premiers compilateurs
(Expressions, instructions, procédures)
1960
Algol
Première définition formelle d‘un langage
(grammaires sous forme de Backus-Naur, bloc, récursivité, ...)
1970
Pascal
types, machines virtuelles (P-code)
1985
C++
Orientation objets, exceptions
1995
Java
Portabilité
Le cours concerne uniquement les langages impératifs (procéduraux)
langages fonctionnels (Lisp) et langages logiques ( Prolog) exigent d‘autres techniques.
Comment est écrit le premier compilateur?
Programmation degré 0 : en binaire (suite de 0 et de 1)
Programmation degré 1 : langage d‘assemblage (LW, JUMP,.)
Programmation degré 2 : langage de programmation (CALL, SINUS,.)
Le premier assembleur est écrit en binaire
Le premier compilateur est écrit en langage d‘assemblage
Aujourd'hui un compilateur pour le langage U est écrit avec un langage V
doté d‘un compilateur écrit dans un langage W.
Pourquoi apprendre la compilation?
Constitue une base pour un ingénieur en informatique
• Comment les compilateurs fonctionnent?
• Comment les ordinateurs fonctionnent?
(instructions, registres, addressage, déroulement d‘une instruction, ...)
• Code machine généré
(efficacité)
• C‘est quoi une bonne conception de langage ?
Utile dans d‘autres domaines
• Lecture des requêtes de bases de données ()
• Lecture des données structurées du type XML, fichier image, ...)
• Interprétation des lignes de commande
• ...
Vue générale
Motivation
Structure d‘un compilateur
Grammaires
Arbres Syntaxiques et Ambiguïté
Classification de Chomsky
Présentation Z#
Structure d‘un compilateur
Programme source v a l
=
10
*
va l
+
i
Analyse lexicale
Unités lexicales
1
3
2
4
1
5
1
(ident) (assign) (number) (times) (ident) (plus) (ident)
"val"
10
"val"
"i"
Analyse syntaxique
Statement
Arbre syntaxique
Expression
Term
ident = number * ident + ident
Code de l‘unité
Valeur de l‘unité
Structure d‘un compilateur
Statement
Arbre syntaxique
Expression
Term
ident = number * ident + ident
Analyse sémantique
Représentation
intermédiaire
Arbre syntaxique, table des symboles, ...
Optimisation
Génération de code
Code machine
00101110000
01101101101
00011111010
...
Compilateurs à une passe
Fonctionnement simultané des phases
Scanne une unité
Analyse une unité
Vérifie une unité
Génère le code pour une unité
n eof?
y
Le programme objet est généré en même temps que le programme source est lu.
Compilateurs à plusieurs passes
Les phases sont des programmes séparés qui s‘exécutent séquentiellement
Lexique
Source
Sémantique
Syntaxe
Unités lexicales
Arbre
Chaque phase lit à partir d‘un fichier et écrit sur un nouveau fichier
Pourquoi plusieurs passes?
• Mémoire insuffisante (Aujourd'hui, ce n‘est plus un motif)
• Langage complexe
• Portabilité importante
...
Code
En général: Compilateurs à deux passes
Passe 1
Passe 2
Lexique
Syntaxe
Sémantique
Génération
code
Représentation
intermédiaire
Dépendant du language
Dépendant de la machine
Java
C
Pascal
Pentium
PowerPC
SPARC
Toute combinaison possible
Avantages
• Meilleure portabilité
• Combiner les techniques entre les deux passes
• Optimisations plus simples sur la représentation
intermédiaire que sur le code source
Inconvénients
• Lenteur
• Plus de mémoire
Différence entre Compilateur et Interpréteur
Compilateur
Traduit vers le code machine
scanner
parser
...
code generator
code source
loader
code machine
Interpréteur exécute le code source "directement"
scanner
• Les instructions d‘une boucle sont
scannées et analysées à chaque
itération
parser
code source
interprétation
Variante: interprétation du code intermédiaire
... compilateur ...
code source
Code intermédiaire
(Langage pivot))
VM
• Le code source est traduit dans le
code d‘une machine virtuelle (VM)
• VM interprète le code
simulant la machine physique
Fonctionnement d‘un compilateur
Analyse Syntaxique
Sémantique
"Programme principal"
Dirige toute la compilation
scanner
Génération de code
Fournit les unités lexicales à partir
du code source
Table des symboles
Maintient des informations sur
les variables et types déclarés
Utilise
Flots de données
génère le code machine
Vue générale
Motivation
Structure d‘un compilateur
Grammaires
Arbres Syntaxiques et Ambiguïté
Classification de Chomsky
Présentation Z#
C‘est quoi une grammaire?
Exemple
Statement = "if" "(" Condition ")" Statement ["else" Statement].
Quatre composantes
Symboles terminaux
Sont atomiques
"if", ">=", ident, number, ...
Symboles non
terminaux
Sont dérivés
en unités
Statement, Expr, Type, ...
productions
Règles donnant la décom- Statement = Designator "=" Expr ";".
position des non terminaux Designator = ident ["." ident].
...
Symbole de départ
Non terminal axiome
CSharp
Notation EBNF
Extended Backus-Naur form
John Backus: a développé le premier compilateur Fortran
Peter Naur: définition de Algol60
Symboles
Sens
exemples
Chaîne
Nom
=
.
Dénote une chaîne de caractères
Dénote un symbole T ou NT
Sépare les membres d‘une production
Termine une production
|
(...)
[...]
{...}
Choix
Choix de groupes
Partie optionnelle
Partie répétitive
"=", "while"
ident, Statement
A=bcd.
a|b|c
a(b|c)
[a]b
{a}b
a or b or c
ab | ac
ab | b
b | ab | aab | aaab | ...
Conventions
• Symboles terminaux : commencent par des lettres minuscules (ex. ident)
• Symboles non terminaux : commencent par des lettres majuscules (ex. Statement)
Exemple: Grammaire pour les expressions arithmétiques
Productions
Expr = [ "+" | "-" ] Term { ( "+" | "-" ) Term }.
Term = Factor { ( "*" | "/" ) Factor }.
Factor = ident | number | "(" Expr ")".
Expr
Symboles Terminaux
"+", "-", "*", "/", "(", ")"
( 1 instance)
Term
ident, number
(plusieurs instances)
Factor
Symboles non terminaux
Expr, Term, Factor
Symbole de départ
Expr
Priorité des opérateurs
Des grammaires peuvent être utilisées pour définir la priorité des opérateurs
Expr = [ "+" | "-" ] Term { ( "+" | "-" ) Term }.
Term = Factor { ( "*" | "/" ) Factor }.
Factor = ident | number | "(" Expr ")".
Entrée: - a * 3 + b / 4 - c
=
=
=
=
- ident * number + ident / number - ident
- Factor * Factor + Factor / Factor - Factor
-
Term
+
Expr
Term
- Term
"*" et "/" ont des priorités supérieures à "+" et "-"
"-" ne porte pas sur a, mais sur a*3
Comment transformer la grammaire pour que "-" porte sur a?
Expr = Term { ( "+" | "-" ) Term }.
Term = Factor { ( "*" | "/" ) Factor }.
Factor = [ "+" | "-" ] ( ident | number | "(" Expr ")" ).
Premiers d‘un non terminal
Avec quels symboles terminaux un non terminal peut commencer?
Expr = ["+" | "-"] Term {("+" | "-") Term}.
Term = Factor {("*" | "/") Factor}.
Factor = ident | number | "(" Expr ")".
First(Factor) =
ident, number, "("
First(Term) =
First(Factor)
= ident, number, "("
First(Expr) =
"+", "-", First(Term)
= "+", "-", ident, number, "("
Suivants d‘un non terminal
Quels symboles terminaux peuvent suivre un non terminal ?
Expr = [ "+" | "-" ] Term { ( "+" | "-" ) Term }.
Term = Factor { ( "*" | "/" ) Factor }.
Factor = ident | number | "(" Expr ")".
Follow(Expr) =
")", eof
Follow(Term) =
"+", "-", Follow(Expr)
= "+", "-", ")", eof
Follow(Factor) =
"*", "/", Follow(Term)
= "*", "/", "+", "-", ")", eof
Voir où Expr apparaît dans le coté droit
d‘une production?
Quels sont les symboles terminaux qui
le suivent?
Terminologie
Alphabet
L‘ensemble des symboles terminaux et non terminaux d‘une grammaire
Chaîne
Une séquence finie de symboles d‘un alphabet.
Dénotées par les lettres grecques (a, b, g, ...)
Ex.: a = ident + number
b = - Term + Factor * number
Chaîne vide
Dénotée par e
Dérivations et Réductions
Dérivation
a => b (dérivation directe)
a
Term + Factor * Factor
Non terminal NT
a =>* b (dérivation indirecte)
b
=>
Term + ident * Factor
Partie droite d‘une
production de NT
a => g1 => g2 => ... => gn => b
a =>L b (dérivation canonique gauche ) Le non terminal le plus à gauche dans a est dérivé
en premier
a =>R b (dérivation canonique droite)
Le non terminal le plus à droite dans a est dérivé
en premier
Réduction
C‘est l‘inverse d‘une dérivation.
Si le coté droit d‘une production figure dans b il est remplacé par le non terminal correspondant
Dérivation de la chaîne vide( Annulabilité )
Une chaîne a peut dériver la chaîne vide.
a =>* e
Exemple
A = B C.
B = [ b ].
C = c | d | e.
B peut dériver la chaîne vide :
B => e
C peut dériver la chaîne vide :
C => e
A peut dériver la chaîne vide :
A => B C => C => e
Plus de terminologie
Forme sententielle
Toute chaîne qui peut être dérivée à partir de l‘axiome d‘une grammaire.
Ex1: Expr // Ex2 : Term + Term + Term; Ex3:Term + Factor * ident + Term
...
Phrase du langage
Une forme sententielle uniquement avec des symboles terminaux.
Ex.: ident * number + ident
Phrase pour un non terminal U
xUy forme sentientielle et U=>+u
Si U=>u : phrase simple
Handle
Phrase simple la plus à gauche
Langage (langage formel)
C‘est l‘ensemble de toutes les phrases d‘une grammaire (en général infini).
Ex.: le langage C est l‘ensemble de tous les programmes C corrects syntaxiquement.
Récursion
Une production est récursive si
A => * w1 A w2
Utilisée pour représenter des répétitions et des structures emboîtées
Récursion directe
A => w1 A w2
Récursion gauche
A = b | A a.
A => A a => A a a => A a a a => b a a a a a ...
Récursion droite
A = b | a A.
A => a A => a a A => a a a A => ... a a a a a b
Récursion centrale A = b | "(" A ")".
Récursion indirecte
A => (A) => ((A)) => (((A))) => (((... (b)...)))
A => * w1 A w2
Exemple
Expr = Term { "+" Term }.
Term = Factor { "*" Factor }.
Factor = id | "(" Expr ")".
Expr => Term => Factor => "(" Expr ")"
Comment éliminer la récursion à gauche?
La récursion à gauche constitue un handicap pour
les analyseurs syntaxiques TopDown
A = b | A a.
Les deux alternatives commencent avec b.
L‘analyseur ne peut décider quoi choisir
La récursion à gauche peut être transformée en une itération
E = T | E "+" T.
Quelles formes sententielles peuvent être dérivées?
T
T+T
T+T+T
...
Ce qui donne la règle itérative EBNF :
E = T { "+" T }.
Vue générale
Motivation
Structure d‘un compilateur
Grammaires
Arbres Syntaxiques et Ambiguité
Classification de Chomsky
Présentation Z#
Notation BNF ordinaire
Symboles terminaux Sont écrits sans quottes (Ex. : ident, +, -)
Symboles non terminaux sont écrits entre < et > (Ex. : <Expr>, <Term>)
Membres d‘une production
sont séparés par ::=
Grammaire BNF pour les expressions arithmétiques
• Alternatives sont transformées en
productions séparées
• Répétition doivent être exprimée par récursion
<Expr>
<Expr>
::= <Sign> <Term>
::= <Expr> <Addop> <Term>
<Sign>
<Sign>
<Sign>
::= +
::= ::=
<Addop>
<Addop>
::= +
::= -
Avantages
<Term>
<Term>
::= <Factor>
::= <Term> <Mulop> <Factor>
• Sans méta symboles ( |, (), [], {})
• Plus facile à construire un arbre syntaxique
<Mulop>
<Mulop>
::= *
::= /
Inconvénient
<Factor>
<Factor>
<Factor>
::= ident
::= number
::= ( <Expr> )
• Lourdeur
Arbre syntaxique
Montre la structure d‘une phrase particulière
Ex. pour 10 + 3 * i
Arbre syntaxique concret (Arbre de l‘analyseur)
Expr
Expr
Sign
e
Addop
Term
Term
Term
Factor
Factor
number
+ number
Mulop Factor
*
Reflète les priorités des opérateurs :
de bas en haut dans l‘arbre.
ident
Arbre syntaxique abstrait (feuilles = opérandes, nœuds internes = opérateurs)
+
number
number
Souvent utilisé comme une représentation interne d‘un programme;
Utilisé pour les optimisations.
*
ident
Ambiguïté
Une grammaire est ambiguë, si plus d‘un arbre syntaxique peuvent être construits
pour une phrase donnée.
Exemple
T = F | T "*" T.
F = id.
phrase: id * id * id
2 arbres syntaxiques existent pour cette phrase
T
T
T
T
T
T
T
T
T
T
F
F
F
F
F
F
id * id * id
id * id * id
Les grammaires ambiguës causent des problèmes dans l‘analyse syntaxique!
Éviter l‘ambiguïté
Exemple
T = F | T "*" T.
F = id.
Remarque : seule la grammaire est ambiguë, pas le langage.
La grammaire peut être transformée :
T
T = F | T "*" F.
F = id.
cad. T a la priorité sur F
T
Un seul arbre syntaxique est possible
T
F
F
F
id * id * id
Encore mieux : transformation vers EBNF
T = F { "*" F }.
F = id.
Ambiguïté inhérente
Il existe des langages avec des ambiguïtés inévitables.
Exemple: Problème des Else
Statement =
|
|
|
Assignment
"if" Condition Statement
"if" Condition Statement "else" Statement
... .
Statement
Il n‘existe pas de grammaire
non ambiguë pour ce langage!
Statement
Condition
if
(a < b)
Condition
if
Condition
Statement
(b < c)
x = c;
Condition
Statement
Statement
Statement
Statement
else
x = b;
Statement
Solution dans les langages :
le dernier Else se rapporte
au dernier If
Vue générale
Motivation
Structure d‘un compilateur
Grammaires
Arbres Syntaxiques et Ambiguïté
Classification de Chomsky
Présentation Z#
Classification des grammaires
Due à Noam Chomsky (1956)
Les grammaires sont des ensembles de productions de la forme a = b.
class 0
Grammaires non restritives (a et b arbitraires)
Ex.: A = a A b | B c B.
aBc = d.
dB = bb.
A => aAb => aBcBb => dBb => bbb
Reconnues par les machines de Turing
class 1
Grammaires à contexte sensitif (a =xUy et b=xuy) ,U=NT
Ex: a A = a b c.
Reconnues par les automates linéaires finis
class 2
Grammaires à contexte-libre (a = NT, b # e)
Ex: A = a b c.
Reconnues par les automates à piles
class 3
Grammaires régulières (a = NT, b = T | T NT)
Ex: A = b | b B.
Reconnues par les automates finis
Seules ces deux classes sont
exploitées dans la construction
des compilateurs.
Vue générale
Motivation
Structure d‘un compilateur
Grammaires
Arbres Syntaxiques et Ambiguïté
Classification de Chomsky
Présentation Z#
Un prototype de langage objet simple : z #
Un programme est composé d‘une seule classe avec des variables globales et méthodes.
Il n’y a pas de classes externes mais seulement des classes internes.
Les classes internes sont utilisées comme des types de données.
La méthode principale est toujours appelée Main().
Quand le programme est appelé, cette méthode est exécutée en premier
Un prototype de langage objet simple : z #
Éléments :
- constantes de type int (Ex: 123) et char (Ex. 'a') .Pas de constantes chaîne de
caractères.
- variables: toutes les variables structurées contiennent des références (pointeurs);
- les variables dans la classe principale sont statiques (globales).
- Types de base : int, char (Unicode, 2 octets)
- Types structurés: tableau à une dimension et classes internes avec des champs mais
sans méthodes.
- les méthodes sont définies dans la classe principale.
- procédures prédéfinies : ord, chr, len.
Exemple de programme z #
class P
const int size = 10;
class Table { int pos[]; int neg[]; }
Table val;
{
void Main ()
int x, i;
{
//---------- Initialize val ---------val = new Table;val.pos = new int[size]; val.neg = new int[size];
i = 0;
while (i < size) { val.pos[i] = 0; val.neg[i] = 0; i++; }
//---------- Read values ---------read(x);
while (-size < x && x < size) {
if (0 <= x) val.pos[x]++; else val.neg[-x]++;
read(x);
}
}
}
Syntaxe complète de z #
Program = "class" ident { ConstDecl | VarDecl | ClassDecl } "{" { MethodDecl } "}".
ConstDecl = "const" Type ident "=" ( number | charConst ) ";".
VarDecl
= Type ident { "," ident } ";".
ClassDecl = "class" ident "{" { VarDecl } "}".
MethodDecl
= ( Type | "void" ) ident "(" [ FormPars ] ")" { VarDecl } Block.
FormPars = Type ident { "," Type ident }.
Type
= ident [ "[" "]" ].
Statement = Designator ( "=" Expr | "(" [ ActPars ] ")" | "++" | "--" ) ";"
| "if" "(" Condition ")" Statement [ "else" Statement ]
| "while" "(" Condition ")" Statement
| "break" ";"
| "return" [ Expr ] ";"
| "read" "(" Designator ")" ";"
| "write" "(" Expr [ "," number ] ")" ";"
| Block
| ";".
Block
= "{" { Statement } "}".
ActPars
= Expr { "," Expr }.
Syntaxe complète de z# (suite)
Condition = CondTerm { "||" CondTerm }.
CondTerm = CondFact { "&&" CondFact }.
CondFact = Expr Relop Expr.
Expr
= [ "-" ] Term { Addop Term }.
Term
= Factor { Mulop Factor }.
Factor
= Designator [ "(" [ ActPars ] ")" ]
| number
| charConst
| "new" ident [ "[" Expr "]" ]
| "(" Expr ")".
Designator = ident { "." ident | "[" Expr "]" }.
Relop
= "==" | "!=" | ">" | ">=" | "<" | "<=".
Addop
= "+" | "-".
Mulop
= "*" | "/" | "%".
Téléchargement