来自“最后的反the 4参考”一书:
我们的字符串规则还不够好,因为它不允许字符串中的双引号。为了支持这一点,大多数语言都定义以反斜杠开头的转义序列。为了在双引号字符串中获得双引号,我们使用
\"。为了支持常见的转义字符,我们需要以下内容:
STRING : '"' ( ESC |.)*? '"' ;
fragment
ESC : '\\"' | '\\\\' ; // 2-char sequences \" and \\ 反斜杠本身需要转义转义字符,所以我们需要
\\来指定反斜杠字符。字符串中的循环现在通过调用片段规则ESC来匹配转义字符序列,或者通过点通配符匹配任何单个字符。*?子规则运算符终止(ESC |.)*?
这听起来不错,但当我读到在ESC和.之间的选择时,我注意到了一定的模糊性。就STRING而言,可以通过将转义字符\与.匹配来匹配输入\,并将以下转义双引号视为结束字符串。这将更不贪婪,因此更符合?的使用。
当然,问题是,如果我们这样做,那么我们有一个额外的双引号在结尾没有得到匹配的任何东西。
所以我写了以下语法:
grammar String;
anything: STRING '"'? '\r\n';
STRING: '"' (ESC|.)*? '"';
fragment
ESC: '\\"' | '\\\\';它在字符串后面接受一个可选的孤独双引号字符。这个语法仍然将"Orange\""解析为一个完整字符串:

所以我的问题是:为什么这是被接受的解析,而不是以"Orange\"作为STRING的解析,然后是一个孤立的双引号"?请注意,后者不那么贪婪,这似乎更符合?的使用,因此人们可能会认为这样做更好。
发布于 2019-02-22 02:46:28
经过更多的实验后,我意识到选择运算符|是顺序相关的(但仅在非贪婪运算符?下):ESC是在.之前尝试的。如果我将两者倒置并编写(.|ESC)*?,我就会得到

这并不令人惊讶,但也是一个有趣的提醒,即ANTLR并不像我们有时所期望的那样具有声明性(在逻辑上--或者是顺序无关,但|不是)。这也很好地提醒我们,非贪婪操作符?并没有将其最小化功能扩展到所有选项,而只是扩展到与输入匹配的第一个选项(@sepp2k补充说,订单依赖只适用于非贪婪的情况)。
https://stackoverflow.com/questions/54819338
复制相似问题