LCC编译器的源程序分析(35)switch语句

switch 语句是多分支选择语句,主要方便多个选择的情况使用,当然也可以使用 if 语句来实现,但嵌套的 if 语句过多会使用程序的可读性降低。
switch( 表达式 )
{
 case 常量表达式 1
       语句 1;
 case 常量表达式 2
       语句 2;
 …
 case 常量表达式 n
       语句 n;
 default:
       语句 n+1
}
上面就是 switch 的语法和语义,现在来分析 LCC 的源程序是怎么样处理这个语句的,先通过下面的函数代码调用:
#054  case SWITCH:  
#055         swstmt(loop, genlabel(2), lev + 1);
#056         break;
55 行是调用函数 swstmt 来处理 switch 语句。第一个参数是循环次数,第二个参数是标号的起始大小,最后一个参数是调用嵌套层数。
 
然后在 swstmt 分析处理这个语句,如下:
#001  static void swstmt(int loop, int lab, int lev)
#002 {
#003  Tree e;
#004  struct swtch sw;
#005  Code head, tail;
#006 
#007  t = gettok();
#008  expect('(');
#009  definept(NULL);
7 行是获取下一个记号。
8 行是检测下一个记号是左括号开始。
9 行是定义了执行点。
 
#010  e = expr(')');
#011  if (!isint(e->type))
#012  {
#013          error("illegal type `%t' in switch expression/n",
#014               e->type);
#015         e = retype(e, inttype);
#016  }
#017 
#018  e = cast(e, promote(e->type));
#019  if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op)
#020         && e->kids[0]->u.sym->type == e->type
#021         && !isvolatile(e->kids[0]->u.sym->type))
#022  {
#023         sw.sym = e->kids[0]->u.sym;
#024         walk(NULL, 0, 0);
#025  }
#026  else
#027  {
#028         sw.sym = genident(REGISTER, e->type, level);
#029         addlocal(sw.sym);
#030         walk(asgn(sw.sym, e), 0, 0);
#031  }
#032 
10 行是处理 switch 后面括号里的表达式,它是调用函数 expr 来处理的。
11 行判断这个表达式返回值是否整数类型,如果不是就会在第 13 行里提示出错,在第 15 行里转换为整型类型。
18 行是转换表达式的值。
19 行到 21 行是判断类型是否可以分配为寄存器变量,如果不可以就在第 23 行和第 24 行里处理;如果可以就在第 28 行到第 30 行里处理。
 
#033  head = code(Switch);
#034  sw.lab = lab;
#035  sw.deflab = NULL;
#036  sw.ncases = 0;
#037  sw.size = SWSIZE;
#038  sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC);
#039  sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC);
#040  refinc /= 10.0;
#041 
33 行生成 switch 的块代码开始。
34 行到第 39 行是设置 switch 的属性结构。
 
#042  statement(loop, &sw, lev);
#043  if (sw.deflab == NULL)
#044  {
#045         sw.deflab = findlabel(lab);
#046         definelab(lab);
#047         if (sw.ncases == 0)
#048               warning("switch statement with no cases/n");
#049  }
#050 
42 行是处理复合语句。
43 行是判断这个 switch 语句的复合语句里是否有分支语句,如果没有就在第 47 行到第 48 行里给出警告。
 
#051  if (findlabel(lab + 1)->ref)
#052         definelab(lab + 1);
#053 
#054  tail = codelist;
#055  codelist = head->prev;
#056  codelist->next = head->prev = NULL;
#057 
#058  if (sw.ncases > 0)
#059         swgen(&sw);
#060 
#061  branch(lab);
#062  head->next->prev = codelist;
#063  codelist->next = head->next;
#064  codelist = tail;
#065 }
51 行是找到最后的标号,并且在第 52 里生成这个标号。
54 行是保存代码表。
59 行生成跳转代码。
61 行是生成标号。
62 行到第 64 行都是设置代码表。
 
通过上面函数的分析,了解 LCC 是怎么样处理 switch 语句的。
 

你可能感兴趣的:(struct,tree,null,编译器,branch)