GCC-3.4.6源代码学习笔记 (101)
来源:互联网 发布:淘宝评论上的暴露照片 编辑:程序博客网 时间:2024/05/07 17:25
5.12.3.2.1.1.3.4.3. 缓存内联函数体
函数start_method为这个method-declaration的声明符构建了节点,随后如果方法有缺省参数,这些参数将被parser的unparsed_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里,在pushclass的5482行,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:加入默认构造函数
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- GCC-3.4.6源代码学习笔记(9)
- oracle 学习
- 利用ajax.dll进行Ajax的开发2007-07-15 15:38
- ASP.NET状态管理之五:隐藏域、ViewState、ControlState
- 用C++实现插件体系结构
- 配置文件的读写操作
- GCC-3.4.6源代码学习笔记 (101)
- Windows Azure 真实案例:软件开发商以基于互联网的平台节省了资金支出,并改善了应用程序
- WinCE6获得设备电源状态
- 手机: 1581 0812 176
- armlinux学习笔记--IIS音频驱动程序分析
- How to debugging on BMP deviceHow to debugging on BMP device
- 刚体3
- 改变按钮字体大小
- silverlight调用JS