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

5.1.2. C内建宏

下面的flag_undef默认是0,但可由选项-undef改写。如果是非0值,则表示不要预定义任何系统特定或GCC特定的宏。但标准预定义的宏仍旧定义(即builtin_array所定义的宏)

 

295  void

296  c_cpp_builtins (cpp_reader *pfile)                                                       in c-cppbuiltin.c

297  {

298    /* -undef turns off target-specific built-ins.  */

299    if (flag_undef)

300      return;

301 

302    define__GNUC__ ();

5.1.2.1.    __GUNC__宏系列

GCC中,预定义的宏__GNUC__永远被定义为编译器的主版本号。例如,如果编译器的版本号是3.4.6,这个宏就被定义为3;而__GNUC_MINOR____GNUC_PATCHLEVEL__则分别被定义为46。另,宏__GNUG__类似于__GNC__,但用于C++。函数define__GNUC__根据保存了版本的字符串version_string,定义这些宏。

 

252  static void

253  define__GNUC__ (void)                                                                     in c-cppbuiltin.c

254  {

255    /* The format of the version string, enforced below, is

256      ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)?  */

257    const char *q, *v = version_string;

258 

259    while (*v && ! ISDIGIT (*v))

260      v++;

261    if (!*v || (v > version_string && v[-1] != '-'))

262      abort ();

263 

264    q = v;

265    while (ISDIGIT (*v))

266      v++;

267    builtin_define_with_value_n ("__GNUC__", q, v - q);

268    if (c_dialect_cxx ())

269      builtin_define_with_value_n ("__GNUG__", q, v - q);

270 

271    if (*v != '.' || !ISDIGIT (v[1]))

272      abort ();

273    q = ++v;

274    while (ISDIGIT (*v))

275      v++;

276    builtin_define_with_value_n ("__GNUC_MINOR__", q, v - q);

277 

278    if (*v == '.')

279    {

280      if (!ISDIGIT (v[1]))

281        abort ();

282      q = ++v;

283      while (ISDIGIT (*v))

284        v++;

285      builtin_define_with_value_n ("__GNUC_PATCHLEVEL__", q, v - q);

286    }

287    else

288      builtin_define_with_value_n ("__GNUC_PATCHLEVEL__", "0", 1);

289 

290    if (*v && *v != ' ' && *v != '-')

291      abort ();

292  }

 

builtin_define_with_value_n将参数macroexpansion合并成一个定义对,并将其传给cpp_define

 

492  static void

493  builtin_define_with_value_n (const char *macro, const char *expansion, size_t elen)

494  {

495    char *buf;

496    size_t mlen = strlen (macro);

497 

498    /* Space for an = and a NUL.  */

499    buf = alloca (mlen + elen + 2);

500    memcpy (buf, macro, mlen);

501    buf[mlen] = '=';

502    memcpy (buf + mlen + 1, expansion, elen);

503    buf[mlen + elen + 1] = '/0';

504 

505    cpp_define (parse_in, buf);

506  }

 

cpp_define同时还处理由命令行定义的宏,命令行定义的宏具有形式m=valm。对于前一个形式,它需要被转换成m val,而对于后一个,应该是m 1 然后这个规范的形式可以被run_directive处理,就像我们前面所见。

 

1804 void

1805 cpp_define (cpp_reader *pfile, const char *str)                                             in cpplib.c

1806 {

1807   char *buf, *p;

1808   size_t count;

1809

1810   /* Copy the entire option so we can modify it.

1811     Change the first "=" in the string to a space. If there is none,

1812     tack " 1" on the end.  */

1813

1814   count = strlen (str);

1815   buf = alloca (count + 3);

1816   memcpy (buf, str, count);

1817

1818   p = strchr (str, '=');

1819   if (p)

1820     buf[p - str] = ' ';

1821   else

1822   {

1823     buf[count++] = ' ';

1824     buf[count++] = '1';

1825   }

1826   buf[count] = '/n';

1827

1828   run_directive (pfile, T_DEFINE, buf, count);

1829 }

5.1.2.2.    stddef.h定义的宏

C++在系统头文件stddef.h中也定义了一些预定义宏。它们是size_tptrdiff_twchar wintc_stddef_cpp_builtins协助创建了与这些宏相关的对象。

 

c_cpp_builtins (continue)

 

304    /* For stddef.h. They require macros defined in c-common.c.  */

305    c_stddef_cpp_builtins ();

 

下面函数调用中的第二个实参,如SIZE_TYPE等,定义都是目标平台相关的,并且它们都是表示类型名的字符串。

 

4249 void

4250 c_stddef_cpp_builtins(void)                                                                       in c-common.c

4251 {

4252   builtin_define_with_value ("__SIZE_TYPE__", SIZE_TYPE, 0);

4253   builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0);

4254   builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0);

