Antlr4:当有转义字符加回车return、新行时,单引号规则失败
Antlr4: single quote rule fails when there are escape chars plus carriage return, new line
我有这样的语法:
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\' '
;
我大概明白为什么解析器会选择这条失败的路由。但是有什么方法可以让它做出不同的选择吗?
根据 ANTLR4 文档,词法分析器和解析器规则都是贪婪,因此匹配尽可能多的输入。在你的情况下:
'yyyy-MM-dd\'T\'HH:mm:ss\'Z\'';
^^^
'cd';
您的语法有些含糊 - 我突出显示的字符可以解释为 \'
'
或 \
''
。看看它是如何工作的。
如果没有 'cd'
,词法分析器会匹配一个字符串,因为它是您语法的有效字符串,突出显示的字符匹配为 \'
'
。但是由于词法分析器是贪婪的,它会首先使用上述歧义来匹配不需要的输入,例如稍后在某处添加另一个未转义的 '
.
这种歧义是由于反斜杠可能是普通字符或转义字符造成的。消除这种歧义的常见解决方案是转义反斜杠本身的规则:\
,您还需要不将其作为普通字符匹配.
或者,您可能希望以不同的方式处理歧义。如果你想 \'
优先于 ''
,你应该写:
L_S_STRING : '\'' ( ('\'\'') | ('\'+ ~'\') | ~('\'' | '\') )* '\'' ;
它将为您的输入工作。
顺便说一句,您可以缩短 L_WS:
的代码
L_WS : [ \t\n\r]+ -> skip ;
我有这样的语法:
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\' '
;
我大概明白为什么解析器会选择这条失败的路由。但是有什么方法可以让它做出不同的选择吗?
根据 ANTLR4 文档,词法分析器和解析器规则都是贪婪,因此匹配尽可能多的输入。在你的情况下:
'yyyy-MM-dd\'T\'HH:mm:ss\'Z\'';
^^^
'cd';
您的语法有些含糊 - 我突出显示的字符可以解释为 \'
'
或 \
''
。看看它是如何工作的。
如果没有 'cd'
,词法分析器会匹配一个字符串,因为它是您语法的有效字符串,突出显示的字符匹配为 \'
'
。但是由于词法分析器是贪婪的,它会首先使用上述歧义来匹配不需要的输入,例如稍后在某处添加另一个未转义的 '
.
这种歧义是由于反斜杠可能是普通字符或转义字符造成的。消除这种歧义的常见解决方案是转义反斜杠本身的规则:\
,您还需要不将其作为普通字符匹配.
或者,您可能希望以不同的方式处理歧义。如果你想 \'
优先于 ''
,你应该写:
L_S_STRING : '\'' ( ('\'\'') | ('\'+ ~'\') | ~('\'' | '\') )* '\'' ;
它将为您的输入工作。
顺便说一句,您可以缩短 L_WS:
的代码L_WS : [ \t\n\r]+ -> skip ;