LCC編譯器的源程序分析_第1頁
LCC編譯器的源程序分析_第2頁
LCC編譯器的源程序分析_第3頁
LCC編譯器的源程序分析_第4頁
LCC編譯器的源程序分析_第5頁
已閱讀5頁,還剩202頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、(摘自:h)LCC編譯器的源程序分析(1)C編譯器的目標2LCC編譯器的源程序分析(2)LCC編譯器的預處理4LCC編譯器的源程序分析(3)選擇不同的目標代碼接口7LCC編譯器的源程序分析(4)處理文件參數10LCC編譯器的源程序分析(5)行號同步與類型初始化15LCC編譯器的源程序分析(6)詞法分析21LCC編譯器的源程序分析(7)詞法分析23LCC編譯器的源程序分析(8)語法分析的開始35LCC編譯器的源程序分析(9)聲明分析41LCC編譯器的源程序分析(10)聲明類型47LCC編譯器的源程序分析(11)聲明與符號表51LCC編譯器的源程序分析(12)自定義類型的聲明55LCC編譯器的源程

2、序分析(13)指針類型的聲明57LCC編譯器的源程序分析(14)結構類型的聲明59LCC編譯器的源程序分析(15)結構類型成員的聲明62LCC編譯器的源程序分析(16)函數的聲明66LCC編譯器的源程序分析(17)參數變量的聲明71LCC編譯器的源程序分析(18)函數定義73LCC編譯器的源程序分析(19)全局函數的定義80LCC編譯器的源程序分析(20)復合語句83LCC編譯器的源程序分析(21)局部變量的聲明87LCC編譯器的源程序分析(22)基本表達式92LCC編譯器的源程序分析(23)一元運算表達式96LCC編譯器的源程序分析(24)條件表達式101LCC編譯器的源程序分析(25)賦值

3、表達式102LCC編譯器的源程序分析(26)逗號表達式103LCC編譯器的源程序分析(27)基本語句104LCC編譯器的源程序分析(28)函數表達式語句111LCC編譯器的源程序分析(29)if條件語句117LCC編譯器的源程序分析(30)while循環(huán)語句118LCC編譯器的源程序分析(31)do while循環(huán)語句120LCC編譯器的源程序分析(32)for循環(huán)語句121LCC編譯器的源程序分析(33)break語句123LCC編譯器的源程序分析(34)continue語句124LCC編譯器的源程序分析(35)switch語句125LCC編譯器的源程序分析(36)case語句127LCC編

4、譯器的源程序分析(37)default語句129LCC編譯器的源程序分析(38)return語句129LCC編譯器的源程序分析(39)goto語句130LCC編譯器的源程序分析(40)賦值表達式樹132LCC編譯器的源程序分析(41)賦值表達式的有向無環(huán)圖134LCC編譯器的源程序分析(42)賦值表達式的有向無環(huán)圖136LCC編譯器的源程序分析(43)賦值表達式的有向無環(huán)圖138LCC編譯器的源程序分析(44)函數名稱的代碼生成139LCC編譯器的源程序分析(45)函數代碼入口和出口的代碼生成140LCC編譯器的源程序分析(46)計算需要使用棧大小143LCC編譯器的源程序分析(47)計算需要

5、使用棧大小145LCC編譯器的源程序分析(48) 寄存器分配146LCC編譯器的源程序分析(49) 寄存器分配147LCC編譯器的源程序分析(50) 分配一個寄存器148LCC編譯器的源程序分析(51) 分配一個寄存器149LCC編譯器的源程序分析(52)寄存器溢出151LCC編譯器的源程序分析(53)指令的選擇154LCC編譯器的源程序分析(54)指令模式匹配155LCC編譯器的源程序分析(55)最終代碼的生成161LCC編譯器的源程序分析(56)寄存器分配的屬性結構162LCC編譯器的源程序分析(57)不同目標代碼生成的接口結構163LCC編譯器的源程序分析(58)后端使用的節(jié)點結構164

