Antlr4 ANTLR中带有贪婪通配符和转义字符的字符串词汇规则
摘自《最终ANTLR 4参考》一书: 我们的字符串规则还不够好,因为它不允许 字符串中的双引号。为了支持这一点,大多数语言定义 以反斜杠开始的转义序列。获得双重报价 在双引号字符串中,我们使用Antlr4 ANTLR中带有贪婪通配符和转义字符的字符串词汇规则,antlr4,Antlr4,摘自《最终ANTLR 4参考》一书: 我们的字符串规则还不够好,因为它不允许 字符串中的双引号。为了支持这一点,大多数语言定义 以反斜杠开始的转义序列。获得双重报价 在双引号字符串中,我们使用\“。来支持公共转义 角色,我们需要如下内容: ANTLR本身需要转义转义字符,所以我们需要\\来 指定反斜杠字符。字符串中的循环现在匹配 通过调用片段规则ESC,或任何 通过点通配符的单个字符。*?子规则运算符 终止(ESC |.*)? 这听起来不错,但当我读到这篇文章时,我注意到在ESC和之间的选择
\“
。来支持公共转义
角色,我们需要如下内容:
ANTLR本身需要转义转义字符,所以我们需要\\
来
指定反斜杠字符。字符串中的循环现在匹配
通过调用片段规则ESC
,或任何
通过点通配符的单个字符。*?
子规则运算符
终止(ESC |.*)?
这听起来不错,但当我读到这篇文章时,我注意到在ESC
和
之间的选择存在某种模糊性。就字符串而言,通过将转义字符\
与
匹配,可以匹配输入“Hi\”
,并考虑下面的双引号作为关闭字符串。这甚至会减少贪婪,因此更符合?
的使用
当然,问题是,如果我们这样做,那么我们在最后会有一个额外的双引号,与任何东西都不匹配
所以我写了以下语法:
grammar String;
anything: STRING '"'? '\r\n';
STRING: '"' (ESC|.)*? '"';
fragment
ESC: '\\"' | '\\\\';
它在字符串后面接受可选的双引号字符。此语法仍将“Orange\”
解析为完整字符串:
所以我的问题是:为什么这是公认的解析,而不是将“Orange\”
作为字符串,后跟一个独立的双引号“
?请注意,后者的贪婪程度较低,这似乎更符合?
的用法,因此人们可能会认为它更可取。经过一些实验后,我意识到解释是选择运算符|
是顺序相关的(但仅在非贪婪运算符?
下):ESC
在之前尝试过。如果我将两者颠倒并写入(.| ESC)*?
,我会得到
这并不令人惊讶,但有趣的是,ANTLR并不像我们有时所期望的那样具有声明性(在某种意义上,逻辑或是顺序独立的,但不是顺序独立的)。这也是一个很好的提醒,非贪婪运算符?
并没有将其最小化功能扩展到所有选项,而只是扩展到与输入匹配的第一个选项(@sepp2k添加了顺序依赖性,仅适用于非贪婪情况)。请注意,只有在使用*?
(非贪婪)时,顺序才起作用。当不使用*?
时,最大芒克规则的应用与备选方案的顺序无关。顺便说一句:您可以通过使用(~'“''ESC)*
或(ESC | `')*
来摆脱这里的不贪婪。
grammar String;
anything: STRING '"'? '\r\n';
STRING: '"' (ESC|.)*? '"';
fragment
ESC: '\\"' | '\\\\';