This shows you the differences between two versions of the page.
alf:laboratoare:10 [2019/04/22 11:37] teodor.deaconu [Exercises] |
alf:laboratoare:10 [2021/05/16 21:26] (current) diana.ghindaoanu |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== TP 10 - Generation du code 2 ====== | + | ====== TP 10 - Assambleur ====== |
- | ===== Three Address Code ===== | + | Dans ce laboratoire, nous utiliserons le simulateur de langage d'assemblage [[https://schweigi.github.io/assembler-simulator/]]. Il simule un processeur avec les fonctionnalités suivantes: |
- | Le code de trois adresses est un moyen d'écrire des instructions. Chaque instruction consiste en: | + | * 4 Hz |
- | * maximum trois adresses (variables, numero, étiquette, ...) | + | * 4 registres à usage général A, B, C si D |
- | * operateur | + | * un registre pour l'instruction IP actuelle |
- | * resultat | + | * un registre pour le sommet de la pile SP |
+ | * 256 B RAM | ||
+ | * 24 B mémoire vidéo (derniers octets de RAM) | ||
- | ===== Expression Parser ===== | + | La description de simulateur este disponible [[https://www.mschweighauser.com/make-your-own-assembler-simulator-in-javascript-part1/]]. |
- | <code jison alf.l> | + | ===== L'ensemble d'instructions ===== |
- | Newline \r?\n | + | |
- | Ws [ \t] | + | |
- | Number [0-9]+("."[0-9]+)? | + | |
- | String_value \"[^\"]*\" | + | |
- | Identifier [A-Za-z][A-Za-z0-9]* | + | |
+ | L'ensemble d'instructions représente les commandes qu'un processeur peut exécuter. Ce processeur connaît les instructions suivantes: | ||
+ | * mov - attribution de données | ||
+ | * add - addition | ||
+ | * sub - soustraction | ||
+ | * inc - incrémentation | ||
+ | * dec - decrémentation | ||
+ | * mul - multiplication | ||
+ | * div - division | ||
+ | * and - et sur les bits | ||
+ | * or - ou sur les bits | ||
+ | * xor - xor | ||
+ | * not - negation des bits | ||
+ | * shl - décaler vers la gauche (équivalent a la multiplication par 2) | ||
+ | * shr 0 siftare la dreapta (équivalent a la division par 2) | ||
+ | * cmp - comparaison | ||
+ | * jmp - saut | ||
+ | * j.. - saut (plusieurs informations) | ||
+ | * call - appel de fonction | ||
+ | * ret - retour de la fonction | ||
+ | * hlt - arrêt du processeur | ||
+ | * push - ajouter dans la pile | ||
+ | * pop - supprimer de la pile at ajouter dans un registre | ||
- | %% | ||
+ | L'ensemble d'instructions avec sa description est disponible sur le site Web du simulateur [[https://schweigi.github.io/assembler-simulator/instruction-set.html]]. | ||
- | "var" { return 'VAR'; } | ||
- | "of" { return 'OF'; } | ||
- | "int" { return 'INT'; } | ||
- | "float" { return 'FLOAT'; } | ||
- | "string" { return 'STRING'; } | ||
- | "function" { return 'FUNCTION'; } | ||
- | "endfunction" { return 'END_FUNCTION'; } | ||
- | "=" { return '='; } | ||
- | "-" { return '-'; } | ||
- | "+" { return '+'; } | ||
- | "*" { return '*'; } | ||
- | "/" { return '/'; } | ||
- | "(" { return 'LP'; } | ||
- | ")" { return 'RP'; } | ||
- | ',' { return ','; } | ||
- | {Ws} { /*skip whitespace*/ } | ||
- | {Newline} { return 'NEWLINE'; } | ||
- | {Number} { return 'NUMBER'; } | ||
- | {String_value} { return 'STRING_VALUE'; } | ||
- | {Identifier} { return 'IDENTIFIER'; } | ||
- | </code> | ||
- | <code jison alf.y> | + | ==== Exercises ==== |
- | %left '+' '-' | + | - Exécutez le programme initial. Changez le nom de la variable et essayez de comprendre comment écrire votre nom sur la sortie (**2p**) |
- | // * and / have higher priority | + | - Écrivez un programme qui place les nombres 0, 2, 4, 6 dans les registres A, B, C et D.(**1p**) |
- | %left '*' '/' | + | - Écrivez le code pour calculer le reste de la division de la valeur du registre A par la valeur du registre B. Retournez la valeur de l'oppération ''17%3''. Expliquez qu'est-ce qui se passe. (**1p**) |
- | + | - Écrivez un programme qui affiche 0 en sortie autant de fois que la valeur du registre C. Affichez dans la sortie 4 chiffres de 0. (**2p**) | |
- | %% | + | - Écrivez un programme qui comprend une fonction qui fait le //swap// entre deux variables. Envoyer les paramètres de fonction à l'aide des registres. Retournez le swap entre les registres A et B. (**2p**). |
- | + | - Écrivez un programme et une fonction qui calcule le reste de la division de deux variables. Envoyer les paramètres de fonction à l'aide de la pile. Verifiez pour ''7%3''. (**1.5p**). | |
- | start: expressions { | + | - Écrivez un programme et une fonction qui calcule la taille d'une chaîne stockée en tant que variable. Vous pouvez partir de l'exemple du premier programme. La fonction doit être rappelable de l'intérieur et vous devez retourner la dimension de la chaîne dans le registre B. (**2p**) |
- | $$ = | + | |
- | { | + | |
- | type:'script', | + | |
- | statements: $1 | + | |
- | }; | + | |
- | return $$; | + | |
- | }; | + | |
- | + | ||
- | expressions: statement NEWLINE expressions { | + | |
- | $3.splice (0, 0, $1); | + | |
- | $$ = $3; | + | |
- | } | + | |
- | | statement NEWLINE { | + | |
- | $$ = [$1]; | + | |
- | } | + | |
- | | statement { | + | |
- | $$ = [$1]; | + | |
- | }; | + | |
- | + | ||
- | statement: expr { | + | |
- | + | ||
- | } | + | |
- | | assign { | + | |
- | + | ||
- | } | + | |
- | | function_run { | + | |
- | + | ||
- | }; | + | |
- | + | ||
- | + | ||
- | expr: '(' expr ')' { | + | |
- | $$ = $2; | + | |
- | } | + | |
- | | expr '+' expr { | + | |
- | $$ = { | + | |
- | type: 'expr', | + | |
- | op: '+', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | expr '-' expr { | + | |
- | $$ = { | + | |
- | type: 'expr', | + | |
- | op: '-', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | expr '*' expr { | + | |
- | $$ = { | + | |
- | type: 'expr', | + | |
- | op: '*', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | expr '/' expr { | + | |
- | $$ = { | + | |
- | type: 'expr', | + | |
- | op: '/', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | IDENTIFIER | + | |
- | { | + | |
- | $$ = { | + | |
- | type: 'id', | + | |
- | value: $1 | + | |
- | }; | + | |
- | } | + | |
- | | NUMBER { | + | |
- | $$ = { | + | |
- | type: 'number', | + | |
- | value: parseFloat ($1) | + | |
- | }; | + | |
- | } | + | |
- | | STRING_VALUE { | + | |
- | $$ = { | + | |
- | type: 'string', | + | |
- | value: $1.substring (1, $1.length-2) | + | |
- | }; | + | |
- | }; | + | |
- | + | ||
- | assign: IDENTIFIER '=' expr | + | |
- | { | + | |
- | $$ = { | + | |
- | type: 'assign', | + | |
- | to: $1, | + | |
- | from: $3 | + | |
- | }; | + | |
- | } | + | |
- | | IDENTIFIER '=' function_run | + | |
- | { | + | |
- | $$ = { | + | |
- | type: 'assign', | + | |
- | to: $1, | + | |
- | from: $3 | + | |
- | }; | + | |
- | }; | + | |
- | + | ||
- | function_run: IDENTIFIER 'LP' parameters_run 'RP' { | + | |
- | $$ = { | + | |
- | type: 'function_run', | + | |
- | id: $1, | + | |
- | parameters: $3 | + | |
- | }; | + | |
- | }; | + | |
- | + | ||
- | parameters_run: expr ',' parameters_run | + | |
- | { | + | |
- | $3.splice (0, 0, $1); | + | |
- | $$ = $3; | + | |
- | } | + | |
- | | expr | + | |
- | { | + | |
- | $$ = [$1]; | + | |
- | } | + | |
- | | { | + | |
- | $$ = []; | + | |
- | }; | + | |
- | </code> | ||
- | <code javascript index.js> | ||
- | "use strict"; | ||
- | |||
- | // import fs for reading | ||
- | var fs = require ('fs'); | ||
- | |||
- | // import the generated Parser | ||
- | var parser = require ('./alf.js').parser; | ||
- | |||
- | var str = fs.readFileSync (process.argv[2], 'UTF-8'); | ||
- | + | <hidden> | |
- | function writeThreeAddressCode (node) | + | ==== Solutions ==== |
- | { | + | - **Bonus** Écrivez un programme et une fonction qui calcule la chaîne a (n) = a (n-1) * a (n-2), a (0) est 1 et a (1) est 2. (**2p**) |
- | if (node.type === 'script') | + | [[https://github.com/alexandruradovici/alf2018/tree/master/TP/TP11|Solutions]] |
- | { | + | </hidden> |
- | for (var statementIndex in node.statements) | + | |
- | { | + | |
- | writeThreeAddressCode(node.statements[statementIndex]); | + | |
- | } | + | |
- | } | + | |
- | else | + | |
- | if (node.type === 'expr') | + | |
- | { | + | |
- | if (node.left !== undefined && node.right !== undefined) | + | |
- | { | + | |
- | writeThreeAddressCode (node.left); | + | |
- | writeThreeAddressCode (node.right); | + | |
- | // node.left is the result of node.left | + | |
- | // node.right is the result of node.right | + | |
- | // write the three address code here | + | |
- | } | + | |
- | } | + | |
- | else | + | |
- | if (node.type === 'number') | + | |
- | { | + | |
- | // the result for a number is the number itself | + | |
- | console.log ('push '+node.value); | + | |
- | } | + | |
- | else | + | |
- | if (node.type === 'id') | + | |
- | { | + | |
- | + | ||
- | } | + | |
- | else | + | |
- | if (node.type === 'function_run') | + | |
- | { | + | |
- | + | ||
- | } | + | |
- | else | + | |
- | if (node.type === 'function') | + | |
- | { | + | |
- | + | ||
- | } | + | |
- | } | + | |
- | var ast = parser.parse (str); | ||
- | console.log (JSON.stringify(ast, null, 4)); | ||
- | writeThreeAddressCode(ast); | ||
- | |||
- | </code> | ||
- | |||
- | ===== Objectif ===== | ||
- | |||
- | Nous voulons transformer l'AST suivant en une liste de Three Address Code avec une pile. | ||
- | |||
- | ===== Exercises ===== | ||
- | |||
- | - Ecrivez le code de trois adresses avec une pile pour les expressions suivantes (**1p**) | ||
- | * 2+3*(5+6) | ||
- | * s = 2+3*(5+6) | ||
- | * e = (s+3)-(s+4) | ||
- | - Ecrivez le code de trois adresses avec une pile pour le programme suivant (**1p**) <code javascript> | ||
- | if (x < 0) | ||
- | { | ||
- | r = 'unde zero'; | ||
- | } | ||
- | else | ||
- | { | ||
- | r = 'above zero'; | ||
- | } | ||
- | </code> | ||
- | - Ecrivez le code de trois adresses avec une pile pour le programme suivant (**1p**) <code javascript> | ||
- | function square (x) | ||
- | { | ||
- | return x*x; | ||
- | } | ||
- | |||
- | square (5+6); | ||
- | </code> | ||
- | - Telechargez [[https://github.com/UPB-FILS/alf/tree/master/TP/TP10|la structure]] du TP.Exécutez le parser du laboratoire et écrivez un programme qui écrit le three address code pour les noeds //expr// (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) <spoiler AST><code javascript> | ||
- | { | ||
- | "type": "script", | ||
- | "statements": [ | ||
- | { | ||
- | "type": "expr", | ||
- | "op": "+", | ||
- | "left": { | ||
- | "type": "expr", | ||
- | "op": "+", | ||
- | "left": { | ||
- | "type": "expr", | ||
- | "op": "+", | ||
- | "left": { | ||
- | "type": "number", | ||
- | "value": 2 | ||
- | }, | ||
- | "right": { | ||
- | "type": "number", | ||
- | "value": 3 | ||
- | } | ||
- | }, | ||
- | "right": { | ||
- | "type": "number", | ||
- | "value": 5 | ||
- | } | ||
- | }, | ||
- | "right": { | ||
- | "type": "expr", | ||
- | "op": "*", | ||
- | "left": { | ||
- | "type": "id", | ||
- | "value": "a" | ||
- | }, | ||
- | "right": { | ||
- | "type": "number", | ||
- | "value": 5 | ||
- | } | ||
- | } | ||
- | }, | ||
- | { | ||
- | "type": "assign", | ||
- | "to": "a", | ||
- | "from": { | ||
- | "type": "function_run", | ||
- | "id": "print", | ||
- | "parameters": [ | ||
- | { | ||
- | "type": "expr", | ||
- | "op": "+", | ||
- | "left": { | ||
- | "type": "number", | ||
- | "value": 2 | ||
- | }, | ||
- | "right": { | ||
- | "type": "number", | ||
- | "value": 3 | ||
- | } | ||
- | }, | ||
- | { | ||
- | "type": "id", | ||
- | "value": "a" | ||
- | } | ||
- | ] | ||
- | } | ||
- | } | ||
- | ] | ||
- | } | ||
- | </code></spoiler>(**2p**) | ||
- | - Modifiez la grammaire pour que les appels de fonction puissent être à l'intérieur des expressions. (**1p**) | ||
- | - Ecrire un programme qui écrit le three address code avec une pile pour les noeds //assign// (**1p**) | ||
- | - Écrivez un programme qui écrit le three address code avec une pile pour les noeds //function_run// (**2p**) | ||
- | - Écrivez un programme qui écrit le three address code avec une pile pour les noeds //function//. Un paramètre est lu dans la fonction en utilisant l'instruction 'index' suivie de la position du paramètre. (**1p**) | ||
- | |||
- | |||
- | ===== Solutions ===== | ||
- | |||
- | [[https://github.com/alexandruradovici/alf2018/tree/master/TP/TP10|Solutions]] | ||