《編譯原理》實驗指導(dǎo)書2016_第1頁
《編譯原理》實驗指導(dǎo)書2016_第2頁
《編譯原理》實驗指導(dǎo)書2016_第3頁
《編譯原理》實驗指導(dǎo)書2016_第4頁
《編譯原理》實驗指導(dǎo)書2016_第5頁
已閱讀5頁,還剩32頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、編譯原理實驗指導(dǎo)書編 譯 原 理實驗與課程設(shè)計指導(dǎo)書2016年10月目錄一、課程簡介2二、實驗?zāi)康?三、實驗環(huán)境2四、實驗任務(wù)2五、實驗項目3實驗一. 詞法分析3實驗二. 自頂向下語法分析8實驗三. 自底向上語法分析10實驗四. 語義分析11實驗五. 中間代碼生成12六、課程設(shè)計13七、考核方式13八、參考文獻14九、附錄PL0語言編譯源程序清單(部分)15編譯原理實驗與課程設(shè)計指導(dǎo)一、課程簡介1. 課程名稱:編譯原理(Principle of Compiler)2. 課程總學(xué)時: 64 學(xué)時理論: 48 學(xué)時;實驗: 16 學(xué)時3. 課程總學(xué)分: 4 學(xué)分二、實驗?zāi)康木幾g原理是計算機類專業(yè)特

2、別是計算機軟件專業(yè)的一門重要專業(yè)課。設(shè)置該課程的目的在于系統(tǒng)地向?qū)W生講述編譯系統(tǒng)的結(jié)構(gòu)、工作流程及編譯程序各組成部分的設(shè)計原理和實現(xiàn)技術(shù),使學(xué)生通過學(xué)習(xí)既掌握編譯理論和方法方面的基本知識,也具有設(shè)計、實現(xiàn)、分析和維護編譯程序等方面的初步能力。編譯原理是一門理論性和實踐性都比較強的課程。進行上機實驗的目的是使學(xué)生通過完成上機實驗題目加深對課堂教學(xué)內(nèi)容的理解。同時培養(yǎng)學(xué)生實際動手能力。三、實驗環(huán)境微機CPU P4以上,256M以上內(nèi)存,安裝好C語言,或C+,或Visual C+開發(fā)環(huán)境。四、實驗任務(wù)用C/C+/Visual C+語言編寫某語言的詞法分析程序、語法分析程序、語義分析程序、中間代碼生成

3、程序。五、實驗項目實驗一. 詞法分析1. 實驗?zāi)康膌 根據(jù)PL/0語言的文法規(guī)范,編寫PL/0語言的詞法分析程序。l 通過設(shè)計調(diào)試詞法分析程序,實現(xiàn)從源程序中分出各種單詞的方法;加深對課堂教學(xué)的理解;提高詞法分析方法的實踐能力。l 掌握從源程序文件中讀取有效字符的方法和產(chǎn)生源程序的內(nèi)部表示文件的法。 l 掌握詞法分析的實現(xiàn)方法。 l 上機調(diào)試編出的詞法分析程序。2. 實驗準(zhǔn)備微機CPU P4以上,256M以上內(nèi)存,安裝好C語言,或C+,或Visual C+.3. 實驗時間4學(xué)時4. 實驗內(nèi)容(1) 試用手工編碼方式構(gòu)造識別以下給定單詞的某一語言的詞法分析程序。(2) 語言中具有的單詞包括五個有

4、代表性的關(guān)鍵字begin、end、if、then、else;標(biāo)識符;整型常數(shù);六種關(guān)系運算符;一個賦值符和四個算術(shù)運算符。參考實現(xiàn)方法簡述如下。(3) 單詞的分類:構(gòu)造上述語言中的各類單詞符號及其分類碼表。表1 語言中的各類單詞符號及其分類碼表單詞符號類別編碼類別碼的助記符單詞值begin1BEGINend2ENDif3IFthen4THENelse5ELSE標(biāo)識符6ID字母打頭的字母數(shù)字串整常數(shù)7INT數(shù)字串<8LT<=9LE=10EQ<>11NE>12GT>=13GE:=14IS+15PL-16MI*17MU/18DI5、 實驗方法與處理過程在一個程序設(shè)

