Antlr4:单引号规则在有转义字符加回车符时失败,换行

时间:2018-11-25 06:00:25

标签: antlr4

我有这样的语法:

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\\' ';

我可以看到解析器为何选择此失败路由的原因。但是有什么方法可以告诉我选择不同的方法吗?

1 个答案:

答案 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 ;