diff --git a/Driver.ml b/Driver.ml new file mode 100644 index 00000000..8d902f03 --- /dev/null +++ b/Driver.ml @@ -0,0 +1,60 @@ +open Language +open Expr +open Stmt +open Ostap +open GT + +ostap ( + expr : expr "+" expr +) + +let rec parse s = + expr id + [| + left , [ostap ("+"), (fun x y -> `Add (x, y)); ostap ("-"), (fun x y -> `Sub (x, y))]; + left , [ostap ("*"), (fun x y -> `Mul (x, y)); ostap ("/"), (fun x y -> `Div (x, y))] + |] + primary + s + and ostap (primary: n: DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" parse -")") + +ostap ( + simp: x:IDENT ":=" e:expr {Assign (x, e)} + | %"read" "(" x:IDENT ")" {Read x} + | %"write" "(" e:expr ")" {Write e} + | %"skip" {Skip}; + + stmt: s:simp ";" d:stmt {Seq (s,d)} + | simp +) + +let parse filename = + let s = Util.read filename in + Util.parse + (object + inherit Matcher.t s + inherit Util.Lexers.ident ["read"; "write"; "skip"] s + inherit Util.Lexers.decimal s + inherit Util.Lexers.skip [ + Matcher.Skip.whitespaces " \t\n" + ] s + end) + (ostap (stmt -EOF)) + +let _ = + match Sys.argv with + | [|_; filename|] -> + match parse filename with + | `Ok stmt -> + let basename = Filename.chop_suffix filename ".expr" in + let text = X86.compile stmt in + Printf.printf "%s\n" (show (Stmt.t) stmt); + let asm = basename ^ ".s" in + let ouch = open_out asm in + Printf.fprintf ouch "%s\n" text; + close_out ouch; + let runtime = try Sys.getenv "RUNTIME" with _ -> "../runtime" in + ignore @@ Sys.command (Printf.sprintf "gcc -m32 -o %s %s/runtime.o %s.s" basename runtime basename) + | `Fail e -> Printf.eprintf "Parsing error: %s\n" e diff --git a/Driver.ml~ b/Driver.ml~ new file mode 100644 index 00000000..b517c2ad --- /dev/null +++ b/Driver.ml~ @@ -0,0 +1,59 @@ +open Language +open Expr +open Stmt +open Ostap +open GT + +ostap ( + expr : expr "+" expr +) + +ostap ( + expr: x:mull "+" y:expr {Add (x,y)} + | mull; + mull: x:prim "*" y:mull {Mul (x,y)} + | prim; + prim: n:DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" expr -")" +(* | "(" e:expr ")" {e} *) +) + +ostap ( + simp: x:IDENT ":=" e:expr {Assign (x, e)} + | %"read" "(" x:IDENT ")" {Read x} + | %"write" "(" e:expr ")" {Write e} + | %"skip" {Skip}; + + stmt: s:simp ";" d:stmt {Seq (s,d)} + | simp +) + +let parse filename = + let s = Util.read filename in + Util.parse + (object + inherit Matcher.t s + inherit Util.Lexers.ident ["read"; "write"; "skip"] s + inherit Util.Lexers.decimal s + inherit Util.Lexers.skip [ + Matcher.Skip.whitespaces " \t\n" + ] s + end) + (ostap (stmt -EOF)) + +let _ = + match Sys.argv with + | [|_; filename|] -> + match parse filename with + | `Ok stmt -> + let basename = Filename.chop_suffix filename ".expr" in + let text = X86.compile stmt in + Printf.printf "%s\n" (show (Stmt.t) stmt); + let asm = basename ^ ".s" in + let ouch = open_out asm in + Printf.fprintf ouch "%s\n" text; + close_out ouch; + let runtime = try Sys.getenv "RUNTIME" with _ -> "../runtime" in + ignore @@ Sys.command (Printf.sprintf "gcc -m32 -o %s %s/runtime.o %s.s" basename runtime basename) + | `Fail e -> Printf.eprintf "Parsing error: %s\n" e diff --git a/Makefile b/Makefile index d39a3d3e..2cdeea41 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ MKDIR ?= mkdir -vp CP ?= cp -OB=ocamlbuild -cflag -g -no-hygiene -use-ocamlfind -plugin-tag "package(str)" -classic-display +OB=ocamlbuild -cflag -g -no-hygiene -use-ocamlfind -plugin-tag "package(str)" -classic-display ifdef OBV OB += -verbose 6 endif diff --git a/Makefile~ b/Makefile~ new file mode 100644 index 00000000..40650142 --- /dev/null +++ b/Makefile~ @@ -0,0 +1,25 @@ +MKDIR ?= mkdir -vp +CP ?= cp + +OB=ocamlbuild -cflag -g -no-hygiene -use-ocmalfind -plugin-tag "package(str)" -classic-display +ifdef OBV +OB += -verbose 6 +endif + +BYTE_TARGETS=src/rc.byte +NATIVE_TARGETS=src/rc.native + +.PHONY: all clean runtime + +.DEFAULT_GOAL: all + +all: main runtime + +runtime: + cd runtime && make all && cd .. + +main: + $(OB) -Is src $(BYTE_TARGETS) $(NATIVE_TARGETS) + +clean: + cd runtime && make clean && cd .. && $(RM) -r _build *.log *.native *.byte diff --git a/_build/_digests b/_build/_digests new file mode 100644 index 00000000..39af2d0f --- /dev/null +++ b/_build/_digests @@ -0,0 +1,9 @@ +"Resource: /home/roma/\208\151\208\176\208\179\209\128\209\131\208\183\208\186\208\184/eltech_compilers/src/StackMachine.ml": "i17\002hfm$\158 \221\186\130\181\134\127" +"Rule: ocaml dependencies ml (%=src/rc )": "\000\2340\188\135\185\204\229\241XR\186\165\222\bT" +"Rule: ocaml dependencies ml (%=src/Driver )": "\190\250\150\140r90\029&ee\136g\004\147U" +"Rule: ocaml dependencies ml (%=src/Interpret )": "\163*\147\246C\144}\246R2\206\"\132\236~z" +"Resource: /home/roma/\208\151\208\176\208\179\209\128\209\131\208\183\208\186\208\184/eltech_compilers/src/Language.ml": "e?R\221\234\1277\156\020eR\215\nE\254\233" +"Resource: /home/roma/\208\151\208\176\208\179\209\128\209\131\208\183\208\186\208\184/eltech_compilers/src/Interpret.ml": "\20969\195\2154\202\150M\143v\185\\\245\236Y" +"Resource: /home/roma/\208\151\208\176\208\179\209\128\209\131\208\183\208\186\208\184/eltech_compilers/src/rc.ml": "\1925m\003\2304M\252\t\212\022\151\002\167\151\245" +"Resource: /home/roma/\208\151\208\176\208\179\209\128\209\131\208\183\208\186\208\184/eltech_compilers/src/Driver.ml": "F95\195\227\028A^\151:\225F\186\153vL" +"Rule: ocaml dependencies ml (%=src/StackMachine )": "T\205\210?\214\132\232\240\216\0074\196p\153\228v" diff --git a/_build/_log b/_build/_log new file mode 100644 index 00000000..ff83643e --- /dev/null +++ b/_build/_log @@ -0,0 +1,2 @@ +### Starting build. +# Compilation unsuccessful. diff --git a/_build/ocamlc.where b/_build/ocamlc.where new file mode 100644 index 00000000..dd25148a --- /dev/null +++ b/_build/ocamlc.where @@ -0,0 +1 @@ +/usr/lib/ocaml diff --git a/_build/src/Driver.ml b/_build/src/Driver.ml new file mode 100644 index 00000000..1cd1b475 --- /dev/null +++ b/_build/src/Driver.ml @@ -0,0 +1,53 @@ +open Language +open Expr +open Stmt +open Ostap + +let parse filename = + let s = Util.read filename in + Util.parse + (object + inherit Matcher.t s + inherit Util.Lexers.ident ["read"; "write"; "skip"; + "if"; "then"; "else"; "elif"; "fi"; + "for"; "while"; "do"; "od"; "repeat"; "until"] s + inherit Util.Lexers.decimal s + inherit Util.Lexers.skip [ + Matcher.Skip.whitespaces " \t\n"; + Matcher.Skip.lineComment "--"; + Matcher.Skip.nestedComment "(*" "*)" + ] s + end) + (ostap (!(Stmt.parse) -EOF)) + +let main = + try + let interpret = Sys.argv.(1) = "-i" in + let stack = Sys.argv.(1) = "-s" in + 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 + 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" + diff --git a/_build/src/Driver.ml.depends b/_build/src/Driver.ml.depends new file mode 100644 index 00000000..507a709b --- /dev/null +++ b/_build/src/Driver.ml.depends @@ -0,0 +1 @@ +src/Driver.ml: Array Expr Filename Interpret Language List Matcher Ostap Printf StackMachine Stmt Sys Util X86 diff --git a/_build/src/Interpret.ml b/_build/src/Interpret.ml new file mode 100644 index 00000000..e7797803 --- /dev/null +++ b/_build/src/Interpret.ml @@ -0,0 +1,95 @@ +open Language + +(* Interpreter for expressions *) +module Expr = + struct + + open Expr + + 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 + | Sub (x, y) -> eval' x - eval' y + | Div (x, y) -> eval' x / eval' y + | Mod (x, y) -> eval' 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 *) +module Stmt = + struct + + open Stmt + + (* 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) + | Write e -> (st, input, output @ [Expr.eval e st]) + | Seq (s1, s2) -> eval s1 conf |> eval s2 + | If (expr, then_part, else_part) -> + if (Expr.eval expr st) != 0 + then eval then_part conf + else eval else_part conf + | While (expr, value) -> + let rec loop expr' value' ( (st', _, _) as conf') = + if (Expr.eval expr' st') != 0 + then loop expr' value' (eval value' conf') + else conf' + in + loop expr value conf + | Until (value, expr) -> + let rec loop expr' value' conf' = + let (st_new, _, _) as conf_new = eval value' conf' in + if (Expr.eval expr' st_new) == 0 + then loop expr' value' conf_new + else conf_new + in + loop expr value c + end + +module Program = + struct + + let eval p input = + let (_, _, output) = + Stmt.eval p ((fun _ -> failwith "undefined variable"), input, []) + in + output + + end diff --git a/_build/src/Interpret.ml.depends b/_build/src/Interpret.ml.depends new file mode 100644 index 00000000..39526c5a --- /dev/null +++ b/_build/src/Interpret.ml.depends @@ -0,0 +1 @@ +src/Interpret.ml: Expr Language Stmt diff --git a/_build/src/Language.ml b/_build/src/Language.ml new file mode 100644 index 00000000..34286838 --- /dev/null +++ b/_build/src/Language.ml @@ -0,0 +1,97 @@ +open Ostap.Util + +module Expr = + struct + + type 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 parse 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))] + |] + expr' s + and + ostap ( + expr': + n:DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" parse -")") + end + +(* AST statements/commands *) +module Stmt = + struct + + type t = + | Skip + | Assign of string * Expr.t + | Read of string + | Write of Expr.t + | Seq of t * t + | If of Expr.t * t * t + | While of Expr.t * t + | Until of t * Expr.t + + let expr = Expr.parse + + ostap ( + simp: x:IDENT ":=" e:expr {Assign (x, e)} + | %"read" "(" x:IDENT ")" {Read x} + | %"write" "(" e:expr ")" {Write e} + | %"skip" {Skip}; + | %"if" e:expr %"then" then_part:parse else_part:else_part_def? + %"fi" {If (exp, then_part, match else_part with None -> Skip | Some else_part -> else_part)} + | %"for" s1:parse "," e:expr "," s2:parse + %"do" s:parse %"od" {Seq (s1, While (e, Seq (s, s2)))} + | %"while" exp:expr + "do" value:parse %"od" {While (expr, value)} + | %"repeat" value:parse + "until" expr:expr {Until (value, expr)}; + else_part_def : + %"else" parse + | %"elif" expr:expr %"then" then_part:parse else_part:else_part_def? + {If (expr, then_part, match else_part with None -> Skip | Some else_part -> else_part)}; + parse: s:simp ";" d:parse {Seq (s,d)} | simp + ) + + end + +module Program = + struct + + type t = Stmt.t + + let parse = Stmt.parse + + end + diff --git a/_build/src/Language.ml.depends b/_build/src/Language.ml.depends new file mode 100644 index 00000000..4530096d --- /dev/null +++ b/_build/src/Language.ml.depends @@ -0,0 +1 @@ +src/Language.ml: diff --git a/_build/src/StackMachine.ml b/_build/src/StackMachine.ml new file mode 100644 index 00000000..6f852215 --- /dev/null +++ b/_build/src/StackMachine.ml @@ -0,0 +1,208 @@ +(* Stack Machine *) +module Instr = + struct + + type t = + | READ + | WRITE + | PUSH of int + | LD of string + | ST of string + | ADD + | MUL + | SUB + | DIV + | MOD + | AND + | OR + | EQUALS + | NOT_EQUALS + | GREATER + | LESS + | GREATER_EQUALS + | LESS_EQUALS + | LBL of int + | CJMP of int * string + | JMP of int + end + +module Program = + struct + + type t = Instr.t list + + end + +module Interpret = + struct + + open Instr + open Interpret.Stmt + + let rec findlb prg lb = + let nom::prg' = prg in + if nom = lb then prg' + else findlb prg' lb + + let run prg input = + let prg_full = prg in + + let rec run' prg ((stack, st, input, output) as conf) = + match prg with + | [] -> conf + | i :: prg' -> + run' prg' ( + 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) + | LBL _ -> (prg', stack, st, input, output) + | JMP l -> (findlb prg_full (LBL l), stack, st, input, output) + | CJMP (m, c) -> let nom::stack' = stack in + if (match c with + | "z" -> (nom = 0) + | "nz" -> (nom != 0)) + then (findlb prg_full (LBL m), stack', st, input, output) + else (prg', stack', st, input, output) + | _ -> let y :: x :: stack' = stack in + ((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, [], + (fun _ -> failwith "undefined variable"), + input, + [] + ) + in + output + end + +module Compile = + struct + + open Instr + let lblCounter = ref 0 + + module Expr = + struct + + open Language.Expr + + 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] + | Sub (x, y) -> (compile x) @ (compile y) @ [SUB] + | Div (x, y) -> (compile x) @ (compile y) @ [DIV] + | Mod (x, y) -> (compile x) @ (compile y) @ [MOD] + | And (x, y) -> (compile x) @ (compile y) @ [AND] + | Or (x, y) -> (compile x) @ (compile y) @ [OR] + | Equals (x, y) -> (compile x) @ (compile y) @ [EQUALS] + | NotEquals (x, y) -> (compile x) @ (compile y) @ [NOT_EQUALS] + | Greater (x, y) -> (compile x) @ (compile y) @ [GREATER] + | Less (x, y) -> (compile x) @ (compile y) @ [LESS] + | GreaterEquals (x, y) -> (compile x) @ (compile y) @ [GREATER_EQUALS] + | LessEquals (x, y) -> (compile x) @ (compile y) @ [LESS_EQUALS] + end + +class lbcounter = + object (this) + val mutable count = 0 + method add_lbs n = count <- (count + n) + method get_count = count + end + + module Stmt = + struct + + open Language.Stmt + + let get_next_label() = + incr lblCounter; + ".lbl"^string_of_int !lblCounter + + let rec compile lb = function + | Skip -> [] + | Assign (x, e) -> Expr.compile e @ [ST x] + | Read x -> [READ; ST x] + | Write e -> Expr.compile e @ [WRITE] + | Seq (l, r) -> compile lb l @ compile lb r + | op -> + lb#add_lbs 2; + let l1 = lb#get_count-1 in + let l2 = lb#get_count in + match op with + | If (exp, pt1, pt2) -> + Expr.compile exp @ + [CJMP (l1,"z")] @ + compile lb pt1 @ + [JMP l2] @ + [LBL l1] @ + compile lb pt2 @ + [LBL l2] + + | While (exp, pt) -> + [JMP l1] @ + [LBL l2] @ + compile lb pt @ + [LBL l1] @ + Expr.compile exp @ + [CJMP (l2, "nz")] + + | Until (pt, exp) -> + [LBL l1] @ + compile lb pt @ + Expr.compile exp @ + [CJMP (l1, "z")] + end + + module Program = + struct + + let compile = Stmt.compile (new lbcounter) + + end + + end + diff --git a/_build/src/StackMachine.ml.depends b/_build/src/StackMachine.ml.depends new file mode 100644 index 00000000..24a07def --- /dev/null +++ b/_build/src/StackMachine.ml.depends @@ -0,0 +1 @@ +src/StackMachine.ml: Interpret Language diff --git a/_build/src/rc.ml b/_build/src/rc.ml new file mode 100644 index 00000000..50265d80 --- /dev/null +++ b/_build/src/rc.ml @@ -0,0 +1 @@ +include Driver diff --git a/_build/src/rc.ml.depends b/_build/src/rc.ml.depends new file mode 100644 index 00000000..e867c951 --- /dev/null +++ b/_build/src/rc.ml.depends @@ -0,0 +1 @@ +src/rc.ml: Driver diff --git a/src/Driver.ml b/src/Driver.ml index 5c8e0b34..1cd1b475 100644 --- a/src/Driver.ml +++ b/src/Driver.ml @@ -8,7 +8,9 @@ let parse filename = Util.parse (object inherit Matcher.t s - inherit Util.Lexers.ident ["read"; "write"; "skip"] s + inherit Util.Lexers.ident ["read"; "write"; "skip"; + "if"; "then"; "else"; "elif"; "fi"; + "for"; "while"; "do"; "od"; "repeat"; "until"] s inherit Util.Lexers.decimal s inherit Util.Lexers.skip [ Matcher.Skip.whitespaces " \t\n"; diff --git a/src/Driver.ml~ b/src/Driver.ml~ new file mode 100644 index 00000000..b08cd9d3 --- /dev/null +++ b/src/Driver.ml~ @@ -0,0 +1,53 @@ +open Language +open Expr +open Stmt +open Ostap + +let parse filename = + let s = Util.read filename in + Util.parse + (object + inherit Matcher.t s + inherit Util.Lexers.ident ["read"; "write"; "skip"; + "if"; "then"; "else"; "elif"; "fi"; + "for"; "while"; "do"; "od"; "repeat"; "until"] s + inherit Util.Lexers.decimal s + inherit Util.Lexers.skip [ + Matcher.Skip.whitespaces " \t\n"; + Matcher.Skip.lineComment "--"; + Matcher.Skip.nestedComment "(*" "*)" + ] s + end) + (ostap (!(Stmt.sequence) -EOF)) + +let main = + try + let interpret = Sys.argv.(1) = "-i" in + let stack = Sys.argv.(1) = "-s" in + 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 + 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" + diff --git a/src/Interpret.ml b/src/Interpret.ml index 12c5dddb..e7797803 100644 --- a/src/Interpret.ml +++ b/src/Interpret.ml @@ -13,6 +13,34 @@ 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' 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 @@ -34,7 +62,25 @@ module Stmt = (update st x z, input', output) | Write e -> (st, input, output @ [Expr.eval e st]) | Seq (s1, s2) -> eval s1 conf |> eval s2 - + | If (expr, then_part, else_part) -> + if (Expr.eval expr st) != 0 + then eval then_part conf + else eval else_part conf + | While (expr, value) -> + let rec loop expr' value' ( (st', _, _) as conf') = + if (Expr.eval expr' st') != 0 + then loop expr' value' (eval value' conf') + else conf' + in + loop expr value conf + | Until (value, expr) -> + let rec loop expr' value' conf' = + let (st_new, _, _) as conf_new = eval value' conf' in + if (Expr.eval expr' st_new) == 0 + then loop expr' value' conf_new + else conf_new + in + loop expr value c end module Program = diff --git a/src/Interpret.ml~ b/src/Interpret.ml~ new file mode 100644 index 00000000..523348cd --- /dev/null +++ b/src/Interpret.ml~ @@ -0,0 +1,95 @@ +open Language + +(* Interpreter for expressions *) +module Expr = + struct + + open Expr + + 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 + | Sub (x, y) -> eval' x - eval' y + | Div (x, y) -> eval' x / eval' y + | Mod (x, y) -> eval' 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 *) +module Stmt = + struct + + open Stmt + + (* 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) + | Write e -> (st, input, output @ [Expr.eval e st]) + | Seq (s1, s2) -> eval s1 conf |> eval s2 + | If (expr, then_part, else_part) -> + if (Expr.eval expr st) != 0 + then eval then_part conf + else eval else_part conf + | While (expr, value) + let rec loop expr' value' ( (st', _, _) as conf') = + if (Expr.eval expr' st') != 0 + then loop expr' value' (eval value' conf') + else conf' + in + loop expr value conf + | Until (value, expr) -> + let rec loop expr' value' conf' = + let (st_new, _, _) as conf_new = eval value' conf' in + if (Expr.eval expr' st_new) == 0 + then loop expr' value' conf_new + else conf_new + in + loop expr value c + end + +module Program = + struct + + let eval p input = + let (_, _, output) = + Stmt.eval p ((fun _ -> failwith "undefined variable"), input, []) + in + output + + end diff --git a/src/Language.ml b/src/Language.ml index 96ac3e01..34286838 100644 --- a/src/Language.ml +++ b/src/Language.ml @@ -1,22 +1,51 @@ -(* AST for expressions *) +open Ostap.Util + 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 - 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 -")" - ) + let rec parse 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))] + |] + expr' s + and + ostap ( + expr': + n:DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" parse -")") end (* AST statements/commands *) @@ -29,6 +58,9 @@ module Stmt = | Read of string | Write of Expr.t | Seq of t * t + | If of Expr.t * t * t + | While of Expr.t * t + | Until of t * Expr.t let expr = Expr.parse @@ -37,7 +69,18 @@ module Stmt = | %"read" "(" x:IDENT ")" {Read x} | %"write" "(" e:expr ")" {Write e} | %"skip" {Skip}; - + | %"if" e:expr %"then" then_part:parse else_part:else_part_def? + %"fi" {If (exp, then_part, match else_part with None -> Skip | Some else_part -> else_part)} + | %"for" s1:parse "," e:expr "," s2:parse + %"do" s:parse %"od" {Seq (s1, While (e, Seq (s, s2)))} + | %"while" exp:expr + "do" value:parse %"od" {While (expr, value)} + | %"repeat" value:parse + "until" expr:expr {Until (value, expr)}; + else_part_def : + %"else" parse + | %"elif" expr:expr %"then" then_part:parse else_part:else_part_def? + {If (expr, then_part, match else_part with None -> Skip | Some else_part -> else_part)}; parse: s:simp ";" d:parse {Seq (s,d)} | simp ) diff --git a/src/Language.ml~ b/src/Language.ml~ new file mode 100644 index 00000000..34286838 --- /dev/null +++ b/src/Language.ml~ @@ -0,0 +1,97 @@ +open Ostap.Util + +module Expr = + struct + + type 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 parse 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))] + |] + expr' s + and + ostap ( + expr': + n:DECIMAL {Const n} + | e:IDENT {Var e} + | -"(" parse -")") + end + +(* AST statements/commands *) +module Stmt = + struct + + type t = + | Skip + | Assign of string * Expr.t + | Read of string + | Write of Expr.t + | Seq of t * t + | If of Expr.t * t * t + | While of Expr.t * t + | Until of t * Expr.t + + let expr = Expr.parse + + ostap ( + simp: x:IDENT ":=" e:expr {Assign (x, e)} + | %"read" "(" x:IDENT ")" {Read x} + | %"write" "(" e:expr ")" {Write e} + | %"skip" {Skip}; + | %"if" e:expr %"then" then_part:parse else_part:else_part_def? + %"fi" {If (exp, then_part, match else_part with None -> Skip | Some else_part -> else_part)} + | %"for" s1:parse "," e:expr "," s2:parse + %"do" s:parse %"od" {Seq (s1, While (e, Seq (s, s2)))} + | %"while" exp:expr + "do" value:parse %"od" {While (expr, value)} + | %"repeat" value:parse + "until" expr:expr {Until (value, expr)}; + else_part_def : + %"else" parse + | %"elif" expr:expr %"then" then_part:parse else_part:else_part_def? + {If (expr, then_part, match else_part with None -> Skip | Some else_part -> else_part)}; + parse: s:simp ";" d:parse {Seq (s,d)} | simp + ) + + end + +module Program = + struct + + type t = Stmt.t + + let parse = Stmt.parse + + end + diff --git a/src/StackMachine.ml b/src/StackMachine.ml index 870537a4..6f852215 100644 --- a/src/StackMachine.ml +++ b/src/StackMachine.ml @@ -10,7 +10,20 @@ module Instr = | ST of string | ADD | MUL - + | SUB + | DIV + | MOD + | AND + | OR + | EQUALS + | NOT_EQUALS + | GREATER + | LESS + | GREATER_EQUALS + | LESS_EQUALS + | LBL of int + | CJMP of int * string + | JMP of int end module Program = @@ -26,7 +39,14 @@ module Interpret = open Instr open Interpret.Stmt + let rec findlb prg lb = + let nom::prg' = prg in + if nom = lb then prg' + else findlb prg' lb + let run prg input = + let prg_full = prg in + let rec run' prg ((stack, st, input, output) as conf) = match prg with | [] -> conf @@ -41,16 +61,54 @@ module Interpret = | LD x -> (st x :: stack, st, input, output) | ST x -> let z :: stack' = stack in (stack', update st x z, input, output) + | LBL _ -> (prg', stack, st, input, output) + | JMP l -> (findlb prg_full (LBL l), stack, st, input, output) + | CJMP (m, c) -> let nom::stack' = stack in + if (match c with + | "z" -> (nom = 0) + | "nz" -> (nom != 0)) + then (findlb prg_full (LBL m), stack', st, input, output) + else (prg', stack', st, input, output) | _ -> let y :: x :: stack' = stack in - ((match i with ADD -> (+) | _ -> ( * )) x y :: stack', + ((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, [] @@ -63,6 +121,7 @@ module Compile = struct open Instr + let lblCounter = ref 0 module Expr = struct @@ -72,29 +131,76 @@ 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] - + | Add (x, y) -> (compile x) @ (compile y) @ [ADD] + | Mul (x, y) -> (compile x) @ (compile y) @ [MUL] + | Sub (x, y) -> (compile x) @ (compile y) @ [SUB] + | Div (x, y) -> (compile x) @ (compile y) @ [DIV] + | Mod (x, y) -> (compile x) @ (compile y) @ [MOD] + | And (x, y) -> (compile x) @ (compile y) @ [AND] + | Or (x, y) -> (compile x) @ (compile y) @ [OR] + | Equals (x, y) -> (compile x) @ (compile y) @ [EQUALS] + | NotEquals (x, y) -> (compile x) @ (compile y) @ [NOT_EQUALS] + | Greater (x, y) -> (compile x) @ (compile y) @ [GREATER] + | Less (x, y) -> (compile x) @ (compile y) @ [LESS] + | GreaterEquals (x, y) -> (compile x) @ (compile y) @ [GREATER_EQUALS] + | LessEquals (x, y) -> (compile x) @ (compile y) @ [LESS_EQUALS] end +class lbcounter = + object (this) + val mutable count = 0 + method add_lbs n = count <- (count + n) + method get_count = count + end + module Stmt = struct open Language.Stmt + + let get_next_label() = + incr lblCounter; + ".lbl"^string_of_int !lblCounter - let rec compile = function + let rec compile lb = function | Skip -> [] | Assign (x, e) -> Expr.compile e @ [ST x] | Read x -> [READ; ST x] | Write e -> Expr.compile e @ [WRITE] - | Seq (l, r) -> compile l @ compile r - + | Seq (l, r) -> compile lb l @ compile lb r + | op -> + lb#add_lbs 2; + let l1 = lb#get_count-1 in + let l2 = lb#get_count in + match op with + | If (exp, pt1, pt2) -> + Expr.compile exp @ + [CJMP (l1,"z")] @ + compile lb pt1 @ + [JMP l2] @ + [LBL l1] @ + compile lb pt2 @ + [LBL l2] + + | While (exp, pt) -> + [JMP l1] @ + [LBL l2] @ + compile lb pt @ + [LBL l1] @ + Expr.compile exp @ + [CJMP (l2, "nz")] + + | Until (pt, exp) -> + [LBL l1] @ + compile lb pt @ + Expr.compile exp @ + [CJMP (l1, "z")] end module Program = struct - let compile = Stmt.compile + let compile = Stmt.compile (new lbcounter) end diff --git a/src/StackMachine.ml~ b/src/StackMachine.ml~ new file mode 100644 index 00000000..33f6c280 --- /dev/null +++ b/src/StackMachine.ml~ @@ -0,0 +1,208 @@ +(* Stack Machine *) +module Instr = + struct + + type t = + | READ + | WRITE + | PUSH of int + | LD of string + | ST of string + | ADD + | MUL + | SUB + | DIV + | MOD + | AND + | OR + | EQUALS + | NOT_EQUALS + | GREATER + | LESS + | GREATER_EQUALS + | LESS_EQUALS + | LBL of int + | CJMP of int * string + | JMP of int + end + +module Program = + struct + + type t = Instr.t list + + end + +module Interpret = + struct + + open Instr + open Interpret.Stmt + + let rec findlb prg lb = + let nom::prg' = prg in + if nom = lb then prg' + else findlb prg' lb in + + let run prg input = + let prg_full = prg in + + let rec run' prg ((stack, st, input, output) as conf) = + match prg with + | [] -> conf + | i :: prg' -> + run' prg' ( + 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) + | LBL _ -> (prg', stack, st, input, output) + | JMP l -> (findlb prg_full (LBL l), stack, st, input, output) + | CJMP (m, c) -> let nom::stack' = stack in + if (match c with + | "z" -> (nom = 0) + | "nz" -> (nom != 0)) + then (findlb prg_full (LBL m), stack', st, input, output) + else (prg', stack', st, input, output) + | _ -> let y :: x :: stack' = stack in + ((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, [], + (fun _ -> failwith "undefined variable"), + input, + [] + ) + in + output + end + +module Compile = + struct + + open Instr + let lblCounter = ref 0 + + module Expr = + struct + + open Language.Expr + + 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] + | Sub (x, y) -> (compile x) @ (compile y) @ [SUB] + | Div (x, y) -> (compile x) @ (compile y) @ [DIV] + | Mod (x, y) -> (compile x) @ (compile y) @ [MOD] + | And (x, y) -> (compile x) @ (compile y) @ [AND] + | Or (x, y) -> (compile x) @ (compile y) @ [OR] + | Equals (x, y) -> (compile x) @ (compile y) @ [EQUALS] + | NotEquals (x, y) -> (compile x) @ (compile y) @ [NOT_EQUALS] + | Greater (x, y) -> (compile x) @ (compile y) @ [GREATER] + | Less (x, y) -> (compile x) @ (compile y) @ [LESS] + | GreaterEquals (x, y) -> (compile x) @ (compile y) @ [GREATER_EQUALS] + | LessEquals (x, y) -> (compile x) @ (compile y) @ [LESS_EQUALS] + end + +class lbcounter = + object (this) + val mutable count = 0 + method add_lbs n = count <- (count + n) + method get_count = count + end + + module Stmt = + struct + + open Language.Stmt + + let get_next_label() = + incr lblCounter; + ".lbl"^string_of_int !lblCounter + + let rec compile lb = function + | Skip -> [] + | Assign (x, e) -> Expr.compile e @ [ST x] + | Read x -> [READ; ST x] + | Write e -> Expr.compile e @ [WRITE] + | Seq (l, r) -> compile lb l @ compile lb r + | op -> + lb#add_lbs 2; + let l1 = lb#get_count-1 in + let l2 = lb#get_count in + match op with + | If (exp, pt1, pt2) -> + Expr.compile exp @ + [CJMP (l1,"z")] @ + compile lb pt1 @ + [JMP l2] @ + [LBL l1] @ + compile lb pt2 @ + [LBL l2] + + | While (exp, pt) -> + [JMP l1] @ + [LBL l2] @ + compile lb pt @ + [LBL l1] @ + Expr.compile exp @ + [CJMP (l2, "nz")] + + | Until (pt, exp) -> + [LBL l1] @ + compile lb pt @ + Expr.compile exp @ + [CJMP (l1, "z")] + end + + module Program = + struct + + let compile = Stmt.compile (new lbcounter) + + end + + end + diff --git a/src/X86.ml b/src/X86.ml index 9f0544af..88541d52 100644 --- a/src/X86.ml +++ b/src/X86.ml @@ -10,12 +10,28 @@ let [|eax; ebx; ecx; esi; edi; edx; esp; ebp|] = Array.mapi (fun i _ -> R i) reg type instr = | Add of opnd * opnd +| Sub of opnd * opnd +| Div of opnd | 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 +| Lbl of int +| Jz of int +| Jnz of int +| Jmp of int +| Test of opnd * opnd let to_string buf code = let instr = @@ -33,6 +49,23 @@ let to_string buf code = | Pop x -> Printf.sprintf "popl\t%s" (opnd x) | Call x -> Printf.sprintf "call\t%s" x | Ret -> "ret" + | 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 + | Cltd -> "cltd" + | Lbl x -> Printf.sprintf "lbl\t%s:" x + | Jz x -> Printf.sprintf "jz\t%s" x + | Jnz x -> Printf.sprintf "jnz\t%s" x + | Jmp x -> Printf.sprintf "jmp\t%s" x + | Test (x, y) -> Printf.sprintf "testl\t%s,%s" (opnd x)(opnd y) in let out s = Buffer.add_string buf "\t"; @@ -75,22 +108,48 @@ let rec sint env prg sstack = | ST x -> let env' = env#local x in let s :: sstack' = sstack in - env', [Mov (s, M x)], sstack' + (match s with + | S _ -> env', [Mov (s, edx); Mov (edx, M x)], sstack' + | _ -> env', [Mov (s, M x)], sstack') | READ -> env, [Call "lread"], [eax] | WRITE -> env, [Push eax; Call "lwrite"; Pop edx], [] + | LBL x -> env, [Lbl x], [] + | JMP x -> env, [Jmp x], [] + | CJMP (x, c) -> (match s with + | S _ -> env', [Mov (s, edx); Mov (edx, M x)], sstack' + | _ -> env', [Mov (s, M x)], sstack') | _ -> 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' - ) (match i with | MUL -> fun x y -> Mul (x, y) | ADD -> fun x y -> 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, [Mov (y, edx); AndBin (y, edx); + Mov (L 0, edx); Setne dl; + Mov (x, eax); AndBin (x, eax); + Mov (L 0, eax); Setne al; + AndBin (eax, edx); Mov (L 0, edx); Setne dl; + Mov (edx, y)] + | 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'' diff --git a/src/X86.ml~ b/src/X86.ml~ new file mode 100644 index 00000000..94687950 --- /dev/null +++ b/src/X86.ml~ @@ -0,0 +1,163 @@ +open StackMachine +open Instr + +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 [|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 +| 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 = + let opnd = function + | R i -> regs.(i) + | S i -> Printf.sprintf "%d(%%ebp)" (-i * 4) + | L i -> Printf.sprintf "$%d" i + | 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" + | 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"; + 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 + | 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 + + method local x = {< locals = S.add x locals >} + method get_locals = S.elements locals + method get_depth = depth + end + +let rec sint env prg sstack = + match prg with + | [] -> env, [], [] + | i :: prg' -> + let env, code, sstack' = + match i with + | PUSH n -> + let env', s = env#allocate sstack in + env', [Mov (L n, s)], s :: sstack + | LD x -> + let env' = env#local x in + let env'', s = env'#allocate sstack in + env'', [Mov (M x, s)], s :: sstack + | ST x -> + let env' = env#local x in + let s :: sstack' = sstack in + env', [Mov (s, M x)], sstack' + | READ -> + env, [Call "lread"], [eax] + | WRITE -> + env, [Push eax; Call "lwrite"; Pop edx], [] + | _ -> + let x::(y::_ as sstack') = sstack in + (match i with + | MUL -> fun x y -> Mul (x, y) + | ADD -> fun x y -> 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, [Mov (y, edx); AndBin (y, edx); + Mov (L 0, edx); Setne dl; + Mov (x, eax); AndBin (x, eax); + Mov (L 0, eax); Setne al; + AndBin (eax, edx); Mov (L 0, edx); Setne dl; + Mov (edx, y)] + | 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'' + +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)) + env#get_locals; + out "\t.text\n"; + out "\t.globl\tmain\n"; + out "main:\n"; + out "\tpushl\t%ebp\n"; + out "\tmovl\t%esp,%ebp\n"; + out (Printf.sprintf "\tsubl\t$%d,%%esp\n" (env#get_depth * 4)); + to_string buf code; + out "\tmovl\t%ebp,%esp\n"; + out "\tpopl\t%ebp\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); + close_out outf; + let inc = try Sys.getenv "RC_RUNTIME" with _ -> "../runtime" in + Sys.command (Printf.sprintf "gcc -m32 -o %s %s/runtime.o %s.s" name inc name)