ANTLR中的字符串词汇规则,带有贪婪的Wildcald和转义字符

时间:2019-02-22 02:46:29

标签: antlr4

摘自《权威ANTLR 4参考》一书

  

我们的STRING规则还不够完善,因为它不允许   字符串中的双引号。为此,大多数语言定义   以反斜杠开头的转义序列。获得双引号   在双引号字符串中,我们使用\"。为了支持普通逃生   字符,我们需要以下内容:

STRING ​: ​ ​'"' ​( ESC |.)*?​ ​'"' ​ ​;
fragment
ESC ​: ​ ​'\\"'  | ​ ​'\\\\' ​ ​; ​ ​// 2-char sequences \" and \\ 
  

ANTLR本身需要转义转义字符,所以这就是为什么我们需要\\来转义   指定反斜杠字符。 STRING中的循环现在可以匹配   通过调用片段规则ESC或其他任何转义字符序列   通过点通配符的单个字符。 *?子规则运算符   终止(ESC |.)*?

听起来不错,但是当我读到它时,发现ESC.之间的选择存在一定的歧义。就STRING而言,可以通过将转义字符"Hi\""\匹配来匹配输入.,并考虑以下转义的双引号作为关闭字符串。这甚至可以减少贪婪程度,因此更适合使用?

当然,问题在于,如果我们这样做,那么末尾会有一个多余的双引号,该双引号不会与任何内容匹配。

所以我写了以下语法:

grammar String;

anything: STRING '"'? '\r\n';

STRING: '"' (ESC|.)*? '"';
fragment
ESC: '\\"' | '\\\\';

,它在字符串之后接受一个可选的孤独双引号字符。该语法仍将"Orange\""解析为完整字符串:

Parse of <code>"Orange\""</code> even if a later isolated double-quote is acceptable

所以我的问题是:为什么这是可接受的解析,而不是将"Orange\"用作STRING,然后加上孤立的双引号"?请注意,后者的贪婪程度会降低,这似乎更适合使用?,因此人们可能会认为它更可取。

1 个答案:

答案 0 :(得分:1)

经过更多的实验,我意识到解释是选择运算符|是依赖顺序的(但仅在非贪婪运算符?下):ESC在{ {1}}。如果我将两者取反并写成.,我会得到

Parse of <code>"Orange\""</code> even if a later isolated double-quote is acceptable after switching <code>ESC</code> and <code>.</code> in the grammar

这并不令人感到意外,但是有趣的是,ANTLR并不像我们有时期望的那样声明(从逻辑上说,逻辑或顺序无关,而(.|ESC)*?则不然)。这也很好地提醒您,非贪婪运算符|不会将其最小化功能扩展到所有选择,而只会扩展到与输入匹配的第一个选择(@ sepp2k补充说,顺序依赖性仅适用于非贪婪的情况)。