Sie sind auf Seite 1von 8

Chapitre 3

Grammaires algbriques, analyse e syntaxique


Tous les langages de programmation sont dots dune dnition de la structure syntaxique de e e leur programmes, et cest ` cette dnition que lon a recours, explicitement ou non, lorsquon a e crit un programme, ou lorsquon cherche ` comprendre pourquoi le compilateur refuse tel ou tel e a morceau de programme avec un message du style erreur de syntaxe ou syntax error . La dnition de la structure syntaxique dun langage (informatique ou non) est appele sa e e grammaire. La grammaire dun langage naturel est la plupart du temps tr`s complexe, mais, par e bonheur, son non-respect nest gnralement pas fatal ` la comprhension. A contrario, la grame e a e maire dun langage informatique est plutt simple, mais, par contre, son non-respect est la plupart o du temps jug fatal par lanalyseur syntaxique qui tente de reconna les phrases du langage en e tre question. La simplicit syntaxique des langages informatiques est telle que leur grammaire sert non seulee ment de rfrence utilisable par un humain, mais aussi de spcication quon peut donner en entre ee e e a ` un gnrateur danalyseurs syntaxiques pour quil produise automatiquement un analyseur du e e langage. Il ne faut pas toutefois trop se er ` cette simplicit qui nest que supercielle et nest a e bien sr pas susante pour comprendre un programme. On a beau conna la grammaire dun u tre langage, la lecture de tous ses programmes nen est pas facile pour autant. Des lments comme ee lindentation, les choix des identicateurs (noms de variables, de fonctions), voire la structuration mme des programmes peuvent en compliquer signicativement la lecture, et donc la rutilisation e e et/ou la maintenance. En dautres termes, tout comme en littrature, la lisibilit nest pas quune e e aaire de syntaxe : cest aussi une aaire de style et de discipline.

Lanalyse syntaxique a pour but dorganiser les lex`mes des programmes en une reprsentation e e comprhensible, de sorte ` pouvoir la traiter systmatiquement par le reste de la cha de compilae a e ne tion. Elle a aussi pour rle de refuser les programmes (syntaxiquement) mal construits, auxquels le o reste de la cha ne saurait donner de sens. La gure 3.1 rappelle la place de lanalyse syntaxique ne dans la cha de compilation. ne 31

3.1. Grammaires

programme source (flux de caractres)

analyseur lexical

Flux de lexmes

analyseur syntaxique

Arbre de syntaxe dite superficielle

analyseur smantique

Arbre de syntaxe dite profonde

gnrateur

Code objet

Fig. 3.1 La place de lanalyse syntaxique dans la cha de compilation ne

3.1

Grammaires

