Vous êtes sur la page 1sur 44

Traduction dirige par la syntaxe

Grammaires attribues Attributs synthtiss Attributs hrits Arbres syntaxiques Grammaires S-attribues Grammaires L-attribues - schmas de traduction - traduction descendante - traduction ascendante

Objectifs
Faire la traduction pendant l'analyse syntaxique Ajouter des actions portant sur les attributs des symboles Obtenir un module qui fait la fois l'analyse syntaxique et la traduction en une seule passe

Analyse descendante Utiliser des fonctions qui ont des paramtres et renvoient des valeurs : les attributs
Analyse ascendante La mthode est applicable avec Bison

Exemple
Grammaire attribue pour une calculette rgle action L --> E '\n' print(E.val) E --> E + T E.val := E1.val + T.val E --> T E.val := T.val T --> T * F T.val := T1.val * F.val T --> F T.val := F.val F --> ( E ) F.val := E.val F --> chiffre F.val := chiffre.val

Numrotation des non-terminaux


E --> E + T E.val := E1.val + T.val

Si la rgle comporte plusieurs fois un mme non-terminal Une occurrence avec un indice dans l'action correspond l'occurrence correspondante dans le membre droit de la rgle

Une occurrence sans indice correspond au membre gauche de la rgle

Arbres dcors
En ajoutant un arbre de drivation les attributs et leurs valeurs, on obtient un arbre dcor
L
E .val=19 E .val=15 T .val=15 T .val=3 * F .val=3 nombre .val=3 F.val=5 nombre .val=5 F.val=4 nombre .val=4 \n

T .val=4

Grammaires attribues
Une grammaire attribue est dfinie par - une grammaire - des attributs associs chaque symbole terminal ou nonterminal - une action associe chaque rgle X --> expr b := f(c1, c2, ... ck) Une action peut avoir des entres c1, c2, ... ck et des sorties b qui sont des attributs de X et des symboles formant expr

Attributs synthtiss ou hrits


X --> expr b := f(c1, c2, ... ck) L'attribut b est un attribut synthtis si dans toutes les actions o il est calcul, c'est un attribut de X C'est un attribut hrit si dans toutes les actions o il est calcul, c'est un attribut d'un des symboles formant expr

Exemple d'attributs synthtiss


Pour calculer les attributs synthtiss, on monte dans l'arbre
L
E .val=19 E .val=15 T .val=15 T .val=3 * F .val=3 nombre .val=3 F.val=5 nombre .val=5 F.val=4 nombre .val=4 \n

T .val=4

Exemple d'attributs hrits


Dclaration de variables en C D --> T L T --> int T --> float L --> L , id L --> id L.type := T.type T.type := integer T.type := real L1.type := L.type ; ajouterType(id.entree, L.type) ajouterType(id.entree, L.type)

L'attribut L.type est hrit

Construction d'un arbre


Une grammaire attribue qui construit un arbre reprsentant une expression arithmtique

+ . - . .

id id .

num

entre pour c

entre pour a

Construction d'un arbre


Fonctions utilises
makeNode(op, left, right)

: cre un noeud dont l'tiquette est l'oprateur op et avec deux champs pour les pointeurs left et right

makeLeaf(id, entree)

: cre un noeud dont l'tiquette est id et avec un champ pour un pointeur vers une entre de la table des symboles : cre un noeud dont l'tiquette est num et avec un champ pour la valeur de la constante

makeLeaf(num, val)

Construction d'un arbre


E --> E + T E --> E - T E --> T T --> ( E ) T --> id T --> num E.ptr := makeNode('+', E1.ptr, T.ptr) E.ptr := makeNode('-', E1.ptr, T.ptr) E.ptr := T.ptr T.ptr := E.ptr T.ptr := makeLeaf(id, id.entree) T.ptr := makeLeaf(num, num.val)

Les deux attributs E.ptr et T.ptr contiennent des pointeurs sur des arbres construits

Grammaires S-attribues
Grammaires dont tous les attributs sont synthtiss Le calcul des attributs peut se faire dans la pile de l'analyseur ascendant

tat valeur

... ...

X X.x

Y Y.y

Z Z.z

