let push () = printf "\tsub $sp,$sp, 4\t\t#PUSH\n" ; printf "\tsw $v0, 0($sp)\n" and pop () = printf "\tlw $v1, 0($sp)\n" ; printf "\tadd $sp,$sp, 4\t\t#POP\n" let rec compile_expression = function | Int i -> printf "\tli $v0, %d\t\t#CONST %d\n" i i | X -> printf "\tmove $v0, $a0\t\t#VAR\n" | Binexp(op,e1,e2) -> compile_expression e2 ; push () ; compile_expression e1 ; pop () ; binop op |
let memo_of_op = function | Plus -> "add" | Minus -> "sub" | Times -> "mul" | Div -> "div" let binop op = let memo =memo_of_op op in printf "\t%s $v0, $v0, $v1\t#%s\n" memo (String.uppercase memo) |
(* Le registre « $v0 » doit être le premier *) let memo_of_op = function | Plus -> "add" | Minus -> "sub" | Times -> "mul" | Div -> "div" let registers = [| "$v0" ; "$a1" ; "$a2" ; "$t0" ; |] let rec do_compile target e = match e with | Int i -> printf "\tli %s, %d\n" registers.(target) i | X -> printf "\tmove %s, $a0\n" registers.(target) | Binexp (op, e1, e2) -> do_compile target e1 ; do_compile (target+1) e2 ; printf "\t%s %s, %s, %s\n" (memo_of_op op) registers.(target) registers.(target) registers.(target+1) let compile_expression e = do_compile 0 e |
target
de la fonction do_compile
.
Cet entier target
est l'indice (dans le tableau
registers
) du premier registre disponible.
… do_compile target e1 ; do_compile (target+1) e2 ; … |
do_compile i …
» n'écrit que dans
des registres dont les indices sont supérieurs ou égaux à i.
let registers = [| "$a0" ; "$v0" ; "$a1" ; "$a2" ; "$t0" ; |] type arg = I of int | R of int let parg chan = function | I i -> fprintf chan "%d" i | R r -> fprintf chan "%s" registers.(r) let to_reg t a = match a with | I i -> printf "\tli %s, %d\n" registers.(t) i ; t, (t+1) | R r -> r, t let rec do_compile target e = match e with | Int i -> I i, target | X -> R 0, target | Binexp (Plus|Times as op, (Int _ as e1), e2) -> compile_bin target op e2 e1 | Binexp (op, e1, e2) -> compile_bin target op e1 e2 and compile_bin target op e1 e2 = let a1, t1 = do_compile target e1 in let r1, t1 = to_reg t1 a1 in let a2, _ = do_compile t1 e2 in fprintf stdout "\t%s %s, %s, %a\n" (memo_of_op op) registers.(target) registers.(r1) parg a2 ; R target, target+1 let compile_expression e = let r,_ = do_compile 1 e in match r with | R 1 -> () | R r -> printf "\tmove %s, %s\n" registers.(1) registers.(r) | I i -> printf "\tli %s, %d\n" registers.(1) i |
do_compile
, en plus d'emettre le code
asembleur, renvoie maintenant résultat de type arg
qui
dit où le code emis a rangé le résultat.target
de do_compile
est l'indice du registre
où ranger le résultat du calcul, mais do_compile
n'utilise
pas forcément ce registre. Il faut donc suivre les évolutions de ce
paramètre. Dès lors la fonction do_compile
renvoie en fait
une paire dont la deuxième composante est l'indice du prochain
registre libre."%a"
dans le format de
fprintf
, qui permet d'appeler un imprimeur arbitraire (ici
parg
pour afficher les valeurs de type arg
.Ce document a été traduit de LATEX par HEVEA.