上面已經介紹選擇不同的目標輸出的引數處理,那麼接著下來,自然的事情就是處理剩下的兩個引數的問題,當然
lcc
rcc.exe -target=x86/na** hello.i hello.a** 其中
hello.i
是輸入檔案,
hello.a**
是輸出檔案。那麼
lcc是怎麼樣開啟輸入檔案和輸出檔案呢?輸入檔案又有什麼技巧呢?要仔細地理解源程式,就知道它的輸入處理是非常高效的。
當選擇合適的目標輸出後,就呼叫下面的函式來處理: //
init(argc, argv);
這個函式就是用來處理其它引數的。它的源程式如下:
#001 void init(int argc, char *argv)
#002
#007
#008
#012
#013
#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 第
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
#030 }
#031 }
#032 else if (strcmp(argv[i], "-x") == 0)
#033 xref++;
#034 else if (strcmp(argv[i], "-a") == 0)
#035
#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
#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
#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
#084
#085 if (infile != null && strcmp(infile, "-") != 0
#086 && freopen(infile, "r", stdin) == null)
#087
#091
#092 if (outfile != null && strcmp(outfile, "-") != 0
#093 && freopen(outfile, "w", stdout) == null)
#094
#098 } 第
7行到第
10行,同樣是讓這個函式只執行一次的**。 第
79行到第
82行是讀取輸入檔案和輸出檔案的名稱。 第
85行到第
90行是開啟輸入的檔案,並處理出錯的情況。 第
92行到第
97行是開啟輸出的檔案,並處理出錯的情況。
其它**就是處理其它引數的功能,這裡就不詳略地介紹了。 ok
,到這裡就已經把輸入的檔案和輸入的檔案開啟,準備好處理源程式的基礎了。由於在函式
input_init
裡已經呼叫
main_init
,後面再呼叫它已經是不再處理了。
下面再來看看函式
input_init
裡呼叫的兩個函式
fillbuf
和nextline
。先來看函式
fillbuf:
#001 void fillbuf(void)
#002
#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
#030 limit = &buffer[maxline+1+bsize];
#031 *limit = '/n';
#032 } 第
3行處理讀取資料為
0的情況,這時就返回去,因為沒有資料處理。 第
6行處理在緩衝區裡已經可以識別所有單詞的情況,如果在行緩衝以後都不能識別出來的單詞,這時又需從檔案裡讀取資料出來,那麼就需要把緩衝區後面的資料移到行緩衝最前面去,這樣就可以把這些字串可以拼接在一起進行處理了,第
10行到
17行就是做這樣的事情。 第
20行是判斷是否讀完檔案,不是的話,在第
23行裡就讀取緩衝區的大小字串。 第
30行調整緩衝區最後的指標,它是指向緩衝區的尾部的。
上面就實現了緩衝檔案的輸入,並且處理檔案的順序識別,當然也限制了一行**是
512個位元組的大小,這也是
c標準裡定義一行**最大的大小,所以寫
c程式時,一行**是不能超過
512個位元組的。
已經分析了這麼多內容,下一節再分析
nextline
吧。
LCC編譯器的源程式分析 12 13
語法分析是比較複雜的處理,下面再來分析乙個例子,它的 如下 typedef unsigned short wchar t typedef wchar t wint t 第一句語句在lcc裡的處理,前面已經解釋清楚,主要生成wchar t儲存符號表裡,並且記錄這個id的型別屬性。那麼第二句是怎麼樣通過...
LCC編譯器的源程式分析 18 19
lcc編譯器的源程式分析 19 全域性函式的定義 函式定義funcdefn處理裡,已經準備好呼叫引數和引數返回,接著就是呼叫全域性函式宣告來處理。如下面的 132 宣告函式。133 cfunc dclglobal sclass,id,ty,pt 134 上面的 是處理函式全域性定義。現在就去就分析d...
LCC編譯器的源程式分析 20 復合語句
在 c語言裡,有一種語句叫做復合語句。它是由 把一些語句括起來的,如下面的例子 在lcc 裡處理這樣的復合語句的函式是 compound 它在上面函式定義函式 funcdefn 是這樣呼叫的 150labels table null,labels 151stmtlabs table null,lab...