6、LCC編譯器的源程序分析(59)代碼生成的源程序注釋165LCC編譯器的源程序分析(60)代碼表的結構196LCC編譯器的源程序分析(61)復合語句的代碼塊流程199LCC編譯器的源程序分析(62)生成常量樹節(jié)點的流程199LCC編譯器的源程序分析(63)創(chuàng)建DAG森林的源程序200LCC編譯器的源程序分析(64)符號表的結構注釋201LCC編譯器的源程序分析(65)后端接口的結構注釋202LCC編譯器的源程序分析(66)DAG樹分析例子205LCC編譯器的源程序分析(67)刪除內存鏈表205LCC編譯器的源程序分析(68)內存分配鏈表206LCC編譯器的源程序分析(69)全局變量的初始化20

7、9LCC編譯器的源程序分析(1)C編譯器的目標先從簡單的目標來分析這個大規(guī)模的C編譯器,畢竟它的功能比較復雜,并且源程序的行數也是非常多的。因此,把簡單的目標定出來,然后再分析它,這樣才會有的放矢。接著再跟著編譯運行的主線來分析它的源程序。下面先看一下簡單的C例子,如下:#001 #include <stdio.h>#002 #003 int main(void)#004 #005 int nTest1 = 1;#006 int nTest2 = 2;#007 int nTest3;#008 int i;#009 #010 nTest3 = nTest1 + nTest2;#011

8、 printf("nTest3 = %drn",nTest3);#012 #013 for (i = 0; i < 5; i+)#014 #015 printf("%drn",nTest3+i);#016 #017 #018 printf(_TIME_" "_DATE_"rnhello worldn");#019 return 0;#020 #021 上面的程序就是用來說明編譯器工作的例子,它在第一行里包含了頭文件,由于后面調用printf函數輸出顯示到屏幕里。第二行空行,第三行是main函數,它是C程序的入

9、口函數。在main函數里,定義了幾個局部變量,分別第5,6,7,8行的變量。第10行作兩個變量nTest1和nTest2的加法,然后賦值給變量nTest3。第11行顯示變量nTest3的值,是用10進制輸出顯示。在第13到16行是5次輸出nTest3+i值。在第18行里輸出編譯這個程序的時間和hello world的字符串。C編譯器的任務,就是把上面的源程序變換到匯編代碼輸出,或者變成其它中間代碼輸出。在這里LCC編譯器是輸出匯編代碼的,所以就不介紹其它的中間代碼輸出。那么LCC把上面的源程序變成什么樣的匯編輸出呢?下面就先把它的目標代碼看一下,如下:#001 global $main#002

10、 section .text#003 $main:#004 push ebx#005 push esi#006 push edi#007 push ebp#008 mov ebp, esp#009 sub esp, 16#010 mov dword ebp + -12, 1#011 mov dword ebp + -16, 2#012 mov edi, dword ebp + -12#013 mov esi, dword ebp + -16#014 lea edi, esi + edi#015 mov dword ebp + -8, edi#016 mov edi, dword ebp + -

11、8#017 push dword edi#018 lea edi, $L2#019 push dword edi#020 call $printf#021 add esp, 8#022 mov dword ebp + -4, 0#023 $L3:#024 mov edi, dword ebp + -8#025 mov esi, dword ebp + -4#026 lea edi, esi + edi#027 push dword edi#028 lea edi, $L7#029 push dword edi#030 call $printf#031 add esp, 8#032 $L4:#0

12、33 inc dword ebp + -4#034 cmp dword ebp + -4, 5#035 jl near $L3#036 lea edi, $L8#037 push dword edi#038 call $printf#039 add esp, 4#040 mov eax, 0#041 $L1:#042 mov esp, ebp#043 pop ebp#044 pop edi#045 pop esi#046 pop ebx#047 ret#048 extern $printf#049 section .data#050 times ($-$) & 0 nop#051 $L

