A(dministrative?)-Normal Form
En Lecture 4, Ben Lerner definió ANF y dio varios ejemplos de como convertir expresiones a ANF.
En clase discutimos alternativas a la funcion anf de Dr. Lerner, en particular que podiamos crear un nuevo tipo para no confundir expresiones con expresiones en ANF. Joe Gibbs presenta una version de ANF que usa unos nuevos tipos, pero me parece un poco complicada. Voy a tratar de hacer una mas sencilla.
Sabemos que queremos distinguir expresiones immediatas de las demas, asi que podemos definir un tipo.
type immexpr =
| ImmNum of int64
| ImmId of string
Ahora podemos definir otro tipo aexp
de expresiones en ANF. A diferencia de las expr
, las aexpr
solo pueden construir expresiones en ANF.
type aexpr =
| AImm of immexpr
| AAdd1 of immexpr
| ASub1 of immexpr
| APrim2 of prim2 * immexpr * immexpr
| AIf of immexpr * aexpr * aexpr
| ALet of string * aexpr * aexpr
La funcion anf debe entoces recibir un expr
y producir un aexpr
. Vamos a llamar esta anfv2
.
let rec anfv2 (e : expr) : aexpr =
match e with
| Num n -> AImm (ImmNum n)
| Id v -> AImm (ImmId v)
Como AAdd1
tiene que recibir un immediato, y Add1
puede contener cualquier expr
, debemos definir una variable para contener la expresion:
| Add1 e ->
let tempnam = gensym "_add1" in
ALet (tempnam, anfv2 e, AAdd1 (ImmId tempnam))
Fijense, ahora no podemos construir un AAdd1 (anfv2 e)
, ya que esto da un error, el tipo que devuelve anfv2 no es un immexpr
.
El compilador tiene que cambiar, el nuevo compilador va a recibir un aexpr
y producir la lista de instrucciones:
let rec compile_aexpr (e : aexpr) (env : env) : instruction list =
let imm_to_arg (e : immexpr) : arg =
match e with
| ImmNum n -> Constant n
| ImmId x -> RegOffset (RSP, lookup x env)
in
match e with
Cuando sabemos que tenemos un immexpr
se simplifica la compilacion
| AImm imm -> [ IMov (Reg RAX, imm_to_arg imm) ]
| AAdd1 imm -> [IMov (Reg RAX, (imm_to_arg imm));
IAdd (Reg RAX, Constant 1L)]