0

所以我正在试验 Antlr v4,我正在用一些不寻常的语法戳它,以了解它是如何工作的。这是我当前的测试用例:

我想要一个按顺序由字母 A、B、C、D 组成的语法。字母可能会重复。我还将 A 和 B 组合在一起,C 和 D 也组合在一起,以使语法更有趣。所以像这样的字符串是可以接受的语法:

AAA

A B C D

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)

任何帮助深表感谢。

4

2 回答 2

0

这不是你所追求的吗?

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

您的语法的以下规则匹配无限长的一系列AB标记,因为尾递归aOrB引用不是可选的。StackOverflowException如果输入开始足够多A和/或字符,您的语法将抛出 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' ;
于 2013-05-03T02:23:49.323 回答
0

您是否意识到您的 aOrB 规则不强制 a 和 b 的任何排序?同样,您的 cOrD 规则。

于 2013-05-03T05:07:04.700 回答