Studying note of GCC-3.4.6 source (119)

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

5.12.4.1.2.       Non-typeparameter

The second and third parameters for the template are non-typetemplate parameter, which have their type specified but varied value assignedat instantation or speclization. The type-specifier “std::size_t” is in form ofsimple-type-specifier. Further, the simple-type-specifier “std::size_t”contains two parts: “std::” forms the nested-name-specifier, and “size_t” is thetype-name. The type “size_t” usualy is typedef as “unsigned long” in the systemheader file <stddef.h>, which normally is under directory“/usr/lib/gcc/`target`/`gcc-v`/include”. And this “size_t” is introduced intonamespace “std” in <cstddef> by using directive: “using ::size_t;” whichmakes “size_t” visible within “std” too.

The call stack is: 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.

Then“chunkSize” and “maxSmallObjectSize” both are the declarator-id part. Callstack: 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_identifiercreates the IDENTIFIER_NODEs for these declarators. Then it will returnfollowing nodes in cp_parser_parameter_declaration beforehandling the default argument.

(Clickhere for open)

Figure 105: decl_specifiers & declarator created

 

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 theassignment-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 }

 

Above notice that the token “=” is consumed at line 11316, so atline 11424 tokens following are parsed by cp_parser_assignment_expression. Token “4096” (via DEFAULT_CHUNK_SIZE expansion) is akind of conditional-expression, which is either “logical-or-expression” or “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           /* An assignmentmay 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   }

 

The language offers a rich arithmetic and logic operators. And ruleof priority and association are defined in accord with common sense. In booksof compliation principle, we have seen the skill to design rules to embodythese priorities. No exception, rule for C++ takes similar technique. Forexamlpe, rule for logical-or-expression is:

logical-or-expression:

    logical-and-expression

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

Also most of the operators are binary operators and left associated,for example the “||” operator in logical-or-expression above. With these forms,the normal way to handle these operators with the correct priority andassociation is the deepth-first transversal into the rules.

 

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 }

 

Argument token_tree_map is of type cp_parser_token_tree_map whichholds a mapping from a token type to a corresponding tree node type.

 

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[];

 

Notice the invocation of fn at line 14067 and 14095, variables lhs and rhs havetheir names abbreviate from “left hand side” and “right hand side”respectively. They are the sub-trees built by handler of higher priority rulesin turn.

For every function below, array map records the operator(s) the function handles,for which cp_parser_binary_expressionwill be used to organize lhs and rhs part to form the expression. Notice thatCPP_EOF must be present as the last element of the array to ensure exitting FOR loop at line 14084 above when rhsis absent.

Also see that it is prefix order transversal of the expression. Sofor our case, token “4096”undergoes a deep call stack with following functions.

For operator “&&”, it is superior than “||”, so the ruleapplied is:

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   }

 

In turn, “|” has next higher priority with the rule:

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   }

 

Next is “^” as indicated by the rule:

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   }

 

While the rule for exclusive-or-expression is as below:

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   }

 

Then and-expression is the expression has following rule.

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   }

 

Operators “==” and “!=” have the lowest priority among relationaloperators.

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 provides extensional relational operators “<?” and “>?”,with which “<?” returns the smaller value within the two operands, and“>?” returns the larger one.

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   }

 

Then 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 is the abbreviation of pointer-to-member expressionwhich may contain the pointer-to-member operators “.*” or “->*”.

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   }

 

On both sides of pointer-to-member operator can be thecast-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 contains non-cast expression of unary-expression,which is the expression token “4096”belongs to.

 

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 contains rich rules, and GNU also supports servalextensions.

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 can beused in: subscripting, function call, explicit type conversion (functionalnotation), pseudo destructor call, class member access, increment anddecrement, 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   }

 

Above, for token “4096”,it is not either form mentioned above, besides it neither issimple-type-specifier, nor is functional cast, parser then needs to handle itas primary-expression with following rules.

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         return token->value;

         

2648     }

2649   }

 

Clearly, token “4096” is the integer-literal of literal. Infact, when lexer reads in this token, an integer constant tree node has beencreated and set as the value of the token. Refer to section 5.6.1.1.2. Number for detail. After creatingnodes for the default argument, the sub-tree for the template argument is builtup as following.

(Clickhere for open)

Figure 106: treefor non-type parameter

 

原创粉丝点击