7 (* ******************************************************************* Pseudo
*)
8 (* pseudocode
abstraction for our architecture
*)
9 structure Pseudo
= struct
11 (* int to C
string, handles negative numbers
*)
12 fun Int_toCString i
= if i
>=0 then Int.toString i
else "-" ^
(Int.toString (~i
))
14 (* code
and data labels are just strings
: *)
15 type clabel
= string (* code label is a goto target
*)
16 type dlabel
= string (* data label is a global variable
of function
*)
18 (* processor registers
: three special purpose registers
and some general ones
*)
21 datatype t
= BP (* stack base
*)
22 |
SP (* stack pointer
*)
23 |
RET (* return value
of every expression
*)
24 | REG
of int (* one
of a few general purpose registers
, numbered from
0 *)
26 fun toString BP
= "fp"
28 | toString RET
= "r_res"
29 |
toString (REG i
) = "r["^
(Int.toString i
)^
"]"
33 (* addresses (places
): different addressing modes
*)
36 datatype t
= Lbl
of dlabel (* address
of the data the label points to
*)
37 | Reg
of R
.t (* a register
*)
38 | Ind
of t (* address referenced by place
*)
39 | Ofs
of (t
*int) (* offset from address referenced by place
*)
41 fun toString (Lbl l
) = l (* global variables are pointers
*)
42 |
toString (Reg r
) = R
.toString r
43 |
toString (Ind a
) = "*(void**)" ^
(toString a
)
44 |
toString (Ofs (a
,i
)) = "*((void**)" ^
(toString a
) ^
" + " ^
(Int_toCString i
) ^
")"
54 datatype t
= Val
of A
.t (* address
of the place
*)
55 | Adr
of A
.t (* value
in the place
*)
56 | Cst
of int (* constant
*)
57 | ConstStr
of string (* constant
string *)
59 fun toString (Val a
) = A
.toString a
60 |
toString (Adr a
) = "(void*)&" ^
(A
.toString a
)
61 |
toString (Cst i
) = Int_toCString i
62 |
toString (ConstStr s
) = "\""^s^
"\""
66 (* instructions
: be very CISCy
, allow all places to be targets
*)
69 datatype t
= Move
of A
.t
*V
.t (* move value to place
*)
70 | Push
of V
.t (* push value onto stack
*)
71 | Pop
of A
.t (* pop from stack to place
*)
72 | Label
of clabel (* put a code label
*)
73 | Goto
of clabel (* goto code label
*)
74 | Goif
of V
.t
*clabel (* go
if value
if not
true *)
75 | Call
of clabel
*clabel (* call
function (first
, return is second
) *)
76 |
Ret (* return from function
*)
77 | Add
of A
.t
*V
.t (* add value to place
*)
78 | Sub
of A
.t
*V
.t (* subtract value from place
*)
79 | Mul
of A
.t
*V
.t (* multiply place by value
*)
80 | Div
of A
.t
*V
.t (* divide place by value
*)
81 | Ccall
of string * V
.t
list (* call a C function
, an analogue
of a system call
*)
82 | Cfunc
of A
.t
* string * V
.t list
83 | Comment
of string (* comment
*)
84 |
Pass (* do nothing
, for labeling
*)
86 fun seq insts
= String.concatWith
"\n" (List.map indent insts
) (* serialize a sequence
of instructions
*)
88 (* indent instructions by a tab
*)
89 and indent (i
as (Label _
)) = toString
i (* but outdent labels
*)
90 | indent i
= "\t" ^
(toString i
)
92 (* convert an instruction to a piece
of C code
, the final newline is omitted
and added
in seq
*)
93 and toString (Move (a
,v
)) = (A
.toString a
) ^
" = " ^
(V
.toString v
) ^
";"
95 |
toString (Push v
) = seq
[Move (A
.Reg R
.SP
, V
.Adr (A
.Ofs (A
.Reg R
.SP
, ~
1))),
96 Move (A
.Ind (A
.Reg R
.SP
), v
)]
97 |
toString (Pop a
) = seq
[Move (a
, V
.Val (A
.Ind (A
.Reg R
.SP
))),
98 Move (A
.Reg R
.SP
, V
.Adr (A
.Ofs (A
.Reg R
.SP
, 1)))]
100 |
toString (Push v
) = toString (Ccall ("push",[v
]))
101 |
toString (Pop a
) = toString (Ccall ("pop",[V
.Adr a
]))
102 |
toString (Label l
) = l ^
":"
103 |
toString (Goto l
) = "goto " ^ l ^
";"
104 |
toString (Goif (v
,l
)) = "if (" ^
(V
.toString v
) ^
") goto " ^ l ^
";"
105 |
toString (Add (a
,v
)) = (A
.toString a
) ^
" += " ^
(V
.toString v
) ^
";"
106 |
toString (Sub (a
,v
)) = (A
.toString a
) ^
" -= " ^
(V
.toString v
) ^
";"
107 |
toString (Mul (a
,v
)) = (A
.toString a
) ^
" *= " ^
(V
.toString v
) ^
";"
108 |
toString (Div (a
,v
)) = (A
.toString a
) ^
" /= " ^
(V
.toString v
) ^
";"
109 |
toString (Ccall (f
,vs
)) = f ^
"(" ^
110 (String.concatWith
"," (List.map V
.toString vs
)) ^
112 |
toString (Cfunc (a
,f
,vs
)) = (A
.toString a
) ^
" = " ^ f ^
"(" ^
113 (String.concatWith
"," (List.map V
.toString vs
)) ^
115 |
toString (Comment s
) = "// " ^ s
116 | toString Pass
= ";"
119 (* boots the pseudo
-processor
: allocates registers
and stack
120 fun boot (nregs
, stacksize
) =
121 "struct {int bp, sp, ret, reg[" ^
(Int.toString nregs
) ^
"];\n" ^
122 " int stack[" ^
(Int.toString stacksize
) ^
"]; } a;\n" ^
125 " a.bp = (int)(a.stack+" ^
(Int.toString stacksize
) ^
");\n" ^
130 fun mkInitArchitecture(nregs
,stacksize
) =
131 "initArchitecture("^
Int.toString(nregs
)^
","^
Int.toString(stacksize
)^
");\n";
135 (* ******************************************************************** Gene
*)
139 val reset
: unit
-> unit
140 val add
: Expr
-> unit
141 val emit
: (int*int) -> string
143 end = struct (* code generation
*)
151 val add
: string -> string
152 val emit
: unit
-> string
153 val reset
: unit
-> unit
156 val (freevars
: (string*string) list ref
) = ref
[]
158 (* add a new free variable
, or use an existing one
*)
160 case List.find (fn vn
=>(#
1 vn
)=varname
) (!freevars
)
164 (* val name
= new_name ("sv_" ^ varname
) *)
167 freevars
:= (varname
, name
) :: (!freevars
)
171 (* fun emit_free (v
,n
) = "void* " ^ n ^
" = (void* )&sc_undef;\n" *)
172 fun emit_free (v
,n
) = ""
174 (* all free variables initially
equal (int)&sc_undef
*)
175 fun emit () = String.concat (map
emit_free (List.rev (!freevars
)))
177 fun reset () = freevars
:= []
184 val initial_code
= []
185 val (code
: I
.t list ref
) = ref initial_code
188 (* add single instr to the code
*)
189 fun % i
= code
:= i
:: (!code
)
191 (* add expression
's code to the code list
*)
192 fun add (Const sexpr
) = (* value is address
of constant
*)
193 let val cname
= Const
.add(sexpr
)
194 in % (I
.Move ((A
.Reg R
.RET
), V
.Adr (A
.Lbl cname
))) end
195 |
add (Var _
) = raise Match (* can
't be here
, must have been resolved earlier
*)
196 |
add (VarFree name
) = (* value is variable
*)
197 let val vname
= Free
.add(name
)
199 (* % (I
.Move ((A
.Reg R
.RET
), V
.Val (A
.Lbl vname
))) *)
200 % (I
.Cfunc ((A
.Reg R
.RET
), "probeSymbolDefined", [V
.ConstStr vname
, V
.Val (A
.Lbl
"topLevel")]))
201 (* add
: check
if defined or not
*)
202 ;% (I
.Move ((A
.Reg R
.RET
), V
.Val (A
.Lbl
"((SymbolEntry*)r_res)->sob")))
205 |
add (If (i
, t
, e
)) =
206 let val then_label
= new_name
"THEN"
207 val else_label
= new_name
"ELSE"
208 val fi_label
= new_name
"ENDIF"
211 ; % (I
.Sub ((A
.Reg R
.RET
), V
.Adr (A
.Lbl (Const
.add (Bool false))))) (* difference between value
and #f
*)
212 ; % (I
.Goif (V
.Val (A
.Reg R
.RET
), then_label
)) (* if different
, goto the
true branch
*)
213 ; % (I
.Goto else_label
) (* otherwise
, goto the
false branch
*)
214 ; % (I
.Label then_label
) (* the
true branch
*)
216 ; % (I
.Goto fi_label
)
217 ; % (I
.Label else_label
) (* the
false branch
*)
219 ; % (I
.Label fi_label
)
224 (* Adds the free variables for the built
-in procedures
. The variables
225 themselves are initialized
in initBuiltins() *)
226 fun addBuiltinsFreeVars() =
227 (map (fn(n
)=>Free
.add n
)
228 ["apply", "binary-add", "binary-div", "binary<?",
229 "binary-mul", "binary=?", "binary-sub",
230 "boolean?", "car", "cdr", "char?", "char->integer",
231 "cons", "eq?", "integer->char",
232 "make-string", "make-vector", "null?", "number?",
233 "pair?", "procedure?", "remainder", "set-car!",
234 "set-cdr!", "string-length", "string-ref", "string?",
235 "string-set!", "vector-length",
236 "vector-ref", "vector?", "vector-set!", "zero?"]
239 fun mkInitBuiltins() = "initBuiltins();";
241 fun emit (nregs
, stacksize
) =
242 (addBuiltinsFreeVars();
243 "\n/* COMP091 Scheme->C Compiler Generated Code */\n\n" ^
244 "#include \"scheme.h\"\n" ^
245 "#include \"assertions.h\"\n" ^
246 "#include \"arch.h\"\n" ^
247 "#include \"builtins.h\"\n" ^
248 "extern SymbolNode *topLevel;\n"^
249 "\n/* Constants */\n" ^
251 "\n/* Free variables */\n" ^
254 "void schemeCompiledFunction() {\n" ^
255 "\t"^
mkInitArchitecture(nregs
,stacksize
)^
"\n" ^
256 "\t"^
mkInitBuiltins()^
"\n" ^
258 (I
.seq (List.rev (!code
))) ^
263 ( names
:= initial_names
266 ; code
:= initial_code
)