Table of Contents

Homework 4 - Semantic

Information

Deadline: 5th of May, 23:55
Points: 2 points out of the final grade
Upload the homework: vmchecker.cs.pub.ro
Late upload: 0.1 points / day (maximum 4 days)

What do you have to do

The purpose of the homework is to create the symbol table and write the semantic analysis for the Alf language.

You will receive an AST from the parser that parses correctly a Alf language source and have to write:

  1. the symbol table
  2. a new AST with the following modifications:
    1. the new AST is a list of function statements
      1. all the AST nodes will have a property called symbol_table that will point towards the symbol table entry where they declare variables, functions and types
      2. the main program is called “script”
      3. all the other function definitions are moved from the old AST to the new AST
    2. all the variable definitions AST nodes are deleted or, if they have an attribution `@var i:int ← 3;`, are replaced by an attribution AST node `i ← 3;`.
  3. the semantic error list

All the three requirements are verified and graded separately. Examples that produce no errors will receive error points only if the symbol table and the new AST are correct.

The program will receive two parameters from the command line:

node main.js source.alf.ast.json source.alf.json

The AST files

Use the ast given here.

Hints for solving the homework

Output file

The format of the output file is the following

{
    symbol_table: {...}, // the symbol_table
    ast: [...], // the ast with the type for very node that returns a value
    errors [] // the error list
}

Symbol table

The symbol table is represented by a Javascript object, where each property is the name of a context. In the example below you can see there are two contexts:

{
    "script": {
        "type": "script",
        "variables": {},
        "functions": {
            "sum": {
                "type": "int",
                "parameters": [
                    {
                        "type": "int",
                        "title": "n1",
                        "line": 4
                    },
                    {
                        "type": "int",
                        "title": "n2",
                        "line": 4
                    }
                ],
                "line": 4
            }
        },
        "types": {}
    },
    "function_sum": {
        "title": "sum",
        "type": "function",
        "parent": "script",
        "variables": {
            "n1": {
                "type": "int",
                "parameter": true,
                "index": 0
            },
            "n2": {
                "type": "int",
                "parameter": true,
                "index": 1
            }
        },
        "functions": {},
        "types": {}
    }
}

While determining the symbol table, add to each AST node a parameter symbol_table with the name of the symbol table in which it has its variables, functions and types.

Context Object

The context object stores

Context objects are generated by

  • the main module
  • a function definition
  • a if definition
  • a for definition
  • a loop when and loop go definition

The object looks like

{
   "variables": { // a dictionary of variables
      "variable_name": {
         "type": // type of the variable
         "line": // the line where the variable was declared
         "parameter": //true if this is a function parameter, false otherwise
         "value": // the expression that the variable initially has (optional, if the define was with an assignment)
      }
   },
   "functions": { // a dictionary of functions
      "function_title": {
         "type": // the return type of the function
         "parameters": [] // the list of parameters the function takes (the parameters node from the AST)
         "line": // the line where the function was declared
 
      }
   }, 
   "types": {  // a dictionary of types
      "type": {
               "type":  // the type of the new type struct or array
               "line":  // the line where the type was declared
               // for array
               "elements_type":  // the type of each array element
               "first":  // the first index
               "length": // the number of elements in the array
               // for struct
               "properties": [ // a list of array elements (the node form the AST)
                  {
                     "type": 
                     "title": 
                     "value": // the expression that the variable initially has (optional, if the define was with an assignment)
                     "line": 
                     "symbol_table": // the context title where the structure was defined
                  },
                  ...
               ]
            }
   },
   "parent": // the parent context the symbol_table (except of the main script that has no parent) 
   "type": // the type of the context (script, function or statements)
}

Context names

The new AST

The AST from the parser has to be transformed so that it does not contain any variable, function or type definitions.

The new AST is a list of objects, each object being either the script either a function.

[
  // the script
  "script": {
    statements: [
      ...
    ]
  },
  // a function
  "function_title": {
     statements: [
       ...
     ]
  }
]

Variable definitions

The variable definitions will be written to the symbol table. The definition will be deleted from the AST (it will not be placed in the statements, as it has no actual action). If the definition is with an attribution @var x:int ← 7;, it will be replaced with an attribution node equivalent to x ← 7;.

Type definitions

Structs and vectors are type definitions. These will be written to the types part in the symbol table.

For structs, if the properties have default values, every struct variable declaration will be replaced with attributions for all the properties. There is an example in the repository.

Verify Types in the AST

Expression return type

For each of the following nodes, determine the return type

All the other elements have the return type none. If there is a type error (eg. float * string) it will be error.

Set type the by adding a parameter type in the node.

When searching for a variable, the algorithm is:

  • search the local context
  • if not found, search the parent context

Example

{
    "id": "expr",
    "op": "+",
    "left": {
       "id": "value",
       "type": "int",
       "value": 2,
       "line": 3,
       "symbol_table": "script"
    },
    "right": {
       "id": "value",
       "type": "int",
       "value": 3,
       "line": 3,
       "symbol_table": "script"
    },
    "line": 3,
    "symbol_table": "script",
    "type": "int"
}