5、計語言中,一般都含有若干類單詞符號,為此可首先為每類單詞建立一張狀態(tài)轉(zhuǎn)換圖,然后將這些狀態(tài)轉(zhuǎn)換圖合并成一張統(tǒng)一的狀態(tài)圖,即得到了一個有限自動機,再進行必要的確定化和狀態(tài)數(shù)最小化處理,最后據(jù)此構(gòu)造詞法分析程序。在此為了使詞法分析程序結(jié)構(gòu)比較清晰,且盡量避免某些枝節(jié)問題的糾纏,假定要編譯的語言中,全部關(guān)鍵字都是保留字,程序員不得將它們作為源程序中的標(biāo)識符;在源程序的輸入文本中,關(guān)鍵字、標(biāo)識符、整常數(shù)之間,若未出現(xiàn)關(guān)系和算術(shù)運算符以及賦值符,則至少須用一個空白字符加以分隔。作了這些限制以后,就可以把關(guān)鍵字和標(biāo)識符的識別統(tǒng)一進行處理。即每當(dāng)開始識別一個單詞時,若掃視到的第一個字符為字母,則把后續(xù)輸入的

6、字母或數(shù)字字符依次進行拼接,直至掃視到非字母、數(shù)字字符為止,以期獲得一個盡可能長的字母數(shù)字字符串,然后以此字符串查所謂保留字表(此保留字表已事先造好),若查到此字符串,則取出相應(yīng)的類別碼;反之,則表明該字符串應(yīng)為一標(biāo)識符。采用上述策略后,針對表I中部分單詞可以構(gòu)造一個如圖1所示的有限自動機(以狀態(tài)轉(zhuǎn)換圖表示)。在圖1中添加了當(dāng)進行狀態(tài)轉(zhuǎn)移時,詞法分析程序應(yīng)執(zhí)行的語義動作。根據(jù)圖1,可用C語言編寫出符合以上幾項要求的一個相應(yīng)的掃描器程序,如程序一所示。圖1 識別表I所列語言中的部分單詞的DFA及相關(guān)的語義過程圖1及程序一中所出現(xiàn)的語義變量及語義函數(shù)的含義和功能說明如下。函數(shù)GETCHAR:每調(diào)用

7、一次,就把掃描指示器當(dāng)前所指示的源程序字符送入字符變量ch,然后把掃描指示器前推一個字符位置。字符數(shù)組TOKEN:用來依次存放一個單詞詞文中的各個字符。函數(shù)CAT:每調(diào)用一次,就把當(dāng)前ch中的字符拼接于TOKEN中所存字符串的右邊。函數(shù)LOOKUP:每調(diào)用一次,就以TOKEN中的字符串查保留字表,若查到,就將相應(yīng)關(guān)鍵字的類別碼賦給整型變量c;否則將c置為零。函數(shù)RETRACT:每調(diào)用一次,就把掃描指示器回退一個字符位置(即退回多讀的那個字符)。函數(shù)OUT:一般僅在進入終態(tài)時調(diào)用此函數(shù),調(diào)用的形式為OUT(c,VAL)。其中,實參c為相應(yīng)單詞的類別碼或其助記符;當(dāng)所識別的單詞為標(biāo)識符和整數(shù)時,實

8、參VAL為TOKEN(即詞文分別為字母數(shù)字串和數(shù)字串),對于其余種類的單詞,VAL均為空串。函數(shù)OUT的功能是,在送出一個單詞的內(nèi)部表示之后,返回到調(diào)用該詞法分析程序的那個程序。程序一 根據(jù)圖1編寫的掃描器# include <stdio.h># include <ctype.h># include <string.h># define ID 6# define INT 7# define LT 8# define LE 9# define EQ 10# define NE 11# define GT 12# define GE 13char TOKEN20

