11

我一直在考虑使用 Haskell 的 Parsec 解析库来解析 Java 的子集作为递归下降解析器,以替代更传统的解析器生成器解决方案,如 Happy。Parsec 似乎很容易使用,解析速度对我来说绝对不是一个因素。不过,我想知道是否有可能使用 Parsec 实现“备份”,这是一种通过依次尝试每一个来找到要使用的正确产品的技术。举一个简单的例子,考虑 JLS Java 语法的最开始:

Literal:
    IntegerLiteral  
    FloatingPointLiteral

我想要一种不必弄清楚我应该如何订购这两个规则以使解析成功的方法。就目前而言,像这样的幼稚实现:

literal = do {
    x <- try (do { v <- integer; return (IntLiteral v)}) <|>
         (do { v <- float; return (FPLiteral v)});
    return(Literal x)
}

不会工作......像“15.2”这样的输入会导致整数解析器首先成功,然后整个事情会在“。”上窒息。象征。当然,在这种情况下,很明显可以通过重新排序两个产品来解决问题。不过,在一般情况下,找到这样的事情将是一场噩梦,而且我很可能会错过一些案例。理想情况下,我想要一种方法让 Parsec 为我找出这样的东西。这是可能的,还是我只是想对图书馆做太多事情?Parsec 文档声称它可以“解析上下文相关的无限前瞻语法”,所以看起来我应该可以在这里做点什么。

4

2 回答 2

8

可以做到这一点的一种方法是使用try组合器,它允许解析器使用输入并失败,而不会导致整个解析失败。

另一个是使用Text.ParserCombinators.ReadP,它实现了一个对称选择运算符,在其中证明了a +++ b = b +++ a,所以实际上哪个顺序并不重要。我比较偏爱ReadP,因为它很小,但提供了构建真正强大的解析器所需的东西。

于 2010-03-23T17:42:22.303 回答
2

要么使用 Parsec'snotFollowedBy来确保将integer所有内容都消耗到某个令牌分隔符(这种方法大多数情况下将扩展到任意场景),要么查看探索所有可能的解析替代方案的解析器组合器。首先想到的是UU_Parsing库。

于 2010-03-22T21:40:20.183 回答