第四部分GCC語法與語義分析程序_第1頁
第四部分GCC語法與語義分析程序_第2頁
第四部分GCC語法與語義分析程序_第3頁
第四部分GCC語法與語義分析程序_第4頁
第四部分GCC語法與語義分析程序_第5頁
已閱讀5頁,還剩29頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第四部分:GCC語法與語義分析程序琚 小 明浙江大學信息與通信工程學系 2002年8月 一、語法與語義分析程序的主要功能語法分析是編譯過程的第二個階段。語法分析的任務是在詞法分析的基礎上將單詞序列分解成各類語法短語,如“程序”,“語句”,“表達式”等等。一般這種語法短語也稱為語法單位,可表示成語法樹。(一)語法分析程序的主要功能語法分析所依據的是語言的語法規則,即描述程序結構的規則。通過語法分析確定整個輸入串是否構成一個語法上正確的程序。在GCC中采用自底向上(bottom-up)最右規約的語法分析方法進行分析的,因為GCC的語法分析程序是由語法分析程序自動產生器(Yacc或bison)生成,

2、LR方法是YACC設定的語法分析方法。語義分析是審查源程序有無語義錯誤,為代碼生成階段收集類型信息。例如語義分析的一個工作是進行類型審查,審查每個算符是否具有語言規范允許的運算對象,當不符合語言規范時,編譯程序應報告錯誤。詞法分析和語法分析本質上都是對源程序的結構進行分析。但詞法分析的任務僅對源程序進行線性掃描即可完成,例如識別標識符,因為標識符的結構是字母打頭的字母和數字串,這只要順序掃描輸入流,遇到既不是字母又不是數字字符時,將前面所發現的所有字母可數字組合在一起而構成單詞標識符。但這種線性掃描不能用于識別的遞歸定義的語法成分,比如不能用此辦法去匹配表達式中的括號。(二)語法分析程序自動產

3、生器(YACC)簡介由于GCC中的語法分析程序是由YACC產生的,故在此對YACC的工作原來作一簡要的介紹。YACC的工作示意圖如圖1:(有關YACC的詳細資料見YACC的說明文檔)YACC源程序YACC單詞符號串(終結符)語法分析的輸出語法分析程序 yyparse輸入串詞法分析程序 yylex圖1 YACC工作示意圖。YACC源程序是用戶按要求對要處理語言的語法描述,經YACC產生語法分析程序yyparse。圖中的詞法分析程序是GCC提供的,它的輸出作為語法分析程序的輸入。在圖中YACC源程序是用戶用YACC提供的一種類似BNF的語言寫的要處理的語言的語法描述。YACC會自動的將這個源程序轉

4、換成用LR方法進行語法分析的語法分析程序yyparse,YACC的宿主語言是c,因此yyparse是一個c語言的程序,用戶在主程序中通過調用yyparse進行語法分析。語法分析必須建立在詞法分析的基礎之上,所以生成的語法分析程序還要有一個詞法分析程序與它配合工作。yyparse要求這個詞法分析程序的名字為yylex。用戶寫yylex時可以借助于LEX,也可以人工編寫。在YACC源程序中除了語法規則外,還要包括當這些語法規則被識別出來時,即用它們進行歸約時要完成的語義動作,語義動作是用c語言寫的程序段。語法分析的輸出可能是一顆語法樹,或生成的目標代碼,或者就是關于輸入串是否符合語法的信息。需要什

5、么樣的輸出都是由語義動作和程序部分的程序段來實現的。(三)語法分析程序的文件構成語法分析程序盡管是由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, m

6、achmode.h, machmode.def, obstack.h, real.h, rtl.h。等二、語法與語義分析程序的流程圖及其說明(一)語法分析程序的主要工作原理由YACC產生的語法分析程序是由放在棧中的有限狀態機構成的,它同時能夠讀取并記住下一個輸入的單詞(token),有時也叫這樣的單詞為向前看字符(lookahead token)。有限狀態機的狀態是用一個整數表示的,這與詞法、語法分析程序中的單詞是相似的。在初始時,機器處在0狀態,此時僅僅棧中包含了狀態0,而沒有向前看字符被讀入。有限自動機在語法分析程序中可執行相應的動作,以決定下一步的動作。語法分析可執行的動作(action

7、)共有4個,它們分別是:移進(shift)、歸約(reduce)、接受(accept)和錯誤(error)。語法分析程序的運行如下:1根據當前狀態,語法分析程序決定是否需要一個向前看字符以決定將要執行什么動作。如果需要一個單詞但還沒有讀入時,語法分析程序將調用yylex獲得下一個單詞。2用當前狀態和向前看字符(如果需要的話),語法分析程序決定它的下一個動作(action),并且執行這個動作。這樣將導致狀態被壓入或被彈出棧,以及向前看字符是被處理了還是放在一邊待用的不同變化。以下分別說明4種語法動作:移進動作(shift action)是語法分析程序采用的最平常的動作。根據當前棧的狀態和向前看字