13、8:#052 db '00:30:28 Apr 07 2007', 13, 10, 'hello world', 10, 0#053 times ($-$) & 0 nop#054 $L7:#055 db '%d', 13, 10, 0#056 times ($-$) & 0 nop#057 $L2:#058 db 'nTest3 = %d', 13, 10, 0#059 LCC是可以生成很多目標代碼的C編譯器,在這里主要介紹生成X86的NASM匯編的代碼。上面的匯編代碼就是NASM的匯編格式,可以使用NASM編譯

14、生成目標文件,然后再用連接程序生成可執(zhí)行文件。如果不能看懂上面的NASM匯編,就需要去看NASM手冊了,這個手冊在網上有下載。如果想更深入理解匯編生成機器碼的過程,當然也可以深入分析NASM的程序實現。從上面的C和匯編也可以看出,匯編代碼比C代碼要復雜,行數也比較多,還分了數據段和代碼段。所以使用C編譯器是可以大大地提高生產效率的,并且更容易理解,這樣就容易降低軟件的成本,容易開發(fā)大規(guī)模的軟件工程。LCC編譯器的源程序分析(2)LCC編譯器的預處理上面已經介紹了C編譯器的目標,其實在實現這個目標之前,是經歷了很多階段處理的,其中第一個階段的處理,就是預處理。預處理的任務是做什么呢?在LCC里預

15、處理主要是把所有包含的頭文件和源程序生成一個中間文件,并且把所有宏展開,替換為真實的值。前面介紹的例子源程序,經過預處理后,就會生成下面的代碼,如下:#line 1 "hello.c"#line 1 "include/stdio.h"typedef unsigned int size_t;typedef unsigned short wchar_t;typedef wchar_t wint_t;typedef wchar_t wctype_t;typedef char * va_list;#line 39 "include/stdio.h&qu

16、ot;struct _iobuf char *_ptr; int _cnt; char *_base;int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; ;typedef struct _iobuf FILE;extern FILE *_iob;typedef long fpos_t;extern FILE (*_imp_iob);int _filbuf(FILE *);int flsbuf(int, FILE *);FILE * _fsopen(const char *, const char *, int);v

17、oid clearerr(FILE *);int fclose(FILE *);int _fcloseall(void);FILE * fdopen(int, const char *);int feof(FILE *);int ferror(FILE *);int fflush(FILE *);int fgetc(FILE *);wchar_t fgetwc(FILE *);wchar_t getwc(FILE *);int _fgetchar(void);int fgetpos(FILE *, fpos_t *);char * fgets(char *, int, FILE *);int

18、fileno(FILE *);int _flushall(void);FILE * fopen(const char *, const char *);int fprintf(FILE *, const char *, .);int xfprintf(FILE *,const char *,.);int fputc(int, FILE *);int _fputchar(int);int fputs(const char *, FILE *);size_t fread(void *, size_t, size_t, FILE *);FILE * freopen(const char *, con

19、st char *, FILE *);int fscanf(FILE *, const char *, .);int xfscanf(FILE *,const char *,.);int fsetpos(FILE *, const fpos_t *);int fseek(FILE *, long, int);long ftell(FILE *);size_t fwrite(const void *, size_t, size_t, FILE *);int getc(FILE *);int getchar(void);char * gets(char *);int getw(FILE *);in

20、t _pclose(FILE *);FILE * popen(const char *, const char *);int printf(const char *, .);int xprintf(const char *,.);int dprintf(const char *, .);int putc(int, FILE *);int putchar(int);int puts(const char *);int _putw(int, FILE *);int remove(const char *);int rename(const char *,const char *);void rew

