40
Vue générale

cour de compilation

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: cour de compilation

Vue générale

Page 2: cour de compilation

Vue généraleMotivation

Structure d‘un compilateur

Grammaires

Arbres Syntaxiques et Ambiguïté

Classification de Chomsky

Présentation Z#

Page 3: cour de compilation

Histoire (Construction des compilateurs)

Autrefois " un mystère ", aujourd'hui l‘une des branches les plus maîtriséesEn 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.

Page 4: cour de compilation

Comment est écrit le premier compilateur?

Programmation degré 0 : en binaire (suite de 0 et de 1)

Programmation degré 2 : langage de programmation (CALL, SINUS,.)

Le premier assembleur est écrit en binaire

Aujourd'hui un compilateur pour le langage U est écrit avec un langage V doté d‘un compilateur écrit dans un langage W.

Programmation degré 1 : langage d‘assemblage (LW, JUMP,.)

Le premier compilateur est écrit en langage d‘assemblage

Page 5: cour de compilation

Pourquoi apprendre la compilation?

• 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 ?

Constitue une base pour un ingénieur en informatique

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

• ...

Page 6: cour de compilation

Vue généraleMotivation

Structure d‘un compilateur

Grammaires

Arbres Syntaxiques et Ambiguïté

Classification de Chomsky

Présentation Z#

Page 7: cour de compilation

Structure d‘un compilateur

Programme source v a l = 01 * v a l + i

Analyse lexicale

Unités lexicales 1(ident)"val"

3(assign)

-

2(number)

10

4(times)

-

1(ident)"val"

5(plus)

-

1(ident)

"i"

Code de l‘unité

Valeur de l‘unité

Analyse syntaxique

Arbre syntaxique

ident = number * ident + ident

Term

Expression

Statement

Page 8: cour de compilation

Structure d‘un compilateur

Analyse sémantique

Arbre syntaxique

ident = number * ident + ident

Term

Expression

Statement

Représentationintermédiaire

Arbre syntaxique, table des symboles, ...

Optimisation

Génération de code

001011100000110110110100011111010...

Code machine

Page 9: cour de compilation

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é

eof?

Le programme objet est généré en même temps que le programme source est lu.

ny

Page 10: cour de compilation

Compilateurs à plusieurs passes

Les phases sont des programmes séparés qui s‘exécutent séquentiellement

Chaque phase lit à partir d‘un fichier et écrit sur un nouveau fichier

Source

Lexique

Unités lexicales

Syntaxe

Arbre

Sémantique ...

Code

Pourquoi plusieurs passes?

• Mémoire insuffisante (Aujourd'hui, ce n‘est plus un motif)• Langage complexe• Portabilité importante

Page 11: cour de compilation

En général: Compilateurs à deux passes

Passe 1

LexiqueSyntaxeSémantique

Représentationintermédiaire

Passe 2

Générationcode

Dépendant du language

Java

C

Pascal

Dépendant de la machine

Pentium

PowerPC

SPARCToute 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

Page 12: cour de compilation

Différence entre Compilateur et Interpréteur

Compilateur Traduit vers le code machine

scanner parser ... code generator loader

code source code machine

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 codesimulant la machine physique

Interpréteur exécute le code source "directement"

scanner parser

code source interprétation

• Les instructions d‘une boucle sontscannées et analysées à chaque

itération

Page 13: cour de compilation

Fonctionnement d‘un compilateur

Analyse SyntaxiqueSémantique

scanner

Table des symboles

Génération de code

Fournit les unités lexicales à partirdu code source

Maintient des informations sur les variables et types déclarés

génère le code machine

"Programme principal"Dirige toute la compilation

Utilise

Flots de données

Page 14: cour de compilation

Vue généraleMotivation

Structure d‘un compilateur

Grammaires

Arbres Syntaxiques et Ambiguïté

Classification de Chomsky

Présentation Z#

Page 15: cour de compilation

C‘est quoi une grammaire?

Exemple Statement = "if" "(" Condition ")" Statement ["else" Statement].

Quatre composantes

Symboles terminaux Sont atomiques "if", ">=", ident, number, ...

Symboles nonterminaux

Sont dérivésen unités

Statement, Expr, Type, ...

productions Règles donnant la décom-position des non terminaux

Statement = Designator "=" Expr ";".Designator = ident ["." ident]....

Symbole de départ Non terminal axiome CSharp

Page 16: cour de compilation

Notation EBNF

Extended Backus-Naur form John Backus: a développé le premier compilateur FortranPeter 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

"=", "while"

ident, Statement

A = b c d .

|

(...)

[...]

{...}

Choix

Choix de groupes

Partie optionnelle

Partie répétitive

a | b | c a or b or c

a ( b | c ) ab | ac

[ a ] b ab | b

{ a } 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)

Page 17: cour de compilation

Exemple: Grammaire pour les expressions arithmétiques

Productions

Expr = [ "+" | "-" ] Term { ( "+" | "-" ) Term }.

Term = Factor { ( "*" | "/" ) Factor }.

Factor = ident | number | "(" Expr ")".Expr

Term

Factor

Symboles Terminaux

"+", "-", "*", "/", "(", ")"( 1 instance)

ident, number(plusieurs instances)

Symboles non terminaux

Expr, Term, Factor

Symbole de départ

Expr

Page 18: cour de compilation

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 + Term - Term "*" et "/" ont des priorités supérieures à "+" et "-"

= Expr "-" ne porte pas sur a, mais sur a*3

Expr = Term { ( "+" | "-" ) Term }.

Term = Factor { ( "*" | "/" ) Factor }.

Factor = [ "+" | "-" ] ( ident | number | "(" Expr ")" ).

