This shows you the differences between two versions of the page.
alf:laboratoare:10 [2021/04/15 11:49] 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 ====== |
- | 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: | + | 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: |
+ | * 4 Hz | ||
+ | * 4 registres à usage général A, B, C si D | ||
+ | * un registre pour l'instruction IP actuelle | ||
+ | * un registre pour le sommet de la pile SP | ||
+ | * 256 B RAM | ||
+ | * 24 B mémoire vidéo (derniers octets de RAM) | ||
- | * maximum trois adresses (variables, numéro, étiquette, …) | + | La description de simulateur este disponible [[https://www.mschweighauser.com/make-your-own-assembler-simulator-in-javascript-part1/]]. |
- | * opérateur | + | |
- | * résultat | + | |
+ | ===== L'ensemble d'instructions ===== | ||
- | Contrairement au TP précédent où la transformation a été implémentée a l'aide des //variables temporaires//, l'objectif de ce travail est de représenter le ''Three Address Code'' en simulant une **pile**. | + | 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 | ||
- | ===== Exemple ===== | + | L'ensemble d'instructions avec sa description est disponible sur le site Web du simulateur [[https://schweigi.github.io/assembler-simulator/instruction-set.html]]. |
- | <code> | ||
- | /* Expression */ | ||
- | (5-3)*7; | ||
- | /* Three Address Code */ | + | ==== Exercises ==== |
- | push 5 | + | - Exécutez le programme initial. Changez le nom de la variable et essayez de comprendre comment écrire votre nom sur la sortie (**2p**) |
- | push 3 | + | - Écrivez un programme qui place les nombres 0, 2, 4, 6 dans les registres A, B, C et D.(**1p**) |
- | sub | + | - É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**) |
- | push 7 | + | - É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**) |
- | mul | + | - É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**). |
- | </code> | + | - É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**) | ||
- | ===== Expression Parser ===== | + | <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> | ||
- | <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 | ||
- | ; | ||
- | |||
- | 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 : ('"'~["]+'"'|'\''~[']+'\''); | ||
- | |||
- | ; | ||
- | </code> | ||
- | <code javascript index.ts> | ||
- | 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) | ||
- | { | ||
- | | ||
- | } | ||
- | else | ||
- | if (node instanceof ValueNode) | ||
- | { | ||
- | | ||
- | } | ||
- | else | ||
- | if (node instanceof VariableNode) | ||
- | { | ||
- | | ||
- | } | ||
- | else | ||
- | if (node instanceof AttributionNode) | ||
- | { | ||
- | | ||
- | } | ||
- | else | ||
- | if (node instanceof Expression) | ||
- | { | ||
- | if (node.left !== undefined && node.right !== undefined) | ||
- | { | ||
- | | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | var ast = parser.parse (str); | ||
- | console.log (JSON.stringify(ast, null, 4)); | ||
- | |||
- | writeThreeAddressCode(ast); | ||
- | </code> | ||
- | |||
- | |||
- | ===== Exercises ===== | ||
- | |||
- | |||
- | - Dans un fichier **ex1.txt** écrivez le //three address code// pour les expressions suivantes (**1p**) | ||
- | * 3-5/(4+8) | ||
- | * a = 2*7/(2-3) | ||
- | * e = (b+5)/(7-a) | ||
- | - Dans un fichier **ex2.txt** écrivez le //three address code// pour le programme suivant (**1p**) <code javascript> | ||
- | if (a == 0) | ||
- | { | ||
- | result = 'null'; | ||
- | } | ||
- | else | ||
- | { | ||
- | result = 'not null'; | ||
- | } | ||
- | </code> | ||
- | - Dans un fichier **ex3.txt** écrivez le //three address code// pour le programme suivant (**1p**) <code javascript> | ||
- | function power (base, exp) | ||
- | { | ||
- | return base ^ exp; | ||
- | } | ||
- | |||
- | power (4/2, 5); | ||
- | </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 et le //Visitor// 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**. (**1p**) | ||
- | - Ecrivez un programme qui écrit le three address code avec une pile pour le noeud //AttributionNode//. Testez avec le fichier **ex6.txt**. (**1p**) | ||
- | - Écrivez un programme qui écrit le three address code avec une pile pour le noeud //FunctionCallNode//. Testez avec le fichier **ex7.txt**. (**2p**) | ||
- | - Écrivez un programme qui écrit le three address code avec une pile pour le noeud //FunctionNode//. 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**) | ||
- | |||
- | |||
- | ===== Solutions ===== | ||
- | |||
- | [[https://github.com/UPB-FILS/alf/tree/master/TP/TP10|Solutions]] | ||