0% ont trouvé ce document utile (0 vote)
192 vues29 pages

Chap6 Bison

Bison est un outil qui génère automatiquement un analyseur syntaxique basé sur une grammaire donnée, permettant de construire un arbre syntaxique après l'analyse lexicale. Le document décrit les étapes pour concevoir un analyseur avec Bison, y compris la définition de la grammaire, les règles de production, et l'association de valeurs aux symboles. Il aborde également les actions sémantiques, la gestion des erreurs et fournit un exemple d'interpréteur d'expressions arithmétiques.

Transféré par

Hous Souh
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PPTX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
192 vues29 pages

Chap6 Bison

Bison est un outil qui génère automatiquement un analyseur syntaxique basé sur une grammaire donnée, permettant de construire un arbre syntaxique après l'analyse lexicale. Le document décrit les étapes pour concevoir un analyseur avec Bison, y compris la définition de la grammaire, les règles de production, et l'association de valeurs aux symboles. Il aborde également les actions sémantiques, la gestion des erreurs et fournit un exemple d'interpréteur d'expressions arithmétiques.

Transféré par

Hous Souh
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PPTX, PDF, TXT ou lisez en ligne sur Scribd

L’outil d’analyse syntaxique

Bison
Introduction

 Une fois l’analyse lexicale est effectuée, l’analyse syntaxique (parsing)


permet de vérifier qu’un texte est conforme à une grammaire G donnée.
 L’analyse syntaxique construit l’arbre syntaxique correspondant au
texte analysé.
 Bison est un outil qui génère d’une manière automatique, un analyseur
syntaxique basé sur une grammaire donnée.
 Un programme Bison est enregistré avec l’extension ”.y”.
Introduction

Etapes pour la conception d’un analyseur syntaxique


avec Bison
 Définir la grammaire de l’analyseur, puis l’écrire en respectant le format
de Bison.
 Pour chaque règle de production de la grammaire, écrire l’action (les
instructions C) qui va être exécutée lorsqu’une instance de cette règle
est reconnue par l’analyseur.
 écrire un analyseur lexical qui va traiter le fichier source et produira les
lexèmes à l’analyseur syntaxique. celui-ci peut être écrit à la main ou
bien avec Flex.
Introduction

Chaîne de compilation
 On compile le fichier contenant le code Bison par :
 bison -d parser.y
 On compile le fichier contenant le code Flex par :
 flex [Link]
 On compile par gcc :
 gcc -o parser [Link].c [Link].c -ly -lfl
 Pour lancer l’analyseur ainsi crée :
 parser < [Link] > [Link]
Format d’un fichier Bison

%{
déclaration (en C) de variables, constantes, inclusions de fichiers,…
}%
déclarations des unités lexicales utilisées
déclarations de priorités et de types
%%
règles de production et actions sémantiques
%%
routines C et bloc principal
Déclarations et définitions

 La partie déclarations et définitions contient les déclarations C (entre les


symboles %{ et %}), ainsi que la déclaration des noms de tokens
(lexèmes).
 Les symboles terminaux utilisables dans la description du langage sont
 des unités lexicales que l’on doit impérativement déclarer par %token
nom. Par exemple :

 des caractères entre quotes. Par exemple: ‘+’ ‘a’


 Les symboles non-terminaux sont les caractères ou les chaînes de
caractères non déclarées comme unités lexicales
 Yacc/bison fait la différence entre majuscules et minuscules SI et si ne
désignent pas le même objet.
Déclarations et définitions

Cas des opérateurs


 Lorsque les tokens correspondent à des opérateurs pour lesquels on
souhaite spécifier une propriété d’associativité, ou utilise left et right
au lieu de token.
 Par exemple, on écrira :

 Si l’on souhaite de plus spécifier la précédence entre opérateurs, on


écrit la déclaration des tokens dans l’ordre inverse des priorités.
 Dans l’exemple ci-dessus, l’opérateur ‘^' a une priorité plus grande que
