我一般认为这个规则
rule: ( something ? ) ;
通常可以表示为没有任何交替,具有相同的语义
rule: ( something | ) ; <-- empty alt here
(当然提供'某事'是单个项目或括号以使其如此) . 它似乎显然是正确的,但antlr4没有它 . 这段代码就像我期望的那样
version 1, works
opt_cursor_into_spec :
( cursor_into_spec ? )
;
cursor_into_spec :
INTO
sident ( COMMA sident ) *
;
但这不是;无法解析输入:
version 2, fails
opt_cursor_into_spec : // this rule's changed
cursor_into_spec
|
// empty alt
;
cursor_into_spec : // this is the same
INTO
sident ( COMMA sident ) *
;
这是版本2上诊断跟踪的一部分,请注意[***]
consume [@1,8:11='crsr',<483>,2:6] rule regular_ident
exit regular_ident, LT(1)=<EOF>
exit sident, LT(1)=<EOF>
exit cic_cursor_name, LT(1)=<EOF>
exit cursor_ident_clause, LT(1)=<EOF>
enter opt_cursor_into_spec, LT(1)=<EOF>
line 4:0 no viable alternative at input '<EOF>' [***]
exit opt_cursor_into_spec, LT(1)=<EOF>
exit fetch_statement, LT(1)=<EOF>
exit sql_item, LT(1)=<EOF>
enter opt_sql_separators, LT(1)=<EOF>
exit opt_sql_separators, LT(1)=<EOF>
exit sql_items, LT(1)=<EOF>
这是奇怪的,因为它声称没有可行的选择,但在它之前说它已进入opt_cursor_into_spec,但是这条规则有空的替代,它肯定总是匹配 - 我总是可以匹配空字符串,我想?
我对这种等价的假设也是如此......
( x ? ) === ( x | <<<nothing>>> )
......不对,还是什么?这个Q不是关于代码,而是关于我对语义的理解 . 如果有人认为这些应该这样做,我会尝试发布可重现的代码 .
编辑:现在更加困惑 . 剥离的语法没有重现 . 关于文件结尾的一些东西是可疑的,因为解析的输入只是 fetch a
并且它似乎根据诊断跟踪被完全解析,然后失败 . 嗯 . 我在启动规则中添加了一个显式的EOF,所以(稍微简化)
sql_items : sql_item * ; // ORIGINAL
成为
sql_items : sql_item * EOF; // NEW
两者( x?
和 x|<<<nothing>>>
)突然为NEW工作 . 以前只有x?曾为ORIGINAL工作过 . 添加EOF测试肯定不会导致以前不成功的解析成功,是吗?
编辑3:编辑2击中,因为它是误导和无益的
编辑2:在反射上向语法添加EOF当然可以导致先前成功的解析失败,因为输入可以在开始时形成良好但整体上是畸形的(即想象解析表达式2 3£$%& ,开始是有效的,但总的来说它是粗鲁的)但这显然不是这里发生的事情 .
1 回答
在版本1中,规则
opt_cursor_into_spec
匹配iff规则cursor_into_spec
匹配 . 在版本2中,规则opt_cursor_into_spec
将始终匹配 . 因此,语法的语义,特别是由于opt_cursor_into_spec
作为元素的规则,将有所不同 .可能,在版本2中,您收到有关可以匹配任何内容的规则的编译时警告 . 除非您真正了解原因和结果,否则您不能忽略该警告 .