理解 ANTLR/EBNF 括号
Understanding ANTLR/EBNF parentheses
ANTLR Reference Guide关于括号的说法如下:
另一方面,我有以下语法:
fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ;
fragment DIGIT : [0-9] ;
WORD : (LOWERCASE | UPPERCASE | DIGIT )+;
如果我 运行 字符串 "asd90",它将作为一个 WORD 进行匹配,如下所示:
>java org.antlr.v4.gui.TestRig Myg myg -tokens
asd90
[@0,0:4='asd90',<WORD>,1:0]
[@1,5:6='\r\n',<NEWLINE>,1:5]
[@2,7:6='<EOF>',<EOF>,2:0]
这让我感到困惑,因为我希望 "asd90" 不匹配,因为在我的语法中,LOWERCASE 和 DIGIT 是 2 个不同的子规则,所以我希望它不匹配,因为 "WORD"。
换句话说,这就像说 "intvoid" 可以作为 return 类型工作,而显然它不会。
您似乎忽略了循环运算符。词法分析器规则 WORD
可以匹配任何 LOWERCASE
、UPPERCASE
和 DIGIT
的 sequence,这意味着匹配是完全有效的asd90
通过使用该循环的 5 次运行(匹配小写规则 3 次,数字规则匹配两次)。
书上的例子没有循环,所以只能匹配一次,不是一个类型就是void
。
更多细节:片段规则有点私人规则(事实上,在旧的 ANLTR 版本中有关键字 private
,后来被重命名为 fragment
)。但是,它们在解析器中不可用,也不会出现在词法分析器规则列表中。您的 WORD
规则像这样存储在 ATN 中:
这表明 3 个片段规则的调用方式与任何其他规则一样。
但是还有另一个区别(这就是 Pavel 提到的)。在歧义解析方面,片段词法分析器规则的处理方式略有不同。
通常情况下是这样的:匹配最长输入的规则获胜。如果两个规则匹配相同的输入,那么在语法中首先出现的规则将获胜。这适用于解析器和词法分析器规则。但是,不适用于片段规则。即使与另一个(非片段)规则匹配相同输入的片段规则首先出现在语法中,非片段规则仍然获胜。
你可以通过稍微改变一下语法来证明这一点:
grammar Example;
start: WORD;
WS : [ \t\r\n]+ -> skip;
fragment LOWERCASE : [a-z]+ ;
fragment UPPERCASE : [A-Z]+ ;
fragment DIGIT : [0-9]+ ;
WORD: (LOWERCASE | UPPERCASE | DIGIT )+;
这会为您提供这些标记:
通过输入 abc
,您仍然会得到 WORD
作为匹配标记,即使 LOWERCASE
在语法中排在第一位。现在删除 fragment 关键字,您将看到 LOWERCASE
被匹配:
Parser error (1, 1): mismatched input 'abc' expecting WORD
Tokens:
[@0,0:2='abc',<2>,1:0]
[@1,4:3='<EOF>',<-1>,2:0]
Parse Tree:
start (
<Error>"abc"
)
这会导致语法错误,因为需要 WORD
。令牌列表变为:
但是,即使您删除了所有片段关键字,您仍然会为 abc90
这样的输入得到 WORD
,因为该规则比它之前的任何单个词法分析器规则匹配得更多。
ANTLR Reference Guide关于括号的说法如下:
另一方面,我有以下语法:
fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ;
fragment DIGIT : [0-9] ;
WORD : (LOWERCASE | UPPERCASE | DIGIT )+;
如果我 运行 字符串 "asd90",它将作为一个 WORD 进行匹配,如下所示:
>java org.antlr.v4.gui.TestRig Myg myg -tokens
asd90
[@0,0:4='asd90',<WORD>,1:0]
[@1,5:6='\r\n',<NEWLINE>,1:5]
[@2,7:6='<EOF>',<EOF>,2:0]
这让我感到困惑,因为我希望 "asd90" 不匹配,因为在我的语法中,LOWERCASE 和 DIGIT 是 2 个不同的子规则,所以我希望它不匹配,因为 "WORD"。
换句话说,这就像说 "intvoid" 可以作为 return 类型工作,而显然它不会。
您似乎忽略了循环运算符。词法分析器规则 WORD
可以匹配任何 LOWERCASE
、UPPERCASE
和 DIGIT
的 sequence,这意味着匹配是完全有效的asd90
通过使用该循环的 5 次运行(匹配小写规则 3 次,数字规则匹配两次)。
书上的例子没有循环,所以只能匹配一次,不是一个类型就是void
。
更多细节:片段规则有点私人规则(事实上,在旧的 ANLTR 版本中有关键字 private
,后来被重命名为 fragment
)。但是,它们在解析器中不可用,也不会出现在词法分析器规则列表中。您的 WORD
规则像这样存储在 ATN 中:
这表明 3 个片段规则的调用方式与任何其他规则一样。
但是还有另一个区别(这就是 Pavel 提到的)。在歧义解析方面,片段词法分析器规则的处理方式略有不同。
通常情况下是这样的:匹配最长输入的规则获胜。如果两个规则匹配相同的输入,那么在语法中首先出现的规则将获胜。这适用于解析器和词法分析器规则。但是,不适用于片段规则。即使与另一个(非片段)规则匹配相同输入的片段规则首先出现在语法中,非片段规则仍然获胜。
你可以通过稍微改变一下语法来证明这一点:
grammar Example;
start: WORD;
WS : [ \t\r\n]+ -> skip;
fragment LOWERCASE : [a-z]+ ;
fragment UPPERCASE : [A-Z]+ ;
fragment DIGIT : [0-9]+ ;
WORD: (LOWERCASE | UPPERCASE | DIGIT )+;
这会为您提供这些标记:
通过输入 abc
,您仍然会得到 WORD
作为匹配标记,即使 LOWERCASE
在语法中排在第一位。现在删除 fragment 关键字,您将看到 LOWERCASE
被匹配:
Parser error (1, 1): mismatched input 'abc' expecting WORD
Tokens:
[@0,0:2='abc',<2>,1:0]
[@1,4:3='<EOF>',<-1>,2:0]
Parse Tree:
start (
<Error>"abc"
)
这会导致语法错误,因为需要 WORD
。令牌列表变为:
但是,即使您删除了所有片段关键字,您仍然会为 abc90
这样的输入得到 WORD
,因为该规则比它之前的任何单个词法分析器规则匹配得更多。