Когда правило соответствует в antlr4, и вы получаете текст этого правила, пробел обычно удаляется лексером с помощью
WS: [ \n\t\r]+ -> skip;
Можно ли спросить у посетителя дерева разбора «Пропустило ли это правило какой-либо пробел?»
Например.
WS: [ \n\t\r]+ -> skip;
ALPHA: [a-z];
NUMERIC: [0-9];
myrule: (ALPHA | NUMERIC)+;
Затем в госте (я использую C ++):
antlrcpp::Any MyVisitor::visitMyrule(dlParser::MyruleContext *ctx) {
if (ctx->didSkipSomeWhitespace()) {
/* There was whitespace */
} else {
/* There was no whitespace */
}
return false;
}
Так:
f56fhj => no whitespace
o9f g66ff o => whitespace
Я попытался получить индексы начала / остановки токена, чтобы я мог сравнить длину текста с количеством введенных в него символов, но стоп-токен не всегда доступен, и если это так, то значения не выровняйте с ожидаемыми индексами, и, кажется, не просто получить доступ к исходным символам ввода, которые сформировали токен.
В этом случае вы не должны skip
эти космические жетоны. Таким образом, парсеры не знают о них. Вместо этого вы должны поместить эти пробелы в другой канал (HIDDEN
, например). Таким образом, парсер не использует эти HIDDEN
токены, но токены присутствуют в потоке токенов и доступны в вашем коде.
Небольшая демонстрация в Java (у меня не работает C ++):
grammar IntList;
list
: '[' ( list_item ( ',' list_item )* )? ']' EOF
;
list_item
: INT
;
INT
: '0'
| [1-9] [0-9]*
;
SPACES
: [ \t\f\r\n] -> channel(HIDDEN)
;
Запуск класса:
import org.antlr.v4.runtime.*;
public class Main {
public static void main(String[] args) {
String source = "[1, 2,3,\t4,5]";
IntListLexer lexer = new IntListLexer(CharStreams.fromString(source));
CommonTokenStream tokens = new CommonTokenStream(lexer);
IntListParser parser = new IntListParser(tokens);
new SpaceInspectionVisitor(tokens).visit(parser.list());
}
}
class SpaceInspectionVisitor extends IntListBaseVisitor<Object> {
private final CommonTokenStream tokens;
SpaceInspectionVisitor(CommonTokenStream tokens) {
this.tokens = tokens;
}
@Override
public Object visitList_item(IntListParser.List_itemContext ctx) {
Token previous = tokens.get(ctx.start.getTokenIndex() - 1);
System.out.printf("token: '%s', previous == SPACES: %s\n", ctx.getText(), previous.getType() == IntListLexer.SPACES);
return null;
}
}
выведет на вашу консоль следующее:
token: '1', previous == SPACES: false
token: '2', previous == SPACES: true
token: '3', previous == SPACES: false
token: '4', previous == SPACES: true
token: '5', previous == SPACES: false
Других решений пока нет …