Add associativity control
This commit is contained in:
parent
e859d01683
commit
5aaa261198
3 changed files with 87 additions and 20 deletions
20
ast.ml
20
ast.ml
|
@ -2,10 +2,12 @@ module Type = struct
|
||||||
type t =
|
type t =
|
||||||
| Int
|
| Int
|
||||||
| Float
|
| Float
|
||||||
|
| String
|
||||||
|
|
||||||
let to_string = function
|
let to_string = function
|
||||||
| Int -> "int"
|
| Int -> "int"
|
||||||
| Float -> "float"
|
| Float -> "float"
|
||||||
|
| String -> "string"
|
||||||
|
|
||||||
let merge a b =
|
let merge a b =
|
||||||
match a, b with
|
match a, b with
|
||||||
|
@ -22,16 +24,24 @@ module Value = struct
|
||||||
type t =
|
type t =
|
||||||
| Int of int
|
| Int of int
|
||||||
| Float of float
|
| Float of float
|
||||||
|
| String of string
|
||||||
| Nop (* return of system operations *)
|
| Nop (* return of system operations *)
|
||||||
|
|
||||||
let to_string = function
|
let to_string = function
|
||||||
| Int n -> Printf.sprintf "%d" n
|
| Int n -> string_of_int n
|
||||||
| Float n -> Printf.sprintf "%f" n
|
| Float n -> string_of_float n
|
||||||
|
| String s -> s
|
||||||
| Nop -> "nop"
|
| Nop -> "nop"
|
||||||
|
|
||||||
|
let of_token = function
|
||||||
|
| Token.Int n -> Int n
|
||||||
|
| Float n -> Float n
|
||||||
|
| _ -> invalid_arg "Value.of_token"
|
||||||
|
|
||||||
let typeof = function
|
let typeof = function
|
||||||
| Int _ -> Type.Int
|
| Int _ -> Type.Int
|
||||||
| Float _ -> Type.Float
|
| Float _ -> Type.Float
|
||||||
|
| String _ -> Type.String
|
||||||
| Nop -> failwith "Value.typeof"
|
| Nop -> failwith "Value.typeof"
|
||||||
|
|
||||||
let promote = function
|
let promote = function
|
||||||
|
@ -92,6 +102,8 @@ type t =
|
||||||
| Binop of t * Binop.t * t
|
| Binop of t * Binop.t * t
|
||||||
| Set_binop_pre of Binop.t * t
|
| Set_binop_pre of Binop.t * t
|
||||||
| Get_binop_pre of Binop.t
|
| Get_binop_pre of Binop.t
|
||||||
|
| Set_binop_aso of Binop.t * string
|
||||||
|
| Get_binop_aso of Binop.t
|
||||||
|
|
||||||
let value v = Value v
|
let value v = Value v
|
||||||
|
|
||||||
|
@ -115,5 +127,9 @@ let print ast =
|
||||||
pr ")"
|
pr ")"
|
||||||
| Get_binop_pre op ->
|
| Get_binop_pre op ->
|
||||||
pr "(get_pre %s)" (Binop.to_string op)
|
pr "(get_pre %s)" (Binop.to_string op)
|
||||||
|
| Set_binop_aso (op, aso) ->
|
||||||
|
pr "(set_assoc %s %s)" (Binop.to_string op) aso
|
||||||
|
| Get_binop_aso op ->
|
||||||
|
pr "(get_pre %s)" (Binop.to_string op)
|
||||||
in
|
in
|
||||||
aux ast; pr "\n"
|
aux ast; pr "\n"
|
||||||
|
|
7
eval.ml
7
eval.ml
|
@ -41,5 +41,12 @@ let eval vars ast =
|
||||||
Nop
|
Nop
|
||||||
| Get_binop_pre op ->
|
| Get_binop_pre op ->
|
||||||
Int (Hashtbl.find Parser.precedence op)
|
Int (Hashtbl.find Parser.precedence op)
|
||||||
|
| Set_binop_aso (op, a) ->
|
||||||
|
Hashtbl.replace Parser.oper_assoc op @@ Parser.assoc_of_string a;
|
||||||
|
Nop
|
||||||
|
| Get_binop_aso op ->
|
||||||
|
match Hashtbl.find_opt Parser.oper_assoc op with
|
||||||
|
| None -> String "left"
|
||||||
|
| Some a -> String (Parser.assoc_to_string a)
|
||||||
in
|
in
|
||||||
aux ast
|
aux ast
|
||||||
|
|
80
parser.ml
80
parser.ml
|
@ -33,6 +33,15 @@ type associativity =
|
||||||
| Left_to_right
|
| Left_to_right
|
||||||
| Right_to_left
|
| Right_to_left
|
||||||
|
|
||||||
|
let assoc_of_string = function
|
||||||
|
| "left" -> Left_to_right
|
||||||
|
| "right" -> Right_to_left
|
||||||
|
| _ -> invalid_arg "assoc_of_string"
|
||||||
|
|
||||||
|
let assoc_to_string = function
|
||||||
|
| Left_to_right -> "left"
|
||||||
|
| Right_to_left -> "right"
|
||||||
|
|
||||||
let oper_assoc = [
|
let oper_assoc = [
|
||||||
Exp, Right_to_left;
|
Exp, Right_to_left;
|
||||||
] |> List.to_seq |> Hashtbl.of_seq
|
] |> List.to_seq |> Hashtbl.of_seq
|
||||||
|
@ -62,6 +71,13 @@ let token_is_operator tok =
|
||||||
|
|
||||||
(* common parsers *)
|
(* common parsers *)
|
||||||
|
|
||||||
|
let token tok seq =
|
||||||
|
match seq () with
|
||||||
|
| Seq.Nil -> expected @@ Token.to_string tok
|
||||||
|
| Seq.Cons (x, seq) ->
|
||||||
|
if x = tok then x, seq
|
||||||
|
else expected @@ Token.to_string tok
|
||||||
|
|
||||||
let idents set seq =
|
let idents set seq =
|
||||||
match seq () with
|
match seq () with
|
||||||
| Seq.Nil ->
|
| Seq.Nil ->
|
||||||
|
@ -85,23 +101,33 @@ let operator seq =
|
||||||
|
|
||||||
(* parser combinators *)
|
(* parser combinators *)
|
||||||
|
|
||||||
let either f g seq =
|
let oneof fs seq =
|
||||||
try f seq with _ -> g seq
|
let rec aux = function
|
||||||
|
| [] -> assert false
|
||||||
|
| [f] -> f seq
|
||||||
|
| f::fs -> (try f seq with _ -> aux fs)
|
||||||
|
in
|
||||||
|
aux fs
|
||||||
|
|
||||||
let (@>) f g seq =
|
let (@>) f g = fun seq ->
|
||||||
let a, seq = f seq in
|
let a, seq = f seq in
|
||||||
g a seq
|
g a seq
|
||||||
|
|
||||||
(* expr := "level" level_inner
|
(* expr := level
|
||||||
|
* | assoc
|
||||||
|
* | let
|
||||||
* | value binop_right
|
* | value binop_right
|
||||||
*)
|
*)
|
||||||
let rec expr seq =
|
let rec expr pre seq =
|
||||||
seq |> either
|
seq |> oneof [
|
||||||
(ident "level" @> level_inner)
|
level;
|
||||||
(value @> binop ~-1)
|
assoc;
|
||||||
|
value @> binop pre;
|
||||||
|
]
|
||||||
|
|
||||||
(* level_inner := "get" | "set" [op] *)
|
(* level := "level" {"get" | "set"} [op] *)
|
||||||
and level_inner _ seq =
|
and level seq =
|
||||||
|
let _, seq = ident "level" seq in
|
||||||
let id, seq = idents (S.of_list ["get"; "set"]) seq in
|
let id, seq = idents (S.of_list ["get"; "set"]) seq in
|
||||||
let op, seq = operator seq in
|
let op, seq = operator seq in
|
||||||
if id = "get" then
|
if id = "get" then
|
||||||
|
@ -112,7 +138,20 @@ and level_inner _ seq =
|
||||||
else
|
else
|
||||||
failwith "Parser.level"
|
failwith "Parser.level"
|
||||||
|
|
||||||
(* value := int | ( expr ) *)
|
(* assoc := "assoc" {"get" | "set"} [op] *)
|
||||||
|
and assoc seq =
|
||||||
|
let _, seq = ident "assoc" seq in
|
||||||
|
let id, seq = idents (S.of_list ["get"; "set"]) seq in
|
||||||
|
let op, seq = operator seq in
|
||||||
|
if id = "get" then
|
||||||
|
Get_binop_aso op, seq
|
||||||
|
else if id = "set" then
|
||||||
|
let a, seq = idents (S.of_list ["left"; "right"]) seq in
|
||||||
|
Set_binop_aso (op, a), seq
|
||||||
|
else
|
||||||
|
failwith "Parser.assoc"
|
||||||
|
|
||||||
|
(* value := int | float | ( expr ) *)
|
||||||
and value seq =
|
and value seq =
|
||||||
match seq () with
|
match seq () with
|
||||||
| Seq.Nil -> raise End_of_tokens
|
| Seq.Nil -> raise End_of_tokens
|
||||||
|
@ -120,7 +159,10 @@ and value seq =
|
||||||
| Token.Int n -> Value (Int n), seq
|
| Token.Int n -> Value (Int n), seq
|
||||||
| Float n -> Value (Float n), seq
|
| Float n -> Value (Float n), seq
|
||||||
| Ident id -> Var id, seq
|
| Ident id -> Var id, seq
|
||||||
| LParen -> expr seq
|
| LParen ->
|
||||||
|
let e, seq = expr min_int seq in
|
||||||
|
let _, seq = token RParen seq in
|
||||||
|
e, seq
|
||||||
| _ -> unexpected_token x
|
| _ -> unexpected_token x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,20 +173,22 @@ and binop pre left seq =
|
||||||
| Seq.Cons (x, seq) -> begin match x with
|
| Seq.Cons (x, seq) -> begin match x with
|
||||||
| op when token_is_operator op ->
|
| op when token_is_operator op ->
|
||||||
let op = token_to_op op in
|
let op = token_to_op op in
|
||||||
let o = precedence_of op in
|
let op_pre = precedence_of op in
|
||||||
(* op has to be calculated first *)
|
(* op has to be calculated first *)
|
||||||
if o > pre || (op_is_right_to_left op && o = pre) then
|
if op_pre > pre
|
||||||
let v, seq = value seq in
|
|| (op_is_right_to_left op && op_pre = pre)
|
||||||
let right, seq = binop o v seq in
|
then
|
||||||
|
let right, seq = expr op_pre seq in
|
||||||
binop pre (Ast.binop left op right) seq
|
binop pre (Ast.binop left op right) seq
|
||||||
else
|
else
|
||||||
left, Seq.cons x seq
|
left, Seq.cons x seq
|
||||||
| Token.RParen -> left, seq
|
|
||||||
|
| Token.RParen -> left, Seq.cons x seq
|
||||||
| _ -> unexpected_token x
|
| _ -> unexpected_token x
|
||||||
end
|
end
|
||||||
|
|
||||||
(* parse tokens *)
|
(* parse tokens *)
|
||||||
let parse ts =
|
let parse ts =
|
||||||
let ast, rest = expr ts in
|
let ast, rest = expr min_int ts in
|
||||||
if rest () <> Seq.Nil then failwith "Parser.parse";
|
if rest () <> Seq.Nil then failwith "Parser.parse";
|
||||||
ast
|
ast
|
||||||
|
|
Loading…
Add table
Reference in a new issue