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

来源:互联网 发布:白金数据结局神乐和龙 编辑:程序博客网 时间:2024/05/17 22:55

5.12.4.1.2.       非类型参数

该模板的第二及第三个参数都是非类型参数。它们都指定了类型,但在具现或特化时会分配不同的值。类型描述符(type-specifier)“std::size_t”是simple-type-specifier的形式。而且,simple-type-specifierstd::size_t”包含了两个部分:“std::”构成了nested-name-specifier,而“size_t”是类型名(type-name)。类型“size_t”通常在系统头文件<stddef.h>中被typedef 为“unsigned long”,这个头文件通常在目录“/usr/lib/gcc/`target`/`gcc-v`/include”下。并且这个“size_t”通过using指示:“using ::size_t;”被引入到文件<cstddef>定义的名字空间“std”中。这使得“size_t”在“std”中可见。

这个调用栈是:cp_parser_template_parameter_list à cp_parser_template_parameter à cp_parser_parameter_declarationà cp_parser_decl_specifier_seq à cp_parser_type_specifierà cp_parser_simple_type_specifier à cp_parser_type_name

而“chunkSize”及“maxSmallObjectSize”都是声明符iddeclarator-id)部分。调用栈:cp_parser_parameter_declaration à cp_parser_declarator à cp_parser_direct_declaratorà cp_parser_declarator_id à cp_parser_id_expressionà cp_parser_unqualified_id à cp_parser_identifier为这些声明符构建了IDENTIFIER_NODE节点。然后在处理缺省实参之前,向cp_parser_parameter_declaration返回以下节点。

点此打开

105:构建的decl_specifiersdeclarator

 

cp_parser_parameter_declaration (continue)

 

11311  /* If the next tokenis `=', then process a default argument. */

11312   if (cp_lexer_next_token_is(parser->lexer, CPP_EQ))

11313   {

11314     bool saved_greater_than_is_operator_p;

11315     /* Consume the`='.  */

11316     cp_lexer_consume_token (parser->lexer);

11317

11318     /* If we aredefining a class, then the tokens that make up the

11319       default argument must be saved andprocessed later.  */

11320     if (!template_parm_p &&at_class_scope_p ()

11321        && TYPE_BEING_DEFINED (current_class_type))

11322     {

           

11406     }

11407     /* Outside of a class definition, we can justparse the

11408       assignment-expression.  */

11409     else

11410     {

11411       bool saved_local_variables_forbidden_p;

11412

11413       /* Make surethat PARSER->GREATER_THAN_IS_OPERATOR_P is

11414         set correctly.  */

11415       saved_greater_than_is_operator_p

11416            = parser->greater_than_is_operator_p;

11417       parser->greater_than_is_operator_p =greater_than_is_operator_p;

11418       /* Local variable names (and the `this'keyword) may not

11419         appear in a default argument.  */

11420      saved_local_variables_forbidden_p

11421          = parser->local_variables_forbidden_p;

11422      parser->local_variables_forbidden_p = true;

11423       /* Parse the assignment-expression.  */

11424      default_argument = cp_parser_assignment_expression (parser);

11425       /* Restore saved state. */

11426       parser->greater_than_is_operator_p

11427           = saved_greater_than_is_operator_p;

11428      parser->local_variables_forbidden_p

11429          = saved_local_variables_forbidden_p;

11430     }

11431     if (!parser->default_arg_ok_p)

11432     {

11433       if (!flag_pedantic_errors)

11434         warning ("deprecated use ofdefault argument for parameter of non-function");

11435       else

11436       {

11437         error ("default arguments are onlypermitted for function parameters");

11438         default_argument = NULL_TREE;

11439       }

11440     }

11441   }

11442   else

11443     default_argument = NULL_TREE;

11444  

11445  /* Create therepresentation of the parameter.  */

11446   if (attributes)

11447     decl_specifiers = tree_cons (attributes,NULL_TREE, decl_specifiers);

11448   parameter = build_tree_list(default_argument,

11449                          build_tree_list(decl_specifiers,

11450                                      declarator));

11451

11452   returnparameter;

11453 }

 

在上面注意符号“=”在11316行被消化,因此在11424行后跟的符号被cp_parser_assignment_expression所解析。符号“4096”(通过展开DEFAULT_CHUNK_SIZE)是conditional-expression的一种——conditional-expression可以是logical-or-expression或者“logical-or-expression? expression:assignment-expression“。

 

