java抽象语法树_抽象语法树(AST)
抽象语法树(AST)
最近在做⼀个类JAVA语⾔的编译器,整个开发过程,⽤抽象语法树(Abstract SyntaxTree,AST)作为程序的⼀种中间表⽰,所以⾸先就要学会建⽴相对应源代码的AST和访问AST。Eclip AST是Eclip JDT的⼀个重要组成部分,定义在包dom中,⽤来表⽰JAVA语⾔中的所有语法结构。
Eclip AST的总体结构
1、dom.AST(AST节点类)
柠檬水怎么制作Eclip AST的⼯⼚类,⽤于创建表⽰各种语法结构的节点。
2、dom.ASTNode及其派⽣类(AST类)
⽤于表⽰JAVA语⾔中的所有语法结构,在实际使⽤中常作为AST上的节点出现。
3、dom.ASTVisitor(ASTVisitor类)
Eclip AST的访问者类,定义了统⼀的访问AST中各个节点的⽅法。
详细介绍:
⼀、AST节点类
整体结构包括CompilationUnit类(编译单元)、TypeDeclaration类(类型声明)、MethodDeclaration类(⽅法声明);
语句包括Block类(语句块)、ExpressionStatement类(表达式)、IfStatement(if语句)、WhileStatement类(while语句)、EmptyStatement类(空语句)、BreakStatement类和ContinueStatement类;
表达式包括MethodInvocation类(⽅法调⽤)、Assignment类(赋值表达式)(“=”、“+=”、“-=”、“*=”、“/=”)、InfixExpression类(中缀表达式)(“+”、“-”、“*”、“/”、“%”、“==”、“!=”、“=”、“&&”、“||”。)、PrefixExpression类(前缀表达式)(“+”PLUS“-”MINUS“!”NOT)、ParenthesizedExpression类(带括号的表达式)、NumberLiteral类(整数)、Name类(simple)、MethodInvocation类(⽅法调⽤)。
dota2新手
⼆、AST类
关键是创建编译单元节点,创建类AST的实例。
AST ast = wAST(JLS3);
三、ASTVisitor类
它提供与节点类有关的visit()⽅法和endVisit()法,与节点类⽆关的preVisit()⽅法和postVisit()⽅法。
booleanvisit( T node):这类⽅法如果返回true,则接着访问⼦节点。如果返回fal,则不再访问⼦节点。
void endVisit(T node):这类⽅法在节点node的⼦节点已经被访问或者是在visit(node)返回fal后调⽤。
void preVisit():这类⽅法在visit(node)之前被调⽤。
void postVisit():这类⽅法在endVisit(node)之后被调⽤。
在做简单解释器过程中,分析句⼦时我主要⽤到了上⾯的visit()和endVisit()⽅法,其中visit()⽅法是⽐较好理解的,主要是endVisit()⽅法在没有特定语法分析树的情况下分析是⽐较抽象的,所以下⾯我举⼏个例⼦分析。
endVisit()在node的⼦节点已被访问后调⽤型:
a、赋值语句分析为例:
反比例函数教案
i1 = 1;
i4 = i1;
它们对应语法树结构:
Expressionstatement
Assignment
simplename
numberLiteral
Expressionstatement
Assignment
simplename
simplename
实现程序:
intrightis_num = 1;
visit(Assignment n){
return true;
}
publicvoidendVisit(Assignment n)//访问完所有的节点后,rightis_num已经能够确定
{
Expression string = n.getLeftHandSide();//返回表达式左部
String simplename =((SimpleName) string).getIdentifier();//将变量串赋给simplename
try
{
if(rightis_num== 1)
卢锡安台词{
与狼共舞电影Expression data1 = n.getRightHandSide();//返回表达式右部
System.out.println(simplename);
hm.put(simplename,newInteger(((NumberLiteral) data1).getToken()));//将变量及值加⼊hashmap System.out.(simplename));
}
el//右部为标识符
{
Expression data2 = n.getRightHandSide();//返回表达式右部
String rightname = ((SimpleName) data2).getIdentifier();
hm.put((rightname));
System.out.(simplename));
}
}
catch(Exception e)
{}
}
对应源程序AST的建⽴
class Program{
static void main(){
i = 10;
}
}
/************实现⽅法************/
AST ast = wAST(JLS3);
CompilationUnit cu = wCompilationUnit();//CompilationUnit实例中包含⼀个TypeDeclaration
TypeDeclaration type = wTypeDeclaration();//TypeDeclaration实例表⽰程序中的类
type.wSimpleName("Program"));
MethodDeclaration method = wMethodDeclaration();//TypeDeclaration实例中添加类Program中的⽅法main();
汉普顿宫
method.wSimpleName("main"));
type.bodyDeclarations().add(method);
健康的定义
method.wPrimitiveType(PrimitiveType.VOID));//设置⽅法main()的返回类型为void
Block mainBody = wBlock();
method.tBody(mainBody);//构造main函数的函数体mainBody
//向⽅法main函数体mainBody中添加语句
Assignment.assign = wAssignment();//构建赋值表达式
assign.wSimpleName("i"));//设置赋值表达式的左值为i
assign.tOperator(Assignment.Operator.ASSIGN);//设置赋值表达式的赋值算符为=
assign.wNumberLiteral("10"));//设置赋值表达式的右值为数字10
ExpressionStatement statement = wExpressionStatement(assign);
褚时健传读后感
mainBody.statements().add(statement);//由赋值表达式构建语句,并把这个语句加⼊⽅法Main()的函数体。
访问⽅法
在Eclip AST中,结合AST节点的accept()⽅法和ASTVisitor实例,假设待访问的AST树的根节点为root,则调⽤root.accept()就可以启动对这棵AST树的遍历。
总结:做这个简单解释器的主要⽬的是熟悉程序源代码对应AST的映射,创建对应的AST⽅法都⽐较的固定,问题不⼤。难主是难在遍历树上,分析不同的语句结构,需要重写Visit()⽅法,同时要适当利⽤endVisit()⽅法增加⼀些控制变量,以决定应该解释句⼦的哪⼀分⽀。到现在对preVisit()和postVisit()⽅法仍然不怎么了解,在接下来的编译器开发中仍需慢慢摸索。熟悉了AST相关知识,后续⼯作可以展开了。