9、;extern int lookup (char*);extern void out (int, char*);extern report_error (void);void scanner_example (FILE *fp)char ch; int i, c;ch=fgetc (fp);if (isalpha (ch) /*it must be a identifer!*/TOKEN0=ch; ch=fgetc (fp); i=1;while (isalnum (ch)TOKENi=ch; i+;ch=fgetc (fp);TOKENi= 0fseek(fp,-1,1); /* retra

10、ct*/c=lookup (TOKEN);if (c=0) out (ID,TOKEN); else out (c," ");elseif(isdigit(ch)TOKEN0=ch; ch=fgetc(fp); i=1;while(isdigit(ch)TOKENi=ch; i+;ch=fgetc(fp);TOKENi= 0;fseek(fp,-1,1);out(INT,TOKEN);elseswitch(ch)case : ch=fgetc(fp);if(ch=)out(LE," ");else if(ch=) out (NE," "

11、;);elsefseek (fp,-1,1);out (LT," ");break;case =: out(EQ, " "); break;case : ch=fgetc(fp);if(ch=)out(GE," ");elsefseek(fp,-1,1);out(GT," ");break;default: report_error( ); break;return;提示:掃描器所用的若干函數(shù)以及主程序有待于具體編寫,并需事先建立好保留字表,以備查詢。另外,在掃描源程序字符串時,一旦識別出關(guān)鍵字、標(biāo)識符、整常數(shù)以及

12、運算符中之一,即以二元式形式(類別編碼,值)輸出單詞。每次調(diào)用詞法分析程序,它均能自動繼續(xù)掃描下去,形成下一個單詞,直至整個源程序全部掃描完畢,并形成相應(yīng)的單詞串形式的源程序。6、 輸出結(jié)果:以文件形式輸入的例子至少應(yīng)包含兩行以上的源代碼,并以對照的形式將掃描器的分析結(jié)果輸出,必要時給出正誤信息。例:以下例題說明運行時的輸入輸出效果:輸入:const a=10;var b,c;beginread(b);c:=a+b;write(c)end.輸出:(constsym ,const )(ident , a)(eql , =)(number, 10)(semicolon , ;)(varsym ,

13、var )(ident, b)(comma, , )(ident, c )(semicolon , ;)(begins ym,begin)(readsym, read )(lparen , ( )(ident, b)(rparen , ) )(semicolon , ;)(ident, c )(becomes , := )(ident, a )(plus , + )(ident, b )(semicolon , ;)(writesym ,write )(lparen , ( )(ident, c )(rparen , ) )(endsym , end )實驗二. 自頂向下語法分析1. 實驗?zāi)康?/p>

14、(1)通過設(shè)計、編制、調(diào)試一個典型的語法分析程序,實現(xiàn)對詞法分析程序所提供的單詞序列進行語法檢查和結(jié)構(gòu)分析,進一步掌握常用的語法分析方法。(2)選擇最有代表性的語法分析方法遞歸子程序法;選擇對各種常見程序語言都具備的語法結(jié)構(gòu),如賦值語句,特別是表達式,作為分析對象。2. 實驗準(zhǔn)備微機CPU P4以上,256M以上內(nèi)存,安裝好C語言,或C+,或Visual C+.3. 實驗時間4學(xué)時4. 實驗內(nèi)容l 構(gòu)造遞歸下降LL(1)語法分析器。完成P87,例4.125. 實驗要求l 語法分析器的編寫方法采用遞歸子程序法。擴充完整例4.12的程序部分。l 輸入文法的句子,作為表達式語法分析器的輸入,進行語法

15、解析,對于語法正確的表達式,報告“語法正確”;l 對于語法錯誤的表達式,報告“語法錯誤”, 指出錯誤原因。l 把語法分析器設(shè)計成一個獨立一遍的過程。6. 輸入輸出輸入:至少找到2個句子,其中一個是文法的句子,另一個不是,分別輸入。輸出:對于語法正確的表達式,報告“語法正確”;對于語法錯誤的表達式,報告“語法錯誤”, 指出錯誤原因。實驗三. 自底向上語法分析1. 實驗?zāi)康慕o出算符優(yōu)先關(guān)系表的構(gòu)造方法,將FIRSTVT集合和LASTVT集合的算法擴充成程序。2. 實驗準(zhǔn)備微機CPU P4以上,256M以上內(nèi)存,安裝好C語言,或C+,或Visual C+.3. 實驗時間4學(xué)時4. 實驗內(nèi)容構(gòu)造求FI

16、RSTVT集合和LASTVT集合的程序。5. 實驗要求l 擴充P113求FIRSTVT集合的算法。l 完成LASTVT集合的算法。6. 輸入輸出輸入:文法。輸出:FIRSTVT集合和LASTVT集合。實驗四. 語義分析1. 實驗?zāi)康膌 通過上機實習(xí),加深對語法制導(dǎo)翻譯原理的理解,掌握將語法分析所識別的語法范疇變換為某種中間代碼的語義翻譯方法。l 掌握目前普遍采用的語義分析方法語法制導(dǎo)翻譯技術(shù)。l 要求在語法分析程序中添加語義處理,對于語法正確的算術(shù)表達式,輸出其計算值。2. 實驗準(zhǔn)備微機CPU P4以上,256M以上內(nèi)存,安裝好C語言,或C+,或Visual C+.3. 實驗時間4學(xué)時4. 實

17、驗內(nèi)容在表達式的語法分析程序里,添加語義處理部分。5. 實驗要求l 語義分析對象重點考慮經(jīng)過語法分析后已是正確的語法范疇,實習(xí)重點是語義子程序。l 在實驗三“語法分析器”的里面添加PL/0語言“表達式”部分的語義處理。l 計算表達式的語義值。6. 輸入輸出輸入:算術(shù)表達式,例如: 2 + 3 * 5作為輸入。輸出:17實驗五. 中間代碼生成1. 實驗?zāi)康囊笤谡Z法分析程序中添加語義處理,對于語法正確的表達式,輸出其中間代碼。2. 實驗準(zhǔn)備微機CPU P4以上,256M以上內(nèi)存,安裝好C語言,或C+,或Visual C+.3. 實驗時間4學(xué)時4. 實驗內(nèi)容在實驗三的表達式語法分析程序里,添加語義

