Strings/arrays/builtins in int/sm

This commit is contained in:
Dmitry Boulytchev 2018-04-25 01:06:18 +03:00
parent b19bea4d58
commit dd5956d663
10991 changed files with 24197 additions and 24039 deletions

View file

@ -6,13 +6,44 @@ open GT
(* Opening a library for combinator-based syntax analysis *)
open Ostap
open Combinators
(* Values *)
module Value =
struct
@type t = Int of int | String of string | Array of t list | Sexp of string * t list with show
let to_int = function
| Int n -> n
| _ -> failwith "int value expected"
let to_string = function
| String s -> s
| _ -> failwith "string value expected"
let to_array = function
| Array a -> a
| _ -> failwith "array value expected"
let of_int n = Int n
let of_string s = String s
let of_array a = Array a
let tag_of = function
| Sexp (t, _) -> t
| _ -> failwith "symbolic expression expected"
let update_string s i x = String.init (String.length s) (fun j -> if j = i then x else s.[j])
let update_array a i x = List.init (List.length a) (fun j -> if j = i then x else List.nth a j)
end
(* States *)
module State =
struct
(* State: global state, local state, scope variables *)
type t = {g : string -> int; l : string -> int; scope : string list}
type t = {g : string -> Value.t; l : string -> Value.t; scope : string list}
(* Empty state *)
let empty =
@ -36,6 +67,27 @@ module State =
let leave st st' = {st' with g = st.g}
end
(* Builtins *)
module Builtin =
struct
let eval (st, i, o, _) args = function
| "read" -> (match i with z::i' -> (st, i', o, Some (Value.of_int z)) | _ -> failwith "Unexpected end of input")
| "write" -> (st, i, o @ [Value.to_int @@ List.hd args], None)
| "$elem" -> let [b; j] = args in
(st, i, o, let i = Value.to_int j in
Some (match b with
| Value.String s -> Value.of_int @@ Char.code s.[i]
| Value.Array a -> List.nth a i
)
)
| "$length" -> (st, i, o, Some (Value.of_int (match List.hd args with Value.Array a -> List.length a | Value.String s -> String.length s)))
| "$array" -> (st, i, o, Some (Value.of_array args))
| s -> failwith (Printf.sprintf "Wow: %s\n" s)
end
(* Simple expressions: syntax and semantics *)
module Expr =
@ -45,10 +97,15 @@ module Expr =
notation, it came from GT.
*)
@type t =
(* integer constant *) | Const of int
(* variable *) | Var of string
(* binary operator *) | Binop of string * t * t
(* function call *) | Call of string * t list with show
(* integer constant *) | Const of int
(* array *) | Array of t list
(* string *) | String of string
(* S-expressions *) | Sexp of string * t list
(* variable *) | Var of string
(* binary operator *) | Binop of string * t * t
(* element extraction *) | Elem of t * t
(* length *) | Length of t
(* function call *) | Call of string * t list with show
(* Available binary operators:
!! --- disjunction
@ -59,7 +116,7 @@ module Expr =
*)
(* The type of configuration: a state, an input stream, an output stream, an optional value *)
type config = State.t * int list * int list * int option
type config = State.t * int list * int list * Value.t option
(* Expression evaluator
@ -96,17 +153,39 @@ module Expr =
let rec eval env ((st, i, o, r) as conf) expr =
match expr with
| Const n -> (st, i, o, Some n)
| Var x -> (st, i, o, Some (State.eval st x))
| Const n -> (st, i, o, Some (Value.of_int n))
| String s -> (st, i, o, Some (Value.of_string s))
| Var x -> (st, i, o, Some (State.eval st x))
| Array xs ->
let (st, i, o, vs) = eval_list env conf xs in
env#definition env "$array" vs (st, i, o, None)
| Sexp (t, xs) ->
let (st, i, o, vs) = eval_list env conf xs in
(st, i, o, Some (Value.Sexp (t, vs)))
| Binop (op, x, y) ->
let (_, _, _, Some x) as conf = eval env conf x in
let (st, i, o, Some y) as conf = eval env conf y in
(st, i, o, Some (to_func op x y))
(st, i, o, Some (Value.of_int @@ to_func op (Value.to_int x) (Value.to_int y)))
| Elem (b, i) ->
let (st, i, o, args) = eval_list env conf [b; i] in
env#definition env "$elem" args (st, i, o, None)
| Length e ->
let (st, i, o, Some v) = eval env conf e in
env#definition env "$length" [v] (st, i, o, None)
| Call (f, args) ->
let args, conf =
List.fold_left (fun (acc, conf) e -> let (_, _, _, Some v) as conf = eval env conf e in v::acc, conf) ([], conf) args
in
env#definition env f (List.rev args) conf
let (st, i, o, args) = eval_list env conf args in
env#definition env f args (st, i, o, None)
and eval_list env conf xs =
let vs, (st, i, o, _) =
List.fold_left
(fun (acc, conf) x ->
let (_, _, _, Some v) as conf = eval env conf x in
v::acc, conf
)
([], conf)
xs
in
(st, i, o, List.rev vs)
(* Expression parser. You can use the following terminals:
@ -129,10 +208,15 @@ module Expr =
|]
)
primary);
primary:
n:DECIMAL {Const n}
| x:IDENT s:("(" args:!(Util.list0)[parse] ")" {Call (x, args)} | empty {Var x}) {s}
primary: b:base is:(-"[" i:parse -"]" {`Elem i} | "." %"length" {`Len}) *
{List.fold_left (fun b -> function `Elem i -> Elem (b, i) | `Len -> Length b) b is};
base:
n:DECIMAL {Const n}
| s:STRING {String (String.sub s 1 (String.length s - 2))}
| c:CHAR {Const (Char.code c)}
| "[" es:!(Util.list0)[parse] "]" {Array es}
| "`" t:IDENT args:(-"(" !(Util.list)[parse] -")")? {Sexp (t, match args with None -> [] | Some args -> args)}
| x:IDENT s:("(" args:!(Util.list0)[parse] ")" {Call (x, args)} | empty {Var x}) {s}
| -"(" parse -")"
)
@ -143,17 +227,15 @@ module Stmt =
struct
(* The type for statements *)
@type t =
(* read into the variable *) | Read of string
(* write the value of an expression *) | Write of Expr.t
(* assignment *) | Assign of string * Expr.t
type t =
(* assignment *) | Assign of string * Expr.t list * Expr.t
(* composition *) | Seq of t * t
(* empty statement *) | Skip
(* conditional *) | If of Expr.t * t * t
(* loop with a pre-condition *) | While of Expr.t * t
(* loop with a post-condition *) | Repeat of t * Expr.t
(* return statement *) | Return of Expr.t option
(* call a procedure *) | Call of string * Expr.t list with show
(* call a procedure *) | Call of string * Expr.t list
(* Statement evaluator
@ -162,17 +244,32 @@ module Stmt =
Takes an environment, a configuration and a statement, and returns another configuration. The
environment is the same as for expressions
*)
let update st x v is =
let rec update a v = function
| [] -> v
| i::tl ->
let i = Value.to_int i in
(match a with
| Value.String s when tl = [] -> Value.String (Value.update_string s i (Char.chr @@ Value.to_int v))
| Value.Array a -> Value.Array (Value.update_array a i (update (List.nth a i) v tl))
)
in
State.update x (match is with [] -> v | _ -> update (State.eval st x) v is) st
let rec eval env ((st, i, o, r) as conf) k stmt =
let seq x = function Skip -> x | y -> Seq (x, y) in
match stmt with
| Read x -> eval env (match i with z::i' -> (State.update x z st, i', o, r) | _ -> failwith "Unexpected end of input") Skip k
| Write e -> eval env (let (st, i, o, Some v) = Expr.eval env conf e in (st, i, o @ [v], r)) Skip k
| Assign (x, e) -> eval env (let (st, i, o, Some v) = Expr.eval env conf e in (State.update x v st, i, o, r)) Skip k
| Assign (x, is, e) ->
let (st, i, o, is) = Expr.eval_list env conf is in
let (st, i, o, Some v) = Expr.eval env (st, i, o, None) e in
eval env (update st x v is, i, o, None) Skip k
| Seq (s1, s2) -> eval env conf (seq s2 k) s1
| Skip -> (match k with Skip -> conf | _ -> eval env conf Skip k)
| If (e, s1, s2) -> let (_, _, _, Some v) as conf = Expr.eval env conf e in eval env conf k (if v <> 0 then s1 else s2)
| If (e, s1, s2) -> let (_, _, _, Some v) as conf = Expr.eval env conf e in eval env conf k (if Value.to_int v <> 0 then s1 else s2)
| While (e, s) -> let (_, _, _, Some v) as conf = Expr.eval env conf e in
if v = 0
if Value.to_int v = 0
then eval env conf Skip k
else eval env conf (seq stmt k) s
| Repeat (s, e) -> eval env conf (seq (While (Expr.Binop ("==", e, Expr.Const 0), s)) k) s
@ -185,9 +282,7 @@ module Stmt =
s:stmt ";" ss:parse {Seq (s, ss)}
| stmt;
stmt:
%"read" "(" x:IDENT ")" {Read x}
| %"write" "(" e:!(Expr.parse) ")" {Write e}
| %"skip" {Skip}
%"skip" {Skip}
| %"if" e:!(Expr.parse)
%"then" the:parse
elif:(%"elif" !(Expr.parse) %"then" parse)*
@ -207,7 +302,7 @@ module Stmt =
| %"repeat" s:parse %"until" e:!(Expr.parse) {Repeat (s, e)}
| %"return" e:!(Expr.parse)? {Return e}
| x:IDENT
s:(":=" e :!(Expr.parse) {Assign (x, e)} |
s:(is:(-"[" !(Expr.parse) -"]")* ":=" e :!(Expr.parse) {Assign (x, is, e)} |
"(" args:!(Util.list0)[Expr.parse] ")" {Call (x, args)}
) {s}
)
@ -249,11 +344,13 @@ let eval (defs, body) i =
let _, _, o, _ =
Stmt.eval
(object
method definition env f args (st, i, o, r) =
let xs, locs, s = snd @@ M.find f m in
let st' = List.fold_left (fun st (x, a) -> State.update x a st) (State.enter st (xs @ locs)) (List.combine xs args) in
let st'', i', o', r' = Stmt.eval env (st', i, o, r) Skip s in
(State.leave st'' st, i', o', r')
method definition env f args ((st, i, o, r) as conf) =
try
let xs, locs, s = snd @@ M.find f m in
let st' = List.fold_left (fun st (x, a) -> State.update x a st) (State.enter st (xs @ locs)) (List.combine xs args) in
let st'', i', o', r' = Stmt.eval env (st', i, o, r) Skip s in
(State.leave st'' st, i', o', r')
with Not_found -> Builtin.eval conf args f
end)
(State.empty, i, [], None)
Skip