Лично мне нравится держать грамматические правила настолько «пустыми», насколько это возможно. В этом случае я бы создал метод лексера, который возвращает true
, если следующие два символа на входе - "--"
. Пока это не регистр, сопоставьте любой символ, кроме \r
и \n
, и повторяйте это ноль или более раз, пока не встретите необязательный "--"
. Обратите внимание, что я не ставил новую строку в конце, потому что не обязательно новая строка в конце (это также может быть EOF
). Кроме того, \r
и \n
, скорее всего, будут соответствовать правилу SPACE
, установленному на канале HIDDEN
: так что, как я советую, делать это не вредно.
Демонстрация:
...
@lexer::members {
private boolean endCommentAhead() {
return input.LA(1) == '-' && input.LA(2) == '-';
}
}
...
SL_COMMENT
: '--' ({!endCommentAhead()}?=> ~('\r' | '\n'))* '--'?
;
...
И если вам не нравится блок членов lexer, вы просто делаете:
SL_COMMENT
: '--' ({!(input.LA(1) == '-' && input.LA(2) == '-')}?=> ~('\r' | '\n'))* '--'?
;
EDIT
Небольшая полная демонстрация:
grammar T;
@parser::members {
public static void main(String[] args) throws Exception {
String source = "12 - 34 -- foo - bar -- 42 \n - - 5678 -- more comments 666\n--\n--";
TLexer lexer = new TLexer(new ANTLRStringStream(source));
TParser parser = new TParser(new CommonTokenStream(lexer));
parser.parse();
}
}
@lexer::members {
private boolean endCommentAhead() {
return input.LA(1) == '-' && input.LA(2) == '-';
}
}
parse
: (t=. {System.out.printf("\%-15s\%s\n", tokenNames[$t.type], $t.text);})* EOF
;
SL_COMMENT
: '--' ({!endCommentAhead()}?=> ~('\r' | '\n'))* '--'?
;
MINUS
: '-'
;
INT
: '0'..'9'+
;
SPACE
: (' ' | '\t' | '\r' | '\n') {skip();}
;
который после разбора ввода:
12 - 34 -- foo - bar -- 42
- - 5678 -- more comments 666
напечатает:
INT 12
MINUS -
INT 34
SL_COMMENT -- foo - bar --
INT 42
MINUS -
MINUS -
INT 5678
SL_COMMENT -- more comments 666
SL_COMMENT --
SL_COMMENT --