18、處理部分輸出表達式的中間代碼,用四元式序列表示。5. 實驗要求l 在實驗三“語法分析器”的里面添加PL/0語言“表達式”部分的語義處理,輸出表達式的中間代碼。l 中間代碼用四元式序列表示。6. 輸入輸出輸入:表達式,例如: a * (b + c)。輸出:( + b c t1 )( * a t1 t2 )六、課程設(shè)計1、選題(四選一):(1)構(gòu)造遞歸下降分析程序語法分析器(2)構(gòu)造預(yù)測分析表語法分析器(3)構(gòu)造算符優(yōu)先分析語法分析器(4)構(gòu)造LR(0)分析法語法分析器2、設(shè)計方法: 小組分工,合作完成。從小到大,逐步擴展。按照文法和程序的特點,逐步完成設(shè)計和測試。3、設(shè)計報告: 應(yīng)包括:報告標(biāo)題

19、、主要工作概述、具體內(nèi)容(算法部分)、開發(fā)經(jīng)驗等。七、考核方式1、實驗報告和課程設(shè)計報告實驗獨立完成,提交實驗報告;課程設(shè)計采用分組的形式,3人一組,每個實習(xí)小組交一份課程設(shè)計報告,格式要求絕對規(guī)范!內(nèi)容應(yīng)包括以下內(nèi)容:l 題目l 設(shè)計思想l 算法l 調(diào)試數(shù)據(jù)(輸入/輸出)2、評分標(biāo)準(zhǔn)l 由指導(dǎo)教師根據(jù)實驗驗收情況并結(jié)合實驗報告質(zhì)量及學(xué)習(xí)態(tài)度等進行評分。l 課程設(shè)計作為獨立考查課,學(xué)分為1。八、參考文獻 編譯原理課程組 35 of 371編譯原理(第二版),張素琴、呂映芝、蔣維杜,清華大學(xué)出版社,2005年出版。2編譯程序設(shè)計原理,杜書敏、王永寧,北京大學(xué)出版社,1988年出版。3計算機編譯原

