Можно ли разделить токен на 2 в Antlr4? - PullRequest
0 голосов
/ 10 марта 2020

Мне нужно иметь возможность разделить один токен на 2 для целей выделения, у меня есть токен, который выглядит следующим образом:

ID_INTERP: '$' IDEN;

, но я хочу выделить знак доллара не так, как идентификатор, поэтому Можно ли разделить этот токен на два, один со знаком доллара, а другой с идентификатором? Я знаю, что при определенных условиях я могу изменить весь токен на другой тип, но я хотел бы иметь возможность добавлять и изменять текст, который он содержит, в основном для изменения потока токенов, поэтому вместо того, чтобы говорить

ID_INTERP [ "$ foo"]

будет выглядеть примерно так:

DOLLAR_SIGN ["$"] IDEN ["foo"]

1 Ответ

2 голосов
/ 10 марта 2020

Это возможно, если вы расширили свой токен, чтобы испустить больше одного токена для данного совпадения. Я использовал эту идею для генерации 2 токенов для правила лексера DOT_IDENTIFIER ( см. Грамматику MySQL в синтаксическом анализаторе MySQL Workbench ). На совпадении он выдвигает точечный токен и устанавливает результат в IDENTIFIER, эффективно создавая 2 отдельных токена для одного правила.

Сэм Харуэлл описал технику расширения вашего лексера для этого подхода в своем ответе с некоторым кодом Java. И вот возможная реализация C ++, которую я использую:

std::unique_ptr<antlr4::Token> MySQLBaseLexer::nextToken() {
  // First respond with pending tokens to the next token request, if there are any.
  if (!_pendingTokens.empty()) {
    auto pending = std::move(_pendingTokens.front());
    _pendingTokens.pop_front();
    return pending;
  }

  // Let the main lexer class run the next token recognition.
  // This might create additional tokens again.
  auto next = Lexer::nextToken();
  if (!_pendingTokens.empty()) {
    auto pending = std::move(_pendingTokens.front());
    _pendingTokens.pop_front();
    _pendingTokens.push_back(std::move(next));
    return pending;
  }
  return next;
}
...