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

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

Recursive Lisp parser with Ocaml Opal

问题

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

这是我的AST:

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

这是解析器:

open Opal
open Ast

let integer = many1 digit => implode % int_of_string => fun n -> Atom (Num n)
let ident = many alpha_num => implode => fun i -> Atom (Ident i)
let parens = between (token "(") (token ")")
let atom = integer <|> ident
let expr = parens (sep_by atom space)

let parse_expr input =
  match parse expr input with
  | Some ans -> List.iter (fun a -> Printf.printf "%s" (show_sexp a)) ans
  | None -> print_endline "ERROR!"

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

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

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

这会产生一个错误:

8 | let rec expr = parens (sep_by (atom <|> expr) space)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type char input -> (sexp list * char input) option
       but an expression was expected of type
         char input -> (sexp * char input) option
       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:

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

And this is the parser:

open Opal
open Ast

let integer = many1 digit =&gt; implode % int_of_string =&gt; fun n -&gt; Atom (Num n)
let ident = many alpha_num =&gt; implode =&gt; fun i -&gt; Atom (Ident i)
let parens = between (token &quot;(&quot;) (token &quot;)&quot;)
let atom = integer &lt;|&gt; ident
let expr = parens (sep_by atom space)

let parse_expr input =
  match parse expr input with
  | Some ans -&gt; List.iter (fun a -&gt; Printf.printf &quot;%s&quot; (show_sexp a)) ans
  | 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:

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

And this produces an error:

8 | let rec expr = parens (sep_by (atom &lt;|&gt; expr) space)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type char input -&gt; (sexp list * char input) option
       but an expression was expected of type
         char input -&gt; (sexp * char input) option
       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

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

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

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

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

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

let rec expr input =
  (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:

let rec expr input = 
  (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:

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

So maybe something like this instead?

let rec expr input =
  (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:

确定