Exemple
Donne Pile S --> E $ E --> E + T E --> T T --> T * F T --> F F --> ( E ) F --> N 3*5+4$ *5+4$ N *5+4$ F *5+4$ T 5+4$ T * +4$ T * N Valeurs 3 3 3 33-5 Rgle

F --> N T --> F

+4$ T * F +4$ T

3-5 15

F --> N T --> T * F

Grammaires S-attribues
Calculer les attributs pendant les rductions A --> X Y Z A.a := f(X.x, Y.y, Z.z) Rduction : - calculer A.a en fonction des valeurs contenues dans la pile - dpiler X Y Z - empiler A - sauvegarder A.a dans la pile

tat valeur tat valeur

... ... ... ...

X X.x A A.a

Y Y.y

Z Z.z

Exemple
L --> E '\n' E --> E + T E --> T T --> T * F T --> F F --> ( E ) F --> chiffre print(val[top-1]) val[ntop] := val[top - 2] + val[top] /* inutile de recopier */ val[ntop] := val[top - 2] * val[top] val[ntop] := val[top - 1]

val[] : pile des valeurs d'attributs top : taille actuelle de la pile ntop : taille de la pile aprs la rduction en cours (se dduit de top et de la longueur de la rgle)

Grammaires L-attribues
Grammaire dans laquelle le calcul des attributs peut tre fait lors d'un parcours en profondeur de l'arbre de drivation

parcours(noeud n) { pour chaque fils m de n { calculer les attributs hrits de m ; parcours(m) ; } calculer les attributs synthtiss de n ; }

Dfinition formelle
Une grammaire est L-attribue si - tout attribut est synthtis ou hrit ; - dans une rgle A --> X1 X2 ...Xn, si un attribut Xi.b est calcul dans l'action associe, il ne dpend que des attributs des variables X1 X2 ...Xi-1 ou des attributs hrits de A

Exemple : le langage EQN


EQN est un langage de composition de texte permettant d'crire des formules mathmatiques Chaque formule est contenue dans une bote virtuelle Une bote peut tre en indice d'une autre Dans ce cas le corps de caractres (taille) de la bote indice est plus petit De mme pour une bote en exposant La hauteur d'une bote (B.ht) dpend - de la hauteur normale des caractres (texte.hn) - du corps de caractres (B.cc) - des indices ou exposants l'intrieur

Exemple : le langage EQN


S --> B B --> B B B.cc := 10 ; S.ht := B.ht B1.cc := B.cc ; B2.cc := B.cc ; B.ht := max(B1.ht, B2.ht) B1.cc := B.cc ; B2.cc := diminue(B.cc) ; B.ht := position(B1.ht, B2.ht) B.ht := texte.hn * B.cc

B --> B sub B

B --> texte

diminue() applique un facteur d'chelle position() modifie la hauteur cause de l'indice

Schmas de traduction
Comme une grammaire attribue mais prcise quand on fait les actions pendant un parcours de l'arbre en profondeur Elles sont insres dans les membres droits des rgles Si une action calcule un attribut d'un non-terminal du membre droit, elle doit tre place avant lui Si une action utilise un attribut d'un non-terminal du membre droit, elle doit tre place aprs lui Exemple : traduction postfixe des expressions additives E --> T R R --> addop T { print(addop.lexeme) } R | T --> num { print(num.val) }

Un schma de traduction mal form


S --> A A { A1.val := 1 ; A2.val := 2 } A --> a { print(A.val) } La deuxime condition n'est pas satisfaite L'action qui calcule A1.val et A2.val est place aprs

Le langage EQN
S --> { B.cc := 10 } B { S.ht := B.ht } B --> { B1.cc := B.cc } B { B2.cc := B.cc } B { B.ht := max(B1.ht, B2.ht) } B --> { B1.cc := B.cc } B sub { B2.cc := diminue(B.cc) } B { B.ht := position(B1.ht, B2.ht) } B --> texte { B.ht := texte.hn * B.cc } Une grammaire L-attribue peut toujours tre mise sous la forme d'un schma de traduction

Schmas de traduction en Bison


Dans une spcification Bison, on peut insrer les actions dans le membre droit des rgles Le traducteur engendr par Bison fera les actions au moment correspondant
E R : T R ; : addop T { printf($1) ; } R | ; : num { print($1) ; } ;