21、ind(FILE *);int _rmtmp(void);int scanf(const char *, .);int xscanf(const char *,.);void setbuf(FILE *, char *);int setvbuf(FILE *, char *, int, size_t);int _snprintf(char *, size_t, const char *, .);int sprintf(char *, const char *, .);int xsprintf(char *, const char *, .);int snprintf(char *,size_t

22、,const char *,.);int xsnprintf(char *,size_t,const char *,.);int sscanf(const char *, const char *, .);int xsscanf(const char *,const char *,.);char * _tempnam(char *, char *);FILE * tmpfile(void);char * tmpnam(char *);char *tempnam(char *,char *);int ungetc(int, FILE *);int _unlink(const char *);in

23、t vfprintf(FILE *, const char *, va_list);int vprintf(const char *, va_list);int _vsnprintf(char *, size_t, const char *, va_list);int _vsnwprintf(wchar_t *, size_t, const wchar_t *, va_list);int vsnprintf(char *,size_t,const char *,va_list);int xvsnprintf(char *,size_t,const char *,va_list);int xvs

24、nprintf(char *,size_t,const char *,va_list);int vsprintf(char *, const char *, va_list);int xvsprintf(char *, const char *, va_list);void perror(const char *);void _wperror(const wchar_t *);#line 2 "hello.c"int main(void) int nTest1 = 1; int nTest2 = 2; int nTest3;int i; nTest3 = nTest1 +

25、nTest2; printf("nTest3 = %drn",nTest3); for (i = 0; i < 5; i+) printf("%drn",nTest3+i); printf("00:30:28"" ""Apr 07 2007""rnhello worldn"); return 0;現在就來分析一下經過預處理的中間文件。#line 1 "hello.c"這行告訴編譯器要編譯的源文件名稱和行號。這里是hello.c的第一行。#line 1

26、 "include/stdio.h"在hello.c的第一行里包含了一個頭文件include/stdio.h,而這個頭文件源程序緊跟著后面,直到#line 2 "hello.c"行前,都是包含的頭文件源程序。在那行的后面才是hello.c的源程序,可以看到在main函數里的宏定義也被替換掉了。如下:printf("00:30:28"" ""Apr 07 2007""rnhello worldn");預處理把宏定義_TIME_變成了"00:30:28"字符串

27、,把宏定義_DATE_變成了"Apr 07 2007"。這兩個宏定義生成的字符串跟編譯時間相關,其實就是把當前編譯的時間生成字符放到相應的位置。上面的中間源程序是LCC預處理生成樣子,沒有刪除任何一行,即使是空行也沒有刪除一行。其實在C里,還有使用#define定義的宏定義,也會替換掉的。因此,在宏定義處理里,沒有復雜的計算,只是字符串的替換。在這里沒有介紹完整的預處理代碼,因為把主要精力放到C編譯器去。C編譯器就是接收上面這樣的中間文件,進行編譯處理的。 LCC編譯器的源程序分析(3)選擇不同的目標代碼接口在LCC里,最重要的一個特征是可以輸出不同的目標代碼。比如同一個C

28、程序,可以生成MIPS,X86等匯編代碼,只需要選擇不同的目標參數。這里只分析生成X86的代碼,所以命令行的參數如下:參數-target=x86/nasm是讓C編譯器選擇生成X86的NASM匯編代碼。參數是前面已經介紹的中間文件,它是經過預處理的。參數是生成的目標文件。C編譯的入口函數是main,它在文件里,定義如下:/int main(int argc, char *argv)在main函數開始里,就是處理參數的代碼,如下:#001 int main(int argc, char *argv) #002 #003 int i, j;#004 #005 for (i = argc - 1; i

29、 > 0; i-)#006 #007 if (strncmp(argvi, "-target=", 8) = 0)#008 #009 break;#010 #011 #012 #013 if (i > 0) #014 #015 char *s = strchr(argvi, '');#016 if (s != NULL)#017 #018 *s = '/'#019 #020 #021 for (j = 0; && bindingsj.ir; j+)#022 #023 if (strcm

