[转载]LCC编译器的源程序分析(4)处理文件参数

 
上面已经介绍选择不同的目标输出的参数处理,那么接着下来,自然的事情就是处理剩下的两个参数的问题,当然 LCC 是可以处理更多其它参数的,但这里只介绍两个文件参数的处理。命令行如下:
rcc.exe -target=x86/nasm hello.i hello.asm
其中 hello.i 是输入文件, hello.asm 是输出文件。那么 LCC 是怎么样打开输入文件和输出文件呢?输入文件又有什么技巧呢?要仔细地理解源程序,就知道它的输入处理是非常高效的。
当选择合适的目标输出后,就调用下面的函数来处理:
//
init(argc, argv);
这个函数就是用来处理其它参数的。它的源程序如下:
#001 void init(int argc, char *argv[])
#002 {
#003  {
#004         extern void input_init(int, char *[]);
#005         input_init(argc, argv);
#006  }
#007  
#008  {
#009         extern void main_init(int, char *[]);
#010         main_init(argc, argv);
#011  }
#012  
#013  {
#014         extern void type_init(int, char *[]);
#015         type_init(argc, argv);
#016  }
#017 }
1 行代码里传入了命令行的参数。
5 行代码是处理参数的处理。如果在第 5 行里调用没有处理 main_init ,那么在第 10 行里会再次调用它进行参数处理。
15 行调函数 type_init 进行类型初始化,比如 C 缺省的数据类型初始化,比如 int 类型,就初始化为 4 字节的有符号类型,还有很多其 C 默认的类型定义。
 
先来分析函数 input_init 的源程序是做什么工作的,下面就是它的程序:
#001 void input_init(int argc, char *argv[])
#002 {
#003  static int inited;
#004 
#005  if (inited)
#006         return;
#007 
#008  inited = 1;
#009  main_init(argc, argv);
#010 
#011  limit = cp = &buffer[MAXLINE+1];
#012  bsize = -1;
#013  lineno = 0;
#014  file = NULL;
#015 
#016  fillbuf();
#017  if (cp >= limit)
#018         cp = limit;
#019 
#020  nextline();
#021 }
 
5 行处理是否初始化,因为只允许初始化一次。第 8 行设置初始化变量为 1 ,让这段代码不要运行两次。
9 行调用主要参数处理函数。后面再接着介绍。
11 行让当前行指针和缓冲区指针指向输入缓冲区的尾部。
12 行初始化读取文件块大小为 -1 ,也就是读取文件失败的状态。
13 行设置分析的 C 程序行号为 0
14 行设置当前输入文件名称为空。
16 行是从输入文件里读取数据到输入缓冲区,同时设置当前处理的指针。
17 行判断当前指针是否大于数据缓冲区的指针。
20 行读取下一行源程序到缓冲区里。
 
