嵌套解析器中的FParsec回溯

时间:2018-06-28 13:43:49

标签: f# fparsec

我想解析构造为a is x or y or z or b is z or w的表达式,因此基本上我在语法上具有相同的分隔符来表示不同的规则。

我已经成功使用Antlr解析了此类表达式,因为它可以很好地回溯。但是现在我想用FParsec解析它,而且我不希望内部解析器不贪心。我当前的解析器如下所示:

let variable = // matches a,b,c,...

// variables ::= variable { "or" variable }+ ;
let variables =
    variable .>>? keyword "or" .>>.? (sepBy1 variable (keyword "or"))

let operation =
    variable .>>? keyword "is" .>>.? variables

// expression ::= operation { "or" operation }+ ;
let expression =
    operation .>>? keyword "or" .>>.? (sepBy1 variable (keyword "or"))

在我的示例中,变量解析器消耗x or y or z or b,而整个过程在is处失败。这意味着我需要使variables解析器的贪婪程度降低,或使其正确回溯。

我找到了一个similar question,他们在其中制作了sepBy1的回溯版本,但是仍然不能解决我的问题。我想那是因为我想回溯到嵌套的解析器。

那么使FParsec接受我的输入的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

除了我在评论中提到的将or的含义之一转换为|之外,还可以如下使用notFollowedBy (keyword "is")

let variables =
    variable .>>? keyword "or" .>>.? (sepBy1 (variable .>> (notFollowedBy (keyword "is"))) (keyword "or"))

我不太热衷于此解决方案,因为它不易推广。除了is之外,还有其他关键字可以出现在变量之后吗?例如,您是否有类似b matches x or y之类的语法?如果是这样,那么您需要编写类似(notFollowedBy ((keyword "is") <|> (keyword "matches")))的内容,它很快就会变得复杂。但是只要关键字is是唯一一个无法解析的关键字,那么使用(notFollowedBy (keyword "is"))可能是最好的选择。