当语法谓词的数量很大时,将Antlr3语法谓词转换为Antlr4中的等效语法

时间:2017-11-10 18:01:06

标签: antlr4 antlr3

我有Antlr3解析器规则,如下所示:

ruleA:
   (TOKEN_1) => TOKEN_1 ruleToken1
   | (TOKEN_2) => TOKEN_2 ruleToken2
   ....
   ....
   <many more such rules>
   | genericRuleA
;

暂时假设适当地定义了令牌和规则。此外,genericRuleA的定义方式使其对任何落在其上方的规则元素的内容表现得像“全能”。

因此,例如,genericRuleA上面的子规则对应于命名函数,ruleToken1ruleToken2捕获这些命名函数的调用方式。 genericRuleA将捕获任何其他未命名的函数(例如用户定义的函数)。

这个语法的净效果是,如果ruleA找到TOKEN_1,它会占用ruleToken1路径并在输入的其余部分不满足{{1}时报告错误}

在Antlr4中,我在取出语法谓词后最终得到以下解析器规则:

ruleToken1

这很有效,除非ruleA: TOKEN_1 ruleToken1 | TOKEN_2 ruleToken2 .... .... <many more such rules> | genericRuleA ; 的其余部分失败,解析器会自动选择ruleToken1作为首选路径。所以现在,我有能够“重载”命名函数的副作用。这在某些情况下可能很有用,但在我的情况下,要求是表示不允许这种重载,即命名函数必须符合genericRuleA中列出的特定结构,并在违反该结构时报告错误。正在编写此语法的系统不支持重载函数。

ruleToken1必须满足除命名函数之外的任何其他内容。

我的第一个问题:是否有实现此转换的标准方式?

我看到的一种方法是创建一个与命名函数(TOKEN_1,TOKEN_2等)对应的标记列表;构造一个genericRuleA函数,如果输入标记在此列表中具有成员资格,则返回@parser::member。因此,假设true已正确定义,规则将类似于:

isNamedFunction()

当你只有几个命名函数时,这可能会有效,但如果你有数百个(例如在TSQL中认为是内置函数),那么这个列表构建起来会相当麻烦。更不用说随着新命名函数的出现,我将不得不继续更新该列表。

所以我的后续问题是:假设上面概述的语义谓词方法是正确的方法,有没有办法以编程方式组装列表?

一种似乎有希望的方法是从ruleA: TOKEN_1 ruleToken1 | TOKEN_2 ruleToken2 | {!isNamedFunction()}? genericRuleA ; 构建它。在这里,我将稍微重新构造规则,以便所有命名函数都属于一个规则(假设我们称之为getExpectedTokens()),如下所示:

namedRuleA

然后从ruleA的ruleA: namedRuleA | genericRuleA ; namedRuleA: TOKEN_1 ruleToken1 | TOKEN_2 ruleToken2 .... .... <many more such rules> ; [ATNState]开始,我会沿着过渡走,直到我到达recognizer.getATN().states.get(recognizer.getState())的{​​{1}},然后使用namedRuleA来获得与ATNStategetATN().getExpectedTokens(<namedRuleA's ATNState>, null)等令牌类型相对应的IntervalSet

这似乎产生了正确的令牌集,并且似乎有意义,因为(我的理解是)TOKEN_1及其转换是已知的并且在转换时间固定,即在.g4 - &gt;期间。 .java转换(或任何你的目标语言)。

我知道有时候转换是通过TOKEN_2次调用动态确定的,例如当有语义谓词涉及时,我们假设我可以确保在ATNState中不会使用语义谓词

我只是想知道其他人是否尝试过这种方法,如果可能存在我完全失踪的问题。

0 个答案:

没有答案