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)