30、p(&argvi8, ) = 0) #024 #025 IR = bindingsj.ir;#026 break;#027 #028 #029 #030 if (s != NULL)#031 #032 *s = ''#033 #034 #035 #036 if (!IR) #037 #038 fprint(stderr, "%s: unknown target", argv0);#039 if (i > 0)#040 #041 fprint(stderr, " %s'", &arg

31、vi8);#042 #043 #044 fprint(stderr, " must specify one ofn");#045 #046 for (i = 0; ; i+)#047 #048 fprint(stderr, "t-target=%sn", );#049 #050 #051 exit(EXIT_FAILURE);#052 程序的第5行到第11行是找到目標代碼的參數,也就是識別-target=參數。如果找到就跳出循環(huán)。程序的第13行到第34行是找到相應的生成目標代碼的接口。C編譯器已經定

32、義好可以生成代碼的數組,因此這里只需要簡單地比較一下名稱,就可以找到相應的目標代碼的接口了。接口定義的結構如下:typedef struct binding char *name; Interface *ir; Binding;name保存目標代碼的名稱,ir保存了接口。而接口定義如下:#001 typedef struct interface #002 Metrics charmetric;#003 Metrics shortmetric;#004 Metrics intmetric;#005 Metrics longmetric;#006 Metrics longlongmetric;#0

33、07 Metrics floatmetric;#008 Metrics doublemetric;#009 Metrics longdoublemetric;#010 Metrics ptrmetric;#011 Metrics structmetric;#012 unsigned little_endian:1;#013 unsigned mulops_calls:1;#014 unsigned wants_callb:1;#015 unsigned wants_argb:1;#016 unsigned left_to_right:1;#017 unsigned wants_dag:1;#0

34、18 unsigned unsigned_char:1;#019 void (*address)(Symbol p, Symbol q, long n);#020 void (*blockbeg)(Env *);#021 void (*blockend)(Env *);#022 void (*defaddress)(Symbol);#023 void (*defconst) (int suffix, int size, Value v);#024 void (*defstring)(int n, char *s);#025 void (*defsymbol)(Symbol);#026 void

35、 (*emit) (Node);#027 void (*export)(Symbol);#028 void (*function)(Symbol, Symbol, Symbol, int);#029 Node (*gen) (Node);#030 void (*global)(Symbol);#031 void (*import)(Symbol);#032 void (*local)(Symbol);#033 void (*progbeg)(int argc, char *argv);#034 void (*progend)(void);#035 void (*segment)(int);#0

36、36 void (*space)(int);#037 void (*stabblock)(int, int, Symbol*);#038 void (*stabend) (Coordinate *, Symbol, Coordinate *, Symbol *, Symbol *);#039 void (*stabfend) (Symbol, int);#040 void (*stabinit) (char *, int, char *);#041 void (*stabline) (Coordinate *);#042 void (*stabsym) (Symbol);#043 void (

37、*stabtype) (Symbol);#044 Xinterface x;#045 Interface;接口定義了輸出匯編目標代碼需要的函數和數據成員。以后再一個函數一個函數地介紹。繼續(xù)分析main函數里,第36行到第52行是找不到生成目標代碼接口的出錯處理。命令行的參數是-target=x86/nasm,所以找到的接口,就是x86/name的接口,它保存在IR全局變量里。到這里,就分析完成選擇不同的目標代碼生成接口了。LCC編譯器的源程序分析(4)處理文件參數上面已經介紹選擇不同的目標輸出的參數處理,那么接著下來,自然的事情就是處理剩下的兩個參數的問題,當然LCC是可以處理更多其它參數的,

38、但這里只介紹兩個文件參數的處理。命令行如下:其中是輸入文件,是輸出文件。那么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 e

39、xtern 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字節(jié)的有符號類型,還有很多其C默認的類

