[转载]LCC编译器的源程序分析(35)switch语句
2007-08-22 12:51
411 查看
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语句的。
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语句的。
相关文章推荐
- LCC编译器的源程序分析(35)switch语句
- LCC编译器的源程序分析(35)switch语句
- LCC编译器的源程序分析(35)switch语句
- [转载] LCC编译器的源程序分析(20)复合语句
- [转载]LCC编译器的源程序分析(28)函数表达式语句
- [转载]LCC编译器的源程序分析(29)if条件语句
- [转载] LCC编译器的源程序分析(61)复合语句的代码块流程
- [转载]LCC编译器的源程序分析(30)while循环语句
- [转载]LCC编译器的源程序分析(31)do while循环语句
- [转载] LCC编译器的源程序分析(34)continue语句
- [转载]LCC编译器的源程序分析(36)case语句
- [转载] LCC编译器的源程序分析(32)for循环语句
- [转载]LCC编译器的源程序分析(37)default语句
- [转载]LCC编译器的源程序分析(33)break语句
- [转载]LCC编译器的源程序分析(38)return语句
- [转载]LCC编译器的源程序分析(27)基本语句
- LCC编译器的源程序分析(61)复合语句的代码块流程
- [转载]LCC编译器的源程序分析(5)行号同步与类型初始化
- [转载]LCC编译器的源程序分析(12)自定义类型的声明
- [转载]LCC编译器的源程序分析(41)赋值表达式的有向无环图