diff --git a/rc.byte b/rc.byte new file mode 120000 index 00000000..f5dacbdf --- /dev/null +++ b/rc.byte @@ -0,0 +1 @@ +/home/sl0n/Documents/DvlpngLnggPrcsss/eltech_compilers/_build/src/rc.byte \ No newline at end of file diff --git a/rc.native b/rc.native new file mode 120000 index 00000000..d40d8b8e --- /dev/null +++ b/rc.native @@ -0,0 +1 @@ +/home/sl0n/Documents/DvlpngLnggPrcsss/eltech_compilers/_build/src/rc.native \ No newline at end of file diff --git a/regression/Makefile b/regression/Makefile index bbecbbd4..30a20692 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=test002 test012 test013 test001 -# 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/regression/test002 b/regression/test002 new file mode 100755 index 00000000..f2b3dadd Binary files /dev/null and b/regression/test002 differ diff --git a/regression/test002.log b/regression/test002.log new file mode 100644 index 00000000..c87a5cf3 --- /dev/null +++ b/regression/test002.log @@ -0,0 +1 @@ +> > 5 diff --git a/regression/test002.s b/regression/test002.s new file mode 100644 index 00000000..b50bd318 --- /dev/null +++ b/regression/test002.s @@ -0,0 +1,31 @@ + .data +x: .int 0 +y: .int 0 +z: .int 0 + .text + .globl main +main: + pushl %ebp + movl %esp,%ebp + subl $0,%esp + call lread + movl %eax,x + call lread + movl %eax,y + movl y,%eax + movl y,%ebx + movl %eax,%edx + imull %ebx,%eax + movl %edx,%eax + movl %eax,z + movl x,%eax + movl z,%ebx + movl %eax,%edx + addl %ebx,%eax + movl %edx,%eax + pushl %eax + call lwrite + popl %edx + movl %ebp,%esp + popl %ebp + ret diff --git a/runtime/runtime.o b/runtime/runtime.o new file mode 100644 index 00000000..ea3478ab Binary files /dev/null and b/runtime/runtime.o differ diff --git a/src/Driver.ml b/src/Driver.ml index 5c8e0b34..d8d009b5 100644 --- a/src/Driver.ml +++ b/src/Driver.ml @@ -3,17 +3,17 @@ open Expr open Stmt open Ostap -let parse filename = +let parse filename = let s = Util.read filename in - Util.parse - (object - inherit Matcher.t s - inherit Util.Lexers.ident ["read"; "write"; "skip"] s + Util.parse + (object + inherit Matcher.t s + inherit Util.Lexers.ident ["read"; "write"; "skip"; "if"; "then"; "else"; "fi"; "while"; "do"; "od"; "for"; "elif"; "repeat"; "until"] s inherit Util.Lexers.decimal s inherit Util.Lexers.skip [ Matcher.Skip.whitespaces " \t\n"; - Matcher.Skip.lineComment "--"; - Matcher.Skip.nestedComment "(*" "*)" + Matcher.Skip.lineComment "--"; + Matcher.Skip.nestedComment "(*" "*)" ] s end) (ostap (!(Stmt.parse) -EOF)) @@ -25,27 +25,29 @@ let main = let to_compile = not (interpret || stack) in let infile = Sys.argv.(if not to_compile then 2 else 1) in match parse infile with + | `Ok prog -> if to_compile - then + then let basename = Filename.chop_suffix infile ".expr" in ignore @@ X86.build prog basename - else - let rec read acc = - try - let r = read_int () in - Printf.printf "> "; - read (acc @ [r]) - with End_of_file -> acc - in - let input = read [] in - let output = - if interpret - then Interpret.Program.eval prog input - else StackMachine.Interpret.run (StackMachine.Compile.Program.compile prog) input - in - List.iter (fun i -> Printf.printf "%d\n" i) output - | `Fail er -> Printf.eprintf "Syntax error: %s\n" er - with Invalid_argument _ -> - Printf.printf "Usage: rc [-i] \n" + else + let rec read acc = + try + let r = read_int () in + Printf.printf "> "; + read (acc @ [r]) + with End_of_file -> acc + in + let input = read [] in + let output = + if interpret + then Interpret.Program.eval prog input + else StackMachine.Interpret.run (StackMachine.Compile.Program.compile prog) input + in + List.iter (fun i -> Printf.printf "%d\n" i) output + | `Fail er -> Printf.eprintf "Syntax error: %s\n" er + with Invalid_argument _ -> + Printf.printf "Usage: rc [-i | -s] \n"; +Printf.printf "Example: cat test001.input | .././rc.native -s test001.expr\n" diff --git a/src/Interpret.ml b/src/Interpret.ml index 9f863d55..f5ba4bee 100644 --- a/src/Interpret.ml +++ b/src/Interpret.ml @@ -13,7 +13,17 @@ module Expr = | Const z -> z | Add (x, y) -> eval' x + eval' y | Mul (x, y) -> eval' x * eval' y - + | Sub (x, y) -> eval' x - eval' y + | Div (x, y) -> eval' x / eval' y + | Mod (x, y) -> eval' x mod eval' y + | And (x, y) -> if( (eval' x) == 1 && (eval' y) == 1) then 1 else 0 + | Or (x, y) -> if( (eval' x) == 0 && (eval' y) == 0) then 0 else 1 + | Equals (x, y) -> if( (eval' x) == (eval' y)) then 1 else 0 + | NotEquals (x, y) -> if( (eval' x) == (eval' y)) then 0 else 1 + | Greater (x, y) -> if( (eval' x) > (eval' y)) then 1 else 0 + | Less (x, y) -> if( (eval' x) < (eval' y)) then 1 else 0 + | GreaterEquals (x, y) -> if( (eval' x) < (eval' y)) then 0 else 1 + | LessEquals (x, y) -> if( (eval' x) > (eval' y)) then 0 else 1 end (* Interpreter for statements *) @@ -30,8 +40,8 @@ module Stmt = | 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) + 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 diff --git a/src/Language.ml b/src/Language.ml index 96ac3e01..70c1d367 100644 --- a/src/Language.ml +++ b/src/Language.ml @@ -1,21 +1,55 @@ +open Ostap.Util + (* AST for expressions *) module Expr = struct type t = - | Var of string - | Const of int - | Add of t * t - | Mul of t * t + | Var of string + | Const of int + | Add of t * t + | Mul of t * t + | Sub of t * t + | Div of t * t + | Mod of t * t + | And of t * t + | Or of t * t + | Equals of t * t + | NotEquals of t * t + | Greater of t * t + | Less of t * t + | GreaterEquals of t * t + | LessEquals of t * t + + + + let rec parser_ s = + expr id + [| + `Nona , [ostap ("||"), (fun x y -> Or (x, y))]; + `Nona , [ostap ("&&"), (fun x y -> And (x, y))]; + `Nona , [ostap ("=="), (fun x y -> Equals (x, y)); + ostap ("!="), (fun x y -> NotEquals (x, y)); + ostap (">"), (fun x y -> Greater (x, y)); + ostap ("<"), (fun x y -> Less (x, y)); + ostap (">="), (fun x y -> GreaterEquals (x, y)); + ostap ("<="), (fun x y -> LessEquals (x, y));]; + + `Lefta , [ostap ("+"), (fun x y -> Add (x, y)); + ostap ("-"), (fun x y -> Sub (x, y))]; + + `Lefta , [ostap ("*"), (fun x y -> Mul (x, y)); + ostap ("/"), (fun x y -> Div (x, y)); + ostap ("%"), (fun x y -> Mod (x, y))] + |] + primary s + and + ostap ( + primary: + n:DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" parser_ -")") - ostap ( - parse: x:mull "+" y:parse {Add (x,y)} | mull; - mull : x:prim "*" y:mull {Mul (x,y)} | prim; - prim : - n:DECIMAL {Const n} - | e:IDENT {Var e} - | -"(" parse -")" - ) end @@ -30,12 +64,12 @@ module Stmt = | Write of Expr.t | Seq of t * t - let expr = Expr.parse + let expr_parser = Expr.parser_ ostap ( - simp: x:IDENT ":=" e:expr {Assign (x, e)} + simp: x:IDENT ":=" e:expr_parser {Assign (x, e)} | %"read" "(" x:IDENT ")" {Read x} - | %"write" "(" e:expr ")" {Write e} + | %"write" "(" e:expr_parser ")" {Write e} | %"skip" {Skip}; parse: s:simp ";" d:parse {Seq (s,d)} | simp diff --git a/src/StackMachine.ml b/src/StackMachine.ml index 870537a4..1b586735 100644 --- a/src/StackMachine.ml +++ b/src/StackMachine.ml @@ -10,7 +10,17 @@ module Instr = | ST of string | ADD | MUL - + | SUB + | DIV + | MOD + | AND + | OR + | EQUALS + | NOT_EQUALS + | GREATER + | LESS + | GREATER_EQUALS + | LESS_EQUALS end module Program = @@ -26,31 +36,50 @@ module Interpret = open Instr open Interpret.Stmt + + + + let run prg input = - let rec run' prg ((stack, st, input, output) as conf) = + let rec run' ((prg,stack, st, input, output) as conf) = match prg with | [] -> conf | i :: prg' -> - run' prg' ( + run'( match i with | READ -> let z :: input' = input in - (z :: stack, st, input', output) - | WRITE -> let z :: stack' = stack in - (stack', st, input, output @ [z]) - | PUSH n -> (n :: stack, st, input, output) - | 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', + (prg',z :: stack, st, input', output) + | WRITE -> let h :: stack' = stack in + (prg',stack', st, input, output @ [h]) + | PUSH n -> (prg',n :: stack, st, input, output) + | LD x -> (prg',st x :: stack, st, input, output) + | ST x -> let h :: stack' = stack in + (prg',stack', update st x h, input, output) + + | _ -> let y :: x :: stack'' = stack in + (prg',(match i with + | ADD -> ( + ) + | MUL -> ( * ) + | SUB -> ( - ) + | DIV -> ( / ) + | MOD -> ( mod ) + | AND -> ( fun a b -> if (a == 1) && (b == 1) then 1 else 0) + | OR -> ( fun a b -> if (a == 0) && (b == 0) then 0 else 1) + | EQUALS -> ( fun a b -> if (a == b) then 1 else 0) + | NOT_EQUALS -> ( fun a b -> if (a == b) then 0 else 1) + | GREATER -> ( fun a b -> if (a > b) then 1 else 0) + | LESS -> ( fun a b -> if (a < b) then 1 else 0) + | GREATER_EQUALS -> ( fun a b -> if (a < b) then 0 else 1) + | LESS_EQUALS -> ( fun a b -> if (a > b) then 0 else 1) + ) x y :: stack'', st, input, output ) ) in - let (_, _, _, output) = - run' prg ([], + let (_,_, _, _, output) = + run' (prg,[], (fun _ -> failwith "undefined variable"), input, [] @@ -69,12 +98,24 @@ module Compile = open Language.Expr - let rec compile = function + let rec compile = + let twoargs op (x,y) = (compile x) @ (compile y) @ [op] in + 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] - + | Add (x, y) -> twoargs ADD (x, y) + | Mul (x, y) -> twoargs MUL (x, y) + | Sub (x, y) -> twoargs SUB (x, y) + | Div (x, y) -> twoargs DIV (x, y) + | Mod (x, y) -> twoargs MOD (x, y) + | And (x, y) -> twoargs AND (x, y) + | Or (x, y) -> twoargs OR (x, y) + | Equals (x, y) -> twoargs EQUALS (x, y) + | NotEquals (x, y) -> twoargs NOT_EQUALS (x, y) + | Greater (x, y) -> twoargs GREATER (x, y) + | Less (x, y) -> twoargs LESS (x, y) + | GreaterEquals (x, y) -> twoargs GREATER_EQUALS (x, y) + | LessEquals (x, y) -> twoargs LESS_EQUALS (x, y) end module Stmt = diff --git a/src/X86.ml b/src/X86.ml index 9f0544af..b3c11e29 100644 --- a/src/X86.ml +++ b/src/X86.ml @@ -6,16 +6,31 @@ type opnd = R of int | S of int | L of int | M of string let regs = [|"%eax"; "%ebx"; "%ecx"; "%esi"; "%edi"; "%edx"; "%esp"; "%ebp"|] let nregs = Array.length regs - 3 + +let [|al; dl|] = [|"%al"; "%dl"|] + let [|eax; ebx; ecx; esi; edi; edx; esp; ebp|] = Array.mapi (fun i _ -> R i) regs type instr = | Add of opnd * opnd +| Sub of opnd * opnd +| Div of opnd +| Cltd | Mul of opnd * opnd | Mov of opnd * opnd | Push of opnd | Pop of opnd | Call of string | Ret +| AndBin of opnd *opnd +| OrBin of opnd *opnd +| Cmp of opnd *opnd +| Setg of string +| Setl of string +| Sete of string +| Setne of string +| Setge of string +| Setle of string let to_string buf code = let instr = @@ -33,6 +48,18 @@ let to_string buf code = | Pop x -> Printf.sprintf "popl\t%s" (opnd x) | Call x -> Printf.sprintf "call\t%s" x | Ret -> "ret" + | Cltd -> "cltd" + | Sub (x, y) -> Printf.sprintf "subl\t%s,%s" (opnd x) (opnd y) + | Div x -> Printf.sprintf "idiv\t%s" (opnd x) + | AndBin (x, y) -> Printf.sprintf "andl\t%s,%s" (opnd x) (opnd y) + | OrBin (x, y) -> Printf.sprintf "orl\t%s,%s" (opnd x) (opnd y) + | Cmp (x, y) -> Printf.sprintf "cmpl\t%s,%s" (opnd x) (opnd y) + | Setg x -> Printf.sprintf "setg\t%s" x + | Setl x -> Printf.sprintf "setl\t%s" x + | Sete x -> Printf.sprintf "sete\t%s" x + | Setne x -> Printf.sprintf "setne\t%s" x + | Setge x -> Printf.sprintf "setge\t%s" x + | Setle x -> Printf.sprintf "setle\t%s" x in let out s = Buffer.add_string buf "\t"; @@ -81,16 +108,32 @@ let rec sint env prg sstack = | WRITE -> env, [Push eax; Call "lwrite"; Pop edx], [] | _ -> - 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' - ) + + let x::(y::_ as sstack') = sstack in + let andop = [Mov (y, edx); AndBin (y, edx); (*compare y with self*) + Mov (L 0, edx); Setne dl; (*put result in edx*) + Mov (x, eax); AndBin (x, eax); (*compare x with self*) + Mov (L 0, eax); Setne al; (*put result in eax*) + AndBin (eax, edx); Mov (L 0, edx); Setne dl; (*compare eax with edx and put result in edx*) +Mov (edx, y)] in + let short codearr = env, [Mov (y, edx)] @ codearr @ [Mov (edx, y)], sstack' in + let shorteq setop = short ([Cmp(x, y); Mov (L 0, edx)] @ setop @ [Mov (edx, y)]) in (match i with - | MUL -> fun x y -> Mul (x, y) - | ADD -> fun x y -> Add (x, y) - ) + (* | MUL -> fun (x, y) -> Mul (x, y) *) + | MUL -> short [Mul(x,y)] + | ADD -> short [Add (x, y)] + | DIV -> env, [Mov (y, eax); Cltd; Div x; Mov (eax, y)], sstack' + | SUB -> short [Sub(x, edx)] + | MOD -> env, [Mov (y, eax); Cltd; Div x; Mov (edx, y)], sstack' + | OR -> short [OrBin(x, edx); Mov (L 0, edx); Setne dl] + | AND -> env, andop, sstack' + | EQUALS -> shorteq [Sete dl] + | NOT_EQUALS -> shorteq [Setne dl] + | GREATER -> shorteq [Setg dl] + | LESS -> shorteq [Setl dl] + | GREATER_EQUALS -> shorteq [Setge dl] + | LESS_EQUALS -> shorteq [Setle dl] + ) in let env, code', sstack'' = sint env prg' sstack' in env, code @ code', sstack''