20、理,張幸兒,科學(xué)出版社,1999年出版。4編譯程序原理與技術(shù),李贛生等,清華大學(xué)出版社,1997年10月出版。九、附錄PL0語言編譯源程序清單(部分)源代碼pl0c.h/* 關(guān)鍵字個數(shù) */#define norw 13/* 名字表容量 */#define txmax 100/* 所有的add1用于定義數(shù)組 */#define txmaxadd1 101/* number的最大位數(shù) */#define nmax 14/* 符號的最大長度 */#define al 10/* 地址上界 */#define amax 2047/* 最大允許過程嵌套聲明層數(shù) */#define levmax 3/*

21、最多的虛擬機代碼數(shù) */#define cxmax 200#define cxmaxadd1 201/* 當(dāng)函數(shù)中會發(fā)生fatal error時,返回-1告知調(diào)用它的函數(shù),最終退出程序 */#define getsymdo if(-1=getsym()return -1#define getchdo if(-1=getch()return -1#define testdo(a,b,c) if(-1=test(a,b,c)return -1#define gendo(a,b,c) if(-1=gen(a,b,c)return -1#define expressiondo(a,b,c) if(-1

22、=expression(a,b,c)return -1#define factordo(a,b,c) if(-1=factor(a,b,c)return -1#define termdo(a,b,c) if(-1=term(a,b,c)return -1#define conditiondo(a,b,c) if(-1=condition(a,b,c)return -1#define statementdo(a,b,c) if(-1=statement(a,b,c)return -1#define constdeclarationdo(a,b,c) if(-1=constdeclaration(

23、a,b,c)return -1#define vardeclarationdo(a,b,c) if(-1=vardeclaration(a,b,c)return -1typedef enum false,true bool;/* 符號 */enum symbol nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,period,becomes,beginsym,endsym,ifsym,thensym,whilesym,writesym,read

24、sym,dosym,callsym,constsym,varsym,procsym;#define symnum 32/* 名字表中的類型 */enum object constant,variable,procedur;/* 虛擬機代碼 */enum fct lit,opr,lod,sto,cal,inte,jmp,jpc;#define fctnum 8/* 虛擬機代碼結(jié)構(gòu) */struct instructionenum fct f; /* 虛擬機代碼指令 */int l; /* 引用層與聲明層的層次差 */int a; /* 根據(jù)f的不同而不同 */;FILE* fas;/* 輸出名字

25、表 */FILE* fa; /* 輸出虛擬機代碼 */FILE* fa1; /* 輸出源文件及其各行對應(yīng)的首地址 */FILE* fa2; /* 輸出結(jié)果 */bool listswitch; /* 顯示虛擬機代碼與否 */bool tableswitch; /* 顯示名字表與否 */char ch; /* 獲取字符的緩沖區(qū),getch 使用 */enum symbol sym; /* 當(dāng)前的符號 */char idal; /* 當(dāng)前ident */int num; /* 當(dāng)前number */int cc,ll,kk; /* getch使用的計數(shù)器,cc表示當(dāng)前字符(ch)的位置 */int

26、 cx; /* 虛擬機代碼指針 */char line81; /* 讀取行緩沖區(qū) */char aal; /* 臨時符號 */struct instruction codecxmaxadd1; /* 存放虛擬機代碼的數(shù)組 */char wordnorwal; /* 保留字 */enum symbol wsymnorw; /* 保留字對應(yīng)的符號值 */enum symbol ssym256; /* 單字符的符號值 */char mnemonicfctnum5; /* 虛擬機代碼指令名稱 */bool declbegsyssymnum; /* 表示聲明開始的符號集合 */bool statbegs

