This is an old revision of the document!
Analyser le fichier source du langage ALF et générer un arbre de syntaxe abstraite JSON (AST).
Le devoir prendra un ou deux paramètres de la ligne de commande. Le premier paramètre est le nom du fichier avec le script ALF, le deuxième est le fichier de sortie. Si le fichier de sortie manque, il aura la même nom que le fichier script avec l'extension ”.json”.
Par exemple, dans ce cas, le fichier de sortie sera script.json
:
node main.js script.ast script.json
Dans l'exemple suivant, tenant compte du fait que le deuxième paramètre manque, le fichier de sortie sera automatiquement généré, ayant le nom script.ast.json
:
node main.js script.ast
Voici quelques conseils pour résoudre le devoir:
Essayez d'exécuter de petits scripts pour tester chaque fonctionnalité.
Tous les nœuds de l'AST ont le format suivant:
{ id:"node_id", line: "the line where the instruction is in the file, starting at 1" }
La liste des identifiants des noeuds:
Si vous avez des questions concernant les devoir, posez-les en postant un issue sur github repository avec le format [alf] <titre de la question>. Vous aurez besoin d'un compte github pour cela.
Si vous souhaitez recevoir un e-mail lorsque des problèmes sont signalés ou lorsqu'il y a de nouveaux messages, accédez au site github repository et cliquez sur Watch.
Le langage Alf est un langage typé défini comme suit:
a=10; b=20; s=55;
Les valeurs sont
7
7.5
"a"
"ceci est un texte"
false
empty
Les commentaires font partie du fichier source et ils sont ignorés. Ils sont encadrés par ”/” et ne sont pas imbriqués.
/* Ceci est un texte pour décrire le script */ declare integer v = 5;
Une variable peut être n'importe quelle valeur qui commence par une lettre ou _ et peut contenir aussi des nombres.
identifier identifier1 _identifier _identifier1
{ id: "Variable", title: "variable_name", line: line_no }
Une valeur est un nombre entier, un nombre reel, une valeur logique ou une chaîne.
3534 45634.423 false "s" "string"
{ "id": "Value", "type": "value_type", //int, float, symbol, boolean, string "value": actual_value, "line": line_no }
declare [variable_type] variable_name [ = value ou expression], ...; declare variable_name, variable_name, variable_name ...;
declare integer a = 3; declare b = false; declare integer a = 1, string b = "text", boolean c = true;
{ "id": "Declaration", "elements": [ { "id": "DeclarationElement", "type": "variable_type", "title": "variable_name", "line": line_no } ], "line": line_no }
class class_name [local property_type property_name [= initial_value]] ... ... end;
{ "id": "ClassDefinition", "title": "class_name", "properties": [ // array of properties { "id": "LocalProperty", "type": "property_type", "title": "property_name", "value": { property_value } // only if it exists "line": prop_line_no }, ... ], "line": class_end_line_no }
object_name.property
{ "id": "ClassProperty", "object": { // class object "id": "Variable", "title": "s", "line": 10 }, "title": "property_name", "line": 10 }
array_type array array_name[from:to] <note> [] sont des parenthèses réelles et sont obligatoires </note>
{ id:"Array", title: array_name, element_type: "elements_data_type", from: from_integer_number, to: to_integer_number }
array_name[index]
{ id: "ArrayElement", array: "array_name", index: { index_object } }
Opérateur | Priorité |
---|---|
if | Low |
= != | |
> >= < ⇐ | |
and or xor | |
not | |
+ - | |
* / mod | High |
2+5; 2*4+5; variable+5; 2+(x+y)*(5+6);
{ id:"Expression", op:"operator", left: { left_operand_object }, right: { right_operand_object } }
variable = expression;
x = 1000; s = "text" + "s"; y = exec _f(); l[i] = 900; q.e = "this is a text";
{ id:"Assign", to: { to_object }, from: { from_object }, line: line_no }
function function_name([parameter1_type] parameter1 [= value], ...):return_type [=> expression];
function function_name:return_type [([parameter1_type] parameter1 [= value], ...):return_type] begin // statements end;
function f1:(integer n1, integer n2):integer; start end;
function _sum (integer a, integer b):integer => a+b;
function power (integer a, integer b):integer begin declare integer n; declare integer i; return n; end;
{ "id": "FunctionDefinition", "title": "function_name", "parameters": [ // parameters list; empty if the function has no parameter { "id": "FunctionDefinitionParameter", "type": "parameter_type", "name": "parameter_name" }, ... ], "return_type": "function_return_type", "statements": [ //statements_list; empty if the function has no instruction { statement_object }, ... ], "return_function": { //return function object; only if the function returns something "id": "ReturnFunction", "value": { return_object }, "line": return_line_no }, "line": function_end_line_no }
Ces sont les instructions qui définissent la valeur de retour d'un message.
return x+y;
{ { "id": "ReturnFunction", "value": { return_object }, "line": return_line_no } }
exec function_name (parameter_name1=value1, parameter_name2=value, ...);
exec function_name (parameter1_value, parameter2_value, ...)
exec write (text="Text"); s = exec sum (3, 5); exec _getdir ();
{ "id": "FunctionCall", "function_name": "function_name", "parameters": [ // parameters list for the function call; empty if the function call has no parameters { "id": "FunctionCallParameter", "name": "parameter_name", "value": { paramter_object_value } } ], "line": function_call_line_no }
if expression ... end;
if expression ... else ... end;
{ id:"IfBranch", exp:{ evaluation_expression_object }, then: [ //instructions list ] }
{ id:"IfBranch", exp:{ evaluation_expression_object }, then: [ //instructions list ] else: [ //instructions list ] }
Il existe trois types de boucles: while, repeat et for.
while expression start ... finish;
{ id:"WhileLoop", exp: { evaluation_expression_object }, statements: [ //instructions list ] }
repeat ... while expression
{ id:"RepeatLoop", exp: { evaluation_expression_object }, statements: [ //instructions list ] }
for variable_name from expr to expr start n = n + 1; finish;
or
for variable_name in variable_name ... end;
{ id:"ForLoop", variable: "variable_name", from :{ from_expression_object }, to :{ to_expression_object }, statements: [ //instructions list ] }
or
{ id:"ForLoop", variable: "variable_name", exp :{ var_expression_object }, statements: [ //instructions list ] }
Pour 0.5 points supplémentaires, implémentez une fonctionnalité pour le traitement des erreurs.
Si le fichier source a des erreurs, vous devrez générer un JSON avec elles. Il y a deux types d'erreurs:
Pour toute erreur lexicale, la sortie sera:
{ "id": "Lexical Error", "line": line_no_in_file, "position": position_in_string, "message": "error_message" }
Pour toute erreur de syntaxe, la sortie sera:
{ "id": "Syntax Error", "line": line_no_in_file, "position": position_in_string, "message": "erorr_message" }
{ "id": "Errors", "errors": [error_node_array] }