Une fois cette archive décompressée (par exemple avec tar zxvf rtl-java.tar.gz), vous obtenez un répertoire mini_c/ contenant plusieurs fichiers Java :
Ops.java | Opérations x86-64 utilisées pendant la sélection d'instructions |
Label.java | Étiquettes |
Register.java | Registres (physiques et pseudo-registres) |
RTL.java | Langage RTL (Register Transfer Language) |
RTLinterp.java | Interprète de code RTL (pour tester) |
Ces classes sont complètes et documentées ici. On prendra le temps de bien comprendre le code fourni.
RTLfile translate(File f)qui traduit l'arbre de syntaxe abstraite issu du typage en code RTL, c'est-à-dire en une valeur du type RTLfile. On pourra écrire cette classe comme un visiteur de la classe abstraite issue du typage, c'est-à-dire
class ToRTL extends EmptyVisitor { ... }
On pourra récupérer ce nouveau Main.java qui ajoute au compilateur une option --interp-rtl pour exécuter le code RTL (avec la classe RTLinterp fournie). Par ailleurs, ce nouveau programme principal affiche le code RTL (avec la méthode print de la classe RTLfile fournie) dès lors que l'option --debug est passée.
On suggère très fortement de procéder construction par construction, en testant systématiquement à chaque fois.
RTLgraph graph; // graphe en cours de constructionLa méthode add de la classe RTLgraph ajoute une nouvelle instruction dans le graphe, à une étiquette fraîche qui est renvoyée.
Pour traduire une expression, il faut se donner
Pour traduire une instruction, il faut se donner
Traduire chaque fonction mini-C vers le type RTLfun des fonctions RTL. Il suffit de créer un pseudo-registre pour le résultat et une étiquette pour la sortie, puis de traduire le corps de la fonction mini-C avec ces paramètres.
Traduire enfin un programme mini-C vers le type RTLfile, en traduisant chacune des fonctions.
Tester avec le programme :
int main() { return 42; }On doit obtenir quelque chose comme :
== RTL ========================== #1 main[] entry : L2 exit : L1 locals : [] L2: mov $42 #1 --> L1
Les nouvelles instructions RTL à utiliser sont : Rmunop, Rmbinop.
Tester avec des programmes comme
int main() { return 40 - (-2); }
Tester avec des programmes comme
int main() { int y, x; y = 40; x = 2; return y + x; }
Pour traduire les instructions if et while, il peut être utile d'introduire une méthode qui, étant données une expression et deux étiquettes truel et falsel, traduit l'expression en RTL et transfert le contrôle à l'étiquette truel si sa valeur est non nulle et à l'étiquette falsel sinon.
Ajouter également le traitement des constructions && et ||, en respectant leur évaluation paresseuse.
Les nouvelles instructions RTL à utiliser sont : Rmubranch, Rmbbranch, Rgoto.
Tester avec des programmes comme
int main() { if (1 <= 2) return 3; else return 4; }
Les nouvelles instructions RTL à utiliser sont : Rcall.
Tester avec des programmes comme
int fact(int n) { if (n <= 1) return 1; return n * fact(n-1); } int main() { return fact(42); }
Les nouvelles instructions RTL à utiliser sont : Rload, Rstore.
Tester avec des programmes comme
struct S { int a; int b; }; int main() { struct S *p; p = malloc(sizeof(struct S)); p->a = 40; p->b = 2; return p->a + p->b; }
> ./run -i "mon/chemin/vers/mini-c --interp-rtl" Test de mon/chemin/vers/mini-c --interp-rtl Interprétation Execution normale ----------------- ........................................................... Execution conduisant à un échec ------------------------------- ... Compilation: Compilation : 62/62 : 100% Comportement du code : 62/62 : 100%