antlr 4 词法分析器规则 RULE: '<TAG>';未被识别为令牌,但如果片段规则被识别

antlr 4 lexer rule RULE: '<TAG>'; isn't recognized as token but if fragment rule then recognized

编辑: 有人问我是否可以提供完整的语法。我不能,原因如下:

我不能提供我的完整语法代码,因为这是作业,我不能公开我的解决方案,如果我的问题因此而无法回答,我将很遗憾地理解.我只是希望这是一件我无法从文档中理解的简单事情,这足以让知道 antlr4 的人知道答案。

这是在原始答案中 post 编辑的,但为了防止可能的帮助者感到沮丧,我现在将其提升到 post 的顶部。 免责声明:这是作业相关的。

我正在尝试为作业标记一段文本,几乎所有内容都按预期工作,但以下内容除外:

TIME                    : '<time>';

这条规则曾经在我的语法中。对一段文本进行标记时,我看不到 TIME 标记,而是看到 '<time>' 标记(我猜 Antlr 以某种方式为我创建了它)。但是当我将字符串本身移动到片段规则并使 TIME 规则指向它时,如下所示:

fragment TIME_TAG       : '<time>';
.
.
.
TIME                    : TIME_TAG;

然后我按预期看到了 TIME 标记。我已经在互联网上搜索了几个小时,但找不到答案。

发生的另一件事是 ATHLETE 规则,其定义为:

ATHLETE                 : WHITESPACE* '<athlete>' WHITESPACE*;

也被正确识别,我看到了 ATHLETE 令牌,但是当 我不允许在标记字符串前后使用 WHITESPACE*

我不能提供我的完整语法代码,因为这是作业,我不能透露我的解决方案,如果我的问题因此而无法回答,我将很遗憾地理解。我只是希望这是一件我无法从文档中理解的简单事情,这足以让知道 antlr4 的人知道答案。

这是我的一段文字:

World Record World Record
[1] <time> 9.86 <athlete> "Carl Lewis" <country> "United
States" <date> 25 August 1991
[2] <time> 9.69 <athlete> "Tyson Gay" <country> "United
States" <date> 20 September 2009
[3] <time> 9.82 <athlete> "Donovan Baily" <country>
"Canada" <date> 27 July 1996
[4] <time> 9.58
 <athlete> "Usain Bolt"
 <country> "Jamaica" <date> 16 August 2009

[5] <time> 9.79 <athlete> "Maurice Greene" <country>
"United State" <date> 16 June 1999

我的任务只是将它标记化。我没有得到令牌的定义,我应该自己决定。我认为 '<sometag>' 非常明显,'"' 包裹的字符串、数字、日期和方括号包围的枚举也是如此。

提前感谢任何帮助或任何有用的知识。

(这将是一个挑战,不只是做功课,但也许一些评论会让你走上正轨)

