我有这样的语法:
grammar Testquote;
program : (Line ';')+ ;
Line: L_S_STRING ;
L_S_STRING : '\'' (('\'' '\'') | ('\\' '\'') | ~('\''))* '\''; // Single quoted string literal
L_WS : L_BLANK+ -> skip ; // Whitespace
fragment L_BLANK : (' ' | '\t' | '\r' | '\n') ;
此语法-尤其是L_S_STRING
-似乎可以很好地与像这样的原始输入配合使用:
'ab';
'cd';
但是,此输入失败:
'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z\\'';
'cd';
当我将第一行更改为任一行时
'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z''';
或
'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z\\' '
;
我可以看到解析器为何选择此失败路由的原因。但是有什么方法可以告诉我选择不同的方法吗?
答案 0 :(得分:1)
根据ANTLR4文档,词法分析器和解析器规则均为贪婪,因此会匹配尽可能多的输入。就您而言:
'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z\\'';
^^^
'cd';
您的语法有些模棱两可-我突出显示的字符可以解释为\'
'
或\
''
。看看它是如何工作的。
没有'cd'
时,词法分析器匹配一个字符串,因为它是您语法的有效字符串,突出显示的字符匹配为\'
'
。但是,由于lexer很贪婪,因此它会首先使用上述歧义来匹配不需要的输入,例如稍后再在某处添加另一个未转义的'
。
这种歧义是由于反斜杠是普通字符还是转义字符的可能引起的。消除这种歧义性的常见解决方案是转义反斜杠本身的规则:\\
,还需要不将其与普通字符匹配。>
或者,您可能希望以不同的方式处理歧义。如果您想将\'
优先于''
,请输入:
L_S_STRING : '\'' ( ('\'\'') | ('\\'+ ~'\\') | ~('\'' | '\\') )* '\'' ;
它将适用于您的输入。
通过这种方式,您可以缩短L_WS的代码:
L_WS : [ \t\n\r]+ -> skip ;