Differences

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

Link to this comparison view

alf:laboratoare:07 [2020/03/29 19:24]
diana.ghindaoanu
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 ​du 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 comme corespondant 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 alf.l> +Pour générer le **parse tree** et la **table de symboles** on va utiliser la grammaire suivante:
-Newline ​              ​\r?​\n +
-Ws                    [ \t] +
-Number ​               [0-9]+("​."​[0-9]+)?​ +
-String_value ​         \"​[^\"​]*\" +
-Identifier ​           [A-Za-z][A-Za-z0-9]*+
  
 +<code g4 Alf.g4>
 +grammar Alf;
  
-%%+start               : (statement SEMICOLON NEWLINE*)* ​              #​multilineProg 
 +                    | statement SEMICOLON ​                          #​singlelineProg  
 +                    ;
  
 +statement ​          : declaration ​                                  #​declarationRule
 +                    | expression ​                                   #​expressionRule
 +                    | list_declaration ​                             #listRule
 +                    | function_declaration ​                         #​functionRule
 +                    | attribution ​                                  #​attributionRule
 +                    ;
  
-"​var" ​                ​{ return ​'VAR'; ​} +declaration ​        : type VARIABLE EQ expression ​                  #​variableDeclaration 
-"​of" ​                 { return ​'OF'; ​} +                    | type VARIABLE EQ function_call ​               #​variableFunctionCall 
-"​int" ​                ​{ return ​'INT'; ​} +                    ; 
-"​float" ​              { return ​'FLOAT'; ​} + 
-"​string" ​             { return ​'STRING'; ​} +type                : INT                                           #​typeInt 
-"​function" ​           { return ​'FUNCTION'; ​} +                    | FLOAT                                         #​typeFloat 
-"​endfunction" ​        { return ​'END_FUNCTION'; ​} +                    | STRING ​                                       #​typeString 
-"​="​  ​     { return ​'='; ​} +                    ; 
-"​-" ​                  { return ​'-'; ​} + 
-"​+" ​                  { return ​'+'; ​} +value               : INT_NUMBER ​                                   #valueInt 
-"​*" ​                  { return ​'*'; ​} +                    | FLOAT_NUMBER ​                                 #​valueFloat 
-"/" ​                  { return ​'/'; ​} +                    | STRING_TEXT ​                                  #​valueString 
-"​(" ​                  { return ​'LP'; ​} +                    | VARIABLE ​                                     #​valueVariable 
-"​)"​  ​                 { return ​'RP'; ​} +                    ; 
-','       { return ​','; ​} + 
-{Ws}                  ​{ ​/*skip whitespace*/​ } +expression ​         : left=expression op=MUL right=expression ​      #​expressionMultiply 
-{Newline            { return '​NEWLINE'; ​} +                    | left=expression op=DIV right=expression ​      #​expressionDivision ​                   
-{Number} ​             return ​'​NUMBER'; ​} +                    | left=expression op=REM right=expression ​      #​expressionRem  
-{String_value} ​       { return ​'STRING_VALUE'; ​} +                    | left=expression op=ADD right=expression ​      #​expressionAddition 
-{Identifier} ​         { return ​'IDENTIFIER'; ​}  ​+                    | left=expression op=SUB right=expression ​      #​expressionSubtraction 
 +                    | LP expression RP                              #​expressionParanthesis 
 +                    | value                                         #​expressionValue 
 +                    ; 
 + 
 +attribution ​        : VARIABLE EQ expression ​                       #​variableAttribution 
 +                    ; 
 + 
 +list_declaration ​   : LIST VARIABLE EQ LSP values RSP               #​listDeclaration 
 +                    ; 
 + 
 +values ​             : (value COMMA)* ​                               #​listValues 
 +                    ; 
 + 
 +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 ​        : ​  ('"'~["​]+'"'​|'​\''​~['​]+'​\''​);
  
 </​code>​ </​code>​
  
-<​code ​jison alf.y+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:​ 
-%left '+' '-+ 
-// * and / have higher priority +<​code ​javascript index.ts
-%left '*' '/'​  +import { CharStreams,​ CodePointCharStream,​ CommonTokenStream,​ Token } from 'antlr4ts'
-  +import { AlfLexer } from './​AlfLexer.js'; 
-%+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';​ 
-// function for grammar rule +import { AlfListener } from './​AlfListener.js'
-function rule (rule_name, items+import { AlfVisitor } from './AlfVisitor.js'; 
-+import * as fs from '​fs';​ 
-  ​return ​+import ​ParseTree } from '​antlr4ts/​tree/​ParseTree';​ 
-    ​rulerule_name, +import { AbstractParseTreeVisitor } from '​antlr4ts/tree/AbstractParseTreeVisitor';​ 
-    itemsitems + 
-  };+let input: string = fs.readFileSync('​./​ex1.txt'​).toString();​ 
 +let inputStream:​ CodePointCharStream = CharStreams.fromString(input);​ 
 +let lexer: AlfLexer = new AlfLexer(inputStream);​ 
 +let tokenStream:​ CommonTokenStream = new CommonTokenStream(lexer);​ 
 +let parser: AlfParser = new AlfParser(tokenStream);​ 
 + 
 +let tree = parser.start();​ 
 + 
 +abstract class ASTNode ​
 +    ​constructor() ​}; 
 +    ​public toJSON()any { 
 +        ​return { 
 +            ...this, idthis.constructor.name 
 +        }; 
 +    }
 } }
