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

来源:互联网 发布:淘宝评论上的暴露照片 编辑:程序博客网 时间:2024/05/07 17:25

5.12.3.2.1.1.3.4.3.           缓存内联函数体

函数start_method为这个method-declaration的声明符构建了节点,随后如果方法有缺省参数,这些参数将被parserunparsed_functions_queues域所记录。而如果接下来的符号是“{”,表示适用function-definition规则,定义了内联函数。

 

cp_parser_save_member_function_body (continue)

 

14656  /*Remember it, if there default args to post process.  */

14657  cp_parser_save_default_args (parser, fn);

14658

14659   /*Create a token cache.  */

14660   cache = cp_token_cache_new ();

14661   /*Save away the tokens that make up the body of the

14662    function.  */

14663   cp_parser_cache_group (parser, cache,CPP_CLOSE_BRACE, /*depth=*/0);

14664   /*Handle function try blocks.  */

14665   while(cp_lexer_next_token_is_keyword(parser->lexer, RID_CATCH))

14666     cp_parser_cache_group (parser, cache,CPP_CLOSE_BRACE, /*depth=*/0);

14667

14668   /*Save away the inline definition; we will process it when the

14669     classis complete.  */

14670   DECL_PENDING_INLINE_INFO(fn) = cache;

14671   DECL_PENDING_INLINE_P (fn) =1;

14672

14673  /*We need to know that this was defined in the class, so that

14674     friendtemplates are handled correctly.  */

14675   DECL_INITIALIZED_IN_CLASS_P(fn) = 1;

14676

14677   /*We're done with the inline definition. */

14678   finish_method(fn);

14679

14680  /*Add FN to the queue of functions to be parsed later.  */

14681   TREE_VALUE(parser->unparsed_functions_queues)

14682    = tree_cons (NULL_TREE,fn,

14683                TREE_VALUE(parser->unparsed_functions_queues));

14684

14685   returnfn;

14686 }

 

在调用处,内联函数要被展开,因此其定义需要被解析器记住。解析器使用类型为cp_token_block的块来缓存函数的定义。每个块的大小是512字节。

 

100    typedef struct cp_token_blockGTY (())                                                     inparser.c

101    {

102      /*The tokens.  */

103      cp_tokentokens[CP_TOKEN_BLOCK_NUM_TOKENS];

104      /*The number of tokens in this block.  */

105      size_t num_tokens;

106      /*The next token block in the chain.  */

107      structcp_token_block *next;

108      /*The previous block in the chain.  */

109      structcp_token_block *prev;

110     } cp_token_block;

 

112     typedef struct cp_token_cacheGTY (())   

113     {

114      /*The first block in the cache. NULL if there are no tokens in the

115        cache.  */

116       cp_token_block*first;

117       /*The last block in the cache. NULL If there are no tokens in the

118        cache.  */

119       cp_token_block*last;

120    } cp_token_cache;

 

对于每个内联函数,都伴随一个cp_token_cache,它把保存定义的多个块串接起来。

 

131    static cp_token_cache *

132    cp_token_cache_new (void)                                                                      inparser.c

133    {

134      returnggc_alloc_cleared (sizeof (cp_token_cache));

135    }

 

