由前面的例子可以知道,
C
函数里包含数据定义部分和执行部分,执行部分就是由语句组成。计算机最基本的动作就是具备条件判断,这也是计算机具有这么大魔力的原因。而这些条件判断是通过语句来实现的。基本的语句有下面几种:
1.
控制语句
:
if else
for
while
do while
continue
brea
k
switch
goto
return
2.
函数调用语句
max(a,b);
3.
表达式语句
nPos = 10;
4.
空语句
;
最后面一种在
LCC
里会提示警告的。
在这节和后面跟着的节就是分析这些基本语句是怎么样处理,以及会生成什么样的代码。在
compound
函数里是这样调用语句分析函数的:
#052 while (kind[t] == IF || kind[t] == ID)
#053 {
#054 statement(loop, swp, lev);
#055 }
#056
因此要去分析函数
statement
是怎么样分析处理上面出现的语句。
下面就是
statement
的代码:
#001 //
所有基本语句处理函数。
#002 //
蔡军生
2007/06/02
#003 void statement(int loop, Swtch swp, int lev)
#004 {
#005 float ref = refinc;
#006
#007 if (Aflag >= 2 && lev == 15)
#008 warning("more than 15 levels of nested statements/n");
#009
第
5
行是保存引用计数。
第
7
行是判断递归调用超过
15
层。
#010 switch (t)
#011 {
#012 case IF:
#013 ifstmt(genlabel(2), loop, swp, lev + 1);
#014 break;
第
13
行是调函数
ifstmt
来处理
if
语句。
#015 case WHILE:
#016 whilestmt(genlabel(3), swp, lev + 1);
#017 break;
第
16
行是调用函数
whilestmt
来处理
while
语句。
#018 case DO:
#019 dostmt(genlabel(3), swp, lev + 1);
#020 expect(';');
#021 break;
#022
第
19
行是调用函数
dostmt
来处理
do while
语句。
第
20
行是处理
do while
语句后需要分号。
#023 case FOR:
#024 forstmt(genlabel(4), swp, lev + 1);
#025 break;
第
24
行是调用函数
forstmt
来处理
for
语句。
#026 case BREAK:
#027 walk(NULL, 0, 0);
#028 definept(NULL);
#029
#030 if (swp && swp->lab > loop)
#031 branch(swp->lab + 1);
#032 else if (loop)
#033 branch(loop + 2);
#034 else
#035 error("illegal break statement/n");
#036
#037 t = gettok();
#038 expect(';');
#039 break;
#040
第
31,33
行是调用函数
branch
来处理
break
语句。
#041 case CONTINUE:
#042 walk(NULL, 0, 0);
#043 definept(NULL);
#044
#045 if (loop)
#046 branch(loop + 1);
#047 else
#048 error("illegal continue statement/n");
#049
#050 t = gettok();
#051 expect(';');
#052 break;
#053
第
46
行是调用函数
branch
来处理
continue
语句。
#054 case SWITCH:
#055 swstmt(loop, genlabel(2), lev + 1);
#056 break;
第
55
行是调用函数
swstmt
来处理
switch
语句。
#057 case CASE:
#058 {
#059 int lab = genlabel(1);
#060 if (swp == NULL)
#061 error("illegal case label/n");
#062
#063 definelab(lab);
#064 while (t == CASE)
#065 {
#066 static char stop[] = { IF, ID, 0 };
#067 Tree p;
#068 t = gettok();
#069 p = constexpr(0);
#070 if (generic(p->op) == CNST && isint(p->type))
#071 {
#072 if (swp)
#073 {
#074 needconst++;
#075 p = cast(p, swp->sym->type);
#076 if (p->type->op == UNSIGNED)
#077 p->u.v.i = extend(p->u.v.u, p->type);
#078 needconst--;
#079 caselabel(swp, p->u.v.i, lab);
#080 }
#081 }
#082 else
#083 error("case label must be a constant integer expression/n");
#084
#085 test(':', stop);
#086 }
#087 statement(loop, swp, lev);
#088 }
#089 break;
第
59
行是调用函数
genlabel
生成标号。
第
64
行是处理所有
case
语句。
第
69
行是处理
case
语句后面的常量表达式,调用函数
constexpr
来处理。
第
70
行到第
81
行是作类型转换的工作,如果不能处理常量类型,就会在第
83
行里提示出错。
第
87
行是递归调用函数
statement
处理
case
语句里语句。
#090 case DEFAULT:
#091 if (swp == NULL)
#092 error("illegal default label/n");
#093 else if (swp->deflab)
#094 error("extra default label/n");
#095 else
#096 {
#097 swp->deflab = findlabel(swp->lab);
#098 definelab(swp->deflab->u.l.label);
#099 }
#100 t = gettok();
#101 expect(':');
#102 statement(loop, swp, lev);
#103 break;
第
97
行是查找
default
语句生成的标号。
第
98
行是定义这个标号。
第
102
行是调用函数
statement
递归处理所有后面语句。
#104 case RETURN:
#105 {
#106 Type rty = freturn(cfunc->type);
#107 t = gettok();
#108 definept(NULL);
#109 if (t != ';')
#110 if (rty == voidtype)
#111 {
#112 error("extraneous return value/n");
#113 expr(0);
#114 retcode(NULL);
#115 }
#116 else
#117 retcode(expr(0));
#118 else
#119 {
#120 if (rty != voidtype)
#121 {
#122 warning("missing return value/n");
#123 retcode(cnsttree(inttype, 0L));
#124 }
#125 else
#126 retcode(NULL);
#127 }
#128 branch(cfunc->u.f.label);
#129 }
#130 expect(';');
#131 break;
#132
第
106
行是取得函数返回的类型。
第
109
行是判断返回语句是否有返回值,如果有返回值,但函数定义类型没有返回值就提示出错,这是在第
110
行里处理。如果函数定义有返回值,并且
return
语句也有返回值就调用第
117
行里的
retcode(expr(0))
来处理返回表达式的值。
如果
return
语句后面没有返回值,但函数需要返回值,这样是出错的,是在第
120
行里处理。如果真的没有返回值,就是返回空值,在第
126
行里处理。
第
128
行跳转到函数调用之后标号执行。
#133 case '{':
#134 compound(loop, swp, lev + 1);
#135 break;
当是大括号开始时,又是复合语句,所以要递归调用函数
compound
来处理。
#136 case ';':
#137 definept(NULL);
#138 t = gettok();
#139 break;
上面是空行语句的处理。
#140 case GOTO:
#141 walk(NULL, 0, 0);
#142 definept(NULL);
#143 t = gettok();
#144 if (t == ID)
#145 {
#146 Symbol p = lookup(token, stmtlabs);
#147
#148 if (p == NULL)
#149 {
#150 p = install(token, &stmtlabs, 0, FUNC);
#151 p->scope = LABELS;
#152 p->u.l.label = genlabel(1);
#153 p->src = src;
#154 }
#155 use(p, src);
#156 branch(p->u.l.label);
#157 t = gettok();
#158 }
#159 else
#160 error("missing label in goto/n"); expect(';');
#161 break;
#162
上面是
goto
语句的处理。
第
144
行先判断
goto
语句后面是否标号
ID
,如果是就运行
146
行的代码来查找已经定义的标号。如果没有找到就生成一个新的标号。最后在第
156
行里跳到标号的位置运行后面的代码。
#163 case ID:
#164 if (getchr() == ':')
#165 {
#166 stmtlabel();
#167 statement(loop, swp, lev);
#168 break;
#169 }
上面处理标号语句。
第
166
行调用函数
stmtlabel
来处理标号语句,最后调用函数
statement
处理其它跟着的语句。
#170 default:
#171 definept(NULL);
#172 if (kind[t] != ID)
#173 {
#174 error("unrecognized statement/n");
#175 t = gettok();
#176 }
#177 else
#178 {
#179 Tree e = expr0(0);
#180 listnodes(e, 0, 0);
#181 if (nodecount == 0 || nodecount > 200)
#182 walk(NULL, 0, 0);
#183 else if (glevel) walk(NULL, 0, 0);
#184 deallocate(STMT);
#185 }
#186 expect(';');
#187 break;
#188
#189 }
#190
#191 if (kind[t] != IF && kind[t] != ID
#192 && t != '}' && t != EOI)
#193 {
#194 static char stop[] = { IF, ID, '}', 0 };
#195 error("illegal statement termination/n");
#196 skipto(0, stop);
#197 }
#198 refinc = ref;
#199 }
#200
如果一个
ID
后面没有跟着冒号,那么它是一个表达式语句。
比如像例子里的语句:
nTest3 = nTest1 + nTest2;
这就是
ID
开始的表达式语句。它会调用前面介绍的表达式处理函数
expr0
来分析的。
第
172
行到
175
行处理不是
ID
的出错。
第
179
行是处理右边的表达式。
第
180
行是调用函数
listnodes
来遍历整个语句树,主要的目的是生成中间的树表示,删除公共的表达式节点,起到优化代码的作用,为后面生成代码作好准备工作。
第
181
行是当中间表示的树节点多于
200
个就进行代码生成。
第
191
行是出错的符号,并进入第
195
行到第
196
行的错误处理。
到这里就把基本语句函数分析完成,接着后面就需要专门地分析具体语句的处理函数。