Comment transformer la grammaire pour que "-" porte sur a?

Page 19: cour de compilation

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, "("

Page 20: cour de compilation

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é droitd‘une production?Quels sont les symboles terminaux quile suivent?

Page 21: cour de compilation

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 (, , , ...)Ex.: = ident + number

= - Term + Factor * number

Chaîne vide

Dénotée par

Page 22: cour de compilation

Dérivations et Réductions

Dérivation

=> (dérivation directe) Term + Factor * Factor

=> Term + ident * Factor

Non terminal NT Partie droite d‘une production de NT

=>* (dérivation indirecte) => 1 => 2 => ... => n =>

=>L (dérivation canonique gauche ) Le non terminal le plus à gauche dans est dérivéen premier

=>R (dérivation canonique droite) Le non terminal le plus à droite dans est dérivéen premier

RéductionC‘est l‘inverse d‘une dérivation.Si le coté droit d‘une production figure dans il est remplacé par le non terminal correspondant

Page 23: cour de compilation

Dérivation de la chaîne vide( Annulabilité )

Une chaîne peut dériver la chaîne vide. =>*

Exemple

A = B C.B = [ b ].C = c | d | .

B peut dériver la chaîne vide : B =>

C peut dériver la chaîne vide : C =>

A peut dériver la chaîne vide : A => B C => C =>

Page 24: cour de compilation

Plus de terminologieForme 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

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.

Phrase pour un non terminal U

xUy forme sentientielle et U=>+uSi U=>u : phrase simple

Handle

Phrase simple la plus à gauche

Page 25: cour de compilation

Récursion

Une production est récursive si A => * 1 A 2

Utilisée pour représenter des répétitions et des structures emboîtées

Récursion directe A => 1 A 2

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 ")". A => (A) => ((A)) => (((A))) => (((... (b)...)))

Récursion indirecte A => * 1 A 2

Exemple

Expr = Term { "+" Term }.Term = Factor { "*" Factor }.Factor = id | "(" Expr ")".

Expr => Term => Factor => "(" Expr ")"

Page 26: cour de compilation

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?

TT + TT + T + T...

Ce qui donne la règle itérative EBNF :

E = T { "+" T }.

Page 27: cour de compilation

Vue généraleMotivation

Structure d‘un compilateur

Grammaires

Arbres Syntaxiques et Ambiguité

Classification de Chomsky

Présentation Z#

Page 28: cour de compilation

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

<Expr> ::= <Sign> <Term><Expr> ::= <Expr> <Addop> <Term>

<Sign> ::= +<Sign> ::= -<Sign> ::=

<Addop> ::= +<Addop> ::= -

<Term> ::= <Factor><Term> ::= <Term> <Mulop> <Factor>

<Mulop> ::= *<Mulop> ::= /

<Factor> ::= ident<Factor> ::= number<Factor> ::= ( <Expr> )

• Alternatives sont transformées en productions séparées

• Répétition doivent être exprimée par récursion

Avantages• Sans méta symboles ( |, (), [], {})• Plus facile à construire un arbre syntaxique

Inconvénient• Lourdeur

Page 29: cour de compilation

Arbre syntaxique

Montre la structure d‘une phrase particulière Ex. pour 10 + 3 * i

Arbre syntaxique concret (Arbre de l‘analyseur)

number + * ident

Factor

Term

number

Factor

Term Mulop FactorSign

TermAddopExpr

Expr

Reflète les priorités des opérateurs :de bas en haut dans l‘arbre.

Arbre syntaxique abstrait (feuilles = opérandes, nœuds internes = opérateurs)

number ident

*

+

number

Souvent utilisé comme une représentation interne d‘un programme;Utilisé pour les optimisations.

Page 30: cour de compilation

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

id

F

T

id

F

T

*

T

id

F

T

*

T

id

F

T

id

F

T

*

T

id

F

T

*

T

Les grammaires ambiguës causent des problèmes dans l‘analyse syntaxique!

Page 31: cour de compilation

É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 = F | T "*" F.F = id.

cad. T a la priorité sur F

Encore mieux : transformation vers EBNF

T = F { "*" F }.F = id.

id

F

T

id

F

*

T

id

F

*

T

Un seul arbre syntaxique est possible

Page 32: cour de compilation

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| ... .

Condition Condition Statement Statement

Statement

Statement

if (a < b) if (b < c) x = c; else x = b;

Condition Condition Statement Statement

Statement

Statement

Il n‘existe pas de grammairenon ambiguë pour ce langage!

Solution dans les langages :le dernier Else se rapporte au dernier If

Page 33: cour de compilation

Vue généraleMotivation

Structure d‘un compilateur

Grammaires

Arbres Syntaxiques et Ambiguïté

Classification de Chomsky

Présentation Z#

Page 34: cour de compilation

Classification des grammairesDue à Noam Chomsky (1956)

Les grammaires sont des ensembles de productions de la forme = .

class 0 Grammaires non restritives ( et 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 ( =xUy et =xuy) ,U=NTEx: a A = a b c.Reconnues par les automates linéaires finis

class 2 Grammaires à contexte-libre ( = NT, # )Ex: A = a b c.Reconnues par les automates à piles

class 3 Grammaires régulières ( = NT, = 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.

Page 35: cour de compilation

Vue généraleMotivation

Structure d‘un compilateur

Grammaires

Arbres Syntaxiques et Ambiguïté

Classification de Chomsky

Présentation Z#

Page 36: cour de compilation

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

Page 37: cour de compilation

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.  

Page 38: cour de compilation

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);

} } }

Page 39: cour de compilation

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 }.

Page 40: cour de compilation

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 = "*" | "/" | "%".