GCC-3.4.6源代码学习笔记(36)

4.1.3.1.2.1.4.4.3.  宏展开体

在宏展开体中,#仅能紧贴在宏参数前,已使其字符串化。另外它还能作为注释自由地出现在汇编语言中。在1431行的CLK_ASM被选项–lang-asm设置,该选项指示编译器直接处理汇编输入。

 

create_iso_definition (continue)

 

1408   if (macro->fun_like)

1409     token = lex_expansion_token (pfile, macro);

1410   else

1411   {

1412     token = alloc_expansion_token (pfile, macro);

1413     *token = *ctoken;

1414   }

1415

1416   for (;;)

1417   {

1418     /* Check the stringifying # constraint 6.10.3.2.1 of

1419       function-like macros when lexing the subsequent token.  */

1420     if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like)

1421     {

1422       if (token->type == CPP_MACRO_ARG)

1423       {

1424         token->flags &= ~PREV_WHITE;

1425         token->flags |= STRINGIFY_ARG;

1426         token->flags |= token[-1].flags & PREV_WHITE;

1427         token[-1] = token[0];

1428         macro->count--;

1429       }

1430       /* Let assembler get away with murder.  */

1431       else if (CPP_OPTION (pfile, lang) != CLK_ASM)

1432       {

1433         cpp_error (pfile, CPP_DL_ERROR,

1434                  "'#' is not followed by a macro parameter");

1435         return false;

1436       }

1437     }

1438

1439     if (token->type == CPP_EOF)

1440       break;

1441

1442     /* Paste operator constraint 6.10.3.3.1.  */

1443     if (token->type == CPP_PASTE)

1444     {

1445       /* Token-paste ##, can appear in both object-like and

1446         function-like macros, but not at the ends.  */

1447       if (--macro->count > 0)

1448         token = lex_expansion_token (pfile, macro);

1449

1450       if (macro->count == 0 || token->type == CPP_EOF)

1451       {

1452         cpp_error (pfile, CPP_DL_ERROR,

1453                 "'##' cannot appear at either end of a macro expansion");

1454         return false;

1455       }

1456

1457       token[-1].flags |= PASTE_LEFT;

1458     }

1459

1460     token = lex_expansion_token (pfile, macro);

1461   }

1462

1463   macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);

1464

1465   /* Don't count the CPP_EOF.  */

1466   macro->count--;

1467

1468   /* Clear whitespace on first token for warn_of_redefinition().  */

1469   if (macro->count)

1470     macro->exp.tokens[0].flags &= ~PREV_WHITE;

1471

1472   /* Commit the memory.  */

1473   BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->exp.tokens[macro->count];

1474

1475   return true;

1476 }

 

注意在14631473行,macro->exp.tokens指向符号缓存的开头,而macro->exp.tokens[macro->count]指向其末尾。

在回到_cpp_create_definition之前,我们最好以上面的例子,先看一下现在的缓存包含了什么(这个缓存由pfile->base_run引用)。

GCC-3.4.6源代码学习笔记(36)_第1张图片

11parse_params执行后的缓存

注意到,对于#define指示的情形,pfile->cur_runsaved_cur_token之间的符号是:#defineCPP_NAME类型)。而对于引号包含的#include指示的情形,这些符号是:#include,文件名(CPP_NAME类型),或者:#include<,文件名,>CPP_GREATER类型)对于尖括号包含的#include指示而言。

GCC-3.4.6源代码学习笔记(36)_第2张图片

 

12create_iso_definition执行后的缓存

在解析宏扩展体时,

pfilea_buff为符号提供缓存,这些符号同时也被macro->exp.tokens引用。

GCC-3.4.6源代码学习笔记(36)_第3张图片

13:恢复词法分析器位置后的缓存

在恢复了词法分析器位置后,看到pfile->cur_token重新跑回了pfile->base_runstrndupa之后(含)的符号将被丢弃。而当前符号之前的符号被标记为行尾。不过,虽然宏名字及参数的符号被扔掉了,宏名字已经存进了ident_hash 而其展开体中也已经标记出参数,并存在cpp_readera_buff缓存内。

4.1.3.1.2.1.4.4.3.  完成创建

从语法上讲,越过宏扩展体后,即超出宏参数的作用域,而被它所屏蔽的变量又将可见。因此需将之前在_cpp_save_parameter中缓存的对象恢复出来。

 

