5.12.3.2.1.1.3.5. 解析其它构造函数
在解析了默认构造函数后,我们回到 cp_parser_member_specification_opt ,它开始解析下一个构造函数: Lock(const Host&) {}
这是一个很有趣的构造函数,因为它的参数是类模板的模板参数。既然我们已经看过解析默认构造函数的过程,在这里我们只看不同的部分。
5.12.3.2.1.1.3.5.1. 解析参数
对于这个构造函数,它具有参数,因此在 10467 行,在 cp_parser_direct_declarator 里,该参数由 cp_parser_parameter_declaration_clause 来解析。
11026 static tree
11027 cp_parser_parameter_declaration_clause (cp_parser* parser) in parser.c
11028 {
11029 tree parameters;
11030 cp_token *token;
11031 bool ellipsis_p;
11032
11033 /* Peek at the next token. */
11034 token = cp_lexer_peek_token (parser->lexer);
11035 /* Check for trivial parameter-declaration-clauses. */
11036 if (token->type == CPP_ELLIPSIS)
11037 {
11038 /* Consume the `...' token. */
11039 cp_lexer_consume_token (parser->lexer);
11040 return NULL_TREE;
11041 }
11042 else if (token->type == CPP_CLOSE_PAREN)
11043 /* There are no parameters. */
11044 {
11045 #ifndef NO_IMPLICIT_EXTERN_C
11046 if (in_system_header && current_class_type == NULL
11047 && current_lang_name == lang_name_c)
11048 return NULL_TREE;
11049 else
11050 #endif
11051 return void_list_node;
11052 }
11053 /* Check for `(void)', too, which is a special case. */
11054 else if (token->keyword == RID_VOID
11055 && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
11056 == CPP_CLOSE_PAREN))
11057 {
11058 /* Consume the `void' token. */
11059 cp_lexer_consume_token (parser->lexer);
11060 /* There are no parameters. */
11061 return void_list_node;
11062 }
11063
11064 /* Parse the parameter-declaration-list. */
11065 parameters = cp_parser_parameter_declaration_list (parser);
11066 /* If a parse error occurred while parsing the
11067 parameter-declaration-list, then the entire
11068 parameter-declaration-clause is erroneous. */
11069 if (parameters == error_mark_node)
11070 return error_mark_node;
所有的参数都将由 cp_parser_parameter_declaration_list 通过 tree_list 节点串接起来。
11109 static tree
11110 cp_parser_parameter_declaration_list (cp_parser* parser) in parser.c
11111 {
11112 tree parameters = NULL_TREE;
11113
11114 /* Look for more parameters. */
11115 while (true)
11116 {
11117 tree parameter;
11118 bool parenthesized_p;
11119 /* Parse the parameter. */
11120 parameter
11121 = cp_parser_parameter_declaration (parser,
11122 /*template_parm_p=*/ false,
11123 &parenthesized_p);
11124
11125 /* If a parse error occurred parsing the parameter declaration,
11126 then the entire parameter-declaration-list is erroneous. */
11127 if (parameter == error_mark_node)
11128 {
11129 parameters = error_mark_node;
11130 break ;
11131 }
11132 /* Add the new parameter to the list. */
11133 TREE_CHAIN (parameter) = parameters;
11134 parameters = parameter;
11135
11136 /* Peek at the next token. */
11137 if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
11138 || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
11139 /* The parameter-declaration-list is complete. */
11140 break ;
…
11187 }
11188
11189 /* We built up the list in reverse order; straighten it out now. */
11190 return nreverse (parameters);
11191 }
由上可见,串中的每个节点都是由 cp_parser_parameter_declaration 准备的。
11215 static tree
11216 cp_parser_parameter_declaration (cp_parser *parser, in parser.c
11217 bool template_parm_p,
11218 bool *parenthesized_p)
11219 {
11220 int declares_class_or_enum;
11221 bool greater_than_is_operator_p;
11222 tree decl_specifiers;
11223 tree attributes;
11224 tree declarator;
11225 tree default_argument;
11226 tree parameter;
11227 cp_token *token;
11228 const char *saved_message;
11229
11230 /* In a template parameter, `>' is not an operator.
11231
11232 [temp.param]
11233
11234 When parsing a default template-argument for a non-type
11235 template-parameter, the first non-nested `>' is taken as the end
11236 of the template parameter-list rather than a greater-than
11237 operator. */
11238 greater_than_is_operator_p = !template_parm_p;
11239
11240 /* Type definitions may not appear in parameter types. */
11241 saved_message = parser->type_definition_forbidden_message;
11242 parser->type_definition_forbidden_message
11243 = "types may not be defined in parameter types";
11244
11245 /* Parse the declaration-specifiers. */
11246 decl_specifiers
11247 = cp_parser_decl_specifier_seq (parser,
11248 CP_PARSER_FLAGS_NONE,
11249 &attributes,
11250 &declares_class_or_enum);
11251 /* If an error occurred, there's no reason to attempt to parse the
11252 rest of the declaration. */
11253 if (cp_parser_error_occurred (parser))
11254 {
11255 parser->type_definition_forbidden_message = saved_message;
11256 return error_mark_node;
11257 }
“ const Host ” 是一个 decl-specifier-seq 。那么 cp_parser_decl_specifier_seq 通过重复调用 cp_parser_type_specifier 不停地解析这个序列。在第一次调用中对于关键字 const 返回了“ const ”的唯一节点;而在第二次调用中,通过下列的调用栈: cp_parser_type_specifier à cp_parser_simple_type_specifier à cp_parser_type_name à cp_parser_class_name à cp_parser_identifier , cp_parser_lookup_name à lookup_name_real ,找出“ Host ”的 TYPE_DECL 节点。
cp_parser_parameter_declaration_clause (continue)
11259 /* Peek at the next token. */
11260 token = cp_lexer_peek_token (parser->lexer);
11261 /* If the next token is a `)', `,', `=', `>', or `...', then there
11262 is no declarator. */
11263 if (token->type == CPP_CLOSE_PAREN
11264 || token->type == CPP_COMMA
11265 || token->type == CPP_EQ
11266 || token->type == CPP_ELLIPSIS
11267 || token->type == CPP_GREATER)
11268 {
11269 declarator = NULL_TREE;
11270 if (parenthesized_p)
11271 *parenthesized_p = false;
11272 }
11273 /* Otherwise, there should be a declarator. */
11274 else
11275 {
11276 bool saved_default_arg_ok_p = parser->default_arg_ok_p;
11277 parser->default_arg_ok_p = false;
11278
11279 /* After seeing a decl-specifier-seq, if the next token is not a
11280 "(", there is no possibility that the code is a valid
11281 expression. Therefore, if parsing tentatively, we commit at
11282 this point. */
11283 if (!parser->in_template_argument_list_p
11284 /* In an expression context, having seen:
11285
11286 (int((char ...
11287
11288 we cannot be sure whether we are looking at a
11289 function-type (taking a "char" as a parameter) or a cast
11290 of some object of type "char" to "int". */
11291 && !parser->in_type_id_in_expr_p
11292 && cp_parser_parsing_tentatively (parser)
11293 && !cp_parser_committed_to_tentative_parse (parser)
11294 && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
11295 cp_parser_commit_to_tentative_parse (parser);
11296 /* Parse the declarator. */
11297 declarator = cp_parser_declarator (parser,
11298 CP_PARSER_DECLARATOR_EITHER,
11299 /*ctor_dtor_or_conv_p=*/ NULL,
11300 parenthesized_p,
11301 /*member_p=*/ false);
11302 parser->default_arg_ok_p = saved_default_arg_ok_p;
11303 /* After the declarator, allow more attributes. */
11304 attributes = chainon (attributes, cp_parser_attributes_opt (parser));
11305 }
随后的符号“ & ”是声明符。因此在 11297 行, cp_parser_declarator 被调用。注意到参数 dcl_kind 是 CP_PARSER_DECLARATOR_EITHER ,它表示声明符( declarator )或者抽象声明符( abstract-declarator )都可以。事实上,“ & ”是一个抽象声明符,因为它不代表任何标识符的名字。
10259 static tree
10260 cp_parser_declarator (cp_parser* parser, in parser.c
10261 cp_parser_declarator_kind dcl_kind,
10262 int* ctor_dtor_or_conv_p,
10263 bool* parenthesized_p,
10264 bool member_p)
10265 {
10266 cp_token *token;
10267 tree declarator;
10268 enum tree_code code;
10269 tree cv_qualifier_seq;
10270 tree class_type;
10271 tree attributes = NULL_TREE;
10272
10273 /* Assume this is not a constructor, destructor, or type-conversion
10274 operator. */
10275 if (ctor_dtor_or_conv_p)
10276 *ctor_dtor_or_conv_p = 0;
10277
10278 if (cp_parser_allow_gnu_extensions_p (parser))
10279 attributes = cp_parser_attributes_opt (parser);
10280
10281 /* Peek at the next token. */
10282 token = cp_lexer_peek_token (parser->lexer);
10283
10284 /* Check for the ptr-operator production. */
10285 cp_parser_parse_tentatively (parser);
10286 /* Parse the ptr-operator. */
10287 code = cp_parser_ptr_operator (parser,
10288 &class_type,
10289 &cv_qualifier_seq);
10290 /* If that worked, then we have a ptr-operator. */
10291 if (cp_parser_parse_definitely (parser))
10292 {
10293 /* If a ptr-operator was found, then this declarator was not
10294 parenthesized. */
10295 if (parenthesized_p)
10296 *parenthesized_p = true;
10297 /* The dependent declarator is optional if we are parsing an
10298 abstract-declarator. */
10299 if (dcl_kind != CP_PARSER_DECLARATOR_NAMED)
10300 cp_parser_parse_tentatively (parser);
10301
10302 /* Parse the dependent declarator. */
10303 declarator = cp_parser_declarator (parser, dcl_kind,
10304 /*ctor_dtor_or_conv_p=*/ NULL,
10305 /*parenthesized_p=*/ NULL,
10306 /*member_p=*/ false);
10307
10308 /* If we are parsing an abstract-declarator, we must handle the
10309 case where the dependent declarator is absent. */
10310 if (dcl_kind != CP_PARSER_DECLARATOR_NAMED
10311 && ! cp_parser_parse_definitely (parser))
10312 declarator = NULL_TREE;
10313
10314 /* Build the representation of the ptr-operator. */
10315 if (code == INDIRECT_REF)
10316 declarator = make_pointer_declarator (cv_qualifier_seq,
10317 declarator);
10318 else
10319 declarator = make_reference_declarator (cv_qualifier_seq,
10320 declarator);
10321 /* Handle the pointer-to-member case. */
10322 if (class_type)
10323 declarator = build_nt (SCOPE_REF, class_type, declarator);
10324 }
10325 /* Everything else is a direct-declarator. */
10326 else
10327 {
10328 if (parenthesized_p)
10329 *parenthesized_p = cp_lexer_next_token_is (parser->lexer,
10330 CPP_OPEN_PAREN);
10331 declarator = cp_parser_direct_declarator (parser, dcl_kind,
10332 ctor_dtor_or_conv_p,
10333 member_p);
10334 }
10335
10336 if (attributes && declarator != error_mark_node)
10337 declarator = tree_cons (attributes, declarator, NULL_TREE);
10338
10339 return declarator;
10340 }
ptr-operator 具有以下的语法。它代表或者有、或者没有 cv-qualifier 部分的直接(引用)或间接(指针)的引用。因此 cp_parser_ptr_operator 的返回值是 ADDR_EXPR 或者 INDIRECT_REF 。
ptr-operator
├ * cv-qualifier-seq [opt]
| Ⅼ cv-qualifier cv-qualifier-seq [opt]
├ & ├ const
| ├ volatile
| Ⅼ __restrict__ GNU Ext
├ ::[opt] nested-name-specifier * cv-qualifier-seq [opt]
GNU Ext Ⅼ & cv-qualifier-seq [opt]
10729 static enum tree_code
10730 cp_parser_ptr_operator (cp_parser* parser, in parser.c
10731 tree* type,
10732 tree* cv_qualifier_seq)
10733 {
10734 enum tree_code code = ERROR_MARK;
10735 cp_token *token;
10736
10737 /* Assume that it's not a pointer-to-member. */
10738 *type = NULL_TREE;
10739 /* And that there are no cv-qualifiers. */
10740 *cv_qualifier_seq = NULL_TREE;
10741
10742 /* Peek at the next token. */
10743 token = cp_lexer_peek_token (parser->lexer);
10744 /* If it's a `*' or `&' we have a pointer or reference. */
10745 if (token->type == CPP_MULT || token->type == CPP_AND)
10746 {
10747 /* Remember which ptr-operator we were processing. */
10748 code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF);
10749
10750 /* Consume the `*' or `&'. */
10751 cp_lexer_consume_token (parser->lexer);
10752
10753 /* A `*' can be followed by a cv-qualifier-seq, and so can a
10754 `&', if we are allowing GNU extensions. (The only qualifier
10755 that can legally appear after `&' is `restrict', but that is
10756 enforced during semantic analysis. */
10757 if (code == INDIRECT_REF
10758 || cp_parser_allow_gnu_extensions_p (parser))
10759 *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
10760 }
10761 else
10762 {
10763 /* Try the pointer-to-member case. */
10764 cp_parser_parse_tentatively (parser);
10765 /* Look for the optional `::' operator. */
10766 cp_parser_global_scope_opt (parser,
10767 /*current_scope_valid_p=*/ false);
10768 /* Look for the nested-name specifier. */
10769 cp_parser_nested_name_specifier (parser,
10770 /*typename_keyword_p=*/ false,
10771 /*check_dependency_p=*/ true,
10772 /*type_p=*/ false,
10773 /*is_declaration=*/ false);
10774 /* If we found it, and the next token is a `*', then we are
10775 indeed looking at a pointer-to-member operator. */
10776 if (!cp_parser_error_occurred (parser)
10777 && cp_parser_require (parser, CPP_MULT, "`*'"))
10778 {
10779 /* The type of which the member is a member is given by the
10780 current SCOPE. */
10781 *type = parser->scope;
10782 /* The next name will not be qualified. */
10783 parser->scope = NULL_TREE;
10784 parser->qualifying_scope = NULL_TREE;
10785 parser->object_scope = NULL_TREE;
10786 /* Indicate that the `*' operator was used. */
10787 code = INDIRECT_REF;
10788 /* Look for the optional cv-qualifier-seq. */
10789 *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
10790 }
10791 /* If that didn't work we don't have a ptr-operator. */
10792 if (!cp_parser_parse_definitely (parser))
10793 cp_parser_error (parser, "expected ptr-operator");
10794 }
10795
10796 return code;
10797 }
回到 cp_parser_declarator ,这个函数根据 cp_parser_ptr_operator 返回的节点码构建对应的树节点。不过,注意到在“ & ”后面没有跟着标识符,参数 target 是 NULL ,它对应于该声明符(它在 cp_parser_declarator 的 10312 行设置)。
113 tree
114 make_reference_declarator (tree cv_qualifiers, tree target) in lex.c
115 {
116 target = build_nt (ADDR_EXPR, target);
117 TREE_TYPE (target) = cv_qualifiers;
118 return target;
119 }
接下来处理可能的缺省参数,幸运的是,这里没有使用缺省参数。
cp_parser_parameter_declaration (continue)
11307 /* The restriction on defining new types applies only to the type
11308 of the parameter, not to the default argument. */
11309 parser->type_definition_forbidden_message = saved_message;
11310
11311 /* If the next token is `=', then process a default argument. */
11312 if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
11313 {
…
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 }
最后,把各部分组合起来,对于构造函数的参数,它是一棵相当复杂的树。
( 点此打开 )
图 74 :构造函数的参数
cp_parser_parameter_declaration_clause (continue)
11072 /* Peek at the next token. */
11073 token = cp_lexer_peek_token (parser->lexer);
11074 /* If it's a `,', the clause should terminate with an ellipsis. */
11075 if (token->type == CPP_COMMA)
11076 {
11077 /* Consume the `,'. */
11078 cp_lexer_consume_token (parser->lexer);
11079 /* Expect an ellipsis. */
11080 ellipsis_p
11081 = (cp_parser_require (parser, CPP_ELLIPSIS, "`...'") != NULL);
11082 }
11083 /* It might also be `...' if the optional trailing `,' was
11084 omitted. */
11085 else if (token->type == CPP_ELLIPSIS)
11086 {
11087 /* Consume the `...' token. */
11088 cp_lexer_consume_token (parser->lexer);
11089 /* And remember that we saw it. */
11090 ellipsis_p = true;
11091 }
11092 else
11093 ellipsis_p = false;
11094
11095 /* Finish the parameter list. */
11096 return finish_parmlist (parameters, ellipsis_p);
11097 }
最终, finish_parmlist 为参数的节点设置需要的标记。
1994 tree
1995 finish_parmlist (tree parms, int ellipsis) in semantics.c
1996 {
1997 if (parms)
1998 {
1999 /* We mark the PARMS as a parmlist so that declarator processing can
2000 disambiguate certain constructs. */
2001 TREE_PARMLIST (parms) = 1;
2002 /* We do not append void_list_node here, but leave it to grokparms
2003 to do that. */
2004 PARMLIST_ELLIPSIS_P (parms) = ellipsis;
2005 }
2006 return parms;
2007 }
注意到关于省略号参数( … )的信息保存在链的头一个节点中。因此中间树看起来就像:
( 点此打开 )
图 75 :完成对构造函数参数的准备