TP 8 - Génération de code

Three Address Code

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 instructions. Chaque instruction consiste en:

  • maximum trois adresses (variable, numéro, étiquette, …)
  • opérateur
  • résultat

Comme il s'agit d'un code intermédiaire, les 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.

Exemple

/* Expression */
e = (a-2)+(a-5)

/* Three Address Code */
t1 = a - 2
t2 = a - 5
t3 = t1 + t2
e = t3

Expression Parser

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
                    ;
 
declaration         : type VARIABLE EQ expression                   #variableDeclaration
                    | type VARIABLE EQ function_call                #variableFunctionCall
                    ;
 
type                : INT                                           #typeInt
                    | FLOAT                                         #typeFloat
                    | STRING                                        #typeString
                    ;
 
value               : INT_NUMBER                                    #valueInt
                    | FLOAT_NUMBER                                  #valueFloat
                    | STRING_TEXT                                   #valueString
                    | VARIABLE                                      #valueVariable
                    ;
 
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
                    ;
 
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         :   ('"'~["]+'"'|'\''~[']+'\'');
 
;
index.js
import { ASTNode } from "./index";
import symbol_tree from './index';
import { Expression, ValueNode, AttributionNode, FunctionCallNode } from './index';
 
var variable_id = 0;
 
let results: string[] = [];
function nextVar ()
{
    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*/
        }
    }
}
 
var ast = parser.parse (str);
console.log (JSON.stringify(ast, null, 4));
 
writeThreeAddressCode(ast);

Exercises

  1. Dans un fichier ex1.txt écrivez le three address code pour les expressions suivantes (1p)
    • (4+2)/5-3
    • (4+2)/5-3
    • e = (a-2)+(a-5)
  2. Dans un fichier ex2.txt écrivez le three address code pour le programme suivant (1p)
    if (a > 0)
    {
      result = 'positive';
    }
    else
    {
      result = 'negative';
    }
  3. Dans un fichier ex3.txt écrivez le three address code pour le programme suivant (1p)
    function double (nr)
    {
        return nr*2;
    }
     
    double (7/2);
  4. Téléchargez 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)
  5. Écrivez un programme qui écrit le three address code pour le noeud AttributionNode et vérifiez la corectitude avec le fichier ex5.txt(2p)
  6. Écrivez un programme qui écrit le three address code pour le noeud FunctionCall et testez avec le fichier ex6.txt(2p)
  7. 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)
  8. 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)

AST

AST

{
    "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"
        }
    }
}

Three Address Code

Three Address Code

[
  {
    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'
  }
]
alf/laboratoare/08.txt · Last modified: 2022/05/02 19:26 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