Verify types

For all the AST nodes, verify that the types match:

This is where most of the errors appear from.

Error List

The error list is an array that contains error objects. The order in which these errors are in the list is up to you.

Error Object Format

Each error has the following format:

{
    type: //  string with the error type
    elements: {
       // items for the error, each type of error has different items
       line: // the line where the error is
    },
    text: // the error text message
}

Error type

The error type is a string with one of the following titles

VARIABLE_ALREADY_DEFINED

The error occurs when a variable definition is repeated.

Elements
{
    variable: // variable name,
}

FUNCTION_ALREADY_DEFINED

The error occurs when a function definition is repeated.

Elements
{
    function: // function name
}

TYPE_ALREADY_DEFINED

The error occurs when a type definition is repeated (array or struct).

Elements
{
    type: // type name
}

STRUCT_PROPERTY_ALREADY_DEFINED

The error occurs when a struct element definition is repeated.

Elements

{

  type: // struct type title
  title: // property title

}

ARRAY_INDEX_VALUE

The error occurs when the array lower index is higher than the higher index

Elements
{
    array: // array type name
    length: // the negative length
}

TYPE_RESOLUTION

The error occurs when the type of a variable is not determinable (bonus only).

Elements
// variable
{
    variable: // the name of the variable with the unresolved type
}
// struct property
{
    struct: // name of struct type
    property: // name of struct element with the unresolved type
}

UNDEFINED_FUNCTION

The error occurs when a function call is made to a function that is not defined.

Elements
{
   title: // function title
}

UNDEFINED_VARIABLE

The error occurs when a variable that is not defined is used.

Elements
{
   variable: // variable title
}

UNDEFINED_TYPE

The error occurs when a type that is not defined is used.

Elements

{

  value: // the type that is undefined

}

NOT_STRUCT_PROPERTY

The error occurs when an element is not part of that struct.

Elements
{
   type: // struct title
   title: // property title
}

NOT_STRUCT

The error occurs when a property is requested for a variable that is not a struct type

Elements
{
   type: // actual type that the variable is (instead of a struct type)
}

NOT_ARRAY

The error occurs when an index is requested for a variable that is not an array

Elements
{
   type: // actual type that the variable is (instead of an array type)
}

ARRAY_INDEX_TYPE

The error occurs when an index for an array is not an int

Elements
{
   type: // the index type
}

RETURN_OUTSIDE_FUNCTION

The error occurs when a value statement (return node) is used outside a function

Elements
{
   // empty
}

TYPE_EXPRESSION

The error occurs when an expression has incompatible types

Elements
// left op right
{
    left:
    right:
    op:
}
// op value
{
    value:
    op:
}
// if, loop-go, loop-when
{
    exp: // expression type
    op: // if, while, repeat
}
// attribution (including for variable)
{
    to: // to type,
    op: "<-",
    from: // from type
}
// return
{
    op: "return"
    to: // return type
    from: // provided type
}
// iteration (for i in exp go)
{
    op: "iteration"
    value: // the exp type
}
// typecast
{
    op: "typecast",
    to: // to type,
    from: // from type
}
 
=== LEXICAL ===
This is a lexical error
 
== Elements ==
<code javascript>
{
    line: // the line number
    text: // the text of the error
}

SYNTAX

This is a syntax error

Elements
{
    line: // the line number
    text: // the text of the error
    token: // the token it got
    expected: [] / the list of expected tokens
}

Bonus

For an additional 0.5p, implement find the type of variables that are declared using just an attribution.

Bonus will be awarded only if all other tests pass.

Copying

The homework is individual. Any attempt of copying will result in 0p for the homework. Automated anti copying system will be used.

Questions

If you have any questions related to the homework, please ask them by posting an issue on the github repository with the title format [calculator] <your question title>. You will need a github account for that.

DO NO POST ANY CODE. This is considered copying and will result in a 0p homework for you.

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.

Testing

The homework will be tested automatically using a set of public and private tests.

Public 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.

To install nodejs in Linux or Windows Linux Subsystem, do the following:

wget https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-x64.tar.xz
tar xvfJ node-v8.9.4-linux-x64.tar.xz
cd node-v8.9.4-linux-x64
sudo cp -R * /usr

Private Tests

When uploading the homework, we might have some private tests that it needs to pass. vmchecker will run them.

You may always upload the homework as many times you want until the deadline. This will run all the tests for you and display the result.

Upload the homework

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.

Readme

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.

Homework Archive

To upload your homework, please follow the following:

  1. Create a zip (not rar, ace, 7zip or anything else) archive containing:
    • your main file
    • your javascript files (*.js)
    • the package.json file
    • the Readme file
  2. sign in with vmchecker
  3. select the Automates et Langages Formelles (FILS) course
  4. select 4. Semantic
  5. upload the archive

The archive needs to contain the files in its root, not in a folder. DO NOT archive a folder with those file, archive DIRECTLY those files.

DO NOT include node_modules.

When the archive is uploaded, vmchecker will run:

unzip archive.zip homework
cd homework
npm install
echo '{ "node":true, "esnext":true }' > .jshintrc
jshint *.js