java - Antlr4 带模式的常用令牌
问题描述
将标记移动到公共文件之前的语法
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。
问题:我该如何解决这个问题?IDENTIFIER 应保留在 CommonLexer 中。
如果您需要更多详细信息,请告诉我,谢谢。
解决方案
我不能确定(你只是在 Common Lexer 提取中有日食),但在原始 Lexer 语法中,只有在你被推送 VALUE_MODE 时才会匹配 IDENTIFIER。当您创建 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。这往往会产生各种令牌化歧义问题。)
推荐阅读
- android - firebaseAuth.getCurrentUser 在第一次调用时返回 null
- python - TypeError: 'DataFrame' object is not callable 错误信息
- python - 降低科学计数法中长小数的准确性
- java - Java - 将十六进制字符串解析为 ASN.1 格式
- python - 递归函数优于使用可读性之外的循环的好处?
- postgresql - 如何使用 Typeorm 创建与 Postgres 的连接
- spyder - 如何更新 spyder 独立应用程序
- sql-server - SQL 复制安全
- c# - 我找不到在哪里添加参数
- flutter - 如何在屏幕上打印一条警告消息,告诉测验问题并以颤振结束