函数cp_parser_cache_group是一个递归函数,因为一个函数可以包含任意对括号或大括号,这种情形由递归函数处理更为简单。注意到end或者是CPP_CLOSE_PAREN,或者是CPP_CLOSE_BRACE,而函数“消化”的第一个符号一定是“{”。

 

15349 static void

15350 cp_parser_cache_group (cp_parser *parser,                                                inparser.c

15351                    cp_token_cache *cache,

15352                     enum cpp_ttype end,

15353                     unsigneddepth)

15354 {

15355   while(true)

15356   {

15357     cp_token *token;

15358

15359     /*Abort a parenthesized expression if we encounter a brace.  */

15360     if ((end ==CPP_CLOSE_PAREN || depth == 0)

15361         && cp_lexer_next_token_is (parser->lexer,CPP_SEMICOLON))

15362       return;

15363     /*If we've reached the end of the file, stop. */

15364     if (cp_lexer_next_token_is (parser->lexer,CPP_EOF))

15365       return;

15366     /*Consume the next token.  */

15367    token = cp_lexer_consume_token (parser->lexer);

15368     /* Add this token to the tokens we aresaving.  */

15369     cp_token_cache_push_token (cache, token);

15370     /* See if it starts a new group.  */

15371     if (token->type ==CPP_OPEN_BRACE)

15372     {

15373       cp_parser_cache_group (parser, cache,CPP_CLOSE_BRACE, depth + 1);

15374       if (depth == 0)

15375         return;

15376     }

15377     else if (token->type ==CPP_OPEN_PAREN)

15378       cp_parser_cache_group (parser, cache,CPP_CLOSE_PAREN, depth + 1);

15379     else if (token->type ==end)

15380       return;

15381   }

15382 }

 

正常情况下,匹配的闭括号或闭大括号满足15379行的条件,使得函数体面退出。但是15360行的条件,并不像注释所说的那样,括号间的分号而不是大括号将使得条件成立。例如内联函数:

void m1() {

   for (int j = 0; j < 10; j++)

{

 

}

}

开括号所触发的缓存仅是红色部分的符号,余下至闭括号的符号被保存在函数体起始的开大括号所开启的缓存里。

 

139    static void

140    cp_token_cache_push_token (cp_token_cache *cache,                                 inparser.c

141                           cp_token *token)

142    {

143      cp_token_block *b =cache->last;

144   

145      /*See if we need to allocate a new token block. */

146      if (!b || b->num_tokens== CP_TOKEN_BLOCK_NUM_TOKENS)

147     {

148        b = ggc_alloc_cleared (sizeof (cp_token_block));

149        b->prev =cache->last;

150        if (cache->last)

151        {

152          cache->last->next= b;

153          cache->last = b;

154        }

155        else

156          cache->first =cache->last = b;

157     }

158      /*Add this token to the current token block. */

159     b->tokens[b->num_tokens++] = *token;

160    }

5.12.3.2.1.1.3.4.4.           退出方法的作用域

在看到该方法的声明符的时候,前端加入方法的作用域对象,并使得其成为当前作用域。现在我们跨过该方法定义的闭大括号,应该退入上一级的作用域。

 

11111  tree

11112  finish_method (tree decl)                                                                                 indecl.c

11113  {

11114    tree fndecl = decl;

11115    tree old_initial;

11116 

11117    tree link;

11118 

11119    if (decl == void_type_node)

11120     returndecl;

11121

11122   old_initial = DECL_INITIAL(fndecl);

11123

11124   /*Undo the level for the parms (from start_method).

11125     Thisis like poplevel, but it causes nothing to be

11126     saved.Saving information here confuses symbol-table

11127     outputroutines. Besides, this information will

11128     becorrectly output when this method is actually

11129    compiled.  */

11130

11131   /*Clear out the meanings of the local variables of this level;

11132     alsorecord in each decl which block it belongs to. */

11133

11134   for(link = current_binding_level->names;link; link = TREE_CHAIN (link))

11135   {

11136     if (DECL_NAME (link) !=NULL_TREE)

11137       pop_binding(DECL_NAME (link), link);

11138     my_friendly_assert(TREE_CODE (link) != FUNCTION_DECL, 163);

11139     DECL_CONTEXT (link) =NULL_TREE;

11140   }

11141

11142   poplevel (0, 0, 0);

11143

11144   DECL_INITIAL (fndecl) =old_initial;

11145

11146   /*We used to check if the context of FNDECL was different from

11147    current_class_type as another way to get inside here. This didn't work

11148     forString.cc in libg++.  */

11149   if (DECL_FRIEND_P (fndecl))

11150   {

11151     CLASSTYPE_INLINE_FRIENDS (current_class_type)

11152        = tree_cons (NULL_TREE, fndecl,CLASSTYPE_INLINE_FRIENDS (current_class_type));

11153     decl = void_type_node;

11154   }

11155

11156   returndecl;

11157 }

 

我们的构造函数其函数体是空的,那么,finish_method及其调用的函数仅是调用了leave_scope。看到作用域对象断开同作用域链的连接,被链入free_binding_level

点此打开

72:“Lock”构造函数的FUNCTION_DECL—退出作用域

5.12.3.2.1.1.3.4.5.           把构造函数插入类

回到cp_parser_member_declaration,接下来的finish_member_declaration完成对方法的处理。下面因为构造函数是声明在struct里,在pushclass5482行,current_access_specifier被设置为access_public_node

 

2089   void

2090   finish_member_declaration (tree decl)                                                in semantics.c

2091   {

2092     if (decl == error_mark_node|| decl == NULL_TREE)

2093       return;

2094  

2095     if (decl == void_type_node)

2096       /*The COMPONENT was a friend, not a member, and so there's

2097        nothing for us to do.  */

2098       return;

2099  

2100     /*We should see only one DECL at a time. */

2101     my_friendly_assert(TREE_CHAIN (decl) == NULL_TREE, 0);

2102  

2103     /*Set up access control for DECL.  */

2104     TREE_PRIVATE (decl)

2105         =(current_access_specifier == access_private_node);

2106     TREE_PROTECTED (decl)

2107         =(current_access_specifier == access_protected_node);

2108     if (TREE_CODE (decl) ==TEMPLATE_DECL)

2109     {

2110       TREE_PRIVATE(DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl);

2111       TREE_PROTECTED (DECL_TEMPLATE_RESULT(decl)) = TREE_PROTECTED (decl);

2112     }

2113  

2114     /*Mark the DECL as a member of the current class. */

2115     DECL_CONTEXT (decl) = current_class_type;

2116  

2117     /*[dcl.link]

2118  

2119       A Clanguage linkage is ignored for the names of class members

2120       andthe member function type of class member functions.  */

2121     if (DECL_LANG_SPECIFIC(decl) && DECL_LANGUAGE (decl) == lang_c)

2122       SET_DECL_LANGUAGE (decl,lang_cplusplus);

2123  

2124     /*Put functions on the TYPE_METHODS list and everything else on the

2125      TYPE_FIELDS list. Note that these are built up in reverse order.

2126       Wereverse them (to obtain declaration order) in finish_struct.  */

2127     if (TREE_CODE (decl) ==FUNCTION_DECL

2128         ||DECL_FUNCTION_TEMPLATE_P (decl))

2129     {

2130       /*We also need to add this function to the

2131         CLASSTYPE_METHOD_VEC.  */

2132       add_method(current_class_type,decl, /*error_p=*/0);

2133  

2134       TREE_CHAIN (decl) =TYPE_METHODS (current_class_type);

2135       TYPE_METHODS (current_class_type)= decl;

2136  

2137       maybe_add_class_template_decl_list(current_class_type,decl,

2138                                     /*friend_p=*/0);

2139     }

2140     /*Enter the DECL into the scope of the class. */

2141     else if ((TREE_CODE (decl)== USING_DECL && TREE_TYPE (decl))

2142            || pushdecl_class_level(decl))

2143     {

         

2172     }

2173   }

 

现在可以向类的节点加入这个方法了。在前端中,类保持一个向量(vector)来保存在其中声明的所有方法。对于构造函数及析构函数,它们是常用的方法,因此它们放在固定的位置(0对应构造函数,1对应析构函数)。

 

721    void

722    add_method (tree type, tree method, interror_p)                                        in class.c

723    {

724      int using;

725      int len;

726      int slot;

727      tree method_vec;

728      int template_conv_p;

729   

730      if (method ==error_mark_node)

731        return;

732     

733      using = (DECL_CONTEXT(method) != type);

734      template_conv_p = (TREE_CODE(method) == TEMPLATE_DECL

735                        && DECL_TEMPLATE_CONV_FN_P (method));

736   

737      if (!CLASSTYPE_METHOD_VEC(type))

738        /*Make a new method vector. We start with 8 entries. We must

739         allocate at least two (for constructors and destructors), and

740          we'regoing to end up with an assignment operator at some point

741          aswell.

742          

743          Wecould use a TREE_LIST for now, and convert it to a TREE_VEC

744          infinish_struct, but we would probably waste more memory

745         making the links in the list than we would by over-allocating

746          thesize of the vector here. Furthermore, we would complicate

747          allthe code that expects this to be a vector. */

748        CLASSTYPE_METHOD_VEC(type) = make_tree_vec (8);

749   

750      method_vec =CLASSTYPE_METHOD_VEC (type);

751      len = TREE_VEC_LENGTH(method_vec);

752   

753     /*Constructors and destructors go in special slots.  */

754      if(DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))

755        slot =CLASSTYPE_CONSTRUCTOR_SLOT;

756      else if(DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))

