Нет способа реализовать строку в кавычках с настраиваемыми разделителями в Antlr4
Я пытаюсь реализовать правило лексера для механизма строк в кавычках оракула Q, где у нас есть что-то вроде q '$some string$'
Здесь вы можете использовать любой символ вместо $, кроме пробела, (, {, [,<, но строка должна начинаться и заканчиваться одним и тем же символом. Некоторые примеры принятых токенов: q '! Some string!' Q 'ssome strings' Обратите внимание на то, что s - это пользовательский разделитель, но хорошо иметь его и в строке, потому что мы заканчиваем только на s '
Вот как я пытался реализовать правило:
Q_QUOTED_LITERAL: Q_QUOTED_LITERAL_NON_TERMINATED . QUOTE-> type(QUOTED_LITERAL);
Q_QUOTED_LITERAL_NON_TERMINATED:
Q QUOTE ~[ ({[<'"\t\n\r] { setDelimChar( (char)_input.LA(-1) ); }
( . { !isValidEndDelimChar() }? )*
;
Я уже проверил значение, которое я получаю из! IsValidEndDelimChar(), и я получаю ложный предикат здесь в нужном месте, поэтому все должно работать, но antlr просто игнорирует этот предикат. Я также попытался переместить предикат, поместив эту часть в отдельное правило и кучу других вещей, после полутора дней исследования того же самого вопроса, я наконец поднял эту проблему.
Я также пытался реализовать его другими способами, но, похоже, нет способа реализовать пользовательскую строку с разделителями в antlr4 (версия antlr3, используемая для работы).
1 ответ
Не уверен, почему { ... }
действие не вызывается, но оно не нужно. Следующая грамматика сработала для меня (поставьте предикат перед .
!):
grammar Test;
@lexer::members {
boolean isValidEndDelimChar() {
return (_input.LA(1) == getText().charAt(2)) && (_input.LA(2) == '\'');
}
}
parse
: .*? EOF
;
Q_QUOTED_LITERAL
: 'q\'' ~[ ({[<'"\t\n\r] ( {!isValidEndDelimChar()}? . )* . '\''
;
SPACE
: [ \t\f\r\n] -> skip
;
Если вы запускаете класс:
import org.antlr.v4.runtime.*;
public class Main {
public static void main(String[] args) {
Lexer lexer = new TestLexer(CharStreams.fromString("q'ssome strings' q'!foo!'"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();
for (Token t : tokens.getTokens()) {
System.out.printf("%-20s %s\n", TestLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}
}
}
будет напечатан следующий вывод:
Q_QUOTED_LITERAL q'ssome strings'
Q_QUOTED_LITERAL q'!foo!'
EOF <EOF>