上面已经介绍选择不同的目标输出的参数处理,那么接着下来,自然的事情就是处理剩下的两个参数的问题,当然
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
吧。