40、型定義。先來分析函數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 = &bufferMAXLINE+1;#012 bsize = -1;#013 lineno = 0;#014 file = NULL;#015 #016 fill

41、buf();#017 if (cp >= limit)#018 cp = limit;#019 #020 nextline();#021 第5行處理是否初始化,因為只允許初始化一次。第8行設置初始化變量為1,讓這段代碼不要運行兩次。第9行調用主要參數處理函數。后面再接著介紹。第11行讓當前行指針和緩沖區(qū)指針指向輸入緩沖區(qū)的尾部。第12行初始化讀取文件塊大小為-1,也就是讀取文件失敗的狀態(tài)。第13行設置分析的C程序行號為0。第14行設置當前輸入文件名稱為空。第16行是從輸入文件里讀取數據到輸入緩沖區(qū),同時設置當前處理的指針。第17行判斷當前指針是否大于數據緩沖區(qū)的指針。第20行讀取下一行源

42、程序到緩沖區(qū)里。調用函數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(argvi, "-g")

43、= 0 | strcmp(argvi, "-g2") = 0)#013 glevel = 2;#014 else if (strncmp(argvi, "-g", 2) = 0) #015 /* -gn,x */#016 char *p = strchr(argvi, ',');#017 glevel = atoi(argvi+2);#018 if (p) #019 #020 comment = p + 1;#021 if (glevel = 0)#022 glevel = 1;#023 if (stabIR.stabline = NUL

44、L) #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(argvi, "-x") = 0)#033 xref+;#034 else if (strcmp(argvi, "-A") = 0) #035 #036 +Aflag;#037 #038 else

45、 if (strcmp(argvi, "-P") = 0)#039 Pflag+;#040 else if (strcmp(argvi, "-w") = 0)#041 wflag+;#042 else if (strcmp(argvi, "-v") = 0)#043 fprint(stderr, "%s %sn", argv0, rcsid);#044 else if (strncmp(argvi, "-s", 2) = 0)#045 density = strtod(&argvi2,

46、NULL);#046 else if (strncmp(argvi, "-errout=", 8) = 0) #047 #048 FILE *f = fopen(argvi+8, "w");#049 if (f = NULL) #050 #051 fprint(stderr, "%s: can't write errors to %s'n", argv0, argvi+8);#052 exit(EXIT_FAILURE);#053 #054 #055 fclose(f);#056 f = freopen(argvi+8

47、, "w", stderr);#057 assert(f);#058 #059 else if (strncmp(argvi, "-e", 2) = 0) #060 #061 int x;#062 if (x = strtol(&argvi2, NULL, 0) > 0)#063 errlimit = x;#064 #065 else if (strncmp(argvi, "-little_endian=", 15) = 0)#066 IR->little_endian = argvi15 - '0'

48、;#067 else if (strncmp(argvi, "-mulops_calls=", 18) = 0)#068 IR->mulops_calls = argvi18 - '0'#069 else if (strncmp(argvi, "-wants_callb=", 13) = 0)#070 IR->wants_callb = argvi13 - '0'#071 else if (strncmp(argvi, "-wants_argb=", 12) = 0)#072 IR->

49、wants_argb = argvi12 - '0'#073 else if (strncmp(argvi, "-left_to_right=", 15) = 0)#074 IR->left_to_right = argvi15 - '0'#075 else if (strncmp(argvi, "-wants_dag=", 11) = 0)#076 IR->wants_dag = argvi11 - '0'#077 else if (*argvi != '-' | strcmp

50、(argvi, "-") = 0) #078 #079 if (infile = NULL)#080 infile = argvi;#081 else if (outfile = NULL)#082 outfile = argvi;#083 #084 #085 if (infile != NULL && strcmp(infile, "-") != 0#086 && freopen(infile, "r", stdin) = NULL) #087 #088 fprint(stderr, "%s

51、: can't read %s'n", argv0, 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", argv0, outfile);

52、#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(vo

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論