5161   static tree

5162   cp_parser_assignment_expression (cp_parser* parser)                                in parser.c

5163   {

5164     tree expr;

5165  

5166     /* If the nexttoken is the `throw' keyword, then we're looking at

5167       a throw-expression.  */

5168     if (cp_lexer_next_token_is_keyword(parser->lexer, RID_THROW))

5169       expr = cp_parser_throw_expression (parser);

5170     /* Otherwise, itmust be that we are looking at a

5171       logical-or-expression.  */

5172     else

5173     {

5174       /* Parse thelogical-or-expression.  */

5175      expr = cp_parser_logical_or_expression (parser);

5176       /* If the nexttoken is a `?' then we're actually looking at a

5177         conditional-expression.  */

5178       if (cp_lexer_next_token_is(parser->lexer, CPP_QUERY))

5179        return cp_parser_question_colon_clause(parser, expr);

5180       else

5181       {

5182         enumtree_code assignment_operator;

5183  

5184         /* If it's anassignment-operator, we're using the second

5185           production.  */

5186         assignment_operator

5187             = cp_parser_assignment_operator_opt(parser);

5188         if (assignment_operator != ERROR_MARK)

5189         {

5190           tree rhs;

5191  

5192           /* Parse the right-hand side of theassignment.  */

5193          rhs = cp_parser_assignment_expression (parser);

5194           /* Anassignment may not appear in a

5195             constant-expression.  */

5196          if (cp_parser_non_integral_constant_expression (parser,

5197                                                  "anassignment"))

5198             returnerror_mark_node;

5199           /* Build the assignment expression.  */

5200           expr = build_x_modify_expr (expr,

5201                                  assignment_operator,

5202                                   rhs);

5203         }

5204       }

5205     }

5206  

5207     return expr;

5208   }

 

C++语言提供了丰富的算术及逻辑操作符,而且优先级及结合规则顺应常识。在有关编译原理的书籍中,我们可以看到定义体现这些优先级规则的技巧。毫无例外,C++的规则采用了相似的技术。例如,logical-or-expression的规则是:

logical-or-expression:

    logical-and-expression

    logical-or-expression ||logical-and-expression

而且绝大多数的操作符是左结合的二元操作符,例如在logical-or-expression中的操作符“||”。根据这些形式,以正确的优先级及结合规则处理这些操作符的通用方法是深度优先的遍历。

 

14059 static tree

14060 cp_parser_binary_expression (cp_parser*parser,                                       in parser.c

14061                         const cp_parser_token_tree_maptoken_tree_map,

14062                         cp_parser_expression_fnfn)

14063 {

14064   tree lhs;

14065

14066   /* Parse the firstexpression.  */

14067   lhs = (*fn) (parser);

14068   /* Now, look formore expressions.  */

14069   while (true)

14070   {

14071     cp_token *token;

14072     constcp_parser_token_tree_map_node *map_node;

14073     tree rhs;

14074

14075     /* Peek at the next token.  */

14076     token = cp_lexer_peek_token(parser->lexer);

14077     /* If the tokenis `>', and that's not an operator at the

14078       moment, then we're done.  */

14079     if (token->type == CPP_GREATER

14080        &&!parser->greater_than_is_operator_p)

14081       break;

14082     /* If we find oneof the tokens we want, build the corresponding

14083       tree representation.  */

14084     for(map_node = token_tree_map;

14085         map_node->token_type != CPP_EOF;

14086         ++map_node)

14087       if (map_node->token_type ==token->type)

14088       {

14089         /* Assume that an overloaded operator will notbe used.  */

14090         bool overloaded_p = false;

14091

14092         /* Consumethe operator token.  */

14093        cp_lexer_consume_token (parser->lexer);

14094         /* Parse theright-hand side of the expression.  */

14095         rhs = (*fn) (parser);

14096         /* Build thebinary tree node.  */

14097         lhs = build_x_binary_op(map_node->tree_type, lhs, rhs,

14098                              &overloaded_p);

14099         /* If the binary operator required the use ofan

14100           overloaded operator, then thisexpression cannot be an

14101           integral constant-expression. Anoverloaded operator

14102           can be used even if both operands areotherwise

14103           permissible in an integralconstant-expression if at

14104           least one of the operands is ofenumeration type.  */

14105         if (overloaded_p

14106           &&(cp_parser_non_integral_constant_expression

14107                           (parser, "callsto overloaded operators")))

14108           lhs = error_mark_node;

14109         break;

14110       }

14111

14112     /* If the tokenwasn't one of the ones we want, we're done. */

14113     if(map_node->token_type == CPP_EOF)

14114       break;

14115   }

14116

14117   return lhs;

14118 }

 