757      {

758        slot =CLASSTYPE_DESTRUCTOR_SLOT;

759        TYPE_HAS_DESTRUCTOR (type)= 1;

760         

761        if (TYPE_FOR_JAVA (type))

762          error (DECL_ARTIFICIAL(method)

763               ? "Java class '%T'cannot have an implicit non-trivial destructor"

764               : "Java class'%T' cannot have a destructor",

765                 DECL_CONTEXT(method));

766      }

767      else

768      {

         

866      }

867         

868      if (processing_template_decl)

869        /*TYPE is a template class. Don't issue any errors now; wait

870         until instantiation time to complain. */

871        ;

872      else

873      {

         

949      }

950   

951     /*Actually insert the new method.  */

952      TREE_VEC_ELT (method_vec,slot)

953         = build_overload (method, TREE_VEC_ELT (method_vec,slot));

954   

955     /*Add the new binding.  */

956      if (!DECL_CONSTRUCTOR_P(method)

957         &&!DECL_DESTRUCTOR_P (method))

958        push_class_level_binding(DECL_NAME (method),

959                             TREE_VEC_ELT (method_vec, slot));

960    }

 

另外,对于类模板,maybe_add_class_template_decl_list也要把该方法记录在该类模板的decl_list中。

点此打开

73:加入默认构造函数