4255   builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0);

4256 }

 

看到builtin_define_with_valuemacroexpansion构成macro=expansion形式,不过前面我们已经看到在cpp_define中,该形式将进一步被转换成macro expansion,然后调用run_directive

 

470  void

471  builtin_define_with_value (const char *macro, const char *expansion, int is_str)

472  {

473    char *buf;

474    size_t mlen = strlen (macro);

475    size_t elen = strlen (expansion);

476    size_t extra = 2;  /* space for an = and a NUL */

477 

478    if (is_str)

479      extra += 2;  /* space for two quote marks */

480 

481    buf = alloca (mlen + elen + extra);

482    if (is_str)

483      sprintf (buf, "%s=/"%s/"", macro, expansion);

484    else

485      sprintf (buf, "%s=%s", macro, expansion);

486 

487    cpp_define (parse_in, buf);

488  }

 

下面的则是控制宏,它们描述了编译器及目标机器的特性。

5.1.2.3.    对应于语言的控制宏

编译器需要一些宏来描述语言的特性。在我们的程序里,我们可以使用这些宏来选择匹配的定义,及做出特别的处理。

 

c_cpp_builtins (continue)

 

307    if (c_dialect_cxx ())

308    {

309      if (SUPPORTS_ONE_ONLY)

310        cpp_define (pfile, "__GXX_WEAK__=1");

311       else

312        cpp_define (pfile, "__GXX_WEAK__=0");

313      if (warn_deprecated)

314        cpp_define (pfile, "__DEPRECATED");

315    }

316    /* Note that we define this for C as well, so that we know if

317      __attribute__((cleanup)) will interface with EH.  */

318    if (flag_exceptions)

319      cpp_define (pfile, "__EXCEPTIONS");

320 

321    /* Represents the C++ ABI version, always defined so it can be used while

322      preprocessing C and assembler.  */

323    if (flag_abi_version == 0)

324      /* Use a very large value so that:

325 

326        #if __GXX_ABI_VERSION >= <value for version X>

327 

328        will work whether the user explicitly says "-fabi-version=x" or

329        "-fabi-version=0". Do not use INT_MAX because that will be

330        different from system to system.  */

331      builtin_define_with_int_value ("__GXX_ABI_VERSION", 999999);

332    else if (flag_abi_version == 1)

333      /* Due to an historical accident, this version had the value

334        "102".  */

335      builtin_define_with_int_value ("__GXX_ABI_VERSION", 102);

336    else

337      /* Newer versions have values 1002, 1003, ....  */

338      builtin_define_with_int_value ("__GXX_ABI_VERSION",

339                          1000 + flag_abi_version);

340 

341    /* libgcc needs to know this.  */

342    if (USING_SJLJ_EXCEPTIONS)

343      cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__");

5.1.2.4.    对应于基本类型特性的宏

