Antlr4:如何退出语法规则?

时间:2013-05-03 01:29:09

标签: 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>)
你可以看到

在第一组元素的末尾有一个空的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)

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

这不是你想要的吗?

prog : 'A'* 'B'* 'C'* 'D'* EOF;

以下语法规则匹配无限长的AB标记序列,因为尾递归aOrB引用不是可选的。如果输入启动了足够多的StackOverflowException和/或A字符,您的语法将抛出B,否则会遇到语法错误。

aOrB : ( a | b ) aOrB ;

如果要维护分组,可以使用此语法。我只对aOrBcOrD规则进行了更改。由于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规则。