Antlr4:如何退出语法规则?
因此,我正在尝试使用Antlr v4,并用一些不寻常的语法对其进行测试,以了解其工作原理。下面是我当前的测试用例: 我想要一个按顺序由字母a、B、C、d组成的语法。这些字母可以重复。我还将a和B分组在一起,C和d也分组在一起,以使语法更有趣。这样的字符串是可以接受的语法: AAA ABCD ACCCDD 但这并不顺利。我认为现在发生的是,Antlr需要一个更好的语法退出规则。它似乎没有意识到,在收集了a和B之后,C的存在意味着进入下一个规则。实际上,这是可行的,但我得到了错误消息,并且生成的解析树似乎有空元素在其中,就像它在发出错误消息的地方插入了一个额外的元素一样 下面是一个示例错误消息:Antlr4:如何退出语法规则?,antlr4,Antlr4,因此,我正在尝试使用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>)
我的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)
运行:
第1行:输入“”处无可行的替代方案
‘A’:(程序(aOrB(A)aOrB)跳线)
第1行:4输入“”处无可行的替代方案
‘AABB’:(程序(aOrB(a)(aOrB(b)aOrB))跳线)
‘B’:(程序(aOrB(B)aOrB)跳线)
第1行:输入“”处无可行的替代方案
第1行:2外部输入'C'应为{'B','A'}
第1行:4输入“”处无可行的替代方案
‘ABCD’:(程序(aOrB(a)(aOrB(b)aOrB))(跳线(c)(跳线(d)跳线)))
第1行:0在输入“C”处没有可行的替代方案
第1行:输入“”处无可行的替代方案
第1行:0在输入“D”处没有可行的替代方案
‘C’:(程序aOrB(跳线(C)跳线))
第1行:输入“”处无可行的替代方案
‘D’:(程序aOrB(跳线(D)跳线))
生成成功(总时间:0秒)
非常感谢您的帮助。这不是您想要的吗
prog : 'A'* 'B'* 'C'* 'D'* EOF;
以下语法规则匹配无限长的
A
和B
标记序列,因为尾部递归aOrB
引用不是可选的。如果输入开始的A
和/或B
字符足够多,则语法将抛出StackOverflowException
,或者如果语法错误不存在,请对其进行计数
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* | d+);
c : 'C'+ ;
d : 'D' ;
你意识到你的aOrB规则不强制a和b的任何顺序吗?同样,你的cOrD规则。好的,部分想法是让语法比你上面的做更多的解析。这是一个简化的测试用例,用于更复杂的事情,所以我想避免像你这样的高度简化的答案简言之,不,这不是我想要的。@user2338547我通过post编辑了一个语法,使其更接近您的语法。好的,扩展的答案很有帮助。这不是我想要的,但我认为它确实回答了我提出的问题。我会将此标记为已回答,并在下一个问题之前好好思考一下。是的,从技术上讲,AB应该是abl在去CD之前,我要无限重复一遍。但你是对的,我没有强迫A和B按顺序出现,这是我应该做到的。我还在学习呢!;)不,不会。关于交错的
A
和B
你是正确的,但是原始问题中的aOrB
规则永远不会终止,因此流永远不会结束,它可以包含的唯一符号是A
和B
(不C
或D
)。
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' ;