《编译技术编译原理 (5).pdf》由会员分享,可在线阅读,更多相关《编译技术编译原理 (5).pdf(63页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、基于python的简易编译器实现simpleJavaCompilerCFG设计CFG设计语句和语句列表CFG设计语句和语句列表运算符相关CFG设计语句和语句列表运算符相关变量与函数声明CFG设计语句和语句列表运算符相关变量与函数声明申请堆内存,新建对象/数组CFG设计语句和语句列表运算符相关变量与函数声明申请堆内存,新建对象/数组流程控制语句流程控制语句CFG设计语句和语句列表运算符相关变量与函数声明申请堆内存,新建对象/数组流程控制语句类型流程控制语句CFG设计语句和语句列表运算符相关变量与函数声明申请堆内存,新建对象/数组流程控制语句类型基本数据单元流程控制语句读取类型定义、CFG,生成A
2、ction&Goto并保存StatementList_|_|StatementListStatement _|_|Expr StatementListStatement _|_|_|IfBlockf0 ;StatementListStatement _|_|f1 Statement IfBlockif (c0 )StatementList|_|_|f2 Declaration|c1 Statement|_|_ if (c0 )StatementList|c0|c2 Expr|VarDeclaration;c1 Statement|_|_ c1 _|_|c3|c2 Expr _|_ f0 ;c2
3、 Type IdList|_|_|c3|c3 =c4 f1 c3 BasicTypeId _|_ f0 ;|_|_|c4 e0 f2 c4 int|c3 =c4 f1|a =c0|e0 e1 c0 e0|c4 e0 f2|c1|e1 e2 c1 e1|e0 e1 c0|c2|e2 e3 c2 e2|e1 e2 c1|c3|e3 e4 c3 e3|e2 e3 c2|c4|e4 Value c4 e4|e3 e4 c3|e0|ValueConstant e0 Value|e4 Value c4|e1|a 2 e1 FunctionCall|Value Constant e0|_|_ e2|e2|a
4、 1 e1|print (ParamList)e3|e3|e2|Param e4|e4|e3|c0 Value|Value|e4|c1 Constant|FunctionCall|Value _|_ c2 1|FunctionCallprint (ParamList)c3 _|_|Param c4 print (ParamList)|c0 e0 Param|c1 e1 c0|c2 e2 c1|c3 e3 c2|c4 e4 c3|e0 Value c4|e1 Constant e0|e2 .e1|e3 e2|e4 e3|Value e4|Constant Value|.Constant|.根据生
5、成的Action和Goto对上面的代码进行分析可以得到右边这样的分析树分析树通常会包含无用的节点,因此需要抽象语法树,只保留有用的节点。Abstract Syntax Tree抽象语法树Ast.ASTNode部分实现Ast.AST部分实现Ast.ASTActionRegister部分实现生成AST总的来说就是减少多余的节点省略了大约330行大多比较相似的内容stmtList_|_|funcDecfuncDecvarDecfunctionCallforBlock_|_ _|_ _|_ _|_ _|_|int gcddefParamListstmtListint coPrimedefParamLi
6、ststmtListint idListprint parameterListvarDecltstmtListsp_|_ _|_ _|_ _|_ _|_|_|_ _|_|functionCall|forBlockidefParamdefParamvarDecwhileBlockreturn defParamdefParamvarDecifBlockassign assign_|_ int idListi10 _|_ _|_ _|_ _|_ _|_|_|_ _|_ _|_ _|_ _|_ _|_|a|gcdparameterListassign varDecltstmtListspint a i
7、nt b int idListne stmtListint a int b int idListne stmtListstmtLista 73872 b 5728 _|_ _|_ _|_ _|_|_|_ _|_|_|_|functionCallj temp|assign|functionCallfunctionCalla b i5 int idListj 10 _|_ b 0 assign assignassign_|_ val1 _|_ _|_|_|_ _|_ _|_|assign coPrimeparameterList|valfunctionCallprint parameterList
8、print parameterList_|_ _|_ temp mod a b btemp _|_ _|_ _|_|_|_|j 5 ij|gcdparameterListgcd(a ,b )=vala and b are co-prime!a b _|_|a b 产生的AST利用AST生成TAC/ILOCCode Block代码块存储由AST产生的三地址代码TAC给每个statementList设置一个新的cb属性,存储一个代码块对象的引用将父节点的代码块引用传递给子节点,这样就可以在任意节点添加TAC在生成TAC之前Scope作用域每个statement list都会产生一个新的作用域/sc
9、ope(0,0)/scope(1,0)/scope(2,0)/scope(2,1)/scope(1,1)/scope(2,2)利用嵌套深度和在该深度的编号,可以唯一地确定作用域。利用深度和每个深度已有的作用域数量,产生唯一的编号声明&查询变量将变量的基本信息封装在一个类中包括标识符,类型,占用字节数,命名空间等在声明语句中创建变量在声明语句中创建变量在普通语句中溯根查询父作用域直到到达根作用域或者命中将结果放置在.var属性中生成TAC给每个AST节点都写个动作,生成TAC/ILOC,并加入到自己节点所属的代码块中部分实现simpleJavaCompiler.py条件判断与循环汇编只有无条件跳
10、转jmp,还有根据CPU flags进行跳转的jz,jnz等要怎么把if while for转换成jmp呢?显然通过if和goto即可描述这些结构除此之外,还需要提供对代码块切分的操作if cond val cb0 cb1if伪指令:当cond=val时跳转到cb0若有cb1则在cb0完成后跳转到cb1goto cb0 cb1goto伪指令:跳转去cb0若有cb1则在cb0完成后跳转到cb1seg从这里开始往后的代码将会被划分为一个新的代码块当前代码块的”next”属性会被设定为新划分的代码块的引用利用元组表示现在不能确定的代码块continue和break也只需要简单地添加跳转即可由于指定代
11、码块的next,也就是指定代码块的下一个代码块并不能在生成时确定(next会因为seg伪指令改变),因此需要在生成完TAC/ILOC后先切分代码块。切分了代码块后,先替换所有未定代码块中的cur为当前代码块引用(_CB_5,next):(_CB_6,next),_CB_6,(_main,next):_CB_5,(_CB_0,next):(_CB_1,next),_CB_1由于未定代码块可能依赖于其他未定代码块,因此为了确定计算顺序,需要建立依赖图建立依赖图后,跑一下拓扑排序即可算出所有代码块的next最后把goto和if转换成真正的目标代码即可函数定义仅对函数做最基本的封装记录变量列表,函数名,返回值类型,以及代码块在对应的action处产生新的Function对象并记录函数调用在说明函数调用前,要先理解如何传值。这是程序运行时,操作系统为其分配的内存要传值的话,需要把参数逆序逆序压进栈中在push完参数后,利用call指令调用函数返回值约定由EAX寄存器保存在windows上,call似乎只存储了原来的EBP指针之后就可以利用ESP+offset的方式读取之前push进栈里的值了逆序压入栈调用保护EAX和EBX寄存器的值不被污染从EAX获取返回值清理实参占用的栈空间成果产生的汇编源码-感谢围观