The second and third parameters for the template are non-type template parameter, which have their type specified but varied value assigned at instantation or speclization. The type-specifier “std::size_t” is in form of simple-type-specifier. Further, the simple-type-specifier “std::size_t” contains two parts: “std::” forms the nested-name-specifier, and “size_t” is the type-name. The type “size_t” usualy is typedef as “unsigned long” in the system header file <stddef.h>, which normally is under directory “/usr/lib/gcc/`target`/`gcc-v`/include”. And this “size_t” is introduced into namespace “std” in <cstddef> by using directive: “using ::size_t;” which makes “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. Call stack: 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 creates the IDENTIFIER_NODEs for these declarators. Then it will return following nodes in cp_parser_parameter_declaration before handling the default argument.
(Click here for open )
Figure 105 : decl_specifiers & declarator created
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 }
Above notice that the token “=” is consumed at line 11316, so at line 11424 tokens following are parsed by cp_parser_assignment_expression . Token “4096” (via DEFAULT_CHUNK_SIZE expansion) is a kind 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 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 }
The language offers a rich arithmetic and logic operators. And rule of priority and association are defined in accord with common sense. In books of compliation principle, we have seen the skill to design rules to embody these priorities. No exception, rule for C++ takes similar technique. For examlpe, 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 and association 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_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 }
Argument token_tree_map is of type cp_parser_token_tree_map which holds a mapping from a token type to a corresponding tree node type.
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 [];
Notice the invocation of fn at line 14067 and 14095, variables lhs and rhs have their names abbreviate from “left hand side” and “right hand side” respectively. They are the sub-trees built by handler of higher priority rules in turn.
For every function below, array map records the operator(s) the function handles, for which cp_parser_binary_expression will be used to organize lhs and rhs part to form the expression. Notice that CPP_EOF must be present as the last element of the array to ensure exitting FOR loop at line 14084 above when rhs is absent.
Also see that it is prefix order transversal of the expression. So for our case, token “4096” undergoes a deep call stack with following functions.
For operator “&&”, it is superior than “||”, so the rule applied 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 relational operators.
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 expression which 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 the 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 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 serval extensions.
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 can be used in: subscripting, function call, explicit type conversion (functional notation), pseudo destructor call, class member access, increment and decrement, 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 }
Above, for token “4096”, it is not either form mentioned above, besides it neither is simple-type-specifier, nor is functional cast, parser then needs to handle it as 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 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 }
Clearly, token “4096” is the integer-literal of literal. In fact, when lexer reads in this token, an integer constant tree node has been created and set as the value of the token. Refer to section 5.6.1.1.2. Number for detail. After creating nodes for the default argument, the sub-tree for the template argument is built up as following.
(Click here for open )
Figure 106 : tree for non-type parameter