8、符,語法分析程序查動作表(action表),以決定將采取什么動作。對于移進動作,不論何時采用移進動作,都有一個向前看字符,不然移進動作將無法執行對單詞的清除處理。而對應的狀態卻被壓入了狀態棧,從而造成錯誤。歸約(reduce action)是用語法規則的左邊代替其右邊的過程。當語法分析程序已經看到某語法規則的右邊,并且確定右邊是語法規則的一個實例時,歸約動作將被采用。通常語法分析程序在采用歸約動作時是不需要查看向前看字符的。歸約動作能防止棧無限增大,因為大多數情況下歸約動作是將狀態彈出棧,減少占用的棧空間。歸約動作取決于語法規則左邊的符號(非終結符)和右邊的符號(終結符和非終結符)數。歸約動作

9、首先根據語法規則右邊的符號數決定將被彈出棧的狀態數,然后將狀態從棧中彈出,使棧中的其它的狀態被顯露出來。事實上,被彈出的狀態就是在識別此規則右邊單詞時壓入棧的狀態,規則一旦被識別,這些狀態將不再有用。將這些狀態彈出之后,在狀態棧中處在棧頂的狀態是語法分析程序開始處理此規則之前的狀態。使用彈出之后的狀態和規則左邊的符號,將獲得一個新狀態(查狀態轉換表即goto表得到)。將此新狀態壓入棧,語法分析繼續。處理左邊符號和普通的單詞移進是有明顯的不同的。把對左邊符號的移進動作叫做狀態轉換動作(goto action),尤其不同的是,當執行移進時,向前看字符是被清除的,但在執行狀態轉換動作時,向前看字符是

10、不受影響的。(事實上,歸約動作在語法分析過程中好像是時間倒轉,將狀態從棧中彈出回到規則右邊剛開始看到時的狀態。當一條規則被識別時,語法分析程序好似在那時看到了規則的左邊。)如果規則的右邊是空的,沒有狀態被彈出棧,也就是棧中被顯露出來的狀態就是棧中的當前狀態。歸約在處理用戶提供的動作和值時也是重要的。當一條規則被識別并被歸約時,在棧被調整以前,由規則提供的代碼(code)將被執行。語法分析程序使用兩個棧:一個是擁有狀態的棧,即上文提到的棧;另一個是與之并行運行的值棧(value stack),這個棧擁有從詞法分析程序和動作返回的值。當移進時,外部變量yylavl被拷貝到值棧。從用戶碼(user

11、code)返回后,歸約被執行。當狀態轉換動作被執行后,外部變量yylval被拷貝到值棧。在YACC中,用偽變量$1,$2等來代表值棧的值,而$代表左邊非終結符的值。另外兩個語法動作相對來說比較簡單。接受動作(accept action)表明整個輸入都已經看到并且匹配語法規則,這個動作只有當向前看單詞是endmarker(文件結束符,在GCC中是以EOF為文件結束符的)才被采用,表明語法分析程序已經成功地完成語法分析工作。報錯動作(error action)說明根據規則在某處語法分析程序不能再繼續語法分析了。當輸入的單詞已經被看到,同時還有向前看字符,但后面不能跟隨可導致合法輸入的任何東西,此時

