UCC编译驱动分析

来源:互联网 发布:淘宝怎么投诉卖家电话 编辑:程序博客网 时间:2024/05/16 19:55

1.  UCC的组成

         UCC编译后,生成一个C语言编译器ucl和编译驱动ucc, ucl执行时将输入的C源文件编译输出预处理文件,而ucc则分析输入参数,根据参数调用

     不同的程序eg. gcc, as, ucl对输入文件执行相关的操作并输出结果。作者的工作目前是C编译器,预处理,汇编, 链接的功能都直接使用了现有的工

     具。

2.  预备知识

2.1  编译的流程

            通常,当需要编译C源文件时,只需要执行gcc/cc即可。实际上,gcc是一个编译驱动程序,它会依据编译参数依次调用预处理器CPP, 编译器CC, 汇编器AS, 连接器LD处理相关文件,最后输出可执行文件或者库文件。

            

2.2  链表List

        在程序中,输入文件集合,输出文件集合以及其他参数使用List来保存,该结构的定义,

        typedef struct list
        {
    char *str;
    struct list *next;
        } *List;

        以Append操作为例,分析List的使用,

        List ListAppend(List list, char *str)
        {
    List *tail = &list;
    List p = list;

    while (p != NULL)
    {
    tail = &p->next;
    p = p->next;
    }
    *tail = p = Alloc(sizeof(*p));
    p->str = str;
    p->next = NULL;


    return list;
     }

    我们注意到,在List的Append操作中使用了二级指针,使用二级指针的操作简练精致。

3.  ucc概览

3.1  编译选项分析

          ucc在开始执行时,会对编译选项进行分析,确定输入文件的阶段。

          -E,  输出预处理文件.

          -S, 输出汇编文件.

          -C, 输出目标文件

          -o, 输出可执行文件.

          -Wl,  链接器选项.

          -Wa, 汇编器选项.

          分析得到的数据放置在struct option, 该结构的定义,

           struct option
           {
       List pflags;  //预处理选项
       List cflags;  //编译选项
       List aflags;  //汇编选项
       List lflags;   //链接选项
       List cfiles;   //c源文件集合
       List pfiles;   //预处理文件集合
       List afiles;   //汇编文件集合
       List ofiles;   //目标文件集合
       List lfiles;    //库文件集合
       List linput;   //其他链接文件集合
       int verbose; //输出信息级别
       int oftype;     //输出文件类型, .i, .s, .o, .out
       char *out;     //最终输出文件名称
         };

3.2 编译过程

3.2.1 ucc的编译流程

              ucc与gcc的编译流程类似,在编译C源文件阶段,调用ucl执行编译任务,

              


        执行流程将根据ucc选项,将依次执行预处理,编译, 汇编,链接的阶段。

        enum { C_FILE, PP_FILE, ASM_FILE, OBJ_FILE, LIB_FILE, EXE_FILE };

         for (i = PP_FILE; i <= Option.oftype; ++i)
{
if (InvokeProgram(i) != 0)
{
RemoveFiles();
fprintf(stderr, "ucc invoke command error:");
PrintCommand();
return -1;
}
}        

3.2.3 预处理示例

              以预处理作为示例,进一步详细分析步骤,

               case PP_FILE:
for (p = Option.cfiles; p != NULL; p = p->next)
{
ofname = FileName(p->str, ".i");
PPFiles = ListAppend(PPFiles, ofname);
il = ListAppend(NULL, p->str);
ol = ListAppend(NULL, ofname);
cmd = BuildCommand(CPPProg, Option.pflags, il, ol);
status = Execute(cmd);
}
Option.pfiles = ListCombine(Option.pfiles, PPFiles);
break;       

               可以看到,首先将C源文件推出输出的预处理文件,将后缀改变为.i,合成命令序列,使用gcc做预处理,每次处理一个文件。