基本类型特性可以由下面的宏获得。它们使得标准头文件给出的数值范围能正确地工作。而下面的TARGET_FLT_EVAL_METHOD是代表float.h头文件中FLT_EVAL_METHOD值的一个C表达式,FLT_EVAL_METHOD确定浮点表达式的评价方法,其值,

如果为-1,不定

如果为0,只是根据类型的范围及精度评估所有的操作数及常量。

如果为1,按double类型的范围及精度来评估类型为floatdouble的操作数及常量, long double类型的范围及精度来评估long double类型的操作数及常量。

如果为2,按long double类型的范围及精度来评估所有的操作数及常量。对于x86,该宏定义如下:

 

747  #define TARGET_FLT_EVAL_METHOD /                                                   in i386.h

748    (TARGET_MIX_SSE_I387 ? -1 : TARGET_SSE_MATH ? 0 : 2)

 

TARGET_MIX_SSE_I387在使用-mfpmath=sse,387时设置表示同时表示387浮点协处理器SSE指令集中的纯量浮点指令scalar floating point instructions),因而结果为不定。TARGET_SSE_MATH则是使用-mfpmath=sse时设置表示使用SSE指令集中的纯量浮点指令。而默认的,x86使用387协处理器,其中间结果都具有80位的精度,而不是结果类型的精度。

 

c_cpp_builtins (continue)

 

345    /* limits.h needs to know these.  */

346    builtin_define_type_max ("__SCHAR_MAX__", signed_char_type_node, 0);

347    builtin_define_type_max ("__SHRT_MAX__", short_integer_type_node, 0);

348    builtin_define_type_max ("__INT_MAX__", integer_type_node, 0);

349    builtin_define_type_max ("__LONG_MAX__", long_integer_type_node, 1);

350    builtin_define_type_max ("__LONG_LONG_MAX__", long_long_integer_type_node, 2);

351    builtin_define_type_max ("__WCHAR_MAX__", wchar_type_node, 0);

352 

353    builtin_define_type_precision ("__CHAR_BIT__", char_type_node);

354 

355    /* float.h needs to know these.  */

356 

357    builtin_define_with_int_value ("__FLT_EVAL_METHOD__",

358                              TARGET_FLT_EVAL_METHOD);

359 

360    builtin_define_float_constants ("FLT", "F", float_type_node);

361    builtin_define_float_constants ("DBL", "", double_type_node);

362    builtin_define_float_constants ("LDBL", "L", long_double_type_node);

363 

364    /* For use in assembly language.  */

365    builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0);

366    builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0);

367 

368   /* Misc.  */

369    builtin_define_with_value ("__VERSION__", version_string, 1);

370 

371   /* Definitions for LP64 model.  */

372    if (TYPE_PRECISION (long_integer_type_node) == 64

373        && POINTER_SIZE == 64

374        && TYPE_PRECISION (integer_type_node) == 32)

375    {

376      cpp_define (pfile, "_LP64");

377      cpp_define (pfile, "__LP64__");

378    }

 

转换到实数模式一节中,可以看到GCC支持IEEE浮点标准。现在GCCIEEE浮点标准的数据,由builtin_define_float_constants输出到预定义宏。这个函数比较简单,我们这里跳过。

365行,REGISTER_PREFIX这个宏,展开为单个符号(不是字符串常量),这个符号用在目标平台的汇编语言中,作为寄存器名的前缀。你可以用它写出可在多个环境中适用的汇编。例如,在m68k-aout的环境中,它展开为空,但在m68k-coff的环境下,它展开为`%'。而__USER_LABEL_PREFIX__这个宏所展开的单个符号,在汇编中作为用户标签(C代码中可见的符号(symbol))的前缀。例如,在m68k-aout环境中,它被展开为`_',但在m68k-coff环境下,则展开为空。

5.1.2.5.    对应于编译器的控制宏

这部分的宏向我们透露了有关编译器的行为。这些宏使得某些GNU头文件提供优化的定义,及选择使用系统库函数的宏或内联函数版本。

 

