java - 如何消除 JavaCC 中的选择冲突?

标签 java parsing recursion compiler-construction javacc

我的制作规则如下:

OtherNonTerminal := NonTerminal | {}
NonTerminal := <TOKEN>:A() | <TOKEN>:A(), Nonterminal()

在JavaCC中,NonTerminal存在选择冲突:

void OtherNonTerminal() : {}
{
    Nonterminal() | {}
}

void Nonterminal() : {}
{
    <TOKEN> <COLON> A()
|
    <TOKEN> <COLON> A() <COMMA> Nonterminal()
}

这是否是摆脱选择冲突的一种方法,并且程序会像我的 NonTerminal 产生规则一样按照指定的方式工作吗?

void Nonterminal() : {}
{
    <TOKEN> <COLON> A() (<COMMA> NonTerminal())? 
}

最佳答案

为什么会出现问题

在 JavaCC 中,决定采用哪个分支的默认方法是查看下一个标记。如果该 token 与第一选择兼容,则采用第一选择,并且该决定不可逆转。没有回溯。

所以看看选择

void Nonterminal() : {}
{
    <TOKEN> <COLON> A()
|
    <TOKEN> <COLON> A() <COMMA> Nonterminal()
}

并假设输入中的下一个标记是 <TOKEN> 。无论是否有 <COMMA> 都会选择第一个选择稍后的。换句话说

  <TOKEN> <COLON> A()
| <TOKEN> <COLON> A() <COMMA> Nonterminal()

相当于

  <TOKEN> <COLON> A()

除了第一个会产生一条警告消息,因为 JavaCC 认为您编写的内容没有意义。

<小时/>

一个好的解决方案

您的问题的答案是"is"。一种解决方案是执行您所做的操作并提取公共(public)前缀

void Nonterminal() : {}
{
    <TOKEN> <COLON> A() (<COMMA> NonTerminal())? 
}
<小时/>

可能更好的解决方案,具体取决于

如果由于某种原因,您确实不知道要考虑什么,您还可以执行以下操作

void Nonterminal() : {}
{
    LOOKAHEAD( <TOKEN> <COLON> A() <COMMA>)
    <TOKEN> <COLON> A() <COMMA> Nonterminal()
|
    <TOKEN> <COLON> A()
}

这里,解析器将在输入流中向前查找。如果它看到逗号,则采用第一个选择。否则,第二个。

如果两种情况下的语义操作不同,这可能会很有用。例如

  LOOKAHEAD( <TOKEN> <COLON> A() <COMMA>)
  <TOKEN> {doSomething();} <COLON> A() <COMMA> Nonterminal()
|
  <TOKEN> {doSomethingDifferent();} <COLON> A()
<小时/>

非递归解决方案。

第三种选择是

void Nonterminal() : {}
{
    Foo() (<COMMA>  Foo() )*
}

void Foo() : {}
{
    <TOKEN> <COLON> A()
}

关于java - 如何消除 JavaCC 中的选择冲突?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53120324/

相关文章:

java - 我应该如何将键值传递给 PL/SQL 过程?

javascript - 尝试在不使用其他算法的情况下使用递归来解决

javascript - JavaScript 中的阶乘仅适用于减少递归,为什么?

c++ - 循环真的比递归快吗?

java - RemoteWebDriver.executeScript() 和 Selenium.getEval() 有什么区别?

java - 如何获取用于函数及其类的注释类型的所有注释属性?

java - 在自定义 Controller 中解析实体 URI (Spring HATEOAS)

python - 从 pandas 数据框创建单个 XML 文件

java - 使用java从字符串中仅删除嵌套的大括号

perl - 在perl中解析制表符分隔的文件