Few things
This commit is contained in:
parent
dae562047c
commit
6444f413ca
4 changed files with 47 additions and 32 deletions
3
ast.ml
3
ast.ml
|
@ -19,6 +19,7 @@ type t =
|
||||||
| Value of typ
|
| Value of typ
|
||||||
| Binop of t * binop * t
|
| Binop of t * binop * t
|
||||||
| Set_binop_pre of binop * t
|
| Set_binop_pre of binop * t
|
||||||
|
| Get_binop_pre of binop
|
||||||
|
|
||||||
let value v = Value v
|
let value v = Value v
|
||||||
|
|
||||||
|
@ -45,5 +46,7 @@ let print ast =
|
||||||
pr "(set_pre %s " (binop_to_string op);
|
pr "(set_pre %s " (binop_to_string op);
|
||||||
aux pre;
|
aux pre;
|
||||||
pr ")"
|
pr ")"
|
||||||
|
| Get_binop_pre op ->
|
||||||
|
pr "(get_pre %s)" (binop_to_string op)
|
||||||
in
|
in
|
||||||
aux ast; pr "\n"
|
aux ast; pr "\n"
|
||||||
|
|
14
eval.ml
14
eval.ml
|
@ -1,15 +1,15 @@
|
||||||
open Ast
|
open Ast
|
||||||
|
|
||||||
let intop f a b =
|
let arith f a b =
|
||||||
match a, b with
|
match a, b with
|
||||||
| Int a, Int b -> Int (f a b)
|
| Int a, Int b -> Int (f a b)
|
||||||
| _ -> failwith "typecheck failed"
|
| _ -> failwith "typecheck failed"
|
||||||
|
|
||||||
let binop_to_func = function
|
let binop_to_func = function
|
||||||
| Add -> intop Int.add
|
| Add -> arith Int.add
|
||||||
| Sub -> intop Int.sub
|
| Sub -> arith Int.sub
|
||||||
| Mul -> intop Int.mul
|
| Mul -> arith Int.mul
|
||||||
| Div -> intop Int.div
|
| Div -> arith Int.div
|
||||||
|
|
||||||
let rec eval = function
|
let rec eval = function
|
||||||
| Value v -> v
|
| Value v -> v
|
||||||
|
@ -18,5 +18,7 @@ let rec eval = function
|
||||||
f (eval l) (eval r)
|
f (eval l) (eval r)
|
||||||
| Set_binop_pre (op, l) ->
|
| Set_binop_pre (op, l) ->
|
||||||
let l = match eval l with Int n -> n | _ -> failwith "not int" in
|
let l = match eval l with Int n -> n | _ -> failwith "not int" in
|
||||||
Hashtbl.replace Parser.precedence (Ast.binop_to_string op) l;
|
Hashtbl.replace Parser.precedence op l;
|
||||||
Unit
|
Unit
|
||||||
|
| Get_binop_pre op ->
|
||||||
|
Int (Hashtbl.find Parser.precedence op)
|
||||||
|
|
18
main.ml
18
main.ml
|
@ -16,15 +16,15 @@ let rec repl () : unit =
|
||||||
printf "> ";
|
printf "> ";
|
||||||
let line = read_line () in
|
let line = read_line () in
|
||||||
if line <> "quit" then begin
|
if line <> "quit" then begin
|
||||||
try
|
(try
|
||||||
line
|
line
|
||||||
|> Lex.tokenize
|
|> Lex.tokenize
|
||||||
|> Parser.parse
|
|> Parser.parse
|
||||||
|> Eval.eval
|
|> Eval.eval
|
||||||
|> Ast.typ_to_string
|
|> Ast.typ_to_string
|
||||||
|> printf "%s\n"
|
|> printf "%s\n"
|
||||||
with
|
with
|
||||||
| e -> print_error e;
|
| e -> print_error e);
|
||||||
repl ()
|
repl ()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
44
parser.ml
44
parser.ml
|
@ -1,5 +1,7 @@
|
||||||
open Ast
|
open Ast
|
||||||
|
|
||||||
|
module S = Set.Make(String)
|
||||||
|
|
||||||
exception Expected of string
|
exception Expected of string
|
||||||
exception Unexpected_token of string
|
exception Unexpected_token of string
|
||||||
|
|
||||||
|
@ -14,14 +16,14 @@ let unexpected_token t =
|
||||||
* precedency, but infering precedence relation from the graph is hard
|
* precedency, but infering precedence relation from the graph is hard
|
||||||
* and the graph can be made to have loops, I just used plain table. *)
|
* and the graph can be made to have loops, I just used plain table. *)
|
||||||
let precedence = [
|
let precedence = [
|
||||||
"+", 10;
|
Add, 10;
|
||||||
"-", 10;
|
Sub, 10;
|
||||||
"*", 20;
|
Mul, 20;
|
||||||
"/", 20;
|
Div, 20;
|
||||||
] |> List.to_seq |> Hashtbl.of_seq
|
] |> List.to_seq |> Hashtbl.of_seq
|
||||||
|
|
||||||
let precedence_of op =
|
let precedence_of op =
|
||||||
Hashtbl.find precedence (Ast.binop_to_string op)
|
Hashtbl.find precedence op
|
||||||
|
|
||||||
let is_left_to_right = function
|
let is_left_to_right = function
|
||||||
| Add | Sub | Mul | Div -> true
|
| Add | Sub | Mul | Div -> true
|
||||||
|
@ -52,7 +54,7 @@ let parse ts =
|
||||||
| Token.Plus | Minus | Asterisk | Slash as op ->
|
| Token.Plus | Minus | Asterisk | Slash as op ->
|
||||||
let op = token_to_op op in
|
let op = token_to_op op in
|
||||||
let o = precedence_of op in
|
let o = precedence_of op in
|
||||||
if o > pre then
|
if o > pre then (* op has to be calculated first *)
|
||||||
let v, seq = value seq in
|
let v, seq = value seq in
|
||||||
let right, seq = binop o v seq in
|
let right, seq = binop o v seq in
|
||||||
binop pre (Ast.binop left op right) seq
|
binop pre (Ast.binop left op right) seq
|
||||||
|
@ -62,6 +64,16 @@ let parse ts =
|
||||||
| _ -> unexpected_token x
|
| _ -> unexpected_token x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
and ident set seq =
|
||||||
|
match seq () with
|
||||||
|
| Seq.Nil ->
|
||||||
|
let msg = "ident " ^ (S.elements set |> String.concat " or ") in
|
||||||
|
expected msg
|
||||||
|
| Seq.Cons (x, seq) -> begin match x with
|
||||||
|
| Token.Ident id when S.mem id set -> id, seq
|
||||||
|
| _ -> unexpected_token x
|
||||||
|
end
|
||||||
|
|
||||||
and operator seq =
|
and operator seq =
|
||||||
match seq () with
|
match seq () with
|
||||||
| Seq.Nil -> expected "operator"
|
| Seq.Nil -> expected "operator"
|
||||||
|
@ -69,22 +81,20 @@ let parse ts =
|
||||||
try token_to_op x, seq with
|
try token_to_op x, seq with
|
||||||
| _ -> expected "operator"
|
| _ -> expected "operator"
|
||||||
|
|
||||||
and set_conf seq =
|
and level seq =
|
||||||
match seq () with
|
let id, seq = ident (S.of_list ["get"; "set"]) seq in
|
||||||
| Seq.Nil -> expected "ident"
|
let op, seq = operator seq in
|
||||||
| Seq.Cons (x, seq) -> begin match x with
|
if id = "get" then
|
||||||
| Token.Ident "level" ->
|
Get_binop_pre op, seq
|
||||||
let op, seq = operator seq in
|
else
|
||||||
let v, seq = value seq in
|
let v, seq = value seq in
|
||||||
Set_binop_pre (op, v), seq
|
Set_binop_pre (op, v), seq
|
||||||
| _ -> expected "argument"
|
|
||||||
end
|
|
||||||
|
|
||||||
and expr seq =
|
and expr seq =
|
||||||
match seq () with
|
match seq () with
|
||||||
| Seq.Nil -> Value Unit, Seq.empty (* nop *)
|
| Seq.Nil -> Value Unit, Seq.empty (* nop *)
|
||||||
| Seq.Cons (x, s) -> begin match x with
|
| Seq.Cons (x, s) -> begin match x with
|
||||||
| Ident "set" -> set_conf s
|
| Ident "level" -> level s
|
||||||
| _ ->
|
| _ ->
|
||||||
let left, seq = value seq in
|
let left, seq = value seq in
|
||||||
binop ~-1 left seq
|
binop ~-1 left seq
|
||||||
|
|
Loading…
Add table
Reference in a new issue