c_cpp_builtins (continue)

 

380    /* Other target-independent built-ins determined by command-line

381      options.  */

382    if (optimize_size)

383      cpp_define (pfile, "__OPTIMIZE_SIZE__");

384    if (optimize)

385      cpp_define (pfile, "__OPTIMIZE__");

386 

387    if (fast_math_flags_set_p ())

388      cpp_define (pfile, "__FAST_MATH__");

389    if (flag_really_no_inline)

390      cpp_define (pfile, "__NO_INLINE__");

391    if (flag_signaling_nans)

392      cpp_define (pfile, "__SUPPORT_SNAN__");

393    if (flag_finite_math_only)

394      cpp_define (pfile, "__FINITE_MATH_ONLY__=1");

395    else

396      cpp_define (pfile, "__FINITE_MATH_ONLY__=0");

397 

398    if (flag_iso)

399      cpp_define (pfile, "__STRICT_ANSI__");

400 

401    if (!flag_signed_char)

402      cpp_define (pfile, "__CHAR_UNSIGNED__");

403 

404    if (c_dialect_cxx () && TREE_UNSIGNED (wchar_type_node))

405      cpp_define (pfile, "__WCHAR_UNSIGNED__");

406 

407    /* Make the choice of ObjC runtime visible to source code.  */

408    if (c_dialect_objc () && flag_next_runtime)

409      cpp_define (pfile, "__NEXT_RUNTIME__");

5.1.2.6.    对应于目标系统的控制宏

C预处理器通常预定义了一些表示所使用系统及机器的宏。对于每个由GCC支持的目标平台,它们显然是不一样的。所有特定于系统的预定义宏都展开为常量1,因此你可以使用#ifdef#if来测试它们。

 

c_cpp_builtins (continue)

 

411    /* A straightforward target hook doesn't work, because of problems

412      linking that hook's body when part of non-C front ends.  */

413  # define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM)

414  # define preprocessing_trad_p() (cpp_get_options (pfile)->traditional)

415  # define builtin_define(TXT) cpp_define (pfile, TXT)

416  # define builtin_assert(TXT) cpp_assert (pfile, TXT)

417    TARGET_CPU_CPP_BUILTINS ();

418    TARGET_OS_CPP_BUILTINS ();

419    TARGET_OBJFMT_CPP_BUILTINS ();

420  }

 

第一组宏记录了CPU的信息。以x86为例,如果使用的目标机器是PentiumPro,那么TARGET_CPU_CPP_BUILTINS将定义以下宏。注意到builtin_define被定义为cpp_define

 

548  #define TARGET_CPU_CPP_BUILTINS()  /                                                in i386.h

549    do                                                        /

550    {                                                  /

         

654     else if (ix86_arch == PROCESSOR_PENTIUMPRO)          /

655     {                                                 /

656       builtin_define ("__i686");                        /

657       builtin_define ("__i686__");                           /

658       builtin_define ("__pentiumpro");                     /

659       builtin_define ("__pentiumpro__");                 /

660     }                                                 /

689    }                                                  /

690    while (0)

 

接下来是描述关于目标机器的语言特性的宏。以Linux OS作为例子。Linux支持PIC(位置无关代码),这个特性可以由GCC命令行选项打开或关闭,在该特性打开时定义__pic____PIC__2者含义相同)。注意对于x86/Linux来说,flag_pic1(“小”pic)或2(“大”pic)是没有区别的。

 

73    #define TARGET_OS_CPP_BUILTINS()           /                                         in linux.h

74      do                                          /

75      {                                    /

76        LINUX_TARGET_OS_CPP_BUILTINS();         /

77        if (flag_pic)                        /

78        {                                 /

79          builtin_define ("__PIC__");            /

80          builtin_define ("__pic__");              /

81        }                                 /

82      }                                    /

83      while (0)

 

