:: Enseignements :: Master :: M2 :: 2011-2012 :: Machine Virtuelle (et bazard autour ...) ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Quelques notes sur la grammaire du language Foo |
Avant propos
Le language Foo n'est pas un vrai langage, mais à un language simple
avec les élements communs avec les langages Python, Ruby ou Javascript
et une syntax proche du C.
Il n'a donc aucune autre prétention que de calculer des valeurs de Fibonacci.
La grammaire
La grammaire du langage définie plus de constructions syntaxiques
que nécessaire pour réaliser les premiers labs. Ici, seuls les productions
pour ces premiers labs sont décrites.
La description de la grammaire est sous la forme d'une EBNF.
Les terminaux sont entre quote ('id' est un terminal) et le non-terminaux
non pas de quote (expr est un non-terminal).
De plus, foo? veut dire que, foo est optionel.
foo+ indique qu'il peut y avoir un ou plusieurs
foo répétés, foo* indique qu'il peut y avoir zéro ou
plusieurs foo répétés. Enfin il existe une construction qui
permet de définir lors d'une répétition un terminal de séparation,
foo/'bar'+ veut dire une serie de foo séparés
par des 'bar'.
Les noms entre '{' et '}' corresponde au nom des productions que l'on
retrouvera dans le code des visiteurs.
Un script
Un script est composé de plusieurs fonctions et d'un block de code
qui est le code à exécuter au début du script, une sorte de main.
Une fonction se déclare comme en C mais avec le mot clé 'fun' devant et
les types des paramétres et le type de retour sont optionnels.
Les instructions d'une fonction sont définies dans un block
c'est à dire entre '{' et '}'.
script = member* block { script }
;
member = func { member_func }
| ...
;
func = 'fun' 'type'? 'id' '(' parameter/'comma'* ')' block { func }
;
parameter = 'type'? 'id' { parameter }
;
block = '{' instr* '}' { block }
;
Instructions
Le langage
foo fait la distinction entre les instructions et les expressions,
les expressions ayant une valeur, et donc repésentent un calcul alors que les instructions
n'ont pas de valeur et représentent plus une commande.
Contrairement au C et comme en Javascript, les instructions peuvent se terminer par
un retour à la ligne à la place d'un point virgule ';' avec les mêmes rêgles
qu'en Javascript
(
Automatic Semicolon Insertion ou ASI).
Pour des questions de clareté, les instructions ont été découpé en plusieurs sections.
Declaration et assignation
Les variables sont déclarés avec le mot-clé var comme en Javascript
mais avec la porté d'une déclaration en C (la portée des variables en Javascript
est bizarre).
Contrairement au C, mais comme en C++ ou en Java, la déclaration de variable est
une instruction et donc peut se retrouver au milieu d'autres instructions.
Il n'est pas possible de déclarer une variable sans expression d'initialisation,
cela évite de se demander si les variables sont initilialisés ou non avant
leur utilisation qui est une contrainte requise par le bytecode Java.
Contrairement au C, l'assignation est une instruction, donc il ne peut pas y avoir
plusieurs assignations pour une instruction.
instr = decl eoln { instr_declaration }
| assignment eoln { instr_assignment }
| ...
decl = 'var' 'type'? 'id' '=' expr { decl }
;
assignment = 'id' '=' expr { assignment }
;
Boucle
Il n'y a qu'une seul syntaxe pour les boucles, la boucle for.
Comme en C, les instructions break et continue existent
et peuvent avoir un label.
Comme en C++ ou en Java, il est possible de déclarer une variable dans
la partie initialisation du for.
instr = ...
| label? 'for' '(' forinit? ';' expr? ';' forupdate? ')' instr { instr_for }
| 'break' 'id'? eoln { instr_break }
| 'continue' 'id'? eoln { instr_continue }
| ...
forinit = decl { forinit_decl }
| assignment { forinit_assignment }
;
forupdate = assignment { forupdate_assignment }
| expr { forupdate_expr }
;
label = 'id' ':' { label }
;
Appel de fonction
Un appel de fonction est une instruction et une expression et les arguments
qui sont des expressions sont séparés par des virgules.
instr = ...
| funcall eoln { instr_funcall }
| ...
primary = ...
| funcall { primary_funcall }
| ...
funcall = 'id' '(' arg/','* ')' { funcall }
;
arg = expr { arg_expr }
| ...
;
Autres instructions
La grammaire définie aussi les instructions if et if/else
ainsi que l'instruction return.
instr = decl eoln { instr_declaration }
| assignment eoln { instr_assignment }
| funcall eoln { instr_funcall }
| block { instr_block }
| 'if' '(' expr ')' instr [else] { instr_if }
| 'if' '(' expr ')' instr 'else' instr { instr_if_else }
| label? 'for' '(' forinit? ';' expr? ';' forupdate? ')' instr { instr_for }
| 'return' expr? eoln { instr_return }
| 'break' 'id'? eoln { instr_break }
| 'continue' 'id'? eoln { instr_continue }
;
Les expressions
Les expressions sont soit des constantes, des variables ou des combinaisons
utilisant les opéraeurs binaires +, -, *, /, %, ==, !=, <, <=, >, >=, && et ||
avec leur précédence habituelle.
Les constantes sont true, false, des entiers sur 32 bits,
des valeurs flottantes 64bits (IEEE 764), des chaines de caractères séparé par des " "
et null.
primary = constant { primary_constant }
| 'id' { primary_id }
| '(' expr ')' { primary_parens }
| funcall { primary_funcall }
;
expr = primary { expr_primary }
| expr '+' expr [plus] { expr_add }
| expr '-' expr [plus] { expr_sub }
| expr '*' expr [star] { expr_mul }
| expr '/' expr [star] { expr_div }
| expr '%' expr [star] { expr_mod }
| expr '==' expr [eq] { expr_eq }
| expr '!=' expr [eq] { expr_neq }
| expr '<' expr [eq] { expr_lt }
| expr '<=' expr [eq] { expr_le }
| expr '>' expr [eq] { expr_gt }
| expr '>=' expr [eq] { expr_ge }
| expr '&&' expr [and] { expr_and }
| expr '||' expr [and] { expr_or }
;
constant = 'boolean_cst' { constant_boolean }
| 'integer_cst' { constant_integer }
| 'double_cst' { constant_double }
| 'string_cst' { constant_string }
| 'null' { constant_null }
;
© Université de Marne-la-Vallée