Rascal语法报错求助:@context="num"引发歧义的原因是什么?
这个问题其实和Rascal的上下文敏感词法分析机制直接相关,咱们一步步拆解来理解:
首先得搞懂@context标签到底是干嘛的:它是用来给词法规则绑定一个专属的上下文环境——意思就是,只有当词法分析器运行在这个指定的上下文里时,对应的词法规则才会被用来匹配输入。如果没在语法规则里明确告诉分析器「什么时候要切换到这个上下文」,它就会一脸懵,不知道该什么时候启用你的Number或者Id规则,进而引发歧义错误。
你的代码里的核心问题
你给Number加了@context="num",给Id加了@context="id",给Type加了@context="type",但在最关键的Statement语法规则里,完全没指定什么时候要进入这些上下文。举个例子:
- 当解析到
Type之后,理论上应该进入"id"上下文来匹配Id,但你没标记这个切换点; - 当解析到
=之后,应该进入"num"上下文来匹配Number,同样没标记。
这就导致词法分析器在处理输入时,不知道什么时候该切换到对应的上下文去匹配规则,它会尝试在当前上下文(默认上下文)里找能匹配的规则,但你的Number和Id都绑定了专属上下文,默认上下文里根本找不到有效的匹配规则,或者和其他规则的匹配范围产生冲突,系统自然就抛出歧义错误了。
为什么去掉@context就正常了?
当你删掉所有@context标签后,所有词法规则都回到了默认上下文里。这时候Rascal的词法分析器会按照内置的优先级来处理:
keyword类型的Type优先级最高,会优先匹配int/str/float这些关键字;Id是字母开头,Number是数字开头,两者的字符集完全不重叠,根本不会冲突;
所以分析器能顺顺利利完成匹配,自然就没错误了。
如何修复带@context的版本?
要让@context生效,你需要在语法规则里显式标记上下文的进入和退出点,告诉分析器什么时候该切换环境。修改后的代码大概是这样:
start syntax Statement = Type <enter("id")> Id <exit("id")> "=" <enter("num")> Number <exit("num")> ";" ; lexical Id = @context="id" [a-z] !<< [a-z]+ !>> [a-z] \ Type; lexical Number = @context="num" [0-9]+; keyword Type = @context="type" ("int"|"str"|"float");
这里的<enter("xxx")>和<exit("xxx")>就是告诉分析器:在这个位置进入/退出指定的上下文,这样它就能精准地在对应环境下启用你的词法规则,歧义问题也就解决了。
内容的提问来源于stack exchange,提问作者E. Apperloo

