antlr4两个lexer规则匹配相同的字符串

antlr4两个lexer规则匹配相同的字符串,antlr,antlr4,lexer,Antlr,Antlr4,Lexer,我目前正在使用antlr4构建解析器,但我遇到了一个问题,我尽了最大努力但没有解决。你能帮我解释并解决它吗 # grammer file : PluginDoc.g4: grammer PluginDoc pluginDef : pluginName | pluginDesc; pluginName : PluginName IDENTIFIER; pluginDesc : PluginDesc TEXT; PluginName '@pluginName' PluginDesc '@plu

我目前正在使用antlr4构建解析器,但我遇到了一个问题,我尽了最大努力但没有解决。你能帮我解释并解决它吗

# grammer file : PluginDoc.g4:

grammer PluginDoc

pluginDef : pluginName | pluginDesc;
pluginName : PluginName IDENTIFIER;
pluginDesc : PluginDesc TEXT;

PluginName '@pluginName'
PluginDesc '@pluginDesc'

IDENTIFIER : [a-zA-Z_]+;
TEXT : ~( ' ' | '\n' | '\t' )+;

input content is: 
@pluginName kafka
@pluginDesc abc
如果我将标识符放在文本之前,我将得到“不匹配的输入'abc'预期文本” 如果我将文本放在标识符之前,我将得到“不匹配的输入'kafka'预期标识符”


看起来标识符和文本都匹配了,我怎么才能只匹配pluginName中的标识符而只匹配pluginDesc中的文本呢?

首先,您发布的语法中有几个错误:

文件头应该指定语法,而不是语法。你的Lexer标记PluginName和PluginDesc前面没有冒号,也没有分号来终止它们。这也是一条(不成文的?)规则,将解析器规则全部写为小写,将lexer规则全部写为大写

grammar PluginDoc;

pluginDef : pluginName | pluginDesc;
pluginName : PLUGIN_NAME IDENTIFIER;
pluginDesc : PLUGIN_DESC TEXT;

PLUGIN_NAME : '@pluginName';
PLUGIN_DESC : '@pluginDesc';

IDENTIFIER : [a-zA-Z_]+;
TEXT : ~( ' ' | '\n' | '\t' )+;
我在测试语法时遇到的一些问题是由于未处理的空格造成的。首先,您应该包括一个Lexer规则,以便在所有其他Lexer规则之后跳过文件末尾的空白

WS: [ \n\t\r]+ -> skip;
接下来,您的
文本
标识符
冲突出现问题。当字符流由Lexer标记时,
kafka
abc
可以是
标识符
文本
标记。由于Lexer-lexes是自上而下的,它们都被标记为语法中的whateve-Lexer规则。这会导致您遇到的错误-无论您定义为第二条规则的内容是什么,都无法在解析器中匹配,因为它不是作为令牌发送的

正如Lucas所建议的,您可能应该将这两个匹配为
TEXT
,然后在您的侦听器/访问者中检查输入的有效性

grammar PluginDoc;

pluginDef : (pluginName | pluginDesc)* EOF;
pluginName : PLUGIN_NAME TEXT;
pluginDesc : PLUGIN_DESC TEXT;

PLUGIN_NAME: '@pluginName';
PLUGIN_DESC: '@pluginDesc';

TEXT : ~[ \r\n\t]+;

WS: [ \r\n\t]+ -> skip;
我还将
pluginDef
解析器规则更改为

pluginDef : (pluginName | pluginDesc)* EOF;
因为我的印象是,您希望同时输入
@pluginName X
@pluginDesc Y
,并识别它们。如果情况并非如此,请随意更改回以前的状态

在您的示例输入上,由上面修改的语法生成的结果AST:


您也可以使用文本文件作为输入来运行此操作。

只需对两者使用
text
,然后在后处理阶段验证标识符名称。
EOF
是什么意思?@GaryGauh-EOF是内置的文件结尾标识符。如果输入是一个文件,则可以是文件的文本结尾,也可以是CTRL-Z/D in终端,具体取决于您的操作系统。举个例子,如果没有它,它可能会很好地工作,但经验告诉我要把它放在那里,以避免以后出现问题。