【问题标题】:Right recursive grammar or left recursive?右递归语法还是左递归?
【发布时间】:2014-06-03 21:21:14
【问题描述】:

我几乎不知道我要问什么,所以我想根据为给定语法实现解析器所需的技能水平提出建议(因为我是这种类型的初学者解析器和语言的正式方法)。

回到几年前,这种情况让我想起了帕斯卡语法与 C/C++ 语法,左右的东西。

但我不打算这样做,我的目的是为 Markdown 等文档的标记语言实现一个简单的解析器。

所以考虑到我是从一种标记语言开始的,我想让事情变得简单,这是这两个选项之间最容易处理的一个,为什么。另一种语法对我来说可能是一个更容易的选择?如果是,你建议哪一个?

【问题讨论】:

    标签: c++ c parsing markup


    【解决方案1】:

    右递归与左递归主要取决于您将如何实现解析器。

    如果您要进行自顶向下(例如递归下降)解析器,您通常希望在语法中使用右递归(对于纯递归下降,这是唯一的选择)。

    如果你打算做一个自底向上的解析器,你通常希望使用左递归。自底向上解析器通常使用 Yacc 或 Bison 之类的解析器生成器生成,其中大多数 可以 在需要时处理右递归,但可以更有效地处理左递归,因此只要不是对语义产生不利影响。

    【讨论】:

    • 您能否为 PEG 语法(en.wikipedia.org/wiki/Parsing_expression_grammar)指定一个特定位置?我的意思是,如果我要为 PEG 编写解析器,我可以假设某些东西会比其他选项更好用?我可以将选项减少到更小的数量或更具体的区域?
    • @user2485710:抱歉,我真的不确定。
    • PEG 不需要左递归(与 LL 文法一样),尽管有一些实现基本上可以通过将文法转换为非左递归形式来处理它。由于 PEG 直接允许 */+ 闭包,因此对于左关联操作需要左递归的问题没有 LL 语法那么重要
    • @ChrisDodd 以略微 OT 为代价,你能在 C/C++ 中为 PEG 语法命名一个好的解析器生成器吗?我想有一个参考作为起点来正式定义我在这里谈论的内容。
    • @user2485710: boost::spirit 对其解析器生成器使用 PEG 语法/解析
    【解决方案2】:

    这取决于您使用的解析器类型。如果使用 LL 类型,则必须使用右递归。

    如果使用 LR 类型,则可以使用左递归或右递归。然而,左递归使堆栈深度最小化。

    【讨论】:

    • “解析器类型”是什么意思,存在多少种解析器?
    • 存在许多类型的解析器。两个主要组是 LL 和 LR。它们有 LR(1)、LALR(1) 等子组。
    • 这就是为什么 Pascal 编译器使用更少内存而 C++ 编译器通常需要更多内存的原因?实现怎么样?实现给定的解析器有多难?
    • 另外,假设我的语法是PEG语法,什么样的解析器可以满足我的要求?
    • 不,这不是 Pascal 编译器使用较少内存的原因。那是因为 Pascal 是一种更简单的语言,并且具有明确定义的语法。 Pascal vs C++ 与左右递归无关。
    【解决方案3】:

    嗯,有两种基本类型的语法:

    LL(k) = Left to tight, leftmost derivation, k symbols look ahead
    LR(k) = Left to right, rightmost derivation, k symbols look ahead
    

    LR 解析器更难手工编写,但是,它们比 LL 解析器更强大。如果您正在查看一些流行的解析器生成器工具:

    ANTLR : a LL parser
    BISON:  a LALR(1) parser (a type of LR parser but a bit less powerful)
    CUP:    a LALR(1) parser (outputs Java / C# code)
    

    【讨论】:

    • 谢谢,我已经有了一些已经可用的解析器或可以生成解析器的库和工具的名称。我现在真正的问题是 PEG 语法似乎并不那么流行,例如,我找不到 PEG 语法的野牛或 antlr 等价物,也许只是我弄错了,或者这种语法不像 left 或正确的语法。
    • 嗯,到目前为止,我只使用过 CUP 和 Bison,并设法编写了一个 pascal 编译器,所以这些东西非常强大。恕我直言,一个好的词法分析器(弹性提示提示)和一个好的解析器生成器将满足您以稳健的方式创建新语言的所有需求:)
    • 请注意,LL(k) 是 LR(k) 的子集——所有 LL(k) 语法都是 LR(k)。此外,虽然语法描述了一种语言,但有许多语法可以描述任何给定的语言。仅仅因为一个文法不是 LL(k)(或 LR(k))并不意味着对于同一语言没有更简单的文法是 LL(k)(或 LR(k))
    猜你喜欢
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    相关资源
    最近更新 更多