ANTLR语法中小数和单词的单独定义



我正在ANTLR4中定义一个语法,它分别包括单词和数字。

数字描述如下:

NUM
: INTEGER+ ('.' INTEGER+)?
;
fragment INTEGER
: ('0' .. '9')
;

并描述了单词:

WORD
: VALID_CHAR +
;
fragment VALID_CHAR
: ('a' .. 'z') | ('A' .. 'Z') 
;

下面的简化语法描述了单词或字母之间的加法(需要像这样递归定义(:

expression
:  left = expression '+' right = expression #addition
|  value = WORD #word
|  value = NUM #num
;

问题是,当我在解析器中输入"d3"时,我会得到一个返回的Word"d"实例。类似地,输入3f将返回数值为3的数字。有没有办法确保"d3"或任何类似的字符串从语法中返回错误消息?

我看过"~"符号,但它似乎是"除外的一切",而不是"唯一"。

总之,我正在寻找一种方法来确保只有一系列字母可以解析为一个单词,并且不包含其他符号。目前,语法似乎忽略了任何其他不允许使用的字符。

类似于输入"3+"时收到的消息:

simpleGrammar::compileUnit:1:2: mismatched input '<EOF>' expecting {WORD, NUM}

目前,出现以下情况:

d --> (d) (word) (correct)
22.3 --> (22.2) number (correct)
d3 --> d (word) (incorrect)

22f.4 --> 22 (number) (incorrect)

但理想情况下会发生以下情况:


d --> (d) (word) (correct)
22.3 --> (22.2) number (correct)
d3 --> (error)
22f.4 --> (error)

【修订以回应修订后的问题和意见】

ANTLR将尝试在输入流中匹配输入流中的内容,然后在达到可识别的最长输入后停止。这意味着,ANTLR对您的输入所能做的最好的事情就是识别一个单词('d'(,然后完全识别它,因为它可以将您输入的其余部分与您的任何规则(使用根expression规则(相匹配

您可以添加一个规则来告诉ANTLR它需要消耗到整个输入中,并使用一个顶级规则,比如:

root: expression EOF;

使用此规则后,您将在"d3"中的"3"处获得"不匹配的输入"。

同样的规则会在"22f.4"中的"f"字符处给出"不匹配的输入"。


这应该能解决您提出的特定问题,并且有望满足您的需求。下面的讨论是对你的评论进行一点解读,可能会以错误消息的方式对你想要的内容进行过多假设。

你的评论(有点(暗示你更喜欢看到类似";你的单词中有一个数字";,或";你的号码里有一个字母";

它有助于理解ANTLR处理输入的管道。首先,它使用Lexer规则(以大写字母开头的规则(来处理您的输入流,以创建令牌流。

您的"d3"输入使用当前语法生成一个由2个标记组成的流;

WORD ('d')
NUM ('3')

这个令牌流就是您的解析器规则(即expression(中要匹配的内容
流中的'22f.4'结果:

NUM ('22')
WORD ('f') 
(I would expect an error here as there is no Lexer rule that matches a stream of characters beginning with a '.')

当ANTLR在匹配您的NUM规则时看到数字(或'.'(以外的东西时,它会认为到目前为止匹配的是NUM令牌的内容,将其放入令牌流中并继续前进。(类似于在单词中查找数字(

这是标准的词法分析/解析行为。

你可以实现你自己的ErrorListener,ANTLR会把它遇到的错误的细节交给你,你可以根据自己的意愿写错误消息,但我认为你会发现很难达到目标。你在错误处理程序中没有足够的上下文来知道之前发生了什么,等等,即使你做到了,这会很快变得非常复杂。

如果您总是希望在NUMs和WORDs之间出现某种空白,您可以执行类似于定义以下Lexer规则的操作:

BAD_ATOM: (INTEGER|VALID_CHAR|'.')+;

(将其放在语法的最后,以便有效流将首先匹配(

然后,当解析器规则与BAD_ATOM规则发生错误时,您可以检查它并提供更具体的错误消息。

警告:这有点非正统,可能会在构建语法时对所允许的内容进行限制。也就是说;"一网打尽";语法底部的Lexer规则,有些人使用它来获得更好的错误消息和/或错误恢复。

最新更新