具有模式的 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。这往往会产生各种令牌化歧义问题。)
将标记移动到普通文件之前的语法
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。这往往会产生各种令牌化歧义问题。)