TD GDC numéro 6 et 7
L'objectif de ces exercices est de spécifier
précisément
la machine virtuelle, d'écrire du code à la main et d'en
générer sur des exemples simples.
-
Specifications pour l'appel de fonction
Il faut préciser chacun des points suivants
-
adresse de retour (empilée avant ou après les
paramètres),
- appel de fonction par jmp ou jsr,
- accès à l'intérieur de la pile par le
pointeur de sommet
de pile SP ou par une construction syntaxique spéciale &
n,
- valeur de retour (pile ou registre),
- retour de fonction par rtn ou jsr,
- qui dépile les paramètres (appelant ou
appelé),
Toute combinaison est possible mais certaines sont plus simples que
d'autres.
-
Quelques fonctions simples
Ecrire à la main, dans le code de la VM et en suivant les
spécifications que vous avez choisies, le code des focntions
suivantes
:
-
les fonctions f et g du TD 1,
- les fonctions fact et fibo, en version
récursive,
Vérifier que le code produit est non seulement correct, mais
qu'il
respecte vos conventions et qu'il aurait pu être produit par un
programme.
-
Calculette
En suivant les spécifications que vous avez choisies,
définir la fonction compile-calcul qui prend une
expression
arithmétique en paramètre et génère le code
VM correspondant.
La spécification de la calculette est la même que dans le
TD
précédent.
- commencer par écrire à la main, dans le code de
la VM, la
fonction correspondant à l'expression que vous voulez compiler ;
- écrire ensuite la fonction compile-calcul,
comme cas particulier
d'une fonction de compilation qui ne traiterait que les cas
d'opérations arithmétiques et de constantes
numériques.
- Fonction fact
Ecrire la fonction de génération de code compile-vm
permettant de compiler la fonction fact écrite de
façon
récursive.
Pour cela, on traitera les schémas de compilation
nécessaires
pour la fonction :
-
constantes numériques et opérateurs arithmétiques
(comme
compile-calcul) ;
- conditionnelles et comparaisons (if et =) ;
- appels de fonctions
-
Variables locales
Généraliser au traitement des variables locales (lambda
ou let), par exemple
-
pour la fonction foo:
(defun foo (n) (let ((x (fact n))) (* (+ x n) (- x n))))
- pour la fonction bar:
(defun bar (n) (let ((x (fact n))) (* (foo (+ x n)) (foo (- x n)))))
Dans les deux cas, on écrira d'abord la fonction à la
main pour
bien voir à quoi on veut aboutir.