调用函数 main_init 主要处理参数,并且打开输入的文件和输出的文件。它的程序如下:
#001 void main_init(int argc, char *argv[])
#002 {
#003  char *infile = NULL, *outfile = NULL;
#004  int i;
#005  static int inited;
#006 
#007  if (inited)
#008         return;
#009 
#010  inited = 1;
#011  for (i = 1; i < argc; i++)
#012         if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0)
#013               glevel = 2;
#014         else if (strncmp(argv[i], "-g", 2) == 0)
#015         {    /* -gn[,x] */
#016               char *p = strchr(argv[i], ',');
#017               glevel = atoi(argv[i]+2);
#018               if (p)
#019               {
#020                    comment = p + 1;
#021                    if (glevel == 0)
#022                          glevel = 1;
#023                    if (stabIR.stabline == NULL)
#024                    {
#025                          stabIR.stabline = IR->stabline;
#026                          stabIR.stabend = IR->stabend;
#027                          IR->stabline = stabline;
#028                          IR->stabend = stabend;
#029                    }
#030               }   
#031         }
#032         else if (strcmp(argv[i], "-x") == 0)
#033               xref++;
#034         else if (strcmp(argv[i], "-A") == 0)
#035         {
#036               ++Aflag;
#037         }
#038         else if (strcmp(argv[i], "-P") == 0)
#039               Pflag++;
#040         else if (strcmp(argv[i], "-w") == 0)
#041               wflag++;
#042         else if (strcmp(argv[i], "-v") == 0)
#043               fprint(stderr, "%s %s/n", argv[0], rcsid);
#044         else if (strncmp(argv[i], "-s", 2) == 0)
#045               density = strtod(&argv[i][2], NULL);
#046         else if (strncmp(argv[i], "-errout=", 8) == 0)
#047         {
#048               FILE *f = fopen(argv[i]+8, "w");
#049               if (f == NULL)
#050               {
#051                    fprint(stderr, "%s: can't write errors to `%s'/n", argv[0], argv[i]+8);
#052                    exit(EXIT_FAILURE);
#053               }
#054 
#055               fclose(f);
#056                f = freopen(argv[i]+8, "w", stderr);
#057               assert(f);
#058         }
#059         else if (strncmp(argv[i], "-e", 2) == 0)
#060         {
#061               int x;
#062               if ((x = strtol(&argv[i][2], NULL, 0)) > 0)
#063                    errlimit = x;
#064         }
#065         else if (strncmp(argv[i], "-little_endian=", 15) == 0)
#066               IR->little_endian = argv[i][15] - '0';
#067        else if (strncmp(argv[i], "-mulops_calls=", 18) == 0)
#068               IR->mulops_calls = argv[i][18] - '0';
#069         else if (strncmp(argv[i], "-wants_callb=", 13) == 0)
#070               IR->wants_callb = argv[i][13] - '0';
#071         else if (strncmp(argv[i], "-wants_argb=", 12) == 0)
#072               IR->wants_argb = argv[i][12] - '0';
#073         else if (strncmp(argv[i], "-left_to_right=", 15) == 0)
#074               IR->left_to_right = argv[i][15] - '0';
#075         else if (strncmp(argv[i], "-wants_dag=", 11) == 0)
#076               IR->wants_dag = argv[i][11] - '0';
#077         else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0)
#078         {
#079               if (infile == NULL)
#080                    infile = argv[i];
#081               else if (outfile == NULL)
#082                    outfile = argv[i];
#083         }
#084 
#085         if (infile != NULL && strcmp(infile, "-") != 0
#086               && freopen(infile, "r", stdin) == NULL)
#087         {
#088               fprint(stderr, "%s: can't read `%s'/n", argv[0], infile);
#089               exit(EXIT_FAILURE);
#090         }
#091 
#092         if (outfile != NULL && strcmp(outfile, "-") != 0
#093               && freopen(outfile, "w", stdout) == NULL)
#094         {
#095               fprint(stderr, "%s: can't write `%s'/n", argv[0], outfile);
#096               exit(EXIT_FAILURE);
#097         }
#098 }
 
7 行到第 10 行,同样是让这个函数只运行一次的代码。
79 行到第 82 行是读取输入文件和输出文件的名称。
85 行到第 90 行是打开输入的文件,并处理出错的情况。
92 行到第 97 行是打开输出的文件,并处理出错的情况。
其它代码就是处理其它参数的功能,这里就不详略地介绍了。
OK ,到这里就已经把输入的文件和输入的文件打开,准备好处理源程序的基础了。由于在函数 input_init 里已经调用 main_init ,后面再调用它已经是不再处理了。
 
下面再来看看函数 input_init 里调用的两个函数 fillbuf nextline 。先来看函数 fillbuf
#001 void fillbuf(void)
#002 {
#003  if (bsize == 0)
#004         return;
#005 
#006  if (cp >= limit)
#007         cp = &buffer[MAXLINE+1];
#008  else
#009  {
#010         int n = limit - cp;
#011         unsigned char *s = &buffer[MAXLINE+1] - n;
#012         assert(s >= buffer);
#013         line = (char *)s - ((char *)cp - line);
#014         while (cp < limit)
#015               *s++ = *cp++;
#016 
#017         cp = &buffer[MAXLINE+1] - n;
#018  }
#019 
#020  if (feof(stdin))
#021         bsize = 0;
#022  else
#023         bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin);
#024 
#025  if (bsize < 0)
#026  {
#027         error("read error/n");
#028         exit(EXIT_FAILURE);
#029  }
#030  limit = &buffer[MAXLINE+1+bsize];
#031  *limit = '/n';
#032 }
 
3 行处理读取数据为 0 的情况,这时就返回去,因为没有数据处理。
6 行处理在缓冲区里已经可以识别所有单词的情况,如果在行缓冲以后都不能识别出来的单词,这时又需从文件里读取数据出来,那么就需要把缓冲区后面的数据移到行缓冲最前面去,这样就可以把这些字符串可以拼接在一起进行处理了,第 10 行到 17 行就是做这样的事情。
20 行是判断是否读完文件,不是的话,在第 23 行里就读取缓冲区的大小字符串。
30 行调整缓冲区最后的指针,它是指向缓冲区的尾部的。
上面就实现了缓冲文件的输入,并且处理文件的顺序识别,当然也限制了一行代码是 512 个字节的大小,这也是 C 标准里定义一行代码最大的大小,所以写 C 程序时,一行代码是不能超过 512 个字节的。
 
已经分析了这么多内容,下一节再分析 nextline

你可能感兴趣的:([转载]LCC编译器的源程序分析(4)处理文件参数)