Une grammaire pour un langage est la donne des lments constituant le langage (les mots e ee ou lex`mes), et les direntes r`gles dassemblage de ces mots. Ces r`gles dassemblage dnissent e e e e e la plupart du temps des catgories syntaxiques (comme expression ou instruction). Dans la suite, e on appellera terminaux les lex`mes du langage, et non terminaux les catgories syntaxiques. Nous e e justierons plus tard cette appellation. Les r`gles sont notes o` et sont des squences de terminaux et de non-terminaux. e e u e Dans les cas des grammaires qui nous intressent (les grammaires dites algbriques), elles ont la e e forme particuli`re plus simple A o` A est un non terminal. e u La dnition de la notion gnrale de grammaire est donne ci-dessous. Dans cette dnition, e e e e e lensemble des squences ventuellement vides tant donns des ensembles A et B, on note A e e e e dlments de A, et AB lensemble des concatnations dlments de A et dlments de B. ee e ee ee Dnition (Grammaire) Une grammaire G est un quadruplet (N, T, P, S) o` : e u N est un ensemble ni de symboles dits non terminaux T est un ensemble de symboles dits terminaux P est lensemble des productions : cest un sous-ensemble de (N T ) N (N T ) (N T ) ; on note un lment (, ) de P ee S est un symbole particulier de N et est appel le symbole de dpart. e e 32 Michel Mauny INE11@Ensta

3.1. Grammaires

On remarquera que le membre gauche dune production doit comporter au moins une occurrence de non terminal. Intuitivement, cest la catgorie syntaxique associe ` ce non terminal que cette e e a production contribue ` dnir. a e Notation : on regroupe souvent dans une mme r`gle 1 |2 | . . . |n lensemble des r`gles e e e i ayant le mme membre gauche . e Le langage L(G) engendr par une grammaire G est lensemble des suites de mots produits e par toutes les rcritures possibles issues du symbole de dpart S (on suppose avoir au moins une ee e production S ). Cette forme de grammaire est beaucoup trop gnrale pour notre besoin. De fait, le linguiste e e Chomsky a class dans les annes 1950 les langages par les grammaires qui les engendraient. e e Dnition (Hirarchie de Chomsky) Une grammaire est dite : e e de type 3 ou rationnelle si chaque production est de la forme A wB ou A w o` A et B u sont des non terminaux et w est un terminal ; de type 2 ou algbrique ou non contextuelle si chaque production est de la forme A o` e u A est un non terminal et est une squence de terminaux ou non terminaux ; e de type 1 ou contextuelle si chaque production est de la forme A o` , et sont u des squences de terminaux ou non terminaux et = ; e de type 0 ou gnrale si chaque production est de la forme , sans autre contrainte. e e On reconna dans cette dnition les grammaires rationnelles (type 3) qui engendrent les lant e gages rationnels que nous avons rencontrs au chapitre prcdent. e e e Les grammaires des langages de programmation sont le plus souvent des grammaires de type 2, dont les catgories syntaxiques sont constitues indpendamment du contexte o` elles apparaissent. e e e u Si on consid`re une grammaire algbrique G = (N, T, P, S), ses productions sont ncessairement e e e de la forme A . Prcisons la dnition du langage engendr par G que nous avons donn cie e e e dessus. Le langage engendr par G est lensemble des suites nies w de terminaux que lon peut e driver de S par la mthode suivante, o` est ce qui a t driv jusqualors (initialement, = S) : e e u ee e e 1. si est une suite w compose uniquement de terminaux, alors w L(G) ; e 2. sinon = A o` A est un non terminal : considrons une production A et remplaons u e c par , et recommencer en 1. Une tape de cette drivation qui change en est note . La fermeture transitive de cette e e e opration (vue comme une relation entre et ) est note . e e Exemple La grammaire des expressions arithmtiques peut scrire : e e E E E E E E Michel Mauny E + E E E / ( E INT E E E E )

INE11@Ensta

33

3.1. Grammaires

o` les terminaux sont les constantes enti`res littrales (symbolises par le lex`me INT), les pau e e e e renth`ses et les quatre oprateurs habituels. Le seul non terminal est E et cest aussi le symbole de e e dpart. e Une expression arithmtique comme 1 + 2 3, reprsente par comme INT1 + INT2 INT3 , peut e e e tre drive de plusieurs mani`res selon quon utilise dabord la production concernant laddition e e e e ou bien celle concernant la multiplication : E E + E INT1 + E INT1 + E E INT1 + INT2 E INT1 + INT2 INT3 E E E E + E E INT1 + E E INT1 + INT2 E INT1 + INT2 INT3 E E + E E + E E E + E INT3 E + INT2 INT3 INT1 + INT2 INT3 Ces trois faons de reconna cette expression arithmtique donnent deux rsultats dirents selon c tre e e e les priorits relatives que lon attribue ` laddition et la multiplication : la premi`re drivation a e a e e considr quune expression tait une somme de produits, et que la cha dentre devait tre lue ee e ne e e comme 1 + (2 3), alors que la seconde drivation la lue comme (1 + 2) 3. Graphiquement, la e premi`re drivation peut tre reprsente par larbre suivant : e e e e e

dont les nuds sont des instances de productions de la grammaire. Un tel arbre est appel parse tree e en anglais. Cet arbre am`ne naturellement ` la production de larbre de syntaxe abstraite suivant : e a

Les deux premi`res drivations sont radicalement direntes puisquelles donnent des rsultats e e e e dirents. Toutefois, elles avaient en commun le fait de toujours driver ` chaque tape le non e e a e terminal le plus ` gauche : on les appelle des drivations gauches. La derni`re, quant ` elle, utilise a e e a les mmes priorits doprateurs que la premi`re, mais a choisi de driver ` chaque tape le non e e e e e a e terminal le plus ` droite. En fait, lordre dans lequel on op`re les drivations (` droite ou ` gauche) a e e a a na pas beaucoup dimportance : cela ne change que lordre dans lequel on construit le parse tree. Et quelque soit cet ordre, on obtient lun ou lautre des arbres correspondants ` 1 + (2 3) et ` a a (1 + 2) 3 pour la reconnaissance de 1 + 2 + 3 avec la grammaire ci-dessus. On dit, pour cette raison, que cette grammaire est ambigu. e 34 Michel Mauny INE11@Ensta

3.2. Analyse descendante

Desambiguation de la grammaire des expressions arithmtiques Nous souhaitons donner e une grammaire non ambigu au langage dexpressions arithmtiques sans changer le langage. Il nous e e faut transformer notre grammaire en une autre, qui int`gre dune part les priorits des oprateurs e e e multiplicatifs sur les oprateurs additifs, mais aussi lassociation ` gauche des oprateurs, de sorte e a e que 1 2 3 soit correctement reconnu comme (1 2) 3. Les priorits relatives des oprateurs peuvent se reprsenter en hirarchisant la grammaire, et en e e e e lexprimant comme ceci : une expression arithmtique est une somme (ou dirence) de produits, e e dont les facteurs sont des entiers ou des expressions entre parenth`ses. Lassociation ` gauche des e a oprateurs se reprsente par une rcursion gauche des non terminaux correspondants : e e e S S S P P P F F S + S P P P / F ( S INT P P F F )

Avec cette nouvelle grammaire, le parse tree correspondant ` 1 + 2 3 est unique et a la forme : a

3.2

Analyse descendante

Il est tentant de chercher ` interprter un non terminal comme une fonction recevant en entre a e e un ux de lex`mes et construisant la reprsentation de lexpression arithmtique en rsultat. On e e e e voit aisment que cela revient ` chercher ` construire le parse tree en commenant par la racine. La e a a c consommation eective des lex`mes du ux dentre a lieu lorsquon excute une fonction associe e e e e a ` un non terminal. Ainsi, linterprtation du non terminal F consomme (si cest possible) une pae renth`se ouvrante, appelle ensuite la fonction correspondant ` S, puis ensuite cherche ` consommer e a a une parenth`se fermante. e On voit rapidement que cette interprtation ne peut fonctionner correctement en prsence de e e non terminaux rcursifs ` gauche : linterprtation de S commence par sappeler elle-mme sans e a e e rien consommer, conduisant irrmdiablement ` une boucle innie. e e a Michel Mauny INE11@Ensta 35

3.3. Analyse ascendante

Une solution consiste ` transformer de nouveau la grammaire pour en produire une version qui a ne soit pas rcursive ` gauche, et qui ne va donc pas considrer naturellement les oprations comme e a e e associant ` gauche. a S P + S S P S S P P F P P F / P P F F ( S ) F INT La lecture de ces non terminaux comme des fonctions danalyse, sappelant les unes les autres et consommant des lex`mes dans le ux dentre est devenue facile. Par contre, on a repouss la dife e e cult vers la production darbres de syntaxe, qui devient un peu moins naturelle. Une faon de e c 1 qui reoit un analyseur doprateurs rsoudre le probl`me consiste a utiliser la fonction suivante e e c e (additifs ou multiplicatifs dans notre langage dexpressions arithmtiques) et un analyseur de termes e (P ou F dans notre exemple) et qui met en uvre le schma ncessaire ` la reconnaissance dexe e a pressions et ` la production darbres de syntaxe corrects : a let left_assoc parse_op parse_term flux = let rec parse_rest t1 = match try Some(parse_op flux) with Parse_error > None with | Some f > let t2 = parse_term flux in parse_rest (f t1 t2) | None > t1 in let t = parse_term flux in parse_rest t La programmation directe danalyseurs descendants nest utilisable que pour de petits langages. On utilise plutt des gnrateurs danalyseurs descendants pour des grammaires appartenant ` une o e e a classe nomme LL (Left-to-right scan, Leftmost derivation) et qui produisent un automate (` pile) e a reprsent par des tables. Toutefois, les gnrateurs LL sont rares, car leur utilisation ncessite de e e e e e profondes modications des grammaires de sorte ` liminer la rcursion gauche. ae e

3.3

Analyse ascendante

Les techniques ascendantes, et plus prcisment les techniques LR (Left-to-right scan, Rightmost e e derivation) sont quant ` elles utilises avec beaucoup de succ`s pour la gnration automatique a e e e e danalyseurs.
1`

A dvelopper. e

36

Michel Mauny

INE11@Ensta

3.4. Ocamlyacc

Lanalyse ascendante va lire des lex`mes en les empilant (shift). Lorsquune r`gle peut tre e e e rduite, les lments qui constituent sa partie droite sont dpils, et remplacs par le non terminal e ee e e e en partie gauche de la r`gle (reduce). e Ces gnrateurs analysent la grammaire qui leur est prsente, et peuvent se plaindre de conits e e e e shift/reduce : cela signie quil existera des cas dentre o` le moteur danalyse aura le choix entre e u deux actions possibles : empiler ou rduire. Les gnrateurs du style Yacc (OCamlyacc, par exemple) e e e choisiront toujours dempiler (shift). Je ne dcris pas ici plus avant les techniques de gnration ou danalyse LR pour cette premi`re e e e e version du polycopi. Pour en savoir plus sur le sujet, se rfrer aux ouvrages classiques sur la e ee compilation.

3.4

Ocamlyacc

OCamlyacc est un gnrateur danalyseurs syntaxiques auquel on donne essentiellement une e e grammaire dans un chier de suxe .mly, et qui produit un analyseur dans un chier de mme e nom avec pour suxe .ml. %{ header ( avec commentaires OCaml ) %} declarations / commentaires ` la C / a %% rules / commentaires ` la C / a %% trailer ( avec commentaires OCaml ) Les prlude header et postlude trailer sont du code OCaml qui sera recopi tel quel dans le e e chier rsultat. e La partie dclaration sert dune part ` dclarer les lex`mes, qui vont appartenir ` un type appel e a e e a e token, qui sera dni automatiquement dans le chier .mli de lanalyseur syntaxique. Dautre part, e cette partie sert aussi ` donner les prcdences et r`gles dassociativit des dirents lex`mes. a e e e e e e / File parser.mly / %token <int> INT %token PLUS MINUS TIMES DIV %token LPAREN RPAREN %token EOL %left PLUS MINUS / lowest precedence / %left TIMES DIV / medium precedence / %nonassoc UMINUS / highest precedence / %start main / the entry point / %type <int> main %% Michel Mauny INE11@Ensta 37

3.5. TP OCamlyacc : ralisation dun analyseur syntaxique e

main: expr EOL { $1 } ; expr: INT { $1 } | LPAREN expr RPAREN { $2 } | expr PLUS expr { $1 + $3 } | expr MINUS expr { $1 $3 } | expr TIMES expr { $1 $3 } | expr DIV expr { $1 / $3 } | MINUS expr %prec UMINUS { $2 } ; La partie suivante contient la grammaire proprement dite, o` chaque r`gle est accompagne dune u e e expression OCaml crite entre accolades, dont la valeur sera produite ` chaque fois que cette r`gle e a e sera rduite, cest-`-dire que le non-terminal correspondant aura t eectivement reconnu. e a ee

3.5
e ::= | | | | |

TP OCamlyacc : ralisation dun analyseur syntaxique e


"fun" IDENT IDENT "->" e "let" IDENT "=" e "in" e ee INT IDENT "(" e ")"

On consid`re le langage dni (informellement) par la grammaire suivante : e e

1. Dnissez un analyseur lexical pour ce langage (en reprenant des lments du TP prcdent). e ee e e 2. Dnissez un type de donnes OCaml qui reprsente les arbres de syntaxe abstraite du langage. e e e 3. Cette grammaire est ambigu. Rcrivez-la en une grammaire non ambigu. e ee e 4. Utilisez Ocamlyacc pour en produire un analyseur syntaxique.

38

Michel Mauny

INE11@Ensta

Das könnte Ihnen auch gefallen