1.1.1. tree_code —— 树节点的ID
在tree_node的定义中,结构体,象tree_type,tree_decl 等,用于代表相应的语法成分。比如,tree_type用于类的定义,而type_decl用于声明。但如果需要进一步分别,比如tree_decl节点为何种声明,则我们需要用到在tree_node中的另一个位。这就是在tree_common定义中,第134行的code。
31 #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
32
33 enum tree_code { in tree.h
34 #include "tree.def"
35
36 LAST_AND_UNUSED_TREE_CODE /* A convenient way to get a value for
37 NUM_TREE_CODE. */
38 };
39
40 #undef DEFTREECODE
另外在C++前端中,枚举类型(enum)cplus_tree_code被附加到上述枚举定义的最后。
887 enum cplus_tree_code { in cp-tree.h
888 CP_DUMMY_TREE_CODE = LAST_C_TREE_CODE,
889 #include "cp-tree.def"
890 LAST_CPLUS_TREE_CODE
891 };
文件tree.def定义了tree_code中前端通用的值。这个文件的内容是一系列的DEFTREECODE。而上面第31行,DEFTREECODE被定义成其中的一个域。这是GCC大量使用的技术。文件tree.def的内容显示在下面的表中。
节点码(tree code)
| 类型 | 描述 |
ERROR_MARK | x | 一个错误构造的解析。 |
IDENTIFIER_NODE | x | 代表名字(例如,代表声明的节点的DECL_NAME 成员)。 |
TREE_LIST | x | tree_list的集合。 |
TREE_VEC | x | tree_vec节点 |
BLOCK | b | 代码块 |
VOID_TYPE | t | Void类型 |
INTEGER_TYPE | t | 所有语言的整数类型,包括C中的char。 |
REAL_TYPE | t | C的float和double。 |
COMPLEX_TYPE | t |
|
VECTOR_TYPE | t |
|
ENUMERAL_TYPE | t | C的enum。 |
BOOLEAN_TYPE | t | Pascal的boolean类型(true或者false是唯一的值)。 |
CHAR_TYPE | t | Pascal的CHAR类型,不用于C。 |
POINTER_TYPE | t | 所有指针类型。 |
OFFSET_TYPE | t | 偏移,相对于对象的指针。 |
REFERENCE_TYPE | t | C++的引用。 |
METHOD_TYPE | t | 第一个参数不出现在参数列表,且指向“自己”的函数类型(C++中的类成员函数)。 |
FILE_TYPE | t | 仅用于Pascal; |
ARRAY_TYPE | t |
|
SET_TYPE | t | Pascal中的sets类型。 |
RECORD_TYPE | t | C中的struct,或者Pascal中的record。 |
UNION_TYPE | t | C中的union。和struct类似,但所有成员的偏移均为0。 |
QUAL_UNION_TYPE | t |
|
FUNCTION_TYPE | t | 函数类型 |
LANG_TYPE | t | 特定于语言的类型 |
INTEGER_CST | c | 包含32位长的成员TREE_INT_CST_LOW 和TREE_INT_CST_HIGH , 可表示64位大小的常量。 |
REAL_CST | c | 代表浮点常量。 |
COMPLEX_CST | c | 表示复数常量 |
VECTOR_CST | c | 表示vector类型常量 |
STRING_CST | c | 表示字符串常量 |
FUNCTION_DECL | d | 函数声明 |
LABEL_DECL | d | 标示(label)声明 |
CONST_DECL | d | 常量声明 |
TYPE_DECL | d | 类型声明(例如:class A;) |
VAR_DECL | d | 局部变量,全局变量,外部变量,静态变量的声明 |
PARM_DECL | d | 函数参数声明 |
RESULT_DECL | d | 函数返回值声明 |
FIELD_DECL | d | Struct/union/class的非方法(method)成员声明 |
NAMESPACE_DECL | d | 名字空间声明 |
TRANSLATION_UNIT_DECL | d | 编译单元,由GCC使用 |
COMPONENT_REF | r | Struct/union/class的非方法(method)成员的引用 |
BIT_FIELD_REF | r | Struct/union/class的位集(bit-field)成员的引用 |
INDIRECT_REF | r | C中的一元操作符*或者Pascal中的^ |
BUFFER_REF | r | Pascal中,用于文件的^ |
ARRAY_REF | r | 通过索引指定的数组元素 |
ARRAY_RANGE_REF | r | 通过索引指定的数组子集 |
VTABLE_REF | r | 通过索引指定的虚表元素。带有虚表垃圾收集器需要的数据。其中操作数0是一个ARRAY_REF(或等效的表达式),操作数1是虚表的基地址(必须是VAR_DECL),操作数2是索引(必须为INTEGER_CST) |
CONSTRUCTOR | e | 构造函数 |
COMPOUND_EXPR | e | 复合表达式 |
MODIFY_EXPR | e | 赋值表达式 |
INIT_EXPR | e | 用于初始化的表达式。其中,操作数0是被初始化的变量,操作数1是初始值 |
TARGET_EXPR | e | 其中,操作数0是初始化的目标,操作数1是初始值,操作数2,如果有,是清除操作。操作数3则是该节点展开后(亦即初始化执行后)所保存的初始值,这样我们可以反复展开这个节点。 |
COND_EXPR | e | 条件表达式(C中为:... ? ... : ...)。其中,操作数0为条件。操作数1为then的值。操作数2为else的值。操作数0可以为任意类型。操作数1必须和整个表达式的类型相同,除非它无条件地抛出异常,而在这种情况下,它应该是void类型。对操作数2,有同样的要求。 |
BIND_EXPR | e | 声明临时变量,包括生成对应的RTL对象及分配空间。操作数0是一串VAR_DECL节点。操作数1是使用这些变量的表达式,其值是BIND_EXPR的值。操作数3是对于的代码块,用于debug的目的。 |
CALL_EXPR | e | 函数调用。操作数0是所调用的函数。操作数1是参数列表。 |
WITH_CLEANUP_EXPR | e | 指定一个求值,连同相应的清除操作。操作数0为对应的表达式。操作数1是对应的清除操作。操作数2是最终代表这个值的RTL_EXPR。 |
CLEANUP_POINT_EXPR | e | 指定一个清除操作。操作数0是需要执行清除操作的表达式。在该表达式展开后,这些清除操作被执行。 |
PLACEHOLDER_EXPR | x | 表示一个,在对该表达式求值时,由一个WITH_RECORD_EXPR 支持的record(GCC内部表示struct/union/class的结构)。该表达式的类型用于寻找替代它的record。 |
WITH_RECORD_EXPR | x | 提供引用了用于替代PLACEHOLDER_EXPR的record的表达式。操作数1为要使用的record,它具有和PLACEHOLDER_EXPR的操作数0相同的类型。 |
PLUS_EXPR | 2 | 加法表达式 |
MINUS_EXPR | 2 | 减法表达式 |
MULT_EXPR | 2 | 乘法表达式 |
TRUNC_DIV_EXPR | 2 | 整数除法,商向0取整(丢弃小数位)。 |
CEIL_DIV_EXPR | 2 | 整数除法,商向正无穷取整(丢弃小数位,加1)。 |
FLOOR_DIV_EXPR | 2 | 整数除法,商向负无穷取整(丢弃小数位,减1)。 |
ROUND_DIV_EXPR | 2 | 整数除法,商四舍五入。 |
TRUNC_MOD_EXPR | 2 | 对应的余数 |
CEIL_MOD_EXPR | 2 | |
FLOOR_MOD_EXPR | 2 | |
ROUND_MOD_EXPR | 2 | |
RDIV_EXPR | 2 | 浮点除法 |
EXACT_DIV_EXPR | 2 | 假定不需要取整的除法。在C中用于指针相减。 |
FIX_TRUNC_EXPR | 1 | 浮点到整型的转换。 |
FIX_CEIL_EXPR | 1 | |
FIX_FLOOR_EXPR | 1 | |
FIX_ROUND_EXPR | 1 | |
FLOAT_EXPR | 1 | 整型到浮点的转换。 |
NEGATE_EXPR | 1 | 一元取反操作符 |
MIN_EXPR | 2 |
|
MAX_EXPR | 2 |
|
ABS_EXPR | 1 | 取绝对值 |
LSHIFT_EXPR | 2 | 对于无符号值为逻辑移位,对有符号值为算术移位 |
RSHIFT_EXPR | 2 | |
LROTATE_EXPR | 2 | |
RROTATE_EXPR | 2 | |
BIT_IOR_EXPR | 2 | 位操作表达式 |
BIT_XOR_EXPR | 2 | |
BIT_AND_EXPR | 2 | |
BIT_NOT_EXPR | 2 | |
TRUTH_ANDIF_EXPR | e | ANDIF和ORIF允许不计算第二个操作数,如果表达式的值可以从第一个操作数确定。AND,OR和XOR则永远对第二个操作数求值,不管它的值是否需要。操作数的类型应为BOOLEAN_TYPE或者INTEGER_TYPE |
TRUTH_ORIF_EXPR | e | |
TRUTH_AND_EXPR | e | |
TRUTH_OR_EXPR | e | |
TRUTH_XOR_EXPR | e | |
TRUTH_NOT_EXPR | e | |
LT_EXPR | < | 关系操作符表达式。其中EQ_EXPR和NE_EXPR允许为任何类型。其他操作符只允许为整型(包括指针或枚举类型),或者浮点类型。在所有情况下,操作数必须有相同的类型,而表达式的类型为语言所定义的布尔类型。 |
LE_EXPR | < | |
GT_EXPR | < | |
GE_EXPR | < | |
EQ_EXPR | < | |
NE_EXPR | < | |
UNORDERED_EXPR | < | 非序浮点数的比较操作符。 |
ORDERED_EXPR | < | |
UNLT_EXPR | < | 非序关系表达式,由GCC使用。(GCC提供了内建的宏,进行C99浮点比较操作,以避免在碰到非序操作数时,抛出异常。NaN的浮点数就是非序的)。 |
UNLE_EXPR | < | |
UNGT_EXPR | < | |
UNGE_EXPR | < | |
UNEQ_EXPR | < | |
IN_EXPR | 2 | Pascal中sets的操作。该版本GCC没有使用。 |
SET_LE_EXPR | < | |
CARD_EXPR | 1 | |
RANGE_EXPR | 2 | |
CONVERT_EXPR | 1 | 表示对一个值的类型转换 |
NOP_EXPR | 1 | 表示一个不需要额外产生代码的转换 |
NON_LVALUE_EXPR | 1 | 非左值的表达式 |
VIEW_CONVERT_EXPR | 1 | 代表把一个类型看作为另一个类型。对应于C中的用法:*(type2 *)&X |
SAVE_EXPR | e | 代表只能求值一次,却会被多次使用的结构(在GCC中,使用一般都会涉及求值,从而对子树进行简化) |
UNSAVE_EXPR | e | 表示诸如TARGET_EXPRs,SAVE_EXPRs,CALL_EXPRs和RTL_EXPRs,这些被防止多次求值的表达式,需被重置。这样新的expand_expr函数调用将对它们重新求值(re-evaluated) |
RTL_EXPR | e | 表示对应的RTL结构已被展开成一个序列,当该表达式被展开时,这个序列将被导出(emitted) |
ADDR_EXPR | e | C里的‘&’ |
REFERENCE_EXPR | e | 对一个对象的非左值引用或者指针 |
ENTRY_VALUE_EXPR | e | C++/C不用 |
FDESC_EXPR | e |
|
COMPLEX_EXPR | 2 | 复数表达式 |
CONJ_EXPR | 1 | 共轭操作符表达式 |
REALPART_EXPR | 1 | 实部表达式 |
IMAGPART_EXPR | 1 | 虚部表达式 |
PREDECREMENT_EXPR | e | C里的++和--。第二个操作数指明增加或减少的值。对于指针,则是指向对象的大小 |
PREINCREMENT_EXPR | e | |
POSTDECREMENT_EXPR | e | |
POSTINCREMENT_EXPR | e | |
VA_ARG_EXPR | e | 用于实现va_arg |
TRY_CATCH_EXPR | e |
|
TRY_FINALLY_EXPR | e |
|
GOTO_SUBROUTINE_EXPR | e | 在编译器内部,用于实现TRY_FINALLY_EXPR时,需要的清除操作 |
LABEL_EXPR | s | 被封装为语句的标示定义(A label definition,) |
GOTO_EXPR | s |
|
RETURN_EXPR | s |
|
EXIT_EXPR | s | 有条件地退出最内层循环 |
LOOP_EXPR | s | 循环 |
LABELED_BLOCK_EXPR | e | 带标识的代码块 |
EXIT_BLOCK_EXPR | e | 退出带标识的代码块,通常返回一个值 |
EXPR_WITH_FILE_LOCATION | e | 用源代码位置信息诠释一个树节点(通常为比表达式)。包括文件名(EXPR_WFL_FILENAME);行号(EXPR_WFL_LINENO);和列号(EXPR_WFL_COLNO) |
SWITCH_EXPR | e | Switch表达式 |
EXC_PTR_EXPR | e | 运行时的异常对象 |
表1 在tree.def中定义的树节点
在上表中的Type列,下列字母用作类识别码(class code),它们的含义如下:
Ø 'x'表示用于例外(不适合其它类别)。
Ø 't'表示用于类型对象。
Ø 'b'用于代码块。
Ø 'c'用于代表常量的节点
Ø 'd'用于代表声明的节点(同时用于临时变量的引用)。
Ø 'r'用于代表访问存储地址的节点。
Ø '<'用于比较表达式。
Ø '1'用于代表一元算术表达式的节点。
Ø '2'用于代表二元算术表达式的节点。
Ø 's'用于代表“语句”(statement)的表达式的节点,该表达式有副作用(side-effects),但其值不被关注(例如,语句“i=5;”有值5,但这个值被忽略了)。
Ø 'e'用于代表其他类型表达式的节点。
对于r,e,<,1,2,和s类型的节点,它们对应于结构体tree_exp,在DEFTREECODE 的定义中,第四个元素为需要在tree_exp中分配的参数的个数。从而确定了节点对象的大小。而对于其他类型节点,结构体本身大小确定,这第四个元素必须为0。如果定义了特定于语言的x或c类别的节点, 该语言的前端必须对langhook的tree_size挂钩(hook)提供函数,以确定这些节点的大小。
对于C++前端,特定于C++的节点定义于文件cp-tree.def。它们的含义如下。
节点码(tree code)
| 类型 | 描述 |
OFFSET_REF | r | OFFSET_REF节点用于下列两种情形: 1 形如A::m的表达式,其中 A是类(a class)而m是非静态成员(a non-static member)。在这种情况下,操作数0应该为对应于A的类型,操作数1可为FIELD_DECL,BASELINK,,或TEMPLATE_ID_EXPR(对应于m)。 如果地址被使用,这个表达式为指向成员的指针(a pointer-to-member),但如果地址没有被使用,表达式仅表示对象的成员。 这个形式只用于解析阶段;当语义分析完成后,它便不复存在。 2 形如x.*p的表达式。在这种情况下,操作数0 是对应于x的表达式,而操作数1则是类型为指向成员指针的表达式。 |
PTRMEM_CST | c | 指向成员的指针常量。对于指针常量X::Y,宏PTRMEM_CST_CLASS得到X对应的RECORD_TYPE,而PTRMEM_CST_MEMBER得到的是Y对应的声明。 |
NEW_EXPR VEC_NEW_EXPR | e e | 对于NEW_EXPR,操作数0定位操作符中的定位地址(placement list)。操作数1是new声明符(例如:new char[8])。操作数2是初始值。 |
DELETE_EXPR VEC_DELETE_EXPR | e e | 对于DELETE_EXPR,操作数0是要被摧毁的存储区,操作数1是传给销毁函数的值,以指示是否回收存储区。 |
SCOPE_REF | r | 引用特定的重载的类方法(particular overloaded class method)。操作数0是这个类,操作数1是方法。节点中的COMPLEXITY域指示类的层次(通常为0) |
MEMBER_REF | r | 引用对象的数据成员。操作数0是对象。操作数1是数据成员(通常由解引用指针得到) |
TYPE_EXPR | e | C++中的类型转换操作符。在节点中,TREE_TYPE是该转换符的目标类型。操作数0是要转换的表达式 |
AGGR_INIT_EXPR | e | 在节点中,操作数0是执行初始化操作的函数,操作数1是函数的参数列表,操作数2是为该表达式分配的内存 |
THROW_EXPR | e | (异常)抛出表达式。操作数0是该表达式,如果该表达式存在,否则为NULL_TREE(C++要求表达式必须出现,但需要考虑混合语言编程的情况)。 |
EMPTY_CLASS_EXPR | e | 表示空的类对象。在节点中TREE_TYPE给出了类的类型。我们使用这种节点避免为空的类生成实例。 |
ALIAS_DECL | d | 作为一个表达式的占位符的声明。用于实现非类域中的匿名union。 |
BASELINK | x | 表示从基类引用的成员函数。在节点中,BASELINK_FUNCTIONS给出对应的FUNCTION_DECL,或者TEMPLATE_DECL,或者OVERLOAD,或者TEMPLATE_ID_EXPR 。BASELINK_BINFO给出了定义该方法的基类,换而言之,当调用这个方法时,this指针需要被转换至的类型。BASELINK_ACCESS_BINFO则给出了最初定义这个方法的基类。 BASELINK代表一个表达式。它的TREE_TYPE给出了该表达式的类型。该类型或者是函数类型(FUNCTION_TYPE),获者是方法类型(METHOD_TYPE),或者是以unknown_type_node 代表的重载函数。 |
TEMPLATE_DECL | d | 模板定义。以下节点中的域都有特定用途,虽然在cp-tree.h中,有其他宏会使用这些域。 DECL_ARGUMENTS – 模板参数vector DECL_TEMPLATE_INFO – 模板特定的信息 DECL_VINDEX – 已具现的模板列表;该版本仅用于函数模板。 TREE_TYPE -- 构建对象的类型 DECL_TEMPLATE_RESULT – 构建对象的声明(例如:对以具现函数模板的FUNCTION_DECL) |
TEMPLATE_PARM_INDEX | x | 模板参数列表的索引。其中TEMPLATE_PARM_IDX 给出实参的索引(从0开始),而TEMPLATE_PARM_LEVEL给出模板参数的层次(从1开始)。例如: template <class T> // Index 0, Level 1. struct S { template <class U, // Index 0, Level 2. class V> // Index 1, Level 2. void f(); }; 域TEMPLATE_PARM_DESCENDANTS是由该节点降阶(descend)后的TEMPLATE_PARM_INDEX节点组成的链表。链表中第一个节点将有相同的索引(IDX),但层次(LEVEL)少一级。链表中节点的TREE_CHAIN域将这些降阶的节点(descendants)链在一起。 域TEMPLATE_PARM_DECL则对应这个模板参数的声明,它要么是个类型声明(TYPE_DECL)要么是个常量声明(CONST_DECL)。 域TEMPLATE_PARM_ORIG_LEVEL则是最外层父节点的层次(the LEVEL of the most distant parent),也即最初声明这个模板参数时,对应的层次(the LEVEL that the parameter originally had when it was declared)。例如,如果我们具现S<int>,我们将得到: struct S<int> { template <class U, // Index 0, Level 1, Orig Level 2 class V> // Index 1, Level 1, Orig Level 2 void f(); }; 如果我们关注模板的类型,TEMPLATE_PARM_LEVEL表示模板参数的层次;如果我们关注具现,则TEMPLATE_PARM_ORIG_LEVEL是关联的层次。 |
TEMPLATE_TYPE_PARM | t | 类型模板参数。对应的模板参数必须是类类型。而TYPE_FIELDS将包含一个TEMPLATE_PARM_INDEX节点。 |
TEMPLATE_TEMPLATE_PARM | t | 模板模板参数。它必须是类类型。TYPE_FIELDS将包含一个TEMPLATE_PARM_INDEX节点。它不绑定任何模板实参,就像C<TT>中的TT。 TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO 则是NULL_TREE,TYPE_NAME 则是对应的TEMPLATE_DECL。 |
BOUND_TEMPLATE_TEMPLATE_PARM | t | 类似TEMPLATE_TEMPLATE_PARM,但用于已绑定实参的模板参数,像TT<int>。在此情形下,TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO 包含模板名和绑定的实参。TYPE_NAME 是一个TYPE_DECL。 |
TYPENAME_TYPE | t | 由类似typename T::t指定的类型。 TYPE_CONTEXT对应T, TYPE_NAME是一个对应于t的IDENTIFIER_NODE 。如果该类型通过template-id来命名, TYPENAME_TYPE_FULLNAME将持有 TEMPLATE_ID_EXPR节点。如果TREE_TYPE不为空,该类型由隐式的类型扩展生成(generated by the implicit typename extension),TREE_TYPE保存了T基类的类型节点(_TYPE from a baseclass of T)。 |
UNBOUND_CLASS_TEMPLATE | t | 形如T::template C的模板模板实参。 TYPE_CONTEXT表示T,模板参数所依赖的对象。TYPE_NAME则是对应C的IDENTIFIER_NODE, 成员类模板。 |
TYPEOF_TYPE | t | 代表由__typeof (expr)指出的类型。TYPE_FIELDS则是要询问的表达式(即例中的expr)。 |
USING_DECL | d | 代表using声明。DECL_INITIAL指明指定的作用域(specified scope)。它不是别名(an alias),但随后它会被展开成多个别名。如果作用域(scope)是依赖的(dependent),该节点的类型是NULL_TYPE,否则就是void类型。 |
USING_STMT | e | 代表using directive。它唯一的操作数是USING_STMT_NAMESPACE |
DEFAULT_ARG | x | 未被解析的缺省实参(un-parsed default argument)。域TREE_CHAIN用于保存那些,必须在此实参被解析时,已被具现好的函数实例(instantiations of functions that had to be instantiated before the argument was parsed)。注:用于模板 |
TEMPLATE_ID_EXPR | e | 形如foo<int>的template-id。其中第一个操作数是所对应的模板节点。如果没有显式的实参,则第二个操作数是NULL,否则就是代表实参的TREE_VEC。所对应的模板节点可以是FUNCTION_DECL,TEMPLATE_DECL,或者OVERLOAD。而如果template-id表示一个成员模板(member template),所对应的模板节点可能是IDENTIFIER_NODE。 |
OVERLOAD | x | 用于链接候选的重载函数。 |
WRAPPER | x | 用于封装非树节点结构,使其可以链如树结构。 |
MODOP_EXPR | e |
|
CAST_EXPR | 1 |
|
REINTERPRET_CAST_EXPR | 1 |
|
CONST_CAST_EXPR | 1 |
|
STATIC_CAST_EXPR | 1 |
|
DYNAMIC_CAST_EXPR | 1 |
|
DOTSTAR_EXPR | e |
|
TYPEID_EXPR | e |
|
PSEUDO_DTOR_EXPR | e |
|
NON_DEPENDENT_EXPR | e | 用于模板中非类型依赖表达式(expression that is not type-dependent)的展位符(placeholder)。当一个非类型依赖的表达式出现在另一个表达式中,我们必须计算这个更大的表达式的类型(compute the type of that larger expression)。这个计算通常会改变原有的表达式,如果那个表达式出现在模板实参列表,这会改变表达式的修饰名(the mangling of that expression)。在这种情况下,我们创建NON_DEPENDENT_EXPR节点来记录原始的表达式(take the place of the original expression)。这个表达式是唯一的操作数,它只用于诊断目的。 |
CTOR_INITIALIZER | e |
|
TRY_BLOCK | e |
|
EH_SPEC_BLOCK | e |
|
HANDLER | e | HANDLER节点封装了一个对应catch句柄(catch handler)的HANDLER_TYPE节点。在HANDLER_PARMS 中是catch变量的声明,HANDLER_BODY则是catch块 |
MUST_NOT_THROW_EXPR | e | MUST_NOT_THROW_EXPR封装的是不会抛出异常的表达式,如果这表达式抛出了异常,程序必须调用terminate结束。 |
TAG_DEFN | e | 用于表示,在C++标准,[over.best.ics]节意义下的隐式转换序列。转换序列通过节点的第一个操作数链接在一起,链表中的转换以相反的次序执行。最里层的转换(亦即在链表尾端的节点)必须是代表自身变换(identity conversion)的IDENTITY_CONV)。 |
IDENTITY_CONV | e | |
LVALUE_CONV | e | |
QUAL_CONV | e | |
STD_CONV | e | |
PTR_CONV | e | |
PMEM_CONV | e | |
BASE_CONV | e | |
REF_BIND | e | |
USER_CONV | e | |
AMBIG_CONV | e | |
RVALUE_CONV | e |
表2 cp-tree.def中定义的树节点