diff --git a/regression/Makefile b/regression/Makefile index bbecbbd4..2a7ced1c 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -1,6 +1,11 @@ -TESTS=test001 test002 test012 test013 test003 test004 test005 test006 test007 test008 test009 test010 test011 test014 test015 test016 test017 test018 +TESTS=test001 test002 test003 test004 test005 test006 test007 test008 test012 test013 -# test019 test020 test021 test022 test023 test024 test025 test026 +# More expressions: +# test003 test004 test005 test006 test007 test008 + +# Later: +# test009 test010 test 11 +# test014 test015 test016 test017 test018 test019 test020 test021 test022 test023 test024 test025 test026 # test027 test028 test029 test030 .PHONY: check $(TESTS) diff --git a/src/Interpret.ml b/src/Interpret.ml index 9f863d55..32a16d5a 100644 --- a/src/Interpret.ml +++ b/src/Interpret.ml @@ -6,13 +6,25 @@ module Expr = open Expr - let rec eval expr st = + let rec eval expr st = let eval' e = eval e st in match expr with - | Var x -> st x - | Const z -> z - | Add (x, y) -> eval' x + eval' y - | Mul (x, y) -> eval' x * eval' y + | Var x -> st x + | Const z -> z + | Binop ("+", x, y) -> eval' x + eval' y + | Binop ("-", x, y) -> eval' x - eval' y + | Binop ("*", x, y) -> eval' x * eval' y + | Binop ("/", x, y) -> eval' x / eval' y + | Binop ("%", x, y) -> (eval' x) mod (eval' y) + | Binop ("<", x, y) -> if (eval' x) < (eval' y) then 1 else 0 + | Binop ("<=", x, y) -> if (eval' x) <= (eval' y) then 1 else 0 + | Binop (">", x, y) -> if (eval' x) > (eval' y) then 1 else 0 + | Binop (">=", x, y) -> if (eval' x) >= (eval' y) then 1 else 0 + | Binop ("==", x, y) -> if (eval' x) == (eval' y) then 1 else 0 + | Binop ("!=", x, y) -> if (eval' x) <> (eval' y) then 1 else 0 + | Binop ("&&", x, y) -> if ((eval' x) <> 0) && ((eval' y) <> 0) then 1 else 0 + | Binop ("!!", x, y) -> if ((eval' x) <> 0) || ((eval' y) <> 0) then 1 else 0 + end @@ -22,27 +34,27 @@ module Stmt = open Stmt - (* State update primitive *) - let update st x v = fun y -> if y = x then v else st y - + (* State update primitive *) + let update st x v = fun y -> if y = x then v else st y + let rec eval stmt ((st, input, output) as conf) = match stmt with | Skip -> conf | Assign (x, e) -> (update st x (Expr.eval e st), input, output) - | Read x -> - let z :: input' = input in - (update st x z, input', output) + | Read x -> + let z :: input' = input in + (update st x z, input', output) | Write e -> (st, input, output @ [Expr.eval e st]) - | Seq (s1, s2) -> eval s1 conf |> eval s2 + | Seq (s1, s2) -> eval s1 conf |> eval s2 end module Program = struct - let eval p input = - let (_, _, output) = - Stmt.eval p ((fun _ -> failwith "undefined variable"), input, []) + let eval p input = + let (_, _, output) = + Stmt.eval p ((fun _ -> failwith "undefined variable"), input, []) in output diff --git a/src/Language.ml b/src/Language.ml index 96ac3e01..418b61c8 100644 --- a/src/Language.ml +++ b/src/Language.ml @@ -5,10 +5,31 @@ module Expr = type t = | Var of string | Const of int - | Add of t * t - | Mul of t * t + | Binop of string * t * t - ostap ( + ostap( + parse: expr0; + expr0: h:expr1 t:(-"!!" expr1)*{ + List.fold_left(fun e op ->Binop("!!", e, op)) h t}; + expr1: h:expr2 t:(-"&&" expr2)*{ + List.fold_left(fun e op ->Binop("&&", e, op)) h t}; + expr2: h:expr3 t:(("==" | "!=" | "<=" | "<" | ">=" | ">")expr3)?{ + match t with + | None -> h + | Some (op, y) -> Binop(Ostap.Matcher.Token.repr op, h, y) + }; + expr3: h:expr4 t:(("+" | "-") expr4)*{ + List.fold_left(fun e (op, y) -> Binop(Ostap.Matcher.Token.repr op, e, y)) h t}; + expr4: h: prim t:(("*" | "/" | "%") prim)*{ + List.fold_left(fun e (op, y) -> Binop(Ostap.Matcher.Token.repr op, e, y)) h t}; + prim: + n:DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" parse -")" + ) + end + + (* ostap ( parse: x:mull "+" y:parse {Add (x,y)} | mull; mull : x:prim "*" y:mull {Mul (x,y)} | prim; prim : @@ -17,7 +38,7 @@ module Expr = | -"(" parse -")" ) - end + end*) (* AST statements/commands *) module Stmt = @@ -51,4 +72,3 @@ module Program = let parse = Stmt.parse end - diff --git a/src/StackMachine.ml b/src/StackMachine.ml index 870537a4..50f5f8e3 100644 --- a/src/StackMachine.ml +++ b/src/StackMachine.ml @@ -10,6 +10,17 @@ module Instr = | ST of string | ADD | MUL + | SUB + | DIV + | MOD + | LT + | LE + | GT + | GE + | EQ + | NEQ + | AND + | OR end @@ -41,12 +52,32 @@ module Interpret = | LD x -> (st x :: stack, st, input, output) | ST x -> let z :: stack' = stack in (stack', update st x z, input, output) - | _ -> let y :: x :: stack' = stack in - ((match i with ADD -> (+) | _ -> ( * )) x y :: stack', - st, - input, - output - ) + | ADD -> let y :: x :: stack' = stack in + ((x + y):: stack', st, input, output) + | MUL -> let y :: x :: stack' = stack in + ((x * y):: stack', st, input, output) + | SUB -> let y :: x :: stack' = stack in + ((x - y):: stack', st, input, output) + | DIV -> let y :: x :: stack' = stack in + ((x / y):: stack', st, input, output) + | MOD -> let y :: x :: stack' = stack in + ((x mod y):: stack', st, input, output) + | LT -> let y :: x :: stack' = stack in + ((if x < y then 1 else 0):: stack', st, input, output) + | LE -> let y :: x :: stack' = stack in + ((if x <= y then 1 else 0):: stack', st, input, output) + | GT -> let y :: x :: stack' = stack in + ((if x > y then 1 else 0):: stack', st, input, output) + | GE -> let y :: x :: stack' = stack in + ((if x >= y then 1 else 0):: stack', st, input, output) + | EQ -> let y :: x :: stack' = stack in + ((if x == y then 1 else 0):: stack', st, input, output) + | NEQ -> let y :: x :: stack' = stack in + ((if x <> y then 1 else 0):: stack', st, input, output) + | AND -> let y :: x :: stack' = stack in + ((if (x <> 0) && (y <> 0) then 1 else 0):: stack', st, input, output) + | OR -> let y :: x :: stack' = stack in + ((if (x <> 0) || (y <> 0) then 1 else 0):: stack', st, input, output) ) in let (_, _, _, output) = @@ -72,8 +103,19 @@ module Compile = let rec compile = function | Var x -> [LD x] | Const n -> [PUSH n] - | Add (x, y) -> (compile x) @ (compile y) @ [ADD] - | Mul (x, y) -> (compile x) @ (compile y) @ [MUL] + | Binop ("+", x, y) -> (compile x) @ (compile y) @ [ADD] + | Binop ("-", x, y) -> (compile x) @ (compile y) @ [SUB] + | Binop ("*", x, y) -> (compile x) @ (compile y) @ [MUL] + | Binop ("/", x, y) -> (compile x) @ (compile y) @ [DIV] + | Binop ("%", x, y) -> (compile x) @ (compile y) @ [MOD] + | Binop ("<", x, y) -> (compile x) @ (compile y) @ [LT] + | Binop ("<=", x, y) -> (compile x) @ (compile y) @ [LE] + | Binop (">", x, y) -> (compile x) @ (compile y) @ [GT] + | Binop (">=", x, y) -> (compile x) @ (compile y) @ [GE] + | Binop ("==", x, y) -> (compile x) @ (compile y) @ [EQ] + | Binop ("!=", x, y) -> (compile x) @ (compile y) @ [NEQ] + | Binop ("&&", x, y) -> (compile x) @ (compile y) @ [AND] + | Binop ("!!", x, y) -> (compile x) @ (compile y) @ [OR] end @@ -99,4 +141,3 @@ module Compile = end end - diff --git a/src/X86.ml b/src/X86.ml index 9f0544af..16d75bb7 100644 --- a/src/X86.ml +++ b/src/X86.ml @@ -11,96 +11,143 @@ let [|eax; ebx; ecx; esi; edi; edx; esp; ebp|] = Array.mapi (fun i _ -> R i) reg type instr = | Add of opnd * opnd | Mul of opnd * opnd +| Sub of opnd * opnd +| Div of opnd * opnd +| Mod of opnd * opnd +| Cmp of opnd * opnd +| Setl +| Setle +| Setg +| Setge +| Sete +| Setne +| Xor of opnd * opnd +| And of opnd * opnd +| Or of opnd * opnd | Mov of opnd * opnd | Push of opnd | Pop of opnd | Call of string +| Movzbl +| Cdq | Ret -let to_string buf code = +let to_string buf code = let instr = let opnd = function | R i -> regs.(i) | S i -> Printf.sprintf "%d(%%ebp)" (-i * 4) | L i -> Printf.sprintf "$%d" i - | M s -> s + | M s -> s in function - | Add (x, y) -> Printf.sprintf "addl\t%s,%s" (opnd x) (opnd y) - | Mul (x, y) -> Printf.sprintf "imull\t%s,%s" (opnd x) (opnd y) - | Mov (x, y) -> Printf.sprintf "movl\t%s,%s" (opnd x) (opnd y) - | Push x -> Printf.sprintf "pushl\t%s" (opnd x) - | Pop x -> Printf.sprintf "popl\t%s" (opnd x) - | Call x -> Printf.sprintf "call\t%s" x - | Ret -> "ret" + | Add (x, y) -> Printf.sprintf "addl\t%s,\t%s" (opnd x) (opnd y) + | Sub (x, y) -> Printf.sprintf "subl\t%s,\t%s" (opnd x) (opnd y) + | Mul (x, y) -> Printf.sprintf "imull\t%s,\t%s" (opnd x) (opnd y) + | Div (x, y) -> Printf.sprintf "idivl\t%s" (opnd x) + + | Cmp (x, y) -> Printf.sprintf "cmp\t%s,\t%s" (opnd x) (opnd y) + | Setl -> "setl\t%al" + | Setle -> "setle\t%al" + | Setg -> "setg\t%al" + | Setge -> "setge\t%al" + | Sete -> "sete\t%al" + | Setne -> "setne\t%al" + + | Xor (x, y) -> Printf.sprintf "xorl\t%s,\t%s" (opnd x) (opnd y) + | Or (x, y) -> Printf.sprintf "orl\t%s,\t%s" (opnd x) (opnd y) + | And (x, y) -> Printf.sprintf "andl\t%s,\t%s" (opnd x) (opnd y) + + | Mov (x, y) -> Printf.sprintf "movl\t%s,\t%s" (opnd x) (opnd y) + | Push x -> Printf.sprintf "pushl\t%s" (opnd x) + | Pop x -> Printf.sprintf "popl\t%s" (opnd x) + | Call x -> Printf.sprintf "call\t%s" x + + | Movzbl -> "movzbl\t%al,\t%edx" + | Cdq -> "cdq" + + | Ret -> "ret" + in - let out s = - Buffer.add_string buf "\t"; - Buffer.add_string buf s; - Buffer.add_string buf "\n" + let out s = + Buffer.add_string buf "\t"; + Buffer.add_string buf s; + Buffer.add_string buf "\n" in List.iter (fun i -> out @@ instr i) code - + module S = Set.Make (String) - + class env = object (this) val locals = S.empty val depth = 0 - + method allocate = function - | [] -> this, R 0 + | [] -> this, R 1 | R i :: _ when i < nregs - 1 -> this, R (i+1) | S i :: _ -> {< depth = max depth (i+1) >}, S (i+1) - | _ -> {< depth = max depth 1 >}, S 1 - + | _ -> {< depth = max depth 1 >}, S 1 + method local x = {< locals = S.add x locals >} method get_locals = S.elements locals method get_depth = depth end - + +let comparator x y cmp = + [Cmp (x, y); cmp; Movzbl] + let rec sint env prg sstack = match prg with | [] -> env, [], [] | i :: prg' -> - let env, code, sstack' = + let env, code, sstack' = match i with - | PUSH n -> + | PUSH n -> let env', s = env#allocate sstack in env', [Mov (L n, s)], s :: sstack - | LD x -> + | LD x -> let env' = env#local x in let env'', s = env'#allocate sstack in - env'', [Mov (M x, s)], s :: sstack + env'', [Mov (M x, edx); Mov (edx, s)], s :: sstack | ST x -> let env' = env#local x in let s :: sstack' = sstack in - env', [Mov (s, M x)], sstack' - | READ -> + env', [Mov (s, edx); Mov (edx, M x)], sstack' + | READ -> env, [Call "lread"], [eax] - | WRITE -> - env, [Push eax; Call "lwrite"; Pop edx], [] - | _ -> + | WRITE -> + env, [Push (R 1); Call "lwrite"; Pop (R 1)], [] + | _ -> let x::(y::_ as sstack') = sstack in (fun op -> - match x, y with - | S _, S _ -> env, [Mov (y, edx); op x edx; Mov (edx, y)], sstack' - | _ -> env, [op x y], sstack' + env, [Mov (y, edx)] @ op x edx @ [ Mov (edx, y)], sstack' + ) + (match i with + | ADD -> fun x y -> [Add (x, y)] + | MUL -> fun x y -> [Mul (x, y)] + | SUB -> fun x y -> [Sub (x, y)] + | DIV -> fun x y -> [Mov (y, eax); Cdq; Div (x, y); Mov (eax, edx)] + | MOD -> fun x y -> [Mov (y, eax); Cdq; Div (x, y);] + | LT -> fun x y -> comparator x y Setl + | LE -> fun x y -> comparator x y Setle + | GT -> fun x y -> comparator x y Setg + | GE -> fun x y -> comparator x y Setge + | EQ -> fun x y -> comparator x y Sete + | NEQ -> fun x y -> comparator x y Setne + | AND -> fun x y -> [Xor (eax, eax); Cmp (y, eax); Setne; Mov (x, edx); Mul (eax, edx); Xor(eax, eax); Cmp(edx, eax); Setne; Mov (eax, y)] + | OR -> fun x y -> [Xor (eax, eax); Or (x, y); Cmp (y, eax); Setne; Mov (eax, y)] ) - (match i with - | MUL -> fun x y -> Mul (x, y) - | ADD -> fun x y -> Add (x, y) - ) in let env, code', sstack'' = sint env prg' sstack' in env, code @ code', sstack'' - -let compile p = + +let compile p = let env, code, [] = sint (new env) (Compile.Program.compile p) [] in let buf = Buffer.create 1024 in let out s = Buffer.add_string buf s in out "\t.data\n"; - List.iter (fun x -> out (Printf.sprintf "%s:\t.int 0\n" x)) + List.iter (fun x -> out (Printf.sprintf "%s:\t.int 0\n" x)) env#get_locals; out "\t.text\n"; out "\t.globl\tmain\n"; @@ -111,9 +158,10 @@ let compile p = to_string buf code; out "\tmovl\t%ebp,%esp\n"; out "\tpopl\t%ebp\n"; + out "\txorl\t%eax,%eax\n"; out "\tret\n"; Buffer.contents buf - + let build stmt name = let outf = open_out (Printf.sprintf "%s.s" name) in Printf.fprintf outf "%s" (compile stmt);