1

我正在使用 Antlr 3.2,但在编写忽略注释行的语法时遇到了麻烦。具体来说,如果注释行是输入的最后一行,后面没有换行符,我会收到错误消息。

我的输入实际上是汇编语言,其中注释以分号开头,然后到行尾。其他所有内容都被解析为命令。

显示问题的我的语法的简化版本是:

grammar Test;

options {
    language = Java;
    output = AST;
    ASTLabelType = CommonTree;
}

@header {
    package test;
}

@lexer::header {
    package test;
}

rule
    :   instruction+ EOF!
    ;

instruction
    :   'SET' NEWLINE!*
    ;

COMMENT
    :   ';' .* NEWLINE+ { $channel=HIDDEN; }
    ;

NEWLINE
    :  '\r'? '\n'
    ;

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

如果我使用如下输入:

; comment line 1 with blank line after it

SET ; comment after command
; comment line again

解析这句话时出现错误line 4:11 required (...)+ loop did not match anything at character '<EOF>'

如果我在输入的最后一行添加换行符,它可以正常工作,因为换行符与注释剥离相匹配,并且 EOF 在规则末尾匹配。

我怎样才能更好地写这个,以便它忽略最后一行的注释但不给出错误?我不想在原始输入中附加任何内容来破解它,有没有更简洁的方法来阅读评论行?我已经尝试了 NEWLINE|EOF 的各种组合,但没有任何方法可以消除错误。

4

1 回答 1

2

这样的事情应该这样做:

COMMENT
    :   ';' ~('\r' | '\n')* { $channel=HIDDEN; }
    ;

如果您希望 aCOMMENT在末尾可能有换行符,请执行以下操作:

COMMENT
    :   ';' ~('\r' | '\n')* NEWLINE? { $channel=HIDDEN; }
    ;

但是,这两个规则NEWLINEWS

NEWLINE
    :  '\r'? '\n'
    ;

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

很危险:ANTLR 的工作原理是这样的:它尝试尽可能多地匹配,因此匹配最多的规则“获胜”。如果两个(或更多)规则匹配相同数量的字符,则第一个定义的“获胜”。

换句话说,如果词法分析器看到类似 的输入"\n"NEWLINE则创建 a。但是,如果词法分析器看到" \n"(一个空格后跟 a "\n"),WS就会创建一个标记(并放在HIDDEN通道上)。

我不确定换行符在您的语言中是否真的重要(它们不是任何汇编语言,AFAIK),所以只需删除NEWLINE规则即可。如果它们重要,请从规则中删除字符\r和字符。\nWS

于 2012-05-08T17:26:10.030 回答