是否可以在 Antlr4 中将令牌拆分为 2?
Is it possible to split a token into 2 in Antlr4?
为了突出显示,我需要能够将一个令牌分成 2 个,我有一个看起来像这样的令牌:
ID_INTERP: '$' IDEN;
但我想突出显示美元符号与标识符不同,那么是否可以将此令牌拆分为两个,一个带有美元符号,另一个带有标识符?我知道我可以在某些条件下将整个令牌更改为不同的类型,但我希望能够添加和更改它包含的文本,基本上是更改令牌流,而不是说
ID_INTERP["$foo"]
它会看到这样的东西:
DOLLAR_SIGN["$"] IDEN["foo"]
可以通过扩展您的令牌源来为给定匹配发出多个令牌。我已经使用这个想法为词法分析器规则 DOT_IDENTIFIER
(see the MySQL grammar in the MySQL Workbench parser) 生成了 2 个标记。在匹配时,它会推送一个点标记并将结果设置为 IDENTIFIER
,有效地为单个规则创建 2 个单独的标记。
Sam Harwell 描述了使用一些 Java 代码为这种方法 in his answer 扩展词法分析器的技术。这是我正在使用的可能的 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;
}
为了突出显示,我需要能够将一个令牌分成 2 个,我有一个看起来像这样的令牌:
ID_INTERP: '$' IDEN;
但我想突出显示美元符号与标识符不同,那么是否可以将此令牌拆分为两个,一个带有美元符号,另一个带有标识符?我知道我可以在某些条件下将整个令牌更改为不同的类型,但我希望能够添加和更改它包含的文本,基本上是更改令牌流,而不是说
ID_INTERP["$foo"]
它会看到这样的东西:
DOLLAR_SIGN["$"] IDEN["foo"]
可以通过扩展您的令牌源来为给定匹配发出多个令牌。我已经使用这个想法为词法分析器规则 DOT_IDENTIFIER
(see the MySQL grammar in the MySQL Workbench parser) 生成了 2 个标记。在匹配时,它会推送一个点标记并将结果设置为 IDENTIFIER
,有效地为单个规则创建 2 个单独的标记。
Sam Harwell 描述了使用一些 Java 代码为这种方法 in his answer 扩展词法分析器的技术。这是我正在使用的可能的 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;
}