首页 > 解决方案 > 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 中。

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

标签: javaparsingantlr4

解决方案


我不能确定(你只是在 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。这往往会产生各种令牌化歧义问题。)


推荐阅读