参数token_tree_map具有类型cp_parser_token_tree_map,它保存了从一个符号类型到对应树节点类型的映射。

 

1079   typedef structcp_parser_token_tree_map_node                                                 in parser.c

1080   {

1081     /* The tokentype.  */

1082     ENUM_BITFIELD (cpp_ttype) token_type : 8;

1083    /* The correspondingtree code.  */

1084     ENUM_BITFIELD (tree_code) tree_type : 8;

1085   }cp_parser_token_tree_map_node;

1086  

1087   /* A complete map consists of several ordinary entries, followed by a

1088     terminator. The terminatingentry has a token_type of CPP_EOF.  */

1089  

1090   typedef cp_parser_token_tree_map_node cp_parser_token_tree_map[];

 

注意在1406714095行对fn的调用,变量lhsrhs分别是“左手侧“(left hand side)及”右手侧“(right hand side)的缩写。它们是由更高优先级的句柄依次所构建的子树。

对于下面的每个函数,数组map记录了该函数所处理的操作符,对于该操作符,cp_parser_binary_expression将被用于把lhsrhs部分组织成相应的表达式。注意到CPP_EOF必须在作为数组的最后一个成员来确保,当rhs缺失时,正确退出14084行的FOR循环。

而且看到这是对表达式的一个前序遍历。因此对于我们的例子,符号“4096“经历一个深的,具有以下函数的调用栈

对于操作符“&&”,它优先于“||”,因此应用的规则是:

logical-or-expression:

   logical-and-expression

   logical-or-expression || logical-and-expression

 

5099   static tree

5100   cp_parser_logical_or_expression(cp_parser* parser)                                  in parser.c

5101   {

5102     static const cp_parser_token_tree_map map = {

5103       { CPP_OR_OR, TRUTH_ORIF_EXPR },

5104       { CPP_EOF, ERROR_MARK }

5105     };

5106  

5107     return cp_parser_binary_expression (parser,

5108                                   map,

5109                                   cp_parser_logical_and_expression);

5110   }

 

依次的,“|”在下面的规则中,优先级又高一些:

logical-and-expression:

   inclusive-or-expression

   logical-and-expression&& inclusive-or-expression

 

5078   static tree

5079   cp_parser_logical_and_expression(cp_parser* parser)                                in parser.c

5080   {

5081     static const cp_parser_token_tree_map map = {

5082       { CPP_AND_AND, TRUTH_ANDIF_EXPR },

5083       { CPP_EOF, ERROR_MARK }

5084     };

5085  

5086     return cp_parser_binary_expression (parser,

5087                                   map,

5088                                   cp_parser_inclusive_or_expression);

5089   }

 

接下来优先级又高一点的是“^”:

inclusive-or-expression:

   exclusive-or-expression

   inclusive-or-expression |exclusive-or-expression

 

5057   static tree

5058   cp_parser_inclusive_or_expression(cp_parser* parser)                              in parser.c

5059   {

5060     static const cp_parser_token_tree_map map = {

5061       { CPP_OR, BIT_IOR_EXPR },

5062       { CPP_EOF, ERROR_MARK }

5063     };

5064  

5065     return cp_parser_binary_expression (parser,

5066                                   map,

5067                                  cp_parser_exclusive_or_expression);

5068   }

 

而规则exclusive-or-expression如下所示:

exclusive-or-expression:

   and-expression

   exclusive-or-expression ^and-expression

 

5035   static tree

5036   cp_parser_exclusive_or_expression (cp_parser* parser)                              in parser.c

5037   {

5038     static const cp_parser_token_tree_map map = {

5039       { CPP_XOR, BIT_XOR_EXPR },

5040       { CPP_EOF, ERROR_MARK }

5041     };

5042  

5043     return cp_parser_binary_expression (parser,

5044                                   map,

5045                                   cp_parser_and_expression);

5046   }

 

and-expression是具有以下规则的表达式:

and-expression:

   equality-expression

   and-expression &equality-expression

 

5014   static tree

5015   cp_parser_and_expression (cp_parser*parser)                                                 in parser.c

