ANTLR如何决定终端是否应该用空格分隔?

时间:2016-03-19 14:48:41

标签: swift antlr antlr4 lexical-analysis language-recognition

我在Swift for 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符号,而其他终端不在其中(例如&#34; as&#34; + Identifier)。

我是对的吗?如果我没错,问题就解决了。但可能有更复杂的逻辑。

现在,如果我有规则

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在&#39; str1&#39;和&#39; str2&#39;之间不是可选的)

所以有两个问题:

  1. 我是对的吗?
  2. 我错过了什么?
  3. 感谢。

1 个答案:

答案 0 :(得分:2)

这是Swift语法中的ANTLR WS规则:

WS : [ \n\r\t\u000B\u000C\u0000]+               -> channel(HIDDEN) ;

-> channel(HIDDEN)指令告诉词法分析器将这些标记放在一个单独的通道上,因此解析器根本不会看到它们。你不应该用WS规则乱丢你的语法 - 它会变得不可读。

ANTLR有两个步骤:你有词法分析器和解析器。词法分析器生成标记,解析器试图从这些标记和语法中找出具体的语法树。

ANTLR中的词法分析器的工作原理如下:

  • 只要符合任何词法规则,就使用字符。
  • 如果有多条规则与您消费的文本相匹配,请使用语法中出现的第一条规则
  • 语法中的文字字符串(如'as')被转换为隐式词法分析器规则(相当于TOKEN_AS: 'as';,但名称只是'as')。这些最终在词法分析器规则列表中 first

示例1

让我们看看lexing as?Int(最后有一个空格)时的后果:

  • a ...可能与Identifier'as'
  • 相匹配
  • as ...可能与Identifier'as'
  • 相匹配
  • as?与任何词法分析器规则不匹配

因此,您使用as,这将成为一个标记。现在你必须决定哪个是令牌类型。 Identifier'as'规则都匹配。 'as'是一个隐式词法分析器规则,被认为在语法中首先出现,因此它优先。词法分析器会使用as类型的文本'as'发出令牌。

下一个标记。

  • ? ...可能与QUESTION规则相匹配
  • ?I与任何规则都不匹配

因此,您从输入中使用?并发出带有文本QUESTION的{​​{1}}类型的标记。

下一个标记。

  • ? ...可能与I
  • 匹配
  • Identifier ...可能与In
  • 匹配
  • Identifier ...可能与Int
  • 匹配
  • Identifier(后跟空格)与任何内容都不匹配

因此,您从输入中使用Int并发出带有文本Int的{​​{1}}类型的标记。

下一个标记。

  • 您有一个空格,它与Identifier规则匹配。

您占用该空间,并在Int频道上发出WS令牌。解析器不会看到这个。

示例2

现在让我们看看WS是如何被标记化的。

  • HIDDEN ...可能与asInta
  • 相匹配
  • Identifier ...可能与'as'as
  • 相匹配
  • Identifier ...可能与'as'
  • 匹配
  • asI ...可能与Identifier
  • 匹配
  • asIn ...可能与Identifier
  • 匹配
  • asInt后跟空格与任何词法规则都不匹配。

因此,您从输入流中使用Identifier,并发出带有文字asInt的{​​{1}}令牌。

解析器

解析器阶段对其获得的令牌类型感兴趣。它关心它们包含哪些文本。忽略默认通道外的标记,这意味着以下输入:

  • asInt - 代币:Identifier asInt as?Int
  • 'as' - 代币:QUESTION Identifier as? Int 'as'
  • QUESTION - 代币:WS Identifier as ? Int 'as' WS

所有这些都会导致解析器看到以下令牌类型:QUESTION WS Identifier,因为'as'位于单独的频道上。