This shows you the differences between two versions of the page.
alf:laboratoare:10 [2020/04/22 22:20] diana.ghindaoanu [Exercises] |
alf:laboratoare:10 [2021/05/16 21:26] (current) diana.ghindaoanu |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== TP 10 - Génération de 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 |
- | * opérateur | + | * un registre pour l'instruction IP actuelle |
- | * résultat | + | * 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 ===== |
- | Ws [ \t] | + | |
- | Number [0-9]+("."[0-9]+)? | + | |
- | String_value \"[^\"]*\" | + | |
- | Identifier [A-Za-z][A-Za-z0-9]* | + | |
- | Newline \r?\n | + | |
- | + | ||
- | %% | + | |
- | + | ||
- | + | ||
- | "def" { return 'DEF'; } | + | |
- | "int" { return 'INT'; } | + | |
- | "float" { return 'FLOAT'; } | + | |
- | "string" { return 'STRING'; } | + | |
- | "function" { return 'FUNCTION'; } | + | |
- | "end" { return 'END'; } | + | |
- | "=" { 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> | + | L'ensemble d'instructions représente les commandes qu'un processeur peut exécuter. Ce processeur connaît les instructions suivantes: |
- | %left '+' '-' | + | * mov - attribution de données |
- | // * and / have higher priority | + | * add - addition |
- | %left '*' '/' | + | * sub - soustraction |
- | + | * inc - incrémentation | |
- | %% | + | * dec - decrémentation |
- | + | * mul - multiplication | |
- | %left '+' '-' | + | * div - division |
- | // * and / have higher priority | + | * and - et sur les bits |
- | %left '*' '/' | + | * or - ou sur les bits |
- | + | * xor - xor | |
- | %% | + | * not - negation des bits |
- | + | * shl - décaler vers la gauche (équivalent a la multiplication par 2) | |
- | start: statements { | + | * shr 0 siftare la dreapta (équivalent a la division par 2) |
- | $$ = { | + | * cmp - comparaison |
- | type:'module', | + | * jmp - saut |
- | statements: $1 | + | * j.. - saut (plusieurs informations) |
- | }; | + | * call - appel de fonction |
- | return $$; | + | * ret - retour de la fonction |
- | }; | + | * hlt - arrêt du processeur |
- | + | * push - ajouter dans la pile | |
- | statements | + | * pop - supprimer de la pile at ajouter dans un registre |
- | : statement NEWLINE statements { | + | |
- | $3.splice (0, 0, $1); | + | |
- | $$ = $3; | + | |
- | } | + | |
- | | statement NEWLINE { | + | |
- | $$ = [$1]; | + | |
- | } | + | |
- | | statement { | + | |
- | $$ = [$1]; | + | |
- | } | + | |
- | ; | + | |
- | + | ||
- | statement | + | |
- | : expression {} | + | |
- | | assign {} | + | |
- | | function_call {} | + | |
- | ; | + | |
- | + | ||
- | + | ||
- | expression | + | |
- | : LP expression RP { $$ = $2; } | + | |
- | | expression '+' expression { | + | |
- | $$ = { | + | |
- | type: 'expression', | + | |
- | operator: '+', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | expression '-' expression { | + | |
- | $$ = { | + | |
- | type: 'expression', | + | |
- | operator: '-', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | expression '*' expression { | + | |
- | $$ = { | + | |
- | type: 'expression', | + | |
- | operator: '*', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | expression '/' expression { | + | |
- | $$ = { | + | |
- | type: 'expression', | + | |
- | operator: '/', | + | |
- | left: $1, | + | |
- | right: $3 | + | |
- | }; | + | |
- | } | + | |
- | | IDENTIFIER { | + | |
- | $$ = { | + | |
- | type: 'identifier', | + | |
- | value: $1 | + | |
- | }; | + | |
- | } | + | |
- | | NUMBER { | + | |
- | $$ = { | + | |
- | type: 'number', | + | |
- | value: parseFloat ($1) | + | |
- | }; | + | |
- | } | + | |
- | | STRING_VALUE { | + | |
- | $$ = { | + | |
- | type: 'string', | + | |
- | value: $1.substring (1, $1.length-2) | + | |
- | }; | + | |
- | } | + | |
- | ; | + | |
- | + | ||
- | + | ||
- | assign | + | |
- | : IDENTIFIER '=' expression { | + | |
- | $$ = { | + | |
- | type: 'assign', | + | |
- | to: $1, | + | |
- | from: $3 | + | |
- | }; | + | |
- | } | + | |
- | | IDENTIFIER '=' function_call { | + | |
- | $$ = { | + | |
- | type: 'assign', | + | |
- | to: $1, | + | |
- | from: $3 | + | |
- | }; | + | |
- | } | + | |
- | ; | + | |
- | + | ||
- | function_call | + | |
- | : IDENTIFIER LP parameters_run RP { | + | |
- | $$ = { | + | |
- | type: 'function_call', | + | |
- | function: $1, | + | |
- | parameters: $3 | + | |
- | }; | + | |
- | }; | + | |
- | + | ||
- | parameters_run | + | |
- | : expression ',' parameters_run { | + | |
- | $3.splice (0, 0, $1); | + | |
- | $$ = $3; | + | |
- | } | + | |
- | | expression { | + | |
- | $$ = [$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'); | ||
- | |||
- | var variable_id = 0; | ||
- | |||
- | |||
- | // get a new temporary variable | ||
- | function nextVar () | ||
- | { | ||
- | return 'var' + variable_id++; | ||
- | } | ||
- | |||
- | |||
- | function writeThreeAddressCode (node) | ||
- | { | ||
- | if (node.type === 'module') | ||
- | { | ||
- | for (var statement of node.statements) | ||
- | { | ||
- | writeThreeAddressCode(statement); | ||
- | } | ||
- | } | ||
- | else | ||
- | if (node.type === 'function_call') | ||
- | { | ||
- | | ||
- | } | ||
- | else | ||
- | if (node.type === 'number') | ||
- | { | ||
- | | ||
- | } | ||
- | else | ||
- | if (node.type === 'assign') | ||
- | { | ||
- | |||
- | } | ||
- | else | ||
- | if (node.type === 'identifier') | ||
- | { | ||
- | } | + | L'ensemble d'instructions avec sa description est disponible sur le site Web du simulateur [[https://schweigi.github.io/assembler-simulator/instruction-set.html]]. |
- | else | + | |
- | if (node.type === 'expression') | + | |
- | { | + | |
- | if (node.left !== undefined && node.right !== undefined) | + | |
- | { | + | |
- | + | ||
- | } | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | 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 ==== |
+ | - Exécutez le programme initial. Changez le nom de la variable et essayez de comprendre comment écrire votre nom sur la sortie (**2p**) | ||
+ | - Écrivez un programme qui place les nombres 0, 2, 4, 6 dans les registres A, B, C et D.(**1p**) | ||
+ | - É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**). | ||
+ | - É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**) | ||
- | ===== Exercises ===== | ||
- | - Dans un fichier texte **ex1.txt**, écrivez le code de trois adresses avec une pile pour les expressions suivantes (**1p**) | ||
- | * (5-3)*7+(2+4) | ||
- | * a = (5-3)*7+(2+4) | ||
- | * e = (a+5)/(a-2) | ||
- | - Dans un fichier texte **ex2.txt**, écrivez le code de trois adresses avec une pile pour le programme suivant (**1p**) <code javascript> | ||
- | if (a > 0) | ||
- | { | ||
- | result = 'positive'; | ||
- | } | ||
- | else | ||
- | { | ||
- | result = 'negative'; | ||
- | } | ||
- | </code> | ||
- | - Dans un fichier texte **ex3.txt**, écrivez le code de trois adresses avec une pile 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/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 noeuds //expression// avec une pile (**2p**) | ||
- | - Modifiez la grammaire (le fichier //alf.y//) pour que les appels de fonction puissent être à l'intérieur des expressions. (Exemple: ''2 + 3 / double(a)''). Testez la validité de la grammaire avec le fichier **ex5.txt** et vérifiez que le programme ne retourne aucune erreur. (**1p**) | ||
- | - Ecrivez un programme qui écrit le three address code avec une pile pour le noeud //assign//. Testez avec le fichier **ex6.txt**. (**1p**) | ||
- | - Écrivez un programme qui écrit le three address code avec une pile pour les noeds //function_call//. Testez avec le fichier **ex7.txt**. (**2p**) | ||
- | - Écrivez un programme qui écrit le three address code avec une pile pour les noeuds //function//. Tout d'abord, il faut modifier la grammaire afin qu'elle accepte la déclaration des fonctions <code> | ||
- | function function_name(param1, param2, ...) | ||
- | { | ||
- | statement1 | ||
- | statement2 | ||
- | ... | ||
- | } | ||
- | </code> | ||
- | Suivez les lignes marquées par TODO8 afin de générer le Three Address Code pour les fonctions. (**2p**) | ||
+ | <hidden> | ||
+ | ==== 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**) | ||
+ | [[https://github.com/alexandruradovici/alf2018/tree/master/TP/TP11|Solutions]] | ||
+ | </hidden> | ||
- | ===== Solutions ===== | ||
- | [[https://github.com/UPB-FILS/alf/tree/master/TP/TP10|Solutions]] | ||