0
点赞
收藏
分享

微信扫一扫

UCC编译器学习笔记19


switch case语句和if else语句到底有什么区别:

switch case语句要求case后必须是常量,因此要求更为严格,但是该语句的执行效率最高,可以认为在O(1)时间匹配到目标分支执行。这是为什么呢,看下面

switch (a)

case constant1: xx;

case constant2: xx;

case constant3: xx;

。。。

编译器把case语句后面的常量进行了表格化跳转,就是和地址直接绑定在了一块,这样可以直接跳转,如下:

case 0: xx;

case 1: xx;

case 2: xx;

这些语句,我只要编译器创建一个映射表,把case 0,1,2对应的语句地址,映射到一个递增地址空间,如果base为基地址,那么 jmp *swtchTable(a)这样,就可一步跳转到目标case地址了,不需要比较,然而if else的原理是需要逐一比较,所以效率低。比如a=2,那么直接跳转到base+2的地址执行,这个不就是case 2的语句地址嘛。

然而,如果case后的常量不是逐步增大的呢,如何做呢,如下:

如果我们遇到的是{1,2,20000,50},相应的跳转表就得有20000个表项,其中大部

分的表项存放的是形如“BB12”这样的用于跳出switch语句的地址,这需要耗费相当大的

内存,此时我们不再构造一张跳转表,而是想把{1,2,20000,50}分成几段,每一段内的

各个数值彼此接近,例如我们可把{1,2,20000,50}分成3段{{1,2},{50},{20000}}。我

们制定一个标准,来衡量各数值彼此接近的程度,UCC编译器引入了一个“Case语句密度”

的概念,

Case语句密度 =Case语句数量/区间大小

例如,对于{1,2,20000,50}来说,其密度为(4/(20000-1)),这有点像人口密度的概念,反

映了人口的密集程度,而{1,2}的密度为2/(2-1)。为了方便代码生成,UCC编译器在语法分

析时,会把在同一switch语句的各case语句,按出现的先后顺序进行排列。而为了统计“Case

语句密度”,在语义检查时,会按各case语句的常量表达式数值,从小到大进行排列。因此,

每条case语句实际上会出两个链表中,UCC编译器用结构体astCaseStatement来描述一条

case语句,其中的next和nextCase域用于构造这样的两个链表。

struct astCaseStatement{

//按case语句在源代码中出现的先后顺序排列

struct astNode *next;

//按case语句的表达式数值从小到大排列

struct astCaseStatement *nextCase;

…..

}

当面对从小到大排列的{1,2,50,20000}时,UCC编译器要求每段的密度要大于

1/2,根据这个经验值,我们可以按以下步骤进行分段,

(1)第1个case语句就是一段,即{1}

(2)把第2个case语句加入{1},则有{1,2},其密度为2

(3)若把第3个case语句加入{1,2},则有{1,2,50},其密度为3/49,小于1/2,因此

我们新创建一段来存放50,即有了{{1,2},{50}}

(4)若把第4个case语句加入{50},则有{50,20000},其密度也小于1/2,因此我们再

新创建一段来存放20000,即有了{{1,2},{50},{20000}}

若有一个整数val,我们要判断val是落在哪一段中,为了减少比较的次数,我们可以

采用二分查找的方法,即先看看val是否落在中间的那一段{50},如果比中间段更小,就再

看看是否能在左侧的段{1,2}中;若更大,则看看是否落在右侧的段{20000}中。按这样思

路,我们可以产生如图5.3.4第23至38行的比较和跳转操作,而第39至50行的中间代码

仍然保持C源程序中case语句的先后顺序。我们还注意到,当某段中的case语句多于1条

时,UCC编译器会通过跳转表来进行跳转,如第34行所示。如果某段中只有一条case语句

且其左侧或右侧的段还没有被比较过,例如第23行的{50},我们可产生形如第23至27行

的代码,即要处理“小于”、“大于”和“落在段中”这3种情况;而如果该段的左侧和右侧

的其他段都已被处理过,例如第36行的{20000},我们可产生形如第36至38行的代码即可,

此时只要处理“等于”和“不等于”这2种情况。

UCC编译器学习笔记19_链表

switch语句的翻译是最难的,接下来看看for等语句,就简单多了,按照套路翻译即可,如下:

UCC编译器学习笔记19_编译器_02

比如for语句:


static void TranslateForStatement(AstStatement stmt)
{
AstForStatement forStmt = AsFor(stmt);
forStmt->loopBB = CreateBBlock();
forStmt->contBB = CreateBBlock();
forStmt->testBB = CreateBBlock();
forStmt->nextBB = CreateBBlock();
if (forStmt->initExpr)
{
TranslateExpression(forStmt->initExpr);
}
GenerateJump(forStmt->testBB);
StartBBlock(forStmt->loopBB);
TranslateStatement(forStmt->stmt);
StartBBlock(forStmt->contBB);
if (forStmt->incrExpr)
{
TranslateExpression(forStmt->incrExpr);
}
StartBBlock(forStmt->testBB);
if (forStmt->expr)
{
TranslateBranch(forStmt->expr, forStmt->loopBB, forStmt->nextBB);
}
else
{
GenerateJump(forStmt->loopBB);
}
StartBBlock(forStmt->nextBB);
}
举报

相关推荐

0 条评论