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

5.12.4.1.2.        非类型参数

该模板的第二及第三个参数都是非类型参数。它们都指定了类型,但在具现或特化时会分配不同的值。类型描述符( type-specifier )“ std::size_t ”是 simple-type-specifier 的形式。而且, simple-type-specifier std::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 ”都是声明符 id declarator-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_specifiers declarator

 

cp_parser_parameter_declaration (continue)

 

11311   /* If the next token is `=', 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 are defining a class, then the tokens that make up the

11319       default argument must be saved and processed 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 just parse the

11408       assignment-expression.  */

11409     else

11410     {

11411       bool saved_local_variables_forbidden_p;

11412

11413       /* Make sure that 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 of default argument for parameter of non-function");

11435       else

11436       {

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

11438         default_argument = NULL_TREE;

11439       }

11440     }

11441   }

11442   else

11443     default_argument = NULL_TREE;

11444  

11445   /* Create the representation 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   return parameter;

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 next token 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, it must be that we are looking at a

5171       logical-or-expression.  */

5172     else

5173     {

5174       /* Parse the logical-or-expression.  */

5175       expr = cp_parser_logical_or_expression (parser);

5176       /* If the next token 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         enum tree_code assignment_operator;

5183  

5184         /* If it's an assignment-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 the assignment.  */

5193           rhs = cp_parser_assignment_expression (parser);

5194           /* An assignment may not appear in a

5195             constant-expression.  */

5196           if (cp_parser_non_integral_constant_expression (parser,

5197                                                  "an assignment"))

5198             return error_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_map token_tree_map,

14062                         cp_parser_expression_fn fn)

14063 {

14064   tree lhs;

14065

14066   /* Parse the first expression.  */

14067   lhs = (*fn) (parser);

14068   /* Now, look for more expressions.  */

14069   while (true)

14070   {

14071     cp_token *token;

14072     const cp_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 token is `>', 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 one of 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 not be used.  */

14090         bool overloaded_p = false;

14091

14092         /* Consume the operator token.  */

14093         cp_lexer_consume_token (parser->lexer);

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

14095         rhs = (*fn) (parser);

14096         /* Build the binary 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 of an

14100           overloaded operator, then this expression cannot be an

14101           integral constant-expression. An overloaded operator

14102           can be used even if both operands are otherwise

14103           permissible in an integral constant-expression if at

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

14105         if (overloaded_p

14106           && (cp_parser_non_integral_constant_expression

14107                           (parser, "calls to overloaded operators")))

14108           lhs = error_mark_node;

14109         break ;

14110       }

14111

14112     /* If the token wasn'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 struct cp_parser_token_tree_map_node                                                 in parser.c

1080   {

1081     /* The token type.  */

1082     ENUM_BITFIELD (cpp_ttype) token_type : 8;

1083     /* The corresponding tree 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 terminating entry has a token_type of CPP_EOF.  */

1089  

1090   typedef cp_parser_token_tree_map_node cp_parser_token_tree_map [];

 

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

对于下面的每个函数,数组 map 记录了该函数所处理的操作符,对于该操作符, cp_parser_binary_expression 将被用于把 lhs rhs 部分组织成相应的表达式。注意到 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-ex pression

     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-operator cast-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     enum tree_code unary_operator;

4240  

4241     /* Peek at the next token.  */

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-specifier template [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 可以被用作:下标,函数调用,显式类型转换(函数记号),伪析构函数调用( pseudo destructor 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 rid keyword;

3419     cp_id_kind idk = CP_ID_KIND_NONE;

3420     tree postfix_expression = NULL_TREE;

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

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

3423       class used to qualify the member.  */

3424     tree qualifying_class = NULL_TREE;

3425  

3426     /* Peek at the next token.  */

3427     token = cp_lexer_peek_token (parser->lexer);

3428     /* Some of the productions are determined by keywords.  */

3429     keyword = token->keyword;

3430     switch (keyword)

3431     {

          ….

3566       default :

3567       {

3568         tree type;

3569  

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

3571           looking at a functional cast. We could also be looking at

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

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

3574         cp_parser_parse_tentatively (parser);

3575         /* Look for the simple-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 that worked, we're done.  */

3584         if (cp_parser_parse_definitely (parser))

3585           break ;

3586  

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

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 a primary-expression.  */

3637         postfix_expression = cp_parser_primary_expression (parser,

3638                                                     &idk,

3639                                                    &qualifying_class);

3640       }

3641       break ;

3642     }

3643  

3644     /* If we were avoiding committing to the processing of a

3645       qualified-id until we knew whether or not we had a

3646       pointer-to-member, we now know.  */

3647     if (qualifying_class)

3648     {

          …

3666     }

3667  

3668     /* Keep looping until 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 a Koenig lookup function call.  */

3675         postfix_expression

3676               = unqualified_name_lookup_error (postfix_expression);

3677        

3678       /* Peek at the next token.  */

3679       token = cp_lexer_peek_token (parser->lexer);

3680  

3681       switch (token->type)

3682        {

            …

4003         default :

4004           return postfix_expression;

4005       }

4006     }

4007  

4008     /* We should never get here.  */

4009     abort ();

4010     return error_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 the primary expression is not an id-expression.  */

2381     *idk = CP_ID_KIND_NONE;

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

2383     *qualifying_class = NULL_TREE;

2384  

2385     /* Peek at the next token.  */

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       case CPP_CHAR:

2396       case CPP_WCHAR:

2397       case CPP_STRING:

2398       case CPP_WSTRING:

2399       case CPP_NUMBER:

2400         token = cp_lexer_consume_token (parser->lexer);

2401         return token->value;

          …

2648     }

2649   }

 

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

点此打开

106 :非类型参数

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值