LCC编译器的源程序分析_第1页
LCC编译器的源程序分析_第2页
LCC编译器的源程序分析_第3页
LCC编译器的源程序分析_第4页
LCC编译器的源程序分析_第5页
已阅读5页,还剩202页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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循环语句118LCC编译器的源程序分析(31)do while循环语句120LCC编译器的源程序分析(32)for循环语句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)赋值表达式的有向无环图134LCC编译器的源程序分析(42)赋值表达式的有向无环图136LCC编译器的源程序分析(43)赋值表达式的有向无环图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)后端使用的节点结构164

6、LCC编译器的源程序分析(59)代码生成的源程序注释165LCC编译器的源程序分析(60)代码表的结构196LCC编译器的源程序分析(61)复合语句的代码块流程199LCC编译器的源程序分析(62)生成常量树节点的流程199LCC编译器的源程序分析(63)创建DAG森林的源程序200LCC编译器的源程序分析(64)符号表的结构注释201LCC编译器的源程序分析(65)后端接口的结构注释202LCC编译器的源程序分析(66)DAG树分析例子205LCC编译器的源程序分析(67)删除内存链表205LCC编译器的源程序分析(68)内存分配链表206LCC编译器的源程序分析(69)全局变量的初始化20

7、9LCC编译器的源程序分析(1)C编译器的目标先从简单的目标来分析这个大规模的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、生成目标文件,然后再用连接程序生成可执行文件。如果不能看懂上面的NASM汇编,就需要去看NASM手册了,这个手册在网上有下载。如果想更深入理解汇编生成机器码的过程,当然也可以深入分析NASM的程序实现。从上面的C和汇编也可以看出,汇编代码比C代码要复杂,行数也比较多,还分了数据段和代码段。所以使用C编译器是可以大大地提高生产效率的,并且更容易理解,这样就容易降低软件的成本,容易开发大规模的软件工程。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=参数。如果找到就跳出循环。程序的第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;接口定义了输出汇编目标代码需要的函数和数据成员。以后再一个函数一个函数地介绍。继续分析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字节的有符号类型,还有很多其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行让当前行指针和缓冲区指针指向输入缓冲区的尾部。第12行初始化读取文件块大小为-1,也就是读取文件失败的状态。第13行设置分析的C程序行号为0。第14行设置当前输入文件名称为空。第16行是从输入文件里读取数据到输入缓冲区,同时设置当前处理的指针。第17行判断当前指针是否大于数据缓冲区的指针。第20行读取下一行源

42、程序到缓冲区里。调用函数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. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论