所谓的内建宏,也即是标准所定义的宏,计有:__TIME__,__DATE__,__FILE__,__BASE_FILE__,__LINE__,__INCLUDE_LEVEL__,_Pragma及__STDC__(参考builtin_array),其处理函数为builtin_macro。
249 static int
250 builtin_macro (cpp_reader *pfile, cpp_hashnode *node) in cppmacro.c
251 {
252 const uchar *buf;
253 size_t len;
254 char *nbuf;
255
256 if (node->value.builtin == BT_PRAGMA)
257 {
258 /* Don't interpret _Pragma within directives. The standard is
259 not clear on this, but to me this makes most sense. */
260 if (pfile->state.in_directive)
261 return 0;
262
263 _cpp_do__Pragma (pfile);
264 return 1;
265 }
C99引入了_Pragma操作符。该特性针对#pragma的主要问题:作为一个指示,它不能作为宏扩展的结果中产生。_Pragma是一个操作符,非常像sizeof或defined,可以嵌入到宏里。
它的语法是_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")
标准没有澄清_Pragma操作符可以出现在何处。预处理器在预处理条件指示,如#if中,不接受它。为了安全起见,你最好不要在除#define以外的指示中使用它,并且让它独占一行。
1369 void
1370 _cpp_do__Pragma (cpp_reader *pfile) in cpplib.c
1371 {
1372 const cpp_token *string = get__Pragma_string (pfile);
1373
1374 if (string)
1375 destringize_and_run (pfile, &string->val.str);
1376 else
1377 cpp_error (pfile, CPP_DL_ERROR,
1378 "_Pragma takes a parenthesized string literal");
1379 }
_Pragma的内容是字符串,例程get__Pragma_string提取这个内容。
1289 static const cpp_token *
1290 get__Pragma_string (cpp_reader *pfile) in cpplib.c
1291{
1292 const cpp_token *string;
1293
1294 if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN)
1295 return NULL;
1296
1297 string = get_token_no_padding (pfile);
1298 if (string->type != CPP_STRING && string->type != CPP_WSTRING)
1299 return NULL;
1300
1301 if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN)
1302 return NULL;
1303
1304 return string;
1305}
这个语句中的符号由get_token_no_padding获取,它只返回非空白符。
1276 static const cpp_token *
1277 get_token_no_padding (cpp_reader *pfile) in cpplib.c
1278 {
1279 for (;;)
1280 {
1281 const cpp_token *result = cpp_get_token (pfile);
1282 if (result->type != CPP_PADDING)
1283 return result;
1284 }
1285 }
这个字符串就是应该跟在#pragma后的部分。在执行对应的#pragma操作符之前,这个字符串还要字符化,以“/”替换“//”,以“.”替换“/””。
1309 static void
1310 destringize_and_run (cpp_reader *pfile, const cpp_string *in) in cpplib.c
1311 {
1312 const unsigned char *src, *limit;
1313 char *dest, *result;
1314
1315 dest = result = alloca (in->len - 1);
1316 src = in->text + 1 + (in->text[0] == 'L');
1317 limit = in->text + in->len - 1;
1318 while (src < limit)
1319 {
1320 /* We know there is a character following the backslash. */
1321 if (*src == '//' && (src[1] == '//' || src[1] == '"'))
1322 src++;
1323 *dest++ = *src++;
1324 }
1325 *dest = '/n';
1326
1327 /* Ugh; an awful kludge. We are really not set up to be lexing
1328 tokens when in the middle of a macro expansion. Use a new
1329 context to force cpp_get_token to lex, and so skip_rest_of_line
1330 doesn't go beyond the end of the text. Also, remember the
1331 current lexing position so we can return to it later.
1332
1333 Something like line-at-a-time lexing should remove the need for
1334 this. */
1335 {
1336 cpp_context *saved_context = pfile->context;
1337 cpp_token *saved_cur_token = pfile->cur_token;
1338 tokenrun *saved_cur_run = pfile->cur_run;
1339
1340 pfile->context = xnew (cpp_context);
1341 pfile->context->macro = 0;
1342 pfile->context->prev = 0;
1343 run_directive (pfile, T_PRAGMA, result, dest - result);
1344 free (pfile->context);
1345 pfile->context = saved_context;
1346 pfile->cur_token = saved_cur_token;
1347 pfile->cur_run = saved_cur_run;
1348 pfile->line--;
1349 }
1350
1351 /* See above comment. For the moment, we'd like
1352
1353 token1 _Pragma ("foo") token2
1354
1355 to be output as
1356
1357 token1
1358 # 7 "file.c"
1359 #pragma foo
1360 # 7 "file.c"
1361 token2
1362
1363 Getting the line markers is a little tricky. */
1364 if (pfile->cb.line_change)
1365 pfile->cb.line_change (pfile, pfile->cur_token, false);
1366 }
在上面1343行的run_directive中,这个经过还原的字符串由cpp_push_buffer压入当前cpp_reader的读入缓存。但是在cpp_get_token里看到,如果当前的上下文不是基本上下文的话,是由当前上下文读入符号,而不是从读入缓存读入符号。为了确保能从读入缓存读入符号,这里伪造了一个基本上下文(1342行的prev为0)。同时也要保存原来基本上下文的cur_token及cur_run。注意这意味着#pragma指示执行完后,其符号是会被挪作他用的。
1136 static void
1137 do_pragma (cpp_reader *pfile) in cpplib.c
1138 {
1139 const struct pragma_entry *p = NULL;
1140 const cpp_token *token, *pragma_token = pfile->cur_token;
1141 unsigned int count = 1;
1142
1143 pfile->state.prevent_expansion++;
1144
1145 token = cpp_get_token (pfile);
1146 if (token->type == CPP_NAME)
1147 {
1148 p = lookup_pragma_entry (pfile->pragmas, token->val.node);
1149 if (p && p->is_nspace)
1150 {
1151 count = 2;
1152 token = cpp_get_token (pfile);
1153 if (token->type == CPP_NAME)
1154 p = lookup_pragma_entry (p->u.space, token->val.node);
1155 else
1156 p = NULL;
1157 }
1158 }
1159
1160 if (p)
1161 {
1162 /* Since the handler below doesn't get the line number, that it
1163 might need for diagnostics, make sure it has the right
1164 numbers in place. */
1165 if (pfile->cb.line_change)
1166 (*pfile->cb.line_change) (pfile, pragma_token, false);
1167 (*p->u.handler) (pfile);
1168 }
1169 else if (pfile->cb.def_pragma)
1170 {
1171 _cpp_backup_tokens (pfile, count);
1172 pfile->cb.def_pragma (pfile, pfile->directive_line);
1173 }
1174
1175 pfile->state.prevent_expansion--;
1176 }
系统支持的#pragma操作符已经由cpp_register_pragma注册,而lookup_pragma_entry将为已注册的操作符返回其登记入口。这些注册的句柄构成了一个层级结构,以我们的例子来说,在1152行cpp_get_token提取了符号dependency,这是注册在句柄GCC下的。注意到当处理#pragma操作符时,宏是不允许展开的(通过1143行设置prevent_expansion)。
如果操作符没有注册,1169行的钩子def_pragma将被调用,它将给出一个警告消息。对于我们的例子,这个操作符由do_pragma_dependency来完成。
当在文件中声明#pragma GCC dependency parse.y,这表示该文件依赖于parse.y,如果parse.y有更新,该文件也要更新。
1248 static void
1249 do_pragma_dependency (cpp_reader *pfile) in cpplib.c
1250 {
1251 const char *fname;
1252 int angle_brackets, ordering;
1253
1254 fname = parse_include (pfile, &angle_brackets);
1255 if (!fname)
1256 return;
1257
1258 ordering = _cpp_compare_file_date (pfile, fname, angle_brackets);
1259 if (ordering < 0)
1260 cpp_error (pfile, CPP_DL_WARNING, "cannot find source file %s", fname);
1261 else if (ordering > 0)
1262 {
1263 cpp_error (pfile, CPP_DL_WARNING,
1264 "current file is older than %s", fname);
1265 if (cpp_get_token (pfile)->type != CPP_EOF)
1266 {
1267 _cpp_backup_tokens (pfile, 1);
1268 do_diagnostic (pfile, CPP_DL_WARNING, 0);
1269 }
1270 }
1271
1272 free ((void *) fname);
1273 }
在指示中指定的文件名可以是形式<file>,这被认为是系统头文件,而且将在对应的查找路径下查找。函数parse_include收集这个文件名并确定它是否为系统头文件。
634 static const char *
635 parse_include (cpp_reader *pfile, int *pangle_brackets) in cpplib.c
636 {
637 char *fname;
638 const cpp_token *header;
639
640 /* Allow macro expansion. */
641 header = get_token_no_padding (pfile);
642 if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME)
643 {
644 fname = xmalloc (header->val.str.len - 1);
645 memcpy (fname, header->val.str.text + 1, header->val.str.len - 2);
646 fname[header->val.str.len - 2] = '/0';
647 *pangle_brackets = header->type == CPP_HEADER_NAME;
648 }
649 else if (header->type == CPP_LESS)
650 {
651 fname = glue_header_name (pfile);
652 *pangle_brackets = 1;
653 }
654 else
655 {
656 const unsigned char *dir;
657
658 if (pfile->directive == &dtable[T_PRAGMA])
659 dir = U"pragma dependency";
660 else
661 dir = pfile->directive->name;
662 cpp_error(pfile, CPP_DL_ERROR, "#%s expects /"FILENAME/" or <FILENAME>",
663 dir);
664
665 return NULL;
666 }
667
668 check_eol (pfile);
669 return fname;
670 }
显然,只有字母,‘<’及‘>’可以出现在文件名里,否则将给出一个错误消息。收集完文件名的信息,_cpp_compare_file_date将按包含文件的查找规则,找出这个文件,并返回时间戳比较的结果。
1023 int
1024 _cpp_compare_file_date (cpp_reader *pfile, const char *fname, in cppfiles.c
1025 int angle_brackets)
1026 {
1027 _cpp_file *file;
1028 struct cpp_dir *dir;
1029
1030 dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE);
1031 if (!dir)
1032 return -1;
1033
1034 file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
1035 if (file->err_no)
1036 return -1;
1037
1038 if (file->fd != -1)
1039 {
1040 close (file->fd);
1041 file->fd = -1;
1042 }
1043
1044 return file->st.st_mtime > pfile->buffer->file->st.st_mtime;
1045 }
当发现当前文件更旧时,这个#pragma操作符将给出警告。
如果是其它的内建宏,下面部分的builtin_macro将得到执行。
builtin_macro (continue)
267 buf = _cpp_builtin_macro_text (pfile, node);
268 len = ustrlen (buf);
269 nbuf = alloca (len + 1);
270 memcpy (nbuf, buf, len);
271 nbuf[len]='/n';
272
273 cpp_push_buffer (pfile, (uchar *) nbuf, len, /* from_stage3 */ true);
274 _cpp_clean_line (pfile);
275
276 /* Set pfile->cur_token as required by _cpp_lex_direct. */
277 pfile->cur_token = _cpp_temp_token (pfile);
278 push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1);
279 if (pfile->buffer->cur != pfile->buffer->rlimit)
280 cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro /"%s/"",
281 NODE_NAME (node));
282 _cpp_pop_buffer (pfile);
283
284 return 1;
285 }
所有这些内建宏是信息性的。更换文件一节详细描述了line_map结构的文件包含链。其中,宏__BASE_FILE__将被展开为主输入文件名。
116 const uchar *
117 _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node) in cppmacro.c
118 {
119 const uchar *result = NULL;
120 unsigned int number = 1;
121
122 switch (node->value.builtin)
123 {
124 default:
125 cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro /"%s/"",
126 NODE_NAME (node));
127 break;
128
129 case BT_FILE:
130 case BT_BASE_FILE:
131 {
132 unsigned int len;
133 const char *name;
134 uchar *buf;
135 const struct line_map *map = pfile->map;
136
137 if (node->value.builtin == BT_BASE_FILE)
138 while (!MAIN_FILE_P (map))
139 map = INCLUDED_FROM (&pfile->line_maps, map);
140
141 name = map->to_file;
142 len = strlen (name);
143 buf = _cpp_unaligned_alloc (pfile, len * 4 + 3);
144 result = buf;
145 *buf = '"';
146 buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
147 *buf++ = '"';
148 *buf = '/0';
149 }
150 break;
151
152 case BT_INCLUDE_LEVEL:
153 /* The line map depth counts the primary source as level 1, but
154 historically __INCLUDE_DEPTH__ has called the primary source
155 level 0. */
156 number = pfile->line_maps.depth - 1;
157 break;
158
159 case BT_SPECLINE:
160 /* If __LINE__ is embedded in a macro, it must expand to the
161 line of the macro's invocation, not its definition.
162 Otherwise things like assert() will not work properly. */
163 if (CPP_OPTION (pfile, traditional))
164 number = pfile->line;
165 else
166 number = pfile->cur_token[-1].line;
167 number = SOURCE_LINE (pfile->map, number);
168 break;
169
170 /* __STDC__ has the value 1 under normal circumstances.
171 However, if (a) we are in a system header, (b) the option
172 stdc_0_in_system_headers is true (set by target config), and
173 (c) we are not in strictly conforming mode, then it has the
174 value 0. */
175 case BT_STDC:
176 {
177 if (CPP_IN_SYSTEM_HEADER (pfile)
178 && CPP_OPTION (pfile, stdc_0_in_system_headers)
179 && !CPP_OPTION (pfile,std))
180 number = 0;
181 else
182 number = 1;
183 }
184 break;
185
186 case BT_DATE:
187 case BT_TIME:
188 if (pfile->date == NULL)
189 {
190 /* Allocate __DATE__ and __TIME__ strings from permanent
191 storage. We only do this once, and don't generate them
192 at init time, because time() and localtime() are very
193 slow on some systems. */
194 time_t tt;
195 struct tm *tb = NULL;
196
197 /* (time_t) -1 is a legitimate value for "number of seconds
198 since the Epoch", so we have to do a little dance to
199 distinguish that from a genuine error. */
200 errno = 0;
201 tt = time(NULL);
202 if (tt != (time_t)-1 || errno == 0)
203 tb = localtime (&tt);
204
205 if (tb)
206 {
207 pfile->date = _cpp_unaligned_alloc (pfile,
208 sizeof ("/"Oct 11 1347/""));
209 sprintf ((char *) pfile->date, "/"%s %2d %4d/"",
210 monthnames[tb->tm_mon], tb->tm_mday,
211 tb->tm_year + 1900);
212
213 pfile->time = _cpp_unaligned_alloc (pfile,
214 sizeof ("/"12:34:56/""));
215 sprintf ((char *) pfile->time, "/"%02d:%02d:%02d/"",
216 tb->tm_hour, tb->tm_min, tb->tm_sec);
217 }
218 else
219 {
220 cpp_errno (pfile, CPP_DL_WARNING,
221 "could not determine date and time");
222
223 pfile->date = U"/"??? ?? ????/"";
224 pfile->time = U"/"??:??:??/"";
225 }
226 }
227
228 if (node->value.builtin == BT_DATE)
229 result = pfile->date;
230 else
231 result = pfile->time;
232 break;
233 }
234
235 if (result == NULL)
236 {
237 /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
238 result = _cpp_unaligned_alloc (pfile, 21);
239 sprintf ((char *) result, "%u", number);
240 }
241
242 return result;
243 }