理解ANTLR/EBNF括号

理解ANTLR/EBNF括号,antlr,antlr4,parentheses,bnf,ebnf,Antlr,Antlr4,Parentheses,Bnf,Ebnf,关于括号的说明如下: 另一方面,我有以下语法: fragment LOWERCASE : [a-z] ; fragment UPPERCASE : [A-Z] ; fragment DIGIT : [0-9] ; WORD : (LOWERCASE | UPPERCASE | DIGIT )+; 如果我运行字符串“asd90”,它将匹配为一个单词,如下所示: >java org.antlr.v4.gui.TestRig Myg myg -tokens

关于括号的说明如下:

另一方面,我有以下语法:

fragment LOWERCASE  : [a-z] ;
fragment UPPERCASE  : [A-Z] ;
fragment DIGIT : [0-9] ;

WORD                : (LOWERCASE | UPPERCASE | DIGIT )+;
如果我运行字符串“asd90”,它将匹配为一个单词,如下所示:

>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]
>java org.antlr.v4.gui.TestRig Myg Myg-tokens
asd90
[@0,0:4='asd90',1:0]
[@1,5:6='\r\n',1:5]
[@2,7:6='',,2:0]
这使我感到困惑,因为我希望“asd90”不匹配,因为在我的语法中,小写和数字是两个不同的子规则,所以我希望它不匹配为“WORD”


换句话说,这就像说“intvoid”将作为一个返回类型工作,而它显然不会这样做。

您似乎没有考虑到循环运算符。lexer规则
WORD
可以匹配任何
小写
大写
数字
序列,这意味着使用该循环的5次运行来匹配
asd90
(匹配小写规则3次,匹配数字规则两次)是完全有效的

书中的示例没有循环,因此只能匹配一次,类型或
void

还有一些细节:片段规则有点像私有规则(事实上,在旧的ANLTR版本中有关键字
private
,后来被重命名为
fragment
)。但是,它们在解析器中不可用,也不会出现在lexer规则列表中。您的
WORD
规则存储在ATN中,如下所示:

这表明3个片段规则的调用与其他任何规则一样

但还有另一个区别(这就是帕维尔提到的)。当涉及到歧义解决时,片段lexer规则的处理略有不同

通常分辨率是这样的:匹配最长输入的规则获胜。如果两个规则匹配相同的输入,则语法中第一个规则获胜。这对于解析器和词法分析器规则都适用。但是,不适用于片段规则。即使与另一个(非片段)规则匹配的片段规则首先出现在语法中,非片段规则仍然获胜

你可以通过稍微改变一下语法来证明:

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
作为匹配的标记,即使
小写字母在语法中排在第一位。现在删除fragment关键字,您将看到
小写
匹配:

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"
)
分析器错误(1,1):输入不匹配的“abc”应为单词
代币:
[@0,0:2='abc',1:0]
[@1,4:3='',,2:0]
解析树:
开始(
“abc”
)
这会导致语法错误,因为需要一个
WORD
。此时,令牌列表变为:


然而,即使您删除了所有的片段关键字,您仍然会得到像
abc90
这样的输入的
WORD
,因为该规则比它之前的任何虚拟词法规则都更匹配。

您似乎忽略了循环操作符。lexer规则
WORD
可以匹配任何
小写
大写
数字
序列,这意味着使用该循环的5次运行来匹配
asd90
(匹配小写规则3次,匹配数字规则两次)是完全有效的

书中的示例没有循环,因此只能匹配一次,类型或
void

还有一些细节:片段规则有点像私有规则(事实上,在旧的ANLTR版本中有关键字
private
,后来被重命名为
fragment
)。但是,它们在解析器中不可用,也不会出现在lexer规则列表中。您的
WORD
规则存储在ATN中,如下所示:

这表明3个片段规则的调用与其他任何规则一样

但还有另一个区别(这就是帕维尔提到的)。当涉及到歧义解决时,片段lexer规则的处理略有不同

通常分辨率是这样的:匹配最长输入的规则获胜。如果两个规则匹配相同的输入,则语法中第一个规则获胜。这对于解析器和词法分析器规则都适用。但是,不适用于片段规则。即使与另一个(非片段)规则匹配的片段规则首先出现在语法中,非片段规则仍然获胜

你可以通过稍微改变一下语法来证明:

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
作为匹配的标记,即使
小写字母在语法中排在第一位。现在删除fragment关键字,您将看到
小写
匹配:

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"
)
分析器错误(1,1):输入不匹配的“abc”应为单词
代币:
[@0,0:2='abc',1:0]
[@1,4:3='',,2:0]
解析树:
开始(
“abc”
)
这会导致语法错误,因为需要一个
WORD
。此时,令牌列表变为:


然而,即使你删除了所有的片段关键字,你仍然会得到输入的
WORD
,比如
abc90
,因为该规则比它之前的任何虚拟词法规则都更匹配。

小写
数字
不是两个不同的子规则,它们是一个特定规则的片段(更准确地说是标记)
WORD
。简单来说,这听起来像:“
WORD
可以包含小写字符,也可以包含大写字符或数字”。这就是“asd90”的意义所在。至于
intvoid
,它与
intvoid
不同
LOWERCASE
DIGIT
不是两个不同的子规则,它们是一个特定规则的片段(更准确地说是标记)
WORD
。简单来说,这听起来像:“
WORD
可以包含小写字符,也可以包含大写字符或数字”。这就是“asd90”的意义所在。至于