_cpp_create_definition (continue)

 

1518   /* Clear the fast argument lookup indices.  */

1519   for (i = macro->paramc; i-- > 0; )

1520   {

1521     struct cpp_hashnode *node = macro->params[i];

1522     node->flags &= ~ NODE_MACRO_ARG;

1523     node->value = ((union _cpp_hashnode_value *) pfile->macro_buffer)[i];

1524   }

1525

1526   if (!ok)

1527     return ok;

1528

1529   if (node->type == NT_MACRO)

1530   {

1531     if (CPP_OPTION (pfile, warn_unused_macros))

1532       _cpp_warn_if_unused_macro (pfile, node, NULL);

1533

1534     if (warn_of_redefinition (pfile, node, macro))

1535     {

1536       cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->directive_line, 0,

1537                     "/"%s/" redefined", NODE_NAME (node));

1538

1539       if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))

1540         cpp_error_with_line (pfile, CPP_DL_PEDWARN,

1541                           node->value.macro->line, 0,

1542                           "this is the location of the previous definition");

1543     }

1544   }

1545

1546   if (node->type != NT_VOID)

1547     _cpp_free_definition (node);

1548

1549   /* Enter definition in hash table.  */

1550   node->type = NT_MACRO;

1551   node->value.macro = macro;

1552   if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))

1553     node->flags |= NODE_WARN;

1554

1555   return ok;

1556 }

 

注意在1529行的node作为该函数的参数传入,在这里的场景下是与宏同名的其他语法成分。在GCC这个预处理器的实现中,除了在定义里,源代码地方中出现宏的名字都会直接被宏展开体所替换。因此,如果已有同名的宏出现(1529行条件),需视情况发出警告。

 

74      int

75      _cpp_warn_if_unused_macro (cpp_reader *pfile, cpp_hashnode *node,        in cppmacro.c

76                            void *v ATTRIBUTE_UNUSED)

77      {

78        if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))

79        {

80          cpp_macro *macro = node->value.macro;

81     

82          if (!macro->used

83              && MAIN_FILE_P (linemap_lookup (&pfile->line_maps, macro->line)))

84            cpp_error_with_line (pfile, CPP_DL_WARNING, macro->line, 0,

85                             "macro /"%s/" is not used", NODE_NAME (node));

86        }

87     

88        return 1;

89      }

 

根据【3C++标准,如果新旧两个定义都一样,则不算错误。

 

1185 static bool

1186 warn_of_redefinition (cpp_reader *pfile, const cpp_hashnode *node,              in cppmacro.c

1187             const cpp_macro *macro2)

1188 {

1189   const cpp_macro *macro1;

1190   unsigned int i;

1191

1192   /* Some redefinitions need to be warned about regardless.  */

1193   if (node->flags & NODE_WARN)

1194     return true;

1195

1196   /* Redefinition of a macro is allowed if and only if the old and new

1197     definitions are the same. (6.10.3 paragraph 2).  */

1198   macro1 = node->value.macro;

1199

1200   /* Don't check count here as it can be different in valid

1201     traditional redefinitions with just whitespace differences.  */

1202   if (macro1->paramc != macro2->paramc

1203       || macro1->fun_like != macro2->fun_like

1204       || macro1->variadic != macro2->variadic)

1205     return true;

1206

1207   /* Check parameter spellings.  */

1208   for (i = 0; i < macro1->paramc; i++)

1209     if (macro1->params[i] != macro2->params[i])

1210       return true;

1211

1212   /* Check the replacement text or tokens.  */

1213   if (CPP_OPTION (pfile, traditional))

1214     return _cpp_expansions_different_trad (macro1, macro2);

1215

1216   if (macro1->count != macro2->count)

1217     return true;

1218

1219   for (i = 0; i < macro1->count; i++)

1220     if (!_cpp_equiv_tokens (&macro1->exp.tokens[i], &macro2->exp.tokens[i]))

1221       return true;

1222

1223   return false;

1224 }

 

如果宏参数名一致,_cpp_equiv_tokens接着比较展开体内的符号。

 

1274 int

1275 _cpp_equiv_tokens (const cpp_token *a, const cpp_token *b)                        in cpplex.c

