diff --git a/_build/_digests b/_build/_digests new file mode 100644 index 00000000..f05c092b --- /dev/null +++ b/_build/_digests @@ -0,0 +1,26 @@ +"Rule: ocaml: ml & cmi -> cmx & o (%=src/StackMachine )": "{m\222\"T\136\011\169\235\134\028t\253\186\207H" +"Resource: /home/konstantin/eltech_compilers/eltech_compilers/src/X86.ml": "\223q\241\169\152\199\1553\172\250@Z\226\011\127s" +"Rule: ocaml: ml -> cmo & cmi (%=src/rc )": "\155\135YJNg^\196@\179+\215kG\247q" +"Resource: /home/konstantin/eltech_compilers/eltech_compilers/src/StackMachine.ml": "\187\160]\214\031ab\006'\234\138'\024\241\192\250" +"Rule: ocaml dependencies ml (%=src/rc )": "\171SM$\002/S\029\154\174\225\215\185\195Q\166" +"Rule: ocaml: ml -> cmo & cmi (%=src/X86 )": "\183\012G|5\151z\150&\015\168\236}\192\134g" +"Rule: ocaml: cmo* -> byte (%=src/rc )": "c1|\229\1951\140\192\131M\225\233\232\238\001\014" +"Rule: ocaml: ml -> cmo & cmi (%=src/Interpret )": "\204\002trh#e\181:>\213\233\187w\241\019" +"Rule: ocaml dependencies ml (%=src/Driver )": "\127\218Gt\030\192\176Q\165\164\026\218O\179\172}" +"Rule: ocaml: ml & cmi -> cmx & o (%=src/X86 )": "0756{n\1622\207\178\144\196\198\141>\213" +"Resource: /home/konstantin/eltech_compilers/eltech_compilers/src/Driver.ml": "N\152\191q\216\185=Q\128EC\129-)4\127" +"Rule: ocaml dependencies ml (%=src/Language )": "\243J\030\003\201\176D\184\139[\241\220\005zx\161" +"Rule: ocaml: ml & cmi -> cmx & o (%=src/Driver )": "L\238\239;\194\186\024\006[\144\030\181\161Q\193\233" +"Rule: ocaml dependencies ml (%=src/Interpret )": "g\244\137u\185#_\227\1801\155c\188\209\021\238" +"Rule: ocaml: ml -> cmo & cmi (%=src/StackMachine )": "\000\160\137#\171\199$ES?\196\158T\r\212\206" +"Rule: ocaml: ml & cmi -> cmx & o (%=src/Interpret )": "E\229\016i\248q\b@\136\188\022\173\220\254\137\012" +"Resource: /home/konstantin/eltech_compilers/eltech_compilers/src/Interpret.ml": "\228\238\207\144Jd\235\021>\1971\138\198\212\031+" +"Resource: /home/konstantin/eltech_compilers/eltech_compilers/src/Language.ml": "j\197\170\150Oy\234\135\219/\196\187:pV\224" +"Rule: ocaml: cmx* & o* -> native (%=src/rc )": "\030\214@uR\240m\148[\182\233 \172y\150x" +"Rule: ocaml: ml -> cmo & cmi (%=src/Language )": "&Nb\001\159\1512\012\197\205=\014\026\024\1484" +"Rule: ocaml: ml & cmi -> cmx & o (%=src/Language )": "\160\165\029\216\012\135\004\2007\139\128\244$]\251\238" +"Rule: ocaml: ml -> cmo & cmi (%=src/Driver )": "\241\138-\188&w\191\212\201\174\246\253=C2\161" +"Resource: /home/konstantin/eltech_compilers/eltech_compilers/src/rc.ml": "\1925m\003\2304M\252\t\212\022\151\002\167\151\245" +"Rule: ocaml: ml & cmi -> cmx & o (%=src/rc )": "\174\196:A\134\242Z \220\245\213\0126\2209\222" +"Rule: ocaml dependencies ml (%=src/X86 )": "\228\181\175\184e\253\128\218N\255G!\r\161yO" +"Rule: ocaml dependencies ml (%=src/StackMachine )": "\188\182iI\007\225\181\213J>\139O\141\205\004n" diff --git a/_build/_log b/_build/_log new file mode 100644 index 00000000..f7f22bb1 --- /dev/null +++ b/_build/_log @@ -0,0 +1,33 @@ +### Starting build. +# Target: src/rc.ml.depends, tags: { debug, extension:ml, file:src/rc.ml, ocaml, ocamldep, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamldep -syntax camlp5o -package ostap.syntax -modules src/rc.ml > src/rc.ml.depends # cached +# Target: src/Driver.ml.depends, tags: { debug, extension:ml, file:src/Driver.ml, ocaml, ocamldep, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamldep -syntax camlp5o -package ostap.syntax -modules src/Driver.ml > src/Driver.ml.depends +# Target: src/Interpret.ml.depends, tags: { debug, extension:ml, file:src/Interpret.ml, ocaml, ocamldep, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamldep -syntax camlp5o -package ostap.syntax -modules src/Interpret.ml > src/Interpret.ml.depends +# Target: src/Language.ml.depends, tags: { debug, extension:ml, file:src/Language.ml, ocaml, ocamldep, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamldep -syntax camlp5o -package ostap.syntax -modules src/Language.ml > src/Language.ml.depends +# Target: src/Language.cmo, tags: { byte, compile, debug, extension:cmo, extension:ml, file:src/Language.cmo, file:src/Language.ml, implem, ocaml, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamlc -c -g -g -rectypes -syntax camlp5o -package ostap.syntax -I src -o src/Language.cmo src/Language.ml +# Target: src/StackMachine.ml.depends, tags: { debug, extension:ml, file:src/StackMachine.ml, ocaml, ocamldep, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamldep -syntax camlp5o -package ostap.syntax -modules src/StackMachine.ml > src/StackMachine.ml.depends +# Target: src/Interpret.cmo, tags: { byte, compile, debug, extension:cmo, extension:ml, file:src/Interpret.cmo, file:src/Interpret.ml, implem, ocaml, package(ostap.syntax), quiet, rectypes, syntax(camlp5o), traverse } +ocamlfind ocamlc -c -g -g -rectypes -syntax camlp5o -package ostap.syntax -I src -o src/Interpret.cmo src/Interpret.ml ++ ocamlfind ocamlc -c -g -g -rectypes -syntax camlp5o -package ostap.syntax -I src -o src/Interpret.cmo src/Interpret.ml +File "src/Interpret.ml", line 11, characters 6-950: +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a value that is not matched: +Binop ("", _, _) +File "src/Interpret.ml", line 45, characters 12-23: +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a value that is not matched: +[] +File "src/Interpret.ml", line 41, characters 6-636: +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a value that is not matched: +Repeat (_, _) +File "src/Interpret.ml", line 69, characters 0-1067: +Error: Multiple definition of the module name Expr. + Names must be unique in a given structure or signature. +Command exited with code 2. +# 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.cmi b/_build/src/Driver.cmi new file mode 100644 index 00000000..002ddd6c Binary files /dev/null and b/_build/src/Driver.cmi differ diff --git a/_build/src/Driver.cmo b/_build/src/Driver.cmo new file mode 100644 index 00000000..a8681d5b Binary files /dev/null and b/_build/src/Driver.cmo differ diff --git a/_build/src/Driver.cmx b/_build/src/Driver.cmx new file mode 100644 index 00000000..fde949be Binary files /dev/null and b/_build/src/Driver.cmx differ diff --git a/_build/src/Driver.ml b/_build/src/Driver.ml new file mode 100644 index 00000000..f1d4181a --- /dev/null +++ b/_build/src/Driver.ml @@ -0,0 +1,51 @@ +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"; "fi"; "while"; "do"; "od"] 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/Driver.o b/_build/src/Driver.o new file mode 100644 index 00000000..c615b33e Binary files /dev/null and b/_build/src/Driver.o differ diff --git a/_build/src/Interpret.cmx b/_build/src/Interpret.cmx new file mode 100644 index 00000000..efc5ea1b Binary files /dev/null and b/_build/src/Interpret.cmx differ diff --git a/_build/src/Interpret.ml b/_build/src/Interpret.ml new file mode 100644 index 00000000..fc1d0177 --- /dev/null +++ b/_build/src/Interpret.ml @@ -0,0 +1,127 @@ +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 + | 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 + +(* 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]) + | If (e, s1, s2) -> if (Expr.eval e st) <> 0 then (eval s1 conf) + else (eval s2 conf) + | While (e, s) -> if (Expr.eval e st) <> 0 then eval stmt (eval s conf) + else conf + | 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, []) + in + output + + end +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 + | 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 + +(* 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 + + 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/Interpret.o b/_build/src/Interpret.o new file mode 100644 index 00000000..66d70523 Binary files /dev/null and b/_build/src/Interpret.o differ diff --git a/_build/src/Language.cmi b/_build/src/Language.cmi new file mode 100644 index 00000000..875a9d6c Binary files /dev/null and b/_build/src/Language.cmi differ diff --git a/_build/src/Language.cmo b/_build/src/Language.cmo new file mode 100644 index 00000000..57b8aa11 Binary files /dev/null and b/_build/src/Language.cmo differ diff --git a/_build/src/Language.cmx b/_build/src/Language.cmx new file mode 100644 index 00000000..2958e703 Binary files /dev/null and b/_build/src/Language.cmx differ diff --git a/_build/src/Language.ml b/_build/src/Language.ml new file mode 100644 index 00000000..458208d8 --- /dev/null +++ b/_build/src/Language.ml @@ -0,0 +1,77 @@ +(* AST for expressions *) +module Expr = + struct + + type t = + | Var of string + | Const of int + | Binop of string * t * t + +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 + +(* 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 + | Repeat 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.parse) %"then" s:!(parse) + %"fi" {If (e, s, Skip)} + + | %"if" e:!(Expr.parse) %"then" s1:!(parse) + %"else" s2:!(parse) + %"fi" {If (e, s1, s2)} + + | %"while" e:!(Expr.parse) %"do" s:!(parse) + %"od" {While (e, s)}; + + 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..0ebcf0ad --- /dev/null +++ b/_build/src/Language.ml.depends @@ -0,0 +1 @@ +src/Language.ml: List Ostap diff --git a/_build/src/Language.o b/_build/src/Language.o new file mode 100644 index 00000000..9b39db0b Binary files /dev/null and b/_build/src/Language.o differ diff --git a/_build/src/StackMachine.cmx b/_build/src/StackMachine.cmx new file mode 100644 index 00000000..a290fd98 Binary files /dev/null and b/_build/src/StackMachine.cmx differ diff --git a/_build/src/StackMachine.ml b/_build/src/StackMachine.ml new file mode 100644 index 00000000..759db2dc --- /dev/null +++ b/_build/src/StackMachine.ml @@ -0,0 +1,184 @@ +(* Stack Machine *) +module Instr = + struct + + type t = + | READ + | WRITE + | PUSH of int + | LD of string + | ST of string + | ADD + | MUL + | SUB + | DIV + | MOD + | LT + | LE + | GT + | GE + | EQ + | NEQ + | AND + | OR + | LBL of string + | JNZ of string + | JZ of string + | JMP of string + + end + +module Program = + struct + + type t = Instr.t list + + end + +module Interpret = + struct + + open Instr + open Interpret.Stmt + + let rec goto prg lbl = + let i :: prg' = prg in + if i = lbl then prg' + else goto prg' lbl + + let run prg input = + let prg_origin = prg in + let rec run' ((prg, stack, st, input, output) as conf) = + match prg with + | [] -> conf + | i :: prg' -> + run' ( + match i with + | READ -> let z :: input' = input in + (prg', z :: stack, st, input', output) + | WRITE -> let z :: stack' = stack in + (prg', stack', st, input, output @ [z]) + | PUSH n -> (prg', n :: stack, st, input, output) + | LD x -> (prg', st x :: stack, st, input, output) + | ST x -> let z :: stack' = stack in + (prg', stack', update st x z, input, output) + | ADD -> let y :: x :: stack' = stack in + (prg', (x + y):: stack', st, input, output) + | MUL -> let y :: x :: stack' = stack in + (prg', (x * y):: stack', st, input, output) + | SUB -> let y :: x :: stack' = stack in + (prg', (x - y):: stack', st, input, output) + | DIV -> let y :: x :: stack' = stack in + (prg', (x / y):: stack', st, input, output) + | MOD -> let y :: x :: stack' = stack in + (prg', (x mod y):: stack', st, input, output) + | LT -> let y :: x :: stack' = stack in + (prg', (if x < y then 1 else 0):: stack', st, input, output) + | LE -> let y :: x :: stack' = stack in + (prg', (if x <= y then 1 else 0):: stack', st, input, output) + | GT -> let y :: x :: stack' = stack in + (prg', (if x > y then 1 else 0):: stack', st, input, output) + | GE -> let y :: x :: stack' = stack in + (prg', (if x >= y then 1 else 0):: stack', st, input, output) + | EQ -> let y :: x :: stack' = stack in + (prg', (if x == y then 1 else 0):: stack', st, input, output) + | NEQ -> let y :: x :: stack' = stack in + (prg', (if x <> y then 1 else 0):: stack', st, input, output) + | AND -> let y :: x :: stack' = stack in + (prg', (if (x <> 0) && (y <> 0) then 1 else 0):: stack', st, input, output) + | OR -> let y :: x :: stack' = stack in + (prg', (if (x <> 0) || (y <> 0) then 1 else 0):: stack', st, input, output) + | LBL _ -> (prg', stack, st, input, output) + | JNZ l -> let x :: stack' = stack in + if x <> 0 then (goto prg_origin (LBL l), stack', st, input, output) + else (prg', stack', st, input, output) + | JZ l -> let x :: stack' = stack in + if x == 0 then (goto prg_origin (LBL l), stack', st, input, output) + else (prg', stack', st, input, output) + | JMP l -> (goto prg_origin (LBL l), stack, st, input, output) + ) + in + let (_, _, _, _, output) = + run' (prg, + [], + (fun _ -> failwith "undefined variable"), + input, + [] + ) + in + output + end + +module Compile = + struct + + let lbl = ref 0 + let get_next_label() = + lbl:= !lbl + 1; + ".L"^string_of_int !lbl + + open Instr + + module Expr = + struct + + open Language.Expr + + let rec compile = function + | Var x -> [LD x] + | Const n -> [PUSH n] + | 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 + + module Stmt = + struct + + open Language.Stmt + + let rec compile = 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 + + | If (e, s1, s2) -> let lbl1 = get_next_label() in + let lbl2 = get_next_label() in + Expr.compile e @ + [JZ lbl1] @ + compile s1 @ + [JMP lbl2; LBL lbl1] @ + compile s2 @ + [LBL lbl2] + + | While (e, s) -> let lbl1 = get_next_label() in + let lbl2 = get_next_label() in + [JMP lbl2; LBL lbl1] @ + compile s @ + [LBL lbl2] @ + Expr.compile e @ + [JNZ lbl1] + end + + module Program = + struct + + let compile = Stmt.compile + + 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/StackMachine.o b/_build/src/StackMachine.o new file mode 100644 index 00000000..82385818 Binary files /dev/null and b/_build/src/StackMachine.o differ diff --git a/_build/src/X86.cmi b/_build/src/X86.cmi new file mode 100644 index 00000000..433f88f4 Binary files /dev/null and b/_build/src/X86.cmi differ diff --git a/_build/src/X86.cmo b/_build/src/X86.cmo new file mode 100644 index 00000000..93c10257 Binary files /dev/null and b/_build/src/X86.cmo differ diff --git a/_build/src/X86.cmx b/_build/src/X86.cmx new file mode 100644 index 00000000..e5c82f96 Binary files /dev/null and b/_build/src/X86.cmx differ diff --git a/_build/src/X86.ml b/_build/src/X86.ml new file mode 100644 index 00000000..cd929d20 --- /dev/null +++ b/_build/src/X86.ml @@ -0,0 +1,171 @@ +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 +| 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 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,\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" + 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 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 + + 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' = + 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, edx); Mov (edx, s)], s :: sstack + | ST x -> + let env' = env#local x in + let s :: sstack' = sstack in + env', [Mov (s, edx); Mov (edx, M x)], sstack' + | READ -> + env, [Call "lread"], [eax] + | WRITE -> + env, [Push (R 1); Call "lwrite"; Pop (R 1)], [] + | _ -> + let x::(y::_ as sstack') = sstack in + (fun op -> + 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)] + ) + 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 "\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); + 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) + diff --git a/_build/src/X86.ml.depends b/_build/src/X86.ml.depends new file mode 100644 index 00000000..a8bee1ca --- /dev/null +++ b/_build/src/X86.ml.depends @@ -0,0 +1 @@ +src/X86.ml: Array Buffer Compile Instr List Printf Set StackMachine String Sys diff --git a/_build/src/X86.o b/_build/src/X86.o new file mode 100644 index 00000000..e9bc0a7c Binary files /dev/null and b/_build/src/X86.o differ diff --git a/_build/src/rc.byte b/_build/src/rc.byte new file mode 100755 index 00000000..0f2b76d3 Binary files /dev/null and b/_build/src/rc.byte differ diff --git a/_build/src/rc.cmi b/_build/src/rc.cmi new file mode 100644 index 00000000..66e3db3e Binary files /dev/null and b/_build/src/rc.cmi differ diff --git a/_build/src/rc.cmo b/_build/src/rc.cmo new file mode 100644 index 00000000..d16bb326 Binary files /dev/null and b/_build/src/rc.cmo differ diff --git a/_build/src/rc.cmx b/_build/src/rc.cmx new file mode 100644 index 00000000..9c47cdab Binary files /dev/null and b/_build/src/rc.cmx differ 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/_build/src/rc.native b/_build/src/rc.native new file mode 100755 index 00000000..b078efb4 Binary files /dev/null and b/_build/src/rc.native differ diff --git a/_build/src/rc.o b/_build/src/rc.o new file mode 100644 index 00000000..c1a26ec3 Binary files /dev/null and b/_build/src/rc.o differ diff --git a/rc.byte b/rc.byte new file mode 120000 index 00000000..a5ad0059 --- /dev/null +++ b/rc.byte @@ -0,0 +1 @@ +/home/konstantin/eltech_compilers/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..cdf3a68f --- /dev/null +++ b/rc.native @@ -0,0 +1 @@ +/home/konstantin/eltech_compilers/eltech_compilers/_build/src/rc.native \ No newline at end of file diff --git a/runtime/runtime.o b/runtime/runtime.o new file mode 100644 index 00000000..5fa1db39 Binary files /dev/null and b/runtime/runtime.o differ diff --git a/src/Driver.ml b/src/Driver.ml index 5c8e0b34..f1d4181a 100644 --- a/src/Driver.ml +++ b/src/Driver.ml @@ -3,12 +3,12 @@ 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"] s inherit Util.Lexers.decimal s inherit Util.Lexers.skip [ Matcher.Skip.whitespaces " \t\n"; @@ -27,21 +27,21 @@ let main = 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 + else let rec read acc = try let r = read_int () in Printf.printf "> "; - read (acc @ [r]) + read (acc @ [r]) with End_of_file -> acc in - let input = read [] in - let output = - if interpret - then Interpret.Program.eval prog input + 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 diff --git a/src/Interpret.ml b/src/Interpret.ml index 9f863d55..fc1d0177 100644 --- a/src/Interpret.ml +++ b/src/Interpret.ml @@ -6,13 +6,90 @@ 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 + +(* 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]) + | If (e, s1, s2) -> if (Expr.eval e st) <> 0 then (eval s1 conf) + else (eval s2 conf) + | While (e, s) -> if (Expr.eval e st) <> 0 then eval stmt (eval s conf) + else conf + | 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, []) + in + output + + end +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 + | 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,28 +99,29 @@ 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 end + diff --git a/src/Interpret.ml~ b/src/Interpret.ml~ new file mode 100644 index 00000000..e2e89778 --- /dev/null +++ b/src/Interpret.ml~ @@ -0,0 +1,62 @@ +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 + | 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 + +(* 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 + + 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..458208d8 100644 --- a/src/Language.ml +++ b/src/Language.ml @@ -5,18 +5,28 @@ module Expr = type t = | Var of string | Const of int - | Add of t * t - | Mul 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 -")" - ) + | Binop of string * t * t +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 (* AST statements/commands *) @@ -29,6 +39,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 + | Repeat of t * Expr.t let expr = Expr.parse @@ -36,9 +49,19 @@ module Stmt = simp: x:IDENT ":=" e:expr {Assign (x, e)} | %"read" "(" x:IDENT ")" {Read x} | %"write" "(" e:expr ")" {Write e} - | %"skip" {Skip}; - - parse: s:simp ";" d:parse {Seq (s,d)} | simp + | %"skip" {Skip} + + | %"if" e:!(Expr.parse) %"then" s:!(parse) + %"fi" {If (e, s, Skip)} + + | %"if" e:!(Expr.parse) %"then" s1:!(parse) + %"else" s2:!(parse) + %"fi" {If (e, s1, s2)} + + | %"while" e:!(Expr.parse) %"do" s:!(parse) + %"od" {While (e, s)}; + + parse: s:simp ";" d:parse {Seq (s,d)} | simp ) end diff --git a/src/Language.ml~ b/src/Language.ml~ new file mode 100644 index 00000000..0d694d08 --- /dev/null +++ b/src/Language.ml~ @@ -0,0 +1,64 @@ +(* AST for expressions *) +module Expr = + struct + + type t = + | Var of string + | Const of int + | Binop of string * t * t + +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 + +(* 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 + + 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}; + + 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..759db2dc 100644 --- a/src/StackMachine.ml +++ b/src/StackMachine.ml @@ -8,8 +8,23 @@ module Instr = | PUSH of int | LD of string | ST of string - | ADD + | ADD | MUL + | SUB + | DIV + | MOD + | LT + | LE + | GT + | GE + | EQ + | NEQ + | AND + | OR + | LBL of string + | JNZ of string + | JZ of string + | JMP of string end @@ -26,35 +41,70 @@ module Interpret = open Instr open Interpret.Stmt + let rec goto prg lbl = + let i :: prg' = prg in + if i = lbl then prg' + else goto prg' lbl + let run prg input = - let rec run' prg ((stack, st, input, output) as conf) = + let prg_origin = prg in + 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) + | READ -> let z :: input' = input in + (prg', z :: stack, st, input', output) + | WRITE -> let z :: stack' = stack in + (prg', stack', st, input, output @ [z]) + | PUSH n -> (prg', n :: stack, st, input, output) + | LD x -> (prg', 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 - ) + (prg', stack', update st x z, input, output) + | ADD -> let y :: x :: stack' = stack in + (prg', (x + y):: stack', st, input, output) + | MUL -> let y :: x :: stack' = stack in + (prg', (x * y):: stack', st, input, output) + | SUB -> let y :: x :: stack' = stack in + (prg', (x - y):: stack', st, input, output) + | DIV -> let y :: x :: stack' = stack in + (prg', (x / y):: stack', st, input, output) + | MOD -> let y :: x :: stack' = stack in + (prg', (x mod y):: stack', st, input, output) + | LT -> let y :: x :: stack' = stack in + (prg', (if x < y then 1 else 0):: stack', st, input, output) + | LE -> let y :: x :: stack' = stack in + (prg', (if x <= y then 1 else 0):: stack', st, input, output) + | GT -> let y :: x :: stack' = stack in + (prg', (if x > y then 1 else 0):: stack', st, input, output) + | GE -> let y :: x :: stack' = stack in + (prg', (if x >= y then 1 else 0):: stack', st, input, output) + | EQ -> let y :: x :: stack' = stack in + (prg', (if x == y then 1 else 0):: stack', st, input, output) + | NEQ -> let y :: x :: stack' = stack in + (prg', (if x <> y then 1 else 0):: stack', st, input, output) + | AND -> let y :: x :: stack' = stack in + (prg', (if (x <> 0) && (y <> 0) then 1 else 0):: stack', st, input, output) + | OR -> let y :: x :: stack' = stack in + (prg', (if (x <> 0) || (y <> 0) then 1 else 0):: stack', st, input, output) + | LBL _ -> (prg', stack, st, input, output) + | JNZ l -> let x :: stack' = stack in + if x <> 0 then (goto prg_origin (LBL l), stack', st, input, output) + else (prg', stack', st, input, output) + | JZ l -> let x :: stack' = stack in + if x == 0 then (goto prg_origin (LBL l), stack', st, input, output) + else (prg', stack', st, input, output) + | JMP l -> (goto prg_origin (LBL l), stack, st, input, output) ) in - let (_, _, _, output) = - run' prg ([], + let (_, _, _, _, output) = + run' (prg, + [], (fun _ -> failwith "undefined variable"), input, [] - ) + ) in output end @@ -62,6 +112,11 @@ module Interpret = module Compile = struct + let lbl = ref 0 + let get_next_label() = + lbl:= !lbl + 1; + ".L"^string_of_int !lbl + open Instr module Expr = @@ -69,11 +124,22 @@ module Compile = 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] + let rec compile = function + | Var x -> [LD x] + | Const n -> [PUSH n] + | 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 @@ -82,13 +148,29 @@ module Compile = open Language.Stmt - let rec compile = 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 - + let rec compile = 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 + + | If (e, s1, s2) -> let lbl1 = get_next_label() in + let lbl2 = get_next_label() in + Expr.compile e @ + [JZ lbl1] @ + compile s1 @ + [JMP lbl2; LBL lbl1] @ + compile s2 @ + [LBL lbl2] + + | While (e, s) -> let lbl1 = get_next_label() in + let lbl2 = get_next_label() in + [JMP lbl2; LBL lbl1] @ + compile s @ + [LBL lbl2] @ + Expr.compile e @ + [JNZ lbl1] end module Program = diff --git a/src/X86.ml b/src/X86.ml index 9f0544af..60d05056 100644 --- a/src/X86.ml +++ b/src/X86.ml @@ -11,96 +11,162 @@ 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 +| Lbl of string +| Jnz of string +| Jz of string +| Jmp of string | 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) + + | Lbl l -> Printf.sprintf "%s:" l + | Jnz l -> Printf.sprintf "jnz\t%s" l + | Jz l -> Printf.sprintf "jz\t%s" l + | Jmp l -> Printf.sprintf "jmp\t%s" l + + | 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 -> - 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], [] - | _ -> + | 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, edx); Mov (edx, s)], s :: sstack + | ST x -> + let env' = env#local x in + let s :: sstack' = sstack in + env', [Mov (s, edx); Mov (edx, M x)], sstack' + | READ -> + env, [Call "lread"], [eax] + | WRITE -> + env, [Push (R 1); Call "lwrite"; Pop (R 1)], [] + | LBL l -> + env, [Lbl l], sstack + | JNZ l -> + let s :: sstack' = sstack in + env, [Cmp (L 0, s); Jnz l], sstack' + | JZ l -> + let s :: sstack' = sstack in + env, [Cmp (L 0, s); Jz l], sstack' + | JMP l -> + env, [Jmp l], 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' + 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,12 +177,14 @@ 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); 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) + diff --git a/src/X86.ml~ b/src/X86.ml~ new file mode 100644 index 00000000..cd929d20 --- /dev/null +++ b/src/X86.ml~ @@ -0,0 +1,171 @@ +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 +| 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 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,\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" + 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 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 + + 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' = + 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, edx); Mov (edx, s)], s :: sstack + | ST x -> + let env' = env#local x in + let s :: sstack' = sstack in + env', [Mov (s, edx); Mov (edx, M x)], sstack' + | READ -> + env, [Call "lread"], [eax] + | WRITE -> + env, [Push (R 1); Call "lwrite"; Pop (R 1)], [] + | _ -> + let x::(y::_ as sstack') = sstack in + (fun op -> + 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)] + ) + 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 "\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); + 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) +