27、yssymnum; /* 表示語句開始的符號集合 */bool facbegsyssymnum; /* 表示因子開始的符號集合 */* 名字表結(jié)構(gòu) */struct tablestructchar nameal;/* 名字 */enum object kind;/* 類型:const,var or procedure */int val; /* 數(shù)值,僅const使用 */int level; /* 所處層,僅const不使用 */int adr; /* 地址,僅const不使用 */int size; /* 需要分配的數(shù)據(jù)區(qū)空間,僅procedure使用 */;struct tablestr

28、uct tabletxmaxadd1; /* 名字表 */FILE* fin;FILE* fout;char fnameal;int err; /* 錯誤計數(shù)器 */void error(int n); int getsym();int getch();void init();int gen(enum fct x,int y,int z);int test(bool* s1,bool* s2,int n);int inset(int e,bool* s);int addset(bool* sr,bool* s1,bool* s2,int n);int subset(bool* sr,bool*

29、 s1,bool* s2,int n);int mulset(bool* sr,bool* s1,bool* s2,int n);int block(int lev,int tx,bool* fsys);void interpret();int factor(bool* fsys,int* ptx,int lev);int term(bool* fsys,int* ptx,int lev);int condition(bool* fsys,int* ptx,int lev);int expression(bool* fsys,int* ptx,int lev);int statement(bo

30、ol* fsys,int* ptx,int lev);void listcode(int cx0);int vardeclaration(int* ptx,int lev,int* pdx);int constdeclaration(int* ptx,int lev,int* pdx);int postion(char* idt,int tx);void enter(enum object k,int* ptx,int lev,int* pdx);int base(int l,int* s,int b);pl0c.c/* Windows 下c語言PL/0編譯程序在Visual C+ 6.0和V

31、isual C.NET上運行通過使用方法:運行后輸入PL/0源程序文件名回答是否輸出虛擬機代碼回答是否輸出名字表fa.tmp輸出虛擬機代碼fa1.tmp輸出源文件及其各行對應(yīng)的首地址fa2.tmp輸出結(jié)果fas.tmp輸出名字表*/#include <stdio.h>#include "pl0c.h"#include "string.h"/* 解釋執(zhí)行時使用的棧 */#define stacksize 500 int main()bool nxtlevsymnum;init();/* 初始化 */fas=fopen("fas.tmp

32、","w");fa1=fopen("fa1.tmp","w");printf("Input file? ");fprintf(fa1,"Input file? ");scanf("%s",fname);/* 輸入文件名 */fin=fopen(fname,"r");if(fin)fprintf(fa1,"%sn",fname);printf("List object code?(Y/N)");/* 是否輸出

