前言
^(root ^(child1 leaf1 leaf2) child2)
forStat : 'for' '(' decl? ';' expr? ';' expr? ')' slit;
输入for(int i=0;;i++){...}的部分AST:
^(FOR ^(VARDEF int i 0) EXPR ^(++ i))
Tree getChild(int i); int getChildCount(); void addTree(Tree t); boolean isNil();
TreeAdaptor的实例见代码//TreeAdaptor编程示例
rule : <<alt1>> -> <<build-this-form-alt1>> | <<alt2>> -> <<build-this-form-alt2>> ... | <<altn>> -> <<build-this-form-altn>> ;
重写规则是描述如何生成树的文法,Parr列出了重写机制常用的场景
sample: stat : 'break' ';' -> 'break' ; expr : '(' expr ')' -> expr | INT -> INT ;
(2)输入元素重排序
decl : 'var' ID ':' type -> type ID;
(3)将某输入元素作为其他元素的根节点
stat : 'return' expr ';' -> ^('return' expr); decl : 'var' ID ':' type -> ^('var' type ID);//与默认机制一致
(4)添加虚构节点
decl :type ID ';' -> ^(VARDEF type ID); forLoopConditional : expression -> ^(EXPR expression) | -> EXPR //需添加此虚构节点,否则会造成信息丢失,压缩的IR不能过分压缩! ;
(5)收集输入元素一起提交
list : ID (',' ID)* -> ID+ ; formalArgs : formalArg (',' formalArg)* -> formalArg+ | ; decl : 'int' ID (',' ID)* -> ^('int' ID+); compilationUnit : packageDef? importDef* typeDef+ -> ^(UNIT packageDef? importDef* typeDef+) ;
(6)复制节点和树
dup : INT -> INT INT; decl : 'int' ID (',' ID)* -> ^('int' ID)+ ; decl : type ID (',' ID)* -> ^(type ID)+ ; decl : modifier? type ID (',' ID)* -> ^(type modifier? ID)+ ;
(7)运行时选择树结构:语义谓词
variableDefinition : modifiers types ID ('=' expression)? ';' -> {inMethod}? ^(VARIABLE ID modifier* expression?) -> ^(FIELD ID modifier* expression?) ; a[int which] : ID INT -> {which==1}? ID -> {which==2}? INT -> ;
forStat : 'for' '(' decl? ';' cond=expr? ';' iter=expr? ')' slist -> ^('for' decl? ^(CONDITION $cond)? ^(ITERATE $iter)?) ;
(9)用任意动作创建节点
a : INT -> {new CommonTree(new CommonToken(FLOAT, $INT.text+".0"));} ; typeDefinition : modifiers! classDefinition[$modifiers.tree] | modifiers! iterfaceDefinition[$modifiers.tree] ; classDefinition[CommonTree mod] ://parser规则的参数是CommonTree 'class' ID ('extend' sup=typename)? ('implements' i+=typename (',' i+=typename)*)? '{' (variableDefinition|methodDefinition|constructorDefiniton)* '}' -> ^('class' ID {$mod} ^('extends $sup)? ^('implements' $i+)?//这里$i+是汇总列表,对应多个子节点 variableDefinition* methodDefinition* constructorDefiniton*) ;
(10)重写规则元素的基数
intValue : expr? -> ^(EXPR expr)? ;
(11)子规则中的重写规则
ifStat : 'if' '(' equalityExpression ')' s1=statement ('else' s2=statement -> ^('if' ^(EXPR equalityExpression) $s1 $s2) | -> ^('if' ^(EXPR equalityExpression) $s1) ) ; decl : type (ID '=' INT -> ^(DECL_WITH_INT type ID INT) |ID -> ^(DECL type ID) ) ;
(12)在重写规则中引用之前规则生成的AST
expr : (INT -> INT ('+' i=INT -> ^('+' $expr $i))* ;
其部分AST: ^('+' $expr 3)
compoundStatement : lp='{' statement* '}' -> ^(SLIST[$lp] statement*) ;
(14)结合重写规则与自动默认的AST构造
primary : INT | FLOAT | '(' expression ')' -> expression ;
tree grammar options { tokenVocab=; ASTLabelType=CommonTree; }
char c; int x; int foo(int y, char d){ int i; for(i=0; i!=3; i=i+1){ x=3; y=5; } }
(VAR char c) (VAR int x) (FUNC int foo (ARG int y) (ARG char d) (SLIT (VAR int i) (for (= i 0) (!= i 3) (= i (+ i 1)) (SLIT (= x 3) (= y 5)))))
java -classpath antlr-3.5-complete.jar org.antlr.Tool CMinus.g CMiusWalker.g
(b.3)生成的tree解析器验证代码见代码//tree解析器结果验证程序
dot ast.dot -Tpng -o ast.png
生成结果见下图
public class TreeAdaptorDemo { public static void main(String[] args) { // 定义虚构Token类型 int LIST = 1; int ID = 2; TreeAdaptor adaptor = new CommonTreeAdaptor(); // CommonTree root = (CommonTree) adaptor.nil(); CommonTree root = (CommonTree) adaptor.create(LIST, "LIST"); root.addChild((CommonTree) adaptor.create(ID, "x")); root.addChild((CommonTree) adaptor.create(ID, "y")); root.addChild((CommonTree) adaptor.create(ID, "z")); System.out.println(root.toStringTree()); } }
//combined grammar: CMinus
grammar CMinus; options {output=AST;} tokens { //用于生成AST中虚构节点的Token VAR;FUNC;ARG;SLIST; } program : declaration+ ; declaration : variable | function ; variable: type ID ';' -> ^(VAR type ID); type : 'int'|'char'; function: type ID '(' (formalParameter (',' formalParameter)*)? ')' block -> ^(FUNC type ID formalParameter* block) ; formalParameter : type ID -> ^(ARG type ID) ; block : lb='{' variable* stat* '}' -> ^(SLIST[$lb, "SLIT"] variable* stat*) ; stat : forStat | expr ';'! | assignStat ';'! | ';'! ; forStat : 'for' '(' init=assignStat ';' expr ';' inc=assignStat ')' block -> ^('for' $init expr $inc block) ; assignStat : ID '=' expr -> ^('=' ID expr) ; expr : condExpr; condExpr: aexpr (('=='^|'!='^) aexpr)?; aexpr : mexpr ('+'^ mexpr)*; mexpr : atom ('*'^ atom)*; atom : ID | INT | '('! expr ')'! ; ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ; INT : '0'..'9'+ ; WS : ( ' '| '\t'| '\r'| '\n') {$channel=HIDDEN;} ;
public class ParserTest { public static void main(String[] args) throws Exception { InputStream is = new FileInputStream(new File("D:/workspace/maven/antlrv3/language/CMinus.test")); // create a CharStream that reads from standard input // ANTLRInputStream input = new ANTLRInputStream(System.in); ANTLRInputStream input = new ANTLRInputStream(is); // create a lexer that feeds off of input CharStream CMinusLexer lexer = new CMinusLexer(input); // create a buffer of tokens pulled from the lexer CommonTokenStream tokens = new CommonTokenStream(lexer); // create a parser that feeds off the tokens buffer CMinusParser parser = new CMinusParser(tokens); // begin parsing at rule program to get its return tree CMinusParser.program_return program = parser.program(); CommonTree tree = (CommonTree) program.getTree(); System.out.println(tree.toStringTree()); System.out.println(tree.toString());// 仅显示root } }
//tree grammar: CMiusWalker
tree grammar CMiusWalker; options {tokenVocab=CMinus; ASTLabelType=CommonTree;} program : declaration+ ; declaration : variable | function ; variable: ^(VAR type ID) {System.out.println("define "+$type.text +" "+ $ID.text);} ; type : 'int'|'char'; function: ^(FUNC type ID formalParameter* block) {System.out.println("define " +$type.text + " " +$ID.text + "()");} ; formalParameter : ^(ARG type ID) ; block : ^(SLIST variable* stat*) ; stat : forStat | expr | assignStat ; forStat : ^('for' assignStat expr assignStat block) ; assignStat : ^('=' ID expr) ; expr : ^('==' expr expr) | ^('!=' expr expr) | ^('+' expr expr) | ^('*' expr expr) | ID | INT ;
public class FinalTest { public static void main(String[] args) throws Exception { InputStream is = new FileInputStream(new File("D:/workspace/maven/antlrv3/language/CMinus.test")); // create a CharStream that reads from standard input // ANTLRInputStream input = new ANTLRInputStream(System.in); ANTLRInputStream input = new ANTLRInputStream(is); // create a lexer that feeds off of input CharStream CMinusLexer lexer = new CMinusLexer(input); // create a buffer of tokens pulled from the lexer CommonTokenStream tokens = new CommonTokenStream(lexer); // create a parser that feeds off the tokens buffer CMinusParser parser = new CMinusParser(tokens); // begin parsing at rule program to get its return tree CMinusParser.program_return program = parser.program(); CommonTree tree = (CommonTree) program.getTree(); System.out.println(tree.toStringTree()); // DOT tree generate DOTTreeGenerator dotTreeGenerator = new DOTTreeGenerator(); StringTemplate st = dotTreeGenerator.toDOT(tree); System.out.println(st); CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree); nodes.setTokenStream(tokens); CMiusWalker walker = new CMiusWalker(nodes); walker.program(); }