Add fatal error on Parser

This commit is contained in:
백현웅 2022-02-17 02:51:56 +09:00
parent e3d683c28f
commit 96d0c882b3
4 changed files with 52 additions and 26 deletions

4
ast.ml
View file

@ -1,5 +1,6 @@
(* simple, untyped AST. *) (* simple, untyped AST. *)
type t = type t =
| Nothing
| Nint of int | Nint of int
| Nfloat of float | Nfloat of float
| Nbool of bool | Nbool of bool
@ -59,6 +60,7 @@ let print ast =
let pr = Printf.printf in let pr = Printf.printf in
let rec aux = function let rec aux = function
| Nothing -> pr ""
| Nint n -> pr "%d" n | Nint n -> pr "%d" n
| Nfloat n -> pr "%f" n | Nfloat n -> pr "%f" n
| Nbool b -> pr "%b" b | Nbool b -> pr "%b" b
@ -75,7 +77,7 @@ let print ast =
| Let (v, e) -> | Let (v, e) ->
pr "(define %s " v; aux e; pr ")" pr "(define %s " v; aux e; pr ")"
| Letin (v, e, f) -> | Letin (v, e, f) ->
pr "(let ((%s " v; aux e; pr "))"; aux f; pr ")" pr "(let ((%s " v; aux e; pr ")) "; aux f; pr ")"
| Unary (op, t) -> | Unary (op, t) ->
let op = op_to_string op in let op = op_to_string op in
pr "(%s " op; aux t; pr ")" pr "(%s " op; aux t; pr ")"

View file

@ -249,6 +249,7 @@ exception Unbound of string
let rec eval env ast = let rec eval env ast =
let rec aux = function let rec aux = function
| Nothing -> Nop
| Nint n -> Int n | Nint n -> Int n
| Nfloat n -> Float n | Nfloat n -> Float n
| Nbool b -> Bool b | Nbool b -> Bool b

View file

@ -9,6 +9,8 @@ let error_to_string e =
| Lex.Invalid_character (col, c) -> | Lex.Invalid_character (col, c) ->
sprintf "invalid character %c at col %d" c col sprintf "invalid character %c at col %d" c col
| Lex.Expected (col, c) -> sprintf "expected %c at col %d" c col | Lex.Expected (col, c) -> sprintf "expected %c at col %d" c col
| Parser.Fatal e -> raise e
| Parser.End_of_tokens -> "expression ended abruptly"
| Parser.Expected (col, t) -> sprintf "expected %s at col %d" t col | Parser.Expected (col, t) -> sprintf "expected %s at col %d" t col
| Parser.Unexpected_token (col, t) -> | Parser.Unexpected_token (col, t) ->
sprintf "unexpected token \"%s\" at col %d" t col sprintf "unexpected token \"%s\" at col %d" t col

View file