每个目标OS也要在相应的宏里铭刻上自己正式的名字。对于Linux,它定义了下面的宏。

 

100  #define LINUX_TARGET_OS_CPP_BUILTINS()     /                                  in linux.h

101    do {                                              /

102      builtin_define ("__gnu_linux__");                     /

103      builtin_define_std ("linux");                      /

104      builtin_define_std ("unix");                       /

105      builtin_assert ("system=linux");                  /

106      builtin_assert ("system=unix");                          /

107      builtin_assert ("system=posix");                 /

108    } while (0)

 

函数builtin_define_std相当有趣,值得看一下。C/C++要求所有特定于系统的宏是“保留名字空间”(reserved namespace)的一部分。所有以“__”“_”加上一个大写字母开头的名字,都是保留给编译器及库,随其所愿使用。不过,由于历史的原因,系统特定的宏有不带特别前缀的名字;例如,在Unix体系上,通常会定义unix。对于这样的宏,GCC提供了一个前后各添加了双下划线的平行宏(parallel macro)。那么,如果unix被定义,__unix__也将被定义。

 

431  void

432  builtin_define_std (const char *macro)                                                 in c-cppbuiltin.c

433  {

434    size_t len = strlen (macro);

435    char *buff = alloca (len + 5);

436    char *p = buff + 2;

437    char *q = p + len;

438 

439   /* prepend __ (or maybe just _) if in user's namespace.  */

440    memcpy (p, macro, len + 1);

441    if (!( *p == '_' && (p[1] == '_' || ISUPPER (p[1]))))

442    {

443      if (*p != '_')

444        *--p = '_';

445      if (p[1] != '_')

446        *--p = '_';

447    }

448    cpp_define (parse_in, p);

449 

450    /* If it was in user's namespace...  */

451    if (p != buff + 2)

452    {

453      /* Define the macro with leading and following __.  */

454      if (q[-1] != '_')

455        *q++ = '_';

456      if (q[-2] != '_')

457        *q++ = '_';

458      *q = '/0';

459      cpp_define (parse_in, p);

460 

461      /* Finally, define the original macro if permitted.  */

462      if (!flag_iso)

463        cpp_define (parse_in, macro);

464    }

465  }

 

除了为目标OS定义宏外,我们还要为系统头文件中可能出现的断言准备答案。在[13]中,关于断言的细节给出如下:

"Assertions"是一个过时的,用于编写测试被编译程序将要运行的系统或机器的条件的,宏以外的方法。 断言通常是预定义的,但你可以通过预处理指示或命令行选项来定义它们。

断言意在提供一个更为系统的方法来描述编译器的目标系统。不过,在实践中,它们就像系统特定的预定义宏那样不可预测。另外,它们不是任何标准的组成部分,只有少数编译器支持它们。因而,使用断言的移植性比使用系统特定的预定义宏的要差。我们建议完全不要使用它们。

一个断言看上去就像这样:

#PREDICATE (ANSWER)

PREDICATE必须是一个标识符。ANSWER可以是任意的符号序列;除了开头及结尾的空白字符,所有的字符都是有意义的,并且其内部空白字符序列的差别将被忽略。(这与宏重定义的规则类似)因此,(x + y)(x+y)不同,但与( x + y )相同。在一个答案中括号不能嵌套。

为了测试断言,你要把它写进一个#if。例如,如果vaxns16000被断言为machine的答案,下面的条件成立。

#if #machine (vax) || #machine (ns16000)

你可以通过忽略条件中的答案,来测试一个述语(predicate)是否已断言了任何答案:

#if #machine

断言由#assert指示生成。它的唯一的参数是要生成的断言,它就是条件中的断言部分,但没有开头的#

#assert PREDICATE (ANSWER)

你也可以为同一个述语给不同的答案以产生多个断言。同一述语后面的断言不会覆盖前面的断言。任一述语的所有答案都是同时为真(true)。

