Differences

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

Link to this comparison view

alf:laboratoare:08 [2020/04/05 17:50]
diana.ghindaoanu
alf:laboratoare:08 [2022/05/02 19:26] (current)
diana.ghindaoanu [Exercises]
Line 1: Line 1:
-====== TP 8 - Analyse Semantique ​====== +====== TP 8 - Génération de code ======
-===== Table de symboles ​=====+
  
-La table de symboles représente une structure de données où tous les identifiants trouvés lors de l'​analyse sont stockés. Il permet de vérifier les types, de stocker les valeurs et autres paramètres.+===== Three Address Code =====
  
-Nous utiliserons ​un dictionnaire javascript.+Dans le domaine informatique,​ le code de trois adresses (**three address code**) représente ​un code intermédiaire utilisé pour les compilateurs en tant que moyen d'​écrire des instructionsChaque instruction consiste en: 
 +  * maximum trois adresses (variable, numéro, étiquette, ...) 
 +  * opérateur 
 +  * résultat
  
-Nous ajoutons une autre fonction qui nous permet d'​ajouter une variable à la table des symboles. 
  
-<code javascript>​ +Comme il s'agit d'un code intermédiaireles opérands ne représentent pas d'​adresses de mémoire ou de registres, mais plutôt des adresses ​//​symboliques//​ qui seront ​ traduites plus tard.
-function addVariable (variable) +
-+
-  symbol_table[variable] = { +
-    type:'variable', +
-    value: undefined +
-  }; +
-+
-</code>+
  
-Nous avons maintenant le parse tree et la table des symboles. Nous devons les retourner tous les deux. La règle de départ renvoie maintenant un objet qui contient le parse tree et la table de symboles. 
  
-<​code ​javascript+=== Exemple === 
-{ +<​code>​ 
-  ast: $1, +/* Expression */ 
-  ​symbol_table:​ symbol_table +e = (a-2)+(a-5) 
-}+ 
 +/* Three Address Code */ 
 +t1 = a - 2 
 +t2 = a - 5 
 +t3 = t1 + t2 
 +e = t3
 </​code>​ </​code>​
  
-<code jison alf.l> +===== Expression Parser =====
-  +
-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
 +                    | function_call ​                                #​functionCallRule
 +                    ;
  
-"​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+<​code ​javascript index.js
-%left '​+'​ '​-'​ +import { ASTNode } from "​./​index";​ 
-%left '​*' ​'/'​  +import symbol_tree from './index'; 
-  +import ​Expression, ValueNode, AttributionNode,​ FunctionCallNode } from './index';
-%{ +
-// function for grammar rule +
-var symbol_table = {};+
  
-function addVariable (variable, type) +var variable_id ​0;
-+
-  symbol_table[variable] ​+
-    type: type, +
-    value: undefined +
-  }; +
-}+
  
-function ​isDefined ​(variable)+let results: string[] = []; 
 +function ​nextVar ​()
 { {
-   // add here the code to verify if a variable is already in the symbol table+    return '​var'​ + variable_id++;​
 } }
    
-%} 
    
-%% +function writeThreeAddressCode (node) 
 +
 +    if (node.id === '​StatementsNode'​) 
 +    { 
 +        for (var statement of node.statements) 
 +        { 
 +            writeThreeAddressCode(statement);​ 
 +        } 
 +    } 
 +    else 
 +    if (node instanceof FunctionCallNode) 
 +    { 
 +        /**TODO: 
 +         * generate the three address code for each parameter of the node.parameters array 
 +         * write on the screen the three address code for each parameter 
 +         * node.result will be nextVar() 
 +         * write on the screen the three address code for function call 
 +         */ 
 +    } 
 +    else 
 +    if (node instanceof ValueNode) 
 +    { 
 +        // the result for a number is the number itself 
 +        node.result = node.value;​ 
 +    } 
 +    else 
 +    if (node instanceof AttributionNode) 
 +    { 
 +        /** TODO:  
 +         * generate the three address code for node.value 
 +         * write on the screen the three address code for an attribution*/​ 
 +    } 
 +    else 
 +    if (node instanceof Expression) 
 +    { 
 +        if (node.left !== undefined && node.right !== undefined) 
 +        { 
 +            writeThreeAddressCode (node.left);​ 
 +            writeThreeAddressCode (node.right);​ 
 + 
 +            // node.left.result is the result of node.left 
 +            // node.right.result is the result of node.right 
 +             
 +            /** TODO:  
 +             * node.result will be nextVar() 
 +             * write on the screen the three address code based on result, left result, right result and operator*/​ 
 +        } 
 +    } 
 +}
    
