GCC-3.4.6源代码学习笔记(109)
来源:互联网 发布:淘宝定贝排名在线查询 编辑:程序博客网 时间:2024/06/06 19:44
5.12.3.2.1.2.1.2. 解析函数体
对于在14368行所见的,跟在“)”后面的关键字“return”,其解释参见章节为方法构建节点。
14356 static tree
14357 cp_parser_function_definition_after_declarator (cp_parser* parser, in parser.c
14358 boolinline_p)
14359 {
14360 tree fn;
14361 bool ctor_initializer_p =false;
14362 boolsaved_in_unbraced_linkage_specification_p;
14363 unsignedsaved_num_template_parameter_lists;
14364
14365 /*If the next token is `return', then the code may be trying to
14366 makeuse of the "named return value" extension that G++ used to
14367 support. */
14368 if (cp_lexer_next_token_is_keyword(parser->lexer, RID_RETURN))
14369 {
14370 /*Consume the `return' keyword. */
14371 cp_lexer_consume_token (parser->lexer);
14372 /*Look for the identifier that indicates what value is to be
14373 returned. */
14374 cp_parser_identifier (parser);
14375 /*Issue an error message. */
14376 error ("named returnvalues are no longer supported");
14377 /*Skip tokens until we reach the start of the function body. */
14378 while(cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
14379 &&cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
14380 cp_lexer_consume_token (parser->lexer);
14381 }
14382 /*The `extern' in `extern "C" void f () { ... }' does not apply to
14383 anything declared inside `f'. */
14384 saved_in_unbraced_linkage_specification_p
14385 =parser->in_unbraced_linkage_specification_p;
14386 parser->in_unbraced_linkage_specification_p = false;
14387 /*Inside the function, surrounding template-parameter-lists do not
14388 apply. */
14389 saved_num_template_parameter_lists
14390 =parser->num_template_parameter_lists;
14391 parser->num_template_parameter_lists = 0;
14392 /*If the next token is `try', then we are looking at a
14393 function-try-block. */
14394 if (cp_lexer_next_token_is_keyword(parser->lexer, RID_TRY))
14395 ctor_initializer_p =cp_parser_function_try_block (parser);
14396 /*A function-try-block includes the function-body, so we only do
14397 thisnext part if we're not processing a function-try-block. */
14398 else
14399 ctor_initializer_p
14400 = cp_parser_ctor_initializer_opt_and_function_body(parser);
14401
14402 /*Finish the function. */
14403 fn = finish_function ((ctor_initializer_p ? 1 : 0) |
14404 (inline_p ?2 : 0));
14405 /*Generate code for it, if necessary. */
14406 expand_or_defer_fn (fn);
14407 /*Restore the saved values. */
14408 parser->in_unbraced_linkage_specification_p
14409 =saved_in_unbraced_linkage_specification_p;
14410 parser->num_template_parameter_lists
14411 =saved_num_template_parameter_lists;
14412
14413 returnfn;
14414 }
5.12.3.2.1.2.1.2.1. 准备阶段
虽然我们用作例子的方法包含了空的函数体,不过处理空函数体仍然包括了相当复杂的过程。
11469 static bool
11470 cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser) in parser.c
11471 {
11472 tree body;
11473 bool ctor_initializer_p;
11474
11475 /*Begin the function body. */
11476 body = begin_function_body ();
11477 /*Parse the optional ctor-initializer. */
11478 ctor_initializer_p =cp_parser_ctor_initializer_opt (parser);
11479 /*Parse the function-body. */
11480 cp_parser_function_body(parser);
11481 /*Finish the function body. */
11482 finish_function_body (body);
11483
11484 returnctor_initializer_p;
11485 }
函数体本身是一个复合语句,它具有以下规则:
compound-statement:
{ statement-seq [opt] }
statement-seq被一对大括号所包含,这对大括号构成了一个作用域来把这个statement-seq与外部分隔开来。因此在真正处理函数体前,它需要某些准备工作。
10756 tree
10757 begin_function_body (void) in decl.c
10758 {
10759 tree stmt;
10760
10761 if (processing_template_decl)
10762 /*Do nothing now. */;
10763 else
10764 /*Always keep the BLOCK node associated with the outermost pair of
10765 curly braces of a function. These are needed for correct
10766 operation of dwarfout.c. */
10767 keep_next_level (true);
10768
10769 stmt = begin_compound_stmt (/*has_no_scope=*/false);
10770 COMPOUND_STMT_BODY_BLOCK(stmt) = 1;
10771
10772 if (processing_template_decl)
10773 /*Do nothing now. */;
10774 else if (DECL_CONSTRUCTOR_P(current_function_decl))
10775 begin_constructor_body ();
10776 else if (DECL_DESTRUCTOR_P (current_function_decl))
10777 begin_destructor_body ();
10778
10779 returnstmt;
10780 }
看到对于这次调用参数has_no_scope是false,它表示该复合语句定义了一个作用域。
998 tree
999 begin_compound_stmt (bool has_no_scope) in semantics.c
1000 {
1001 tree r;
1002 int is_try = 0;
1003
1004 r = build_stmt(COMPOUND_STMT, NULL_TREE);
1005
1006 if (last_tree && TREE_CODE(last_tree) == TRY_BLOCK)
1007 is_try = 1;
1008
1009 add_stmt(r);
1010 if (has_no_scope)
1011 COMPOUND_STMT_NO_SCOPE (r)= 1;
1012
1013 last_expr_type = NULL_TREE;
1014
1015 if (!has_no_scope)
1016 do_pushlevel(is_try ? sk_try : sk_block);
1017 else
1018 /* Normally, we try hard to keep the BLOCK fora
1019 statement-expression. But, if it's a statement-expression with
1020 ascopeless block, there's nothing to keep, and we don't want
1021 toaccidentally keep a block *inside* the scopeless block. */
1022 keep_next_level (false);
1023
1024 returnr;
1025 }
在中间树里,大括号及中括号都不能出现。为了标记在该复合语句中的所有的语句,在语句链表的头部构建一个COMPOUND_STMT节点。在84行,在begin_stmt_tree中,last_expr_filename 被更新为input_filename。而如果当前输入文件不是当前函数所在的文件,构建FILE_STMT节点来记录这个不同。
81 tree
82 add_stmt (tree t) in c-semantics.c
83 {
84 if (input_filename !=last_expr_filename)
85 {
86 /* If the filenamehas changed, also add in a FILE_STMT. Do a string
87 compare first, though, as it might be anequivalent string. */
88 int add = (strcmp(input_filename, last_expr_filename) != 0);
89 last_expr_filename =input_filename;
90 if (add)
91 {
92 tree pos = build_nt(FILE_STMT, get_identifier(input_filename));
93 add_stmt (pos);
94 }
95 }
96
97 /*Add T to the statement-tree. */
98 TREE_CHAIN (last_tree) = t;
99 last_tree = t;
100
101 /*When we expand a statement-tree, we must know whether or not the
102 statements are full-expressions. We record that fact here. */
103 STMT_IS_FULL_EXPR_P(last_tree) = stmts_are_full_exprs_p ();
104
105 returnt;
106 }
注意到语句被加到语句链表的末尾,不过FUNCTION_DECL的saved_tree域仍旧指向该链表的末尾。如果当前语句是一个完整的表达式(即,在该语句中构建的临时对象,在语句的末尾被毁灭),函数stmts_are_full_exprs_p返回true。在cxx_push_function_context的11299行,设置了stmts_are_full_exprs_p域为1。
306 int
307 stmts_are_full_exprs_p (void) in semantics.c
308 {
309 returncurrent_stmt_tree()->stmts_are_full_exprs_p;
310 }
那么如果该复合语句定义了一个作用域,将加入一个新的sk_block或try_block作用域。
364 void
365 do_pushlevel (scope_kind sk) in semantics.c
366 {
367 if (stmts_are_full_exprs_p ())
368 {
369 if (!processing_template_decl)
370 add_scope_stmt(/*begin_p=*/1, /*partial_p=*/0);
371 begin_scope (sk, NULL);
372 }
373 }
如果不是一个模板声明,向语句链表插入一个SCOPE_STMT节点。参数begin_p表示该语句是否开启或结束一个作用域;对于一个部分作用域(即在一个标签(label)后开始的作用域,而该标签处构建了一个需要清除操作的对象),partial_p是true。在C++中,作用域可以被其他作用域完全包含,但不会彼此部分重叠。因此栈是适合记录作用域的,其中新的节点代表新的作用域。
131 tree
132 add_scope_stmt (int begin_p, int partial_p) in c-semantics.c
133 {
134 tree *stack_ptr = current_scope_stmt_stack ();
135 tree ss;
136 tree top = *stack_ptr;
137
138 /*Build the statement. */
139 ss = build_stmt (SCOPE_STMT,NULL_TREE);
140 SCOPE_BEGIN_P (ss) =begin_p;
141 SCOPE_PARTIAL_P (ss) =partial_p;
142
143 /*Keep the scope stack up to date. */
144 if (begin_p)
145 {
146 top = tree_cons (ss,NULL_TREE, top);
147 *stack_ptr = top;
148 }
149 else
150 {
151 if (partial_p !=SCOPE_PARTIAL_P (TREE_PURPOSE (top)))
152 abort ();
153 TREE_VALUE (top) = ss;
154 *stack_ptr = TREE_CHAIN(top);
155 }
156
157 /*Add the new statement to the statement-tree. */
158 add_stmt(ss);
159
160 returntop;
161 }
上面提及的SCOPE_STMT栈由current_scope_stmt_stack返回。
1199 tree *
1200 current_scope_stmt_stack (void) in c-semantics.c
1201 {
1202 return&cfun->language->base.x_scope_stmt_stack;
1203 }
在151行,SCOPE_PARTIAL_P表示部分作用域(partial scope),例如:
S s;
l:
S s2;
goto l;
在‘1’后面是一个(隐含的)新的作用域,即便没有大括号。特别的,当我们执行goto,我们必须破坏s2然后再重新构建它。
那么在进行函数体解析前,以下的决定将被构建。这里我们忽略last_tree节点,因为它总是指向链表的末尾。
(点此打开)
图94:在解析函数体之前
- GCC-3.4.6源代码学习笔记(109)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 支付宝接口asp.net转帖
- sed 借个使用的例子及特殊符号说明
- v4l2驱动编写篇
- 使用XP自带网络连接登陆网通
- SQL Server 数据库操作实用技巧锦集
- GCC-3.4.6源代码学习笔记(109)
- 支付宝接口(ASP.NET)
- 10 个值得采用的 UNIX 命令行习惯[z]
- 键盘扫描码(转)_虚拟USB键盘
- 常用正则表达式-总结
- 百度的两道笔试题
- 【免费讲座】3G/嵌入式/物联网/云计算
- web2.0设计师个人主页css+xhtml+js全站模板
- 什么是COM? 什么是COM+?