断言可以通过#unassert指示取消。它的句法与#assert相同。在这个形式中,它只取消了在#unassert所在行上指明的答案,这个述语的其他答案仍然为真。你可以不指明答案来取消整个述语:

#unassert PREDICATE

在这2个形式中,如果没有生成过这样的断言,#unassert没有效果。

 

1854 void

1855 cpp_assert (cpp_reader *pfile, const char *str)                                              in cpplib.c

1856 {

1857   handle_assertion (pfile, str, T_ASSERT);

1858 }

 

[10]中,记录的用法是#assert PRED=ANS。因而handle_assertion将其转之为形式#assert PRED(ANS)

 

1868 static void

1869 handle_assertion (cpp_reader *pfile, const char *str, int type)                        in cpplib.c

1870 {

1871   size_t count = strlen (str);

1872   const char *p = strchr (str, '=');

1873

1874   /* Copy the entire option so we can modify it. Change the first

1875     "=" in the string to a '(', and tack a ')' on the end.  */

1876   char *buf = alloca (count + 2);

1877

1878   memcpy (buf, str, count);

1879   if (p)

1880   {

1881     buf[p - str] = '(';

1882     buf[count++] = ')';

1883   }

1884   buf[count] = '/n';

1885   str = buf;

1886

1887   run_directive (pfile, type, str, count);

1888 }

 

对于断言,其处理句柄是do_assert,它由run_directive来调用。

 

1733 static void

1734 do_assert (cpp_reader *pfile)                                                                             in cpplib.c

1735 {

1736   struct answer *new_answer;

1737   cpp_hashnode *node;

1738

1739   node = parse_assertion (pfile, &new_answer, T_ASSERT);

1740   if (node)

1741   {

1742     /* Place the new answer in the answer list. First check there

1743       is not a duplicate.  */

1744     new_answer->next = 0;

1745     if (node->type == NT_ASSERTION)

1746     {

1747       if (*find_answer (node, new_answer))

1748       {

1749         cpp_error (pfile, CPP_DL_WARNING, "/"%s/" re-asserted",

1750                  NODE_NAME (node) + 1);

1751        return;

1752       }

1753       new_answer->next = node->value.answers;

1754     }

1755

1756     node->type = NT_ASSERTION;

1757     node->value.answers = new_answer;

1758     BUFF_FRONT (pfile->a_buff) += (sizeof (struct answer)

1759                                  + (new_answer->count - 1)

1760                                    * sizeof (cpp_token));

1761     check_eol (pfile);

1762   }

1763 }

 

作为cpp_hashnode的一部分,answer具有以下的定义。下面的域first被设计为可变长度的数值,用于记录构成答案的符号。

 

29    struct answer                                                                                             in cpplib.c

30    {

31      struct answer *next;

32      unsigned int count;

33      cpp_token first[1];

34    };

 

注意到在答案中的符号不能像宏那样可以展开。因为它的行为异于宏,又是由预处理器处理,系统需要一个方法来区分它们与宏。因此GCC在断言的名字前加上‘#’

 

1651 static cpp_hashnode *

1652 parse_assertion (cpp_reader *pfile, struct answer **answerp, int type)            in cpplib.c

1653 {

1654   cpp_hashnode *result = 0;

1655   const cpp_token *predicate;

1656

1657  /* We don't expand predicates or answers.  */

1658   pfile->state.prevent_expansion++;

1659

1660   *answerp = 0;

1661   predicate = cpp_get_token (pfile);

1662   if (predicate->type == CPP_EOF)

1663     cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate");

1664   else if (predicate->type != CPP_NAME)

1665     cpp_error (pfile, CPP_DL_ERROR, "predicate must be an identifier");

1666   else if (parse_answer (pfile, answerp, type) == 0)

1667   {

1668     unsigned int len = NODE_LEN (predicate->val.node);

1669     unsigned char *sym = alloca (len + 1);

1670

1671     /* Prefix '#' to get it out of macro namespace.  */

1672     sym[0] = '#';

1673     memcpy (sym + 1, NODE_NAME (predicate->val.node), len);

1674     result = cpp_lookup (pfile, sym, len + 1);

1675   }

1676

1677   pfile->state.prevent_expansion--;

1678   return result;

1679 }

 

