"标识符"规则还使用ANTLR词法器语法中的关键字



在研究用于Java解析的Antlr 3.5语法时,注意到">IDENTIFIER"规则在Antlr Lexer语法中消耗的关键字很少。Lexer语法是

lexer grammar JavaLexer;
options {
//k=8;
language=Java;
filter=true;
//backtrack=true;
}
@lexer::header {
package java;
}
@lexer::members {
public ArrayList<String> keywordsList = new ArrayList<String>();
}
V_DECLARATION
:
( ((MODIFIERS)=>tok1=MODIFIERS WS+)? tok2=TYPE WS+ var=V_DECLARATOR WS* )
{...};
fragment
V_DECLARATOR
:
(
tok=IDENTIFIER WS* ( ',' | ';' | ASSIGN WS* V_VALUE )
)
{...};
fragment
V_VALUE
: (IDENTIFIER (DOT WS* IDENTIFIER WS* '(' | ',' | ';'))
;
MODIFIERS
:
(PUBLIC | PRIVATE | FINAL)+
;
PRIVATE
:    tok = 'private'
{ keywordsList.add($tok.getText());  }
;
PUBLIC
:    tok = 'public'
{ keywordsList.add($tok.getText()); }
;
DOT
:    '.'
{ keywordsList.add("."); }
;
THIS
:    tok = 'this'
{ keywordsList.add($tok.getText()); }
;
ASSIGN
:    '='
{ keywordsList.add("="); }
;    
IDENTIFIER:
tok =Identifier
{  
//System.out.println("Identifier: " + $tok.text);
}
;  
fragment
Identifier 
:   (Letter (Letter|JavaIDDigit)*);
fragment
Letter
:  'u0024' |
'u0041'..'u005a' |
'u005f' |
'u0061'..'u007a' |
'u00c0'..'u00d6' |
'u00d8'..'u00f6' |
'u00f8'..'u00ff' |
'u0100'..'u1fff' |
'u3040'..'u318f' |
'u3300'..'u337f' |
'u3400'..'u3d2d' |
'u4e00'..'u9fff' |
'uf900'..'ufaff'
;
fragment
JavaIDDigit
:  'u0030'..'u0039' |
'u0660'..'u0669' |
'u06f0'..'u06f9' |
'u0966'..'u096f' |
'u09e6'..'u09ef' |
'u0a66'..'u0a6f' |
'u0ae6'..'u0aef' |
'u0b66'..'u0b6f' |
'u0be7'..'u0bef' |
'u0c66'..'u0c6f' |
'u0ce6'..'u0cef' |
'u0d66'..'u0d6f' |
'u0e50'..'u0e59' |
'u0ed0'..'u0ed9' |
'u1040'..'u1049'
;
WS  :  (' '|'r'|'t'|'u000C'|'n') {$channel=HIDDEN; skip();}
;

当我试图解析行时:

public final int inch = this.getValue();

然后,规则"VAR_VALUE->IDENTIFIER"也会使用"this">关键字,这是不可取的,因为关键字也会收集到一个单独的列表中。

Antlr语法中是否有任何技巧/规定可以在不影响其他功能(如"IDENTIFIER")的情况下自行匹配关键字规则?

您的问题确实是由对lexer中的内容和解析器中的内容的误解引起的:

Lexer的工作是确定字符流代表哪些单词
  • 例如,thisTHIS0NUMBERthatIDENTIFIER
  • Parser的工作是确定lexer发出的单词序列是否符合给定的语言,也就是说,由这些单词组成的"句子"是否有意义
    • 例如,该声明由可能的修饰符、类型和标识符列表组成

  • 由于lexer的工作是确定输入中的单词,因此它处理输入并寻找最长有效匹配(在ANTLR中,如果两个或多个规则接受相同的输入,则源语法中最顶端的规则获胜)。不是针对任何"最具体的",而是针对最长的。

    示例:

    • 输入t
      • 可以是THISIDENTIFIER
    • 输入h
      • Still可以是THISIDENTIFIER
    • 输入a
      • 不能再是THIS,只能是IDENTIFIER
    • 输入t
      • IDENTIFIER
    • 输入.
      • 不再匹配IDENTIFIER,因此that将匹配为IDENTIFIER,最后一个输入.将匹配为下一个令牌的新开始

    还有另一个例子:

    • 输入this
      • 可以匹配为THISIDENTIFIER
    • 输入.
      • 不能再被任何东西匹配,因此this将被匹配为THIS(最上面的匹配规则),而不是IDENTIFIER,并且.将启动一个新的令牌

    现在到了重要的部分-只要从另一个lexer规则引用了lexer规则,它就被认为只是引用lexer规则的一个片段。这意味着匹配它不会发出新的令牌,而且它不会在片段匹配结束时触发多个匹配令牌之间的任何决策。由于this确实可以由IDENTIFIER规则匹配,因此整个声明符合V_DECLARATIONlexer规则-因此,除非有另一个lexer规则可以匹配至少相同长度的输入,并且在语法中早于该规则,否则该规则将适用。

    您没有提供任何引用THIS的规则,所以我们不知道这在您的语法中到底是如何表现的,但显而易见的原因是lexer可以比使用THIS规则的任何规则匹配更长的输入或更早的规则。

    最新更新