12、語法分析程序報告一個錯誤,并且試圖恢復狀況(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是y

13、ychar的語法分析的內部形式;yylval 是lookahead symbol 的語義值; yyval 是用于從執行程序中返回語義值;yystate 是從執行程序中返回的狀態。2yynewstate:將返回的狀態yystate壓入狀態棧,成為新狀態。*+yyssp=yystate;3取出產生式號yyn=yypactyystate;如果產生式號yyn為YYFLAG,則轉到4(yydefault)。如果yychar為YYEMPTY,則調用詞法分析函數得到一個單詞(token),即 yychar=YYLEX。索引表是用單詞(token)的內部形式索引的,故將單詞轉換為內部形式。 當yychar&l

14、t;=0 時:yychar1=0; yychar=YYEOF;當yychar>0時:yychar1=YYTRANSLATE(yychar);計算yychar1的產生式號:yyn+=yychar1;根據計算的產生式號到表中取出相應的產生式號: 初始化狀態和棧指針yynewstate讀取向前看單詞,并將其轉換成語法分析的內部形式;置新狀態。計算產生式號,并由此查yytable表得到產生式號yyn移進NYYyyn > 0Nyyn < 0或yyn=0Y成功NY歸約Y出錯yyn < 0Nyyn是終態?圖2 語法分析程序的流程圖。語法分析有兩個棧:一個是狀態棧;一個是值棧。這兩個棧

15、在進行語法分析時,它們的棧指針是同步移動的。對于出錯情況的處理有兩種:一種是處理后繼續執行語法分析;一種是中斷返回。圖中用虛線表示是編譯器多數情況下的處理結果。yyn=yytableyyn。yyn是這個token類型在此狀態下要做的動作:如果yyn是正數,則移進,而yyn是新狀態。如果yychar不是YYEOF,則放棄被移進的token,置yychar=YYEMPTY; *+yyvsp=yylval; yystate=yyn;轉到2(yynewstate);如果新狀態是終態,則返回成功而不必移進。4yydefault:執行當前狀態的默認產生式。 yyn=yydefactyystate; 5yy

16、reduce:如果yyn是負數,則規約,而-yyn是語法規則號,yyn=-yyn;yylen=yyr2yyn; 如果yylen>0, 則yyval=yyvsp1-yylen;由此實現執行的默認值。6如果yyn是0或者大多數的負數時,則出錯。7根據yyn的值確定產生式,并執行相應的動作。8規約后,yyvsp-=yylen;yyssp-=yylen;將單詞(token)的語義值賦給語義棧,*+yyvsp=yyval;yychar!=YYEOFyyn>0NY放棄被移進的單詞yychar=YYEMPTYY將單詞的值壓入值棧*+yyvsp=yylval將新狀態壓入狀態棧yystate=yyn

17、yynewstate圖3 移進動作的流程圖。移進動作較簡單,只需將單詞放棄,即將yychar置為YYEMPTY。然后將單詞的值和新狀態分別壓入值棧和狀態棧。返回到語法分析的開始處。9根據彈出后的狀態和被規約的產生式號決定轉換到什么狀態。yyn=yyr1yyn; yystate=yypgotoyyn-YYNTBASE+*yyssp;當yystate不在yytable表中時,yystate=yytableyystate;否則yystate=yydefgotoyyn-YYNTBASE;轉到2(yynewstate)。10yyerrhandle:出錯處理。yystate=yyn;轉到2(yynewst

18、ate)。或返回1。11yyacceptlab:接受狀態,釋放棧空間:free(yyss);free(yyvs); 并返回0。 對于語法分析時進行歸約所要執行的動作在此不作介紹,相關的說明見第四部分的函數功能介紹和語法樹結構等內容。歸約動作的主要內容是建立語法樹,并進行相應的語法和語義分析。yyn<0Y將產生式號取反yyn=-yynyyval=yyvsp1-yylenyylen>0查yyr2表得到歸約的長度yylen=yyr2yynN根據yyn的不同完成各種歸約動作(詳見源代碼)根據歸約的長度yylen,彈出狀態棧和值棧中相應數量的狀態和值。yyvsp-=yylen;yyssp-=

19、yylen;將返回的語義值置入值棧*+yyvsp=yyval移進歸約的結果yyn=yyr1yyn;根據當前的狀態和歸約的產生式號,決定轉換的狀態yystate=yypgotoyyn-YYNTBASE+*yysspyystate>=0&&yystate<=YYLAST&&yycheckyystate=*yyssp查yytable表得到新狀態yystate=yytableyystateYN查yydefgoto表得到新狀態yystate=yydefgotoyyn-YYNTBASEyynewstate圖4 歸約動作的流程圖。根據產生式號進行相應的歸約動作,用

20、產生式的左邊代替右邊,并將相應的狀態和值彈出棧。根據當前狀態和產生式號,從轉換表(yypgoto)中得到新狀態。三、語法與語義分析程序的數據結構及其說明GCC語法分析程序的一個主要任務是建立合理和有效的語法樹。為此,GCC定義了由12個數據結構組成的一個聯合,這個聯合能夠描述不同樹節點的全部內容。這些不同的樹節點是由TREE_CODE來說明的,而TREE_CODE是在文件tree.def中定義的。一個樹節點能描述一個數據類型、一個變量、一個表達式或一個語句。每個節點都有一個TREE_CODE用來說明所描述的內容是哪類的。例如常用的codes:INTEGER_TYPE描述的是整型類型;ARRAY

21、_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(IDE

22、NTIFIER_NODE, “identifier_node”, “x”, -1)其中的第一個參數是用來定義TREE_CODE的;第二個參數是輸出時用的;第三個參數可以是下列參數之一:“x” 用于表示特別的TREE_CODE,它不屬于任何一類。“t” 用于表示類型。“b” 用于表示詞法的塊。“c” 用于表示常量。“d” 用于表示聲明。“r” 用于表示訪問存儲器。“<” 用于表示比較表達式。“1” 用于表示一元算術表達式。“2” 用于表示二元算術表達式。“s” 用于表示固有副作用(side effects)的表達式。“e” 用于表示其他種類的表達式。對應 “r”、“e”、“<”、“1

23、”、“2”、“s”和“x”所表示的節點,第四個元素是表示要分配參數槽的數量,這決定了樹節點的大小。TREE_CODE共有11種類別(數字表示可再分類的個數),總計有125種不同的TREE_CODE用來表示不同的節點,下面所列的是關于對文件tree.def的一個統計,詳細的內容見源代碼。1. error_mark: 12. identifier: 23. tree_list: 14. tree_vec: 15. block:: 16. datatype: 20 (5 for pascal)7. constant: 58. declaration: 89. reference: 610. cons

24、tructor:111. expression: 79 (4 for pascal)(二) 樹節點的有關結構說明對于一個樹節點的內容,有些結構成員或字段(fields)是所有節點共享的,同樣有些有各自不同特殊用途的字段。在GCC中,為了一致樹節點的結構,定義了一個聯合(union)tree_node,所有的樹節點均可以用此聯合來表示。在這個聯合中,總共包含了12個結構,其中結構tree_common是一個通用的結構,可以認為是其他11個結構的共有部分。另外11結構是為各種不同的樹結構而定義的,但它們在結構定義中都為tree_common結構保留了空間,因此,tree_common結構在聯合中始

25、終是存在的,成為所有結構的共享部分。這個聯合的定義如下: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_d

26、ecl 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_COD

27、E(NODE) (enum tree_code)(NODE)->common.code)這些宏的定義都是在文件tree.h中。下面將對聯合中的每個結構的主要結構成員作一簡要的說明,關于聯合中的12個結構的定義詳見附錄。(1) 結構tree_common主要成員的說明:code:code即指TREE_CODE,說明的是什么類型的節點。Code是在文件tree.def中定義的。type:在所有是表達式的節點中,這是表達式的數據類型;在POINTER_TYPE節點中,這是指針所指向的類型;在ARRAY_TYPE節點中,這是元素的類型。chain:很多情況下節點是通過chain鏈接起來的,這些節

