2022-01-10 01:31:47 +09:00
|
|
|
open Ast
|
|
|
|
|
2022-01-11 01:05:29 +09:00
|
|
|
module S = Set.Make(String)
|
|
|
|
|
2022-01-10 01:31:47 +09:00
|
|
|
exception Expected of string
|
|
|
|
exception Unexpected_token of string
|
|
|
|
|
|
|
|
let expected t =
|
|
|
|
raise (Expected t)
|
|
|
|
|
|
|
|
let unexpected_token t =
|
|
|
|
raise @@ Unexpected_token (Token.to_string t)
|
|
|
|
|
2022-01-10 23:11:13 +09:00
|
|
|
(* precedence table.
|
|
|
|
* my first thought was using some sort of partially-ordered graph for
|
|
|
|
* precedency, but infering precedence relation from the graph is hard
|
|
|
|
* and the graph can be made to have loops, I just used plain table. *)
|
2022-01-10 01:31:47 +09:00
|
|
|
let precedence = [
|
2022-01-11 01:05:29 +09:00
|
|
|
Add, 10;
|
|
|
|
Sub, 10;
|
|
|
|
Mul, 20;
|
|
|
|
Div, 20;
|
2022-01-13 01:13:41 +09:00
|
|
|
Mod, 30;
|
|
|
|
Exp, 30;
|
2022-01-10 01:31:47 +09:00
|
|
|
] |> List.to_seq |> Hashtbl.of_seq
|
|
|
|
|
|
|
|
let precedence_of op =
|
2022-01-11 01:05:29 +09:00
|
|
|
Hashtbl.find precedence op
|
2022-01-10 01:31:47 +09:00
|
|
|
|
2022-01-10 23:11:13 +09:00
|
|
|
let is_left_to_right = function
|
|
|
|
| Add | Sub | Mul | Div -> true
|
2022-01-13 01:13:41 +09:00
|
|
|
| _ -> assert false
|
2022-01-10 23:11:13 +09:00
|
|
|
|
2022-01-10 01:31:47 +09:00
|
|
|
let token_to_op = function
|
|
|
|
| Token.Plus -> Add
|
|
|
|
| Minus -> Sub
|
|
|
|
| Asterisk -> Mul
|
|
|
|
| Slash -> Div
|
2022-01-13 01:13:41 +09:00
|
|
|
| Carret -> Exp
|
|
|
|
| Percent -> Mod
|
2022-01-10 01:31:47 +09:00
|
|
|
| _ -> failwith "Parser.token_to_op"
|
|
|
|
|
2022-01-13 00:31:26 +09:00
|
|
|
(* common parsers *)
|
|
|
|
|
|
|
|
let idents 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
|
|
|
|
|
|
|
|
let ident str seq =
|
|
|
|
idents (S.singleton str) seq
|
|
|
|
|
|
|
|
let operator seq =
|
|
|
|
match seq () with
|
|
|
|
| Seq.Nil -> expected "operator"
|
|
|
|
| Seq.Cons (x, seq) ->
|
|
|
|
try token_to_op x, seq with
|
|
|
|
| _ -> expected "operator"
|
|
|
|
|
|
|
|
(* parser combinators *)
|
|
|
|
|
|
|
|
let either f g seq =
|
|
|
|
try f seq with _ -> g seq
|
|
|
|
|
|
|
|
let (@>) f g seq =
|
|
|
|
let a, seq = f seq in
|
|
|
|
g a seq
|
|
|
|
|
|
|
|
(* parse tokens *)
|
2022-01-10 23:11:13 +09:00
|
|
|
let parse ts =
|
2022-01-10 01:31:47 +09:00
|
|
|
(* value := int | ( expr ) *)
|
|
|
|
let rec value seq =
|
|
|
|
match seq () with
|
|
|
|
| Seq.Nil -> assert false
|
|
|
|
| Seq.Cons (x, seq) -> begin match x with
|
|
|
|
| Token.Int n -> Value (Int n), seq
|
2022-01-18 15:33:56 +09:00
|
|
|
| Token.Float n -> Value (Float n), seq
|
2022-01-10 01:31:47 +09:00
|
|
|
| LParen -> expr seq
|
|
|
|
| _ -> unexpected_token x
|
|
|
|
end
|
|
|
|
|
|
|
|
(* binop := binop op binop *)
|
|
|
|
and binop pre left seq =
|
|
|
|
match seq () with
|
|
|
|
| Seq.Nil -> left, Seq.empty
|
|
|
|
| Seq.Cons (x, seq) -> begin match x with
|
2022-01-13 01:13:41 +09:00
|
|
|
| Token.Plus | Minus | Asterisk | Slash | Percent as op ->
|
2022-01-10 01:31:47 +09:00
|
|
|
let op = token_to_op op in
|
|
|
|
let o = precedence_of op in
|
2022-01-11 01:05:29 +09:00
|
|
|
if o > pre then (* op has to be calculated first *)
|
2022-01-10 01:31:47 +09:00
|
|
|
let v, seq = value seq in
|
|
|
|
let right, seq = binop o v seq in
|
|
|
|
binop pre (Ast.binop left op right) seq
|
|
|
|
else
|
|
|
|
left, Seq.cons x seq
|
2022-01-13 01:13:41 +09:00
|
|
|
| Carret as op ->
|
|
|
|
let op = token_to_op op in
|
|
|
|
let o = precedence_of op in
|
|
|
|
if o >= pre then (* op has to be calculated first *)
|
|
|
|
let v, seq = value seq in
|
|
|
|
let right, seq = binop o v seq in
|
|
|
|
binop pre (Ast.binop left op right) seq
|
|
|
|
else
|
|
|
|
left, Seq.cons x seq
|
2022-01-10 01:31:47 +09:00
|
|
|
| RParen -> left, seq
|
|
|
|
| _ -> unexpected_token x
|
|
|
|
end
|
|
|
|
|
2022-01-13 00:31:26 +09:00
|
|
|
and level _ seq =
|
|
|
|
let id, seq = idents (S.of_list ["get"; "set"]) seq in
|
2022-01-11 01:05:29 +09:00
|
|
|
let op, seq = operator seq in
|
|
|
|
if id = "get" then
|
|
|
|
Get_binop_pre op, seq
|
2022-01-13 00:31:26 +09:00
|
|
|
else if id = "set" then
|
2022-01-11 01:05:29 +09:00
|
|
|
let v, seq = value seq in
|
|
|
|
Set_binop_pre (op, v), seq
|
2022-01-13 00:31:26 +09:00
|
|
|
else
|
|
|
|
failwith "Parser.level"
|
2022-01-10 01:31:47 +09:00
|
|
|
|
|
|
|
and expr seq =
|
2022-01-13 00:31:26 +09:00
|
|
|
seq |> either
|
|
|
|
(ident "level" @> level)
|
|
|
|
(value @> binop ~-1)
|
2022-01-10 01:31:47 +09:00
|
|
|
in
|
2022-01-10 23:11:13 +09:00
|
|
|
let ast, rest = expr ts in
|
2022-01-10 01:31:47 +09:00
|
|
|
if rest () <> Seq.Nil then failwith "Parser.parse";
|
|
|
|
ast
|