我们在分析源代码时有时只想获得其中一部分信息,例如:我们想知道一个java文件中的类的类名,类有哪些方法,方法的参数和返回值及其类型,属性及其类型和此类继承了什么类。但是我们必须写出java的全部文法才可以分析java文件,这很有难度也没有必要。ANTLR中加入了一个叫filter的设置项,filter为布尔类型默认为false。filter为true时词法分析器可以处于一种过滤状态,我们只需定义出我们关心部分的词法结构,其它部分全部被忽略掉。
filter=true模式中的词法规则是有优先顺序的,写在最前面的词法规则优先级最高之后从高到低依次排列。这样规定是因为有些规则会被其它规则所包含造成一些规则无法被识别出来。请看下面的示例:
lexer grammarTestFilter;
options {
filter=true;
language=CSharp;
}
A : aText=AA{Console.Out.WriteLine("A:"+$aText.Text);};
B : bText=BB{Console.Out.WriteLine("B:"+$bText.Text);};
AA : 'ab';
BB : 'a';
执行代码为:
ICharStream input= new ANTLRFileStream("t.txt");
FuzzyJava2Lexer lex = new FuzzyJava2Lexer(input);
ITokenStream tokens = new CommonTokenStream(lex);
tokens.ToString();
此文法中规则AA匹配字符串“ab”,规则BB匹配字符串“a”,规则AA包含规则BB。t.txt文件中的内容为“xxxxxxabxxxxx”。我们看一看是内容规则A匹配优先还是规则B优先匹配,这可以反应出优先关系。这个例中输出为:“A : ab”。这说明规则A优先匹配了。下面修改一下文法:
B :bText=BB{Console.Out.WriteLine("B: "+$bText.Text);};
A : aText=AA{Console.Out.WriteLine("A:"+$aText.Text);};
BB : 'a';
AA : 'ab';
相同的输入这次输出为:B: a。这说明规则B优先匹配了。但是如果将规则BB改为匹配字符“b”则输出为“A : ab”。
B :bText=BB{Console.Out.WriteLine("B: "+$bText.Text);};
A : aText=AA{Console.Out.WriteLine("A:"+$aText.Text);}; //输出为 A : ab
BB : 'b';
AA : 'ab';
下面给出一个从java文件中读取类,方法,属性信息的示例。
lexer grammarFuzzyJava2;
options {
filter=true;
}
IMPORT : 'import'WS name=QIDStar WS? ';'
{Console.Out.WriteLine("Import: "+$name.Text);};
PACKAGE : 'package'WS name=QID WS?';'
{Console.Out.WriteLine("Package: "+$name.Text);};
CLASS : 'class' WSname=ID WS? ('extends' WS QID WS?)?
('implements' WS QID WS? (',' WS? QID WS?)*)? '{'
{Console.Out.WriteLine("Class:"+$name.Text);};
METHOD : type1=TYPEWS name=ID WS?
'(' ( ARG WS?(',' WS? ARG WS?)* )? ')' WS?
('throws' WS QIDWS? (',' WS? QID WS?)*)? '{'
{Console.Out.WriteLine("Method: "+type1.Text+""+$name.Text + "()");};
FIELD :defvisi=DEFVISI WS TYPE WS name=ID '[]'? WS? (';'|'=')
{Console.Out.WriteLine("Field:"+$defvisi.Text+""+$name.Text+";");};
DEFVISI : 'public'| 'protected' | 'private';
USECOMMENT : '/**'(options {greedy=false;} : . )* '*/' ;
COMMENT : '/*'(options {greedy=false;} : . )* '*/'
//{Console.Out.WriteLine("found comment "+Text);};
SL_COMMENT : '//'(options {greedy=false;} : . )* '\r'?'\n' ;
WS : (''|'\t'|'\r'|'\n' )+ ;
STRING : '"'(options {greedy=false;}: ESC | .)* '"';
CHAR : '\''(options {greedy=false;}: ESC | .)* '\'';
fragment QID : ID ('.' ID)*;
fragment QIDStar : ID ('.' ID)* '.*'? ;
fragment TYPE : QID '[]'?;
fragment ARG : type=TYPE WS name=ID
{Console.Out.WriteLine("Param: "+$type.Text + ""+$name.Text + " , ");};
fragment ID : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;
fragment ESC : '\\' ('"'|'\''|'\\');
分析此java源代码。
/* [The "BSDlicence"] Copyright (c) 2005-2006 Terence Parr
All rights reserved.*/
package org.antlr.analysis;
import org.antlr.misc.IntSet;
import org.antlr.misc.OrderedHashSet;
import org.antlr.misc.Utils;
import org.antlr.tool.Grammar;
import java.util.*;
public class DFAState extends State {
public DFA dfa;
public DFAState(DFA dfa) {
this.dfa = dfa;
}
public intaddTransition(DFAState target, Label label) {
transitions.add(new Transition(label, target) );
return transitions.size()-1;
}
/** Print all NFAstates plus what alts they predict */
public int getLookaheadDepth() {
return k;
}
public void setLookaheadDepth(int k) {
this.k = k;
if ( k > dfa.max_k ) { // track max k for entire DFA
dfa.max_k = k;
}
}
}
如果将上面的java程序分析后会输出下面的结果。
Package: org.antlr.analysis
Import: org.antlr.misc.IntSet
Import: org.antlr.misc.OrderedHashSet
Import: org.antlr.misc.Utils
Import: org.antlr.tool.Grammar
Import: java.util.*
Class: DFAState
Field:public dfa;
Param: DFA dfa ,
Method: public DFAState()
Param: DFAState target ,
Param: Label label ,
Method: int addTransition()
Method: int getLookaheadDepth()
Param: int k ,
Method: void setLookaheadDepth()