5016   {

5017     static const cp_parser_token_tree_map map = {

5018       { CPP_AND, BIT_AND_EXPR },

5019       { CPP_EOF, ERROR_MARK }

5020     };

5021  

5022     return cp_parser_binary_expression (parser,

5023                                   map,

5024                                   cp_parser_equality_expression);

5025   }

 

操作符“==”及“!=”,在关系操作符中,具有最低的优先级。

equality-expression:

   relational-expression

   equality-expression ==relational-expression

   equality-expression !=relational-expression

 

4992   static tree

4993   cp_parser_equality_expression(cp_parser* parser)                                     in parser.c

4994   {

4995     static const cp_parser_token_tree_map map = {

4996       { CPP_EQ_EQ, EQ_EXPR },

4997       { CPP_NOT_EQ, NE_EXPR },

4998       { CPP_EOF, ERROR_MARK }

4999     };

5000  

5001     return cp_parser_binary_expression (parser,

5002                                   map,

5003                                   cp_parser_relational_expression);

5004   }

 

GNU提供扩展的关系操作符<?”及“>?”,其中“<?”返回两者中较小的那个,而“>?”则返回较大的那个。

relational-expression:

    shift-expression

    relational-expression < shift-expression

    relational-expression > shift-expression

     relational-expression<= shift-expression

     relational-expression>= shift-expression

GNU Extension:

  relational-expression:

      relational-expression<? shift-expression

      relational-expression>? shift-expression

 

4965   static tree

4966   cp_parser_relational_expression (cp_parser* parser)                                   in parser.c

4967   {

4968     static const cp_parser_token_tree_map map = {

4969       { CPP_LESS, LT_EXPR },

4970       { CPP_GREATER, GT_EXPR },

4971       { CPP_LESS_EQ, LE_EXPR },

4972       { CPP_GREATER_EQ, GE_EXPR },

4973       { CPP_MIN, MIN_EXPR },

4974       { CPP_MAX, MAX_EXPR },

4975       { CPP_EOF, ERROR_MARK }

4976     };

4977  

4978     return cp_parser_binary_expression (parser,

4979                                   map,

4980                                   cp_parser_shift_expression);

4981   }

 

然后,shift-expression:

   additive-expression

   shift-expression <<additive-expression

   shift-expression >>additive-expression

 

4934   static tree

4935   cp_parser_shift_expression (cp_parser*parser)                                         in parser.c

4936   {

4937     static const cp_parser_token_tree_map map = {

4938       { CPP_LSHIFT, LSHIFT_EXPR },

4939       { CPP_RSHIFT, RSHIFT_EXPR },

4940       { CPP_EOF, ERROR_MARK }

4941     };

4942  

4943     return cp_parser_binary_expression (parser,

4944                                   map,

4945                                   cp_parser_additive_expression);

4946   }

 

additive-expression:

   multiplicative-expression

   additive-expression +multiplicative-expression

   additive-expression -multiplicative-expression

 

4911   static tree

4912   cp_parser_additive_expression(cp_parser* parser)                                     in parser.c

4913   {

4914     static const cp_parser_token_tree_map map = {

4915       {CPP_PLUS, PLUS_EXPR },

4916      { CPP_MINUS, MINUS_EXPR },

4917       { CPP_EOF, ERROR_MARK }

4918     };

4919  

4920     return cp_parser_binary_expression (parser,

4921                                   map,

4922                                   cp_parser_multiplicative_expression);

4923   }

 

mulitplicative-expression:

  pm-expression

  multiplicative-expression * pm-expression

  multiplicative-expression / pm-expression

  multiplicative-expression % pm-expression

 

4887   static tree

4888   cp_parser_multiplicative_expression (cp_parser* parser)                                    in parser.c

4889   {

4890     static const cp_parser_token_tree_map map = {

4891       { CPP_MULT, MULT_EXPR },

4892       { CPP_DIV, TRUNC_DIV_EXPR },

4893       { CPP_MOD, TRUNC_MOD_EXPR },

4894       { CPP_EOF, ERROR_MARK }

4895     };

4896  

4897     return cp_parser_binary_expression (parser,

4898                                   map,

4899                                   cp_parser_pm_expression);

4900   }

 

Pm-expression是指向成员指针(pointer-to-member)表达式的缩写,它可能包含指向成员操作符“.*”或“->*”。

pm-expression:

   cast-expression

   pm-expression .*cast-expression

   pm-expression ->*cast-expression

 