les opérateurs '+' et '−' (qui sont de même priorité).
Déclarations et définitions

Cas des opérateurs


 Il est également possible de modifier la précédence d’un opérateur dans
une règle.
 Par exemple, si l’on souhaite décrire le ”moins unaire” aussi désigné par
les symbole '−' comme un opérateur ayant même précédence qu’un
token de nom NEG, on écrira :
' −' %prec NEG
 afin de ne pas associer au ”moins unaire” la même précédence que le
”moins binaire”.
Déclarations et définitions

 Il ne faut pas oublier de retourner les unités lexicales (les tokens) au


niveau de la partie « règles » du programme flex associé
Déclarations et définitions

 Chaque non-terminal doit apparaître au moins une fois comme partie


gauche d’une règle.
 L’axiome de la grammaire spécifiée peut être désigné explicitement
dans la partie des déclaration en utilisant la directive %start.
 Par exemple : %start axiome
 Par défaut, l’axiome de la grammaire sera le premier non-terminal
apparaissant dans la partie gauche de la première règle.
 Si la grammaire est ambigüe, Bison sera confronté à des conflits
”shift/reduce” ou ”reduce/shift”.
Règles

 Une règle est une règle de production de la grammaire, enrichie


d’actions.
 Une règle s’écrit :
 A : Corps;
 où A est le nom (un identificateur) d’un non-terminal et Corps est une
suite (éventuellement vide) de noms (de terminaux et non-terminaux) et
de littéraux (caractères entre guillemets).
 Lorsqu’il existe plusieurs règles de production pour un même non-
terminal, l’opérateur ”|” peut être utilisé pour séparer le corps de
chaque règle.
 On peut par exemple écrire :
Règles

 Les règles de production sont des suites d’instructions de la forme


 non-terminal : prod1
 |prod2
 …
 | prodn
 ;
 Les actions sémantiques sont des instructions en C insérées dans les
règles de production. Elles sont exécutées chaque fois que la production
est vérifiée.
 Exemple:
Association d’une valeur aux
symboles
 Bison fait appel à la fonction yylex() de Flex à chaque fois qu’un token
est nécessaire à la suite de l’analyse syntaxique.
 L’association d’une valeur à un token se fait via la variable globale de
Bison nommée yylval.
 L’analyseur syntaxique et l’analyseur lexical peuvent communiquer
entre eux par l’intermédiaire de la variable int yylval
Association d’une valeur aux
symboles
 Dans une action lexicale (dans le fichier flex par exemple), l’instruction
return(unité) permet de renvoyer à l’analyseur syntaxique l’unité
lexicale unité.
 La valeur de cette unité lexicale peut être rangée dans yylval.
 L’analyseur syntaxique prendra automatiquement le contenu de yylval
comme valeur de l’attribut associé à cette unité lexicale.
Association d’une valeur aux
symboles
 yylval est de type YYSTYPE.
 Par défaut, YYSTYPE correspond au type int.
 Il est possible de redéfinir le type YYSTYPE via la macro ”#define”. La
redéfinition s’effectue dans la section des définitions.
 Il se peut que les valeurs des tokens aient des types différents.
 Pour traiter ce cas, on peut définir une union des types via la clause
%union. Par exemple, si l’on veut associer aux tokens des valeurs de
type ”entier” et ”chaîne de caractères”, on écrira :

 permet de stocker dans yylval à la fois des int des double et des char*.
Association d’une valeur aux
symboles
 L’analyseur lexical pourra par exemple contenir

 Le type des lexèmes doit alors être précisé en utilisant les noms des
champs de l’union
Association d’une valeur aux
symboles
 On peut également typer des non-terminaux pour pouvoir associer une
