编译器开发从零单排3

北京那个治疗白癜风医院比较好 http://pf.39.net/bdfyy/bjzkbdfyy/
NaiveCompiler前端设计语义分析(semanticanalysis)

编译器在完成语法分析之后的步骤为语义分析,该步骤会添加语义信息到ParseTree中,并构建符号表(SymbolTable)。

在这个过程中,会同时进行语义检测,例如:类型检查(typechecking),以及定义赋值检查(definiteassignmentanalysis)等。

语义分析通常是基于ParseTree或者AST进行。NaiveCompiler的语义分析实现于analysis_handler.py中。analysis_handler.py中的类继承visitor.py中实现的visitor访问模式类NodeVisitor,实现对AST的访问和分析。

Clang中的语义分析定义于SemaChecking.cpp中。同样是通过Visitor模式实现。

Visitor模式及其实现

Visitor模式是《设计模式》(GoFdesignpatterns)中的23个设计模式之一,可以实现算法和实际对象结构的分离,可以在不修改对象结构的情况下给对象添加新的方法。

在C++中可以利用函数重载,doubledispatch来实现visitor模式,不需要修改已定义好的class源码。而Python中则更为简单,通过反射获取类名即可实现。

Visitor模式还有一个好处,即遍历AST时,所有的节点都是继承自ASTNode,所以可以方便的递归遍历整颗树,并只对感兴趣的节点做处理。

在NaiveCompiler的前端中,visitor都继承自visitor.py中的NodeVisitor。该源码修改自CPython自身的NodeVisitor(定义于/Lib/ast.py)。

classNodeVisitor(object):defvisit(self,node):method=visit_+node.__class__.__name__visitor=getattr(self,method,self.generic_visit)returnvisitor(node)defgeneric_visit(self,node):forcinnode.children():self.visit(c)

要实现特定的功能只需要继承该类,以visit_XXX的方式定义想要处理的节点,没有定义对应函数的节点会调用generic_visit函数,自动访问其子节点。

例如做定义赋值检查(definiteassignmentanalysis)时,AnalysisVisitor继承NodeVisitor,并在访问到函数定义时切换到针对FuncDef的类。

classFuncHelper(NodeVisitor):def__init__(self):self.scope=Scope()def_has_error(self):returnself.scope.has_errordefvisit_TypeDecl(self,node):#printTypeDecl,node.__class__.__name__self.scope.define_symbol(node._id.name,node._type)defvisit_DeclStmt(self,node):#self.generic_visit(node.decl)self.visit_TypeDecl(node.decl)defvisit_ContinueStmt(self,node):logging.error("continueoutsideloop!")self.scope.has_error=Truedefvisit_BreakStmt(self,node):logging.error("breakoutsideloop!")self.scope.has_error=Truedefvisit_Assignment(self,node):iftype(node.cast_expr)isVariableSymbol:self.scope.resolve_symbol(node.cast_expr.name)#helper=AssignmentExprHelper(self.scope)#helper.visit(node)

可以看到,在访问到声明和赋值语句时,会回调visit_TypeDecl和visit_Assignment。

其中visit_TypeDecl会在符号表中注册该变量,而visit_Assignment会检测该变量是否存在于符号表中(同时也可以检测变量的类型和赋值的对象是否相同)。

而visit_BreakStmt和visit_ContinueStmt则会检查是否有循环外的break和continue语句。因为循环语句会触发visit_WhileStmt,进入LoopHelper对象进行下一步处理,在没有进去LoopHelper访问到的break和continue即为循环外定义的非法语句。

中间代码生成

通常的代码生成过程为:源代码解析为的AST或者三地址代码,生成高级的中间代码(HIR),然后可能会生成中级的中间代码(MIR)或低级的中间代码(LIR),中间代码一般是机器无关的代码,最后编译器在中间代码的基础上生成机器相关的代码(例如x86汇编代码)。MIR基本上适合大多是优化场景,HIR则用于依赖分析等场景,LIR用于明确指明寄存器和地址等的优化,参考《高级编译器的设计与实现》(鲸书)第四章《中间表示》。

最常见的HIR即为抽象语法树(AST),而MIR需要表示源代码的变量、临时变量、寄存器,能够把控制流归约为简单的有条件跳转和无条件跳转、函数调用(call)、和返回(ret),还需要用明显的操作来支持块结构(BasicBlock)和过程(Function)。

BasicBlock是CFG的基本组成部分,有一系列除了头和尾没有分支的代码序列,一个BasicBlock中的代码会按顺序依次执行。

一个BasicBlock只能有一个入口(entrypoint),意味着BasicBlock中的代码不能是某个跳转指令的目标。一个BasicBlock只能有一个出口(exitpoint),代表只有BasicBlock中的最后一条指令才允许跳转到另外的BasicBlock中开始执行。

BasicBlock(简称BB块)之间的关系为,BB块结束后跳转的目标称作successors,一个BB块可能有多个successors(条件跳转)。跳转到先有BB块的称作predecessors,一个BB块也可能有多个predecessors。

下面将以clang和gcc为例,通过下面的testif.c来说明常见的中间代码形式和生成过程。

testif.c

intmain(){inta=1;if(a0){return1;}return0;}Clang中的中间代码生成

Clang中会先将AST划分为CFG(Control-flow_graph),用于进一步的分析和平台无关的优化。然后再以类似划分CFG的逻辑划分BasicBlocks,并生成三地址代码。

Clang中会生成LLVM的IR,再调用LLVM生成目标机器码,使用clang-S-emit-llvm1可以dump出Clang生成的LLVMIR。以下面的测试代码为例:

生成的testif.ll代码如下:

definei32

main()#0{%1=allocai32,align4%2=allocai32,align4storei,i32*%1,align4storei,i32*%2,align4%3=loadi32,i32*%2,align4%4=icmpsgti32%3,0bri1%4,label%5,label%6;label:5:;preds=%0storei,i32*%1,align4brlabel%7;label:6:;preds=%0storei,i32*%1,align4brlabel%7;label:7:;preds=%6,%5%8=loadi32,i32*%1,align4reti32%8}

可以看到C代码中的if语句编译为了icmp和br,然后if和else分支分别对应label5和label6。而label7为if后续的语句,可以看到label7的注释中标注有preds=%6,%5,其代表着label7的前置label为5和6,这代表了BasicBlock间的关系。除了第一个BasicBlock,如果某个BasicBlock没有前置的BasicBlock,则该分支为无效的分支。下面我们将一起来看一下BasicBlock的具体概念。

GCC中的中间代码生成

以上面的testif.c为例,使用gcc-fdump-tree-alltestif.c可以dump出gcc中的中间语言gimple(.gimple文件,为高级的中间表达式)以及cfg(.cfg由高级的gimple生成低级的中间表达式)。

上面的testif.c生成的cfg如下

;;nodes:;;2succs{34};;3succs{5};;4succs{5};;5succs{1}main(){inta;intD.;bb2[0.00%]:a=1;if(a0)gotobb3;[0.00%]elsegotobb4;[0.00%]bb3[0.00%]:D.=1;gotobb5(L2);[0.00%]bb4[0.00%]:D.=0;L2[0.00%]:returnD.;}

关于gcc的gimple中间表达式可以参考



转载请注明地址:http://www.sanbaicaoasb.com/scls/7887.html
  • 上一篇文章:
  • 下一篇文章:
  • 热点文章

    • 没有热点文章

    推荐文章

    • 没有推荐文章