Differences

This shows you the differences between two versions of the page.

Link to this comparison view

alf:laboratoare:07 [2018/04/15 13:42]
claudia.dumitru1803 [Exercises]
alf:laboratoare:07 [2021/04/17 19:29] (current)
diana.ghindaoanu [Exercises]
Line 1: Line 1:
-====== TP 7 - AST ======+====== TP 7 - Analyse Sémantique ​======
  
-===== AST =====+===== Table des symboles ​=====
  
-L'AST est un arbre représentant ​le format source. Il est indépendant ​de la forme de la grammaire. L'AST peut être une transformation ​de le parse tree ou peut être généré directement par l'analyseur.+La **table de symboles** représente ​un structure de données créée et traitée par le compilateur afin de stocker des informations sur l'apparition ​de certains éléments tels que le nom des variables, le nom des fonctions, les objets, les classes, les interfaces et d'​autres similaires. Essentiellement,​ la table de symbole est utilisée pour acccomplir la fonction d'**analyse** du compilateur.
  
-Dans l'ASTchaque règle ​de langue a un noeud.+Selon le langage utiliséle tableau ​de symbole peut servir aux suivants objectifs:
  
-Pour ce laboratoirevous pouvez définir le format ​de nœud AST comme vous le souhaitez. Un point de départ est le suivant:+   * stocker les noms de toutes les entités sous une forme structuréea un seul endroit 
 +   * vérifier si une variable a été déclarée avant l'​utilisation 
 +   * implémenter la vérification des types, en vérifiant si les attributions et les expressions du code source sont correctes ​de point de vue sémantique 
 +   * déterminer la portée (//scope//) d'un nom (résolution de la portée) 
 + 
 + 
 +Pour stocker les variables dans la table de symboles, on va utiliser un dictionnaire:
  
 <code javascript>​ <code javascript>​
-+interface VariableSymbolTable ​
-  type:"​node_type"​+    type: string
-  ...+    ​value:​ any
 } }
-</​code>​ 
  
-==== Exemple de AST ==== +let symbol_table:​ { [variable: string]: VariableSymbolTable } {};
-Pour le code suivant+
  
-<​code>​ +function ​addVariableToSymbolTable(variable: string, type: string
-2+3 +    symbol_table[variable] = { 
-var a of int +        type: type, 
-function ​fid (a of int+        value: undefined 
-5+6 +    }; 
-endoffunction+}
 </​code>​ </​code>​
  
-Nous pouvons décrire ​l'​AST ​suivant+Du TP passé on a appris comment créer et structurer ​l'AST. Le but est de retourner les 2 structures de données dans un meme objet: 
  
 <code javascript>​ <code javascript>​
-{ +let ast = visitor.visit(tree).toJSON();​ 
-  type: '​program',​ +let symbol_tree = 
-  elements: +    ​ast
-  [ +    ​symbol_table
-    ​{ +
-      type:'​expr',​ +
-      op: '​+',​ +
-      left: { +
-        type: '​int',​ +
-        value: 2 +
-      }, +
-      right: { +
-        type: '​int',​ +
-        value: 3 +
-      } +
-    ​}+
-    ​+
-      type: '​var',​ +
-      variables: [ +
-        { +
-          id: '​a',​ +
-          type: '​int'​ +
-        } +
-      ] +
-    }, +
-    { +
-      type: '​function_definition',​ +
-      id: '​fid',​ +
-      parameters:​[ +
-        { +
-          id:'​a',​ +
-          type:'​int'​ +
-        } +
-      ] +
-    } +
-  ]+
 } }
 +
 +console.log(JSON.stringify(symbol_tree,​ null, 4));
 </​code>​ </​code>​
  
-===== Grammaire pour le langage ===== 
  
-<code jison program.jison>​ +Pour générer le **parse tree** et la **table de symboles** on va utiliser la grammaire suivante:
-     +
-    ​+
  
