在研究用于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的工作是确定字符流代表哪些单词- 例如,
this
是THIS
,0
是NUMBER
,that
是IDENTIFIER
- 例如,该声明由可能的修饰符、类型和标识符列表组成
由于lexer的工作是确定输入中的单词,因此它处理输入并寻找最长有效匹配(在ANTLR中,如果两个或多个规则接受相同的输入,则源语法中最顶端的规则获胜)。不是针对任何"最具体的",而是针对最长的。
示例:
- 输入
t
- 可以是
THIS
或IDENTIFIER
- 可以是
- 输入
h
- Still可以是
THIS
或IDENTIFIER
- Still可以是
- 输入
a
- 不能再是
THIS
,只能是IDENTIFIER
- 不能再是
- 输入
t
IDENTIFIER
- 输入
.
- 不再匹配
IDENTIFIER
,因此that
将匹配为IDENTIFIER
,最后一个输入.
将匹配为下一个令牌的新开始
- 不再匹配
还有另一个例子:
- 输入
t
、h
、i
、s
- 可以匹配为
THIS
或IDENTIFIER
- 可以匹配为
- 输入
.
- 不能再被任何东西匹配,因此
this
将被匹配为THIS
(最上面的匹配规则),而不是IDENTIFIER
,并且.
将启动一个新的令牌
- 不能再被任何东西匹配,因此
现在到了重要的部分-只要从另一个lexer规则引用了lexer规则,它就被认为只是引用lexer规则的一个片段。这意味着匹配它不会发出新的令牌,而且它不会在片段匹配结束时触发多个匹配令牌之间的任何决策。由于this
确实可以由IDENTIFIER
规则匹配,因此整个声明符合V_DECLARATION
lexer规则-因此,除非有另一个lexer规则可以匹配至少相同长度的输入,并且在语法中早于该规则,否则该规则将适用。
您没有提供任何引用THIS
的规则,所以我们不知道这在您的语法中到底是如何表现的,但显而易见的原因是lexer可以比使用THIS
规则的任何规则匹配更长的输入或更早的规则。