为什么我的antlr语法似乎正确地解析了这个输入?

时间:2012-04-11 16:03:27

标签: antlr antlr3

我在ANTLR中使用python创建了一个小语法(一种语法可以接受ID列表中的数字列表),但是当我输入一个字符串如December 12 1965时,ANTLR将运行在文件上,并显示以下代码没有错误(我正在使用的所有python代码都通过@main嵌入):

grammar ParserLang;

options {
    language=Python;
}

@header {
import sys
import antlr3

from ParserLangLexer import ParserLangLexer
}

@main { 
def main(argv, otherArg=None):
    char_stream = antlr3.ANTLRInputStream(open(sys.argv[1],'r'))
    lexer = ParserLangLexer(char_stream)

    tokens = CommonTokenStream(lexer)
    parser = ParserLangParser(tokens);

    rule   = parser.entry_rule()
}

program     : idList EOF
            | integerList EOF
            ;

idList      : ID whitespace idList 
            | ID
            ;

integerList : INTEGER whitespace integerList 
            | INTEGER
            ;

whitespace  : (WHITESPACE | COMMENT) +;

ID            : LETTER (DIGIT | LETTER)*;
INTEGER       : (NONZERO_DIGIT DIGIT*) | ZERO ;
WHITESPACE    : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+    { $channel = HIDDEN; } ;
COMMENT       : ('/*' .* '*/') | ('//' .* '\n') { $channel = HIDDEN; } ;

fragment ZERO            : '0' ;
fragment DIGIT         : '0' .. '9';
fragment NONZERO_DIGIT : '1' .. '9';
fragment LETTER        : 'a' .. 'z' | 'A' .. 'Z';

我做错了吗?

编辑:当我使用具有相同语法和输入的ANTLRWorks时,抛出NoViableAltException。如何通过代码获取该错误?

1 个答案:

答案 0 :(得分:2)

我无法重现它。当我在修复语法中的错误(rule = parser.entry_rule()应该是:rule = parser.program())后从输入生成词法分析器和解析器,并解析输入"December 12 1965"(作为文件的输入,或者作为一个普通字符串),我收到以下错误:

line 1:0 no viable alternative at input u'December'

这可能看起来很奇怪,因为那可能是idList的开始。事实是,你的语法包含一个错误和一个可以改进的小东西:

  • WHITESPACECOMMENT位于HIDDEN频道,因此在解析器规则中不可用(至少,不会更改解析器读取其令牌的频道)。 ..);
  • 输入结尾处的
  • 一个COMMENT,即最后没有\n,将无法正确标记。最好像这样定义单行注释:'//' ~('\r' | '\n')*。毕竟,WHITESPACE规则将捕获尾随换行符。

由于idList规则导致解析器无法与integerList(或whitespace匹配),因此会产生指向第一个令牌的错误({{1 }})。

这是一个有效的语法(正如预期的那样):

'December'

运行从上面的语法生成的解析器也会产生错误:

grammar ParserLang;

options {
    language=Python;
}

@header {
import sys
import antlr3

from ParserLangLexer import ParserLangLexer
}

@main { 
def main(argv, otherArg=None):
    lexer = ParserLangLexer(antlr3.ANTLRStringStream('December 12 1965'))
    parser = ParserLangParser(CommonTokenStream(lexer))
    parser.program()
}

program     : idList EOF
            | integerList EOF
            ;

idList      : ID+
            ;

integerList : INTEGER+
            ;

ID          : LETTER (DIGIT | LETTER)*;
INTEGER     : (NONZERO_DIGIT DIGIT*) | ZERO ;
WHITESPACE  : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;
COMMENT     : ('/*' .* '*/' | '//' ~('\r' | '\n')*)   { $channel = HIDDEN; } ;

fragment ZERO          : '0' ;
fragment DIGIT         : '0' .. '9';
fragment NONZERO_DIGIT : '1' .. '9';
fragment LETTER        : 'a' .. 'z' | 'A' .. 'Z';

但是这是预期的:在line 1:9 missing EOF at u'12' 之后,解析器需要idList,但它会遇到EOF