所以我正在试验Antlr v4,我用一些不同寻常的语法来探究它是如何运作的。这是我目前的测试用例:
我想要一个按顺序包含字母A,B,C,D的语法。这些字母可能会重复。我还将A和B组合在一起,而C和D也是如此,以使语法更有趣。所以像这样的字符串是可接受的语法:
AAA
ABCD
ACCCDD
但是进展不顺利。我认为发生的事情是Antlr需要一个更好的退出规则来解决我的语法问题。在收集A和B之后似乎没有认识到C的存在意味着要进入下一个规则。实际上它有点工作,但我得到错误消息,并且生成的解析树似乎在其中有空元素,就像它在发出错误消息时插入了一个额外的元素。
以下是一个示例错误消息:
line 1:2 extraneous input 'C' expecting {'B', 'A'}
输入'ABCD'。所以当Antlr在那里看到C时,会发生一些奇怪的事情。这是解析树的输出:
'ABCD': (prog (aOrB (a A) (aOrB (b B) aOrB)) (cOrD (c C) (cOrD (d D) cOrD)) <EOF>)
你可以看到在第一组元素的末尾有一个空的aOrB元素。
知道发生了什么事吗?什么是Antlr在发出错误并添加空元素时“思考”?我怎么能解决这个问题?
好的,这是血腥的细节。
我的语法:
grammar Abcd;
prog : aOrB cOrD EOF;
aOrB : ( a | b ) aOrB ;
a : 'A'+ ;
b : 'B'+ ;
cOrD : ( c | d ) cOrD ;
c : 'C'+ ;
d : 'D'+ ;
我在Java中的测试程序:
package antlrtests;
import antlrtests.grammars.*;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
class AbcdTest {
private final String[] testVectors = {
"A", "AABB", "B", "ABCD", "C", "D", };
public void runTests() {
for( String test : testVectors )
simpleTest( test );
}
private void simpleTest( String test ) {
ANTLRInputStream ains = new ANTLRInputStream( test );
AbcdLexer wpl = new AbcdLexer( ains );
CommonTokenStream tokens = new CommonTokenStream( wpl );
AbcdParser wikiParser = new AbcdParser( tokens );
ParseTree parseTree = wikiParser.prog();
System.out.println( "'" + test + "': " + parseTree.toStringTree(
wikiParser ) );
}
}
我测试程序的输出。请注意,错误消息与常规输出混杂在一起,因为它们是由Antlr在标准错误上打印的。
run:
line 1:1 no viable alternative at input '<EOF>'
'A': (prog (aOrB (a A) aOrB) cOrD <EOF>)
line 1:4 no viable alternative at input '<EOF>'
'AABB': (prog (aOrB (a A A) (aOrB (b B B) aOrB)) cOrD <EOF>)
'B': (prog (aOrB (b B) aOrB) cOrD <EOF>)
line 1:1 no viable alternative at input '<EOF>'
line 1:2 extraneous input 'C' expecting {'B', 'A'}
line 1:4 no viable alternative at input '<EOF>'
'ABCD': (prog (aOrB (a A) (aOrB (b B) aOrB)) (cOrD (c C) (cOrD (d D) cOrD)) <EOF>)
line 1:0 no viable alternative at input 'C'
line 1:1 no viable alternative at input '<EOF>'
line 1:0 no viable alternative at input 'D'
'C': (prog aOrB (cOrD (c C) cOrD) <EOF>)
line 1:1 no viable alternative at input '<EOF>'
'D': (prog aOrB (cOrD (d D) cOrD) <EOF>)
BUILD SUCCESSFUL (total time: 0 seconds)
非常感谢任何帮助。
答案 0 :(得分:0)
这不是你想要的吗?
prog : 'A'* 'B'* 'C'* 'D'* EOF;
以下语法规则匹配无限长的A
和B
标记序列,因为尾递归aOrB
引用不是可选的。如果输入启动了足够多的StackOverflowException
和/或A
字符,您的语法将抛出B
,否则会遇到语法错误。
aOrB : ( a | b ) aOrB ;
如果要维护分组,可以使用此语法。我只对aOrB
和cOrD
规则进行了更改。由于a
规则与A
令牌序列匹配,aOrB
规则使用a?
而不是a*
(只有a
的一个实例可以永远都会出现,整个系列的A
代币都是它的子代。)
grammar Abcd;
prog : aOrB cOrD EOF;
aOrB : a? b?;
a : 'A'+ ;
b : 'B'+ ;
cOrD : c? d?;
c : 'C'+ ;
d : 'D'+ ;
这是另一种语法,它匹配相同的语言(但产生不同的解析树),显示*
,+
和?
量词的其他选项。我不建议使用这个语法,但你应该仔细查看它,以了解每个选项的作用,并理解为什么它与我上面给出的语法完全匹配相同的输入。
grammar Abcd;
prog : aOrB cOrD? EOF;
aOrB : a* b;
a : 'A' ;
b : 'B'* ;
cOrD : (c d* | d+);
c : 'C'+ ;
d : 'D' ;
答案 1 :(得分:0)
你有没有意识到你的aOrB规则没有强制执行a和b的任何排序?同样是你的cOrD规则。