如何使用具有相同开头的lexer规则?

我正在尝试使用两个相似的词法分析器规则(具有相同的开头):

TIMECONSTANT: ('0'..'9')+ ':' ('0'..'9')+;
INTEGER     : ('0'..'9')+;
COLON       : ':';

这是我的示例语法:
grammar TestTime;

text      : (timeexpr | caseblock)*;

timeexpr  : TIME;
caseblock : INT COLON ID;

TIME      : ('0'..'9')+ ':' ('0'..'9')+;
INT       : ('0'..'9')+;
COLON     : ':';
ID        : ('a'..'z')+;

WS        : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};

当我尝试解析文本时:
12:44
123 : abc
123: abc

正确解析了前两行,第3行-产生错误。
由于某些原因,“123:” ANTLR解析为TIME(不是)。

那么,是否有可能用这样的词法进行语法制作呢?

在我的语言中,要同时使用大小写块和日期时间常量,必须有这样的规则。例如,用我的语言可以写:
case MyInt of
  1: a := 01.01.2012;
  2: b := 12:44;
  3: ....
end;

最佳答案

一旦DIGIT+ ':'被匹配,词法分析器期望它之后是另一个DIGITTIMECONSTANT匹配。如果这没有发生,则它不能依赖于另一个匹配DIGIT+ ':'的词法分析器规则,并且该词法分析器不会放弃已经匹配的':'来匹配INTEGER

一种可能的解决方案是在':' DIGIT+规则的末尾有选择地匹配INTEGER,并在匹配时更改 token 的类型:

grammar T;

parse
 : (t=. {System.out.printf("\%-15s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
 ;

INTEGER      : DIGIT+ ((':' DIGIT)=> ':' DIGIT+ {$type=TIMECONSTANT;})?;
COLON        : ':';
SPACE        : ' ' {skip();};

fragment DIGIT : '0'..'9';
fragment TIMECONSTANT : ;

解析输入时:
11: 12:13 : 14

将打印以下内容:
INTEGER         '11'
COLON           ':'
TIMECONSTANT    '12:13'
COLON           ':'
INTEGER         '14'

编辑



真的。但是,这并不是ANTLR的不足:我所知道的大多数词法分析器生成器都将在正确标记此类TIMECONSTANT时遇到问题(当同时存在INTEGERCOLON时)。 ANTLR至少有助于在词法分析器中处理它的方法:)

您还可以让它由解析器而不是词法分析器处理:
time_const : INTEGER COLON INTEGER;
INTEGER    : '0'..'9'+;
COLON      : ':';
SPACE      : ' ' {skip();};

但是,如果您语言的词法分析器忽略空格,则输入如下内容:
12 :    34

当然,也会通过time_const规则进行匹配。

关于ANTLR如何使用以相同的开头的词法分析器规则?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10029137/

10-10 09:00