28、點被鏈接在一起有很多用途。如: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。在FAC

29、T_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:是標

30、識符的長度。pointer:是指向標識符的字符指針。(7) 結構tree_list主要成員的說明:這些list節點通過TREE_CHAIN鏈接成列表。purpose:指向參數鏈的指針。value:(8) 結構tree_vec主要成員的說明:length:是數組元素的個數。a1:是指向數組元素的結構指針。(9) 結構tree_exp主要成員的說明:complexity:operands1:是指向操作數的結構指針。在SAVE_EXPR節點中,用的是operands1, operands2。在RTL_EXPR節點中,用的是operands0, operands1。在CALL_EXPR節點中,用的是o

31、perands2。在CONSTRCTOR節點中,用的是operands1。在通常的表達式節點中,任意一個操作數operandsI都有可能被使用, 同時還有成員complexity。(10) 結構tree_block主要成員的說明:subblocks:包含了一個由BLOCK_CHAIN 鏈接起來的子塊的鏈。 supercontext: 指向父塊(parent block)。 對于一個描述函數最外層范圍的塊,它指向函數聲明節點(FUNCTION_DECL)。 vars: 指向聲明節點的鏈。 type_tags:指向有自己名字的類型的鏈。 chain: 指向下一個同一級(level)的塊,即指前面提