Traduction descendante
Pour l'analyse descendante, on limine la rcursivit gauche dans la grammaire Il faut aussi adapter les attributs Exemple E --> E + T E --> E - T E --> T T --> ( E ) T --> chiffre

E.val := E1.val + T.val E.val := E1.val - T.val E.val := T.val T.val := E.val E.val := chiffre.val

Elimination de la rcursivit gauche


E --> T { E'.he := T.val } E' {E.val := E'.sy } E' --> + T { E'1.he := E'.he + T.val } E' {E'.sy := E'1.sy } E' --> - T { E'1.he := E'.he - T.val } E' {E'.sy := E'1.sy } E' --> {E'.sy := E'.he } T --> ( E ) {T.val := E.val } T --> N {T.val := N.val } L'attribut E'.he sert transmettre la valeur de l'expression situe gauche

Elimination de la rcursivit gauche


E
E'.he=9

E' .he=4
T .val=9 T .val=5 + T .val=2 E' .he=6

nombre .val=9

nombre .val=5

nombre .val=2

Traduction descendante
Donne : un schma de traduction non rcursif gauche Rsultat : le code d'un traducteur descendant Pour chaque non-terminal A, construire une fonction dont les paramtres sont les attributs hrits de A et qui renvoie comme valeur les attributs synthtiss de A (on suppose qu'il n'y en a qu'un) Le code pour A dcide quelle rgle appliquer en fonction du symbole courant dans la donne Pour chaque attribut d'une variable du membre droit, dclarer une variable locale

Traduction descendante
Le code associ une rgle parcourt le membre droit et fait les actions suivantes : - pour un symbole terminal X avec un attribut x, sauvegarder la valeur de x dans une variable locale et lire X - pour un non-terminal B, faire c := B(b1, b2, ... bk) o c est l'attribut synthtis de B et b1, b2, ... bk sont les attributs hrits de B - pour une action, faire l'action

Traduction ascendante
Le problme est de calculer les attributs hrits On effectue les actions seulement au moment o on rduit Dans une rgle A --> X1 X2 ...Xn, au moment o on passe Xi, on a dans la pile X1 X2 ...Xi-1 mais pas A Si un attribut hrit de Xi dpend d'un attribut de A, quand et comment le calculer ? on ira le chercher dans la pile et non dans la rgle La mthode prsente est applicable certaines grammaires L-attribues dont la grammaire sous-jacente est LR(1)

Elimination des actions insres


On remplace le schma de traduction par une grammaire L-attribue en remplaant certaines actions par de nouveaux non-terminaux appels marqueurs Exemple E --> T R R --> + T { print('+') } R | - T { print('-') } R | T --> num { print(num.val) } devient : E --> T R R --> + T M R | - T N R | T --> num { print(num.val) } M --> {print('+') } N --> {print('-') }

Schmas de traduction en Bison


Pour traiter un schma de traduction Bison fait de mme R : addop T { printf($1) ; } R | ; devient : R : addop T M R | ; M : { printf($1) ; } ;

Schmas de traduction en Bison


La numrotation des symboles dans le membre droit des rgles tient compte des actions Chaque action compte comme un symbole R : addop T { printf($1) ; } R | ;

L'attribut de R est dans $4

Trouver un attribut dans la pile


A --> X1 X2 ...Xn Quand on analyse Xi, les attributs hrits de A sont parfois calculables partir d'autres attributs qui sont dj dans la pile Exemple D --> T L L.type := T.type T --> int T.type := integer T --> float T.type := real L --> L , id L1.type := L.type ; ajouterType(id.entree, L.type) L --> id ajouterType(id.entree, L.type)

Trouver un attribut dans la pile


donne pile rgle int p , q , r $

L.type vient de T.type


Le T en question est toujours juste audessous du L dans la pile

p , q , r $ int p,q,r$ T , q , r $ T id T --> int

,q,r$ TL
, r $ T L , id ,r$ TL

L --> id
L --> L , id

r$ TL,
$ T L , id $ TL $ D L --> L , id D --> T L

Trouver un attribut dans la pile


On peut donc accder une case de la pile au-dessous de la rgle en cours D --> T L /* inutile de recopier ici */ T --> int val[ntop] := integer T --> float val[ntop] := real L --> L , id ajouterType(val[top], val[top-3]) /* dans la pile : T L , id */ L --> id ajouterType(val[top], val[top-1]) /* dans la pile : T id */ L'action de la premire rgle est effectue la fin : trop tard pour recopier l'attribut

Trouver un attribut dans la pile


Cette mthode est applicable avec Bison
D T T L : ; : ; : ; : T L int float { $$ := INTEGER ; } { $$ := REAL ; }

L , id { ajouterType($3, $0) ; /* dans la pile : T L , id */ } | id { ajouterType($1, $0) ; /* dans la pile : T id */ } ;

Pour descendre dans la pile : $0, $-1, $-2...

Trouver un attribut dans la pile


S --> a A C C.he := A.sy S --> b A B C C.he := A.sy C --> c C.sy := f(C.he) Quand on rduit c vers C, A.sy peut se trouver en val[top-1]ou en val[top-2] Il faut modifier la grammaire S --> a A C C.he := A.sy S --> b A B M C M.he := A.sy ; C.he := M.sy M --> M.sy := M.he C --> c C.sy := f(C.he) Quand on rduit c vers C, A.sy est toujours en val[top-1]

Trouver un attribut dans la pile


S --> a A C C.he := g(A.sy) S --> b A B C C.he := A.sy C --> c C.sy := f(C.he) On modifie la grammaire S --> a A N C N.he := A.sy ; C.he := N.sy N --> N.sy := g(N.he) S --> b A B M C M.he := A.sy ; C.he := M.sy M --> M.sy := M.he C --> c C.sy := f(C.he) Quand on rduit c vers C, C.he est toujours en val[top-1]

Exemple : le langage EQN


S --> L B L --> B --> B M B B.cc := L.cc ; S.ht := B.ht L.cc := 10 B1.cc := B.cc ; M.he := B.cc ; B2.cc := M.sy ; B.ht := max(B1.ht, B2.ht) corps de caractres : 10 points, 12 points... hauteur : distance entre la ligne de pied et le haut de la bote hauteur normale d'un caractre : hauteur du caractre lorsqu'il est compos en corps 1

.cc .ht

.hn

Exemple : le langage EQN


S --> L B L --> B --> B M B B.cc := L.cc ; S.ht := B.ht L.cc := 10 B1.cc := B.cc ; M.he := B.cc ; B2.cc := M.sy ; B.ht := max(B1.ht, B2.ht) M.sy := M.he B1.cc := B.cc ; N.he := B.cc ; B2.cc := N.sy ; B.ht := position(B1.ht, B2.ht) N.sy := diminue(N.he) B.ht := texte.hn * B.cc

M --> B --> B sub N B

N --> B --> texte

Exemple : le langage EQN


S --> L B L --> B --> B M B M --> B --> B sub N B N --> B --> texte val[ntop] := val[top] val[ntop] := 10 val[ntop] := max(val[top-2], val[top]) /* dans la pile : L B M B */ val[ntop] := val[top-1] /* dans la pile : L B */ val[ntop] := position(val[top-3], val[top]) val[ntop] := diminue(val[top-2]) /* dans la pile : L B sub */ val[ntop] := val[top] * val[top-1] /* dans la pile : L B */

Algorithme gnral
Donne : une grammaire L-attribue Rsultat : un traducteur ascendant On suppose que chaque non-terminal A a un attribut hrit A.he et que chaque symbole X a un attribut synthtis X.sy Remplacer chaque rgle A --> X1 X2 ...Xn par A --> M1 X1 M2 X2 ... Mn Xn Associer les Xi.he aux Mi Quand on rduit vers Mi, la position de A.he, X1.he X2.he ... dans la pile se dduit de la nouvelle grammaire

Rsum
Les schmas de traduction permettent d'incorporer la traduction l'analyse syntaxique pour obtenir un traducteur en une passe Les attributs synthtiss sont faciles calculer - analyse descendante : valeurs des fonctions associes aux non-terminaux de la grammaire - analyse ascendante : dans la pile Les attributs hrits sont calculs - en analyse descendante : comme paramtres des fonctions - en analyse ascendante : en remontant dans la pile, et s'il le faut en introduisant des non-terminaux "marqueurs"

Vous aimerez peut-être aussi