0

作为学习练习,我正在尝试使用功能解析器库 fparsec ( FParsec ) 为 graphviz 点语言 ( The DOT language ) 实现解析器。该语言描述图形。

查看语言定义,我不得不写下以下定义:

let rec pstmt_list = opt(pstmt .>> opt(pchar ';') >>. opt pstmt_list)

wherepstmtpchar ';'是解析器,.>>>>.左解析器的出现与右解析器的出现组合opt,并将其参数解析器的可选出现解析为选项值。然而,这个定义并不能抱怨“......结果类型将是无限的......”。

通过查看上面链接的 DOT 语言,这个示例可能最容易理解。

我知道以下看似相关的问题:

但是我的 F# 知识可能还不足以翻译它们,如果它们在这里适用的话。

4

2 回答 2

4

FParsec 为解析序列提供了特殊的组合子。通常,您应该更喜欢这些组合器而不是使用递归函数重新实现它们。您可以在此处找到用于解析序列的可用组合子的概述:http ://www.quanttec.com/fparsec/reference/parser-overview.html#parsing-sequences

在此示例pstmt_list中,是一系列以分号分隔并可选结束的语句,因此您可以轻松地将解析器定义为

let pstmt_list = sepEndBy pstmt (pstring ";")
于 2011-06-21T19:29:56.173 回答
2

问题是您的pstmt_list解析器产生了某种类型的一些值,但是当您在定义中使用它时,您将这种类型的值与其他option类型包装起来(使用opt组合器)。

F# 编译器认为解析器返回的值的类型例如'a应该与包装类型相同option 'a(当然,这是不可能的)。

无论如何,我认为这不是你需要做的——.>>组合器创建一个解析器,它返回第二个参数的结果,这意味着你将忽略pstmt到目前为止 parsed 的所有结果。

我想你可能需要这样的东西:

let rec pstmt_list : Parser<int list, unit> = 
  parse.Delay(fun () ->
    opt(pstmt .>> pchar ';') .>>. opt pstmt_list
    |>> (function Some(prev), Some(rest) -> prev::rest
                | Some(prev), _ -> [prev]
                | _, Some(rest) -> rest
                | _ -> [] ))

的额外用途Delay是避免声明直接引用自身的值。

于 2011-06-21T13:15:04.950 回答