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_scopefalse,它表示该复合语句定义了一个作用域。

 

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_DECLsaved_tree域仍旧指向该链表的末尾。如果当前语句是一个完整的表达式(即,在该语句中构建的临时对象,在语句的末尾被毁灭),函数stmts_are_full_exprs_p返回true。在cxx_push_function_context11299行,设置了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_blocktry_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_ptrue。在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:在解析函数体之前

 

原创粉丝点击