5

如何使用具有相同开头的词法分析器规则?

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

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

前两行正确解析,第三行 - 生成错误。出于某种原因,'123:' ANTLR 解析为 TIME(虽然不是)...

那么,有没有可能用这样的词法来制作语法呢?

在我的语言中,有这样的规则对于使用 case-blocks 和 datetime 常量是必要的。例如,用我的语言可以写成:

case MyInt of
  1: a := 01.01.2012;
  2: b := 12:44;
  3: ....
end;
4

2 回答 2

6

一旦DIGIT+ ':'匹配,词法分析器期望 this 后面跟着另一个DIGIT匹配 a TIMECONSTANT。如果这没有发生,它就不能依靠另一个匹配DIGIT+ ':'的词法分析器规则,并且词法分析器不会放弃已经匹配':'的匹配一个INTEGER.

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

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 的缺点:我知道的大多数词法分析器生成器在正确标记这样的 a 时都会遇到问题TIMECONSTANT(当INTEGERCOLON也存在时)。ANTLR 至少有利于在词法分析器中处理它:)

可以让解析器而不是词法分析器来处理它:

time_const : INTEGER COLON INTEGER;
INTEGER    : '0'..'9'+;
COLON      : ':';
SPACE      : ' ' {skip();};

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

12 :    34

当然,也将按time_const规则匹配。

于 2012-04-05T17:18:27.767 回答
1

ANTLR 词法分析器不能回溯,这意味着一旦它到达 TIMECONSTANT 规则中的“:”,它必须完成该规则,否则将引发异常。您可以通过使用谓词来测试冒号后面是否存在数字,从而使您的语法正常工作。

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

这将迫使 ANTLR 在确定它在 TIMECONSTANT 规则中之前查看冒号之外的内容。

于 2012-04-05T16:16:21.573 回答