4864   static tree

4865   cp_parser_pm_expression (cp_parser*parser)                                            in parser.c

4866   {

4867     static const cp_parser_token_tree_map map = {

4868       { CPP_DEREF_STAR, MEMBER_REF },

4869       { CPP_DOT_STAR, DOTSTAR_EXPR },

4870       { CPP_EOF, ERROR_MARK }

4871     };

4872  

4873     return cp_parser_binary_expression (parser,map,

4874                                   cp_parser_simple_cast_expression);

4875   }

 

在指向成员指针操作符两边可以是转换表达式(cast-expression)。

cast-expression:

   unary-expression

   ( type-id ) cast-expression

 

14595 static tree

14596 cp_parser_simple_cast_expression (cp_parser *parser)                               in parser.c

14597 {

14598   return cp_parser_cast_expression (parser, /*address_p=*/false);

14599 }

 

Cast-expression包含属于非转换表达式的一元表达式(unary-expression),它是符号“4096所从属的表达式类别。

 

4751   static tree

4752   cp_parser_cast_expression (cp_parser*parser, bool address_p)                   in parser.c

4753   {

4754     /* If it's a `(',then we might be looking at a cast.  */

4755     if (cp_lexer_next_token_is(parser->lexer, CPP_OPEN_PAREN))

4756     {

         

4848     }

4849  

4850     /* If we get here,then it's not a cast, so it must be a

4851       unary-expression.  */

4852     return cp_parser_unary_expression (parser,address_p);

4853   }

 

Unary-epxression包含丰富的规则,而且GNU还支持几个扩展。

unary-expression:

     postfix-expression

     ++ cast-expression

     -- cast-expression

     unary-operatorcast-expression

     sizeof unary-expression

     sizeof ( type-id )

     new-expression

     delete-expression

GNU Extensions:

   unary-expression:

     __extension__cast-expression

     __alignof__unary-expression

     __alignof__ ( type-id )

     __real__ cast-expression

     __imag__ cast-expression

     && identifier

 

4235   static tree

4236   cp_parser_unary_expression (cp_parser*parser, bool address_p)                in parser.c

4237   {

4238     cp_token *token;

4239     enumtree_code unary_operator;

4240  

4241     /* Peek at the nexttoken.  */

4242     token = cp_lexer_peek_token(parser->lexer);

        

4406     return cp_parser_postfix_expression (parser,address_p);

4407   }

 

postfix-expression:

     primary-expression

     postfix-expression [expression ]

     postfix-expression (expression-list [opt] )

     simple-type-specifier (expression-list [opt] )

     typename :: [opt]nested-name-specifier identifier ( expression-list [opt] )

     typename :: [opt] nested-name-specifiertemplate [opt] template-id (expression-list [opt])

     postfix-expression .template [opt] id-expression

     postfix-expression ->template [opt] id-expression

     postfix-expression .pseudo-destructor-name

     postfix-expression ->pseudo-destructor-name

     postfix-expression ++

     postfix-expression --

     dynamic_cast < type-id> ( expression )

     static_cast < type-id> ( expression )

     reinterpret_cast <type-id > ( expression )

     const_cast < type-id> ( expression )

     typeid ( expression )

     typeid ( type-id )

GNU Extension:

   postfix-expression:

     ( type-id ) {initializer-list , [opt] }

Postfix-expression可以被用作:下标,函数调用,显式类型转换(函数记号),伪析构函数调用(pseudodestructor call),类成员访问,自增及自减,动态类型转换(dynamic cast),类型识别(type identification),静态类型转换(static cast),重解释转换(reinterpret cast),常量类型转换(constant cast)。

 

3414   static tree

3415   cp_parser_postfix_expression (cp_parser*parser, bool address_p)                      in parser.c

