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
语句的。