具有模式的 Antlr4 通用标记

Antlr4 common tokens with modes

将标记移动到普通文件之前的语法

lexer grammar ALexer;

COMMAND_START
    : [a-zA-Z]                          -> pushMode(COMMAND_MODE)
    ;

EQUALS
    : '='                               -> pushMode(VALUE_MODE)
    ;

mode COMMAND_MODE;

COMMAND_NAME_REMAINDER
    : ([a-zA-Z0-9_ ]? [a-zA-Z0-9])*     -> popMode
    ;

mode VALUE_MODE; 

IDENTIFIER
    : A_Z ((UNDERSCORE | A_Z | DIGIT | WS)*? (UNDERSCORE | A_Z | DIGIT))* -> popMode
    ;

将标记移动到普通文件后的语法

其他 3 个词法分析器导入了通用词法分析器。它具有共享的 IDENTIFIER 令牌。

lexer grammar CommonLexer;

..
..
IDENTIFIER
    : A_Z ((UNDERSCORE | A_Z | DIGIT | WS)*? (UNDERSCORE | A_Z | DIGIT))*
    ;

下面的词法分析器导入了普通词法分析器,有几种模式

lexer grammar ALexer;

import CommonLexer;

COMMAND_START
    : [a-zA-Z]                          -> pushMode(COMMAND_MODE)
    ;

EQUALS
    : '='                               -> pushMode(VALUE_MODE)
    ;


mode COMMAND_MODE;

COMMAND_NAME_REMAINDER
    : ([a-zA-Z0-9_ ]? [a-zA-Z0-9])*     -> popMode
    ;

mode VALUE_MODE; 

IDENTIFIER_VALUE_MODE
    : IDENTIFIER                            -> type(IDENTIFIER), popMode
    ;   

解析器语法:

parser grammar AParser;

options { tokenVocab=ALexer; }

genericCommand
    : COMMAND_START COMMAND_NAME_REMAINDER? (COLON parameterArray)?
    ;

结果: 诸如“删除资源:a;”之类的命令之前被识别为 COMMAND_START 现在被识别为 IDENTIFIER.

result screenshot

问题:我该如何解决这个问题? IDENTIFIER 应保留在 CommonLexer 中。

如果您需要更多详细信息,请告诉我,谢谢。

我不能确定(你只是在 Common Lexer 摘录中有遮蔽),但在原始的 Lexer 语法中,IDENTIFIER 只会在你被推送 VALUE_MODE 时匹配。在您创建 Common Lexer 时,您似乎已经失去了该特征。由于它在普通的 Lexer 中是“公开的”,因此无论您是否在 VALUE_MODE 中,它都会匹配(并且长度将使它成为更强的匹配)。这解释了不同的行为。

您的 IDENTIFIER 词法分析器规则匹配的字符串比 COMMAND_START 长,因此优先。您不会在 COMMAND_START 规则上“命中”以将您推向 COMMAND_MODE。这是你问题的核心。您的 IDENTIFIER 规则与 COMMAND_START 规则重叠,并且总是至少与 COMMAND_START 规则匹配一样长(1 个字符)或更长,因此 ANTLR 将始终支持它。

如果没有 A_Z、UNDERSCORE、DIGIT 和 WS 的片段定义(您像片段一样使用它们,所以我认为它们是),很难确定您想要的区别在 COMMAND 和 IDENTIFIER 之间。

您 COMMAND_START 触发模式只是立即弹出的方式是“不寻常的”。我希望看到包含整个模式的 COMMAND Lexer 规则:

COMMAND: [a-zA-Z]([a-zA-Z0-9_ ]? [a-zA-Z0-9])* 

这里是我无法真正区分输入流中的 COMMAND 和 IDENTIFIER 的地方。 (在标记中包含 WS 也是一种反模式)。

这是您可以控制语言设计的东西,还是必须匹配既定定义的东西?

如果你有控制权,我建议你应该稍微阅读并重新考虑你的方法。

如果它已经建立,也许你可以分享建立的定义以及它如何区分 IDENTIFIER 和 COMMAND。

阅读此处的字里行间,似乎冒号之前的内容是命令,冒号之后的内容是您期望的标识符。

我认为您试图将太多工作投入 Lexer。尝试重新考虑您的命令解析器规则,使其更像解析器规则:

genericCommand:  +IDENTIFIER (COLON parameterArray)?;

(如果您可以管理它,我建议从 COMMAND 和 IDENTIFIER 令牌中删除 WS。这往往会产生各种令牌化歧义问题。)