在处理用于 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”等其他功能?
最佳答案
你的问题确实是对什么属于词法分析器什么属于解析器的误解造成的:
- 词法分析器的工作是确定字符流代表哪些词
- 例如
this
是一个THIS
,0
是一个NUMBER
而that
是一个标识符
- 例如
- 解析器的工作是确定词法分析器发出的单词序列是否符合给定的语言,即由这些单词组成的“句子”是否有意义
- 例如该声明由可能的修饰符、类型和标识符列表组成
由于词法分析器的工作是确定输入中有哪些词,它会处理输入并寻找最长有效匹配(在 ANTLR 中,如果两个或多个规则接受相同的输入,则最上面的一个在源语法胜出)。不是针对任何“最具体的”,而是针对最长的。
例子:
- 输入
t
- 可以是
THIS
或IDENTIFIER
- 可以是
- 输入
h
- 仍然可以是
THIS
或IDENTIFIER
- 仍然可以是
- 输入
a
- 不能再是
THIS
,只能是IDENTIFIER
- 不能再是
- 输入
t
IDENTIFIER
当然
- 输入
。
- 不再匹配
IDENTIFIER
,因此that
将匹配为IDENTIFIER
并且最后输入的.
将是匹配为下一个 token 的新开始
- 不再匹配
还有一个例子:
- 输入
t
,h
,i
,s
- 可以一直匹配为
THIS
或IDENTIFIER
- 可以一直匹配为
- 输入
。
- 不能再被任何东西匹配,所以
this
将被匹配为THIS
(最高匹配规则)而不是IDENTIFIER
和.
将启动一个新 token
- 不能再被任何东西匹配,所以
现在到了重要的部分 - 只要一个词法分析器规则被另一个词法分析器规则引用,它就被认为只是引用词法分析器规则的一个片段。这意味着匹配它不会发出新的标记,也不会在片段匹配结束时触发多个匹配标记之间的任何决定。由于 this
确实可以通过 IDENTIFIER
规则匹配,整个声明符合 V_DECLARATION
词法分析器规则 - 所以除非有另一个 词法分析器 可以匹配至少相同长度输入的规则 and 在语法中早于此规则,此规则将适用。
您没有提供任何引用 THIS
的规则,因此我们不知道这在您的语法中究竟是如何发挥作用的,但显而易见的原因是词法分析器可以匹配更长的输入或匹配比之前更早的规则任何使用 THIS
规则的东西。
关于java - 'IDENTIFIER' 规则也使用 ANTLR Lexer 语法中的关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42221144/