我正在使用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; }
;
答案 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
。由于您在语法中定义了三个标记(0
,1
和 ,
)和您的输入,"00"
,不包含任何未经语法处理的字符,不会引发NoViableAltException
。如果您将输入更改为"0?0"
,则会弹出NoViableAltException
。
由于您的解析器找到第一个0
,然后找不到,
,它只是停止解析,因为您没有“告诉”它一直解析到文件的末尾。
希望澄清事情。如果没有,请告诉我。