-/* Jison example file */ +<code g4 Alf.g4> 
-  +grammar Alf;
-/* Tokens part */ +
-%lex +
-  +
-%% +
-  +
-/* RegEx */ +
-  +
-// add newline for Windows (\r\n) and Linux/​Unix/​Mac (\n) +
-\r?​\n return '​NEWLINE';​ +
-// \s includes \n space and tab, we need the NEWLINE token, so we put space and tab in white spacve +
-[ \t]                   /* skip whitespace */  +
-var               return '​VAR';​ +
-of               return '​OF';​ +
-int                     ​return '​INT';​ +
-float                     ​return '​FLOAT';​ +
-string ​                    ​return '​STRING';​ +
-function return '​FUNCTION';​ +
-endfunction ​                ​return '​END_FUNCTION';​ +
-[0-9]+("​."​[0-9]+)? ​ return '​NUMBER';​  +
-\"​[^\"​]*\"​ return '​STRING_VALUE';​ +
-// add the token for the variable +
-[A-Za-z][A-Za-z0-9]* ​ return '​IDENTIFIER';​ +
-'​='​  ​         return '​=';​ +
-"​-" ​                  ​return '​-';​ +
-"​+" ​                  ​return '​+';​ +
-"​*" ​                  ​return '​*';​ +
-"/" ​                  ​return '/';​ +
-"​(" ​                  ​return '​(';​ +
-"​)"​  ​                 return '​)';​ +
-','​  ​         return ','​;+
  
 +start               : (statement SEMICOLON NEWLINE*)* ​              #​multilineProg
 +                    | statement SEMICOLON ​                          #​singlelineProg ​
 +                    ;
  
-  +statement ​          declaration ​                                  #​declarationRule 
-/lex +                    | expression ​                                   #​expressionRule 
-  +                    | list_declaration ​                             #listRule 
-/* Grammar part, for this lab */ +                    | function_declaration ​                         #​functionRule 
-  +                    | attribution ​                                  #​attributionRule 
-// when it is ambiguous, derive the left part +                    ;
-%left '​+'​ '​-'​ +
-// * and / have higher priority +
-%left '​*'​ '/'​  +
-  +
-%{ +
-// function for grammar rule +
-function rule (rule_name, items) +
-+
-  return { +
-    rulerule_name, +
-    ​items:​ items +
-  }; +
-} +
-  +
-// function for token +
-function token (token_name,​ value) +
-+
-  return { +
-    token: token_name,​ +
-    value: value +
-  }; +
-}+
  
 +declaration ​        : type VARIABLE EQ expression ​                  #​variableDeclaration
 +                    | type VARIABLE EQ function_call ​               #​variableFunctionCall
 +                    ;
  