33、虛擬機代碼 */scanf("%s",fname);listswitch=(fname0='y'|fname0='Y');printf("List symbol table?(Y/N)");/* 是否輸出名字表 */scanf("%s",fname);tableswitch=(fname0='y'|fname0='Y');err=0;cc=cx=ll=0;ch=' 'kk=al-1;if(-1!=getsym()fa=fopen("fa.tmp&

34、quot;,"w");fa2=fopen("fa2.tmp","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlevperiod=true;if(-1=block(0,0,nxtlev)/* 調(diào)用編譯程序 */fclose(fa);fclose(fa1);fclose(fin);printf("n");return 0;fclose(fa);fclose(fa1);if(sym!=period)error(9);if(err=0)interpret();/*

35、調(diào)用解釋執(zhí)行程序 */elseprintf("Errors in pl/0 program");fclose(fin);elseprintf("Can't open file!n");fprintf(fa1,"Can't open file!n");fclose(fa1);fclose(fas);printf("n");return 0;/* 在適當(dāng)?shù)奈恢蔑@示錯誤 */void error(int n)char space81;memset(space,32,81);spacecc-1=0; /*

36、出錯時當(dāng)前符號已經(jīng)讀完,所以cc-1 */ printf("*%s!%dn",space,n);fprintf(fa1,"*%s!%dn",space,n);err+;/* 詞法分析,獲取一個符號 */int getsym()int i,j,k;while(ch=' '|ch=10|ch=9)/* 忽略空格、換行和TAB */getchdo;if(ch>='a'&&ch<='z')/* 名字或保留字以a.z開頭 */k=0;doif(k<al)ak=ch;k+;getchd

37、o;while(ch>='a'&&ch<='z'|ch>='0'&&ch<='9');ak=0;strcpy(id,a);i=0;j=norw-1;do /* 搜索當(dāng)前符號是否為保留字 */k=(i+j)/2;if(strcmp(id,wordk)<=0)j=k-1;if(strcmp(id,wordk)>=0)i=k+1;while(i<=j);if(i-1>j)sym=wsymk; else sym=ident; /* 搜索失敗則,是名字或數(shù)字 *

38、/elseif(ch>='0'&&ch<='9')/* 檢測是否為數(shù)字:以0.9開頭 */k=0;num=0;sym=number;donum=10*num+ch-'0'k+;getchdo;while(ch>='0'&&ch<='9'); /* 獲取數(shù)字的值 */k-;if(k>nmax)error(30);elseif(ch=':')/* 檢測賦值符號 */getchdo;if(ch='=')sym=becomes;g

39、etchdo;elsesym=nul;/* 不能識別的符號 */elseif(ch='<')/* 檢測小于或小于等于符號 */getchdo;if(ch='=')sym=leq;getchdo;elsesym=lss;elseif(ch='>')/* 檢測大于或大于等于符號 */getchdo;if(ch='=')sym=geq;getchdo;elsesym=gtr;elsesym=ssymch;/* 當(dāng)符號不滿足上述條件時,全部按照單字符符號處理 */getchdo;return 0;/* 編譯程序主體 */int

40、 block(int lev, /* 當(dāng)前分程序所在層 */ int tx, /* 名字表當(dāng)前尾指針 */ bool* fsys /* 當(dāng)前模塊后跟符號集合 */ )int i;int dx; /* 名字分配到的相對地址 */int tx0; /* 保留初始tx */int cx0; /* 保留初始cx */bool nxtlevsymnum; /* 在下級函數(shù)的參數(shù)中,符號集合均為值參,但由于使用數(shù)租實現(xiàn), 傳遞進來的是指針,為防止下級函數(shù)改變上級函數(shù)的集合,開辟新的空間 傳遞給下級函數(shù),之后所有的nxtlev都是這樣 */dx=3; tx0=tx;/* 記錄本層名字的初始位置 */tabl

41、etx.adr=cx;gendo(jmp,0,0);if(lev>levmax)error(32);doif(sym=constsym)/* 收到常量聲明符號,開始處理常量聲明 */getsymdo;doconstdeclarationdo(&tx,lev,&dx);/* dx的值會被constdeclaration改變,使用指針 */while(sym=comma) getsymdo;constdeclarationdo(&tx,lev,&dx);if(sym=semicolon)getsymdo;else error(5);while(sym=iden

42、t);if(sym=varsym)/* 收到變量聲明符號,開始處理變量聲明 */getsymdo;dovardeclarationdo(&tx,lev,&dx);while(sym=comma) getsymdo;vardeclarationdo(&tx,lev,&dx);if(sym=semicolon)getsymdo;else error(5);while(sym=ident);while(sym=procsym) /* 收到過程聲明符號,開始處理過程聲明 */getsymdo;if(sym=ident)enter(procedur,&tx,lev

43、,&dx);/* 記錄過程名字 */getsymdo;else error(4);/* procedure后應(yīng)為標(biāo)識符 */if(sym=semicolon)getsymdo;else error(5);/* 漏掉了分號 */memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlevsemicolon=true;if(-1=block(lev+1,tx,nxtlev)return -1;/* 遞歸調(diào)用 */if(sym=semicolon)getsymdo;memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nx

44、tlevident=true;nxtlevprocsym=true;testdo(nxtlev,fsys,6);else error(5);/* 漏掉了分號 */memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlevident=true;testdo(nxtlev,declbegsys,7);while(inset(sym,declbegsys);/* 直到?jīng)]有聲明符號 */codetabletx0.adr.a=cx;/* 開始生成當(dāng)前過程代碼 */tabletx0.adr=cx;/* 當(dāng)前過程代碼地址 */tabletx0.size=dx;/

45、* 聲明部分中每增加一條聲明都會給dx增加1,聲明部分已經(jīng)結(jié)束,dx就是當(dāng)前過程數(shù)據(jù)的size */cx0=cx;gendo(inte,0,dx);/* 生成分配內(nèi)存代碼 */* 語句后跟符號為分號或end */memcpy(nxtlev,fsys,sizeof(bool)*symnum);/* 每個后跟符號集和都包含上層后跟符號集和,以便補救 */nxtlevsemicolon=true;nxtlevendsym=true;statementdo(nxtlev,&tx,lev);gendo(opr,0,0);/* 每個過程出口都要使用的釋放數(shù)據(jù)段指令 */memset(nxtlev,

46、0,sizeof(bool)*symnum);/*分程序沒有補救集合 */testdo(fsys,nxtlev,8);/* 檢測后跟符號正確性 */listcode(cx0);/* 輸出代碼 */return 0;/* 初始化 */void init()int i;/* 設(shè)置單字符符號 */for(i=0;i<=255;i+)ssymi=nul;ssym'+'=plus;ssym'-'=minus;ssym'*'=times;ssym'/'=slash;ssym'('=lparen;ssym')

47、9;=rparen;ssym'='=eql;ssym','=comma;ssym'.'=period;ssym'#'=neq;ssym''=semicolon;/* 設(shè)置保留字名字 */strcpy(&(word00),"begin");strcpy(&(word10),"call");strcpy(&(word20),"const");strcpy(&(word30),"do");strcpy(&

48、;(word40),"end");strcpy(&(word50),"if");strcpy(&(word60),"odd");strcpy(&(word70),"procedure");strcpy(&(word80),"read");strcpy(&(word90),"then");strcpy(&(word100),"var");strcpy(&(word110),"while&quo

49、t;);strcpy(&(word120),"write");/* 設(shè)置保留字符號 */wsym0=beginsym;wsym1=callsym;wsym2=constsym;wsym3=dosym;wsym4=endsym;wsym5=ifsym;wsym6=oddsym;wsym7=procsym;wsym8=readsym;wsym9=thensym;wsym10=varsym;wsym11=whilesym;wsym12=writesym;/* 設(shè)置指令名稱 */strcpy(&(mnemoniclit0),"lit");strc

50、py(&(mnemonicopr0),"opr");strcpy(&(mnemoniclod0),"lod");strcpy(&(mnemonicsto0),"sto");strcpy(&(mnemoniccal0),"cal");strcpy(&(mnemonicinte0),"int");strcpy(&(mnemonicjmp0),"jmp");strcpy(&(mnemonicjpc0),"jpc&qu

51、ot;);/* 供getsym取一個字符,每次讀一行,存入line緩沖區(qū),line被getsym取空時 再讀一行*/int getch()if(cc=ll)if(feof(fin)printf("program incomplete");return -1;ll=0;cc=0;printf("%d ",cx);fprintf(fa1,"%d ",cx);ch=' 'while(ch!=10)fscanf(fin,"%c",&ch);printf("%c",ch);fprintf(fa1,"%c",ch);linell=ch;ll+;printf("n");fprintf(fa1,"n");ch=linecc;cc+;return 0;/* 生成一項名字表 */void enter(enum object k,/* 名字種類const,var or procedure */ int* ptx,/* 名字表尾指針的指針,為了可以改變名字表尾指針的值,以后所

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論