如何强制ANTLR生成NoViableAltException?

时间:2010-02-17 05:39:55

标签: error-handling antlr

我正在使用antlr 3.2。我有一个由原子(字符“0”或“1”)组成的简单语法,以及一个将逗号分隔的列表累加到列表中的规则。

当我输入“00”作为输入时,我没有收到错误,这让我感到惊讶,因为这不应该是有效的输入:

C:\Users\dan\workspace\antlrtest\test>java -cp antlr-3.2.jar org.antlr.Tool Test.g
C:\Users\dan\workspace\antlrtest\test>javac -cp antlr-3.2.jar *.java
C:\Users\dan\workspace\antlrtest\test>java -cp .;antlr-3.2.jar TestParser
[0]

在这种情况下如何强制生成错误?这特别令人费解,因为当我在ANTLRWorks中使用此输入的解释器时,它 显示NoViableAltException。

我发现,如果我将语法更改为要求,例如,结尾处有分号,则会生成错误 ,但我正在使用的实际语法中无法使用该解决方案上。

这是语法,它是自包含且可运行的:

grammar Test;

@parser::members {
  public static void main(String[] args) throws Exception {
    String text = "00";
    ANTLRStringStream in = new ANTLRStringStream(text);
    TestLexer lexer = new TestLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    System.out.println(new TestParser(tokens).mainRule());
  }
}

mainRule returns [List<String> words]
@init{$words = new ArrayList<String>();}
  :  w=atom {$words.add($w.text);} (',' w=atom {$words.add($w.text);} )*
  ;


atom: '0' | '1';

WS
  :  ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; }
  ;

1 个答案:

答案 0 :(得分:2)

在你的mainRule之后,你应该添加一个EOF令牌,否则当没有有效的令牌匹配时,ANTLR将停止解析。

此外,atom规则应该是词法分析器规则而不是解析器规则(词法分析器规则以大写字母开头)。

请改为尝试:

grammar Test;

@parser::members {
  public static void main(String[] args) throws Exception {
    String text = "0,1  ,  1  , 0,1";
    ANTLRStringStream in = new ANTLRStringStream(text);
    TestLexer lexer = new TestLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    System.out.println(new TestParser(tokens).mainRule());
  }
}

mainRule returns [List<String> words]
@init{$words = new ArrayList<String>();}
  :  w=Atom {$words.add($w.text);} (',' w=Atom {$words.add($w.text);} )* EOF
  ;

Atom
  :  '0' | '1'
  ;

WS
  :  ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; }
  ;

修改

澄清:正如您已经发现的那样,EOF不是强制性的。它只会导致解析器遍历整个输入。只有当词法分析器偶然发现未使用词法分析器语法处理的标记/字符时,才会抛出NoViableAltException。由于您在语法中定义了三个标记(01 ,您的输入,"00" ,不包含任何未经语法处理的字符,不会引发NoViableAltException。如果您将输入更改为"0?0",则会弹出NoViableAltException

由于您的解析器找到第一个0,然后找不到,,它只是停止解析,因为您没有“告诉”它一直解析到文件的末尾。

希望澄清事情。如果没有,请告诉我。