【问题标题】:Rewrite recursive BNF rule with iteration用迭代重写递归 BNF 规则
【发布时间】:2015-04-20 22:32:49
【问题描述】:

看下面的递归BNF规则

(1) X = Xa | b

这会产生类似的句子

X = b
X = ba
X = baa
X = baaa
...

这可以写成

(2) X = b a*

右手边不是递归的

现在看看下面的递归 BNF 规则

(3) X = { X } | b

这会产生类似的句子

X = b
X = {b}
X = {{b}}
X = {{{b}}}
...

有没有办法以非递归方式重写规则 (3),类似于我们将规则 (1) 重写为规则 (2) 时所做的那样。

观察到 X = {* b }* 不好,因为括号需要平衡。

【问题讨论】:

  • 有点猜想但是:x = (, ab)* a
  • 顺便说一句:对于规则 (3):x = {ab 我不确定它是否好。
  • @AdamOcsvari ,您没有括号。并且不涉及逗号。
  • @helpYou:没错!这更简单:x = ab* a
  • 他想要像 {(ab{)*a(})*}({ab)*{a}(})* 这样的东西,但有更多的控制权 - 在双方都有相同的号码作为 * 的替代品。 (开括号的数量应该等于闭括号的数量)

标签: recursion matching parentheses bnf non-recursive


【解决方案1】:

我不知道上面的问题是否可以回答。上述问题的原因是我想避免我的解析器(用 Java 编写)中的无限循环。一种方法是确保 BNF 规则不是递归的,因此是我的问题。但另一种方法是使用递归规则,但要避免我的(Java)程序中的无限循环。事实证明,您可以通过延迟实例化来避免循环。

例如看下面的规则:

expression = term ('+' term)*;
term       = factor ('*' factor)*;
factor     = '(' expression ')' | Num;

expression() 调用 term(),它调用 factor(),它调用 expression(),因此我们可以以无限循环结束。为了避免这种情况,我们可以使用惰性实例化,而不是编写如下内容:

public Parser expression() {
    expression = new ...
    return expression;
}

我们改为写:

public Parser expression() {
    if (expression == null) {
        expression = new ...
    }
    return expression;
}

请注意,您必须将表达式声明为实例变量才能使其工作。

【讨论】:

  • 也许我错了,但是解析器中的无限循环意味着给定的规则一遍又一遍地调用自己而不消耗任何输入。这就是使用递归下降方法实现左递归规则时发生的情况。上面的语法不是这样,因为解析器在再次调用 empression 之前必须消耗“(”。没有无限循环。(edited:typo)
猜你喜欢
  • 2017-12-26
  • 1970-01-01
  • 2011-04-17
  • 2011-11-09
  • 2016-09-22
  • 1970-01-01
  • 2012-10-17
  • 2019-12-10
  • 1970-01-01
相关资源
最近更新 更多