open System
// your code goes here
type binop =
| Add
| Sub
| Mul
| Div
type unop =
| Dup
| Drop
type expr =
| Val of int
| BinOp of binop
| UnOp of unop
// Starts at address #x00 #x03
let duplicate =
"POTA #xFF #x00\n" +
"PUFA #xFF #x00\n" +
"PUFA #xFF #x00\n" +
"RET\n"
// Starts at address #x00 #x0E
let multiply =
"POTA #xFF #x00\n" + // puts multiplicand at xFF x00
"PUFA #xFF #x00\n" +
"PUFA #xFF #x00\n" +
"POTA #xFF #x01\n" + // Counter
"PUFA #xFF #x01\n" + // Grab counter
"PUSH 0\n" +
"EQ?\n" + // Counter == 0?
"JIF #x00 #x34\n" + // This should go to RET
"PUFA #xFF #x00\n" +
"ADD\n" + // Accumulate value
"PUFA #xFF #x01\n" +
"PUSH 1\n" +
"SUB\n" +
"POTA #xFF #x01\n" + // Decrement counter
"JMP #x00 #x1B\n" + // Return to beginning of loop
"RET\n"
// Starts at address #0x00 #0x35
let divide =
"POTA #xFF #x00\n" + // puts multiplicand at xFF x00
"PUFA #xFF #x00\n" +
"PUFA #xFF #x00\n" +
"POTA #xFF #x01\n" + // Counter
"PUFA #xFF #x01\n" + // Grab counter
"PUSH 0\n" +
"EQ?\n" + // Counter == 0?
"JIF #x00 #x5B\n" + // This should go to RET
"PUFA #xFF #x00\n" +
"SUB\n" + // Accumulate value
"PUFA #xFF #x01\n" +
"PUSH 1\n" +
"SUB\n" +
"POTA #xFF #x01\n" + // Decrement counter
"JMP #x00 #x42\n" + // Return to beginning of loop
"RET\n"
let stdlib =
"JMP #x00 #x5C\n" + // Should point after stdlib
duplicate +
multiply +
divide
let translate xpr out =
match xpr with
| Val x
-> let o
= sprintf "PUSH %i" x
o::out
| BinOp op -> match op with
| Add -> "ADD"::out
| Sub -> "SUB"::out
| Mul -> "JSR #x00 #x0E"::out
| Div -> "JSR #x00 #x35"::out
| UnOp op -> match op with
| Dup -> "JSR #x00 #x03"::out
| Drop -> "POP"::out
let rec parse prog =
match prog with
| [] -> []
| x::xs -> match x with
| "+" -> BinOp Add::(parse xs)
| "-" -> BinOp Sub::(parse xs)
| "*" -> BinOp Mul::(parse xs)
| "/" -> BinOp Div::(parse xs)
| "dup" -> UnOp Dup::(parse xs)
| "drop" -> UnOp Drop::(parse xs)
| v -> let i = int v
Val i::(parse xs)
let compile (prog : string) =
let parsed = prog.Split [|' '|]
|> Array.toList
|> parse
|> List.rev
let initout = []
let rec compiling p out =
match p with
| [] -> out
| x::xs -> compiling xs (translate x out)
let lines = compiling parsed initout
stdlib + List.reduce (fun x y -> x + "\n" + y) lines
let p = "4 5 + dup *"
let r = compile p
printfn "%s" r