激动人心的时刻就要开始了,从这节开始,就进入处理实际的代码了。由于
C
语言是函数式的语言,也就是每个程序都是有一个一个的函数组成的,一个
C
源程序至少包含一个函数(
main
函数),也可以包含一个
main
函数和若干个其它函数。因此,函数是
C
程序的基本单位。仔细地查看一下第一节里的例子代码,它是如下:
#001 #include <stdio.h>
#002
#003 int main(void)
#004 {
#005 int nTest1 = 1;
#006 int nTest2 = 2;
#007 int nTest3;
#008 int i;
#009
#010 nTest3 = nTest1 + nTest2;
#011 printf("nTest3 = %d/r/n",nTest3);
#012
#013 for (i = 0; i < 5; i++)
#014 {
#015 printf("%d/r/n",nTest3+i);
#016 }
#017
#018 printf(__TIME__" "__DATE__"/r/nhello world/n");
#019 return 0;
#020 }
#021
当预处理变成下面的代码:
int main(void)
{
int nTest1 = 1;
int nTest2 = 2;
int nTest3;
int i;
nTest3 = nTest1 + nTest2;
printf("nTest3 = %d/r/n",nTest3);
for (i = 0; i < 5; i++)
{
printf("%d/r/n",nTest3+i);
}
printf("00:30:28"" ""Apr 07 2007""/r/nhello world/n");
return 0;
}
现在就来分析
LCC
处理这个函数定义的代码。首先跟其它函数声明一样,把函数声明
int main(void)
调用以前介绍的函数声明处理方法来分析后,就会运行到函数
decl
里,然后判断是否有函数的定义,如果有的话就去处理定义的代码,并生成最终的代码。如下:
#022 //
判断是否函数定义开始。
#023 if (params && id && isfunc(ty1) &&
#024 (t == '{' || istypename(t, tsym) ||
#025 (kind[t] == STATIC && t != TYPEDEF)))
#026 {
#027 if (sclass == TYPEDEF)
#028 {
#029 error("invalid use of `typedef'/n");
#030 sclass = EXTERN;
#031 }
#032
#033 if (ty1->u.f.oldstyle)
#034 {
#035 exitscope();
#036 }
#037
#038 //
函数定义
,
开始生成代码。
#039 funcdefn(sclass, id, ty1, params, pos);
#040
#041 return;
第
23
行判断是否函数的声明,如果是函数的声明,就再进一步判断是否函数定义的复合语句。如果有函数定义,在第
39
行开始处理函数定义,并生成汇编代码。
现在就开始去分析函数定义的处理函数
funcdefn
,调用的参数如下:
sclass
是函数返回存储类型。
id
是函数声明的名称。
ty1
是返回类型。
params
是函数的参数列表。
pos
是函数定义的位置。
funcdefn
处理函数定义是非常多代码的,要准备好艰苦的心理啊。从上面的函数
main
里,就可以看到函数定义要处理的几部分肯定有:
1.
局部变量的声明。
2.
局部变量的赋值。
3.
调用其它函数。
4.
循环语句。
5.
函数返回值。
当然函数的定义不仅仅限于上面的这些,还有很多语句,比如
if
语句等等。不管它的代码有多么复杂,相信我们一定有能力去分析它的实现的。
下面先来粗略地分析
funcdefn
函数代码实现:
#001 //
函数定义分析函数。
#002 static void funcdefn(int sclass, char *id, Type ty,
#003 Symbol params[], Coordinate pt)
#004 {
#005 int i, n;
#006 Symbol *callee, *caller, p;
#007
#008 Type rty = freturn(ty);
#009
第
8
行是处理函数返回的类型。
#010 if (isstruct(rty) && rty->size == 0)
#011 error("illegal use of incomplete type `%t'/n", rty);
#012
第
10
行是处理返回类型出错的情况。
#013 //
设置参数结束。
#014 for (n = 0; params[n]; n++)
#015 ;
#016 if (n > 0 && params[n-1]->name == NULL)
#017 params[--n] = NULL;
#018
#019 if (Aflag >= 2 && n > 31)
#020 warning("more than 31 parameters in function `%s'/n", id);
#021
第
14
行到第
17
行计算参数个数,然后设置参数列表结束位置。
第
19
行提示参数的个数过多,比如超过
31
个,一般的函数都不可能有那么多参数的,除非是程序自动生成的函数。
#022 //
旧风格的函数定义。
#023 if (ty->u.f.oldstyle)
#024 {
#025 if (Aflag >= 1)
#026 warning("old-style function definition for `%s'/n", id);
#027
#028 caller = params;
#029 callee = newarray(n + 1, sizeof *callee, FUNC);
#030 memcpy(callee, caller, (n+1)*sizeof *callee);
#031 enterscope();
#032 assert(level == PARAM);
#033
#034 //
#035 while (kind[t] == STATIC || istypename(t, tsym))
#036 decl(dclparam);
#037
#038 foreach(identifiers, PARAM, oldparam, callee);
#039
#040 for (i = 0; (p = callee[i]) != NULL; i++)
#041 {
#042 if (!p->defined)
#043 callee[i] = dclparam(0, p->name, inttype, &p->src);
#044
#045 *caller[i] = *p;
#046 caller[i]->sclass = AUTO;
#047 caller[i]->type = promote(p->type);
#048 }
#049
#050 p = lookup(id, identifiers);
#051 if (p && p->scope == GLOBAL && isfunc(p->type)
#052 && p->type->u.f.proto)
#053 {
#054 Type *proto = p->type->u.f.proto;
#055 for (i = 0; caller[i] && proto[i]; i++)
#056 {
#057 Type ty = unqual(proto[i]);
#058 if (eqtype(isenum(ty) ? ty->type : ty,
#059 unqual(caller[i]->type), 1) == 0)
#060 break;
#061 else if (isenum(ty) && !isenum(unqual(caller[i]->type)))
#062 warning("compatibility of `%t' and `%t' is compiler dependent/n",
#063 proto[i], caller[i]->type);
#064 }
#065
#066 if (proto[i] || caller[i])
#067 error("conflicting argument declarations for function `%s'/n", id);
#068
#069 }
#070 else
#071 {
#072 Type *proto = newarray(n + 1, sizeof *proto, PERM);
#073 if (Aflag >= 1)
#074 warning("missing prototype for `%s'/n", id);
#075
#076 for (i = 0; i < n; i++)
#077 proto[i] = caller[i]->type;
#078
#079 proto[i] = NULL;
#080 ty = func(rty, proto, 1);
#081 }
#082 }
#083 else
#084 {
#085 //
新风格的函数。
#086 callee = params;
#087 caller = newarray(n + 1, sizeof *caller, FUNC);
#088
#089 for (i = 0; (p = callee[i]) != NULL && p->name; i++)
#090 {
#091 NEW(caller[i], FUNC);
#092 *caller[i] = *p;
#093 if (isint(p->type))
#094 caller[i]->type = promote(p->type);
#095
#096 caller[i]->sclass = AUTO;
#097
#098 if ('1' <= *p->name && *p->name <= '9')
#099 error("missing name for parameter %d to function `%s'/n", i + 1, id);
#100
#101 }
#102 caller[i] = NULL;
#103 }
#104
上面代码是生成旧风格和新风格的参数
callee
和
caller
,第一个是传入函数的参数列表,第二个是返回给调用函数的参数列表。
#105 for (i = 0; (p = callee[i]) != NULL; i++)
#106 {
#107 if (p->type->size == 0)
#108 {
#109 error("undefined size for parameter `%t %s'/n",
#110 p->type, p->name);
#111 caller[i]->type = p->type = inttype;
#112 }
#113 }
#114
上面代码判断参数传送的类型是否出错。
#115 if (Aflag >= 2 && sclass != STATIC && strcmp(id, "main") == 0)
#116 {
#117 if (ty->u.f.oldstyle)
#118 warning("`%t %s()' is a non-ANSI definition/n", rty, id);
#119 else if (!(rty == inttype
#120 && (n == 0 && callee[0] == NULL
#121 || n == 2 && callee[0]->type == inttype
#122 && isptr(callee[1]->type) && callee[1]->type->type == charptype
#123 && !variadic(ty))))
#124 warning("`%s' is a non-ANSI definition/n", typestring(ty, id));
#125 }
#126
上面处理
main
函数定义出错的处理。
#127 p = lookup(id, identifiers);
#128 if (p && isfunc(p->type) && p->defined)
#129 error("redefinition of `%s' previously defined at %w/n",
#130 p->name, &p->src);
#131
上面的代码是判断函数是否重复声明。
#132 //
声明函数。
#133 cfunc = dclglobal(sclass, id, ty, &pt);
#134
上面的代码是处理函数全局定义。
#135 //
生成第一个标号。
#136 cfunc->u.f.label = genlabel(1);
#137 cfunc->u.f.callee = callee;
#138 cfunc->u.f.pt = src;
#139 cfunc->defined = 1;
#140
#141 if (xref)
#142 use(cfunc, cfunc->src);
#143
#144 if (Pflag)
#145 printproto(cfunc, cfunc->u.f.callee);
#146
#147 if (ncalled >= 0)
#148 ncalled = findfunc(cfunc->name, pt.file);
#149
上面的代码保存函数的属性。
#150 labels = table(NULL, LABELS);
#151 stmtlabs = table(NULL, LABELS);
#152 refinc = 1.0;
#153 regcount = 0;
#154 codelist = &codehead;
#155 codelist->next = NULL;
#156
#157 if (!IR->wants_callb && isstruct(rty))
#158 retv = genident(AUTO, ptr(unqual(rty)), PARAM);
#159
上面的代码是准备生成代码。
#160 //
分析函数定义里的复合语句。
#161 compound(0, NULL, 0);
#162
第
161
行是调用函数
compound
来分析复合语句。在
C
语言里由大括号组成的语句就是复合语句。
#163 definelab(cfunc->u.f.label);
#164 if (events.exit)
#165 apply(events.exit, cfunc, NULL);
#166
#167 walk(NULL, 0, 0);
#168
#169 exitscope();
#170 assert(level == PARAM);
#171
#172 foreach(identifiers, level, checkref, NULL);
#173 if (!IR->wants_callb && isstruct(rty))
#174 {
#175 Symbol *a;
#176 a = newarray(n + 2, sizeof *a, FUNC);
#177 a[0] = retv;
#178 memcpy(&a[1], callee, (n+1)*sizeof *callee);
#179 callee = a;
#180 a = newarray(n + 2, sizeof *a, FUNC);
#181 NEW(a[0], FUNC);
#182 *a[0] = *retv;
#183 memcpy(&a[1], caller, (n+1)*sizeof *callee);
#184 caller = a;
#185 }
#186
#187 if (!IR->wants_argb)
#188 {
#189 for (i = 0; caller[i]; i++)
#190 {
#191 if (isstruct(caller[i]->type))
#192 {
#193 caller[i]->type = ptr(caller[i]->type);
#194 callee[i]->type = ptr(callee[i]->type);
#195 caller[i]->structarg = callee[i]->structarg = 1;
#196 }
#197 }
#198 }
#199
#200 if (glevel > 1)
#201 for (i = 0; callee[i]; i++) callee[i]->sclass = AUTO;
#202
#203 if (cfunc->sclass != STATIC)
#204 (*IR->export)(cfunc);
#205
#206 if (glevel && IR->stabsym)
#207 {
#208 swtoseg(CODE); (*IR->stabsym)(cfunc);
#209 }
#210
#211 swtoseg(CODE);
#212
#213 (*IR->function)(cfunc, caller, callee, cfunc->u.f.ncalls);
#214
#215 if (glevel && IR->stabfend)
#216 (*IR->stabfend)(cfunc, lineno);
#217
#218 foreach(stmtlabs, LABELS, checklab, NULL);
#219
#220 exitscope();
#221
#222 expect('}');
#223 labels = stmtlabs = NULL;
#224 retv = NULL;
#225 cfunc = NULL;
#226 }
#227
上面这部分代码都是进行代码生成部份的处理。
函数定义的代码是很长的,已经粗略地分析它们的作用,下一次再来详细地分析它们。