32、到的BLOCK_CHAIN。abstract_origin: 指向起始(original)樹節點,當前塊是起始數節點的一個實例(instance),或者它為NULL,表明當前塊不是其他任何節點的實例。當它為非空(non-NULL)時,它可指向另一個塊節點,或者指向一個函數聲明節點。abstract_flag: 如果當前塊描述的是一個塊的起始實例,則它是非0的。(11) 結構tree_type主要成員的說明:size:包含一顆樹,這顆樹是一個按位計算大小的表達式。 mode:包含這種類型的機器模式的值。 pointer_to:包含了一個類型,用一個指針指向這種類型。如果pointer_to為0,

33、則這種類型的節點還未建立。 next_variant:是用于鏈接由類型限定修飾詞"const" 和 "volatile"修飾的變量的類型。 main_variant:指向上述由TYPE_NEXT_VARIANT鏈接的鏈的頭指針。 noncopied_parts:是一個 list節點,用于說明這個類型的對象哪一部分是不能通過賦值拷貝的。 每個節點的TREE_PURPOSE 是這部分的偏移量。TREE_VALUE 是這部分以位計的大小。 name:包含為這種類型在程序中使用的名字的信息(為GDB符號表的輸出)。它是一個類型定義(typedef)的 TYPE_

34、DECL節點;或者是一個IDENTIFIER_NODE 節點在結構、聯合、枚舉已知是有標簽(tag)的;或者是0,當類型還沒有特殊的名字。 context:對類型有一個名字或者已經命名的成員(member)中的任意一種情況,它指向描述給定類型的范圍的節點,或者如果此類型具有文件范圍(file scope),則它是NULL_TREE。對大多數的類型來說,它將指向一個塊(block)節點或是函數聲明節點(FUNCTION_DECL),但是它也能夠指向函數類型節點(FUNCTION_TYPE),或者是結構類型節點(RECORD_TYPE)和 聯合類型節點(UNION_TYPE)。chain:是用于枚

