ANTLR 4:认可'和'但不是'或'没有空间

时间:2017-04-14 05:42:23

标签: antlr4

我在IntelliJ中使用ANTLR 4插件,我有最奇怪的错误。我将从相关的解析器/词法分析器规则开始:

// Take care of whitespace.
WS : [ \r\t\f\n]+ -> skip;

OTHER: . -> skip;

STRING
: '"' [A-z ]+ '"'
;

evaluate // starting rule.
: textbox? // could be an empty textbox.
;

textbox
: (row '\n')*
;

row
: ability
| ability_list

ability
: activated_ability
| triggered_ability
| static_ability

triggered_ability
: trigger_words ',' STRING 
;

trigger_words
: ('when'|'whenever'|'as') whenever_triggers|'at'
;

whenever_triggers
: triggerer (('or'|'and') triggerer)* // this line has the issue.
;

triggerer
: self

self: '~'

我将此文字传递给whenever ~ or ~,并在or上失败,说line 1:10 mismatched input ' or' expecting {'or', 'and'}。但是,如果我在whenever_triggers规则or字符串中添加空格(使其成为' or'|'and'),则可以正常使用。

最奇怪的是,如果我尝试whenever ~ and ~,即使规则在and字符串中没有空格也能正常工作。如果我使'and'|'or'成为词法分析规则,这不会改变。这很奇怪。我已经确认在运行“测试台”时会发生此错误。在Antlrworks 2中,它不仅仅是一个IntelliJ的东西。

发生错误时,这是​​解析树的图像:

enter image description here

1 个答案:

答案 0 :(得分:2)

好吧,你已经或多或少地找到了答案,所以我的答案将集中在解释为什么问题首先发生。

首先 - 对于每个人都绊倒这个问题 - 问题是他有另一个隐含的词法分析器规则定义为' or'(注意空白)。将其更改为'or'即可解决问题。

但为什么会出现问题呢? 为了理解你必须理解在你的一个解析器规则中编写'<something>'时ANTLR会做什么:编译语法时,它将为每个声明生成一个新的词法分析器规则。这些词法分析器规则将在语法中定义的词法分析器规则之前创建。词法分析器本身将匹配给定的输入到标记,并且它按照它们被声明的顺序一次处理每个词法分析器规则。因此,它总是以隐式令牌定义开始,然后转到最顶层的真实&#34; lexer规则。
问题是词法分析器对这个过程并不太聪明,这意味着一旦它将一些输入与当前的词法分析器规则相匹配,它将创建一个相应的标记并继续使用尾随输入。

因此,将跳过与之相匹配的词法分析器规则(但作为另一个令牌,因为它是不同的词法分析器规则)将被跳过,以便相应的输入可能没有预期的令牌类型,因为勒克斯规则已经过时了。

在您的示例中,自覆盖规则为' or'(令牌1)和'or'(令牌2)。这些隐式词法分析器规则之间的每一个都将导致不同的词法分析器规则,并且当第一个匹配器规则匹配时,我认为它是在第二个之前声明的。 现在看看你的输入:whenever ~ or ~词法分析器将开始解释它,它遇到的第一个规则是' or'(当然开始匹配)并且它将匹配输入,因为确实存在or之前的空格。因此它将匹配为令牌1 另一方面,解析器在此时期待令牌2,以便它会抱怨给定的输入(尽管它确实抱怨错误的令牌类型)。将输入更改为whenever ~or ~将导致正确的解释。

正是这就是为什么你不应该在你的语法中使用隐式标记定义的原因(除非它真的很小)。为每个输入创建一个新的词法分析器规则,并从最具体的规则开始。这意味着匹配特殊字符序列(例如关键字)的规则应该在诸如IDSTRING之类的常规词法规则之前声明。为了预先解释词法分析器在无法识别的输入上抛出错误,将匹配所有字符的规则必须在最后声明,因为它们会覆盖它们之后的每个词法分析器规则。