GCC-3.4.6源代码学习笔记(109)

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 :在解析函数体之前

 

你可能感兴趣的:(function,tree,processing,token,Constructor,destructor)