ANTLR文法中十进制数和字的单独定义
Separate definitions of decimal number and word in ANTLR grammar
我正在努力在 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 returns 一个值为 3 的数字。有没有办法确保 'd3' 或任何类似的字符串 returns 来自语法的错误消息?
我查看了“~”符号,但它似乎是 'everything except',而不是 'only'。
总而言之,我正在寻找一种方法来确保只能将一系列字母解析为 Word,并且不包含其他符号。目前,语法似乎忽略了任何其他不允许的字符。
类似于输入“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”处获得 'mismatched input'。
同样的规则会在“22f.4”中的 'f' 字符处给出 'mismatched input'。
这应该可以解决您提出的具体问题,并且希望足以满足您的需求。以下讨论是对您的评论的一些解读,并且可能对错误消息的方式假设太多。
您的评论(有点)暗示您更愿意看到类似“您的单词中有一个数字”或“您的数字中有一个字母”的错误消息
它有助于理解 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
令牌的内容,将其放入令牌流并继续前进。 (类似于在单词中查找数字)
这是标准的 lexing/parsing 行为。
您可以实现自己的 ErrorListener,其中 ANTLR 会将遇到的错误的详细信息交给您,您可以根据自己的需要对错误消息进行表述,但我认为您会发现它看起来很棘手你的目标是。您在错误处理程序中没有足够的上下文来知道之前发生了什么,等等,即使您知道,这也会很快变得非常复杂。
IF 你总是希望在 NUM
s 和 WORD
s 之间出现某种空白,你可以做一些事情,比如定义以下 Lexer 规则:
BAD_ATOM: (INTEGER|VALID_CHAR|'.')+;
(将其放在语法的最后,以便首先匹配有效流)
然后当解析器规则因 BAD_ATOM
规则出错时,您可以检查它并提供更具体的错误消息。
警告:这有点不正统,可能会限制您在构建语法时允许的内容。也就是说,在语法底部找到“包罗万象”的 Lexer 规则并不少见,有些人使用它来获得更好的错误消息 and/or 错误恢复。
我正在努力在 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 returns 一个值为 3 的数字。有没有办法确保 'd3' 或任何类似的字符串 returns 来自语法的错误消息?
我查看了“~”符号,但它似乎是 'everything except',而不是 'only'。
总而言之,我正在寻找一种方法来确保只能将一系列字母解析为 Word,并且不包含其他符号。目前,语法似乎忽略了任何其他不允许的字符。
类似于输入“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”处获得 'mismatched input'。
同样的规则会在“22f.4”中的 'f' 字符处给出 'mismatched input'。
这应该可以解决您提出的具体问题,并且希望足以满足您的需求。以下讨论是对您的评论的一些解读,并且可能对错误消息的方式假设太多。
您的评论(有点)暗示您更愿意看到类似“您的单词中有一个数字”或“您的数字中有一个字母”的错误消息
它有助于理解 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
令牌的内容,将其放入令牌流并继续前进。 (类似于在单词中查找数字)
这是标准的 lexing/parsing 行为。
您可以实现自己的 ErrorListener,其中 ANTLR 会将遇到的错误的详细信息交给您,您可以根据自己的需要对错误消息进行表述,但我认为您会发现它看起来很棘手你的目标是。您在错误处理程序中没有足够的上下文来知道之前发生了什么,等等,即使您知道,这也会很快变得非常复杂。
IF 你总是希望在 NUM
s 和 WORD
s 之间出现某种空白,你可以做一些事情,比如定义以下 Lexer 规则:
BAD_ATOM: (INTEGER|VALID_CHAR|'.')+;
(将其放在语法的最后,以便首先匹配有效流)
然后当解析器规则因 BAD_ATOM
规则出错时,您可以检查它并提供更具体的错误消息。
警告:这有点不正统,可能会限制您在构建语法时允许的内容。也就是说,在语法底部找到“包罗万象”的 Lexer 规则并不少见,有些人使用它来获得更好的错误消息 and/or 错误恢复。