TIME : '<time>'; 规则应该可以正常工作。 ANTLR 只在解析器规则中为你创建标记。 (解析器规则以小写字母开头,而 Lexer 规则以大写字母开头,所以这个例子不会是这种情况(也许你有一个以小写字母开头的规则名称?)

注意:如果转储令牌,您会看到 TIME 令牌如下所示:

[@3,5:10='<time>',<'<time>'>,2:4]

这意味着 ANTLR 已将其识别为 TIME 令牌(我怀疑这可能是混淆的根源。这正是 ANTLR 打印出 TIME 令牌的方式。)

正如@kaby76 所提到的,我们通常会跳过空格或将其放入隐藏通道,因为我们不想在解析器规则中明确指出我们允许空格的所有地方。这些选项中的任何一个都会导致它们被解析器忽略。一个非常常见的空白规则是:

WS: [ \t\r\n]+;`.  

由于您只是进行标记化,因此无需担心解析器规则。

添加此 Lexer 规则将为您将空格标记为单独的标记,因此您无需在 ATHLETE.

等规则中考虑它

您需要为您的内容制定 Lexer 规则,但这也许会帮助您前进。

以下实现是拆分 lexer/parser 语法,可“标记化”您的输入文件。如果你喜欢,你可以把两者结合起来。我通常会因为 Antlr 词法分析器语法的限制而拆分我的语法,例如当你想“超类”词法分析器时。

但是,如果没有明确的问题陈述,此实现可能无法按要求对输入进行标记。所有的软件都必须从需求开始。如果作业中给出了 none,那么我会准确说明识别的标记类型是什么。

在大多数语言中,空格不包含在解析器使用的标记类型集中。因此,我用“-> skip”来实现它,它告诉词法分析器不要为识别的输入生成标记。

也不清楚输入如“[1]”是作为一个标记还是单独标记。在以下实现中,我为“[”、“1”和“]”生成单独的标记。

“片段”规则的使用可能是不必要的,因此我不包括对该功能的任何使用。 “片段”规则本身不能用于生成标记,并且该符号不能在解析器规则中使用。它们对于重用公共 RHS 很有用。您可以阅读更多相关信息 here

FooLexer.g4:

lexer grammar FooLexer;
Athlete : '<athlete>';
Date : '<date>';
Time : '<time>';
Country : '<country>';
StringLiteral : '"' .*? '"';
Stray : [a-zA-Z]+;
OB : '[';
CB : ']';
Number : [0-9.]+;
Ws : [ \t\r\n]+ -> skip;

FooParser.g4:

parser grammar FooParser;
options { tokenVocab = FooLexer; }
start: .* EOF;

代币:

$ trparse input.txt | trtokens
Time to parse: 00:00:00.0574154
# tokens per sec = 1219.1850966813781
[@0,0:4='World',<6>,1:0]
[@1,6:11='Record',<6>,1:6]
[@2,13:17='World',<6>,1:13]
[@3,19:24='Record',<6>,1:19]
[@4,27:27='[',<7>,2:0]
[@5,28:28='1',<9>,2:1]
[@6,29:29=']',<8>,2:2]
[@7,31:36='<time>',<3>,2:4]
[@8,38:41='9.86',<9>,2:11]
[@9,43:51='<athlete>',<1>,2:16]
[@10,53:64='"Carl Lewis"',<5>,2:26]
[@11,66:74='<country>',<4>,2:39]
[@12,76:91='"United\r\nStates"',<5>,2:49]
[@13,93:98='<date>',<2>,3:8]
[@14,100:101='25',<9>,3:15]
[@15,103:108='August',<6>,3:18]
[@16,110:113='1991',<9>,3:25]
[@17,116:116='[',<7>,4:0]
[@18,117:117='2',<9>,4:1]
[@19,118:118=']',<8>,4:2]
[@20,120:125='<time>',<3>,4:4]
[@21,127:130='9.69',<9>,4:11]
[@22,132:140='<athlete>',<1>,4:16]
[@23,142:152='"Tyson Gay"',<5>,4:26]
[@24,154:162='<country>',<4>,4:38]
[@25,164:179='"United\r\nStates"',<5>,4:48]
[@26,181:186='<date>',<2>,5:8]
[@27,188:189='20',<9>,5:15]
[@28,191:199='September',<6>,5:18]
[@29,201:204='2009',<9>,5:28]
[@30,207:207='[',<7>,6:0]
[@31,208:208='3',<9>,6:1]
[@32,209:209=']',<8>,6:2]
[@33,211:216='<time>',<3>,6:4]
[@34,218:221='9.82',<9>,6:11]
[@35,223:231='<athlete>',<1>,6:16]
[@36,233:247='"Donovan Baily"',<5>,6:26]
[@37,249:257='<country>',<4>,6:42]
[@38,260:267='"Canada"',<5>,7:0]
[@39,269:274='<date>',<2>,7:9]
[@40,276:277='27',<9>,7:16]
[@41,279:282='July',<6>,7:19]
[@42,284:287='1996',<9>,7:24]
[@43,290:290='[',<7>,8:0]
[@44,291:291='4',<9>,8:1]
[@45,292:292=']',<8>,8:2]
[@46,294:299='<time>',<3>,8:4]
[@47,301:304='9.58',<9>,8:11]
[@48,308:316='<athlete>',<1>,9:1]
[@49,318:329='"Usain Bolt"',<5>,9:11]
[@50,333:341='<country>',<4>,10:1]
[@51,343:351='"Jamaica"',<5>,10:11]
[@52,353:358='<date>',<2>,10:21]
[@53,360:361='16',<9>,10:28]
[@54,363:368='August',<6>,10:31]
[@55,370:373='2009',<9>,10:38]
[@56,378:378='[',<7>,12:0]
[@57,379:379='5',<9>,12:1]
[@58,380:380=']',<8>,12:2]
[@59,382:387='<time>',<3>,12:4]
[@60,389:392='9.79',<9>,12:11]
[@61,394:402='<athlete>',<1>,12:16]
[@62,404:419='"Maurice Greene"',<5>,12:26]
[@63,421:429='<country>',<4>,12:43]
[@64,432:445='"United State"',<5>,13:0]
[@65,447:452='<date>',<2>,13:15]
[@66,454:455='16',<9>,13:22]
[@67,457:460='June',<6>,13:25]
[@68,462:465='1999',<9>,13:30]
[@69,466:465='',<-1>,13:34]