-start +var ast = parser.parse (str); 
-: expressions { +console.log (JSON.stringify(ast, null4))
- return { ast: { + 
- type: '​program'​, +writeThreeAddressCode(ast);
- elements:​ $1, +
- line: yylineno + 1 +
-                                             }, +
-                                             ​symbol_table:​ symbol_table +
- }+
-             } +
-;+
    
-expressions 
-: expressions NEWLINE statement { 
- $1.push($3);​ // add the expression to the array produced by expressions ($1) 
- $$ = $1; 
- } 
-| statement { 
- $$ = []; 
- $$.push($1);​ // an array with one element 
- } 
-; 
-  
-statement 
-: expr 
-| variable 
-| assign 
-| function 
-| function_run 
-; 
-  
-  
-expr 
-: '​('​ expr '​)'​ { 
- $$ = { 
- type:​ '​expr',​ 
- value:​ $2, 
- line:​ yylineno + 1 
- }; 
- } 
-| expr '​+'​ expr { 
- $$ = { 
- type:​ '​expr',​ 
- op: $2, 
- left:​ $1, 
- right:​ $3, 
- line:​ yylineno + 1 
- }; 
- } 
-| expr '​-'​ expr { 
- $$ = { 
- type:​ '​expr',​ 
- op: $2, 
- left:​ $1, 
- right:​ $3, 
- line:​ yylineno + 1 
- }; 
- } 
-| expr '​*'​ expr { ​ 
- $$ = { 
- type:​ '​expr',​ 
- op: $2, 
- left:​ $1, 
- right:​ $3, 
- line:​ yylineno + 1 
- }; 
- } 
-| expr '/'​ expr { 
- $$ = { 
- type:​ '​expr',​ 
- op: $2, 
- left:​ $1, 
- right:​ $3, 
- line:​ yylineno + 1 
- }; 
- } 
-| NUMBER {  
- $$ = { 
- type:​ '​int',​ 
- value:​ $1, 
- line:​ yylineno + 1 
- }; 
- } 
-| IDENTIFIER { 
- if(!isDefined($1)) { 
- return 'ERROR at line ' + (yylineno + 1) + ': ' + $1 + ' is not defined';​ 
- } 
-  
- $$ = { 
- type:​ '​variable',​ 
- value:​ $1, 
- line:​ yylineno + 1 
- }; 
- } 
-| STRING_VALUE { 
- $$ = { 
- type:​ '​string',​ 
- value:​ $1, 
- line:​ yylineno + 1 
- }; 
- } 
-; 
-  
-variable: VAR variables { 
- $$ = { 
- type:​ '​var',​ 
- variables:​ $2, 
- line:​ yylineno + 1 
- }; 
- } 
-; 
-  
-variables 
-: variables ','​ IDENTIFIER { 
- //​ add the variable to the symbol table 
-  
- $1.push({ 
- id:​ $3, 
- line:​ yylineno + 1 
- });​ 
- $$ = $1; 
- } 
-| IDENTIFIER { 
- //​ add the variable to the symbol table 
-  
- $$ = []; 
- $$.push({ 
- id:​ $1, 
- line:​ yylineno + 1 
- })  
- } 
-| variables ','​ IDENTIFIER OF type { 
- //​ add the variable to the symbol table 
-  
- $1.push({ 
- id:​ $3, 
- type:​ $5, 
- line:​ yylineno + 1 
- });​ 
- $$ = $1; 
- } 
-| IDENTIFIER OF type { 
- //​ add the variable to the symbol table 
-  
- $$ = []; 
- $$.push({ 
- id:​ $1, 
- type:​ $3, 
- line:​ yylineno + 1 
- });​  
- } 
-; 
-  
-type 
-: INT  
-| FLOAT 
-| STRING 
-; 
-  
-assign 
-: IDENTIFIER '​='​ expr { 
- if(!isDefined($1)) { 
- return 'ERROR at line ' + (yylineno + 1) + ': ' + $1 + ' is not defined';​ 
- } 
-  
- $$ = { 
- type:​ '​assign',​ 
- to: { 
- id:​ $1, 
- line:​ yylineno + 1 
- }, 
- from:​ $3, 
- line:​ yylineno + 1 
- }; 
- } 
-; 
-  
-function 
-: FUNCTION IDENTIFIER '​('​ parameters '​)'​ NEWLINE expressions NEWLINE END_FUNCTION { 
- $$ = { 
- type:​ '​function_declaration',​ 
- id:​ $2, 
- parameters:​ $4, 
- expressions:​ $7, 
- line:​ yylineno + 1 
- };​  
- } 
-; 
-  
-parameters 
-: parameters ','​ IDENTIFIER OF type { 
- $1.push({ 
- id:​ $3, 
- type:​ $5, 
- line:​ yylineno + 1 
- });​ 
- $$ = $1; 
- } 
-| IDENTIFIER OF type { 
- $$ = []; 
- $$.push({ 
- id:​ $1, 
- type:​ $3, 
- line:​ yylineno + 1 
- });​ 
- } 
-| { 
- $$ = []; 
- } 
-; 
-  
-function_run 
-: IDENTIFIER '​('​ parameters_run '​)'​ { 
- $$ = { 
- type:​ '​function_run',​ 
- id:​ $1, 
- parameters:​ $3, 
- line:​ yylineno + 1 
- };​ 
- } 
-; 
-  
-parameters_run 
-: parameters_run ','​ expr  { 
- $1.push($3);​ 
- $$ = $1; 
- } 
-| expr { 
- $$ = []; 
- $$.push($1);​ 
- } 
-| { 
- $$ = []; 
- } 
-; 
  
 </​code>​ </​code>​
  
