GCC语法分析
483435351.doc
第四部分:GCC语法与语义分析程序
琚 小 明
浙江大学信息与通信工程学系 2002年8月
一、语法与语义分析程序的主要功能
语法分析是编译过程的第二个阶段。语法分析的任务是在词法分析的基础上将单词序列分解成各类语法短语,如“程序”,“语句”,“表达式”等等。一般这种语法短语也称为语法单位,可表示成语法树。
(一)语法分析程序的主要功能
语法分析所依据的是语言的语法规则,即描述程序结构的规则。通过语法分析确定整个输入串是否构成一个语法上正确的程序。在GCC中采用自底向上(bottom-up)最右规约的语法分析方法进行分析的,因为GCC的语法分析程序是由语法分析程序自动产生器(Yacc或bison)生成,LR方法是YACC设定的语法分析方法。
语义分析是审查源程序有无语义错误,为代码生成阶段收集类型信息。例如语义分析的一个工作是进行类型审查,审查每个算符是否具有语言
规范
编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载
允许的运算对象,当不符合语言规范时,编译程序应
报告
软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载
错误。
词法分析和语法分析本质上都是对源程序的结构进行分析。但词法分析的任务仅对源程序进行线性扫描即可完成,例如识别标识符,因为标识符的结构是字母打头的字母和数字串,这只要顺序扫描输入流,遇到既不是字母又不是数字字符时,将前面所发现的所有字母可数字组合在一起而构成单词标识符。但这种线性扫描不能用于识别的递归定义的语法成分,比如不能用此办法去匹配表达式中的括号。
(二)语法分析程序自动产生器(YACC)简介
由于GCC中的语法分析程序是由YACC产生的,故在此对YACC的工作原来作一简要的介绍。YACC的工作示意图如图1:(有关YACC的详细资料见YACC的说明文档)
YACC源程序
YACC
单词符号串 语法分析的 (终结符)输入串 输出 词法分析程序 语法分析程序
yylex yyparse
图1 YACC工作示意图。YACC源程序是用户按要求对要处理语言 的语法描述,经YACC产生语法分析程序yyparse。图中的词法分 析程序是GCC提供的,它的输出作为语法分析程序的输入。
- 1 -
483435351.doc
在图中YACC源程序是用户用YACC提供的一种类似BNF的语言写的要处理的语言的语法描述。YACC会自动的将这个源程序转换成用LR方法进行语法分析的语法分析程序yyparse,YACC的宿主语言是c,因此yyparse是一个c语言的程序,用户在主程序中通过调用yyparse进行语法分析。
语法分析必须建立在词法分析的基础之上,所以生成的语法分析程序还要有一个词法分析程序与它配合工作。yyparse要求这个词法分析程序的名字为yylex。用户写yylex时可以借助于LEX,也可以人工编写。
在YACC源程序中除了语法规则外,还要包括当这些语法规则被识别出来时,即用它们进行归约时要完成的语义动作,语义动作是用c语言写的程序段。
语法分析的输出可能是一颗语法树,或生成的目标代码,或者就是关于输入串是否符合语法的信息。需要什么样的输出都是由语义动作和程序部分的程序段来实现的。
(三)语法分析程序的文件构成
语法分析程序尽管是由YACC自动产生的,但其语义动作是由用户自己编写的c代码,构成语法分析程序的文件有:c-parse.y,tree.h,tree.def, c-tree.h,tree.c,c-decl.c,c-typeck.c, stmt.c等。其中c-parse.y是根据YACC的规范要求对c语言文法进行的语法描述文件,即YACC源程序,经YACC可产生相应的c文件c-parse.c。
相关的文件有c-lex.h,input.h,c-iterate.c,varasm.c,c-common.c,c-lex.c, machmode.h,
machmode.def, obstack.h, real.h, rtl.h。等
二、语法与语义分析程序的流程图及其说明
(一)语法分析程序的主要工作原理
由YACC产生的语法分析程序是由放在栈中的有限状态机构成的,它同时能够读取并记住下一个输入的单词(token),有时也叫这样的单词为向前看字符(lookahead token)。有限状态机的状态是用一个整数表示的,这与词法、语法分析程序中的单词是相似的。在初始时,机器处在0状态,此时仅仅栈中包含了状态0,而没有向前看字符被读入。
有限自动机在语法分析程序中可执行相应的动作,以决定下一步的动作。语法分析可执行的动作(action)共有4个,它们分别是:移进(shift)、归约(reduce)、接受(accept)和错误(error)。语法分析程序的运行如下:
1(根据当前状态,语法分析程序决定是否需要一个向前看字符以决定将要执行什么动作。如果需要一个单词但还没有读入时,语法分析程序将调用yylex获得下一个单词。
2(用当前状态和向前看字符(如果需要的话),语法分析程序决定它的下一个动作(action),并且执行这个动作。这样将导致状态被压入或被弹出栈,以及向前看字符是被处理了还是放在一边待用的不同变化。
以下分别说明4种语法动作:
移进动作(shift action)是语法分析程序采用的最平常的动作。根据当前栈的状态和向前看字符,语法分析程序查动作表(action表),以决定将采取什么动作。对于移进动作,不论何时采用移进动作,都有一个向前看字符,不然移进动作将无法执行对单词的清除处理。而对应的状态却被压入了状态栈,从而造成错误。
归约(reduce action)是用语法规则的左边代替其右边的过程。当语法分析程序已经看到某语法规则的右边,并且确定右边是语法规则的一个实例时,归约动作将被采用。通常语法分析程序在采
- 2 -
483435351.doc
用归约动作时是不需要查看向前看字符的。
归约动作能防止栈无限增大,因为大多数情况下归约动作是将状态弹出栈,减少占用的栈空间。归约动作取决于语法规则左边的符号(非终结符)和右边的符号(终结符和非终结符)数。归约动作首先根据语法规则右边的符号数决定将被弹出栈的状态数,然后将状态从栈中弹出,使栈中的其它的状态被显露出来。事实上,被弹出的状态就是在识别此规则右边单词时压入栈的状态,规则一旦被识别,这些状态将不再有用。将这些状态弹出之后,在状态栈中处在栈顶的状态是语法分析程序开始处理此规则之前的状态。使用弹出之后的状态和规则左边的符号,将获得一个新状态(查状态转换表即goto表得到)。将此新状态压入栈,语法分析继续。
处理左边符号和普通的单词移进是有明显的不同的。把对左边符号的移进动作叫做状态转换动作(goto action),尤其不同的是,当执行移进时,向前看字符是被清除的,但在执行状态转换动作时,向前看字符是不受影响的。
(事实上,归约动作在语法分析过程中好像是时间倒转,将状态从栈中弹出回到规则右边刚开始看到时的状态。当一条规则被识别时,语法分析程序好似在那时看到了规则的左边。)
如果规则的右边是空的,没有状态被弹出栈,也就是栈中被显露出来的状态就是栈中的当前状态。
归约在处理用户提供的动作和值时也是重要的。当一条规则被识别并被归约时,在栈被调整以前,由规则提供的代码(code)将被执行。语法分析程序使用两个栈:一个是拥有状态的栈,即上文提到的栈;另一个是与之并行运行的值栈(value stack),这个栈拥有从词法分析程序和动作返回的值。当移进时,外部变量yylavl被拷贝到值栈。从用户码(user code)返回后,归约被执行。当状态转换动作被执行后,外部变量yylval被拷贝到值栈。在YACC中,用伪变量$1,$2等来代表值栈的值,而$$代表左边非终结符的值。
另外两个语法动作相对来说比较简单。
接受动作(accept action)表明整个输入都已经看到并且匹配语法规则,这个动作只有当向前看单词是endmarker(文件结束符,在GCC中是以EOF为文件结束符的)才被采用,表明语法分析程序已经成功地完成语法分析工作。
报错动作(error action)说明根据规则在某处语法分析程序不能再继续语法分析了。当输入的单词已经被看到,同时还有向前看字符,但后面不能跟随可导致合法输入的任何东西,此时语法分析程序报告一个错误,并且试图恢复状况(situation),试图接着进行语法分析。
(二)语法分析程序yyparse的主要流程说明
在语法分析过程中,YACC语法分析器主要使用两个栈:一个是状态栈,一个是语义值栈。两套指针:short *yyss, yyssa;YYSTYPE *yyvs, yyvsa。
1( 初始化状态栈的状态和值栈的单词值。yystate=0;yyerrstatus=0;yynerrs=0;yychar=YYEMPTY;
初始化栈指针:yyssp=yyss-1; yyvsp=yyvs;
对于其中主要变量的说明:yychar 是lookahead symbol;yychar1是yychar的语法分析的内部形式;yylval 是lookahead symbol 的语义值; yyval 是用于从执行程序中返回语义值;yystate 是从执行程序中返回的状态。
2(yynewstate:将返回的状态yystate压入状态栈,成为新状态。*++yyssp=yystate;
3(取出产生式号yyn=yypact[yystate];如果产生式号yyn为YYFLAG,则转到4(yydefault)。如果yychar为YYEMPTY,则调用词法分析函数得到一个单词(token),即 yychar=YYLEX。 索引表是用单词(token)的内部形式索引的,故将单词转换为内部形式。 当yychar<=0 时:yychar1=0; yychar=YYEOF;当yychar>0时:yychar1=YYTRANSLATE(yychar);
计算yychar1的产生式号:yyn+=yychar1;根据计算的产生式号到表中取出相应的产生式号:
- 3 -
483435351.doc
初始化状态和栈指针 yynewstate
读取向前看单词,并将其转换
成语法分析的内部形式;置新
状态。
计算产生式号,并由此查yytable
表得到产生式号yyn
Y
归约 yyn < 0
N Y Y yyn > 0 移进
N
Y yyn < 0或 出错 yyn=0
N Y
yyn是终态, 成功
N
图2 语法分析程序的流程图。语法分析有两个栈:一个是状态栈;一个是值栈。这 两个栈在进行语法分析时,它们的栈指针是同步移动的。对于出错情况的处理有两 种:一种是处理后继续执行语法分析;一种是中断返回。图中用虚线表示是编译器 多数情况下的处理结果。
yyn=yytable[yyn]。yyn是这个token类型在此状态下要做的动作:如果yyn是正数,则移进,而yyn是新状态。如果yychar不是YYEOF,则放弃被移进的token,置yychar=YYEMPTY; *++yyvsp=yylval; yystate=yyn;转到2(yynewstate);如果新状态是终态,则返回成功而不必移进。
4(yydefault:执行当前状态的默认产生式。 yyn=yydefact[yystate];
5(yyreduce:如果yyn是负数,则规约,而-yyn是语法规则号,yyn=-yyn;yylen=yyr2[yyn]; 如果yylen>0, 则yyval=yyvsp[1-yylen];由此实现执行的默认值。
6(如果yyn是0或者大多数的负数时,则出错。
7(根据yyn的值确定产生式,并执行相应的动作。
8(规约后,yyvsp-=yylen;yyssp-=yylen;将单词(token)的语义值赋给语义栈,*++yyvsp=yyval;
- 4 -
483435351.doc
yyn>0
N
yychar!=YYEOF
Y
放弃被移进的单词
yychar=YYEMPTYY
将单词的值压入值栈
*++yyvsp=yylval
将新状态压入状态栈
yystate=yyn
yynewstate
图3 移进动作的流程图。移进动作较简单,只需将单词放弃,即将yychar
置为YYEMPTY。然后将单词的值和新状态分别压入值栈和状态栈。返
回到语法分析的开始处。
9(根据弹出后的状态和被规约的产生式号决定转换到什么状态。yyn=yyr1[yyn]; yystate=yypgoto[yyn-YYNTBASE]+*yyssp;
当yystate不在yytable表中时,yystate=yytable[yystate];否则yystate=yydefgoto[yyn-YYNTBASE];转到2(yynewstate)。
10(yyerrhandle:出错处理。yystate=yyn;转到2(yynewstate)。或返回1。
11(yyacceptlab:接受状态,释放栈空间:free(yyss);free(yyvs); 并返回0。
对于语法分析时进行归约所要执行的动作在此不作介绍,相关的说明见第四部分的函数功能介绍和语法树结构等内容。归约动作的主要内容是建立语法树,并进行相应的语法和语义分析。
- 5 -
483435351.doc
yyn<0
将产生式号取反yyn=-yyn
查yyr2表得到归约的长度
yylen=yyr2[yyn]
Y yyval=yyvsp[1-yylen] yylen>0
N
根据yyn的不同完成各种归约动作
(详见源代码)
根据归约的长度yylen,弹出状态栈和值
栈中相应数量的状态和值。
yyvsp-=yylen;yyssp-=yylen;
将返回的语义值置入值栈
*++yyvsp=yyval
移进归约的结果yyn=yyr1[yyn];
根据当前的状态和归约的产生式号,决定转换的
状态
yystate=yypgoto[yyn-YYNTBASE]+*yyssp
yystate>=0&&yystate<= Y
查yytable表得到新状态 YYLAST&&yycheck[yy
yystate=yytable[yystate] state]==*yyssp
N
查yydefgoto表得到新状态
yystate=yydefgoto[yyn-YYNTBASE]
yynewstate
图4 归约动作的流程图。根据产生式号进行相应的归约动作,用产 生式的左边代替右边,并将相应的状态和值弹出栈。根据当前状态 和产生式号,从转换表(yypgoto)中得到新状态。
- 6 -
483435351.doc
三、语法与语义分析程序的数据结构及其说明
GCC语法分析程序的一个主要任务是建立合理和有效的语法树。为此,GCC定义了由12个数据结构组成的一个联合,这个联合能够描述不同树节点的全部内容。这些不同的树节点是由TREE_CODE来说明的,而TREE_CODE是在文件tree.def中定义的。
一个树节点能描述一个数据类型、一个变量、一个表达式或一个语句。每个节点都有一个TREE_CODE用来说明所描述的内容是哪类的。例如常用的codes:INTEGER_TYPE描述的是整型类型;ARRAY_TYPE描述的是指针类型;VAR_DECL描述的是已声明了的变量;INTEGER_CST描述的是整型常量值;PLUS_EXPR描述的是一个和(一个表达式)等。
(一) 树节点的类型TREE_CODE的有关说明
对TREE_CODE的定义采用如下方法:
#define DEFTREECODE(SYM, STRING, TYPE, NARGS) SYM,
enum tree_code {
#include “tree.def”
LAST_AND_UNUSED_TREE_CODE
};
#undef DEFTREECODE
文件tree.def是用来定义TREE_CODE的,其形式如下:
DEFTREECODE(IDENTIFIER_NODE, “identifier_node”, “x”, -1)
其中的第一个参数是用来定义TREE_CODE的;第二个参数是输出时用的;第三个参数可以是下列参数之一:
“x” 用于表示特别的TREE_CODE,它不属于任何一类。
“t” 用于表示类型。
“b” 用于表示词法的块。
“c” 用于表示常量。
“d” 用于表示声明。
“r” 用于表示访问存储器。
“<” 用于表示比较表达式。
“1” 用于表示一元算术表达式。
“2” 用于表示二元算术表达式。
“s” 用于表示固有副作用(side effects)的表达式。
“e” 用于表示其他种类的表达式。
对应 “r”、“e”、“<”、“1”、“2”、“s”和“x”所表示的节点,第四个元素是表示要分配参数槽的数量,这决定了树节点的大小。
TREE_CODE共有11种类别(数字表示可再分类的个数),总计有125种不同的TREE_CODE用来表示不同的节点,下面所列的是关于对文件tree.def的一个统计,详细的内容见源代码。 1. error_mark: 1
2. identifier: 2
3. tree_list: 1
4. tree_vec: 1
- 7 -
483435351.doc
5. block:: 1
6. datatype: 20 (5 for pascal)
7. constant: 5
8. declaration: 8
9. reference: 6
10. constructor:1
11. expression: 79 (4 for pascal)
(二) 树节点的有关结构说明
对于一个树节点的内容,有些结构成员或字段(fields)是所有节点共享的,同样有些有各自不同特殊用途的字段。在GCC中,为了一致树节点的结构,定义了一个联合(union)tree_node,所有的树节点均可以用此联合来表示。在这个联合中,总共包含了12个结构,其中结构tree_common是一个通用的结构,可以认为是其他11个结构的共有部分。另外11结构是为各种不同的树结构而定义的,但它们在结构定义中都为tree_common结构保留了空间,因此,tree_common结构在联合中始终是存在的,成为所有结构的共享部分。这个联合的定义如下:
union tree_node
{
struct tree_common common; //通用结构,是其他11个结构在联合中的共有部分。
struct tree_int_cst int_cst; //整型常量结构
struct tree_real_cst real_cst; //实型常量结构
struct tree_string string; //字符串常量结构
struct tree_complex complex; //复数类型结构
struct tree_identifier identifier; //标识符结构
struct tree_decl decl; //声明与定义结构
struct tree_type type; //类型说明结构
struct tree_list list; //列表节点,用于数据结构的描述等
struct tree_vec vec; //矢量结构
struct tree_exp exp; //表达式结构
struct tree_block block; //块结构,用于描述函数体等
}
以及一个重要的结构指针的定义:
typedef union tree_node * tree;
在GCC中,对节点的结构成员或字段(fields)是不直接存取的,都是通过定义宏的方式来实现这一目的的。例如:
#define TREE_CODE(NODE) ((enum tree_code)(NODE)->common.code)
这些宏的定义都是在文件tree.h中。
下面将对联合中的每个结构的主要结构成员作一简要的说明,关于联合中的12个结构的定义详见附录。
(1) 结构tree_common主要成员的说明:
code:code即指TREE_CODE,说明的是什么类型的节点。Code是在文件tree.def中定义的。
- 8 -
483435351.doc
type:在所有是表达式的节点中,这是表达式的数据类型;在POINTER_TYPE节点中,这是指针所指向的类型;在ARRAY_TYPE节点中,这是元素的类型。
chain:很多情况下节点是通过chain链接起来的,这些节点被链接在一起有很多用途。如:a、类型节点被链接在一起是为输出到debugger调试程序而
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
这些类型的; b、在同一范围(scope)的声明节点将被链接在一起以记录此范围的内容;c、连续语句的语句节点通常被链接在一起;d、通常列表(lists)是由被链接在一起的TREE_LIST节点来描述的。
(2) 结构tree_int_cst主要成员的说明:
在INTEGER_CST节点中,int_cst_low和int_cst_high一起组成一个2字节整数。如果是有符号的数据类型,则整数的值是扩展符号位的2字节数,即使原来的2字节并不是所有位都被使用。如果是无符号的整数常量,则额外的符号位是0。
在FACT_CST节点中,2个长整型用来得到64位数,用于描述分数。
(3) 结构tree_real_cst主要成员的说明:
在REAL_CST节点中,可以将一个实数值描述成“double”或是字符串。
(4) 结构tree_string主要成员的说明
length:是字符串的长度,整型。
pointer:是指向字符串的字符指针。
(5) 结构tree_complex主要成员的说明:
real:在COMPLEX_CST节点中real是复数的实部。
imag:在COMPLEX_CST节点中imag是复数的虚部。
(6) 结构tree_identifier主要成员的说明:
这是为某些特殊用途的树节点定义的。
length:是标识符的长度。
pointer:是指向标识符的字符指针。
(7) 结构tree_list主要成员的说明:
这些list节点通过TREE_CHAIN链接成列表。
purpose:指向参数链的指针。
value:
(8) 结构tree_vec主要成员的说明:
length:是数组元素的个数。
a[1]:是指向数组元素的结构指针。
(9) 结构tree_exp主要成员的说明:
complexity:
operands[1]:是指向操作数的结构指针。在SAVE_EXPR节点中,用的是operands[1], operands[2]。
在RTL_EXPR节点中,用的是operands[0], operands[1]。在CALL_EXPR节点中,用的是
operands[2]。在CONSTRCTOR节点中,用的是operands[1]。在通常的表达式节点中,任意一
个操作数operands[I]都有可能被使用, 同时还有成员complexity。
(10) 结构tree_block主要成员的说明:
subblocks:包含了一个由BLOCK_CHAIN 链接起来的子块的链。
supercontext: 指向父块(parent block)。 对于一个描述函数最外层范围的块,它指向函数声明
- 9 -
483435351.doc
节点(FUNCTION_DECL)。
vars: 指向声明节点的链。
type_tags:指向有自己名字的类型的链。
chain: 指向下一个同一级(level)的块,即指前面提到的BLOCK_CHAIN。
abstract_origin: 指向起始(original)树节点,当前块是起始数节点的一个实例(instance),或者它为NULL,表明当前块不是其他任何节点的实例。当它为非空(non-NULL)时,它可指向另一个块节点,或者指向一个函数声明节点。
abstract_flag: 如果当前块描述的是一个块的起始实例,则它是非0的。
(11) 结构tree_type主要成员的说明:
size:包含一颗树,这颗树是一个按位计算大小的表达式。
包含这种类型的机器模式的值。 mode:
pointer_to:包含了一个类型,用一个指针指向这种类型。如果pointer_to为0,则这种类型的节点还未建立。
next_variant:是用于链接由类型限定修饰词"const" 和 "volatile"修饰的变量的类型。
main_variant:指向上述由TYPE_NEXT_VARIANT链接的链的头指针。
noncopied_parts:是一个 list节点,用于说明这个类型的对象哪一部分是不能通过赋值拷贝的。 每个节点的TREE_PURPOSE 是这部分的偏移量。TREE_VALUE 是这部分以位计的大小。
name:包含为这种类型在程序中使用的名字的信息(为GDB符号表的输出)。它是一个类型定义(typedef)的 TYPE_DECL节点;或者是一个IDENTIFIER_NODE 节点在结构、联合、枚举已知是有标签(tag)的;或者是0,当类型还没有特殊的名字。
context:对类型有一个名字或者已经命名的成员(member)中的任意一种情况,它指向描述给定类型的范围的节点,或者如果此类型具有文件范围(file scope),则它是NULL_TREE。对大多数的类型来说,它将指向一个块(block)节点或是函数声明节点(FUNCTION_DECL),但是它也能够指向函数类型节点(FUNCTION_TYPE),或者是结构类型节点(RECORD_TYPE)和 联合类型节点(UNION_TYPE)。
chain:是用于枚举类型(ENUMERAL_TYPE),结构类型(RECORD_TYPE) 和 联合类型(UNION_TYPE)节点的。
(12) 结构tree_decl主要成员的说明:
所有与名字有关的都描述为..._DECL节点,这些在一个绑定上下文(binding context)的节点通过TREE_CHAIN链接起来。
name:包含一个IDENTIFIER_NODE的节点,此节点是给定实体的名字。对labels来说,DECL_NAME为0。
context:指向描述此声明作用范围的上下文的节点。对FIELD_DECLs而言,这是定义它的RECORD_TYPE 或是 UNION_TYPE 节点。对VAR_DECL, PARM_DECL, FUNCTION_DECL,
LABEL_DECL, 及CONST_DECL 节点来说,它指向包含它们的FUNCTION_DECL节点。如果给定的声明是文件范围,则它是 NULL_TREE。
abstract_origin:如果非0,它指向起始(original)声明节点,而当前声明节点是它的一个实例(instance)。
当相关的时候,TREE_TYPE 拥有对象的数据类型。而LABEL_DECLs 没有数据类型。对TYPE_DECL来说, TREE_TYPE 的内容是一个类型,它的类型名正在被声明,也可以说TREE_TYPE是已声明实体的类型。
frame_size, size, 和mode: 存在于声明节点和类型节点,它们在LABEL_DECL, TYPE_DECL 和 CONST_DECL 节点中是没有用的。
以下三个字段仅与 FIELD_DECLs 和PARM_DECLs有关:
DECL_OFFSET :拥有相对位偏移的整数值。
DECL_VOFFSET: 拥有可变偏移的表达式,它与DECL_VOFFSET_UNIT (一个整数)相乘可得偏移量。
initial:拥有对一个变量的初始化的值,或是初始化一个常量的值。对一个函数而言,它指向一个块(block),用一个块来说明函数的binding contour并且包含了函数的语句。对于C 中的 LABEL_DECL, 它是一个标志(flag),当label的定义已被看见时,此标志为非0。
- 10 -
483435351.doc
PARM_DECLs 使用特殊的字段:
initial:是参数实际上通过类型检查的类型,此类型可能与它原来在函数中的类型有所不同。
FUNCTION_DECLs 使用以下四个特殊的字段:
arguments: 拥有一条参数声明PARM_DECL节点的链。
result:拥有一个函数返回值声明的 RESULT_DECL 节点。或者当函数无返回值时,它为0。(在c中,函数返回void即为无返回值)
DECL_RESULT_TYPE :拥有函数实际返回值的类型。这通常与DECL_RESULT的类型是相同的,但这可能是一个宽整型类型;同时为了内联,甚至对函数的编译已经结束,这仍然有效。这是两者的不同之处。
frame_size:是一个代码数字(code number),非0时表示是内建函数(built-in function)。它的值是一个枚举类型值,指明了是哪一个内建函数。
filename: 拥有一个文件名字符串。
linenum:拥有一个行数。
abstract_flag:非0时,此声明说明一个声明的抽象实例(abstract instance)。
(三) 建立树节点时的有关栈与数据结构的说明
Gcc在处理语法树节点时使用栈存放节点的内容,有关各个栈的详细内容见源代码,下面仅对各栈作一简要的说明:
1. permanent_obstack 存放永久的树节点,如标识符,全局的有关东西,函数定义的参数等。 2. maybepermanent_obstack 存放在函数内的初始的RTL和_TYPE节点,通常它们在函数结束时
被释放。
3. temporay_obstack是用来读全局变量的初始化值的。
4. momentary_obstack 存放表达式的树节点,它们在表达式结束时都被释放。 5. temp_decl_obstack 存放的树节点,当声明通过语法检查时被释放。
6. momentary_level 暂时存放momentary_obstack,以便恢复。
7. obstack_stack 时用来选择推进还是弹出obstack。
标识符节点、体外所有的东西和函数定义的参数分配在permanent_obstack中。RTL的初始化,所有在一个函数内的_TYPE节点分配在function_maybepermanent_obstack中,通常它们在函数结束时被释放,但如果函数是内联函数时将被储存,嵌套的函数存放在各自分开的栈中。当前函数定义的内容分配在function_obstack中,在函数结束时全部被释放,嵌套的函数存放在各自分开的栈中。表达式节点分配在temp_decl_obstack中,当声明体通过语法时全部被释放。
Struct obstack *saveable_obstack 指向permanent_obstack 或者当前的function_maybepermanent_obstack.
Struct obstack *current_obstack 指向permanent_obstack或者当前的function_obstack. 在语法和展开期间,Struct obstack *rtl_obstack 与saveable_obstack一样;在优化时它指向当前函数的栈;这是用来产生rtl 对象的栈。
Struct obstack *current_obstack指向permanent_obstack 或者当前的function_obstack或者momentary_obstack.
对每个binding contour 分配一个binding _level structure,这个结构记录了定义在那个contour中的names。Contour 包括:全局的contour;每个有参数的内部声明出现的函数定义;复合语句,记录它的声明。
struct binding_level
- 11 -
483435351.doc
{
tree names;
tree tags;
tree shadowed;
tree blocks;
tree this_block;
struct binding_level *level_chain; char parm_flag;
char tag_transparent;
char subblocks_tag_transparent;
char keep;
char keep_if_subblocks;
int n_incomplete;
tree parm_order;
}
names:指向所有变量,常量,函数和typedef 类型的_DECL节点的链。这个链是以相反的顺序提供的。
tags:指向一个结构,联合和枚举定义的list, 这是一个TREE_LIST 节点的链,每个节点的TREE_PURPOSE 时一个name或者NULL_TREE; 节点的TREE_VALUE时一个RECORD_TYPE,UNION_TYPE,或者是ENUBERAL_TYPE节点。
对每一层,当这一层被弹出时,被屏蔽的外层局部定义的list 将被存储。每个link 是一个TREE_LIST, 它的TREE_PURPOSE时一个标识符,它的TREE_VALUE是它原来的定义(-DECL节点)。
blocks:对于每一个level,都有一条由块(block)节点组成的链,blocks指向此链。
shadowed:对于每一个level,当这个level被弹出时,被屏蔽(shadowed)的外层level的局部定义的list节点将被储存起来。每个list链节点的TREE_PURPOSE是一个标识符,而TREE_VALUESHI 是它老的定义(是_DECL节点)。
this_block:这层level的block节点由this_block指向。
level_chain:binding_level是由level_chain链接在一起的。
parm_flag:非0表示此level拥有函数的参数。
tag_transparent:非0表示这层level没有tags。
parm_order:声明的列表是以相反的参数顺序说明的。
定义了三个主要的结构指针,其中current_binding_level是当前有效的操作level;free_binding_level是binding_level的链,用来把释放的binding_level链起来以备重复使用。目的是减少内存堆中的碎块;global_binding_level是最外层的binding_level,它是在编译器开始编译的时候建立的,并在整个运行过程中存在。它们分别定义如下:
struct binding_level * current_binding_level; struct binding_level * free_binding_level; struct binding_level * global_binding_level;
(四)语法分析时建立的语法树结构
对于每个binding contour都将分配一个binding_level节点,用来记录在这个contour这定义的names。Contour包含以下三个方面:
1( 全局的contour。
- 12 -
483435351.doc
2( 每个函数定义都有一个对应的contour,参数的内部声明出现在那里。
3( 每个复合语句对应一个contour,用来记录它的声明。
结构指针free_binding_level的用处:
当一个binding_level节点被弹出时,并不实际释放内存空间,而是将此节点链入到free_binding_level指向的链中。当需要一个binding_level节点时,首先查看free_binding_level链释放为空。若有就重复使用原来已经存在的节点,否则新建一个节点。
supercontext
block decl node current_function_decl
initial result initial result initial result
binding_level current_binding_level global_binding_level
names tags blocks names tags blocks names tags blocks
list node
value purpose value purpose value purpose
type node
context context context
block node
block/
current_function_decl initial
decl node binding level node list node type node block node
图5 顶层的语法树结构binding_level。GCC在进行语法分析时,是以 current_binding_level为中心,所有的声明、参数定义和块等都是挂在 binding_level上的。图中的虚线箭头表示省略了节点,对与其他图相连的连 线和箭头采用不同的颜色加以区别。
存储当前level的状态:
decls)每当当前level被弹出时,level中的状态将被保存到一个块(block)中。将当前level的names(链入block的vars;将当前level的tags链入block的type_tags;将当前level的blocks链入block的subblocks。然后将当前level节点弹出,同时链入到free_binding_level链中,并使下一个level节点成为当前level。
- 13 -
483435351.doc
parm decl node
initial result initial result initial result
block node
supercontext supercontext
current_function_decl
names initial result type arguments
decl node
context type node
type values
type node list node
value purpose value purpose value purpose
arg types
图6 当前函数声明current_function_decl的语法树结构。initial 指向的
block节点包含了函数体的语句;result指向的decl节点是函数的返回值;
arguments指向的是参数声明节点的链。TYPE_VALUES是list链,它的
TREE_PURPOSE是名字,TREE_VALUE是值 ( INTEGER_CST节点)。
block node
vars type_tags subblocks supercontext block
current_function_decl
blocks block node
list node tags
value purpose value purpose value purpose
decl node names
initial result initial result initial result
图7 块节点block的语法树结构。一个块包含声明、参数、子块等,
这些都是挂在同一个块的节点上的。以个块也可能是一个函数体,
在图5中,函数声明initial指向的块block就是一个函数体。
- 14 -
483435351.doc
四、语法与语义分析程序主要函数的功能:
void push_obstacks (curren, saveable) struct abstack* current, *saveable; 将当前各栈的指针放到obstack_stack 中,然后将current,saveable设置为当前栈。
void push_obstacks_nochange ()
将当前各栈中的指针存放到obstack_stack中,并使栈指针指向它。
void push_momentary ()
分配临时存储空间(struct momentary_level) (在c 中,每个复合语句有自己的层次,这个层次在每个语句结束时被释放。所有表达式节点也是分配momentary_stack)。
void pop_momentary ()
释放momentary_stack。
tree make_node (code)
enum tree_code code;
根据code指向不同的obstack, 在obstack 中创建对应code 的节点,并返回这个节点的指针。 Identifier 节点始终是永久的,因为它们在编译器运行中是唯一的,初始化它的id和它的TREE_PERMANENT flag。对decl和type节点,一些其它fields要初始化(如decl_source_line;
decl_source_file; decl_source_file 等)。其余的都初始化为0。
tree copy_node (node)
tree node;
根据node 确定不同类型的TREE_CODE, 在当前栈中创建对应code的节点,并将node 拷贝到当前栈的节点,不同的是TREE_CHAIN 为0。TREE_PERMANENT不同,返回指向新建节点的指针。
tree copy_list (list)
tree list;
调用copy_node (node)将list 指向的节点链拷贝到当前栈中,返回链的头指针,链是由TREE_CHAIN链接起来的。
tree get_identifier (text)
register char* text;
根据字符串text 查hash_table,找到则返回指向它的指针;否则调用make_node (node)在permanent_obstack中建立一个节点,并将此节点链入hash_table中,返回指向新节点的指针。
tree built_int_2_wide (low, hi)
HOST_WIDE_INT low, hi;
调用make_node (node) 新建一个INTEGER_CST节点,它的常数值由两个整形数low和hi说明,TREE_TYPE置为int 型,返回指向此节点的指针。
此函数需经过宏build_int_2被使用。
- 15 -
483435351.doc
tree build_real (type, d )
tree type;
REAL_VALUE_TYPE d;
调用make_node (node)建立一个REAL_CST节点,置TREE_TYPE为type, 它的值为d, 返回指向此节点的指针。
tree build_string (len, str)
int len;
char* str;
调用make_node (node) 建立一个STRING_CST节点,将TREE_STRING_LENGTH置为len, TREE_STRING_POINTER指向字符串,返回指向此节点的指针。
tree build_complex (real, imag)
tree real, imag;
调用make_node (node) 建立一个COMPLEX_CST节点,它的值由实部real和虚部imag说明,real和imag要求是常数节点,TREE_TYPE指向COMPLEX_TYPE节点,返回指向新建节点的指针。
tree make_tree_vec (len)
int len;
在当前栈中分配存储空间,建立TREE_VEC节点,它的长度置为len, 返回指向此节点的指针。
tree chainon (op1, op2)
tree op1, op2;
op1,op2是两个由TREE_CHAIN链接的节点链,通过修改op1最后一个节点的chain使之指向op2,实现将op1, op2链接在一起,返回指向头的指针。
tree nreverse (t)
tree t;
颠倒链t 中各元素节点的顺序,返回指向新链头的指针(即原链中最后一个元素)。
tree listfy (chain)
tree chain;
给定由chain 指向的节点链,将chain 中的节点建成TREE_LIST节点,TREE_VALUE指向对应chain节点,并将各TREE_LIST节点通过TREE_CHAIN链接, 返回指向第一个节点的指针(顺序与chain一致)。
tree build_tree_list (parm, value) tree parm, value;
调用make_node (node) 建立一个TREE_LIST的节点,置它的TREE_PURPOSE为parm, TREE_VALUE为value, 返回指向此节点的指针。
tree build_decl_list (parm, value) tree parm, value;
调用build_tree_list (parm, value)建立一个TREE_LIST节点,不同是建立在temp_decl_obstack中。
tree tree_cons (purpose, value, chain)
- 16 -
483435351.doc
tree purpose, value, chain;
在当前栈中分配空间,建立一个TREE_LIST节点,置其code 为TREE_LIST,TREE_PURPOSE为purpose,TREE_VALUE为chain, 即将新节点链入chain链的链首,并返回头指针。
tree decl_tree_cons (purpose, value, chain) tree purpose, value, chain;
此函数是通过调用tree_cons (purpose, value, chain)实现的, 不同的是建立在temp_decl_obstack中。
tree perm_tree_cons (purpose, value, chain) tree purpose, value, chain;
在permanent_obstack 中调用tree_cons (purpose, value, chain)建立一个TREE_LIST节点,返回链的头指针。
tree temp_tree_cons (purpose, value, chain) tree purpose, value, chain;
在temporary_obstack 中建立TREE_LIST节点,并将节点链入chain 链中,返回链的头指针。
tree saveable_tree_cons (purpose, value, chain) tree purpose, value, chain;
在saveable_obstack 中建立TREE_LIST,并将节点链入chain 链中,返回链的头指针。
tree build (enum tree_code code, …)
调用make_node (code)建立一个code的节点,置此节点的TREE_TYPE为type, 操作数TREE_OPERAND由参数arg1及其后面的参数说明, 构成一个表达式节点。返回指向此节点的指针。
注:表达式及其相关的节点能以这种方式建立;常数,声明,类型及misc节点则不能用此方式建立。
tree build (code, type, node)
enum tree_code code;
tree type;
tree node;
同build (),但仅仅为一元操作符建立表达式节点,在表达式栈中分配空间,置TREE_TYPE为type,TREE_SET_CODE为code,TREE_OPERAND为node等。返回指向此节点的指针。
tree build_nt (enum tree_code code, …)
调用make_node (code)建立一个code 节点,置TREE_OPERANT,不同的是没有说明TREE_TYPE且置TREE_SIDE_EFFECTS为0。返回此节点的指针。
tree build_parse_node (enum tree_code code, …)
同buil_nt (), 不同的是节点建立在temp_decl_obstack,调用make_node (code)建立节点,置TREE_OPERANT。返回此节点的指针。
tree build_decl (code, name, type)
enum tree_code code;
tree name, type;
调用make_node (code)建立一个code节点,置DECL_NAME为name, DECL_ASSEMBLER_NAME
- 17 -
483435351.doc
为TREE_TYPE为type等。返回指向此节点的指针。
tree build_block (vars, tags, subblocks, supercontext, chain)
tree vars, tags, subblocks, supercontext, chain; 调用make_node (node)建立一个节点,置BLOCK_VARS为vars,BLOCK_TYPE_TAGS为tags, BLOCK_SUBBLOCKS为subblocks,BLOCK_SUPERCONTEXT为supercontext,BLOCK_CHAIN为chain。返回指向此节点的指针。
tree build_type_variant (type, constp, volatilep) tree type;
int constp, volatilep;
调用copy_node (type)将type节点拷贝到新建节点,置此节点的TYPE_READONLY为constp, TYPE_VOLATILE为volatilep,TYPE_POINTER_TO为0,TYPE_REFERENCE_TO为0,并将新节点加入由TYPE_MAIN_VARIANT为头指针的变量类型节点链的第二个节点位置。返回指向新节点的指针。
tree build_type_copy (type)
tree type;
调用copy_node (type)建立一个新节点,置TYPE_POINTER_TO为0,TYPE_REFERENCE_TO为0,并将新节点链入由TYPE_MAIN_VARIANT指向的变量类型链的第二个节点位置。返回指向新节点的指针。
struct type_hash
{ stuct type_hash *next;
int hashcode;
tree type;
}
struct type_hash* type_hash_table[59]; hash table用于以下几种类型:函数类型,数组类型及数组下标范围类型。当所有这些类型在同一表中,它们是完全独立的,对每一种类型,hash code的计算是不同的。
tree type_hash_lookup (hashcode, type) int hashcode;
tree type;
在hash table中查找给定的hashcode,type,找到则返回改表相的type,否则返回0。
void type_hash_add (hashcode,type) int hashcode;
tree type;
建立一个给定的hashcode,type的节点,并将此节点加入hash table的表项中。
tree type_hash_canon (hashcode, type) int hashcode;
tree type;
对给定的hashcode,type,调用type_hash_lookup ()查找hash table,若找到则释放当前栈中的节点,返回该找到节点的指针;否则调用type_hash_add()在hash table 中增加表项,并返回type。
- 18 -
483435351.doc
int tree_list_equal (l1,l2)
tree l1, l2;
给定两个类型的list,它是由TREE_LIST节点构成的链,其TREE_VALUE包含类型在其中,如果两个list以同样顺序包含相同类型,且TREE_PURPOSEs也匹配,则返回1,否则返回0。
int tree_int_cst_equal (t1, t2)
tree t1, t2;
入两个整型常量t1,t2相等则返回1,否则返回0。
int tree_int_cst_lt (t1, t2)
tree t1, t2;
如果整型常量描述的值t1
blocks, block)将给定的block 节点链入当前binding_level的blocks链尾。
void set_block (block)
register tree block;
将当前binding_level的this_block指向给定的block节点。
void pushtag (name, type)
tree name, type;
将结构、联合或枚举的定义或声明置入tag链中。type应为类型节点。
- 22 -
483435351.doc
将给定的name, type的结构(type的TYPE_NAME指向name)置入tags链中。首先查找tag_transparent为0的binding_level, 并将它的tags指向新建的list节点,其TREE_VALUE为type,TREE_PURPOSE为name。
int duplicate_decls (newdecl, olddecl) tree newdecl, olddecl;
当一个新的声明NEWDECL和老的声明具有相同的名字时,调用此函数进行处理。如果可能,改变OLDDECL是其与NEWDECL相象,返回1。否则返回0。
tree pushdecl (x)
tree x;
将x的context指向current_function_decl。如果x节点的DECL_NAME不为0,返回当前binding_level旧声明链中符合x的DECL_NAME的节点指针。如果x的DECL_NAME为0,则返回指针x。
tree pushdecl_top_level (x)
tree x;
同pushdecl(x),调用pushdecl(x)将x放入global_binding_level,并回到当前binding_level。返回 值同pushdecl(x)。
tree implicitly_declare (functionid)
tree functionid;
为给定的标识符functionid产生一个隐含声明,即返回值为int型的函数。
tree lookup_tag (code, name, binding_level, thislevel_only)
Enum tree_code code;
Struct binding_level * binding_level; Tree name;
Int thislevel_only;
给定name,即标识符节点,返回此name的结构定义。从给的binding_level开始向上至global level查找,对每个level中的tags链节点,符合TREE_PURPOSE为name,TREE_CODE(TREE_VALUE)为code的节点。返回此节点的TREE_VALUE, 即结构的定义。否则未找到,返回NULL_TREE。 如果thislevel_only非0,则只查找给定的binding_level。Code是RECORD_TYPE,UNION_TYPE,或ENUMERAL_TYPE。
tree lookup_tag_reverse (type)
tree type;
给定type,从当前binding_level开始沿链查找,对每个level的tags链查找符合TREE_VALUE为type的节点,返回此节点的TREE_PURPOSE(即结构定义名)。否则未找到,返回NULL_TREE。
tree lookup_name (name)
tree name;
从当前binding_level的变量,函数,类型定义的名字空间中查找name,找到返回一个代表该名字定义的_DECL声明节点,否则为定义返回0。
tree lookup_name_current_level (name) tree name;
- 23 -
483435351.doc
如果在global_binding_level,返回name的IDENTIFIER_GLOBAL_VALUE。如果name的IDENTIFIER_LOCAL_VALUE为0,则返回0。否则,在当前binding_level的names链中查找符合DECL_NAME为name的节点,并返回此节点的指针。
void init_decl_processing ()
创建c 预定义的标量类型和一些代表标准常量的节点;初始化golbal_binding_level,为内建函数建立定义等。
void shadow_tag (declspecs)
tree declspecs;
在给定的declspecs链中每个节点的TREE_CODE(TREE_VALUE),如果此类型为RECORD_TYPE, UNION_TYPE, 或ENUMERAL_TYPE,调用lookup_tag_reverse (value), 从当前binding_level的tags链按declspecs的TREE_VALUE查找链中的name,如果此name存在,则调用lookup_tag (code, name,
current_binding_level, 1)在当前binding_level中结构名,若不存在,调用make_node (code)建立一个节点,并用pushtag (name, t)把此节点放入tags链中。
tree groktypename (typename)
tree typename;
对给定的类型说明和声明,调用grokdeclarator (…..),返回一个_TYPE类型节点指针。Typename是一个list节点指针。
tree groktypename_in_parm_context (typename) tree typename;
对给定的类型说明和声明,调用grokdeclarator (….),返回一个PARM_DECL节点指针。Typename是一个list节点指针。
tree star_decl (declarator, declspecs, initialized) tree declarator, declspecs;
int initialized;
调用grokdeclarator (…..)建立一个带类型的decl节点,如果initialized非0,按decl的TREE_CODE不同声明类型TYPE_DECL, FUNCTION_DECL, PARM_DECL等进行初始化,调用pushdecl(decl)将新建立的节点decl添加到当前binding_level中。返回指向新建节点decl的指针或已存在声明链的某节点的指针。
void finish_decl (decl, init, asmspec_tree) tree decl, init;
tree asmspec_tree;
完成一个声明的处理过程,并把安装初始值。如果以前数组类型的长度未知,现在它必须从初始值中得到确定,不然就出错了。
void push_parm_decl (parm)
tree parm;
给定一个经过语法的参数声明,调用grokdeclarator (…..)创建一个节点,并将此节点链入当前binding_level的parm_order链中,同时将此节点添加到当前binding_level 的声明链中。
tree grokdeclarator (declarator, declspecs, decl_context, initialized)
- 24 -
483435351.doc
tree declspecs;
tree declarator;
enum decl_context decl_context;
int initialized;
给定declarator,declspecs建立一个decl节点,同时建立type节点并链接到decl节点。返回decl节点的指针。
declspecs是list节点的链,它的TREE_VALUE是存放存储类别和类型说明的。 decl_context是说明这个声明所处的语义上下文,有以下几种:NORMAL, FUNCDEF, PARM,
TYPENAME, FIELD, BITFIELD.
Initialized是1如果此声明有初始化。
declarator 在 TYPENAME的情况下是一个绝对声明。在PARM的情况,它是一个参数类型已说明的原型。
tree grokparms (parms_info, funcdef_flag) tree parms_info;
int funcdef_flag;
对函数类型或函数定义的参数链进行处理,返回函数参数类型链的指针。
parms_info是指向函数参数list链的头指针,此链是list 节点链,它的TREE_PURPOSE是参数声明链,TREE_VALUE是在参数中声明的struct,union,enum的标签的链。
funcdef_flag非0,表示是函数定义,0仅仅表示是函数声明。
tree get_parm_infl (void_at_end)
int void_at_end;
经过语法分析,参数list链附有信息,返回此参数list链的头指针。
void_at_end 非0表示将void追加到type_list的末尾;0表示参数链以省略号结尾。
tree xref_tag (code, name)
enum tree_code code;
tree name;
给定code是struct,enum,union,它的名字是name。调用lookup_tag(…..)在当前binding_level的tags链中查找name,找到则返回指向此节点的指针,否则调用make_node (code)建立一个新节点,并调用pushtag(…)将新节点链入tags链中。返回指向新节点的指针。
tree start_struct (code, name)
enum tree_code code;
tree name;
调用lookup_tag (….)在当前binding_level的tags链中查找name,找到则返回其TREE_VALUE,否则调用make_node (code)建立一个新节点,并调用pushtag(…)将新节点链入tags链中。返回指向新节点的指针。
tree grokfield (filename, line, declarator, declspecs, width)
char * filename;
int line;
tree declarator, declspecs, width; 调用grokdeclarator (….)产生一个FIELD_DECL节点,并对结构成员的declspecs,declarator,width进行处理,返回此节点的指针。
- 25 -
483435351.doc
此函数是在结构声明的语法分析过程中完成的,FIELD_DECL节点将被串在一起,最后将通过build_struct建立RECORD_TYPE节点。
tree finish_struct (t, fieldlist)
register tree t, fieldlist;
将fieldlist链中所有节点的DECL_CONTEXT指向t,并将此链挂在t的TREE_VALUES上。返回指向t节点的指针。
t节点是指向类型节点的指针,t 的TREE_MAIN_VARIANT是const,volatile的类型节点链。Fieldlist是FIELD_DECL节点链指针。
如图: type node
t values main_variant
context context context
decl node
initial result initial result initial result fieldlist
tree start_enum (name)
tree name;
开始编译枚举类型定义。调用lookup_tag (….)在当前binding_level的tags链中查找name,找到则返回指向它的指针,否则调用make_node (ENUMERAL_TYPE)建立新节点,并调用pushtag(…)将新节点链入tags链中。返回指向新节点的指针。
tree finish_enum (enumtype, values) register tree enumtype, values;
给定enumtype是类型节点,values是list节点链。将values链中每个list节点的DECL_NAME(TREE_PURPOSE)直接赋给TREE_PURPOSE,并将enumtype的TYPE_VALUES指向values。返回指向enumtype的指针。
如图: type node
enumtype values
list node values purpose purpose purpose
decl node
name
- 26 -
483435351.doc
tree build_enumerator (name, value) tree name, value;
为当前枚举类型的值建立一个CONST_DECL节点,将此节点的DECL_INITIAL指向value,并将此节点链入声明链。返回指向此声明链的头指针。
如图:
decl node
decl initial
type node value
type
integer_type_node
int start_function (declspecs, declarator, nested)
tree declarator, declspecs;
int nested;
调用grokdeclarator (…..)建立一个FUNCDEF节点,同时调用build_function_type (….)为此函数定义节点建立类型节点,使声明节点的TREE_TYPE指向类型节点。将当前函数定义节点值为current_function_decl, 并调用pushlevel (0)进入一个新的binding_level。 然后调用build_decl (….)建立函数返回值类型的声明节点,即RESULT_DECL节点,并使current_function_decl节点的DECL_RESULT指向RESULT_DECL节点。返回1。
如图:
decl node
decl type values result
restype type node
type values list node
type value purpose value purpose value purpose
void store_parm_decls ()
在当前binding_level中,将参数声明及参数标签分别加入names链和tags链。
void finish_function (nested)
int nested;
- 27 -
483435351.doc
当函数结束时,调用poplevel (1,0,1)退出当前binding_level,将BLOCK_SUPERCONTEXT(DECL_INITIAL)和DECL_CONTEXT(DECL_RESULT)分别指向current_function_decl。其中block是在退出当前binding_level之前建立的,函数返回值声明节点是在start_function中建立的。
如图:
block node
supercontext current_function_decldecl node
initial result initial result initial result
context
- 28 -
483435351.doc
附录:主要数据结构的定义
struct resword wordlist[] =
{
{"int", TYPESPEC, RID_INT },
{"__typeof__", TYPEOF, NORID },
{"__signed__", TYPESPEC, RID_SIGNED },
{"__signed", TYPESPEC, RID_SIGNED },
{"switch", SWITCH, NORID },
{"__inline__", SCSPEC, RID_INLINE },
{"__interrupt", SCSPEC, RID_INTERRUPT },
{"__iterator__", SCSPEC, RID_ITERATOR },
{"__interrupt__", SCSPEC, RID_INTERRUPT },
{"if", IF, NORID },
{"__label__", LABEL, NORID },
{"__fract", TYPESPEC, RID_FRACT },
{"__typeof", TYPEOF, NORID },
{"__fract__", TYPESPEC, RID_FRACT },
{"default", DEFAULT, NORID },
{"sizeof", SIZEOF, NORID },
{"__const", TYPE_QUAL, RID_CONST },
{"break", BREAK, NORID },
{"__const__", TYPE_QUAL, RID_CONST },
{"dm", TYPE_QUAL, RID_DM },
{"__complex__", TYPESPEC, RID_COMPLEX },
{"__asm__", ASM_KEYWORD, NORID },
{"__inline", SCSPEC, RID_INLINE },
{"__extension__", EXTENSION, NORID },
{"while", WHILE, NORID },
{"__alignof__", ALIGNOF, NORID },
{"__creal", REALPART, NORID },
{"__attribute__", ATTRIBUTE, NORID },
{"void", TYPESPEC, RID_VOID },
{"__volatile__", TYPE_QUAL, RID_VOLATILE },
{"inline", SCSPEC, RID_INLINE },
{"__complex", TYPESPEC, RID_COMPLEX },
{"case", CASE, NORID },
{"else", ELSE, NORID },
{"const", TYPE_QUAL, RID_CONST },
{"__alignof", ALIGNOF, NORID },
{"extern", SCSPEC, RID_EXTERN },
{"struct", STRUCT, NORID },
{"static", SCSPEC, RID_STATIC },
- 29 -
483435351.doc
{"signed", TYPESPEC, RID_SIGNED },
{"__asm", ASM_KEYWORD, NORID },
{"__attribute", ATTRIBUTE, NORID },
{"__iterator", SCSPEC, RID_ITERATOR },
{"__volatile", TYPE_QUAL, RID_VOLATILE },
{"do", DO, NORID },
{"short", TYPESPEC, RID_SHORT },
{"unsigned", TYPESPEC, RID_UNSIGNED },
{"volatile", TYPE_QUAL, RID_VOLATILE },
{"__cimag", IMAGPART, NORID },
{"continue", CONTINUE, NORID },
{"return", RETURN, NORID },
{"float", TYPESPEC, RID_FLOAT },
{"asm", ASM_KEYWORD, NORID },
{"long", TYPESPEC, RID_LONG },
{"double", TYPESPEC, RID_DOUBLE },
{"union", UNION, NORID },
{"auto", SCSPEC, RID_AUTO },
{"typeof", TYPEOF, NORID },
{"typedef", SCSPEC, RID_TYPEDEF },
{"char", TYPESPEC, RID_CHAR },
{"pm", TYPE_QUAL, RID_PM },
{"enum", ENUM, NORID },
{"for", FOR, NORID },
{"goto", GOTO, NORID },
{"register", SCSPEC, RID_REGISTER },
}
union tree_node
{
struct tree_common common;
struct tree_int_cst int_cst;
struct tree_real_cst real_cst;
struct tree_string string;
struct tree_complex complex;
struct tree_identifier identifier;
struct tree_decl decl;
struct tree_type type;
struct tree_list list;
struct tree_vec vec;
struct tree_exp exp;
struct tree_block block;
};
struct tree_common
{
union tree_node *chain;
union tree_node *type;
#ifdef ONLY_INT_FIELDS
unsigned int code : 8;
- 30 -
483435351.doc #else
enum tree_code code : 8; #endif
#if defined(ADI) && defined(MEMSEG) #ifdef ONLY_INT_FIELDS
unsigned segment;
#else
memory_segment segment : 2; #endif
#endif
unsigned side_effects_flag : 1;
unsigned constant_flag : 1;
unsigned permanent_flag : 1;
unsigned addressable_flag : 1;
unsigned volatile_flag : 1;
unsigned readonly_flag : 1;
unsigned unsigned_flag : 1;
unsigned asm_written_flag: 1;
unsigned used_flag : 1;
unsigned raises_flag : 1;
unsigned static_flag : 1;
unsigned public_flag : 1;
unsigned private_flag : 1;
unsigned protected_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
unsigned lang_flag_3 : 1;
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1; };
struct tree_int_cst
{
char common[sizeof (struct tree_common)];
HOST_WIDE_INT int_cst_low;
HOST_WIDE_INT int_cst_high; };
struct tree_real_cst
{
char common[sizeof (struct tree_common)];
struct rtx_def *rtl;
REAL_VALUE_TYPE real_cst; };
struct tree_string
{
char common[sizeof (struct tree_common)];
struct rtx_def *rtl;
int length;
char *pointer;
};
struct tree_complex
{
char common[sizeof (struct tree_common)];
- 31 -
483435351.doc
struct rtx_def *rtl;
union tree_node *real;
union tree_node *imag; };
struct tree_identifier
{
char common[sizeof (struct tree_common)];
int length;
char *pointer;
};
struct tree_decl
{
char common[sizeof (struct tree_common)];
char *filename;
int linenum;
union tree_node *size;
unsigned int uid;
#ifdef ONLY_INT_FIELDS
int mode : 8;
#else
enum machine_mode mode : 8; #endif
#ifdef ADI
unsigned interrupt_flag :1; #endif
unsigned external_flag : 1;
unsigned nonlocal_flag : 1;
unsigned regdecl_flag : 1;
unsigned inline_flag : 1;
unsigned bit_field_flag : 1;
unsigned virtual_flag : 1;
unsigned ignored_flag : 1;
unsigned abstract_flag : 1;
unsigned in_system_header_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
unsigned lang_flag_3 : 1;
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned lang_flag_7 : 1;
union tree_node *name;
union tree_node *context;
union tree_node *arguments;
union tree_node *result;
union tree_node *initial;
union tree_node *abstract_origin;
char *print_name;
union tree_node *assembler_name;
struct rtx_def *rtl;
int frame_size;
union {
struct rtx_def *r;
int i;
} saved_insns;
union tree_node *vindex;
struct lang_decl *lang_specific;
- 32 -
483435351.doc };
struct tree_type
{
char common[sizeof (struct tree_common)];
union tree_node *values;
union tree_node *size;
unsigned uid;
#ifdef ONLY_INT_FIELDS
int mode : 8;
#else
enum machine_mode mode : 8; #endif
unsigned char precision;
unsigned char binarypoint;
unsigned no_force_blk_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
unsigned lang_flag_3 : 1;
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned int align;
union tree_node *pointer_to;
union tree_node *reference_to;
int parse_info;
int symtab_address;
union tree_node *name;
union tree_node *minval;
union tree_node *maxval;
union tree_node *next_variant;
union tree_node *main_variant;
union tree_node *binfo;
union tree_node *noncopied_parts;
union tree_node *context;
struct lang_type *lang_specific; };
struct tree_list
{
char common[sizeof (struct tree_common)];
union tree_node *purpose;
union tree_node *value;
};
struct tree_vec
{
char common[sizeof (struct tree_common)];
int length;
union tree_node *a[1];
};
struct tree_exp
{
char common[sizeof (struct tree_common)];
int complexity;
union tree_node *operands[1]; };
- 33 -
483435351.doc struct tree_block
{
char common[sizeof (struct tree_common)];
unsigned handler_block_flag : 1;
unsigned abstract_flag : 1;
union tree_node *vars;
union tree_node *type_tags;
union tree_node *subblocks;
union tree_node *supercontext;
union tree_node *abstract_origin;
struct rtx_def *end_note;
};
- 34 -