GCC-3.4.6源代码学习笔记(109)
2010-10-11 11:34
357 查看
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
bool
inline_p)
14359
{
14360
tree fn;
14361
bool ctor_initializer_p =
false;
14362
bool
saved_in_unbraced_linkage_specification_p;
14363
unsigned
saved_num_template_parameter_lists;
14364
14365
/*
If the next token is `return', then the code may be trying to
14366
make
use 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 return
values 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
this
next 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
return
fn;
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
return
ctor_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
return
stmt;
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 for
a
1019
statement-expression. But, if it's a statement-expression with
1020
a
scopeless block, there's nothing to keep, and we don't want
1021
to
accidentally keep a block *inside* the scopeless block.
*/
1022
keep_next_level (false);
1023
1024
return
r;
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 filename
has changed, also add in a FILE_STMT. Do a string
87
compare first, though, as it might be an
equivalent 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
return
t;
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
return
current_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
return
top;
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
:在解析函数体之前
解析函数体
对于在
14368
行所见的,跟在“
)
”后面的关键字“
return
”,其解释参见章节
为方法构建节点
。
14356
static
tree
14357
cp_parser_function_definition_after_declarator
(cp_parser* parser,
in parser.c
14358
bool
inline_p)
14359
{
14360
tree fn;
14361
bool ctor_initializer_p =
false;
14362
bool
saved_in_unbraced_linkage_specification_p;
14363
unsigned
saved_num_template_parameter_lists;
14364
14365
/*
If the next token is `return', then the code may be trying to
14366
make
use 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 return
values 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
this
next 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
return
fn;
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
return
ctor_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
return
stmt;
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 for
a
1019
statement-expression. But, if it's a statement-expression with
1020
a
scopeless block, there's nothing to keep, and we don't want
1021
to
accidentally keep a block *inside* the scopeless block.
*/
1022
keep_next_level (false);
1023
1024
return
r;
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 filename
has changed, also add in a FILE_STMT. Do a string
87
compare first, though, as it might be an
equivalent 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
return
t;
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
return
current_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
return
top;
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源代码学习笔记(129 续)
- GCC-3.4.6源代码学习笔记(144)
- GCC-3.4.6源代码学习笔记(69)
- GCC-3.4.6源代码学习笔记(148)
- GCC-3.4.6源代码学习笔记(20)
- GCC-3.4.6源代码学习笔记(132)
- GCC-3.4.6源代码学习笔记(164)
- GCC-3.4.6源代码学习笔记(139-续1)
- GCC-3.4.6源代码学习笔记(140)
- GCC-3.4.6源代码学习笔记(60)
- GCC-3.4.6源代码学习笔记(118)
- GCC-3.4.6源代码学习笔记(46)
- GCC-3.4.6源代码学习笔记(172)
- GCC-3.4.6源代码学习笔记(133)
- GCC-3.4.6源代码学习笔记(78)
- GCC-3.4.6源代码学习笔记(176)
- GCC-3.4.6源代码学习笔记(23)
- GCC-3.4.6源代码学习笔记(158)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(137)