Antlr4:如何退出语法规则?

Antlr4:如何退出语法规则?,antlr4,Antlr4,因此,我正在尝试使用Antlr v4,并用一些不寻常的语法对其进行测试,以了解其工作原理。下面是我当前的测试用例: 我想要一个按顺序由字母a、B、C、d组成的语法。这些字母可以重复。我还将a和B分组在一起,C和d也分组在一起,以使语法更有趣。这样的字符串是可以接受的语法: AAA ABCD ACCCDD 但这并不顺利。我认为现在发生的是,Antlr需要一个更好的语法退出规则。它似乎没有意识到,在收集了a和B之后,C的存在意味着进入下一个规则。实际上,这是可行的,但我得到了错误消息,并且生成的解析

因此,我正在尝试使用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' ;