3416   {

3417     cp_token *token;

3418     enum ridkeyword;

3419     cp_id_kind idk = CP_ID_KIND_NONE;

3420     tree postfix_expression = NULL_TREE;

3421     /* Non-NULL only ifthe current postfix-expression can be used to

3422       form a pointer-to-member. Inthat case, QUALIFYING_CLASS is the

3423       class used to qualify themember.  */

3424     tree qualifying_class = NULL_TREE;

3425  

3426     /* Peek at the nexttoken.  */

3427     token = cp_lexer_peek_token(parser->lexer);

3428     /* Some of theproductions are determined by keywords. */

3429     keyword = token->keyword;

3430     switch(keyword)

3431     {

          ….

3566       default:

3567       {

3568         tree type;

3569  

3570         /* If the nextthing is a simple-type-specifier, we may be

3571           looking at a functionalcast. We could also be looking at

3572           an id-expression. So, wetry the functional cast, and if

3573           that doesn't work we fallback to the primary-expression.  */

3574         cp_parser_parse_tentatively(parser);

3575         /* Look for thesimple-type-specifier.  */

3576         type = cp_parser_simple_type_specifier(parser,

3577                                          CP_PARSER_FLAGS_NONE,

3578                                          /*identifier_p=*/false);

3579         /* Parse the cast itself.  */

3580         if (!cp_parser_error_occurred (parser))

3581           postfix_expression

3582                  = cp_parser_functional_cast(parser, type);

3583         /* If thatworked, we're done.  */

3584         if (cp_parser_parse_definitely(parser))

3585           break;

3586  

3587         /* If the functional-cast didn't work out, trya

3588           compound-literal.  */

3589         if (cp_parser_allow_gnu_extensions_p(parser)

3590            && cp_lexer_next_token_is (parser->lexer,CPP_OPEN_PAREN))

3591         {

             

3634         }

3635  

3636         /* It must be aprimary-expression.  */

3637         postfix_expression = cp_parser_primary_expression (parser,

3638                                                    &idk,

3639                                                   &qualifying_class);

3640       }

3641       break;

3642     }

3643  

3644     /* If we wereavoiding committing to the processing of a

3645       qualified-id until we knewwhether or not we had a

3646       pointer-to-member, we nowknow.  */

3647     if (qualifying_class)

3648     {

         

3666     }

3667  

3668     /* Keep loopinguntil the postfix-expression is complete. */

3669     while (true)

3670     {

3671       if (idk == CP_ID_KIND_UNQUALIFIED

3672         && TREE_CODE (postfix_expression) == IDENTIFIER_NODE

3673          && cp_lexer_next_token_is_not(parser->lexer, CPP_OPEN_PAREN))

3674         /* It is not aKoenig lookup function call.  */

3675         postfix_expression

3676               = unqualified_name_lookup_error(postfix_expression);

3677        

3678       /* Peek at thenext token.  */

3679       token = cp_lexer_peek_token(parser->lexer);

3680  

3681       switch(token->type)

3682       {

           

4003         default:

4004           returnpostfix_expression;

4005       }

4006     }

4007  

4008     /* We should neverget here.  */

4009     abort ();

4010     returnerror_mark_node;

4011   }

 

上面,对于符号“4096”,它不是上面提及的形式,此外它也不是简单类型指示符(simple-type-specifier),亦不是函数转换,那么解析器需要按以下规则将其作为primary-expression来处理。

primary-expression:

     literal

     this

     ( expression )

     id-expression

GNU Extensions:

   primary-expression:

     ( compound-statement )

     __builtin_va_arg (assignment-expression , type-id )

   literal:

     __null

 

2373   static tree

2374   cp_parser_primary_expression (cp_parser*parser,                                     in parser.c

2375                             cp_id_kind *idk,

2376                             tree*qualifying_class)

2377   {

2378     cp_token *token;

2379  

2380     /* Assume theprimary expression is not an id-expression. */

2381     *idk = CP_ID_KIND_NONE;

2382     /* And that itcannot be used as pointer-to-member.  */

2383     *qualifying_class = NULL_TREE;

2384  

2385     /* Peek at the nexttoken.  */

2386     token = cp_lexer_peek_token(parser->lexer);

2387     switch(token->type)

2388     {

2389       /* literal:

2390         integer-literal

2391         character-literal

2392         floating-literal

2393         string-literal

2394         boolean-literal  */

2395       caseCPP_CHAR:

2396       caseCPP_WCHAR:

2397       caseCPP_STRING:

2398       caseCPP_WSTRING:

2399       caseCPP_NUMBER:

2400        token = cp_lexer_consume_token (parser->lexer);

2401         returntoken->value;

         

2648     }

2649   }

 

显然,符号“4096”是literal 规则中的整形文本(integer-literal)。事实上,当词法分析器读入这个符号时,一个整形常量树节点被构建出来,并且被设置为该符号的值。其细节参考章节5.6.1.1.2. 数字。在为缺省实参构建了节点之后,为模板参数所建立的子树显示如下。

点此打开

106:非类型参数