树节点由下面的make_node函数来分配。函数中的参数code,在上面的表中给出,注意它也是由.def文件定义的。
202 tree
203 make_node (enum tree_code code) in tree.c
204 {
205 tree t;
206 int type = TREE_CODE_CLASS (code);
207 size_t length;
208 #ifdef GATHER_STATISTICS
209 tree_node_kind kind;
210 #endif
211 struct tree_common ttmp;
212
213 /* We can't allocate a TREE_VEC without knowing how many elements
214 it will have. */
215 if (code == TREE_VEC)
216 abort ();
217
218 TREE_SET_CODE ((tree)&ttmp, code);
219 length = tree_size ((tree)&ttmp);
在上面TREE_CODE_CLASS被定义如下,它获取要创建的树节点的类识别码。
54 #define TREE_CODE_CLASS(CODE) tree_code_type[(int) (CODE)] in tree.h
对于C++,tree_code_type包含以下文件的内容:其中文件tree.def通用于所有的语言,c-common.def由C/C++使用,cp_tree.def则专用于C++。注意,DEFTREECODE在tree_code_type前被重新定义,获取对应的域。
197 #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
199 const char tree_code_type[] = { in cp-lang.c
200 #include "tree.def"
201 'x',
202 #include "c-common.def"
203 'x',
204 #include "cp-tree.def"
205 };
下面,我们补上来自c-common.def的树节点的定义。它关注C/C++中的表达式和语句
Tree Code
|
Type |
Description |
SIZEOF_EXPR |
1 |
|
ARROW_EXPR |
1 |
|
ALIGNOF_EXPR |
1 |
|
EXPR_STMT |
e |
用于表达式语句 |
COMPOUND_STMT |
e |
用于大括号对围起的代码块。节点中的操作数是COMPOUND_BODY节点 |
DECL_STMT |
e |
用于表示局部声明(local declaration) |
IF_STMT |
e |
表示if语句 |
FOR_STMT |
e |
表示for语句 |
WHILE_STMT |
e |
表示while语句 |
DO_STMT |
e |
表示do语句 |
RETURN_STMT |
e |
表示return语句 |
BREAK_STMT |
e |
表示break语句 |
CONTINUE_STMT |
e |
表示continue语句 |
SWITCH_STMT |
e |
表示switch语句 |
GOTO_STMT |
e |
表示goto语句 |
LABEL_STMT |
e |
表示label语句 |
ASM_STMT |
e |
表示内联的汇编代码 |
SCOPE_STMT |
e |
用于表示代码块的起始与结尾 |
FILE_STMT |
e |
表示当前源文件改变(换为另一文件)的点 |
CASE_LABEL |
e |
用于表示case语句中的标识(label) |
STMT_EXPR |
e |
用于复合表达式 |
COMPOUND_LITERAL_EXPR |
e |
用于C99复数 |
CLEANUP_STMT |
e |
用于记录对象被完全创建的点 |
表3 c-common.def定义的树节点
在上面第218行,带有指定树节点码的伪节点被创建,它用于确定节点的真正大小。
12316 #define TREE_SET_CODE(NODE, VALUE) ((NODE)->common.code = (VALUE)) in tree.h
138 size_t
139 tree_size (tree node) in tree.c
140 {
141 enum tree_code code = TREE_CODE (node);
142
143 switch (TREE_CODE_CLASS (code))
144 {
145 case 'd': /* A decl node */
146 return sizeof (struct tree_decl);
147
148 case 't': /* a type node */
149 return sizeof (struct tree_type);
150
151 case 'b': /* a lexical block node */
152 return sizeof (struct tree_block);
153
154 case 'r': /* a reference */
155 case 'e': /* an expression */
156 case 's': /* an expression with side effects */
157 case '<': /* a comparison expression */
158 case '1': /* a unary arithmetic expression */
159 case '2': /* a binary arithmetic expression */
160 return (sizeof (struct tree_exp)
161 + TREE_CODE_LENGTH (code) * sizeof (char *) - sizeof (char *));
162
163 case 'c': /* a constant */
164 switch (code)
165 {
166 case INTEGER_CST: return sizeof (struct tree_int_cst);
167 case REAL_CST: return sizeof (struct tree_real_cst);
168 case COMPLEX_CST: return sizeof (struct tree_complex);
169 case VECTOR_CST: return sizeof (struct tree_vector);
170 case STRING_CST: return sizeof (struct tree_string);
171 default:
172 return (*lang_hooks.tree_size) (code);
173 }
174
175 case 'x': /* something random, like an identifier. */
176 switch (code)
177 {
178 case IDENTIFIER_NODE: return lang_hooks.identifier_size;
179 case TREE_LIST: return sizeof (struct tree_list);
180 case TREE_VEC: return (sizeof (struct tree_vec)
181 + TREE_VEC_LENGTH(node) * sizeof(char *)
182 - sizeof (char *));
183
184 case ERROR_MARK:
185 case PLACEHOLDER_EXPR: return sizeof (struct tree_common);
186
187 default:
188 return (*lang_hooks.tree_size) (code);
189 }
190
191 default:
192 abort ();
193 }
194 }
函数tree_size通用于所有的语言,如果语言提供了特定的节点类,正如我们前面提到的,必须把前端的钩子中的函数指针tree_size绑定到合适的函数,否则在172和188行的调用会出问题。
确定要创建的树节点的大小后,make_node接着为其分配内存。这里忽略了收集统计数据的代码。
make_node (continue)
272 t = ggc_alloc_tree (length);
273
274 memset (t, 0, length);
275
276 TREE_SET_CODE (t, code);
277
278 switch (type)
279 {
280 case 's':
281 TREE_SIDE_EFFECTS (t) = 1;
282 break;
283
284 case 'd':
285 if (code != FUNCTION_DECL)
286 DECL_ALIGN (t) = 1;
287 DECL_USER_ALIGN (t) = 0;
288 DECL_IN_SYSTEM_HEADER (t) = in_system_header;
289 DECL_SOURCE_LOCATION (t) = input_location;
290 DECL_UID (t) = next_decl_uid++;
291
292 /* We have not yet computed the alias set for this declaration. */
293 DECL_POINTER_ALIAS_SET (t) = -1;
294 break;
295
296 case 't':
297 TYPE_UID (t) = next_type_uid++;
298 TYPE_ALIGN (t) = char_type_node ? TYPE_ALIGN (char_type_node) : 0;
299 TYPE_USER_ALIGN (t) = 0;
300 TYPE_MAIN_VARIANT (t) = t;
301
302 /* Default to no attributes for type, but let target change that. */
303 TYPE_ATTRIBUTES (t) = NULL_TREE;
304 (*targetm.set_default_type_attributes) (t);
305
306 /* We have not yet computed the alias set for this type. */
307 TYPE_ALIAS_SET (t) = -1;
308 break;
309
310 case 'c':
311 TREE_CONSTANT (t) = 1;
312 break;
313
314 case 'e':
315 switch (code)
316 {
317 case INIT_EXPR:
318 case MODIFY_EXPR:
319 case VA_ARG_EXPR:
320 case RTL_EXPR:
321 case PREDECREMENT_EXPR:
322 case PREINCREMENT_EXPR:
323 case POSTDECREMENT_EXPR:
324 case POSTINCREMENT_EXPR:
325 /* All of these have side-effects, no matter what their
326 operands are. */
327 TREE_SIDE_EFFECTS (t) = 1;
328 break;
329
330 default:
331 break;
332 }
333 break;
334 }
335
336 return t;
337 }
注意第274行的memset,因此所创建的节点是由0填充的。