当把所有的源程序生成
DAG
表示后,就进入了编译器的最后处理阶段,
LCC
是把
DAG
生成汇编的目标代码。在这一阶段,编译器为源程序定义和使用的变量选择存储单元,并把中间指令翻译成完成相同任务的汇编代码指令序列。在代码生成里,需要处理的问题是存储管理、指令选择、寄存器分配、计算次序等等。
在第一节里就已经看到了汇编代码生成,函数的名称生成如下:
#001 [global $main]
那么在
LCC
是怎么样生成上面的函数名称呢?现在就跟我来分析它的代码。
先从函数里
funcdefn
里调用代码:
#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;
第
203
行就是判断函数是否静态函数,如果不是静态函数,就会调用后端的接口来生成函数的名称。
第
204
行的调用接口的代码如下:
#001 static void export(Symbol p)
#002 {
#003
#004 #if 0
#005 print("public %s/n", p->x.name);
#006 #else
#007 print("[global %s]/n", p->x.name);
#008 #endif
#009
#010 }
由于
IR->export
是一个函数指针,只要设置不同的函数指针,就可以生成不同的函数名称。这就是
LCC
可以生成不同机器代码的原因。
第
7
行里是生成函数的名称
main
,它是调用
print
函数输出到文件里。
p->x.name
是符号表里的函数名称。很简单吧,就这样可以生成不同的函数名称了。