1276 {

1277   if (a->type == b->type && a->flags == b->flags)

1278     switch (TOKEN_SPELL (a))

1279     {

1280       default:                   /* Keep compiler happy.  */

1281       case SPELL_OPERATOR:

1282         return 1;

1283       case SPELL_NONE:

1284         return (a->type != CPP_MACRO_ARG || a->val.arg_no == b->val.arg_no);

1285       case SPELL_IDENT:

1286         return a->val.node == b->val.node;

1287       case SPELL_LITERAL:

1288         return (a->val.str.len == b->val.str.len

1289               && !memcmp (a->val.str.text, b->val.str.text,

1290                            a->val.str.len));

1291     }

1292

1293   return 0;

1294 }

 

为了更好地理解上面的代码,考虑下面【3】中给出的例子。

以下的是有效的

#define OBJ_LIKE        (1-1)

#define OBJ_LIKE        /* white space */ (1-1) /* other */

#define FTN_LIKE(a)   ( a )

#define FTN_LIKE(a) (        /* note the white space */      /

                                          a /* other stuff on this line

                          */ )

但下面的重定义是无效的(结合上面的定义):

#define OBJ_LIKE        (0)          /* different token sequence */

#define OBJ_LIKE        (1 – 1)    /* different white space */

#define FTN_LIKE(b)   ( a )        /* different parameter usage */

#define FTN_LIKE(b)   ( b )       /* different parameter spelling */

4.1.3.1.2.1.1.              完成读入

对于PCH文件,其中的每个宏定义都分配了cpp_buffer对象。随着宏解析的结束,应该释放这个对象了。

 

1949 void

1950 _cpp_pop_buffer (cpp_reader *pfile)                                                          in cpplib.c

1951 {

1952   cpp_buffer *buffer = pfile->buffer;

1953   struct _cpp_file *inc = buffer->file;

1954   struct if_stack *ifs;

1955

1956   /* Walk back up the conditional stack till we reach its level at

1957     entry to this file, issuing error messages.  */

1958   for (ifs = buffer->if_stack; ifs; ifs = ifs->next)

1959     cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0,

1960              "unterminated #%s", dtable[ifs->type].name);

1961  

1962     /* In case of a missing #endif.  */

1963     pfile->state.skipping = 0;

1964  

1965    /* _cpp_do_file_change expects pfile->buffer to be the new one.  */

1966     pfile->buffer = buffer->prev;

1967  

1968     free (buffer->notes);

1969  

1970    /* Free the buffer object now; we may want to push a new buffer

1971       in _cpp_push_next_include_file.  */

1972     obstack_free (&pfile->buffer_ob, buffer);

1973  

1974     if (inc)

1975     {

1976       _cpp_pop_file_buffer (pfile, inc);

1977  

1978       _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);

1979     }

1980   }

 

if_stack构成当前正在进展的条件的栈,成功及失败的条件都被包含。

 

38    struct if_stack                                                                                     in cpplib.c

39    {

40      struct if_stack *next;

41      unsigned int line;              /* Line where condition started.  */

42      const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */

43      bool skip_elses;         /* Can future #else / #elif be skipped?  */

44      bool was_skipping;           /* If were skipping on entry.  */

45      int type;                   /* Most recent conditional for diagnostics.  */

46    };

 

当到达缓存的末尾(对于普通的包含文件,缓存将包含整个文件的内容。而对于PCH文件,缓存仅包含单个宏的定义,但在该情况下不可能看到指示(directive),因而没有创建if_stack),如果仍有if_stack存在,这表明仍有条件指示没有被封闭(例如缺少#endif等);对此在上面的1960行给出错误信息。

 

1059 void

1060 _cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file)                                    in cppfiles.c

1061 {

1062   /* Record the inclusion-preventing macro, which could be NULL

1063     meaning no controlling macro.  */

1064   if (pfile->mi_valid && file->cmacro == NULL)

1065     file->cmacro = pfile->mi_cmacro;

1066

1067   /* Invalidate control macros in the #including file.  */

1068   pfile->mi_valid = false;

1069

1070   if (file->buffer)

1071   {

1072     free ((void *) file->buffer);

1073     file->buffer = NULL;

1074     file->buffer_valid = false;

1075   }

1076 }

 

对于PCH文件的读入,_cpp_do_file_change不起什么作用。

 

 

 

你可能感兴趣的:(struct,File,buffer,token,macros,whitespace)