valeur de type autre que int à un non-terminal par
Attributs

 A chaque symbole (terminal ou non) est associé une valeur (de type entier
par défaut) Cette valeur peut être utilisée dans les actions sémantiques
comme un attribut synthétisé).
 Le symbole $$ référence la valeur de l’attribut associé au non-terminal de la
partie gauche, tandis que $i référence la valeur associée au i-ème symbole
(terminal ou non-terminal) ou action sémantique de la partie droite.
 Ces variables correspondent aux valeurs retournées par les actions
correspondant aux éléments de la partie droite de la règle.
 Par exemple, étant donné la règle :
A : B C D { ($1, $2, $3); }
 les valeurs $1, $2 et $3 correspondent aux valeurs retournées par les actions
spécifiées dans les règles utilisées reconnaissant B, C et D
Actions

 Exemple:

 Par défaut lorsqu’aucune action n’est indiquée, c’est $1 qui est


retournée et yacc/bison génère l’action {$$=$1;}
Actions

 Bison permet d’exécuter des actions avant la fin de l’application d’une


règle.
 Il est donc possible d’indiquer une action entre deux éléments de la
partie droite d’une règle.
 Par exemple, la règle :

aura pour effet d’affecter la valeur 1 à la variable x et la valeur retournée par la


règle utilisée pour reconnaître C à la variable y.
Actions

 Il est possible d’appeler la fonction qui effectue l’analyse syntaxique en


invoquant son nom ”yyparse”().
 Lors de l’exécution de la fonction ”yyparse”(), si une erreur de syntaxe
est détectée,
 la fonction ”yyerror”() est appelée afin qu’un message d’erreur s’affiche.
 la fonction ”yyparse”() déclenche l’arrêt immédiat de l’analyse syntaxique
après l’exécution de la fonction ”yyerror”().
 Celle-ci, affiche par défaut le message : ”syntax error”.
 la fonction ”yyparse”() retourne une valeur non nulle.
Variables fonctions et actions prédéfinies

 yyparse(): appel de l’analyseur syntaxique


 YYACCEPT: instruction qui permet de stopper l’analyseur syntaxique
 YYABORT : instruction qui permet également de stopper l’analyseur mais
yyparse() retourne alors ce qui peut être utilisé pour signifier l’echec de l
analyseur
 main(): le main par défaut se contente d’appeler yyparse(). L’utilisateur
peut écrire son propre main dans la partie du bloc principal.
Exemple

 Cet exemple lit des listes d’entiers précédées soit du mot somme, soit
du mot produit.
 Une liste d’entiers est composée d’entiers séparés par des virgules et se
termine par un point.
 Lorsque la liste débute par somme, l’exécutable doit afficher la somme des
entiers,
 lorsqu’elle débute par produit il doit en afficher le produit,
 Le fichier doit se terminer par $.
 Cet exemple utilise la fonction yylex générée par le compilateur flex à
partir du fichier de spécification suivant:
 Le fichier de spécifications bison est alors le suivant
Exécution
 utiliser le compilateur bison du nom.y avec l’option -d qui produit un fichier
[Link].h contenant les définitions (sous forme de #define) des unités lexicales (les
tokens) rencontrées et du type YYSTYPE s’il est redéfini
Bison –d
nom.y nom.y [Link].h

 Dans la partie ”déclarations” du fichier Flex, on écrira la ligne :


#include ”nom .tab.h”
 Compiler le fichier flex par
[Link] Flex [Link]
[Link].c
x

 lors de la compilation C du fichier [Link].c, il faut faire le lien avec [Link].c et


rajouter la bibliothèque flex lors de la compilation C du fichier [Link].c avec :
 gcc [Link].c [Link].c -ly -lfl
 attention à l’ordre de ces bibliothèques
Exercice

Enoncé
 écrire un interpréteur d’expressions arithmétiques sur les ”entiers” et
n’utilisant que les opérateurs + ( additions) et (multiplications).
 Modifier cet interpréteur pour qu’il puisse traiter les ”doubles”.

Vous aimerez peut-être aussi