-  + 
-// function for token +class StatementsNode extends ASTNode { 
-function token (token_namevalue) +    ​constructor(public readonly statements: ASTNode[]public readonly line: number) { 
-+        ​super();​ 
-  ​return ​+    } 
-    ​tokentoken_name, + 
-    value: value +
-  };+class DeclarationNode extends ASTNode ​
 +    ​constructor(public readonly variable_typestringpublic readonly variablestring, public readonly op: string, public readonly ​value: Expression | ValueNode | FunctionCallNode,​ public readonly line: number) { 
 +        ​super(); 
 +    }
 } }
-  
-  
-%} 
-  
-%%  
-  
-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:​ '​LP'​ expr '​RP'​ { 
- $$ = 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 
-            ] 
-           ); 
-  
-            }; 
-  
-  
-  
-function: FUNCTION IDENTIFIER '​LP'​ parameters '​RP'​ 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)]);}; 
-  
-parameters: IDENTIFIER OF type ','​ parameters 
- { 
- $$ = rule ('​parameters',​ [$1, token ('​OF',​ '​of'​),​ $3, token (',',​ $4), $5]); 
- } 
- | IDENTIFIER OF type 
- { 
- $$ = rule ('​parameters',​ [$1, token ('​OF',​ '​of'​),​ $3]); 
- } 
- | { 
- $$ = token ('​EMPTY',​ ''​);​ 
- }; 
-  
-function_run:​ IDENTIFIER '​LP'​ parameters_run '​RP'​ { $$ = 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>​+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(); 
 +    } 
 +}
  
-Le javascript+/* TODO 1: Declare Symbol Table type and initialize object */
  
-<code javascript main.js>​ +let symbol_table = {}
-"use strict"​+function addVariableToSymbolTable(variable:​ string, type: string) { 
-  +    /* symbol_table[variable] ​{ 
-// import fs for reading  +        type: type, 
-var fs require ('​fs'​);​ +        ​value:​ undefined 
-  +    }; *
-// import the generated Parser +}
-var parser = require ('./program.js'​).parser;​ +
-  +
-var str = fs.readFileSync (process.argv[2],​ '​UTF-8'​);​+
  
-// add text to the parser +/* TODO 2: Check if variable was already defined in the Symbol Table *
-try +function isVariableDefined(variable: string{ 
-+    
-        ​// run the parser using a string, why are the values printed upside down? +
- var info = parser.parse ​(str); +
- console.log ('​AST'​);​ +
- console.log (JSON.stringify (info, null, 4));+
 } }
-catch (e) + 
-{ +/** TODO 3: Check if the types of the value nodes of an expression's operands are matching 
-        // display ​the error message and data +  *         The only operation allowed between strings is addition 
-// console.log ('You have an error at line '+(e.hash.line+1)+'​ at position '​+e.hash.loc.first_column);​ +*/ 
-// console.log ​(e.message); +function checkTypes(left: ValueNode, right: ValueNode, op: string{ 
-    ​console.log (e);+    ​
 } }
-</​code>​ 
  
-Exemple de program+/** 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 
 + */
  
-<​code>​ +function ​getType(left: ValueNode, right: ValueNode, op: string{ 
-var a of int +     
-a=10 +}
-function ​() +
-var s of int +
-endfunction+
  
-</code>+/** 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;
  
-===== Exercises ===== +        ​/** TODO 3: Check the type for each operand Value Node  
-<​note>​ +         *  If the types are not matchingthrow ERROR: The types are not corresponding 
-L'​exemple inclus dans la structure du tp génère le parse tree pour le langage du fichier ​//​script.alf//​. +        *
-Utilisez la même source pour tous les exercicesécrivez des fonctions pour toutes les actions et ajoutez-les dans le meme fichier .y. Écrivez les erreurs sur l'​écran. +        if (op.text) { 
-</note> +            ​/* TODO 4Add expression final type */ 
-  - Téléchargez/​clonez [[https://​github.com/UPB-FILS/​alf/​tree/​master/​TP/​TP7|la structure]] du tp. Ajoutez des numéros de ligne au parse tree (**Indice**: modifiez la fonction rule() de sorte qu'​elle accèpte comme paramètre yylineno pour chaque règle) (**2p**) +            let type = ''; 
-  - Modifiez la grammaire de l'exemple pour générer un AST pour les expressions. Suivez les explications marquées par TODO 2. Pour chaque règle correspondant a expression/​expression_string,​ on doit attribuer a la variable %%$$%% un objet avec les propriétés suivantes: type (nom de la règle), ​op (valeur de l'​opérateur), left (valeur du premier opérande), right (valeur du deuxième opérande). Pour chaque feuille%%$$%% recevra un objet contenant le type et la valeur du noeudAu moment de la génération de l'AST, il faut commenter l'​appel des fonctions ''​rule''​ et ''​token''​Pour tester la correctitude de votre grammaireparsez le contenu du fichier **ex2.txt**. ​(**3p**+            return new Expression(op.text, left as Expression, right as Expressionctx._op.linetype); 
-  - Modifiez la grammaire de l'​exemple afin de générer un AST pour tout le programParsez le contenu du fiechier **ex3.txt**. (**5p**+        } else throw new Error(); 
-  - **Bonus** Vérifiez que toutes les variables utilisées dans les expressions sont définies avant.Parsez le contenu du fichier **ex4.txt**. (**1p**)+    } 
 +    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
 +        */
  
-<​hidden>​ +         if (op.text) { 
-==== Solutions ====+            /* 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;
  
-[[https://​github.com/​UPB-FILS/​alf/​tree/​master/​TP/​TP7|Solutions]] +        /** TODO 3Check the type for each operand Value Node  
-</hidden>+         ​* ​ 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.1585499075.txt.gz · Last modified: 2020/03/29 19:24 by diana.ghindaoanu
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