-%} +type                : INT                                           #typeInt 
-  +                    | FLOAT                                         #typeFloat 
-%%  +                    | STRING ​                                       #​typeString 
-  +                    ;
-start: expressions {  +
- $$ = rule ('​start',​ [$1]); +
- return $$;  +
- // AST +
- // return { +
- // ​   ​type: '​program',​ +
- // ​   elements: $1 +
- // } +
-            }; +
-             +
-expressions:​ statement NEWLINE expressions { +
- $$ = rule ('​statement',​ [$1, token ('​NEWLINE',​ $2), $3]); +
- //​ AST  +
- //​ $3.splice (0, 0, $1); // add the expression to the array produced by expressions ($3) +
- //​ $$ = $3; +
-+
- | statement NEWLINE { +
- $$ = rule ('​statement',​ [$1, token ('​NEWLINE',​ $2)]); +
- // AST +
- // $$ = [$1]; // an array with one element +
-+
- | statement { +
- $$ = rule ('​statement',​ [$1]); +
- // AST +
- // $$ = [$1]; // an array with one element +
- }; +
-  +
-statement: ​ expr  { +
-                    $$ = rule ('​statement',​ [$1]); +
-                +
-            | variable { +
-                        $$ = rule ('​statement',​ [$1]); +
-                    } +
-            | assign { +
-                        $$ = rule ('​statement',​ [$1]); +
-                    } +
-            | function { +
-            $$ = rule ('​function',​ [$1]); +
-            } +
- | function_run { +
-            $$ = rule ('​function_run',​ [$1]); +
-            }; +
-             +
-  +
-expr:​ '​('​ expr '​)'​ { +
- $$ = rule ('​expr',​ [token ('​(',​ $1), $2, token ('​)',​ $3)]); +
-+
-   | expr '​+'​ expr {  +
- $$ = rule ('​expr',​ [$1, token ('​+',​ $2), $3]); +
-+
-      | expr '​-'​ expr { +
-    $$ = rule ('​expr',​ [$1, token ('​-',​ $2), $3]); +
-      } +
-      | expr '​*'​ expr {  +
-    $$ = rule ('​expr',​ [$1, token ('​*',​ $2), $3]); +
-+
-      | expr '/'​ expr { +
-    $$ = rule ('​expr',​ [$1, token ('/',​ $2), $3]); +
-      } +
-      | NUMBER {  +
-   // $1 is string so we store its float value +
-   $$ = token ('​NUMBER',​ parseFloat ($1)); +
-   } +
-   | IDENTIFIER { +
- // store the variable +
-   $$ = token ('​IDENTIFIER',​ $1); +
-+
-    | STRING_VALUE { +
- // store the variable +
- // get the value of the string without the quotes +
-   $$ = token ('​STRING_VALUE',​ $1.substring (1, $1.length-2));​ +
- }; +
-  +
-variable:​ VAR variables +
-+
- $$ = rule ('​variable',​ [token ('​VAR',​ $1), $2]); +
- }; +
-  +
-variables:​ IDENTIFIER ','​ variables ​   +
-+
- $$ = rule ('​variables',​  +
-            [ +
-               token ('​IDENTIFIER',​ $1),  +
-               token (',',​ ','​),​  +
-               $3 +
-            ] +
-           ); +
-  +
-+
- | IDENTIFIER  +
-+
- $$ = token ('​IDENTIFIER',​ $1); +
-  +
-+
- | IDENTIFIER OF type ','​ variables ​   +
-+
- $$ = rule ('​variables',​  +
-            [ +
-               token ('​IDENTIFIER',​ $1),  +
-               token ('​OF',​ '​of'​),​ +
-               $3, +
-               token (',',​ ','​),​  +
-               $5 +
-            ] +
-           ); +
-  +
-+
- | IDENTIFIER OF type +
-+
- $$ = rule ('​variables',​  +
-               [ +
-                  token ('​IDENTIFIER',​ $1),  +
-                  token ('​OF',​ '​of'​),​ +
-                  $3 +
-               ] +
-              ); +
-     +
- }; +
-  +
-type  ​INT  +
-            { +
-                $$ = token ('​INT',​ '​int'​);​ +
-            } +
-        ​| FLOAT +
-            { +
-                $$ = token ('​FLOAT',​ '​float'​);​ +
-            } +
-        ​| STRING +
-            { +
-                $$ = token ('​STRING',​ '​string'​); +
-            }; +
-  +
-assign: IDENTIFIER '​='​ expr +
-            { +
-                $$ = rule ('​assign',​  +
-            [ +
-               token ('​IDENTIFIER',​ $1),  +
-               token ('​=',​ '​='​),​  +
-               $3 +
-            ] +
-           ); +
-  +
-            }; +
-            ​+
  
 +value               : INT_NUMBER ​                                   #valueInt
 +                    | FLOAT_NUMBER ​                                 #valueFloat
 +                    | STRING_TEXT ​                                  #​valueString
 +                    | VARIABLE ​                                     #​valueVariable
 +                    ;
  
-functionFUNCTION IDENTIFIER '​('​ parameters '​)'​ NEWLINE expressions END_FUNCTION {$$ rule ('​function',​ [token('​FUNCTION',​ $1), token('​IDENTIFIER',​ $2), token('​(',​ $3), $4, token('​)',​ $5), token('​NEWLINE',​ $6), $7, token('​END_FUNCTION',​ $8)]);};+expression ​         ​left=expression op=MUL right=expression ​      #​expressionMultiply 
 +                    | left=expression op=DIV right=expression ​      #​expressionDivision ​                   
 +                    | left=expression op=REM right=expression ​      #​expressionRem  
 +                    | left=expression op=ADD right=expression ​      #​expressionAddition 
 +                    | left=expression op=SUB right=expression ​      #​expressionSubtraction 
 +                    | LP expression RP                              #​expressionParanthesis 
 +                    | value                                         #​expressionValue 
 +                    ​;
  
-parametersIDENTIFIER OF type ',' ​parameters +attribution ​        VARIABLE EQ expression ​                       #​variableAttribution 
- { +                    ; 
- $$ = rule ('parameters'[$1, token ('OF''of'), $3, token (',', $4), $5])+ 
- } +list_declaration ​   : LIST VARIABLE EQ LSP values RSP               #​listDeclaration 
- | IDENTIFIER OF type +                    ; 
- { + 
- $$ = rule ('parameters'[$1, token ('OF''of')$3])+values ​             : (value COMMA)* ​                               #​listValues 
- +                    ; 
- | + 
- $$ = token ('EMPTY'''​);​ +function_declaration:​ FUNCTION VARIABLE LP (parameter COMMA*)* RP LB (statement SEMICOLON)* return_function RB    #​functionContent 
- };+                    ; 
 + 
 +parameter ​          : declaration ​                                  #​functionParameter 
 +                    ; 
 + 
 +return_function ​    : RETURN statement SEMICOLON ​                   #​returnStatement 
 +                    | RETURN SEMICOLON ​                             #​emptyReturn 
 +                    ; 
 + 
 +function_call ​      : VARIABLE LP (value COMMA*)* RP                #​functionCall 
 +                    ; 
 + 
 + 
 +WS                  :   (' ')       -> skip; 
 +NEWLINE ​            : ​  ​([\r\n]+) ​  -> skip; 
 +FUNCTION ​           :   '​function';​ 
 +VARIABLE ​           :   ('_'[a-zA-Z0-9]+);​ 
 +ADD                 : ​  '+'
 +SUB                 : ​  '-'
 +MUL                 : ​  '*'; 
 +DIV                 : ​  '/';​ 
 +REM                 : ​  '​%';​ 
 +INT                 : ​  '​int';​ 
 +FLOAT               : ​  '​float';​ 
 +STRING ​             :   '​string';​ 
 +LIST                :   '​list';​ 
 +LP                  :   '​('
 +RP                  :   '​)';​ 
 +EQ                  :   '​=';​ 
 +SEMICOLON ​          : ​  ';';​ 
 +LSP                 : ​  '​['​
 +RSP                 : ​  ']'
 +COMMA               : ​  ','
 +LB                  :   '​{'; 
 +RB                  :   '}'
 +RETURN ​             :   'return'
 +INT_NUMBER ​         :   ​([0-9]+); 
 +FLOAT_NUMBER ​       :   ​([0-9]+'​.'​[0-9]+);​ 
 +STRING_TEXT ​        : ​  ​('"'​~["​]+'"'​|'​\''​~['​]+'​\''​);
  
-function_run:​ IDENTIFIER '​('​ parameters_run '​)'​ { $$ = rule ('​function_run',​ [token ('​IDENTIFIER',​ $1), token ('​(',​ $2), $3, token ('​)',​ $4)]); 
- }; 
-  
-parameters_run:​ expr ','​ parameters_run 
- { 
- $$ = rule ('​parameters_run',​ [$1, token (',',​ $2), $3]); 
- } 
- | expr 
- { 
- $$ = rule ('​parameters_run',​ [$1]); 
- } 
- | { 
- $$ = token ('​EMPTY',​ ''​);​ 
- }; 
 </​code>​ </​code>​
  
-Le javascript+Pour pouvoir visiter tous les noeuds et générer les 2 structures de données, on va utiliser comme support les méthodes suivantes:
  
-<code javascript ​main.js+<code javascript ​index.ts
-"use strict"​+import { CharStreams,​ CodePointCharStream,​ CommonTokenStream,​ Token } from '​antlr4ts'​
-  +import ​{ AlfLexer } from './​AlfLexer.js'; 
-// import ​fs for reading  +import ​{ AlfParser, ExpressionAdditionContext,​ ExpressionDivisionContext,​ ExpressionMultiplyContext,​ ExpressionParanthesisContext,​ ExpressionRemContext,​ ExpressionSubtractionContext,​ MultilineProgContext,​ SinglelineProgContext,​ TypeFloatContext,​ TypeIntContext,​ TypeStringContext,​ ValueFloatContext,​ ValueIntContext,​ ValueStringContext,​ VariableDeclarationContext,​ ExpressionValueContext,​ ListDeclarationContext,​ ListValuesContext,​ ValueVariableContext,​ FunctionContentContext,​ FunctionParameterContext,​ VariableAttributionContext,​ FunctionCallContext,​ VariableFunctionCallContext } from './AlfParser.js'
-var fs = require ('fs')+import { AlfListener } from './​AlfListener.js'​
-  +import { AlfVisitor } from './AlfVisitor.js'
-// import ​the generated Parser +import * as fs from '​fs';​ 
-var parser = require ('./program.js').parser+import { ParseTree } from '​antlr4ts/​tree/​ParseTree';​ 
-  +import { AbstractParseTreeVisitor } from '​antlr4ts/​tree/​AbstractParseTreeVisitor';
-var str = fs.readFileSync (process.argv[2], ​'UTF-8');+
  
-// add a text to the parser +let input: string = fs.readFileSync('​./ex1.txt'​).toString();​ 
-try +let inputStream:​ CodePointCharStream = CharStreams.fromString(input);​ 
-{ +let lexer: AlfLexer = new AlfLexer(inputStream);​ 
-        // run the parser ​using a string, why are the values printed upside down? +let tokenStream:​ CommonTokenStream = new CommonTokenStream(lexer);​ 
- var info = parser.parse (str); +let parser: AlfParser = new AlfParser(tokenStream);​ 
- console.log ​('​AST'​); + 
- console.log ​(JSON.stringify (infonull, 4));+let tree = parser.start(); 
 + 
 +abstract class ASTNode { 
 +    constructor() { }
 +    ​public toJSON(): any { 
 +        return { 
 +            ​...thisid: this.constructor.name 
 +        }; 
 +    }
 } }
-catch (e) + 
-+class StatementsNode extends ASTNode ​
-        // display the error message and data +    ​constructor(public readonly statements: ASTNode[], public readonly ​line: number{ 
-// console.log ​('You have an error at line '​+(e.hash.line+1)+' at position '​+e.hash.loc.first_column);​ +        super(); 
-// console.log ​(e.message); +    ​
-    ​console.log ​(e);+ 
 +
 +class DeclarationNode extends ASTNode { 
 +    constructor(public readonly variable_type:​ string, public readonly variable: string, public readonly op: string, public readonly value: Expression | ValueNode | FunctionCallNode,​ public readonly line: number) { 
 +        super(); 
 +    }
 } }
-</​code>​ 
  
-Exemple de program+class ValueNode extends ASTNode { 
 +    constructor(public readonly value: number | string, public readonly line: number, public readonly type: string) { 
 +        super(); 
 +    } 
 +
 +class TypeNode extends ASTNode { 
 +    constructor(public readonly type_name: string, public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class Expression extends ASTNode { 
 +    constructor(public readonly op: string, public readonly left: Expression, public readonly right: Expression, public readonly line: number, public readonly type: string) { 
 +        super(); 
 +    } 
 +
 +class ListNode extends ASTNode { 
 +    constructor(public readonly type: string, public readonly name: string, public readonly values: ListValuesNode,​ public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class ListValuesNode extends ASTNode { 
 +    constructor(public readonly values: ValueNode[],​ public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class AttributionNode extends ASTNode { 
 +    constructor(public readonly variable: string, public readonly value: Expression, public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class FunctionNode extends ASTNode { 
 +    constructor(public readonly function_name:​ string, public readonly parameters: ParameterNode[],​ public readonly instructions:​ StatementsNode,​ public readonly return_node:​ ReturnNode, public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class ParameterNode extends ASTNode { 
 +    constructor(public readonly type: string, public readonly value: string | number, public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class ReturnNode extends ASTNode { 
 +    constructor(public readonly statement: ASTNode, public readonly line: number) { 
 +        super(); 
 +    } 
 +
 +class FunctionCallNode extends ASTNode { 
 +    constructor(public readonly function_name:​ string, public readonly parameters: ValueNode[],​ public readonly line: number) { 
 +        super(); 
 +    } 
 +}
  
-<​code>​ +/* TODO 1: Declare Symbol Table type and initialize object */
-var a of int +
-a=10 +
-function f () +
-var s of int +
-endfunction+
  
-</code>+let symbol_table = {}; 
 +function addVariableToSymbolTable(variable:​ string, type: string) { 
 +    ​/* symbol_table[variable] = { 
 +        type: type, 
 +        value: undefined 
 +    }; */ 
 +}
  
 +/* TODO 2: Check if a variable was already defined in the Symbol Table */
 +function isVariableDefined(variable:​ string) {
 +    ​
 +}
  
-===== Exercises ===== +/** TODO 3: Check if the types of the value nodes of an expression'​s operands are matching 
-<​note>​ +  *         The only operation allowed between strings is addition 
-Utilisez la même source, écrivez une fonction pour toutes ces actions. Écrivez les erreurs sur l'​écran. +*/ 
-</note> +function checkTypes(left: ValueNode, right: ValueNode, op: string{ 
-  - Ajouter des numéros de ligne à le parse tree (indice: yylineno) (**2p**) +     
-  ​- Modifiez la grammaire de l'​exemple pour générer un AST pour les expressions. (**3p**) +}
-  - Modifiez la grammaire de l'​exemple afin de générer un AST pour tout le program. ​(**5p**+
-  - **Bonus** Vérifiez que toutes les variables utilisées sont définies. (**1p**)+
  
-==== Solutions ====+/** TODO 4: Get expression final type 
 + * If both operants have the same type, the expression will receive their type 
 + * If one of the operands is string in the addition expression, the expression will receive the type '​string'​ 
 + * If one of the operands is float, the expression will receive the type '​float'​ 
 + * Add a new parameter to the Expression class, type, which will be the expression final type 
 + */
  
-[[https://​github.com/​alexandruradovici/​alf2018/​tree/​master/​TP/​TP7|Solutions]]+function getType(leftValueNode, right: ValueNode, op: string) { 
 +     
 +}
  
 +/** TODO 5: Add the function parameters to the Symbol Table
 + ​* ​ Each entry will have the function name as key and an object with the parameters list as value
 + ​* ​ The function will also store the parameters as variables in the symbol table. This action is not necessary
 + */
  
 +function addFunctionToSymbolTable(function_name:​ string, parameters: ParameterNode[]) {
 +    ​
 +}
 +class MyAlfVisitor extends AbstractParseTreeVisitor<​ASTNode>​ implements AlfVisitor<​ASTNode>​ {
 +    defaultResult() {
 +        return new StatementsNode([],​ 0);
 +    }
 +    visitMultilineProg(ctx:​ MultilineProgContext):​ StatementsNode {
 +        let statements = [];
 +        for (let i = 0; i < ctx.statement().length;​ i++)
 +            statements[i] = this.visit(ctx.statement(i));​
 +        if (statements) {
 +            return new StatementsNode(statements,​ 1);
 +        } else {
 +            throw new Error();
 +        }
 +    }
 +    visitSinglelineProg(ctx:​ SinglelineProgContext):​ ASTNode {
 +        return new StatementsNode([this.visit(ctx.statement())],​ 1);
 +    }
 +    visitVariableDeclaration(ctx:​ VariableDeclarationContext):​ DeclarationNode {
 +        /* TODO 1 & 2 */
 +        return new DeclarationNode(
 +            (this.visit(ctx.type()) as TypeNode).type_name,​
 +            ctx.VARIABLE().text,​
 +            ctx.EQ().text,​
 +            this.visit(ctx.expression()) as Expression,
 +            ctx.VARIABLE().symbol.line
 +        );
 +    }
 +    visitValueInt(ctx:​ ValueIntContext):​ ValueNode {
 +        return new ValueNode(
 +            parseInt(ctx.INT_NUMBER().text),​
 +            ctx.INT_NUMBER().symbol.line,​
 +            '​int'​
 +        );
 +    }
 +    visitValueVariable(ctx:​ ValueVariableContext):​ ValueNode {
 +        /* TODO 1 & 2 */
 +        return new ValueNode(
 +            ctx.VARIABLE().text,​
 +            ctx.VARIABLE().symbol.line,​
 +            '​variable'​
 +        );
 +    }
 +    visitValueFloat(ctx:​ ValueFloatContext):​ ValueNode {
 +        return new ValueNode(
 +            parseFloat(ctx.FLOAT_NUMBER().text),​
 +            ctx.FLOAT_NUMBER().symbol.line,​
 +            '​float'​
 +        );
 +    }
 +    visitValueString(ctx:​ ValueStringContext):​ ValueNode {
 +        return new ValueNode(
 +            ctx.STRING_TEXT().text,​
 +            ctx.STRING_TEXT().symbol.line,​
 +            '​string'​
 +        );
 +    }
 +    visitTypeInt(ctx:​ TypeIntContext):​ TypeNode {
 +        return new TypeNode(
 +            ctx.INT().text,​
 +            ctx.INT().symbol.line
 +        )
 +    }
 +    visitTypeString(ctx:​ TypeStringContext):​ TypeNode {
 +        return new TypeNode(
 +            ctx.STRING().text,​
 +            ctx.STRING().symbol.line
 +        )
 +    }
 +    visitTypeFloat(ctx:​ TypeFloatContext):​ TypeNode {
 +        return new TypeNode(
 +            ctx.FLOAT().text,​
 +            ctx.FLOAT().symbol.line
 +        )
 +    }
 +    visitExpressionMultiply(ctx:​ ExpressionMultiplyContext):​ Expression {
 +        const left = this.visit(ctx.expression(0));​
 +        const right = this.visit(ctx.expression(1));​
 +        const op = ctx._op;
  
 +        /** TODO 3: Check the type for each operand Value Node 
 +         ​* ​ If the types are not matching, throw ERROR: The types are not corresponding
 +        */
 +        if (op.text) {
 +            /* TODO 4: Add expression final type */
 +            let type = '';​
 +            return new Expression(op.text,​ left as Expression, right as Expression, ctx._op.line,​ type);
 +        } else throw new Error();
 +    }
 +    visitExpressionDivision(ctx:​ ExpressionDivisionContext):​ Expression {
 +        const left = this.visit(ctx.expression(0));​
 +        const right = this.visit(ctx.expression(1));​
 +        const op = ctx._op;
 +
 +        /** TODO 3: Check the type for each operand Value Node 
 +         ​* ​ If the types are not matching, throw ERROR: The types are not corresponding
 +        */
 +
 +         if (op.text) {
 +            /* TODO 4: Add expression final type */
 +            let type = '';​
 +            return new Expression(op.text,​ left as Expression, right as Expression, ctx._op.line,​ type);
 +        } else throw new Error();
 +    }
 +    visitExpressionRem(ctx:​ ExpressionRemContext):​ Expression {
 +        const left = this.visit(ctx.expression(0));​
 +        const right = this.visit(ctx.expression(1));​
 +        const op = ctx._op;
 +
 +        /** TODO 3: Check the type for each operand Value Node 
 +         ​* ​ If the types are not matching, throw ERROR: The types are not corresponding
 +        */
 +
 +         if (op.text) {
 +            /* TODO 4: Add expression final type */
 +            let type = '';​
 +            return new Expression(op.text,​ left as Expression, right as Expression, ctx._op.line,​ type);
 +        } else throw new Error();
 +    }
 +    visitExpressionAddition(ctx:​ ExpressionAdditionContext):​ Expression {
 +        const left = this.visit(ctx.expression(0));​
 +        const right = this.visit(ctx.expression(1));​
 +        const op = ctx._op;
 +
 +        /** TODO 3: Check the type for each operand Value Node 
 +         ​* ​ If the types are not matching, throw ERROR: The types are not corresponding
 +        */
 +
 +         if (op.text) {
 +            /* TODO 4: Add expression final type */
 +            let type = '';​
 +            return new Expression(op.text,​ left as Expression, right as Expression, ctx._op.line,​ type);
 +        } else throw new Error();
 +    }
 +    visitExpressionSubtraction(ctx:​ ExpressionSubtractionContext):​ Expression {
 +        const left = this.visit(ctx.expression(0));​
 +        const right = this.visit(ctx.expression(1));​
 +        const op = ctx._op;
 +
 +        /** TODO 3: Check the type for each operand Value Node 
 +         ​* ​ If the types are not matching, throw ERROR: The types are not corresponding
 +        */
 +
 +         if (op.text) {
 +            /* TODO 4: Add expression final type */
 +            let type = '';​
 +            return new Expression(op.text,​ left as Expression, right as Expression, ctx._op.line,​ type);
 +        } else throw new Error();
 +    }
 +    visitExpressionParanthesis(ctx:​ ExpressionParanthesisContext) {
 +        return this.visit(ctx.expression());​
 +    }
 +    visitExpressionValue(ctx:​ ExpressionValueContext):​ ValueNode {
 +        let value = this.visit(ctx.value());​
 +        if (value !== undefined) {
 +            return new ValueNode((this.visit(ctx.value()) as ValueNode).value,​ ctx.value()._start.line,​ (this.visit(ctx.value()) as ValueNode).type);​
 +        } else throw new Error();
 +    }
 +    visitListDeclaration(ctx:​ ListDeclarationContext):​ ListNode {
 +        return new ListNode(
 +            '​list',​
 +            ctx.VARIABLE().text,​
 +            this.visit(ctx.values()) as ListValuesNode,​
 +            ctx.values().start.line
 +        );
 +    }
 +    visitListValues(ctx:​ ListValuesContext):​ ListValuesNode {
 +        let values: ValueNode[] = [];
 +        for (let i = 0; i < ctx.value().length;​ i++) {
 +            let node = (this.visit(ctx.value(i)) as ValueNode);
 +            values[i] = new ValueNode(node.value,​ node.line, node.type);
 +        }
 +        if (values) {
 +            return new ListValuesNode(values,​ values[0].line);​
 +        } else {
 +            throw new Error();
 +        }
 +    }
 +    visitVariableAttribution(ctx:​ VariableAttributionContext):​ AttributionNode {
 +        /* TODO 1 & 2*/
 +        ​
 +        /* TODO 5: Set the type of the variable in the Symbol Tables as being the final type of the expression */
 +        return new AttributionNode(
 +            ctx.VARIABLE().text,​
 +            this.visit(ctx.expression()) as Expression,
 +            ctx.VARIABLE().symbol.line
 +        );
 +    }
 +    visitFunctionContent(ctx:​ FunctionContentContext):​ FunctionNode {
 +        let parameters = [];
 +        for (let i = 0; i < ctx.parameter().length;​ i++) {
 +            let node = (this.visit(ctx.parameter(i)) as ParameterNode);​
 +            parameters[i] = new ParameterNode(node.type,​ node.value, node.line);
 +        }
 +        let instructions = [];
 +        for (let i = 0; i < ctx.statement().length;​ i++) {
 +            instructions[i] = this.visit(ctx.statement(i));​
 +        }
 +        /** TODO 5 */
 +
 +        return new FunctionNode(
 +            ctx.VARIABLE().text,​
 +            parameters,
 +            new StatementsNode(instructions,​ ctx.FUNCTION().symbol.line),​
 +            new ReturnNode(this.visit(ctx.return_function()),​ ctx.return_function().start.line),​
 +            ctx.FUNCTION().symbol.line
 +        );
 +    }
 +    visitVariableFunctionCall(ctx:​ VariableFunctionCallContext):​ DeclarationNode {
 +        /* TODO 1 & 2 */
 +        return new DeclarationNode(
 +            (this.visit(ctx.type()) as TypeNode).type_name,​
 +            ctx.VARIABLE().text,​
 +            ctx.EQ().text,​
 +            this.visit(ctx.function_call()) as FunctionCallNode,​
 +            ctx.VARIABLE().symbol.line
 +        );
 +    }
 +    visitFunctionCall(ctx:​ FunctionCallContext):​ FunctionCallNode {
 +        let parameters = [];
 +        for (let i = 0; i < ctx.value().length;​ i++) {
 +            let node = (this.visit(ctx.value(i)) as ValueNode);
 +            parameters[i] = new ValueNode(node.value,​ node.line, node.type);
 +        }
 +        return new FunctionCallNode(
 +            ctx.VARIABLE().text,​
 +            parameters,
 +            ctx.VARIABLE().symbol.line
 +        );
 +    }
 +}
 +
 +
 +const visitor = new MyAlfVisitor();​
 +
 +let ast = visitor.visit(tree).toJSON();​
 +
 +let symbol_tree = {
 +    ast,
 +    symbol_table
 +}
 +
 +console.log(JSON.stringify(symbol_tree,​ null, 4));
 +</​code>​
 +
 +
 +===== Exercises =====
 +  - Téléchargez [[https://​github.com/​UPB-FILS-ALF/​TP/​tree/​main/​TP7|la structure]] du TP. En suivant les lignes marquées par TODO 1, ajoutez les variables et leur type au tableau des symboles. Testez avec le fichier ''​ex1.txt''​ (**2.5p**).
 +  - Si une variable est définie plusieurs fois, retournez sur l'​écran une erreur et arretez le programme. Suivez les lignes marquées par TODO 2 et puis testez avec le ficher ''​ex3.txt''​ (**2p**)
 +  - Pour chaque type d'​expression,​ vérifiez le type de chaque élément (int, float ou string). Si l'​opérateur est une variable, vérifiez son type en utilisant le tableau des symboles. Retournez une erreur et arretez l'​exécution du programme si vous ne pouvez pas calculer la valeur de l'​expression (par exemple, toute opération entre les string et les nombres, sauf la somme). (**Hint**: Vous pouvez définir une fonction supplémentaire qui fait toutes les validations et seulement l'​appeler pour chaque regle). Suivez les lignes avec TODO 3 et testez avec ''​ex3.txt''​. A la fin, modifiez le contenu du fichier ''​ex3.txt''​ pour tester votre programme pour l'​expression **123 - "​alf";​**. (**3p**). ​
 +  - Pour les variables qui n'ont pas recu un type au moment de la déclaration,​ déterminez le type lorsque la variable obtient une valeur (regle assign). Vous devrez déterminer le type de chaque expression en tenant compte du type de chaque opérande. (**Hint**: Si l'un des opérandes est nombre réel/​string,​ le résultat sera réel/​string. Vous pouvez implémenter une fonction qui fait les vérifications et l'​appeler pour déterminer le type de chaque expression). Testez avec le fichier ''​ex4.txt''​. Suivez les lignes avec TODO 4. (**2.5p**). ​
 +  - **BONUS:** Ajoutez la définition de fonction dans la table des symboles, de facon similaire a l'​ajout d'une variable. Chaque parametre doit etre ajouté au tableau des symboles avec le type //​parameter//​. L'​entrée de la table de symboles recevra la fonction et la liste des paramètres de la fonction. Testez avec ''​ex5.txt''​. Suivez les lignes marquées par TODO 5. (**2p**)
  
  
alf/laboratoare/07.1523788968.txt.gz · Last modified: 2018/04/15 13:42 by claudia.dumitru1803
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0