首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Antlr4:如何退出语法规则?

Antlr4:如何退出语法规则?
EN

Stack Overflow用户
提问于 2013-05-03 09:29:09
回答 2查看 1.3K关注 0票数 0

所以我正在试验Antlr v4,我用一些不同寻常的语法来戳它,以了解它是如何工作的。

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

AAA

ABCD

ACCCDD

但进展并不顺利。我认为Antlr需要为我的语法制定一个更好的退出规则。它似乎没有意识到,在收集了A和B之后,出现C意味着要转到下一个规则。实际上,它在某种程度上是有效的,但我得到了错误消息,并且生成的解析树中似乎有null元素,比如它在发出错误消息的位置插入了一个额外的元素。

下面是一个错误消息示例:

代码语言:javascript
复制
line 1:2 extraneous input 'C' expecting {'B', 'A'}

对于输入'ABCD‘会发生这种情况。所以当Antlr看到C的时候发生了一些奇怪的事情。以下是解析树的输出:

代码语言:javascript
复制
'ABCD': (prog (aOrB (a A) (aOrB (b B) aOrB)) (cOrD (c C) (cOrD (d D) cOrD)) <EOF>)

在第一组元素的末尾有一个空的aOrB元素。

知道这是怎么回事吗?当Antlr发出错误并添加空元素时,它“在想”什么呢?我该如何解决这个问题呢?

好了,下面是一些血淋淋的细节。

我的语法是:

代码语言:javascript
复制
grammar Abcd;

prog : aOrB cOrD EOF;
aOrB : ( a | b ) aOrB ;
a : 'A'+ ;
b : 'B'+ ;
cOrD : ( c | d ) cOrD ;
c : 'C'+ ;
d : 'D'+ ;

我的Java测试程序:

代码语言:javascript
复制
  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在标准错误时打印的。

代码语言:javascript
复制
  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)

任何帮助都是非常感谢的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-03 10:23:49

这不是你要找的吗?

代码语言:javascript
复制
prog : 'A'* 'B'* 'C'* 'D'* EOF;

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

代码语言:javascript
复制
aOrB : ( a | b ) aOrB ;

如果你想维护分组,你可以使用这个语法。我只对aOrBcOrD规则进行了更改。由于a规则匹配一系列A标记,因此aOrB规则使用a?而不是a* (只能出现一个a实例,并且整个A标记系列都是它的子代)。

代码语言:javascript
复制
grammar Abcd;

prog : aOrB cOrD EOF;
aOrB : a? b?;
a : 'A'+ ;
b : 'B'+ ;
cOrD : c? d?;
c : 'C'+ ;
d : 'D'+ ;

下面是另一个匹配相同语言的语法(但生成不同的解析树),其中显示了*+?量词的其他选项。我不推荐使用这种语法,但您应该仔细查看它,以了解每个选择都在做什么,并理解为什么它与我上面给出的语法完全匹配。

代码语言:javascript
复制
grammar Abcd;

prog : aOrB cOrD? EOF;
aOrB : a* b;
a : 'A' ;
b : 'B'* ;
cOrD : (c d* | d+);
c : 'C'+ ;
d : 'D' ;
票数 0
EN

Stack Overflow用户

发布于 2013-05-03 13:07:05

您是否意识到您的aOrB规则并不强制对a和b进行任何排序?与您的cOrD规则类似。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16350239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档