02 - Analyse syntaxique
Informations
Deadline: le 25 avril, 23:59
Points: 2 points de la note finale
Lien: https://classroom.github.com/a/A5xk-pKC
Téléchargement tardif: 0.5p/jour (maximum 4 jours)
Demandes
Analysez le fichier avec du code source dans le langage ALF et générez un arbre abstrait de syntaxe (AST). Utilisez un Visiteur pour réaliser une représentation à partir des classes de la bibliothèque de compilateur. Ensuite, affichez l'arbre obtenu sous la forme d'un JSON.
Vous recevrez le nom du fichier de la ligne de commande.
Syntaxe du langage ALF
Le langage Alf est un langage typé qui contient les instructions suivantes:
- définitions des variables
- définitions des fonctions
- définitions des classes (en tant que nouveau type de données)
- définitions des listes (en tant que nouveau type de données)
- expressions
- attributions
- appels des fonctions
- branches (des instructions
if
) - boucles (
while
,for
,repeat
)
Les instructions sont séparées par ;
.
Notations
- [facultatif]: ce qui se trouve entre
[]
est une partie optionnelle de l'instruction - <nom> : ce qui se trouve entre
<>
est seulement un modèle
Commentaires
Les commentaires font partie du fichier source et ils sont ignorés. Ils sont encadrés par /*
et */
et ne sont pas imbriqués. Ils peuvent s'étendre sur plusieurs lignes.
Tous les fichiers de test ont un commentaire sur la première ligne. Si votre grammaire n'a pas de règles pour les commentaires, vous pouvez tout simplement ignorer la première ligne.
/* Ceci est un texte pour décrire le script */
declare integer v = 5;
Types de données
Nom du type | Signification | Exemple d'une valeur |
---|---|---|
integer | nombre entier | 7 |
float | nombre réel | 7.5 |
char | caractère | 'a' |
string | chaîne | "ceci est une texte" |
boolean | valeur logique | false |
Pour les valeurs et les variables avec les types integer
et float
, on vous demande d’utiliser I64
et F64
pour les noms des types. Par exemple, pour le code suivant:
45;
la sortie sera:
{
"@type" : "Module",
"block" : {
"@type" : "Block",
"statements" : [ {
"@type" : "Value",
"value" : "45",
"typeName" : "I64",
"line" : 1
} ],
"line" : 1,
"scope" : {
"@type" : "SymbolTable",
"variables" : { },
"types" : { },
"functions" : { }
}
},
"line" : 1,
"scope" : null
}
Valeurs
Syntaxe:
<valeur>;
Exemples:
5;
"string";
true;
Les chaînes peuvent avoir les caractères spéciaux suivants:
- ” - notée \”
- \ - noté \
- \r - noté \r
- \n - noté \n
Notre langage peut aussi contenir la valeur vide:
emtpy;
Expressions
Priorité des opérateurs
Opérateur | Priorité |
---|---|
* , / , mod | Haute |
+ , - | |
! (not logique) | |
and , or , xor | |
> , >= , < , <= | |
== , != | Bas |
Exemples:
2+5;
2*4+5;
variable+5;
2+(x+y)*(exec func());
not true;
Déclarations des variables
Syntaxe:
declare [type_de_la_variable_1] <nom_de_la_variable_1> [ = <expréssion_1>] [, [type_de_la_variable_2] <nom_de_la_variable_2> [ = <expréssion_2>], ... ]
Exemples:
declare a;
declare integer b;
declare boolean c = false;
declare integer d = 7, string e = "texte", float f = 3.14;
Les noms des variables sont des chaînes qui commencent par une lettre ou _ et peuvent contenir d’autres lettres ou des chiffres.
Exemples:
var13
variable
_nomVar12
_a
Définitions des classes
Syntaxe:
class <nom_de_la_classe>
[local <property_type> <property_name> [= <valeur_initiale>]]
...
...
end;
Exemple:
class person
local string name;
local integer age = 20;
end;
Accès aux propriétés d'une classe
Syntaxe:
<nom_du_objet>.<nom_de_la_propriété>
Exemple:
p.name = "Un autre nom";
Définitions des listes
De la même manière comme pour les classe, définir une liste en fait défini un nouveau type des données. Pour l’utiliser, il faut déclarer une variable de ce nouveau type (avec la syntaxe normale pour la déclaration des variables).
Syntaxe:
//note: dans ce cas, [] sont des parenthèses réelles et sont obligatoires
<nom_du_type_des_données> array <nom_du_type_de_liste>[<from>:<to>];
Exemple:
integer array exemple[1:9];
Accès aux éléments d’une liste
Syntaxe:
//note: dans ce cas, [] sont des parenthèses réelles et sont obligatoires
<nom_de_la_variable_liste>[<index>]
Exemple:
v[5] = "New value inside the array";
Affectations
Syntaxe:
<variable> = <expression>;
Exemples:
var2 = 2*4+5;
obj.classfield = true;
v[5] = "New value inside the array";
Définitions des fonctions
Syntaxe:
function <nom_de_la_fonction>[([<type_paramètre_1> <nom_paramètre_1>[, <type_paramètre_2> <nom_paramètre_2>, ...]])] : <return_type> [=><expression>]
function <nom_de_la_fonction>[([<type_paramètre_1> <nom_paramètre_1>[, <type_paramètre_2> <nom_paramètre_2>, ...]])] : <return_type>
begin
<instructions>
end
Exemples:
function sample(float f1, float f2): integer;
function returns : string => "Fonction sans paramètres";
function withbody(integer i1, integer i2): integer
begin
s = i1 + i2;
end
L’instruction return
Syntaxe:
return <expression>;
Exemples:
return s;
return 2*3+1;
Appel des fonctions
Syntaxe
exec <nom_de_la_fonction>(<valeur_paramètre_1>, <valeur_paramètre_2>, ...);
Exemples:
exec write("Text");
s = exec _sum(2, 5);
exec getdir();
Branches
Syntaxe
if <expression>
<instructions>
end;
if <expression>
<instructions>
else
<instructions>
end;
Exemples
if var1 > 2
exec function1(s);
else
s = s + 9;
end;
Boucles
While
Syntaxe
while <expression> start
<instructions>
finish;
Repeat
Syntaxe
repeat
<instructions>
while <expression>;
For
Syntaxe
for <nom_de_variable> from <expression> to <expression> start
<instructions>
finish;
For iteration
Syntaxe
for <nom_de_variable> in <nom_de_variable> start
<instructions>
finish;
Exemple de représentation JSON
Pour afficher le résultat sous la forme d’un JSON, on va utiliser une instance de ObjectMapper de la manière suivante:
import com.fasterxml.jackson.databind.ObjectMapper
fun main(){
val serializer = ObjectMapper().writerWithDefaultPrettyPrinter()
val module: Module = ...
//votre code ici
//pour obtenir le JSON comme String (pour pouvoir l’écrire dans un fichier):
val jsonModule : String = serializer.writeValueAsString(module)
}
Pour le programme suivant:
/* Variable value Attribution */
declare integer n;
n = 6;
La sortie dans le format JSON sera:
{
"@type" : "Module",
"block" : {
"@type" : "Block",
"statements" : [ {
"@type" : "Group",
"declarations" : [ {
"@type" : "VariableDefinition",
"variable" : {
"@type" : "Identifier",
"title" : "n",
"typeName" : "I64",
"line" : 3
},
"init" : null,
"line" : 3
} ],
"line" : 3
}, {
"@type" : "Assignment",
"to" : {
"@type" : "Identifier",
"title" : "n",
"typeName" : null,
"line" : 5
},
"from" : {
"@type" : "Value",
"value" : "6",
"typeName" : "I64",
"line" : 5
},
"line" : 5
} ],
"line" : 3,
"scope" : {
"@type" : "SymbolTable",
"variables" : { },
"types" : { }
}
},
"line" : 3,
"scope" : null
}
Vous pouvez aussi regarder les testes ici.
Bonus
Implantez une fonctionalité pour traiter les erreurs.
Si le fichier source contient des erreurs, vous devez générer un JSON avec elles. Il y a deux types d'erreurs:
- lexicales (jéton pas reconnu)
- syntaxe (jéton inattendu)
Au lieu d’afficher l’AST pour le code reçu, vous devez afficher une liste contenant toutes les erreurs, ordonées en fonction de la ligne sur laquelle elles se trouvent.
Pour le code suivant:
declare variable < integer;
La sortie sera:
[ {
"id" : "Syntax Error",
"line" : 2,
"charPosition" : 17,
"msg" : "no viable alternative at input 'variable<'"
} ]
Conseils d'implantation
Pour chaque instruction possible du langage, on vous conseil de suivre les étapes suivantes:
- Écrivez les règles de la grammaire pour l’instruction.
- Implantez les fonctions du visiteur pour l’instruction.
- Testez votre implantation. Vous pouvez utiliser les données dans les testes.
Questions
Si vous avez des questions concernant les devoirs, posez-les en publiant un problème sur le github repository pour les questions avec le format du titre [syntaxique]<titre de votre question>
. Vous aurez besoin d'un compte github pour cela.
Ne postez pas de code. Cette action est considéré comme tentative de tricher et alors vous obtiendrez 0p pour le devoir.
Si vous souhaitez recevoir un e-mail lorsque des problèmes sont publiés ou lorsqu'il y a de nouveaux messages, accédez au repository pour les questions et cliquez sur Regarder.