我的生产规则如下:
OtherNonTerminal := NonTerminal | {}
NonTerminal := <TOKEN>:A() | <TOKEN>:A(), Nonterminal()
在JavaCC中,非终端有选择冲突:
void OtherNonTerminal() : {}
{
Nonterminal() | {}
}
void Nonterminal() : {}
{
<TOKEN> <COLON> A()
|
<TOKEN> <COLON> A() <COMMA> Nonterminal()
}
这是摆脱选择冲突的一种方法,程序是否可以像我的非终端生产规则那样按指定方式工作?
void Nonterminal() : {}
{
<TOKEN> <COLON> A() (<COMMA> NonTerminal())?
}
答案 0 :(得分:2)
在JavaCC中,决定采用哪个分支的默认方法是查看下一个标记。如果令牌与首选兼容,则采取首选且该决定不可逆。没有回溯。
所以看看选择
void Nonterminal() : {}
{
<TOKEN> <COLON> A()
|
<TOKEN> <COLON> A() <COMMA> Nonterminal()
}
,并假设输入中的下一个标记是<TOKEN>
。无论以后是否有<COMMA>
,都将采用第一选择。换句话说
<TOKEN> <COLON> A()
| <TOKEN> <COLON> A() <COMMA> Nonterminal()
等同于
<TOKEN> <COLON> A()
除了第一个会产生警告消息,因为JavaCC认为您编写的内容没有意义。
您的问题的答案是“是”。一种解决方案是做您所做的事情并排除掉公共前缀
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()
}