Few things

This commit is contained in:
백현웅 2022-01-11 01:05:29 +09:00
parent dae562047c
commit 6444f413ca
4 changed files with 47 additions and 32 deletions

3
ast.ml
View file

@ -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
View file

@ -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
View file

@ -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

View file

@ -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