@ -2,6 +2,8 @@ open Ast
module S = Set.Make(String) module S = Set.Make(String)
(* fatal exception that parsing need to be stopped *)
exception Fatal of exn
exception Expected of int * string exception Expected of int * string
exception Unexpected_token of int * string exception Unexpected_token of int * string
exception End_of_tokens exception End_of_tokens
@ -84,7 +86,7 @@ let is_keyword = function
| "if" | "then" | "else" | "let" | "in" -> true | "if" | "then" | "else" | "let" | "in" -> true
| _ -> false | _ -> false
(* common parsers *) (* parser primitives *)
let any seq = let any seq =
match seq () with match seq () with
@ -120,16 +122,25 @@ let operator seq =
(* parser combinators *) (* parser combinators *)
let mustbe f seq =
try f seq with
| e -> raise @@ Fatal e
let oneof fs seq = let oneof fs seq =
let rec aux = function let rec aux = function
| [] -> assert false | [] -> assert false
| [f] -> f seq | [f] -> f seq
| f::fs -> (try f seq with _ -> aux fs) | f::fs ->
(try f seq with
| Fatal _ as e -> raise e
| _ -> aux fs)
in in
aux fs aux fs
let either f g = fun seq -> let either f g = fun seq ->
try f seq with _ -> g seq try f seq with
| Fatal _ as e -> raise e
| _ -> g seq
let (@>) f g = fun seq -> let (@>) f g = fun seq ->
let a, seq = f seq in let a, seq = f seq in
@ -141,6 +152,7 @@ let more f seq =
let x, seq = f seq in let x, seq = f seq in
aux (x::xs) seq aux (x::xs) seq
with with
| Fatal _ as e -> raise e
| _ -> xs, seq | _ -> xs, seq
in in
let xs, seq = aux [] seq in let xs, seq = aux [] seq in
@ -153,8 +165,14 @@ let rec decl seq =
seq |> oneof [ seq |> oneof [
expr min_int; expr min_int;
let_global; let_global;
nothing;
] ]
and nothing seq =
match seq () with
| Seq.Nil -> Nothing, seq
| Seq.Cons ((col, x), _) -> unexpected_token col x
(* let_global := "let" ident "=" expr *) (* let_global := "let" ident "=" expr *)
and let_global seq = and let_global seq =
let _, seq = ident "let" seq in let _, seq = ident "let" seq in
@ -178,16 +196,17 @@ and expr pre seq =
assoc; assoc;
lambda; lambda;
extern_value; extern_value;
(* TODO: place error routine here *)
] ]
(* let_value := "let" id "=" expr "in" expr *) (* let_value := "let" id "=" expr "in" expr *)
and let_value seq = and let_value seq =
let _, seq = ident "let" seq in let _, seq = ident "let" seq in
let id, seq = any_ident seq in let id, seq = mustbe any_ident seq in
let _, seq = token Equal seq in let _, seq = token Equal seq in
let e, seq = expr min_int seq in let e, seq = mustbe (expr min_int) seq in
let _, seq = ident "in" seq in let _, seq = ident "in" seq in
let f, seq = expr min_int seq in let f, seq = mustbe (expr min_int) seq in
Letin (id, e, f), seq Letin (id, e, f), seq
(* level := "level" {"get" | "set"} [op] *) (* level := "level" {"get" | "set"} [op] *)
@ -219,22 +238,24 @@ and assoc seq =
(* lambda := "fun" [ident]+ "->" expr *) (* lambda := "fun" [ident]+ "->" expr *)
and lambda seq = and lambda seq =
let _, seq = ident "fun" seq in let _, seq = ident "fun" seq in
let v0, seq = any_ident seq in seq |> mustbe (fun seq ->
let vars, seq = more any_ident seq in let v0, seq = any_ident seq in
let _, seq = token Right_arrow seq in let vars, seq = more any_ident seq in
let e, seq = expr min_int seq in let _, seq = token Right_arrow seq in
List.fold_right (fun v f -> Nfunction (v, f)) (v0::vars) e, let e, seq = expr min_int seq in
seq List.fold_right (fun v f -> Nfunction (v, f)) (v0::vars) e,
seq)
(* ifexpr := "if" expr "then" expr "else" expr *) (* ifexpr := "if" expr "then" expr "else" expr *)
and ifexpr seq = and ifexpr seq =
let _, seq = ident "if" seq in let _, seq = ident "if" seq in
let co, seq = expr min_int seq in seq |> mustbe (fun seq ->
let _, seq = ident "then" seq in let co, seq = expr min_int seq in
let th, seq = expr min_int seq in let _, seq = ident "then" seq in
let _, seq = ident "else" seq in let th, seq = expr min_int seq in
let el, seq = expr min_int seq in let _, seq = ident "else" seq in
If (co, th, el), seq let el, seq = expr min_int seq in
If (co, th, el), seq)
(* apply := value [value]+ *) (* apply := value [value]+ *)
and apply seq = and apply seq =
@ -246,7 +267,7 @@ and apply seq =
(* extern_value := external ident *) (* extern_value := external ident *)
and extern_value seq = and extern_value seq =
let _, seq = ident "external" seq in let _, seq = ident "external" seq in
let id, seq = any_ident seq in let id, seq = mustbe any_ident seq in
Nexternal id, seq Nexternal id, seq
(* unary := - value *) (* unary := - value *)
@ -257,7 +278,7 @@ and unary seq =
then Negate, seq then Negate, seq
else expected col "minus (-)" else expected col "minus (-)"
in in
let v, seq = value seq in let v, seq = mustbe value seq in
Ast.unary op v, seq Ast.unary op v, seq
(* value := int | float | ( expr ) *) (* value := int | float | ( expr ) *)
@ -265,7 +286,7 @@ and value seq =
match seq () with match seq () with
| Seq.Nil -> raise End_of_tokens | Seq.Nil -> raise End_of_tokens
| Seq.Cons ((col, x), seq) -> begin match x with | Seq.Cons ((col, x), seq) -> begin match x with
| Ident id when is_keyword id -> failwith "value" | Ident id when is_keyword id -> expected col "value"
| Ident "true" -> Nbool true, seq | Ident "true" -> Nbool true, seq
| Ident "false" -> Nbool false, seq | Ident "false" -> Nbool false, seq
| Ident id -> Var id, seq | Ident id -> Var id, seq
@ -276,8 +297,8 @@ and value seq =
let _, t, seq = any seq in let _, t, seq = any seq in
Nsymbol (Token.to_string t), seq Nsymbol (Token.to_string t), seq
| LParen -> | LParen ->
let e, seq = expr min_int seq in let e, seq = mustbe (expr min_int) seq in
let _, seq = token RParen seq in let _, seq = mustbe (token RParen) seq in
e, seq e, seq
| _ -> unexpected_token col x | _ -> unexpected_token col x
end end
@ -294,7 +315,7 @@ and binop pre left seq =
if op_pre > pre if op_pre > pre
|| (op_is_right_to_left op && op_pre = pre) || (op_is_right_to_left op && op_pre = pre)
then then
let right, seq = expr op_pre seq in let right, seq = mustbe (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 (col, x) seq left, Seq.cons (col, x) seq
@ -306,6 +327,6 @@ and binop pre left seq =
(* parse tokens *) (* parse tokens *)
let parse ts = let parse ts =
let ast, rest = decl ts in let ast, rest = try decl ts with Fatal e -> raise e in
if rest () <> Seq.Nil then failwith "Parser.parse"; if rest () <> Seq.Nil then failwith "Parser.parse";
ast ast