如何使用具有相同起点的词法分析器规则?
我正在尝试使用两个类似的词法规则(具有相同的起点):
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;
答案 0 :(得分:6)
一旦匹配DIGIT+ ':'
,词法分析器就会希望此后跟另一个DIGIT
匹配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:我知道的大多数词法生成器会有一个问题正确地标记这样的TIMECONSTANT
(当INTEGER
和COLON
也存在时)。 ANTLR至少有助于在词法分析器中处理它:)
你可以也让解析器而不是词法分析器来处理它:
time_const : INTEGER COLON INTEGER;
INTEGER : '0'..'9'+;
COLON : ':';
SPACE : ' ' {skip();};
但是,如果您的语言词法分析器忽略空格,则输入如下:
12 : 34
当然,也会与time_const
规则相匹配。
答案 1 :(得分:1)
ANTLR词法分析器无法回溯,这意味着一旦它到达TIMECONSTANT规则中的“:”,它必须完成规则或抛出异常。您可以使用谓词来测试冒号后面是否存在数字,从而使语法正常工作。
TIMECONSTANT: ('0'..'9')+ (':' '0'..'9')=> ':' ('0'..'9')+;
INTEGER : ('0'..'9')+;
COLON : ':';
这将强制ANTLR在确定它处于TIMECONSTANT规则之前超越冒号。