#java #antlr4
#java #antlr4
Вопрос:
Я пытаюсь скомпилировать шаблон для грамматики html. Приведенный ниже код показывает, как анализировать строку, содержащую htmlAttributeRule
:
String code = "href="val"";
CharStream chars = CharStreams.fromString(code);
Lexer lexer = new HTMLLexer(chars);
lexer.pushMode(HTMLLexer.TAG);
TokenStream tokens = new CommonTokenStream(lexer);
HTMLParser parser = new HTMLParser(tokens);
parser.htmlAttribute();
Но когда я пытаюсь:
ParseTreePatternMatcher matcher = new ParseTreePatternMatcher(lexer, parser);
matcher.compile(code, HTMLParser.RULE_htmlAttribute);
сбой с ошибкой:
line 1:0 no viable alternative at input 'href="val"'
org.antlr.v4.runtime.NoViableAltException
at org.antlr.v4.runtime.atn.ParserATNSimulator.noViableAlt(ParserATNSimulator.java:2026)
at org.antlr.v4.runtime.atn.ParserATNSimulator.execATN(ParserATNSimulator.java:467)
at org.antlr.v4.runtime.atn.ParserATNSimulator.adaptivePredict(ParserATNSimulator.java:393)
at org.antlr.v4.runtime.ParserInterpreter.visitDecisionState(ParserInterpreter.java:316)
at org.antlr.v4.runtime.ParserInterpreter.visitState(ParserInterpreter.java:223)
at org.antlr.v4.runtime.ParserInterpreter.parse(ParserInterpreter.java:194)
at org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher.compile(ParseTreePatternMatcher.java:205)
Когда я попытался:
List<? extends Token> tokenList = matcher.tokenize(code);
Результат содержал один токен, такой же, как при использовании лексера с DEFAULT_MODE
. Есть ли какой-нибудь способ исправить это?
Ответ №1:
Проблема заключалась в следующем коде из ParseTreePatternMatcher::tokenize
:
TextChunk textChunk = (TextChunk)chunk;
ANTLRInputStream in = new ANTLRInputStream(textChunk.getText());
lexer.setInputStream(in);
Token t = lexer.nextToken();
Lexer::setInputStream
очищает _modeStack
и устанавливает _mode
в 0
. Одним из возможных решений является расширение ParseTreePatternMatcher
, переопределение метода tokenize
и вставка lexer.pushMode(lexerMode)
после lexer.setInputStream(in)
:
TextChunk textChunk = (TextChunk)chunk;
ANTLRInputStream in = new ANTLRInputStream(textChunk.getText());
lexer.setInputStream(in);
lexer.pushMode(lexerMode);
Token t = lexer.nextToken();
Но метод tokenize
использует Chunk
и TextChunk
, к которым нельзя получить доступ из большого пакета, поэтому мы обязаны определить класс расширения в том же пакете, что и ParseTreePatternMatcher
.
Другим решением, которое я рассматриваю, является изменение байтового кода метода с использованием ASM.