答案是由parse_answer提前的。这个函数很简单,与提前宏定义的函数很相似。

 

1575 static int

1576 parse_answer (cpp_reader *pfile, struct answer **answerp, int type)                      in cpplib.c

1577 {

1578   const cpp_token *paren;

1579   struct answer *answer;

1580   unsigned int acount;

1581

1582   /* In a conditional, it is legal to not have an open paren. We

1583     should save the following token in this case.  */

1584   paren = cpp_get_token (pfile);

1585

1586   /* If not a paren, see if we're OK.  */

1587   if (paren->type != CPP_OPEN_PAREN)

1588   {

1589     /* In a conditional no answer is a test for any answer. It

1590       could be followed by any token.  */

1591     if (type == T_IF)

1592     {

1593       _cpp_backup_tokens (pfile, 1);

1594       return 0;

1595     }

1596

1597     /* #unassert with no answer is valid - it removes all answers.  */

1598     if (type == T_UNASSERT && paren->type == CPP_EOF)

1599       return 0;

1600

1601     cpp_error (pfile, CPP_DL_ERROR, "missing '(' after predicate");

1602     return 1;

1603   }

1604

1605   for (acount = 0;; acount++)

1606   {

1607     size_t room_needed;

1608     const cpp_token *token = cpp_get_token (pfile);

1609     cpp_token *dest;

1610

1611     if (token->type == CPP_CLOSE_PAREN)

1612       break;

1613

1614     if (token->type == CPP_EOF)

1615     {

1616       cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer");

1617       return 1;

1618     }

1619

1620     /* struct answer includes the space for one token.  */

1621     room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token));

1622

1623     if (BUFF_ROOM (pfile->a_buff) < room_needed)

1624       _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer));

1625

1626     dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount];

1627     *dest = *token;

1628

1629     /* Drop whitespace at start, for answer equivalence purposes.  */

1630     if (acount == 0)

1631       dest->flags &= ~PREV_WHITE;

1632   }

1633

1634   if (acount == 0)

1635   {

1636     cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty");

1637     return 1;

1638   }

1639

1640   answer = (struct answer *) BUFF_FRONT (pfile->a_buff);

1641   answer->count = acount;

1642   answer->next = NULL;

1643   *answerp = answer;

1644

1645   return 0;

1646 }

 

find_answer设计来查找candidate给定的答案,是否已经加入node中。注意到答案包含了符号,其相等性应由_cpp_equiv_tokens一个一个符号来检查确定。同一答案不能被重新插入。

 

1683 static struct answer **

1684 find_answer (cpp_hashnode *node, const struct answer *candidate)                in cpplib.c

1685 {

1686   unsigned int i;

1687   struct answer **result;

1688

1689   for (result = &node->value.answers; *result; result = &(*result)->next)

1690   {

1691    struct answer *answer = *result;

1692

1693    if (answer->count == candidate->count)

1694    {

1695      for (i = 0; i < answer->count; i++)

1696        if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i]))

1697          break;

1698

1699      if (i == answer->count)

1700        break;

1701    }

1702  }

1703

1704  return result;

1705}

 

最后TARGET_OBJFMT_CPP_BUILTINS创建了关于目标格式的宏定义。对于x86/Linux,其默认的目标格式是elf

 

24    #define TARGET_OBJFMT_CPP_BUILTINS()          /                                 in elfso.h

25      do                                          /

26      {                                     /

27           builtin_define ("__ELF__");         /

28      }                                     /

29      while (0)

 

你可能感兴趣的:(GCC-3.4.6源代码学习笔记(72))