-<code javascript index.js>​ 
-"use strict";​ 
  
-var parser ​require ('​./​alf.js'​).parser;​ +===== Exercises =====
-var fs require ('​fs'​);​+
  
-try { +  - Dans un fichier **ex1.txt** écrivez le //three address code// pour les expressions suivantes (**1p**) 
-    var data = fs.readFileSync('​ex1.txt').toString(); +    * (4+2)/5-3 
-    ​console.log(JSON.stringify(parser.parse (data), null, 2));+    ​(4+2)/5-3 
 +    * e = (a-2)+(a-5) 
 +  - Dans un fichier **ex2.txt** écrivez le //three address code// pour le programme suivant ​(**1p**<code javascript>​ 
 +if (a > 0) 
 +
 +  result = '​positive'​;
 } }
-catch (e) +else 
-    ​console.log (e.message);+
 +  ​result = '​negative'​;
 } }
 </​code>​ </​code>​
 +  - Dans un fichier **ex3.txt** écrivez le //three address code// pour le programme suivant (**1p**) <code javascript>​
 +function double (nr)
 +{
 +    return nr*2;
 +}
 + 
 +double (7/2);
 +</​code>​
 +  - Téléchargez [[https://​github.com/​UPB-FILS-ALF/​TP/​tree/​main/​TP8 | la structure]] du tp. Pour les exercices suivants vous devez modifier seulement le contenu du fichier et **three_address_code.ts**. Exécutez le parser du laboratoire et écrivez un programme qui génere le three address code pour le noeud //​expression//​ et vérifiez avec le fichier //ex4.txt// (**Indice**:​ Pour nommer les variables temporaires,​ vous pouvez prendre un compteur global que vous incrémentez chaque fois que vous avez besoin d'une autre variable). (**2p**)
 +  - Écrivez un programme qui écrit le three address code pour le noeud //​AttributionNode//​ et vérifiez la corectitude avec le fichier //​ex5.txt//​(**2p**)
 +  - Écrivez un programme qui écrit le three address code pour le noeud //​FunctionCall//​ et testez avec le fichier //​ex6.txt//​(**2p**)
 +  - Au lieu d'​écrire sur l'​écran,​ ajoutez le three address code dans un tableau. A la fin, affichez le tableau sur l'​écran. (**1p**)
 +  - **BONUS: **Pour résoudre cet exercice, on vous recommande de créer un nouveau fichier, ''​tac_bonus.ts'',​ pour pouvoir modifier la structure sans supprimer les exercices précedents. Ajoutez le type à chaque argument dans le tableau. Les types sont: nombre, identifier, string, temp (une valeur temporaire). Pour chaque valeur temporaire, ajoutez la ligne où elle est assignée dans le three address code. Modifiez la structure du fichier index.js de facon que, si vous testez avec le fichier **ex8.txt**,​ vous obteniez le resultat suivant.(**2p**)
 +<spoiler AST><​code javascript>​
 +{
 +    "​ast":​ {
 +        "​statements":​ [
 +            {
 +                "​variable":​ "​_s",​
 +                "​value":​ {
 +                    "​op":​ "​-",​
 +                    "​left":​ {
 +                        "​op":​ "​*",​
 +                        "​left":​ {
 +                            "​value":​ 1,
 +                            "​line":​ 1,
 +                            "​type":​ "​int",​
 +                            "​id":​ "​ValueNode"​
 +                        },
 +                        "​right":​ {
 +                            "​value":​ 4,
 +                            "​line":​ 1,
 +                            "​type":​ "​int",​
 +                            "​id":​ "​ValueNode"​
 +                        },
 +                        "​line":​ 1,
 +                        "​type":​ "​int",​
 +                        "​id":​ "​Expression"​
 +                    },
 +                    "​right":​ {
 +                        "​value":​ 2,
 +                        "​line":​ 1,
 +                        "​type":​ "​int",​
 +                        "​id":​ "​ValueNode"​
 +                    },
 +                    "​line":​ 1,
 +                    "​type":​ "​int",​
 +                    "​id":​ "​Expression"​
 +                },
 +                "​line":​ 1,
 +                "​id":​ "​AttributionNode"​
 +            },
 +            {
 +                "​function_name":​ "​_sum",​
 +                "​parameters":​ [
 +                    {
 +                        "​value":​ 1,
 +                        "​line":​ 2,
 +                        "​type":​ "​int",​
 +                        "​id":​ "​ValueNode"​
 +                    },
 +                    {
 +                        "​value":​ "​_s",​
 +                        "​line":​ 2,
 +                        "​type":​ "​int",​
 +                        "​id":​ "​ValueNode"​
 +                    }
 +                ],
 +                "​line":​ 2,
 +                "​id":​ "​FunctionCallNode"​
 +            }
 +        ],
 +        "​line":​ 1,
 +        "​id":​ "​StatementsNode"​
 +    },
 +    "​symbol_table":​ {
 +        "​_s":​ {
 +            "​type":​ "​int"​
 +        }
 +    }
 +}
 +</​code>​
 +</​spoiler>​
 +<spoiler Three Address Code><​code javascript>​
 +[
 +  {
 +    result: { type: '​temp',​ value: '​var0',​ line: 1 },
 +    arg1: { type: '​int',​ value: '​1'​ },
 +    arg2: { type: '​int',​ value: '​4'​ },
 +    op: '​*'​
 +  },
 +  {
 +    result: { type: '​temp',​ value: '​var1',​ line: 1 },
 +    arg1: { type: '​temp',​ value: '​var0',​ line: 1 },
 +    arg2: { type: '​int',​ value: '​2'​ },
 +    op: '​-'​
 +  },
 +  {
 +    result: null,
 +    arg1: '​_s',​
 +    arg2: { type: '​temp',​ value: '​var1',​ line: 1 },
 +    op: '​='​
 +  },
 +  {
 +    result: null,
 +    arg1: { type: '​int',​ value: '​1'​ },
 +    arg2: null,
 +    op: '​param'​
 +  },
 +  {
 +    result: null,
 +    arg1: { type: '​int',​ value: '​_s'​ },
 +    arg2: null,
 +    op: '​param'​
 +  },
 +  {
 +    result: { type: '​temp',​ value: '​var2',​ line: 2 },
 +    arg1: '​_sum',​
 +    arg2: 2,
 +    op: '​call'​
 +  }
 +]
 +</​code>​
 +</​spoiler>​
 +
 +<​hidden>​
 +===== Solutions =====
 +
 +[[https://​github.com/​upb-fils/​alf/​tree/​master/​TP/​TP9|Solutions]]
 +</​hidden>​
 +
 +
 +
  
-===== Exercises ===== 
-  - Téléchargez [[https://​github.com/​UPB-FILS/​alf/​tree/​master/​TP/​TP8|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''​ (**2p**). 
-  - 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 ''​ex2.txt''​ (**2p**) 
-  - Pour chaque type d'​expression,​ vérifiez le type de chaque élément (int, float ou string). Si l'​operateur 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). Testez avec ''​ex3.txt''​. Suivez les lignes avec TODO 3 (**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). Testez avec le fichier''​ex4.txt''​. Suivez les lignes avec TODO 4. (**1p**). ​ 
-  - 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**) 
  
-==== Solutions ==== 
-[[https://​github.com/​UPB-FILS/​alf/​tree/​master/​TP/​TP8|Solutions]] 
alf/laboratoare/08.1586098205.txt.gz · Last modified: 2020/04/05 17:50 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