您的位置:首页 > 编程语言

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

:在解析函数体之前
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: