是否有任何用于功能语言的LL解析器生成器,如Haskell或Scala?

时间:2011-03-31 23:37:10

标签: scala haskell functional-programming antlr3 parser-generator

我注意到明显缺乏LL解析器,它们在函数式语言中创建解析器。对于我一直在寻找没有成功的东西的理想发现是为ANTLR样式的LL(*)语法生成Haskell解析器(模式的重新格式化模式),并且惊讶于每个最后的解析器生成器都具有功能我找到的语言目标是某种LR解析器。

我想转换我正在研究的这种语言的解析器,它具有ANTLR的功能特性,并且在语言本身中自我托管,如果我可以移植到我的语言几乎肯定是正确的,那将会有很大的帮助。另一种功能语言(最好是我熟悉的,Haskell和Scala),而不是必须从头开始重写它,尽管最后我可能会这样做,因为核心语言很小。

在这一点上,甚至对此的解决方案还是非常好奇为什么没有这样的LL(*)甚至LL(k)解析器生成器,但是很多LR生成器因为LL本身就更容易了。

6 个答案:

答案 0 :(得分:20)

这样做的主要原因是大多数用函数式语言编写的LL(k)解析器只是使用解析器组合器实现,因为生成解析器组合器库的最简单路径是recursive descent

Haskell的parsecattoparsecpolyparse以及Scala的股票解析器组合器都产生了有效的LL(*)解析器。

parsec和attoparsec都要求你使用显式的try组合来获得回溯,但这只是为了提高效率而scala parser combinators也可以处理packrat parsing

考虑Brent Yorgey最近的announcement套餐unbound中的以下片段:

parseAtom = parens parseTerm
    <|> var <$> ident
    <|> lam <$> brackets ident <*> parseTerm

很容易看到原始语法。

LR解析器需要更复杂的预处理才能生成有效执行的表,因为使用类似recursive ascent的直接手动编码非常糟糕。

通过将解析器组合器实现为EDSL而不是外部工具,可以更好地使用编程语言的高级功能。您可以使语法的某些部分更高阶,将lexer hack直接构建到解析器中等等。典型的LR解析器生成器不能执行这些操作,或者只能在有限的上下文中以特殊方式提供它们,因为需要能够最终发射表格。

答案 1 :(得分:4)

你激励我将一个旧的爱好项目发布到https://github.com/nrnrnr/ebnf。它支持标准ML的LL(1)解析器生成。如果你找到了解Icon的人,那么适应Haskell并不难。

爱德华评论说,人们倾向于选择组合器来进行解析是非常正确的,但是找到FIRST和FOLLOW集的工具有一些优点,并且会抱怨模棱两可。

EBNF的主要优点是它的符号:序列,Maybe类型和保留字都是本机支持的,没有额外的麻烦。

答案 2 :(得分:3)

SML已经使用了ml-antlr几年了:

http://www.classes.cs.uchicago.edu/archive/2007/winter/22610-1/docs/lpt-manual.pdf

还有方案的sllgen。

至于为什么LR解析器生成器比LL解析器多得多 - 手动编写LR解析器很困难,所以你真的需要一个生成器。使用LL解析器,手动编码的实现仍然与语法匹配,因此对生成器的需求要少得多。

答案 3 :(得分:2)

使用Scala,您可以使用所有现有的Java工具,而无需太多开销。 JavaCC是LL(k)解析器生成器。您可以使用它自动创建具体的语法树,并在Scala中执行其他所有操作。我实际上是为一个小项目做的,只是因为JavaCC语法已经存在。

答案 4 :(得分:1)

在我描述LL(k)解决方案under development之前,我将解释为什么我没有使用我所知道的其他可用选项。

  1. 解析器组合子库,即递归下降解析器,不会:

    • 保证无上下文语法(CFG),因为他们do not calculate是第一组和跟随集。
    • 执行有效的表驱动k前瞻标记。相反,它们会进行低效的回溯。
    • 不要使用效率更高的stack based解析算法。

    缺乏上下文自由是manifested as ambiguities in the syntax,例如是否在源代码行的开头(在没有用分号发送的行之后)的运算符是在其右侧的表达式上的前缀一元,或者在前一个源的末尾的表达式上的中缀二元运算符代码行。

  2. JavaCC有以下缺点:

    • 将词法分析器和解析器生成混为一谈。
    • 过于冗长的BNF语法语法。
    • 输出Java,我想要Scala(最终是Copute)。
    • afaics不会在语法和AST中紧密结合名称。
    • afaics单片源代码,例如不能(轻松)提取模块以生成第一个和后续集合(这样我就可以插入自己的解析器生成)。
  3. 我正在尝试创建一个LL(k)解析器生成器,它将输出到Scala,然后希望引导输出我正在开发的语言(Copute,它将编译为Scala)。

    我目前的尝试是使用subset SLK语法语法,因此SLK工具可用于验证语法是否无上下文。

答案 5 :(得分:-2)

您可以使用ANTLR在Java(以及其他)中生成LL *解析器,因此.class resp .jar个文件。