上面439行,如果文件找到并成功打开,_cpp_find_file将对应的_cpp_file对象返回,交由pfile->main_file保存。由此,可以开始读入文件的内容。
cpp_read_main_file (continue)
473 _cpp_stack_file (pfile, pfile->main_file, false);
474
475 /* For foo.i, read the original filename foo.c now, for the benefit
476 of the front ends. */
477 if (CPP_OPTION (pfile, preprocessed))
478 {
479 read_original_filename (pfile);
480 if (!pfile->map)
481 return NULL;
482 fname = pfile->map->to_file;
483 }
484 return fname;
485 }
在以下函数中,参数import为true,如果文件是由#import指示包含的。关于#import指示,【6】给出如下解释。
GNU CPP支持2种方式来表示一个头文件只应被读入一次。但它们都不如#ifdef那样具有可移植性,建议在新的程序中不要使用。 在Objective-C语言中,有#include的一个变体,叫#import,它引入(include)一个文件,但最多只引入一次。如果你使用了#import而不是#include,那么你不需要在头文件中加入条件语句来防止多次包含。GCC也允许在C及C++中使用#import。然而它不是C或C++的标准,因此不应为可移植程序使用。 #import不是一个实现得很好的特性。它要求头文件的使用者知道这个文件只应被包含一次。头文件的实现者写的头文件不需要使用者知道这些的话,要比这好的多。#ifndef能实现这一目标。 在当前的实现中,单个#import就会使得文件通过#import或#include都不能被重新读入。 但你不能依赖这一点,不要同时使用#import及#include来引用同一个头文件。 另一个防止头文件被多次引入的方法是#pragma once指示。如果在扫描一个头文件时,看到#pragm once,不管怎样,这个文件以后不会再读入了。 #pragma once没有#import的问题,但不是所有的预处理器都能识别它,因此不要在可移植程序中依赖它。 |
643 bool
644 _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) in cppfiles.c
645 {
646 cpp_buffer *buffer;
647 int sysp;
648
649 if (!should_stack_file (pfile, file, import))
640 return false;
这里,对于由#import指示包含的头文件,once_only,seen_once_only在563行被_cpp_mark_file_once_only设置,因此下次该文件又开始被读入时,它将在556行退出。而这在572行,则是测试文件是否定义了守卫宏(header guard)。
549 static bool
550 should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) in cppfiles.c
551 {
552 _cpp_file *f;
553
554 /* Skip once-only files. */
555 if (file->once_only)
556 return false;
557
558 /* We must mark the file once-only if #import now, before header
559 guard checks. Otherwise, undefining the header guard might
560 cause the file to be re-stacked. */
561 if (import)
562 {
563 _cpp_mark_file_once_only (pfile, file);
564
565 /* Don't stack files that have been stacked before. */
566 if (file->stack_count)
567 return false;
568 }
569
570 /* Skip if the file had a header guard and the macro is defined.
571 PCH relies on this appearing before the PCH handler below. */
572 if (file->cmacro && file->cmacro->type == NT_MACRO)
573 return false;
574
575 /* Handle PCH files immediately; don't stack them. */
576 if (include_pch_p (file))
577 {
578 pfile->cb.read_pch (pfile, file->path, file->fd, file->pchname);
579 close (file->fd);
580 file->fd = -1;
581 return false;
582 }
上面576行,include_pch_p通过检查_cpp_file的pch域来确定文件是否是PCH,这个域在pch_open_file中设置,如果这个PCH文件是有效的。
375 void
376 c_common_read_pch (cpp_reader *pfile, const char *name, in c-pch.c
377 int fd, const char *orig_name ATTRIBUTE_UNUSED)
378 {
379 FILE *f;
380 struct c_pch_header h;
381 char *buf;
382 unsigned long written;
383 struct save_macro_data *smd;
384
385 f = fdopen (fd, "rb");
386 if (f == NULL)
387 {
388 cpp_errno (pfile, CPP_DL_ERROR, "calling fdopen");
389 return;
390 }
391
392 cpp_get_callbacks (parse_in)->valid_pch = NULL;
393
394 if (fread (&h, sizeof (h), 1, f) != 1)
395 {
396 cpp_errno (pfile, CPP_DL_ERROR, "reading");
397 return;
398 }
399
400 buf = xmalloc (16384);
401 for (written = 0; written < h.asm_size; )
402 {
403 long size = h.asm_size - written;
404 if (size > 16384)
405 size = 16384;
406 if (fread (buf, size, 1, f) != 1
407 || fwrite (buf, size, 1, asm_out_file) != 1)
408 cpp_errno (pfile, CPP_DL_ERROR, "reading");
409 written += size;
410 }
411 free (buf);
412
413 cpp_prepare_state (pfile, &smd);
414
415 gt_pch_restore (f);
416
417 if (cpp_read_state (pfile, name, f, smd) != 0)
418 return;
419
420 fclose (f);
421 }
注意到此处fd指向已经打开的有效的PCH文件,在上面385行的fdopen,我们可以继续从文件中target_data后的位置读入文件。在那个位置中应该包含c_pch_header,而这个结构仅含有一个域asm_size,它表示这个PCH文件的汇编形式内容大小。这部分内容直接写入asm_out_file。
如果预处理头文件仅是包含汇编代码,它与库文件有何区别呢?我们又如何能使用在其中定义的数据结构和函数呢?因此,在汇编代码部分的后面,PCH文件还包括了中间树形式的内容,读入这部分内容并与当前编译单元的中间树合并,PCH文件的行为即与普通头文件无异。
589 void
590 cpp_prepare_state (cpp_reader *r, struct save_macro_data **data) in cpppch.c
591 {
592 struct save_macro_data *d = xmalloc (sizeof (struct save_macro_data));
593
594 d->macros = NULL;
595 d->count = ARRAY_SIZE (d->macros->macs);
596 cpp_forall_identifiers (r, save_macros, d);
597 d->saved_pragmas = _cpp_save_pragma_names (r);
598 *data = d;
599 }
在cpp_reader中,它包含了域hash_table,这个域首先由_cpp_init_hashtable初始化。在预处理阶段,它用作文件中可见宏的哈希表。cpp_reader的实例一直代表当前处理的文件,因此现在我们正要处理PCH头文件,我们需要更新cpp_reader实例,首先需要保存当前文件中已见过的宏。
546 struct save_macro_item { in cpppch.c
547 struct save_macro_item *next;
548 struct cpp_hashnode macs[64];
549 };
551 struct save_macro_data
552 {
553 struct save_macro_item *macros;
554 size_t count;
555 char **saved_pragmas;
556 };
注意在cpp_prepare_state的595行,对于新建的缓存(buffer)count是64。
112 void
113 cpp_forall_identifiers (cpp_reader *pfile, cpp_cb cb, void *v) in cpppch.c
114 {
115 /* We don't need a proxy since the hash table's identifier comes
116 first in cpp_hashnode. */
117 ht_forall (pfile->hash_table, (ht_cb) cb, v);
118 }
209 void
210 ht_forall (hash_table *table, ht_cb cb, const void *v) in hashtable.c
211 {
212 hashnode *p, *limit;
213
214 p = table->entries;
215 limit = p + table->nslots;
216 do
217 if (*p)
218 {
219 if ((*cb) (table->pfile, *p, v) == 0)
220 break;
221 }
222 while (++p < limit);
223 }
下面HT_STR及HT_LEN分别访问cpp_hashnode的ht_identifier域中的str和len域。注意ht_identifier是cpp_hashnode的主体,并且是哈希表的规范节点。
561 static int in cpppch.c
562 save_macros (cpp_reader *r ATTRIBUTE_UNUSED, cpp_hashnode *h, void *data_p)
563 {
564 struct save_macro_data *data = (struct save_macro_data *)data_p;
565 if (h->type != NT_VOID
566 && (h->flags & NODE_BUILTIN) == 0)
567 {
568 cpp_hashnode *save;
569 if (data->count == ARRAY_SIZE (data->macros->macs))
570 {
571 struct save_macro_item *d = data->macros;
572 data->macros = xmalloc (sizeof (struct save_macro_item));
573 data->macros->next = d;
574 data->count = 0;
575 }
576 save = data->macros->macs + data->count;
577 data->count++;
578 memcpy (save, h, sizeof (struct cpp_hashnode));
579 HT_STR (&save->ident) = xmemdup (HT_STR (HT_NODE (save)),
580 HT_LEN (HT_NODE (save)),
581 HT_LEN (HT_NODE (save)) + 1);
582 }
583 return 1;
584 }
4.1.3.1.2.1.1. 预处理阶段的#pragma指示
以下段落抽取自文献【6】中有关#pargma指示的部分
#pragma指示是C标准指定的方式,为编译器提供语言自身所不能携带的信息。1999 C标准指定了这个指示的3个形式(通常所说的pragmas)。C编译器可以自由为其他形式加上它所乐意的含义。 对于这个目的(注:即编译器引入语言标准外新的含义),GCC有倾向于使用语言语义扩展的传统,例如__attribute__。不过,GCC仍然定义了自己的几个pragmas。这些pragmas大多数会影响整个编译单元或源文件。 在GCC 3版本,所有的GNU定义,支持的pragmas都被加上GCC前缀。这与C9定义的pragmas都带有STDC前缀做法一致。出于向后兼容的目的,被前一版本所识别的pragmas仍然可以不使用GCC前缀,但这个用法已经过时。一些更旧的pragmas整个都过时了。它们不能带有GCC前缀。 C99引入了_Pragma操作符。这个特性针对#pragma的一个主要问题:作为一个指示,它不能由宏展开来生成。 _Pragma的语法是_Pragma (string-literal),其中的字符串可以是普通的或宽字符字符串。对于string-literal,通过用‘/’替换‘//’及‘”’替换‘/”’,实现非字符串化。其结果就如同出现在#pragma指示右手边那样被处理。例如, _Pragma (“GCC dependency /”parse.y/””) 其作用等同于#pragma GCC dependency “parse.y”。这个效果可以通过宏来实现,例如 #define DO_PRAGMA(x) _Pragma (#x) DO_PRAGMA (GCC dependency “parse.y”) 标准并未指明操作符何处可以出现。预处理器不接受在预处理条件指示如#if中的_pragma。出于安全,你最好不要在除#define外的指示中使用它,并让其自成一行。 用于预处理器的pragmas有:
#pragma GCC dependency #pragma GCC dependency允许检查当前文件和其他文件的相对日期。如果其他文件比当前文件更新,给出一个警告。如果当前文件从其他文件派生,并由此需要重新生成,这个特性是有用的。其他文件使用通常的头文件查找路径来查找。可选的结尾文本可用于在警告消息中给出更多的信息。 #pragma GCC dependency “parse.y” #pramga GCC dependency “/usr/include/time.h” rerun fuxincludes
#pragma GCC poison 有时,你希望从你的程序中完全移除一个识别符,并确保它不会回来。要确保实现这一点,你可以用该pragma“毒死”识别符。#pragma GCC poison后接一串要“毒害”的识别符。在这个指示后在源代码中,任何一个这些识别符的出现都会导致错误。例如, #pragma GCC poison printf sprintf fprintf sprintf (some_string, “hello”); 将产生一个错误。 如果一个“中毒”的识别符出现在其被“毒害”前定义的宏的扩展中,将不会导致错误。这使得你可以“毒害”一个识别符而不需要担心系统头文件定义的宏会使用它。例如, #define strrchr rindex #pragma GCC poison rindex strrchr (someth_string, ‘h’); 将不会产生错误。
#pragma GCC system_header 这个pragma不带任何参数。它使得当前文件中余下的代码被视为来自系统头文件。 |
1095 char **
1096 _cpp_save_pragma_names (cpp_reader *pfile) in cpplib.c
1097 {
1098 int ct = count_registered_pragmas (pfile->pragmas);
1099 char **result = xnewvec (char *, ct);
1100 (void) save_registered_pragmas (pfile->pragmas, result);
1101 return result;
1102 }
1062 static int
1063 count_registered_pragmas (struct pragma_entry *pe) in cpplib.c
1064 {
1065 int ct = 0;
1066 for (; pe != NULL; pe = pe->next)
1067 {
1068 if (pe->is_nspace)
1069 ct += count_registered_pragmas (pe->u.space);
1070 ct++;
1071 }
1072 return ct;
1073 }
1078 static char **
1079 save_registered_pragmas (struct pragma_entry *pe, char **sd)
1080 {
1081 for (; pe != NULL; pe = pe->next)
1082 {
1083 if (pe->is_nspace)
1084 sd = save_registered_pragmas (pe->u.space, sd);
1085 *sd++ = xmemdup (HT_STR (&pe->pragma->ident),
1086 HT_LEN (&pe->pragma->ident),
1087 HT_LEN (&pe->pragma->ident) + 1);
1088 }
1089 return sd;
1090 }
在上面的例子中,GCC即构成1069行的pe->u.space中的space部分,其下又有dependency,poison及system_header。 save_registered_paragmas,由count_registered_pragmas配合,将这个pragmas树存入由save_macro_data构成的链表中。