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

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License