




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
PAGE目錄TOC\o\h\z\u1前言 12PL/0語言描述 12.1PL/0語言的語法描述圖 22.2PL/0語言文法的EBNF表示 33PL/0語言的詞法與語法分析 43.1PL/0編譯器的詞法分析 43.2PL/0編譯器的語法分析 73.2.1PL/0編譯器語法分析過程的直觀思想 73.2.2PL/0編譯器語法分析程序分析 84PL/0語言詞法與語法分析器的設(shè)計 105PL/0語言詞法與語法分析器的編程實現(xiàn) 115.1編程環(huán)境簡介 115.1.1系統(tǒng)硬件設(shè)備 115.1.2系統(tǒng)支持軟件 115.2所采用的關(guān)鍵技術(shù)介紹 115.2.1窗口初始化 115.2.2切分窗口 125.2.3位圖的顯示 135.3具體功能的實現(xiàn) 145.3.1菜單的設(shè)計與實現(xiàn) 145.3.2窗體分割的設(shè)計與實現(xiàn) 155.3.3彈出式對話框的設(shè)計與實現(xiàn) 165.3.4工具條的設(shè)計 165.3.5起始屏的設(shè)計 185.4PL/0語言詞法與語法分析器的測試 195.4.1測試的重要性 195.4.2分析器的測試過程和運(yùn)行效果 196結(jié)束語 22參考文獻(xiàn) 22附錄 23PL/0語言的詞法語法分析器的設(shè)計與實現(xiàn)摘要:編譯器是現(xiàn)代計算機(jī)系統(tǒng)的基本組成部分之一,它把源語言程序翻譯成目標(biāo)語言程序。詞法分析和語法分析是編譯器的兩個重要功能。詞法分析的任務(wù)是對構(gòu)成源程序的字符流進(jìn)行掃描和分解,從而識別出單詞序列;語法分析的任務(wù)是將詞法分析得到的單詞序列分解成各類語法短語。本文在介紹PL/0語言編譯器的詞法分析和語法分析過程的基礎(chǔ)上,具體闡述了利用VC++作為編程工具完成PL/0語言詞法與語法分析器的設(shè)計與實現(xiàn)的過程。關(guān)鍵詞:編譯器;源語言;目標(biāo)語言;詞法分析;語法分析DesigningandImplementingtheLexicalAnalyzerandSyntaxAnalyzerofPL/0LanguageAbstract:Compilerisabasicpartofmoderncomputersystem,ittranslatesthesourcelanguageprogramintothetargetlanguageprgram.Lexicalanalysisandsyntaxanalysisaretwoimportantfunctionofthecompiler.Theformercompletesthetaskofscanninganddecomposingthestreamofcharactersmakingupthesourceprogramandidentifyingsequencesofwords.Thelattercompletesthetaskofclassingthestreamofwordsintosyntaxphrases.Inthispaper,onthebasisofintroducingthecoursesoflexicalanalysingandsyntaxanalyzingofofPL/0Languagecompiler,thedesignandimplementationprocessofusingVisualC++asaprogrammingtooltocompletethelexicalanalyzerandsyntaxanalyzerofPL/0Languageisconcretelydescribed.Keywords:Compiler;Sourcelanguage;Targetlanguage;Lexicalanalysis;SyntaxanalysisPAGE221前言編譯器是現(xiàn)代計算機(jī)系統(tǒng)的基本組成部分之一,而且多數(shù)計算機(jī)系統(tǒng)都含有不止一個高級語言的編譯器,對有些高級語言甚至配置了幾個不同性能的編譯器。從功能上看,一個編譯器就是一個語言翻譯程序。它把一種語言(稱作源語言)書寫的程序翻譯成另一種語言(稱作目標(biāo)語言)的等價的程序。比如匯編程序是一個翻譯程序,它把匯編語言程序翻譯成機(jī)器語言程序。如果源語言是像FORTRAN,PASCAL,或C那樣的高級語言,目標(biāo)語言是像匯編語言或機(jī)器語言那樣的低級語言,則這種翻譯程序稱作編譯程序或編譯器[3]。詞法分析是編譯過程的第一個階段,這個階段的作用是從左到右一個字符一個字符地讀入源程序,對構(gòu)成源程序的字符流進(jìn)行掃描和分解,從而識別一個個單詞。源程序中常見的單詞可以歸為幾大類:關(guān)鍵字、標(biāo)識符、字面量和特殊符號。語法分析就是編譯過程的第二個階段,它的作用是在詞法分析的基礎(chǔ)上將單詞序列分解成各類語法短語,如“程序”,“語句”,“表達(dá)式”等等。所以語法分析器的任務(wù)是在詞法分析的基礎(chǔ)上對源程序的語法短語進(jìn)行分析,找出其中的錯誤并且對用戶發(fā)出警告[5]。文獻(xiàn)[8]中指出,PL/0語言具有功能簡單、結(jié)構(gòu)清晰、可讀性強(qiáng)的特點,且具備了一般高級語言的必須部分。PL/0語言的編譯器能充分體現(xiàn)一個高級語言編譯器實現(xiàn)的基本技術(shù)和步驟。因此,本次畢業(yè)設(shè)計在對PL/0語言編譯器的詞法分析過程與語法分析過程進(jìn)行深入分析研究的基礎(chǔ)上,采用VC++編程來實現(xiàn)PL/0語言的詞法與語法分析器。以通過對PL/0語言編譯器中的詞法分析和語法分析程序的學(xué)習(xí)和詞法語法分析器的設(shè)計,達(dá)到深入理解編譯原理及熟練掌握編程語言的目的。2PL/0語言描述PL/0語言是PASCAL語言的一個子集[3],主要用于處理整型數(shù)值間的加減乘除和賦值等各種簡單運(yùn)算以及各種關(guān)系運(yùn)算,它的功能簡單、結(jié)構(gòu)清晰、可讀性強(qiáng)、而又具備了一般高級語言的必須部分,PL/0語言的編譯器能充分體現(xiàn)一個高級語言編譯器實現(xiàn)的基本技術(shù)和步驟,對建立實現(xiàn)編譯器的整體概念有很大幫助。以下為一個PL/0示例程序:Programabc;/*以下是程序體*/Varx,y,z;/*變量聲明*/Consta=10;/*常量聲明*/Procedureab(integerm,n:Var;t:Const);/*過程聲明*/Begint:=n+m;Ifm>nthen/*條件語句*/n:=telsem:=t;Whilen<mdo/*循環(huán)語句*/Beginn:=n+1EndEnd;Beginx:=1;y:=2;z:=3;Callab(x,y,z);z:=4+z+(1+2+6+x)*3*y*5+7;If~3<=x&y<>4thenz:=0;/*條件表達(dá)式*/y:=219;z:=37;x:=a*z/*賦值語句*/End./*程序結(jié)束符*/根據(jù)示例程序可以看到PL/0語言鮮明的特點,為了更清楚的了解它的語法特點,下面分別用語法描述圖和EBNF來表示。2.1PL/0語言的語法描述圖PL/0語言的語法規(guī)則可用語法描述圖來描述,用語法圖描述語法規(guī)則具有直觀、易讀的優(yōu)點。在語法圖中,用橢圓和圓圈中的英文字表示終結(jié)符,用長方形內(nèi)的中文字表示非終結(jié)符。所謂終結(jié)符,是構(gòu)成語言文法的單詞,是語法成分的最小單位。而每個非終結(jié)符是一個語法成分,在書寫語言程序時并不出現(xiàn),它是由終結(jié)符和非終結(jié)符、或終結(jié)符串定義的[11]。例如,圖2-1中,程序是由非終結(jié)符‘分程序’和終結(jié)符“.”這個串定義的。由于對某些非終結(jié)符可以遞歸定義,這就使得無窮的句子集可用有窮的文法描述。而通常稱第一個非終結(jié)符如‘程序’為文法的開始符號。如圖2-2所示為分程序的語法描述圖。分程序分程序.程序圖2-1程序語法描述圖圖2-2分程序語法描述圖2.2PL/0語言文法的EBNF表示PL/0語言的語法描述也可用擴(kuò)充的巴科斯-瑙爾范式[3]表達(dá)如下:(1)EBNF表示的符號說明<>:用左右尖括號括起來的中文字表示語法構(gòu)造成分,或稱語法單位,為非終結(jié)符?!?:=’:該符號的左部由右部定義,可讀作‘定義為’?!畖’:表示‘或’,為左部可由多個右部定義。‘{}’:表示花括號內(nèi)的語法成分可以重復(fù)。在不加上下界時可重復(fù)0到任意次數(shù),在有上下界時為可重復(fù)次數(shù)的限制?!甗]’:表示方括號內(nèi)的成分為任選項?!ǎ?表示圓括號內(nèi)的成分優(yōu)先。(2)PL/0語言文法的EBNF表示<程序>::=<分程序>.<分程序>::=[<常量說明部分>][<變量說明部分>][<過程說明語句>]<語句><常量說明部分>::=CONST<常量定義>{,<常量定義>};<常量定義>::=<標(biāo)識符>=<無符號整數(shù)><無符號整數(shù)>::=<數(shù)字>{<數(shù)字>}<變量說明部分>::=VAR<標(biāo)識符>{,<標(biāo)識符>};<標(biāo)識符>::=<字母>{<字母>|<數(shù)字>}<過程說明部分>::=<過程首部><分程序>{;<過程說明部分>};<過程首部>::=PROCEDURE<標(biāo)識符>;<語句>::=<賦值語句>|<條件語句>|<當(dāng)型循環(huán)語句>|<過程調(diào)用語句>|<讀語句>|<寫語句>|<復(fù)合語句>|<空><賦值語句>::=<標(biāo)識符>:=<表達(dá)式><復(fù)合語句>::=BEGIN<語句>{;<語句>}END<條件>::=<表達(dá)式><關(guān)系運(yùn)算符><表達(dá)式>|ODD<表達(dá)式><表達(dá)式>::=[+|-]<項>{<加法運(yùn)算符><項>}<項>::=<因子>{<乘法運(yùn)算符><因子>}<因子>::=<標(biāo)識符>|<無符號整數(shù)>|‘(’<表達(dá)式>‘)’<加法運(yùn)算符>::=+|-<乘法運(yùn)算符>::=*|/<關(guān)系運(yùn)算符>::==|#|<|<=|>|>=<條件語句>::=IF<條件>THEN<語句><過程調(diào)用語句>::=CALL<標(biāo)識符><當(dāng)型循環(huán)語句>::=WHILE<條件>DO<語句><讀語句>::=READ‘(’<標(biāo)識符>{,<標(biāo)識符>}‘)’<寫語句>::=WRITE‘(’<表達(dá)式>{,<表達(dá)式>}‘)’<字母>::=a|b|…|X|Y|Z<數(shù)字>::=0|1|2|…|8|93PL/0語言的詞法與語法分析3.1PL/0編譯器的詞法分析文獻(xiàn)[12]中指出,PL/0編譯器的詞法分析程序可以看成是一個獨(dú)立的過程,其功能是為語法分析提供單詞,是語法分析的基礎(chǔ),它把輸入的字符串形式的源程序分割成一個個單詞符號。為此PL/0編譯器設(shè)置了三個全程量的公用單元如下:(1)SYM:存放每個單詞的類別,用內(nèi)部編碼形式表示。(2)ID:存放用戶所定義的標(biāo)識符的值。即標(biāo)識符字符串的機(jī)內(nèi)表示。(3)NUM:存放用戶自定義的數(shù)。PL/0語言單詞的種類有五種。(1)基本字:也可稱為保留字,如BEGIN、END、IF、THEN等。(2)運(yùn)算符:如+、-、*、/、:=、#、>=、<=等。(3)標(biāo)識符:如用戶定義的變量名、常數(shù)名、過程名。(4)常數(shù):如10、25、100等整數(shù)。(5)界符:如‘、’、‘.’、‘;’、‘(’、‘)’等。如果把基本字、運(yùn)算符、界符稱為語言固有的單詞,而對標(biāo)識符、常數(shù)稱為用戶定義的單詞。那么經(jīng)詞法分析程序分解出的單詞,對語言固有的單詞只給出類別存放在SYM中,而對用戶定義的單詞(標(biāo)識符或常數(shù))既給出類別又給出值,其類別放在SYM中,值放在ID或NUM中,全部單詞種類由編譯器定義的SYMBOL給出,也可稱為語法的詞匯表。如下面提到的IFSYM,THENSYM,IDENT,NUMBER均屬SYMBOL中的元素。因此,PL/0編譯器的詞法分析過程將完成下列任務(wù):(1)濾空格:空格在詞法分析時是一種不可缺少的界符,而在語法分析時則是無用的所以必須濾掉。(2)識別保留字:設(shè)有一張保留表。對每個字母打頭的字母、數(shù)字字符串要查此表。若查著則為保留字,將對應(yīng)的類別放在SYM中。如IF對應(yīng)值IFSYM,THEN對應(yīng)值THENSYM。若查不到,則認(rèn)為是用戶定義的標(biāo)識符。(3)識別標(biāo)識符:對用戶定義的標(biāo)識符將IDENT放在SYM中,標(biāo)識符本身的值放在ID中。(4)拼數(shù):當(dāng)所取單詞是數(shù)字時,將數(shù)的類別NUMBER放在SYM中,數(shù)值本身的值存放在NUM中。(5)拼復(fù)合詞:對兩個字符組成的算符如:>=、:=、<=等單詞,識別后將類別送SYM中。(6)輸出源程序:為邊讀入字符邊輸出(可輸出在文件中)。由于一個單詞往往是由一個或幾個字符組成的,所以在詞法分析過程CIFAFENXI中又定義了一個取字符過程GETCH,由詞法分析需要取字符時調(diào)用。根據(jù)以上分析,可得詞法分析過程CIFAFENXI的流程圖如圖3-1所示。圖3-1詞法分析過程CIFAFENXI取字符過程GETCH的流程圖如圖3-2所示。圖3-2取字符過程GETCH圖中GETCH所用單元說明如下:CH:存放當(dāng)前讀取的字符,初值為空。LINE:為一維數(shù)組,其數(shù)組元素為字符,界對為1:80。用于讀入一行字符的緩沖區(qū)。LL和CC為計數(shù)器,初值為0。CIFAFENXI流程圖的工作單元說明:A:一維數(shù)組,數(shù)組元素為字符,界對[1:10]。ID:同A。WORD:保留字表,一維數(shù)組,數(shù)組元素是以字符為元素的一維數(shù)組。界對為[1:13]。查表采用二分法。根據(jù)上述描述定義一個詞法分析子程序,命名為getsym,其功能是從源程序中讀出一個單詞符號(token),把它的信息放入全局變量sym、id和num中,語法分析器需要單詞時,直接從這三個變量中獲得。(注意!語法分析器每次用完這三個變量的值就立即調(diào)用getsym子程序獲取新的單詞供下一次使用。而不是在需要新單詞時才調(diào)用getsym過程。)getsym過程通過反復(fù)調(diào)用getch子過程從源程序過獲取字符,并把它們拼成單詞。getch過程中使用了行緩沖區(qū)技術(shù)以提高程序運(yùn)行效率。調(diào)用getsym時,它通過getch過程從源程序中獲得一個字符。如果這個字符是字母,則繼續(xù)獲取字符或數(shù)字,最終可以拼成一個單詞,查保留字表,如果查到為保留字,則把sym變量賦成相應(yīng)的保留字類型值;如果沒有查到,則這個單詞應(yīng)是一個用戶自定義的標(biāo)識符(可能是變量名、常量名或是過程的名字),把sym置為ident,把這個單詞存入id變量。查保留字表時使用了二分法查找以提高效率。如果getch獲得的字符是數(shù)字,則繼續(xù)用getch獲取數(shù)字,并把它們拼成一個整數(shù),然后把sym置為number,并把拼成的數(shù)值放入num變量。如果識別出其它合法的符號(比如:賦值號、大于號、小于等于號等),則把sym置成相應(yīng)的類型。如果遇到不合法的字符,把sym置成null。3.2PL/0編譯器的語法分析文獻(xiàn)[12]中指出,語法分析的任務(wù)是識別由詞法分析給出的單詞符號序列在結(jié)構(gòu)上是否符合給定的文法規(guī)則。PL/0語言的文法規(guī)則已在前面給出,本節(jié)將以語法圖描述的語法形式為依據(jù),給出語法分析的直觀思想。3.2.1PL/0編譯器語法分析過程的直觀思想PL/0編譯器的語法分析采用了自頂向下的遞歸子程序法[3]。粗略地說,就是對應(yīng)每個非終結(jié)符語法單元,編一個獨(dú)立的處理過程(或子程序)。語法分析從讀入第一個單詞開始由非終結(jié)符‘程序’即開始符出發(fā),沿語法描述圖箭頭所指出的方向進(jìn)行分析,當(dāng)遇到非終結(jié)符時,則調(diào)用相應(yīng)的處理過程,從語法描述圖看,也就是進(jìn)入了一個語法單元,再沿當(dāng)前所進(jìn)入的語法描述圖的箭頭方向進(jìn)行分析,當(dāng)遇到描述圖中是終結(jié)符時,則判斷當(dāng)前讀入的單詞是否與圖中的終結(jié)符相匹配,若匹配則說明符合語法規(guī)則;再讀取下一個單詞繼續(xù)分析。遇到分支點時將當(dāng)前的單詞與分支點上的多個終結(jié)符逐個相比較,若都不匹配時可能是進(jìn)入下一非終結(jié)符語法單位或是出錯。文獻(xiàn)[8]中指出,如果一個PL/0語言的單詞序列在整個語法分析中,都能逐個得到匹配,直到結(jié)束符‘.’,這時說明所輸入的程序是正確的。圖3-3語法調(diào)用關(guān)系程序分程序圖3-3語法調(diào)用關(guān)系程序分程序語句條件表達(dá)式項因子每個產(chǎn)生式的右部都由終結(jié)符號開始。如果兩個產(chǎn)生式有相同的左部,那么它們的右部由不同的終結(jié)符開始。對于這樣的文法顯然在推導(dǎo)過程中完全可以根據(jù)當(dāng)前的輸入符號決定選擇哪個產(chǎn)生式往下推導(dǎo),因此分析過程是唯一確定的。此外,從PL/0的語法描述圖中可以清楚的看到,當(dāng)對PL/0語言進(jìn)行語法分析時,各個非終結(jié)符語法單元所對應(yīng)的分析過程之間必須存在相互調(diào)用的關(guān)系。這種調(diào)用關(guān)系可用圖3-3表示。也可稱為PL/0語法的依賴圖,在圖中箭頭所指向的程序單元表示存在調(diào)用關(guān)系,從圖中不難看出這些子程序在語法分析時被直接調(diào)用或間接遞歸調(diào)用。3.2.2PL/0編譯器語法分析程序分析語法分析主要完成兩大功能:說明部分的處理和程序體的處理[3]。程序體就是語法單元中的分程序部分,通常把它稱為過程體。語法分析由過程YUFAFENXI完成,其流程如圖3-4所示。YUFAFENXIYUFAFENXI為DX,TX置初值,暫時保留CODE的下標(biāo)指針CX值在TABLE表中SYM=CONSTSYM?常量說明處理SYM=VARSYM?變量說明處理SYM=PROCSYM?在TABLE表中登記過程名遞歸調(diào)用YUFAFENXICIFAFENXI出錯處理返回是否為語句開始符在TABLE表中返填過程體入口圖3-4YUFAFENXI過程的流程圖過程YUFAFENXI內(nèi)對程序說明部分和程序體部分的處理如下:(1)說明部分由于PL/0語言允許過程調(diào)用語句,且允許過程嵌套定義,因此每個過程應(yīng)有過程首部以定義局部于它自己過程的常量、變量、和過程標(biāo)識符,也稱局部量[3]。每個過程所定義的局部量只能供它自己和它自己定義的內(nèi)過程引用。對于同一層并列過程的調(diào)用關(guān)系是先定義者可以被后定義者引用,反之則不行。說明部分的處理任務(wù)就是對每個過程(包括主程序,也可看成是一個主過程)的說明對象造名字表,填寫所在層次(主程序為第0層,主程序定義的過程為第1層,隨著嵌套的深度增加而將層次數(shù)加大。PL/0最多允許3層)、標(biāo)識符的屬性和分配的相對位置等。標(biāo)識符的屬性不同時,所需要填的信息也不同。不同的信息是調(diào)用不同的過程完成的。所造表放在全程量一維數(shù)組TABLE表中。TX為索引表的指針,表中的每個元素為紀(jì)錄型數(shù)據(jù)。LEV給出層次,DX給出每層局部量當(dāng)前分配到的相對位置,可稱地址指示器,每說明完一個變量后DX指示器加1。例如:一個過程的說明部分為:CONSTA=35,B=49;VARC,D,E;PRTCEDUREP;VARG對它的常量,變量和過程名說明分析后,在TABLE表中的信息如表3-1所示。表3-1TABLE表的信息NAME:ANAME:BNAME:CNAME:DNAME:ENAME:PKIND:CONSTANTKIND:CONSTANTKIND:VARIABLEKIND:VARIABLEKIND:VARIABLEKIND:PROCEDURVAL:35VAL:49LEVEL:LEVLEVEL:LEVLEVEL:LEVLEVEL:LEVADR:DXADR:DX+1ADR:DX+2ADR:NAME:G…KIND:VARIABLE…LEVEL:LEV+1…ADR:DX…在說明處理后TABLE表中的信息對于過程名的ADR域,是在過程體的目標(biāo)代碼生成后返填過程體的入口地址。例中在處理P過程的說明時對LEV就增加1。在P過程中的變量名的層次為LEV+1后的值。對過程還有一項數(shù)據(jù)SIZE,是記錄該過程所需的數(shù)據(jù)空間。TABLE表的表頭索引TX和層次單元LEV都以YUFAFENXI的參數(shù)形式出現(xiàn)。在主程序調(diào)用YUFAFENXI時實參值都為0.每個過程中的變量的相對起始位置在YUFAFENXI內(nèi)置初值DX:=3。(2)過程體程序的主體是由語句[12]構(gòu)成的。處理完過程的說明后就處理由語句組成的過程體,從語法上要對語句進(jìn)行逐句分析。當(dāng)語法正確時就打印程序正確。當(dāng)遇到標(biāo)識符的引用時就查TABLE表,看是否有過正確的定義,若已有,則從表中取相應(yīng)的有關(guān)信息,供代碼的生成用,若無定義則出錯。4PL/0語言詞法與語法分析器的設(shè)計文獻(xiàn)[9]中指出,為了方便程序的編寫,一般軟件的開發(fā)都將開發(fā)工作分成若干個功能模塊。本分析器的功能設(shè)計模塊規(guī)劃如圖4-1所示。本分析器將軟件中出現(xiàn)次數(shù)比較頻繁的一些常用代碼設(shè)計為獨(dú)立的單元,例如設(shè)置顏色的代碼和詞法分析以及語法分析的代碼等,這樣設(shè)計新的模塊時如果有重復(fù)出現(xiàn)的部分,只需要將編寫好的模塊用include語句[9]來組裝就可以了。本分析器雖然分為好幾個模塊來設(shè)計,但是它們的功能是獨(dú)立的,可以分開來設(shè)計和編寫,這樣有利于提高模塊的內(nèi)聚性[3],降低了程序的耦合性[3]。詞法語法分析器詞法語法分析器窗口的初始化菜單的設(shè)計工具條的設(shè)計彈出式對話框設(shè)計添加語法分析添加詞法分析添加樣例演示添加設(shè)置顏色圖標(biāo)按鈕化24位位圖設(shè)計關(guān)于此分析器顏色設(shè)置框窗口切割設(shè)計起始屏的設(shè)計詞法語法分析圖4-1分析器的設(shè)計模塊圖5PL/0語言詞法與語法分析器的編程實現(xiàn)5.1編程環(huán)境簡介根據(jù)開發(fā)本分析器所使用的開發(fā)工具的特點,出于安全性考慮,開發(fā)本詞法與語法分析器軟件時,對軟件環(huán)境和硬件環(huán)境有特定的要求。5.1.1系統(tǒng)硬件設(shè)備本軟件開發(fā)時需要具有PentiumIII處理器且滿足以下要求的計算機(jī):最低256MB內(nèi)存、最小8G硬盤、鼠標(biāo)、鍵盤。5.1.2系統(tǒng)支持軟件本軟件在WindowsXP操作系統(tǒng)上開發(fā)。所用的開發(fā)工具包是MicrosoftVisualStudio2005或VC++6.0。VisualC++是匯集了MS公司技術(shù)精華的主流產(chǎn)品,它將程序設(shè)計方法與可視的軟件開發(fā)環(huán)境完美地結(jié)合在一起,其開發(fā)環(huán)境和適應(yīng)Internet應(yīng)用程序的特點很適合于開發(fā)Windows應(yīng)用程序,因此受到廣大軟件設(shè)計人員的青睞。使用VisualC++6.0可以開發(fā)強(qiáng)大的32位應(yīng)用程序,能為用戶全方位地服務(wù)[1]。5.2所采用的關(guān)鍵技術(shù)介紹由于采用的是VisualC++6.0進(jìn)行本詞法與語法分析器的編寫,因此根據(jù)實際需要,開發(fā)該詞法與語法分析器時用到的關(guān)鍵技術(shù)主要有窗口初始化、切分窗口、以及位圖顯示技術(shù)。5.2.1窗口初始化在開發(fā)VC++應(yīng)用程序時,MicroSoft公司提供了一種被稱為AppWizard的動態(tài)模板生成程序[1]。創(chuàng)建的步驟如下:(1)建立ApplicationMicroSoftVisualC++編譯器的菜單條中,選擇File菜單,然后從列出的菜單項中選擇“New”按鈕,創(chuàng)建一個MFCAppWizard(exe)的應(yīng)用程序,為本分析器的工程命名為“SS”,如圖5-1所示。(2)生成代碼及資源視圖單擊“OK”,選擇“Singledocument”以及依次點擊“Next>”直到所有設(shè)置初始化以后單擊“Finish”按鈕,將會看到一個對話框是AppWizard為這個項目創(chuàng)建的東西的簡單描述,它是對各項選擇的一個摘要。接著單擊“OK”就可以生成如圖5-2所示的關(guān)于這個窗口的代碼和資源視圖。圖5-1工程的創(chuàng)建視圖圖5-2分析器的設(shè)計資源視圖5.2.2切分窗口因為所開發(fā)的詞法語法分析器既有輸入程序又要求將分析結(jié)果輸出在窗口中,因此為了區(qū)分輸入與輸出,必須實現(xiàn)兩個窗口的并列顯示,于是用到了切分窗口技術(shù),在拆分窗口中,窗口可以被拆分成多個面板,多個面板可以相對于一個視圖,也可以逐一對應(yīng)視圖。在窗口拆分中可分為靜態(tài)窗口拆分和動態(tài)窗口拆分[1],可以用CSplitterWnd類來實現(xiàn)這兩種類型的窗口拆分,既可以將窗口縱向拆分,也可以橫向拆分。動態(tài)拆分窗口可以被拆分成多個面板,這樣,當(dāng)用戶想同時閱讀同一文檔中的兩個不同位置的內(nèi)容時,不必打開兩個窗口,而直接將該文檔分成若干個窗口即可。靜態(tài)拆分窗口可以被拆分成多個面板的窗口,而每個面板起到不同的作用,因此根據(jù)實際需要這里采用了靜態(tài)拆分窗口技術(shù)。在主界面中嵌入CSplitterWnd成員變量時,使用CreatStatic()函數(shù)進(jìn)行創(chuàng)建,其原型為:BOOLCreatStatic(CWnd*pParentWnd,intnRows,intnCols,DWORDdwStyle=WS_CHILD|WS_VISIBLE,UINTNid=AFX_IDW_PANE_FIRST);CWnd*pParentWnd參數(shù)表示父窗口的指針,intnRows參數(shù)表示要創(chuàng)建的行數(shù),intnCols參數(shù)表示要創(chuàng)建的列數(shù),DWORDdwStyle參數(shù)表示要顯示的窗口風(fēng)格,UINTNid=AFX_IDW_PANE_FIRST參數(shù)表示子窗口ID。5.2.3位圖的顯示由于該分析器的起始屏設(shè)計需要用到位圖的顯示技術(shù)[2],所以在制作位圖顯示之前,首先應(yīng)該了解一下位圖的顯示過程:位圖數(shù)據(jù)在顯示之前應(yīng)先轉(zhuǎn)移到內(nèi)存中,在WindowsAPI中,所分配的內(nèi)存句柄被稱為HBITMAP。它用來獲得位圖在內(nèi)存中的地址以及長度的數(shù)據(jù),當(dāng)駐留在內(nèi)存中的數(shù)據(jù)轉(zhuǎn)移到視頻內(nèi)存中時,位圖將被顯示到顯示器上。位圖顯示的實現(xiàn)的步驟如下:(1)創(chuàng)建Cbitmap對象。Cbitmap對象在首次實例化時是空的,該類所包裝的位圖最終必須被創(chuàng)建以使對象有效,格式為:CbitmapBitmap;//創(chuàng)建位圖對象(2)加載和設(shè)置位圖內(nèi)容,在使用位圖之前,可能希望使用有意義的數(shù)據(jù)設(shè)置位圖的內(nèi)容,當(dāng)位圖首次被創(chuàng)建時,內(nèi)存中的數(shù)據(jù)是不可知的,所以必須在內(nèi)存中添加自己的內(nèi)容,這里將使用LoadBitmap()函數(shù),格式為:Bitmap.LoadBitmap(IDR_BITMAP1);(3)將Cbitmaps繪制到屏幕上,一旦具備了一個有效位圖的Cbitmap對象,就可以將它繪制到屏幕上去,在通常情況下,用BitBlt()函數(shù),其語法如下:BOOLBitBlt(intx,inty,intnWidth,intnHeight,CDC*pSrcDC,intxSrc,intySrc,DWORDdwRop);其中參數(shù)X為位圖在視窗內(nèi)顯示的橫坐標(biāo),Y為位圖在視窗內(nèi)像是的縱坐標(biāo)nWidth和intnHeight分別為位圖的寬度和高度,pSrcDC是顯示設(shè)備環(huán)境句柄,xSrc和ySrc是被顯示的位圖的起始位置,dwRop為位圖顯示形式。5.3具體功能的實現(xiàn)5.3.1菜單的設(shè)計與實現(xiàn)根據(jù)上述PL/0語言的詞法與語法的描述以及詞法分析和語法分析的設(shè)計思想和模塊分析,首先對其菜單進(jìn)行編輯和處理。如圖5-3所示:利用VC++提供的組件可以輕松的對窗口的Menu組件及下拉菜單樣式和內(nèi)容進(jìn)行編輯。其中XP用戶常用組合鍵都自動保存在資源視圖中Accelerator表中,如圖5-4所示。根據(jù)需要本分析器在菜單中加入編譯選項然后在該彈出式選項下拉菜單中添加詞法分析、語法分析、設(shè)置顏色、樣例演示四個選項,分別命名為ID_CIFA、ID_YUFA、ID_SET、ID_TEST。圖5-3菜單設(shè)計視圖圖5-4組合鍵Accelerator表5.3.2窗體分割的設(shè)計與實現(xiàn)主窗口設(shè)置模塊是本系統(tǒng)的界面核心部分,從某種意義上來說,真正實現(xiàn)了詞法分析和語法分析的操作性。窗口設(shè)置如圖5-5所示:5-5窗體布局設(shè)計視圖本分析器采用XP菜單式樣進(jìn)行窗口設(shè)置,采用窗口分割技術(shù)將窗口進(jìn)行了分割處理,實現(xiàn)窗口分割的源代碼如下:BOOLCMainFrame::OnCreateClient(LPCREATESTRUCTlpcs,CCreateContext*pContext){ if(!m_wndSplitter.CreateStatic(this,1,2))//創(chuàng)建行列的切分窗口 { TRACE0("FailedtoCreateStaticSplitter\n"); returnFALSE; } CRectrc; //獲得客戶區(qū)大小 GetClientRect(rc); intx=rc.Width()/2; inty=rc.Height()/2; if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CSourceEditView),CSize(x,y),pContext)) { TRACE0("Failedtocreatesecondpane\n"); returnFALSE; }//創(chuàng)建第個視圖 if(!m_wndSplitter.CreateView(0,1, pContext->m_pNewViewClass,CSize(x,y),pContext)) { TRACE0("Failedtocreatefirstpane\n"); returnFALSE; }//創(chuàng)建第個視圖 m_pEditSrc=&((CEditView*)m_wndSplitter.GetPane(0,0))->GetEditCtrl();//獲得CEditView視圖中的編輯框控件的指針 m_pEditOut=&((CEditView*)m_wndSplitter.GetPane(0,1))->GetEditCtrl();5.3.3彈出式對話框的設(shè)計與實現(xiàn)(1)字體和背景顏色自定義的實現(xiàn)為了讓用戶在使用該系統(tǒng)的時候能夠方便的對所輸入的程序體進(jìn)行區(qū)別標(biāo)識,本分析器設(shè)置了顏色自定義選項。為方便用戶使用,本人將其制作成了彈出式對話框形式的取色器,如圖5-6所示:圖5-6顏色編輯對話框設(shè)計視圖(2)關(guān)于此編譯器對話框的設(shè)計在Dialog資源夾下IDD_ABOUTBOX就是VC中默認(rèn)的關(guān)于此軟件的對話框模板,這個對話框的作用就是顯示一些關(guān)于該軟件的版權(quán)信息,如圖5-7所示:圖5-7關(guān)于此編譯器對話框設(shè)計視圖5.3.4工具條的設(shè)計工具條主要用于為該分析器中菜單中的一些重要選項提供快捷方式。本軟件中工具條的設(shè)計采用VC提供的Toolbar資源模板實現(xiàn),工具條設(shè)計視圖如圖5-8所示:5-8工具條設(shè)計視圖將工具條嵌入到主界面中的關(guān)鍵代碼如下:intCMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct){ if(CFrameWnd::OnCreate(lpCreateStruct)==-1) return-1; if(!m_wndToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP |CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)|| !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failedtocreatetoolbar\n"); return-1;//failtocreate }m_wndToolBar.SetButtonText(0,"新建");//你所需要做的工作只需要添加這些:)m_wndToolBar.SetButtonText(1,"打開");//第一個參數(shù)是圖標(biāo)索引,第個參數(shù)是想要顯示的文本m_wndToolBar.SetButtonText(2,"保存");m_wndToolBar.SetButtonText(4,"剪切");m_wndToolBar.SetButtonText(5,"復(fù)制");m_wndToolBar.SetButtonText(6,"粘貼");m_wndToolBar.SetButtonText(8,"打印");m_wndToolBar.SetButtonText(10,"關(guān)于");m_wndToolBar.SetButtonText(11,"詞法分析");m_wndToolBar.SetButtonText(13,"語法分析");m_wndToolBar.SetButtonText(14,"設(shè)置顏色");m_wndToolBar.SetButtonText(15,"樣例演示");m_wndToolBar.SetButtonText(16,"退出");m_wndToolBar.SetSizes(CSize(90,45),CSize(24,24));5.3.5起始屏的設(shè)計到此為止,本詞法語法分析器的幾個主要功能模塊已經(jīng)編碼實現(xiàn)了,已經(jīng)可以作為一個單獨(dú)的小軟件來進(jìn)行程序測試了。接下來的任務(wù)就是美化軟件的界面,使之趨于完善。通常在啟動一個大型應(yīng)用程序時,往往要等待相當(dāng)長的一段時間(從幾秒到幾十秒),在這段時間里,如果使用起始屏,會產(chǎn)生相當(dāng)好的效果。起始屏一般被設(shè)置為一幅位圖,其處理過程是:先在內(nèi)存中加載一幅位圖,然后啟動一個定時器,當(dāng)定時結(jié)束時,關(guān)閉位圖顯示。在VisualC++中,起始屏的設(shè)計是可以通過組件來完成的。只需在Project菜單下選擇AddtoProject選項下的Components&Controls,選擇VisualC++Components中的SplashScreen組件即可,實現(xiàn)的代碼如下:BOOLCLogoThread::InitInstance(){//說明:通常,系統(tǒng)內(nèi)的每個線程都有自己的輸入隊列。本函數(shù)(既“連接線程輸入函數(shù)”)允許線程和進(jìn)程共享輸入隊列。連接了線程后,輸入焦點、窗口激活、鼠標(biāo)捕獲、鍵盤狀態(tài)以及輸入隊列狀態(tài)都會進(jìn)入共享狀態(tài)::AttachThreadInput(m_nThreadID, //欲連接線程的標(biāo)識符(ID) AfxGetApp()->m_nThreadID, //與idAttach線程連接的另一個線程的標(biāo)識符 true ); //TRUE(非零)連接,F(xiàn)ALSE撤消連接m_pLogoDlg=newCLogoDlg;m_pLogoDlg->Create(IDD_LOGODLG);m_pLogoDlg->ShowWindow(SW_SHOW);//在這個用戶界面線程中創(chuàng)建對話框returntrue;}voidCLogoThread::HideSplash(){ m_pLogoDlg->SendMessage(WM_CLOSE);}intCLogoThread::ExitInstance(){ m_pLogoDlg->DestroyWindow(); deletem_pLogoDlg; returnCWinThread::ExitInstance();}BEGIN_MESSAGE_MAP(CLogoThread,CWinThread)END_MESSAGE_MAP()使用SplashScreen組件時,實現(xiàn)起始屏的設(shè)計的代碼是在logo.cpp中編輯的,而起始屏的圖片設(shè)計代碼則在logodlg.cpp中實現(xiàn)。圖5-9為起始屏的設(shè)計視圖:圖5-9起始屏的設(shè)計視圖5.4PL/0語言詞法與語法分析器的測試5.4.1測試的重要性軟件開發(fā)過程可分為:需求分析、軟件設(shè)計、軟件實現(xiàn)和軟件測試四個階段。需求分析的結(jié)果決定輸入,測試后的軟件是最終的輸出。重視軟件的輸入和輸出,就把住了產(chǎn)品的質(zhì)量關(guān)。成熟的客戶一定會積極參與測試,測試不到家時是絕對不會允許軟件投產(chǎn)的;成熟的軟件項目開發(fā)團(tuán)體都會安排充足的時間對系統(tǒng)進(jìn)行測試。一般來說越早發(fā)現(xiàn)軟件問題,改正的成本越低,破壞性越小。所以,在系統(tǒng)發(fā)布前,要盡量多地把軟件可能存在的問題找出來。找問題的主要手段就是有計劃、有組織地進(jìn)行充分的測試。如果不測試,等軟件投產(chǎn)后發(fā)現(xiàn)的問題,其危害性將被成倍放大,將直接損壞開發(fā)商和客戶雙方的利益和聲譽(yù)。總之,是否重視所開發(fā)軟件的測試[3],是判定開發(fā)商和客戶是否成熟的重要標(biāo)志。5.4.2分析器的測試過程和運(yùn)行效果本軟件的設(shè)計思路簡單,因此不需要特別多的測試環(huán)節(jié)。本次畢業(yè)設(shè)計只設(shè)計了一個樣例程序演示詞法分析與語法分析的運(yùn)行情況。點擊工具條上的“演示”按鈕,得到如圖5-10的結(jié)果,測試程序按設(shè)計要求輸出在左邊的輸入窗口中:圖5-10點擊樣例演示效果圖點擊“詞法分析”按鈕,分析器對測試程序進(jìn)行詞法分析的結(jié)果按要求輸出在圖5-11所示的右邊輸出窗口中:圖5-11測試程序詞法分析結(jié)果點擊“語法分析”按鈕,分析器對測試程序進(jìn)行語法分析的結(jié)果按要求輸出在圖5-12所示的右邊輸出窗口中:圖5-12測試程序的語法分析結(jié)果單擊“關(guān)于”按鈕,顯示如圖5-13所示的版權(quán)信息:圖5-13關(guān)于此編譯器單擊“顏色”按鈕,運(yùn)行效果如圖5-14所示,可設(shè)置背景、前景顏色效果。圖5-14顏色設(shè)置效果圖6結(jié)束語通過這次畢業(yè)設(shè)計,實現(xiàn)了PL/0語言的詞法語法分析器的大部分功能,讓本人對VC++語言有了一個比較深入的了解,而且對于編程語言和編程工具有了一個深刻的認(rèn)識,掌握了一些軟件的基本操作,以及軟件界面的設(shè)計,熟悉了一些簡單的程序設(shè)計過程和界面美化方法。雖然該P(yáng)L/0詞法與語法分析器大部分功能已經(jīng)實現(xiàn)了,但其中可能仍存在許多不足之處。首先,系統(tǒng)的界面的設(shè)計還不夠美觀,技巧性不強(qiáng),布局不很合理;其次,這個詞法語法分析器的性能如何還沒有經(jīng)過實際應(yīng)用的大量測試和考驗,譬如,分析器僅限于對PL/0語言的程序進(jìn)行詞法和語法分析,具有很大的局限性,這是一個比較現(xiàn)實的問題;另外在實際的運(yùn)行中可能還會出現(xiàn)隱藏的問題。而且由于時間倉促,作者水平有限,沒有對系統(tǒng)其他一些十分有用的功能進(jìn)行發(fā)掘和實現(xiàn),還有許多地方尚待改進(jìn)和完善。參考文獻(xiàn)[1]費(fèi)雷澤.可變目標(biāo)C編譯器設(shè)計與實現(xiàn)[M].北京:電子工業(yè)出版社,2005[2]CharlesN.Fischer.編譯器構(gòu)造C語言設(shè)計[M].北京:機(jī)械工業(yè)出版社,2005[3]呂映芝,張素琴,蔣維杜.編譯原理[M].北京:清華大學(xué)出版社,2005[4]AndrewW.Appel.現(xiàn)代編譯原理C語言描述[M].北京:人民郵電出版社,2006[5]陳火旺,錢家驊,孫永強(qiáng).程序設(shè)計語言編譯原理[M].北京:國防工業(yè)出版社,1980[6]KennethC.Louden.編譯原理及實踐[M].北京:機(jī)械工業(yè)出版社,2000[7]鴻健.C語言高級程序員編程指南[M].北京:中科院希望出版社,2000[8]劉海濤.TurboPascal程序設(shè)計基礎(chǔ)[M].北京:清華大學(xué)出版社,2000[9]斯科特.程序設(shè)計語言—實踐之路[M].北京:電子工業(yè)出版社,2005[10]AndrewKoenig.C陷阱與缺陷[M].北京:人民郵電出版社,2002[11]溫敬和.編譯原理使用教程[M].北京:清華大學(xué)出版社,2005[12]阿霍,塞西,厄爾曼.編譯原理技術(shù)與工具[M].北京:人民郵電出版社,2002附錄詞法語法分析程序頭文件fenxi.h:/*************************************************************************文件名:FenXi.h*文件描述:詞法語法分析的頭文件*創(chuàng)建人:黃遠(yuǎn)強(qiáng),2007年04月15日*版本號:1.0************************************************************************/#if!defined_FENXI_H#define_FENXI_HstructCIFA //保存詞法分析結(jié)果{ intnType; //0:錯誤, 1:標(biāo)志符, 2:數(shù)字, 3-:關(guān)鍵字和操作符, -1:結(jié)束符 intnValue; //二元式中的值 charszText[20]; //單詞 charszDesc[50];//描述 intnAddr; //源文件緩沖區(qū)中地址};classCFenXi{ public: voidYuFaFenXi();//語法分析 voidCiFaFenXi();//詞法分析 intm_nErrAddr; //語法錯誤對應(yīng)單詞的地址 intm_nErrNo; //語法錯誤代碼 charm_str[20000]; //源程序緩沖區(qū) charm_szErrMsg[100][100]; //錯誤信息表 CIFA*m_cifa[10000]; //詞法分析結(jié)果protected: voidinit(); intm_nCur; //用于語法分析中,指示詞法分析結(jié)果表中當(dāng)前的位置 intm_n; //用于詞法分析中,用于指示詞法分析結(jié)果的個數(shù) charm_kw[50][20]; //關(guān)鍵詞表 intFinKW(char*);/*語法分析函數(shù)*/ boolChengXu(); //程序 boolChengXuTi(); //程序體 boolShengMing(); //聲明 boolShengMingChuan(); //聲明串 boolBianliangShengMing(); //變量聲明 boolChangliangShengMing(); //常量聲明 boolGuoChengShengMing(); //過程聲明 boolShiCan(); //實參 boolXingCan(); //形參 boolYuJu(); //語句 boolYuJuChuan(); //語句串 boolGuoChengYuJu(); //過程語句 boolXunHuanYuJu(); //循環(huán)語句 boolTiaoJianYuJu(); //條件語句 boolFuZhiYuJu(); //賦值語句 boolFuHeYuJu(); //復(fù)合語句 boolBiaoDaShi(); //表達(dá)式 boolGuanXiBiaoDaShi(); //關(guān)系表達(dá)式 boolBoolBiaoDaShi(); //布爾表達(dá)式 boolXiang(); //項 boolYinZi(); //因子 boolGuanXi(); //關(guān)系/**/};#endif詞法語法分析程序fenxi.cpp:/*************************************************************************文件名:FenXi.cpp*文件描述:詞法語法分析的實現(xiàn)文件*創(chuàng)建人:黃遠(yuǎn)強(qiáng),2007年04月15日************************************************************************/#include"stdafx.h"#include"fenxi.h"/*================================================================*函數(shù)名:CiFaFenXi*功能描述:詞法分析(public)*返回值:void================================================================*/voidCFenXi::CiFaFenXi(){ BOOLflag=false; chartoken[20]; intk,v; init(); for(inti=0;i<m_n;i++)//當(dāng)?shù)?次調(diào)用該函數(shù)時,就要釋放前1次的資源 { deletem_cifa[i]; } intn=0; //用于指示當(dāng)前的字符 m_n=0; //詞法結(jié)果單詞的個數(shù) while(m_str[n]) { if(flag) { while(!((m_str[n]=='*')&&(m_str[n+1]=='/'))) { if(m_str[n]) n++; else break; } if(m_str[n]) { n++; n++; flag=false; } } while(1) { while((m_str[n]==32)||(m_str[n]==9)) n++; if(!((m_str[n]==13)&&(m_str[n+1]==10))) break; n++; n++; } if(isalpha(m_str[n])) //字母 { k=0; while(1) { if(k<19) //標(biāo)志符的長度為20 token[k++]=m_str[n++]; else n++; if(!isalnum(m_str[n]))//如果不是數(shù)字或字母就退出 break; } token[k]=0; v=FinKW(token); //查找關(guān)鍵詞表 if(v) //如果是關(guān)鍵詞 { m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"基本字"); m_cifa[m_n]->nAddr=n-k; m_n++; } else//普通標(biāo)志符 { m_cifa[m_n]=newCIFA; /*在詞法分析結(jié)果中查找*/ intvv=1; for(inti=0;i<m_n;i++) { if(m_cifa[i]->nType==1) { vv++; if(!::stricmp(m_cifa[i]->szText,token)) m_cifa[m_n]->nValue=m_cifa[i]->nValue; } } m_cifa[m_n]->nValue=vv; /**/ m_cifa[m_n]->nType=1; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"標(biāo)識符"); m_cifa[m_n]->nAddr=n-k; m_n++; } } elseif(isdigit(m_str[n])) //數(shù)字 { k=0; BOOLerror=false; while(1) { if(k<=8) token[k++]=m_str[n++]; else { error=true; n++; } if(!isdigit(m_str[n])) break; } token[k]=0; v=::strtol(token,NULL,10); if(error) { m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=1; m_cifa[m_n]->nType=0; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,""); m_cifa[m_n]->nAddr=n-k; m_n++; } else { m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=v; m_cifa[m_n]->nType=2; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"常數(shù)"); m_cifa[m_n]->nAddr=n-k; m_n++; } } else switch(m_str[n]) //其他符號 { case'+': case'-': case'*': case'=': token[0]=m_str[n]; token[1]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; break; case'~': case'&': case'|': case';': case'.': case',': case'(': case')': token[0]=m_str[n]; token[1]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"界符"); m_cifa[m_n]->nAddr=n; m_n++; n++; break; case'\0': break; case'/': switch(m_str[n+1]) { case'*': n++; n++; flag=true; break; default: token[0]=m_str[n]; token[1]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"___"); m_cifa[m_n]->nAddr=n; m_n++; n++; } break; case'<': switch(m_str[n+1]) { case'=': token[0]=m_str[n]; token[1]=m_str[n+1]; token[2]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; n++; break; case'>': token[0]=m_str[n]; token[1]=m_str[n+1]; token[2]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; n++; break; default: token[0]=m_str[n]; token[1]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; } break; case'>': switch(m_str[n+1]) { case'=': token[0]=m_str[n]; token[1]=m_str[n+1]; token[2]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; n++; break; default: token[0]=m_str[n]; token[1]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; } break; case':': switch(m_str[n+1]) { case'=': token[0]=m_str[n]; token[1]=m_str[n+1]; token[2]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"運(yùn)算符"); m_cifa[m_n]->nAddr=n; m_n++; n++; n++; break; default: token[0]=m_str[n]; token[1]=0; v=FinKW(token); m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=v; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"界符"); m_cifa[m_n]->nAddr=n; m_n++; n++; } break; default: token[0]=m_str[n]; token[1]=0; m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=2; m_cifa[m_n]->nType=0; strcpy(m_cifa[m_n]->szText,token); strcpy(m_cifa[m_n]->szDesc,"___"); m_cifa[m_n]->nAddr=n; m_n++; n++; } if(m_n==10000-2) //詞法分析的結(jié)果的個數(shù)規(guī)定為10000 { m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=99; m_cifa[m_n]->nType=0; strcpy(m_cifa[m_n]->szText,""); strcpy(m_cifa[m_n]->szDesc,"錯誤"); m_cifa[m_n]->nAddr=n-1; m_n++; break; } } m_cifa[m_n]=newCIFA; m_cifa[m_n]->nValue=0; m_cifa[m_n]->nType=-1; //結(jié)束符 strcpy(m_cifa[m_n]->szText,""); strcpy(m_cifa[m_n]->szDesc,"程序結(jié)束"); m_cifa[m_n]->nAddr=0; m_n++; return;}/*================================================================*函數(shù)名:FinKW(char*a)*功能描述:在關(guān)鍵字表中查找(protected)*返回值:int(如果找到返回在表中的位置,否則返回0)================================================================*/intCFenXi::FinKW(char*a){ for(inti=0;i<50;i++) if(!::stricmp(m_kw[i],a))//找到 returni; return0;//未找到}/*================================================================*函數(shù)名:YuFaFenXi*功能描述:語法分析(public)*返回值:void*作者:黃遠(yuǎn)強(qiáng)2007年4月15日================================================================*/voidCFenXi::YuFaFenXi(){ if(m_n==0) return; //尚未進(jìn)行詞法分析 m_nCur=0; //m_nCur用語指示詞法分析結(jié)果表中單詞的位置 ChengXu(); //從程序開始 return;}/*================================================================*函數(shù)名:ChengXu*功能描述:分析整個程序(protected)*返回值:bool*示例: Programabc; 這里是程序體 .================================================================*/boolCFenXi::ChengXu() //程序{ if(m_cifa[m_nCur]->nType!=3) { m_nErrNo=3; //缺少程序聲明符號program m_nErrAddr=m_nCur; returnfalse; } m_nCur++; //分析下一個單詞 if(m_cifa[m_nCur]->nType!=1)//標(biāo)識符 { m_nErrNo=4; //program后缺少標(biāo)識符! m_nErrAddr=m_nCur; returnfalse; } m_nCur++; if(m_cifa[m_nCur]->nType!=30)//; { m_nErrNo=5; //程序聲明后缺少; m_nErrAddr=m_nCur; returnfalse; } m_nCur++; if(!ChengXuTi())//分析程序體 returnfalse; if(m_cifa[m_nCur]->nType!=31) //.(程序的最后一個符號) { m_nErrNo=6; //缺少程序結(jié)束符. m_nErrAddr=m_nCur; returnfalse; } m_nCur++; if(m_cifa[m_nCur]->nType!=-1) { m_nErrNo=96; //源程序結(jié)束符.后還有多余的內(nèi)容! m_nErrAddr=m_nCur; returnfalse; } m_nErrNo=0; //語法分析成功 m_nErrAddr=m_nCur; returntrue;}/*================================================================*函數(shù)名:ChengXuTi*功能描述:分析程序體(protected)*返回值:bool*示例: varx,y,z;//變量聲明 consta,b;//常量聲明 Procedureab(Integerm,n:var;t:const);//過程聲明 Begin t:=n+m; Ifm>nthenn:=telsem:=t; Whilen<mdo Begin n:=n+1 End End; Begin 這里是語句串 End================================================================*/boolCFenXi::ChengXuTi(){ switch(m_cifa[m_nCur]->nType) { case5: //procedure case14: //var case15: //const if(!ShengMingChuan())//聲明串(用;隔開的多個變量或過程聲明) returnfalse; if(m_cifa[m_nCur]->nType!=30)//; { m_nErrNo=5; //缺少;!" m_nErrAddr=m_nCur; returnfalse; } m_nCur++; break; case6: /
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 建筑施工合同轉(zhuǎn)讓協(xié)議
- 砂礫購銷合同
- 房地產(chǎn)項目顧問服務(wù)合同
- 售貨機(jī)銷售合同協(xié)議
- 醫(yī)藥研發(fā)服務(wù)合同
- 第12課《自定主題活動三:制作方便面盒滑翔機(jī)》(教學(xué)設(shè)計)-2023-2024學(xué)年四年級下冊綜合實踐活動浙教版
- Unit 6 教學(xué)設(shè)計2024-2025學(xué)年人教版(2024)七年級英語上冊
- 六安職業(yè)技術(shù)學(xué)院《獸醫(yī)流行病學(xué)專題》2023-2024學(xué)年第二學(xué)期期末試卷
- 石家莊城市經(jīng)濟(jì)職業(yè)學(xué)院《化學(xué)合成實驗》2023-2024學(xué)年第二學(xué)期期末試卷
- 中國地質(zhì)大學(xué)(北京)《水生態(tài)保護(hù)與修復(fù)》2023-2024學(xué)年第二學(xué)期期末試卷
- 固定翼飛機(jī)的結(jié)構(gòu)和飛行原理
- 內(nèi)蒙古鄂爾多斯杭錦經(jīng)濟(jì)開發(fā)區(qū)地質(zhì)災(zāi)害危險性評估報告
- DB23T 2656-2020樺樹液采集技術(shù)規(guī)程
- 2023年蘇州職業(yè)大學(xué)單招職業(yè)適應(yīng)性測試題庫及答案解析
- 中國故事英文版哪吒英文二篇
- 2023年中智集團(tuán)及下屬單位招聘筆試題庫及答案解析
- GB/T 8888-2003重有色金屬加工產(chǎn)品的包裝、標(biāo)志、運(yùn)輸和貯存
- GB/T 32685-2016工業(yè)用精對苯二甲酸(PTA)
- GB/T 21872-2008鑄造自硬呋喃樹脂用磺酸固化劑
- 酒店業(yè)主代表崗位職責(zé)標(biāo)準(zhǔn)(8篇)
- 上海市中小學(xué)生語文學(xué)業(yè)質(zhì)量綠色指標(biāo)測試
評論
0/150
提交評論