Parse the ALF language source file and generate a JSON abstract syntax tree (AST).
The homework will take one or two parameters from the command line. The first paremeter is the filename with the Alf script, the second one the output file. If the output file is missing, the output is the same as the script file with the extension ”.json”.
node main.js script.alf script.alf.json
Here are some tips for solving the homework:
Try running small scripts to test every feature.
A useful debugging too is jison-debugger
All the nodes in the AST have the following format:
{ id:"node_id", line: "the line where the instruction is in the file, starting at 1" }
The list of the node ids is:
If you have any questions related to the homework, please ask them by posting an issue on the github repository with the title format [alf] <your question title>. You will need a github account for that.
If you want to receive an email when issues are posted or when there are new messages, got to the github repository and click Watch.
The Alf language is a typed language defined as follows:
a=10; b=20; s=55;
Values are
1
0.1
"a"
"this is a text"
false
none
Comments are a part of the source file that is ignored. They are enclosed between ”#” and ”#” and NOT not imbricated.
#this is a text to describe the script# @var v:int <- 55;
An identifier can be any value that starts with a letter, $ or _ and may have also numbers in its name.
identifier $identifier _identifier
{ id:"identifier", title:"identifier_name" }
A value is any integer number, float number, bool, character or string.
3534 45634.423 false "s" "string"
{ id:"value", type:"value_type", // int, float, bool, character, string value:actual_value }
@var variable_name [:variable_type] [<- value or expression], ...; @var variable_name, variable_name, variable_name, ... :variable_type, ....;
@var a:int <- 3; @var a <- 3; @var a1:int <- 3, a2:string <- "text", a3:int; @var a,b : int;
{ id:"var", variables:[ // array of variables { type:"data type", title: "variable name", value: "variable value" }, ] }
struct struct_name property_name:data_type [= initial_value] ... ... end;
{ id:"struct_def", title:"struct_name", properties:[ // array of properties { type:"property data type", title: "property name", value: "property value" // if it exists }, ] }
struct_name.property
{ id:"prop", object: { expression for object }, title: { expression for property } }
vector_name:elements_data_type[integer_number -- integer_number] <note> [] are actual brackets and are mandatory </note>
{ id:"vector", title: vector_name, element_type:elements_data_type, from: from_integer_number, to: to_integer_number }
vector_name[index]
{ id:"element_of_vector", vector:{ expression for array }, index: { expression for index } }
Operator | Precedence |
---|---|
if | Low |
== != | |
> >= < ⇐ | |
and or xor | |
not | |
+ - | |
* / mod | High |
2+5; 2*4+5; variable+5; x>y; x=y; 2+(x+y)*(5+6);
{ id:"expr", op:"operator", left:left_operand, right:right_operand }
{ id:"expr", op:"negative", value:50 }
variable <- expression;
x <- 1000; s <- "text" + "s"; y <- f(); l[i] <- 900; q.e <- "this is a text";
{ id:"attr", to: { ... id, property, element_of_array }, from: { ... exp } }
function function_name (parameter1:[parameter1_type][<-value], ...):return_type -> expression;
function function_name (parameter1:[parameter1_type][<-value], ...):return_type start ... end;
function f1:none () start end;
function sum (a:int, b:int):int -> a+b;
function power (a:int, n:int):int start @var p:int; @var i:int; if n == 0 then start power <- 1; end; for i between (1,n) p <- p * a; return p; end;
{ id:"function_def", title:"function_name", parameters:[ // array of parameters { type:"data type", name: "parameter name" }, ], return_type:"type of the value that the function returns", statements:[ // array of statements (even if it is only one) ... ] }
This is the statement that sets the return value of the function.
return x+y;
{ id:"return", value: { ... } }
The is a call for a function
function_name (parameter_name1:value1, parameter_name2:value, ...);
function_name (parameter1_value, parameter2_value, ...)
write (text:"Text"); s = sum (3, 5); getdir ();
{ id:"function_call", function:"function_name", parameters:{ // dictionary of parameter name or index and value "parameter1": parameter_value, "2":parameter value, ... } }
if expression then ... end;
if expression then ... else ... end;
{ id:"if_then", exp:expression, then: [ // list of statements ] }
{ id:"if_then", exp:expression, then: [ // list of statements ], else: [ // list of statements ] }
There are three types of loops: while, repeat and for.
loop expression go ... end;
{ id:"loop_go", exp :expression, statements: [ // array of statements ] }
loop ... when expression;
{ id:"loop_when", exp :expression, statements: [ // array of statements ] }
for variable_name of expression go ... end;
or
for variable_name from number to number go ... end;
for variable_name from number downto number go ... end;
{ id:"for", variable:variable_name, exp:{ expression ... } statements: [ // array of statements ] }
or
{ id:"for", variable:variable_name, from: { expression }, to/downto: { expression }, statements: [ // array of statements ] }
If the source file has any error, you will have to output a JSON with the error. There are two kinds of errors:
For any lexical error, the output will be:
{ error:"lexical", line: line_number, text: "text that is not recognised" }
For any syntactical error, the output will be:
{ error:"syntax", line: line_number, token: "token that the parser saw", // token name will not be checked by checker expected: [list of expected tokens] // token name will not be checked by checker }
For an additional 0.5p, implement the following:
Add preprocessing to the source. You have
Registers an identifier to a value.
®ister identifier value
The identifier will be replaced in the program with the value (textually).
Verifies if an identifier is registered and has a value and adds the source code up to else or endif. Else is optional.
®ister platform ... ... &if platform = windows p <- "Windows" #this source is ignored if platform is not windows# &else p <- "Linux" #this source code is ignored if platform is not linux# &endif
Unregister an identifier from a value.
®ister N value ... &unregister N #N is undefined#
The homework will be tested automatically using a set of public and private tests.
You can download the public tests from the GitHub repository.
To run the tests, download the contents of the repository in the folder with the homework. Enter the verify folder and run ./run_all.sh.
cd verify ./run_all.sh
You will need bash for that. You can use either Linux or Windows Linux Subsystem.
wget https://nodejs.org/dist/v6.10.0/node-v6.10.0-linux-x64.tar.xz tar xvfJ node-v6.10.0-linux-x64.tar.xz cd node-v6.10.0-linux-x64 sudo cp -R * /usr
When uploading the homework, we might have some private tests that it needs to pass. vmchecker will run them.
The homework needs to be uploaded to vmchecker. Login with your moodle user name, select the Automates et Langages Formelles (FILS) course and upload the homework archive.
The readme file has the following format:
Your full name Group An explanation how you wrote your homework, what did you use, what are the main ideas.
To upload your homework, please follow the following:
DO NO include node_modules.
When the archive is uploaded, vmchecker will run:
unzip archive.zip homework cd homework npm install echo '{ "node":true, "loopfunc": true, "esnext":true }' > .jshintrc jshint *.js jison grammar.y grammar.l -o grammar.js