35、舉類型(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,

36、 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,

37、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_DEC

38、L, 它是一個標志(flag),當label的定義已被看見時,此標志為非0。 PARM_DECLs 使用特殊的字段: initial:是參數實際上通過類型檢查的類型,此類型可能與它原來在函數中的類型有所不同。FUNCTION_DECLs 使用以下四個特殊的字段: arguments: 擁有一條參數聲明PARM_DECL節點的鏈。 result:擁有一個函數返回值聲明的 RESULT_DECL 節點。或者當函數無返回值時,它為0。(在c中,函數返回void即為無返回值) DECL_RESULT_TYPE :擁有函數實際返回值的類型。這通常與DECL_RESULT的類型是相同的,但這可能是一個寬整

39、型類型;同時為了內聯,甚至對函數的編譯已經結束,這仍然有效。這是兩者的不同之處。frame_size:是一個代碼數字(code number),非0時表示是內建函數(built-in function)。它的值是一個枚舉類型值,指明了是哪一個內建函數。filename: 擁有一個文件名字符串。linenum:擁有一個行數。abstract_flag:非0時,此聲明說明一個聲明的抽象實例(abstract instance)。 (三) 建立樹節點時的有關棧與數據結構的說明Gcc在處理語法樹節點時使用棧存放節點的內容,有關各個棧的詳細內容見源代碼,下面僅對各棧作一簡要的說明:1. permanen

40、t_obstack 存放永久的樹節點,如標識符,全局的有關東西,函數定義的參數等。2. maybepermanent_obstack 存放在函數內的初始的RTL和_TYPE節點,通常它們在函數結束時被釋放。3. temporay_obstack是用來讀全局變量的初始化值的。4. momentary_obstack 存放表達式的樹節點,它們在表達式結束時都被釋放。5. temp_decl_obstack 存放的樹節點,當聲明通過語法檢查時被釋放。6. momentary_level 暫時存放momentary_obstack,以便恢復。7. obstack_stack 時用來選擇推進還是彈出ob

41、stack。標識符節點、體外所有的東西和函數定義的參數分配在permanent_obstack中。RTL的初始化,所有在一個函數內的_TYPE節點分配在function_maybepermanent_obstack中,通常它們在函數結束時被釋放,但如果函數是內聯函數時將被儲存,嵌套的函數存放在各自分開的棧中。當前函數定義的內容分配在function_obstack中,在函數結束時全部被釋放,嵌套的函數存放在各自分開的棧中。表達式節點分配在temp_decl_obstack中,當聲明體通過語法時全部被釋放。Struct obstack *saveable_obstack 指向permanent_

42、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.對每個b

43、inding contour 分配一個binding _level structure,這個結構記錄了定義在那個contour中的names。Contour 包括:全局的contour;每個有參數的內部聲明出現的函數定義;復合語句,記錄它的聲明。struct binding_leveltree names;tree tags;tree shadowed;tree blocks;tree this_block;struct binding_level *level_chain; char parm_flag;char tag_transparent;char subblocks_tag_tran

44、sparent;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 將

45、被存儲。每個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指向。le

46、vel_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,

47、它是在編譯器開始編譯的時候建立的,并在整個運行過程中存在。它們分別定義如下: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。2 每個函數定義都有一個對應的contou

48、r,參數的內部聲明出現在那里。3 每個復合語句對應一個contour,用來記錄它的聲明。結構指針free_binding_level的用處:當一個binding_level節點被彈出時,并不實際釋放內存空間,而是將此節點鏈入到free_binding_level指向的鏈中。當需要一個binding_level節點時,首先查看free_binding_level鏈釋放為空。若有就重復使用原來已經存在的節點,否則新建一個節點。supercontextblockcurrent_function_decldecl nodeinitial resultinitial resultinitial resu

49、ltbinding_levelcurrent_binding_levelglobal_binding_levelnames tags blocksnames tags blocksnames tags blockslist nodevalue purposevalue purposevalue purposetype nodecontextcontextcontextblock nodeblock/ current_function_declinitialdecl nodeblock nodetype nodelist nodebinding level node圖5 頂層的語法樹結構bind

50、ing_level。GCC在進行語法分析時,是以current_binding_level為中心,所有的聲明、參數定義和塊等都是掛在binding_level上的。圖中的虛線箭頭表示省略了節點,對與其他圖相連的連線和箭頭采用不同的顏色加以區別。存儲當前level的狀態:每當當前level被彈出時,level中的狀態將被保存到一個塊(block)中。將當前level的names(decls)鏈入block的vars;將當前level的tags鏈入block的type_tags;將當前level的blocks鏈入block的subblocks。然后將當前level節點彈出,同時鏈入到free_bi

51、nding_level鏈中,并使下一個level節點成為當前level。parm decl nodeinitial resultinitial resultinitial resultblock nodesupercontextsupercontextcurrent_function_declnamesinitial result type argumentsdecl nodecontexttype valuestype nodetype nodevalue purposevalue purposelist nodevalue purposearg types圖6 當前函數聲明current_

52、function_decl的語法樹結構。initial 指向的block節點包含了函數體的語句;result指向的decl節點是函數的返回值;arguments指向的是參數聲明節點的鏈。TYPE_VALUES是list鏈,它的 TREE_PURPOSE是名字,TREE_VALUE是值 ( INTEGER_CST節點)。block nodeblockvars type_tags subblocks supercontextcurrent_function_declblockstagsnamesblock nodelist nodevalue purposevalue purposevalue p

53、urposedecl nodeinitial resultinitial resultinitial result圖7 塊節點block的語法樹結構。一個塊包含聲明、參數、子塊等,這些都是掛在同一個塊的節點上的。以個塊也可能是一個函數體,在圖5中,函數聲明initial指向的塊block就是一個函數體。四、語法與語義分析程序主要函數的功能:void push_obstacks (curren, saveable)struct abstack* current, *saveable;將當前各棧的指針放到obstack_stack 中,然后將current,saveable設置為當前棧。void

54、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 n

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論