使用Ocaml Opal实现的递归Lisp解析器。

huangapple go评论148阅读模式
英文:

Recursive Lisp parser with Ocaml Opal

问题

我正在尝试使用OCaml Opal编写一个简单的Lisp解析器:

这是我的AST:

  1. type atom = Num of int | Ident of string [@@deriving show]
  2. type sexp = Atom of atom | ListSexp of sexp list [@@deriving show]

这是解析器:

  1. open Opal
  2. open Ast
  3. let integer = many1 digit => implode % int_of_string => fun n -> Atom (Num n)
  4. let ident = many alpha_num => implode => fun i -> Atom (Ident i)
  5. let parens = between (token "(") (token ")")
  6. let atom = integer <|> ident
  7. let expr = parens (sep_by atom space)
  8. let parse_expr input =
  9. match parse expr input with
  10. | Some ans -> List.iter (fun a -> Printf.printf "%s" (show_sexp a)) ans
  11. | None -> print_endline "ERROR!"

当我尝试解析Parser.parse_expr (LazyStream.of_string "(5 3 abc)")时,这个解析器工作得很好。

然而,我尝试递归地解析S表达式,通过简单地修改我的expr函数为:

  1. let rec expr = parens (sep_by (atom <|> expr) space)

这会产生一个错误:

  1. 8 | let rec expr = parens (sep_by (atom <|> expr) space)
  2. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  3. Error: This expression has type char input -> (sexp list * char input) option
  4. but an expression was expected of type
  5. char input -> (sexp * char input) option
  6. Type sexp list is not compatible with type sexp

这个错误似乎是合理的,因为atom函数返回的类型是char input -> (sexp * char input) option,而expr函数返回的类型是char input -> (sexp list * char input) option

但我不确定如何修复这个问题。有什么想法吗?

英文:

I'm trying to write a simple Lisp parser with OCaml Opal:

This is my AST:

  1. type atom = Num of int | Ident of string [@@deriving show]
  2. type sexp = Atom of atom | ListSexp of sexp list [@@deriving show]

And this is the parser:

  1. open Opal
  2. open Ast
  3. let integer = many1 digit =&gt; implode % int_of_string =&gt; fun n -&gt; Atom (Num n)
  4. let ident = many alpha_num =&gt; implode =&gt; fun i -&gt; Atom (Ident i)
  5. let parens = between (token &quot;(&quot;) (token &quot;)&quot;)
  6. let atom = integer &lt;|&gt; ident
  7. let expr = parens (sep_by atom space)
  8. let parse_expr input =
  9. match parse expr input with
  10. | Some ans -&gt; List.iter (fun a -&gt; Printf.printf &quot;%s&quot; (show_sexp a)) ans
  11. | None -&gt; print_endline &quot;ERROR!&quot;

This works ok when I try to parse Parser.parse_expr (LazyStream.of_string &quot;(5 3 abc)&quot;)

However, the next thing I tried is to parse S-Expressions recursively by naively modifying my expr function to:

  1. let rec expr = parens (sep_by (atom &lt;|&gt; expr) space)

And this produces an error:

  1. 8 | let rec expr = parens (sep_by (atom &lt;|&gt; expr) space)
  2. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  3. Error: This expression has type char input -&gt; (sexp list * char input) option
  4. but an expression was expected of type
  5. char input -&gt; (sexp * char input) option
  6. Type sexp list is not compatible with type sexp

This seems ok since atom function returns char input -&gt; (sexp * char input) option while expr function returns char input -&gt; (sexp list * char input) option.

But I'm not sure how can to fix this. Ideas?

答案1

得分: 2

你需要将 sexp lisp 包装在 ListSexp 构造函数中,以便它可以成为 sexp 类型,否则你会有两个冲突的类型,sexp 可以是 AtomListSexp,以及 sexp list

你测试了以下代码,并且它是有效的:

  1. let rec expr input =
  2. (parens (sep_by (expr &lt;|&gt; atom) space) =&gt; fun l -&gt; ListSexp l) input

但我认为一个表达式并不总是一个列表,在 EBNF 表示法中,我会这样写:

  1. EXPR := ATOM | &quot;(&quot; EXPR* &quot;)&quot;

所以也许可以尝试这样修改:

  1. let rec expr input =
  2. (parens (sep_by expr space) =&gt; (fun l -&gt; ListSexp l) &lt;|&gt; atom) input
英文:

You need to wrap sexp lisp in a ListSexp constructor so that it can be of type sexp, otherwise you have two conflicting types, sexp which is either an Atom or a ListSexp, and sexp list.

You tested the following, and it works:

  1. let rec expr input =
  2. (parens (sep_by (expr &lt;|&gt; atom) space) =&gt; fun l -&gt; ListSexp l) input

But I think an expression is not always a list, in EBNF notation I would write:

  1. EXPR := ATOM | &quot;(&quot; EXPR* &quot;)&quot;

So maybe something like this instead?

  1. let rec expr input =
  2. (parens (sep_by expr space) =&gt; (fun l -&gt; ListSexp l) &lt;|&gt; atom) input

huangapple
  • 本文由 发表于 2023年7月31日 18:11:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76802599.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定