Режимы сопоставления с шаблоном Antlr и lexer

#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.