This shows you the differences between two versions of the page.
alf:teme:tema4_en [2019/04/29 13:19] teodor.deaconu |
alf:teme:tema4_en [2020/04/25 12:15] (current) alexandru.radovici |
||
---|---|---|---|
Line 14: | Line 14: | ||
===== What do you have to do ===== | ===== What do you have to do ===== | ||
- | The purpose of the homework is to write the semantic analysis, the intermediate language for the Alf language. | + | 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: | You will receive an AST from the parser that parses correctly a Alf language source and have to write: | ||
- the symbol table | - the symbol table | ||
- | - add to every AST node an attribute //symbol// with the context id and determine the types for the nodes that return (expression, value, id, element_of_array, element_of_struct elements, value_of_function) | + | - a new AST with the following modifications: |
+ | - the new AST is a list of function statements | ||
+ | - 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 | ||
+ | - the main program is called "script" | ||
+ | - all the other function definitions are moved from the old AST to the new AST | ||
+ | - 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;`. | ||
- the semantic error list | - the semantic error list | ||
+ | |||
<note> | <note> | ||
- | All the three requirements are verified and graded separately. Examples that produce no errors will receive erroor points only if the symbol table and the ast are correct. | + | 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. |
</note> | </note> | ||
Line 29: | Line 35: | ||
* the output file | * the output file | ||
<code bash> | <code bash> | ||
- | node main.js source.alf source.alf.json | + | node main.js source.alf.ast.json source.alf.json |
</code> | </code> | ||
Line 48: | Line 54: | ||
<code javascript> | <code javascript> | ||
{ | { | ||
- | symbol_table: [...], // the symbol_table | + | symbol_table: {...}, // the symbol_table |
- | ast: {...}, // the ast with the type for very node that returns a value | + | ast: [...], // the ast with the type for very node that returns a value |
- | error_list [] // the error list | + | errors [] // the error list |
} | } | ||
</code> | </code> | ||
Line 56: | Line 62: | ||
===== Symbol table ===== | ===== Symbol table ===== | ||
- | The symbol table is an array of context objects. | + | 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// - the context for the main script | ||
+ | * //function_sum// - the context generated by the `sum` function | ||
<code javascript> | <code javascript> | ||
- | [ | + | { |
- | // context object id 0 - the context of the main script | + | "script": { |
- | { | + | "type": "script", |
- | ... | + | "variables": {}, |
- | }, | + | "functions": { |
- | // context object id 1 - the context object of a function | + | "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": {} | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
- | While determining the symbol table, add to each AST node a parameter //symbol// with the value of the its context id. | + | |
+ | 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 ==== | ==== Context Object ==== | ||
Line 78: | Line 122: | ||
* the variable declared in that context | * the variable declared in that context | ||
* the function declared in that context | * the function declared in that context | ||
- | * the struct declared in that context | + | * the types (array, struct) declared in that context |
- | * the parent context id (position in the symbol_table array) | + | * the parent context name |
- | * the type of the context (module or message) | + | * the type of the context (`script`, `statements` or `function`) |
- | * the name of the function which context it is (unless this is not the module) | + | * the title of the function which context it is (if the context type is `function`) |
- | * the name of the struct which context it is (unless this is not the module) | + | |
- | * the type of the return value of the message which context it is (unless this is not the module) | + | |
<note> | <note> | ||
Line 89: | Line 131: | ||
* the main module | * the main module | ||
* a function definition | * a function definition | ||
- | * a struct | + | * a if definition |
+ | * a for definition | ||
+ | * a loop when and loop go definition | ||
</note> | </note> | ||
Line 99: | Line 143: | ||
"type": // type of the variable | "type": // type of the variable | ||
"line": // the line where the variable was declared | "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) | "value": // the expression that the variable initially has (optional, if the define was with an assignment) | ||
} | } | ||
}, | }, | ||
"functions": { // a dictionary of functions | "functions": { // a dictionary of functions | ||
- | "function_name": { | + | "function_title": { |
"type": // the return type of the function | "type": // the return type of the function | ||
"parameters": [] // the list of parameters the function takes (the parameters node from the AST) | "parameters": [] // the list of parameters the function takes (the parameters node from the AST) | ||
"line": // the line where the function was declared | "line": // the line where the function was declared | ||
- | "symbol": // the context object id that the function creates | ||
} | } | ||
Line 113: | Line 157: | ||
"types": { // a dictionary of types | "types": { // a dictionary of types | ||
"type": { | "type": { | ||
- | "type": // the type of the new type class or array | + | "type": // the type of the new type struct or array |
"line": // the line where the type was declared | "line": // the line where the type was declared | ||
// for array | // for array | ||
"elements_type": // the type of each array element | "elements_type": // the type of each array element | ||
- | "from": // the first index | + | "first": // the first index |
- | "to": // the last index | + | "length": // the number of elements in the array |
// for struct | // for struct | ||
- | "elements": [ // a list of array elements (the node form the AST) | + | "properties": [ // a list of array elements (the node form the AST) |
{ | { | ||
"type": | "type": | ||
- | "id": | + | "title": |
+ | "value": // the expression that the variable initially has (optional, if the define was with an assignment) | ||
"line": | "line": | ||
+ | "symbol_table": // the context title where the structure was defined | ||
}, | }, | ||
... | ... | ||
Line 130: | Line 176: | ||
} | } | ||
}, | }, | ||
- | "parent": 0, // the parent context position in the symbol_table (except of the main script that has no parent), usually 0, | + | "parent": // the parent context the symbol_table (except of the main script that has no parent) |
- | "type": // the type of the | + | "type": // the type of the context (script, function or statements) |
- | "function": // the function name if this is a function context | + | |
- | "struct": // the struct name if the context is in a function that is in a struct | + | |
- | "return_value": // the return type of the function if this is a function context | + | |
} | } | ||
</code> | </code> | ||
- | === Exemple === | + | |
+ | ==== Context names ==== | ||
+ | * ''script'' - script | ||
+ | * ''function'' - function_''title'' | ||
+ | * ''if_then'' - if_''line_where_the_if_then_was_defined'' | ||
+ | * ''loop_when'' - do_while_''line_where_the_loop_when_was_defined'' | ||
+ | * ''loop_go'' - while_''line_where_the_loop_go_was_defined'' | ||
+ | |||
+ | ===== 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. | ||
<code javascript> | <code javascript> | ||
- | { | + | [ |
- | "variables": { | + | // the script |
- | "s": { | + | "script": { |
- | "type": "school", | + | statements: [ |
- | "line": 8 | + | ... |
- | } | + | ] |
- | }, | + | }, |
- | "functions": {}, | + | // a function |
- | "types": { | + | "function_title": { |
- | "school": { | + | statements: [ |
- | "type": "class", | + | ... |
- | "line": 6, | + | ] |
- | "elements": [ | + | } |
- | { | + | ] |
- | "type": "int", | + | |
- | "id": "type", | + | |
- | "line": 5 | + | |
- | }, | + | |
- | { | + | |
- | "type": "logic", | + | |
- | "id": "private", | + | |
- | "line": 4 | + | |
- | }, | + | |
- | { | + | |
- | "type": "string", | + | |
- | "id": "name", | + | |
- | "line": 3 | + | |
- | } | + | |
- | ] | + | |
- | } | + | |
- | } | + | |
- | } | + | |
</code> | </code> | ||
+ | |||
+ | ==== 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 [[https://github.com/UPB-FILS/alf/blob/master/Devoir/semantic/verify/semantic/4_struct/definition_with_values_and_variable.alf|example]] in the repository. | ||
===== Verify Types in the AST ===== | ===== Verify Types in the AST ===== | ||
Line 177: | Line 225: | ||
==== Expression return type ==== | ==== Expression return type ==== | ||
For each of the following nodes, determine the return type | For each of the following nodes, determine the return type | ||
- | * exp | + | * expr |
* value | * value | ||
* identifier | * identifier | ||
* return | * return | ||
- | * element | + | * element_of_vector |
* property | * property | ||
- | * dispatch | + | * function_call |
+ | |||
+ | 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. | Set type the by adding a parameter type in the node. | ||
Line 189: | Line 239: | ||
<note> | <note> | ||
When searching for a variable, the algorithm is: | When searching for a variable, the algorithm is: | ||
- | * if it is a function context, search the local variables | + | * search the local context |
- | * if not found, search the parameters | + | * if not found, search the parent context |
- | * if not found, search the struct context local variables | + | |
- | + | ||
- | * if it is the module context, search the global variables | + | |
</note> | </note> | ||
=== Example === | === Example === | ||
<code javascript> | <code javascript> | ||
- | { | + | { |
- | "id": "exp", | + | "id": "expr", |
- | "op": "=", | + | "op": "+", |
- | "left": { | + | "left": { |
- | "id": "exp", | + | "id": "value", |
- | "op": "mod", | + | "type": "int", |
- | "left": { | + | "value": 2, |
- | "id": "id", | + | "line": 3, |
- | "value": "n", | + | "symbol_table": "script" |
- | "line": 8, | + | }, |
- | "symbol": 1, | + | "right": { |
- | "type": "int" | + | "id": "value", |
- | }, | + | "type": "int", |
- | "right": { | + | "value": 3, |
- | "id": "id", | + | "line": 3, |
- | "value": "i", | + | "symbol_table": "script" |
- | "line": 8, | + | }, |
- | "symbol": 1, | + | "line": 3, |
- | "type": "int" | + | "symbol_table": "script", |
- | }, | + | "type": "int" |
- | "line": 8, | + | |
- | "symbol": 1, | + | |
- | "t": "int" | + | |
- | }, | + | |
- | "right": { | + | |
- | "id": "value", | + | |
- | "type": "int", | + | |
- | "value": 0, | + | |
- | "line": 8, | + | |
- | "symbol": 1 | + | |
- | }, | + | |
- | "line": 8, | + | |
- | "symbol": 1, | + | |
- | "type": "logic" | + | |
} | } | ||
</code> | </code> | ||
Line 239: | Line 272: | ||
* attributions work | * attributions work | ||
* expressions can be calculated | * expressions can be calculated | ||
- | * the if/loop/loop when aslongas expression is a logic value | + | * the if/loop-go/loop-when expression is a logic value |
* the for variable is a number | * the for variable is a number | ||
* that variables are defined before being used | * that variables are defined before being used | ||
Line 245: | Line 278: | ||
* array indexes are numbers | * array indexes are numbers | ||
* struct properties exist | * struct properties exist | ||
- | * the variable for element_of_array is an array | + | * the variable for element_of_vector is an array |
* the variable for a property is a struct | * the variable for a property is a struct | ||
* variables are not redefined | * variables are not redefined | ||
Line 265: | Line 298: | ||
{ | { | ||
type: // string with the error type | type: // string with the error type | ||
- | line: // the line number in the source (starting at 1) | + | elements: { |
- | elements: // items for the error, each type of error has different items | + | // items for the error, each type of error has different items |
+ | line: // the line where the error is | ||
+ | }, | ||
text: // the error text message | text: // the error text message | ||
} | } | ||
</code> | </code> | ||
+ | |||
==== Error type ==== | ==== Error type ==== | ||
Line 280: | Line 316: | ||
<code javascript> | <code javascript> | ||
{ | { | ||
- | variable: // variable name | + | variable: // variable name, |
} | } | ||
</code> | </code> | ||
Line 304: | Line 340: | ||
</code> | </code> | ||
- | === STRUCT_ELEMENT_ALREADY_DEFINED === | + | === STRUCT_PROPERTY_ALREADY_DEFINED === |
The error occurs when a struct element definition is repeated. | The error occurs when a struct element definition is repeated. | ||
== Elements == | == Elements == | ||
{ | { | ||
- | struct: // struct type name | + | type: // struct type title |
- | element: // element name | + | title: // property title |
} | } | ||
Line 320: | Line 356: | ||
{ | { | ||
array: // array type name | array: // array type name | ||
- | low_index: // the lower index value | + | length: // the negative length |
- | high_index: // the higher index value | + | |
} | } | ||
</code> | </code> | ||
Line 334: | Line 369: | ||
variable: // the name of the variable with the unresolved type | variable: // the name of the variable with the unresolved type | ||
} | } | ||
- | // struct element | + | // struct property |
{ | { | ||
struct: // name of struct type | struct: // name of struct type | ||
- | element: // name of struct element with the unresolved type | + | property: // name of struct element with the unresolved type |
} | } | ||
</code> | </code> | ||
- | === UNDEFINED_MESSAGE === | + | === UNDEFINED_FUNCTION === |
- | The error occurs when a function call is made to a function that is not defned. | + | The error occurs when a function call is made to a function that is not defined. |
== Elements == | == Elements == | ||
<code javascript> | <code javascript> | ||
{ | { | ||
- | id: // message name | + | title: // function title |
} | } | ||
</code> | </code> | ||
Line 358: | Line 393: | ||
<code javascript> | <code javascript> | ||
{ | { | ||
- | variable: // variable name | + | variable: // variable title |
} | } | ||
</code> | </code> | ||
Line 367: | Line 402: | ||
== Elements == | == Elements == | ||
{ | { | ||
- | variable: // the variable that has that type | + | value: // the type that is undefined |
- | type: // the type that is undefined | + | |
} | } | ||
Line 377: | Line 411: | ||
<code javascript> | <code javascript> | ||
{ | { | ||
- | struct: // struct name | + | type: // struct title |
- | property: // element name | + | title: // property title |
} | } | ||
</code> | </code> | ||
Line 402: | Line 436: | ||
</code> | </code> | ||
=== ARRAY_INDEX_TYPE === | === ARRAY_INDEX_TYPE === | ||
- | The error occurs when an index for an array is not a number or symbol | + | The error occurs when an index for an array is not an int |
== Elements == | == Elements == | ||
<code javascript> | <code javascript> | ||
{ | { | ||
- | array: // array type | + | type: // the index type |
- | index: // supplied index type | + | |
} | } | ||
</code> | </code> | ||
Line 438: | Line 471: | ||
op: | op: | ||
} | } | ||
- | // if, while or repeat - aslongas | + | // if, loop-go, loop-when |
{ | { | ||
- | expression: // expression type | + | exp: // expression type |
op: // if, while, repeat | op: // if, while, repeat | ||
} | } | ||
- | // for | + | // attribution (including for variable) |
{ | { | ||
- | expression: // expression type | + | to: // to type, |
- | op: "for" | + | op: "<-", |
- | element: // variable, from, to or step | + | from: // from type |
} | } | ||
- | // value_of_function | + | // return |
{ | { | ||
- | op: "value" | + | op: "return" |
to: // return type | to: // return type | ||
from: // provided type | from: // provided type | ||
} | } | ||
- | // is | + | // iteration (for i in exp go) |
{ | { | ||
- | op: "is" | + | op: "iteration" |
- | to: // to type | + | value: // the exp type |
- | from: // from type | + | |
} | } | ||
- | // struct element type is undefined | + | // typecast |
{ | { | ||
- | struct: // struct type, | + | op: "typecast", |
- | element: // name of struct element | + | to: // to type, |
+ | from: // from type | ||
} | } | ||
- | // variable type is undefined | ||
- | { | ||
- | variable: // name of the variable | ||
- | } | ||
- | </code> | ||
=== LEXICAL === | === LEXICAL === |