ANTLR 如何决定终端是否应该用空格分隔?
How ANTLR decides whether terminals should be separated with whitespaces or not?
我正在 Swift 中为 Swift 编写词法分析器。我使用了ANTLR的语法,但我遇到了一个问题,我不明白ANTLR是如何决定终端是否应该用空格分隔的。
语法如下:https://github.com/antlr/grammars-v4/blob/master/swift/Swift.g4
假设我们在 Swift 中进行了转换。它还可以使用可选类型(Int?、String?)和非可选类型(Int、String)进行操作。以下是有效示例:"as? Int"、"as Int"、"as?Int"。无效示例:"asInt"(不是强制转换)。当语法规则中的终端可以用 0 个或多个 WS(空白)符号分隔时,我已经实现了逻辑。但是按照这个逻辑 "asInt" 匹配一个演员表,因为它包含 "as" 和一个类型 "Int" 并且有 0 个或多个 WS 符号。不过应该是无效的。
Swift 语法包含这些规则:
DOT : '.' ;
LCURLY : '{' ;
LPAREN : '(' ;
LBRACK : '[' ;
RCURLY : '}' ;
RPAREN : ')' ;
RBRACK : ']' ;
COMMA : ',' ;
COLON : ':' ;
SEMI : ';' ;
LT : '<' ;
GT : '>' ;
UNDERSCORE : '_' ;
BANG : '!' ;
QUESTION: '?' ;
AT : '@' ;
AND : '&' ;
SUB : '-' ;
EQUAL : '=' ;
OR : '|' ;
DIV : '/' ;
ADD : '+' ;
MUL : '*' ;
MOD : '%' ;
CARET : '^' ;
TILDE : '~' ;
似乎所有这些终端都可以用0 WS符号与其他终端分开,而其他终端则不能(例如"as" +标识符)。
我说得对吗?如果我是对的,问题就解决了。但是可能会有更复杂的逻辑。
现在如果我有规则
WS : [ \n\r\t\u000B\u000C\u0000]+
a : 'str1' b
b : 'str2' c
c : '+' d
d : 'str3'
我使用它们就像它们是这些规则一样:
WS : [ \n\r\t\u000B\u000C\u0000]+
a : WS? 'str1' WS? 'str2' WS? '+' WS? 'str3' WS?
我想他们应该是这样的(我不知道,这就是问题所在):
WS : [ \n\r\t\u000B\u000C\u0000]+
a: 'str1' WS 'str2' WS? '+' WS? 'str3'
(注意 WS 在 'str1' 和 'str2' 之间不是可选的)
所以有 2 个问题:
- 我说得对吗?
- 我错过了什么?
谢谢。
这是您 Swift 语法中的 ANTLR WS
规则:
WS : [ \n\r\t\u000B\u000C\u0000]+ -> channel(HIDDEN) ;
-> channel(HIDDEN)
指令告诉词法分析器将这些标记放在单独的通道上,因此解析器根本看不到它们。你不应该用 WS
规则乱扔你的语法 - 它会变得不可读。
ANTLR 分两步工作:你有词法分析器和解析器。词法分析器生成标记,解析器尝试从这些标记和语法中找出具体的语法树。
ANTLR 中的词法分析器是这样工作的:
- 只要符合任何词法分析器规则,就使用字符。
- 如果有多个规则与您使用的文本相匹配,请使用出现在语法中的第一个规则
- 语法中的文字字符串(如
'as'
)被转换为隐式词法分析器规则(等同于 TOKEN_AS: 'as';
除了名称只是 'as'
)。这些最终在词法分析器规则列表中第一。
示例 1
让我们看看这些在对 as?Int
进行词法分析时的结果(最后是 space):
a
... 可能匹配 Identifier
和 'as'
as
... 可能匹配 Identifier
和 'as'
as?
不匹配任何词法分析器规则
因此,您消费as
,这将成为代币。现在您必须决定哪种令牌类型。 Identifier
和 'as'
规则都匹配。 'as'
是一个隐含的词法分析器规则,被认为首先出现在语法中,因此它具有优先权。词法分析器发出一个标记,其中文本 as
类型为 'as'
.
下一个令牌。
?
... 可能匹配 QUESTION
规则
?I
不符合任何规则
因此,您从输入中使用 ?
并发出类型为 QUESTION
且文本为 ?
.
的标记
下一个令牌。
I
...可能匹配 Identifier
In
...可能匹配 Identifier
Int
...可能匹配 Identifier
Int
(后跟一个space)不匹配任何东西
因此,您从输入中使用 Int
并发出类型为 Identifier
且文本为 Int
.
的标记
下一个令牌。
- 那里有一个 space,它符合
WS
规则。
您消费 space,并在 HIDDEN
频道上发出 WS
令牌。解析器不会看到这个。
示例 2
现在让我们看看 asInt
是如何标记化的。
a
... 可能匹配 Identifier
和 'as'
as
... 可能匹配 Identifier
和 'as'
asI
...可能匹配 Identifier
asIn
...可能匹配 Identifier
asInt
...可能匹配 Identifier
asInt
后跟 space 不匹配任何词法分析器规则。
因此,您从输入流中使用 asInt
,并发出带有文本 asInt
.
的 Identifier
标记
解析器
解析器阶段仅对其获取的标记类型感兴趣。它 不 关心它们包含的文本。默认通道之外的令牌将被忽略,这意味着以下输入:
as?Int
- 令牌:'as'
QUESTION
Identifier
as? Int
- 代币:'as'
QUESTION
WS
Identifier
as ? Int
- 代币:'as'
WS
QUESTION
WS
Identifier
所有这些都会导致解析器看到以下标记类型:'as'
QUESTION
Identifier
,因为 WS
在单独的通道上。
我正在 Swift 中为 Swift 编写词法分析器。我使用了ANTLR的语法,但我遇到了一个问题,我不明白ANTLR是如何决定终端是否应该用空格分隔的。
语法如下:https://github.com/antlr/grammars-v4/blob/master/swift/Swift.g4
假设我们在 Swift 中进行了转换。它还可以使用可选类型(Int?、String?)和非可选类型(Int、String)进行操作。以下是有效示例:"as? Int"、"as Int"、"as?Int"。无效示例:"asInt"(不是强制转换)。当语法规则中的终端可以用 0 个或多个 WS(空白)符号分隔时,我已经实现了逻辑。但是按照这个逻辑 "asInt" 匹配一个演员表,因为它包含 "as" 和一个类型 "Int" 并且有 0 个或多个 WS 符号。不过应该是无效的。
Swift 语法包含这些规则:
DOT : '.' ;
LCURLY : '{' ;
LPAREN : '(' ;
LBRACK : '[' ;
RCURLY : '}' ;
RPAREN : ')' ;
RBRACK : ']' ;
COMMA : ',' ;
COLON : ':' ;
SEMI : ';' ;
LT : '<' ;
GT : '>' ;
UNDERSCORE : '_' ;
BANG : '!' ;
QUESTION: '?' ;
AT : '@' ;
AND : '&' ;
SUB : '-' ;
EQUAL : '=' ;
OR : '|' ;
DIV : '/' ;
ADD : '+' ;
MUL : '*' ;
MOD : '%' ;
CARET : '^' ;
TILDE : '~' ;
似乎所有这些终端都可以用0 WS符号与其他终端分开,而其他终端则不能(例如"as" +标识符)。
我说得对吗?如果我是对的,问题就解决了。但是可能会有更复杂的逻辑。
现在如果我有规则
WS : [ \n\r\t\u000B\u000C\u0000]+
a : 'str1' b
b : 'str2' c
c : '+' d
d : 'str3'
我使用它们就像它们是这些规则一样:
WS : [ \n\r\t\u000B\u000C\u0000]+
a : WS? 'str1' WS? 'str2' WS? '+' WS? 'str3' WS?
我想他们应该是这样的(我不知道,这就是问题所在):
WS : [ \n\r\t\u000B\u000C\u0000]+
a: 'str1' WS 'str2' WS? '+' WS? 'str3'
(注意 WS 在 'str1' 和 'str2' 之间不是可选的)
所以有 2 个问题:
- 我说得对吗?
- 我错过了什么?
谢谢。
这是您 Swift 语法中的 ANTLR WS
规则:
WS : [ \n\r\t\u000B\u000C\u0000]+ -> channel(HIDDEN) ;
-> channel(HIDDEN)
指令告诉词法分析器将这些标记放在单独的通道上,因此解析器根本看不到它们。你不应该用 WS
规则乱扔你的语法 - 它会变得不可读。
ANTLR 分两步工作:你有词法分析器和解析器。词法分析器生成标记,解析器尝试从这些标记和语法中找出具体的语法树。
ANTLR 中的词法分析器是这样工作的:
- 只要符合任何词法分析器规则,就使用字符。
- 如果有多个规则与您使用的文本相匹配,请使用出现在语法中的第一个规则
- 语法中的文字字符串(如
'as'
)被转换为隐式词法分析器规则(等同于TOKEN_AS: 'as';
除了名称只是'as'
)。这些最终在词法分析器规则列表中第一。
示例 1
让我们看看这些在对 as?Int
进行词法分析时的结果(最后是 space):
a
... 可能匹配Identifier
和'as'
as
... 可能匹配Identifier
和'as'
as?
不匹配任何词法分析器规则
因此,您消费as
,这将成为代币。现在您必须决定哪种令牌类型。 Identifier
和 'as'
规则都匹配。 'as'
是一个隐含的词法分析器规则,被认为首先出现在语法中,因此它具有优先权。词法分析器发出一个标记,其中文本 as
类型为 'as'
.
下一个令牌。
?
... 可能匹配QUESTION
规则?I
不符合任何规则
因此,您从输入中使用 ?
并发出类型为 QUESTION
且文本为 ?
.
下一个令牌。
I
...可能匹配Identifier
In
...可能匹配Identifier
Int
...可能匹配Identifier
Int
(后跟一个space)不匹配任何东西
因此,您从输入中使用 Int
并发出类型为 Identifier
且文本为 Int
.
下一个令牌。
- 那里有一个 space,它符合
WS
规则。
您消费 space,并在 HIDDEN
频道上发出 WS
令牌。解析器不会看到这个。
示例 2
现在让我们看看 asInt
是如何标记化的。
a
... 可能匹配Identifier
和'as'
as
... 可能匹配Identifier
和'as'
asI
...可能匹配Identifier
asIn
...可能匹配Identifier
asInt
...可能匹配Identifier
asInt
后跟 space 不匹配任何词法分析器规则。
因此,您从输入流中使用 asInt
,并发出带有文本 asInt
.
Identifier
标记
解析器
解析器阶段仅对其获取的标记类型感兴趣。它 不 关心它们包含的文本。默认通道之外的令牌将被忽略,这意味着以下输入:
as?Int
- 令牌:'as'
QUESTION
Identifier
as? Int
- 代币:'as'
QUESTION
WS
Identifier
as ? Int
- 代币:'as'
WS
QUESTION
WS
Identifier
所有这些都会导致解析器看到以下标记类型:'as'
QUESTION
Identifier
,因为 WS
在单独的通道上。