LCC编译器的源程序分析(18)函数定义

激动人心的时刻就要开始了,从这节开始,就进入处理实际的代码了。由于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
上面这部分代码都是进行代码生成部份的处理。
函数定义的代码是很长的,已经粗略地分析它们的作用,下一次再来详细地分析它们。

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