編譯原理與技術(shù)_第1頁
編譯原理與技術(shù)_第2頁
編譯原理與技術(shù)_第3頁
編譯原理與技術(shù)_第4頁
編譯原理與技術(shù)_第5頁
已閱讀5頁,還剩25頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

編譯原理實驗報告課程名稱:編譯原理與技術(shù)學(xué)院名稱:計算機(jī)科學(xué)與技術(shù)學(xué)院專業(yè)班級:計算機(jī)學(xué)生姓名:學(xué)號:指導(dǎo)教師:實驗一:PL/0語言建立一個詞法分程序GETSYM(函數(shù))實驗?zāi)康模杭由顚φn堂教學(xué)的理解;提高詞法分析方法的實踐能力。實驗要求:把關(guān)鍵字、算符、界符稱為語言固有的單詞,標(biāo)識符、常量稱為用戶自定義的單詞。為此設(shè)置三個全程量:SYM,ID,NUM。SYM:存放每個單詞的類別,為內(nèi)部編碼的表示形式。ID:存放用戶所定義的標(biāo)識符的值,即標(biāo)識符字符串的機(jī)內(nèi)表示。NUM:存放用戶定義的數(shù)。GETSYM要完成的任務(wù):濾掉單詞間的空格。識別關(guān)鍵字,用查關(guān)鍵字表的方法識別。當(dāng)單詞是關(guān)鍵字時,將對應(yīng)的類別放在SYM中。如IF的類別為IFSYM,THEN的類別為THENSYM。識別標(biāo)識符,標(biāo)識符的類別為IDENT,IDRNT放在SYM中,標(biāo)識符本身的值放在ID中。關(guān)鍵字或標(biāo)識符的最大長度是10。拼數(shù),將數(shù)的類別NUMBER放在SYM中,數(shù)本身的值放在NUM中。拼由兩個字符組成的運算符,如:>=、<=等等,識別后將類別存放在SYM中。打印源程序,邊讀入字符邊打印。由于一個單詞是由一個或多個字符組成的,所以在詞法分析程序GETSYM中定義一個讀字符過程GETCH。3.程序設(shè)計:首先將標(biāo)識符,變量,常量,運算符,關(guān)鍵字,標(biāo)點符號分別放入數(shù)組中。構(gòu)造實驗所需要的方法:如下源代碼中所示(包括文本的搜索和讀入等)。根據(jù)要編譯的程序中的空格將其中的單詞等分辨出來,并將其保存在相應(yīng)的數(shù)組中。將結(jié)果寫入文件。實驗二:PL/0語言建立一個語法分析程序BLOCK(函數(shù))實驗內(nèi)容:PL/0編譯程序采用一遍掃描的方法,所以語法分析和代碼生成都有在BLOCK中完成。BLOCK的工作分為兩步:說明部分的處理說明部分的處理任務(wù)就是對每個過程(包括主程序,可以看成是一個主過程)的說明對象造名字表。填寫所在層次(主程序是0層,在主程序中定義的過程是1層,隨著嵌套的深度增加而層次數(shù)增大。PL/0最多允許3層),標(biāo)識符的屬性和分配的相對地址等。標(biāo)識符的屬性不同則填寫的信息不同。所造的表放在全程量一維數(shù)組TABLE中,TX為指針,數(shù)組元素為結(jié)構(gòu)體類型數(shù)據(jù)。LEV給出層次,DX給出每層的局部量的相對地址,每說明完一個變量后DX加1。例如:一個過程的說明部分為:consta=35,b=49;varc,d,e;procedurep;varg;對它的常量、變量和過程說明處理后,TABLE表中的信息如下:TX0→TX0→TX1→NAME:aNAME:bNAME:cNAME:dNAME:eNAME:pKIND:CONSTANTKIND:CONSTANTKIND:VARIABLEKIND:VARIABLEKIND:VAEIABLEKIND:PROCEDUREVAL:35VAL:49LEVEL:LEVLEVEL:LEVLEVEL:LEVLEVEL:LEVADR:DXADR:DX+1ADR:DX+2ADR:NAME:g。。。KIND:VARIABLE。。。LEVEL:LEV+1。。。ADR:DX。。。對于過程名的ADR域,是在過程體的目標(biāo)代碼生成后返填過程體的入口地址。TABLE表的索引TX和層次單元LEV都是以BLOCK的參數(shù)形式出現(xiàn),在主程序調(diào)用BLOCK時實參的值為0。每個過程的相對起始位置在BLOCK內(nèi)置初值DX=3。2.語句處理和代碼生成對語句逐句分析,語法正確則生目標(biāo)代碼,當(dāng)遇到標(biāo)識符的引用則去查TABLE表,看是否有過正確的定義,若有則從表中取出相關(guān)的信息,供代碼生成用。PL/0語言的代碼生成是由過程GEN完成。GEN過程有三個參數(shù),分別代表目標(biāo)代碼的功能碼、層差、和位移量。生成的目標(biāo)代碼放在數(shù)組CODE中。CODE是一維數(shù)組,數(shù)組元素是結(jié)構(gòu)體類型數(shù)據(jù)。PL/0語言的目標(biāo)指令是一種假想的棧式計算機(jī)的匯編語言,其格式如下:flfla其中f代表功能碼,l代表層次差,a代表位移量。目標(biāo)指令有8條:①LIT:將常數(shù)放到運棧頂,a域為常數(shù)。②LOD:將變量放到棧頂。a域為變量在所說明層中的相對位置,l為調(diào)用層與說明層的層差值。③STO:將棧頂?shù)膬?nèi)容送到某變量單元中。a,l域的含義與LOD的相同。④CAL:調(diào)用過程的指令。a為被調(diào)用過程的目標(biāo)程序的入中地址,l為層差。⑤INT:為被調(diào)用的過程(或主程序)在運行棧中開辟數(shù)據(jù)區(qū)。a域為開辟的個數(shù)。⑥JMP:無條件轉(zhuǎn)移指令,a為轉(zhuǎn)向地址。⑦JPC:條件轉(zhuǎn)移指令,當(dāng)棧頂?shù)牟紶栔禐榉钦鏁r,轉(zhuǎn)向a域的地址,否則順序執(zhí)行。⑧OPR:關(guān)系和算術(shù)運算。具體操作由a域給出。運算對象為棧頂和次頂?shù)膬?nèi)容進(jìn)行運算,結(jié)果存放在次頂。a域為0時是退出數(shù)據(jù)區(qū)。實驗主要步驟:1.首先運行詞法分析器,逐個讀取文件中的單詞,2.然后識別每個單詞,判定每個單詞的類別3.之后根據(jù)單詞的類別來選擇不同的處理方式4.而且在語法分析函數(shù)的block函數(shù)中定義了兩個可變數(shù)組,分別存放table表和code代碼。5.另外定義了error數(shù)組,分別存放出錯的類型,但是數(shù)量有限,不能完全識別所有錯誤。實驗三:建立一個解釋執(zhí)行目標(biāo)程序的函數(shù)實驗內(nèi)容:編譯結(jié)束后,記錄源程序中標(biāo)識符的TABLE表已退出內(nèi)存,內(nèi)存中只剩下用于存放目標(biāo)程序的CODE數(shù)組和運行時的數(shù)據(jù)區(qū)S。S是由解釋程序定義的一維整型數(shù)組。解釋執(zhí)行時的數(shù)據(jù)空間S為棧式計算機(jī)的存儲空間。遵循后進(jìn)先出的規(guī)則,對每個過程(包括主程序)當(dāng)被調(diào)用時,才分配數(shù)據(jù)空間,退出過程時,則所分配的數(shù)據(jù)空間被釋放。為解釋程序定義四個寄存器:I:指令寄存器,存放當(dāng)前正在解釋的一條目標(biāo)指令。P:程序地址寄存器,指向下一條要執(zhí)行的目標(biāo)指令(相當(dāng)于CODE數(shù)組的下標(biāo))。T:棧頂寄存器,每個過程運行時要為它分配數(shù)據(jù)區(qū)(或稱為數(shù)據(jù)段),該數(shù)據(jù)區(qū)分為兩部分。靜態(tài)部分:包括變量存放區(qū)和三個聯(lián)單元。動態(tài)部分:作為臨時工作單元和累加器用。需要時臨時分配,用完立即釋放。棧頂寄存器T指出了當(dāng)前棧中最新分配的單元(T也是數(shù)組S的下標(biāo))。B:基地址寄存器,指出每個過程被調(diào)用時,在數(shù)據(jù)區(qū)S中給出它分配的數(shù)據(jù)段起始地址,也稱為基地址。每個過程被調(diào)用時,在棧頂分配三個聯(lián)系單元。這三個單元的內(nèi)容分別是:SL:靜態(tài)鏈,它是指向定義該過程的直接外過程運行時數(shù)據(jù)段的基地址。DL:動態(tài)鏈,它是指向調(diào)用該過程前正在運行過程的數(shù)據(jù)段的基地址。RA:返回地址,記錄調(diào)用該過程時目標(biāo)程序的斷點,即當(dāng)時的程序地址寄存器P的值。具體的過程調(diào)用和結(jié)束,對上述寄存器及三個聯(lián)系單元的填寫和恢復(fù)由下列目標(biāo)指令完成。INT0aa:為局部量個數(shù)加3OPR00恢復(fù)調(diào)用該過程前正在運行過程(或主程序)的數(shù)據(jù)段的基地址寄存器的值,恢復(fù)棧頂寄存器T的值,并將返回地址送到指令寄存器P中。CALlaa為被調(diào)用過程的目標(biāo)程序的入口,送入指令地址寄存器P中。CAL指令還完成填寫靜態(tài)鏈,動態(tài)鏈,返回地址,給出被調(diào)用過程的基地址值,送入基址寄存器B中。部分源代碼如下:packagepl0;importjava.util.Vector;publicclassgenerate{ publicwordanalysisCiFa; publicwordword; publicStringid=null;//用于登錄名字表時的word名字 publicintlineNum;//用于錯誤處理時的行數(shù)記錄 publicinterrorNumber=0;//用于保存語法分析中的錯誤數(shù)目 publicErrorerror=newError(); intcx;//VectorCode'ssize intcx0;//VectorCode'ssize,保存當(dāng)前代碼的地址 intdx;//給出每層的局部量的相對地址 intlev=-1;//記錄層次 interrorNum=0; VectorCODE=newVector();;//生成一個vector矢量!//此矢量用作存放CodeElement的數(shù)組 VectorTABLE=newVector();//生成一個存放矢量作為名字表; publicgenerate(wordanalysisCF)//語法分析構(gòu)造函數(shù) { CiFa=CF;//從主程序傳入一個詞法分析對象,將其賦給CiFa word=CiFa.GetWord();//獲得一個word analyse();//然后調(diào)用分析程序 } publicintgetErroNumber() { returnerrorNumber; } publicvoidprintTable()//用來查看符號表內(nèi)容的 { for(intt=1;t<TABLE.size();t++) { tabname=(tab)TABLE.get(t); if(name.kind.equals("constant")) name.showConst(); elseif(name.kind.equals("variable")) name.show(); elseif(name.kind.equals("procedure")) { //???t++ t++; tabtempname=(tab)TABLE.get(t);//此時的name.adr為0 name.adr=tempname.adr;//??? name.show();//System.out.println("tempname:");// tempname.show(); } } } publicvoidprintTable(inti)//用來查看符號表內(nèi)容的 { intt=i; tabname=(tab)TABLE.get(t); if(name.kind.equals("constant")) name.showConst(); elseif(name.kind.equals("variable")) name.show(); elseif(name.kind.equals("procedure")) { //???t++ t++; tabtempname=(tab)TABLE.get(t);//此時的name.adr為0 name.adr=tempname.adr;//??? name.show();//System.out.println("tempname:");// tempname.show(); } } publicvoidprintCode()//CodeElement的顯示方法,如果沒有錯誤,則打印CodeElement代碼 { for(intk=1;k<CODE.size();k++) { Codecode=(Code)CODE.get(k); code.print(k);// System.out.println(n+"\t"+code.getF()+"\t"+code.getL()// +"\t"+code.getA());// Codecode=(Code)CODE.get(n);// System.out.println(n+"\t"+code.getF()+"\t"+code.getL()// +"\t"+code.getA()); } } publicvoidprintCode(inti)//CodeElement的顯示方法,如果沒有錯誤,則打印CodeElement代碼 { intk=i; Codecode=(Code)CODE.get(k); code.print(k);// System.out.println(n+"\t"+code.getF()+"\t"+code.getL()// +"\t"+code.getA());// Codecode=(Code)CODE.get(n);// System.out.println(n+"\t"+code.getF()+"\t"+code.getL()// +"\t"+code.getA()); } /** *語法分析 *調(diào)用常量聲明、變量聲明、過程聲明 *遞歸調(diào)用analyse */ publicvoidanalyse() { inttx0; lev++; dx=3;//初始ADR,以后每遇到一個變量,dx+1 tx0=TABLE.size();//用tx0保存當(dāng)前層的符號在符號表中的起始位置 TABLE.addElement(newtab("","",0,0,0));//在這里給符號表填加一個元素,否則下一條代碼會運行出界 ((tab)TABLE.get(tx0)).setAdr(CODE.size());//在上面加的那個元素里的私有字段adr里保存當(dāng)前層代碼的開始位置 CODE.addElement(newCode("jmp",0,0));//生成跳轉(zhuǎn)指令由于跳轉(zhuǎn)位置未知暫時添0System.out.println("1:"+CODE.size()); while(word.getSym().equals("constsym") ||word.getSym().equals("varsym") ||word.getSym().equals("procsym")) { if(word.getSym().equals("constsym"))//常量處理 { word=CiFa.GetWord(); constDefine();//調(diào)用常量聲明,注意常量聲明完畢時還要再次讀取一個word //若在常量聲明后讀取的word為逗號,則要繼續(xù)進(jìn)行常量聲明,這里采用while循環(huán),直到word不是逗號 while(word.getSym().equals(",sym")) { word=CiFa.GetWord(); constDefine();//調(diào)用常量聲明,注意常量聲明完畢時還要再次讀取一個word } if(word.getSym().equals(";sym"))//若word不是逗號,則應(yīng)該是分號了,標(biāo)志常量聲明結(jié)束 { word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),5);//如果常量聲明完畢后沒有遇到分號;則拋出15號錯誤 } } //變量處理 elseif(word.getSym().equals("varsym")) { word=CiFa.GetWord();//讀取一個word,應(yīng)該是一個ident標(biāo)識符 varDefine();//調(diào)用變量聲明 while(word.getSym().equals(",sym")) { word=CiFa.GetWord(); varDefine();//調(diào)用變量聲明,注意常量聲明完畢時還要再次讀取一個word } if(word.getSym().equals(";sym")) { word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),5);//如果變量聲明完畢后沒有遇到分號;則調(diào)用錯誤處理程序拋出5號錯誤 } } //循環(huán)聲明各個子過程 //這里為什么要用while???改成if語句結(jié)果也正確,主要是例子里面沒有嵌套的過程吧。 while(word.getSym().equals("procsym")) { word=CiFa.GetWord(); if(word.getSym().equals("ident")) { id=word.getName(); add("procedure",id); word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),4);//過程名不是標(biāo)識符,拋出4號錯誤 } if(word.getSym().equals(";sym")) { word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),5); }//過程名后沒有分號 //保存當(dāng)前的ADE和lev inttempdx=dx; intlevv=lev; //在這里遞歸調(diào)用下一層的分程序段分析,接下來如果不是常量、變量、過程聲明, //那么就直接跳過analyse開始的while循環(huán),開始進(jìn)行語句的分析了 analyse(); dx=tempdx; lev=levv; if(word.getSym().equals(";sym")) { word=CiFa.GetWord(); //若end;后的符號不在ident,procsym,begin,call,if,while中,則調(diào)用6號錯誤 Stringsym=word.getSym(); if(!(sym.equals("ident")||sym.equals("procsym") ||sym.equals("beginsym")||sym.equals("callsym") ||sym.equals("ifsym")||sym.equals("whilesym"))) { errorNumber++; error.error(word.getLineNum(),6); } }else { errorNumber++; error.error(word.getLineNum(),5); } } }//???下面又不懂了?。。?! //把前面生成的跳轉(zhuǎn)指令的跳轉(zhuǎn)位置改成當(dāng)前位置System.out.println(CODE.size());printCode(CODE.size()-1); ((Code)CODE.get(((tab)TABLE.get(tx0)).getAdr())).setA(CODE.size()); System.out.println("CODE"+((tab)TABLE.get(tx0)).getAdr());printCode(((tab)TABLE.get(tx0)).getAdr()); //在符號表中,對于過程名,adr應(yīng)填入編譯該過程所生成的CodeElement指令序列的入口地址 //目前TABLE.get(tx0))里面還沒有什么內(nèi)容。 ((tab)TABLE.get(tx0)).setAdr(CODE.size());System.out.println("TABLEtx0:"+tx0);printTable(tx0); cx0=CODE.size();//在cx0中保存當(dāng)前代碼的分配地址 CODE.addElement(newCode("int",0,dx));//生成空間分配指令,分配dx個空間(3個空間+變量的數(shù)目) //printCode(cx0-2);//printCode(cx0-1); //printCode(cx0);//??? statement();//處理當(dāng)前遇到的語句; CODE.addElement(newCode("opr",0,0));//生成子程序返回指令; } /** *常量聲明 * */ publicvoidconstDefine()//常量聲明的方法 { if(word.getSym().equals("ident"))//在analyse調(diào)用常量聲明時,上一個word為const,這一個應(yīng)該是ident標(biāo)識符 { id=word.getName();//調(diào)用Word類的getNam方法,獲得當(dāng)前word的內(nèi)容,這里將其保存在id中,為的是一會進(jìn)行的符號表插入工作 word=CiFa.GetWord();//然后再讀取一個word,應(yīng)該是等號"="了 if(word.getSym().equals(":=sym")) { errorNumber++; error.error(word.getLineNum(),1);//如果不是等號,而是賦值符號:=,拋出1號錯誤 }elseif(word.getSym().equals("=sym")) { word=CiFa.GetWord();//繼續(xù)讀取一個word,現(xiàn)在應(yīng)該是一個數(shù)字了 if(word.getSym().equals("number")) { add("constant",id);//如果當(dāng)前word是數(shù)字,則調(diào)用符號表插入方法,將常量插入符號表; word=CiFa.GetWord();//再次讀取一個word,為后邊做準(zhǔn)備,應(yīng)該是一個逗號或者是分號 }else //如果等號后不是數(shù)字,調(diào)用2號錯誤 { errorNumber++; error.error(word.getLineNum(),2); } }else //如果標(biāo)識符后不是等號,調(diào)用3號錯誤 { errorNumber++; error.error(word.getLineNum(),3); } }else //如果常量聲明過程中遇到的第一個字符不是標(biāo)識符,調(diào)用4號錯誤 { errorNumber++; error.error(word.getLineNum(),4); } } /** *變量聲明 */ publicvoidvarDefine()//變量聲明的方法 { if(word.getSym().equals("ident")) { id=word.getName(); add("variable",id);//調(diào)用符號表注冊方法進(jìn)行變量的注冊 word=CiFa.GetWord(); }else //如果變量聲明過程中遇到的第一個字符不是標(biāo)識符,調(diào)用4號錯誤 { errorNumber++; error.error(word.getLineNum(),4); } } /** *向Table表中增加變量 *@paramk *@paramname */ publicvoidadd(Stringk,Stringname)//Table表中添加變量 {//k中保存的是傳過來的string if(k.equals("constant")) {//如果是常量,則要判斷此常量的賦值是否大于整數(shù)的最大允許值2047 intnum=Integer.parseInt(word.getName()); if(num>2047) {// TABLE.addElement(newtab(id,k,0,0,0)); TABLE.addElement(newtab(name,k,0,0,0)); error.error(word.getLineNum(),31);//若整數(shù)越界,拋出31號錯誤,并將其賦為0,繼續(xù)進(jìn)行分析 System.out.println("整數(shù)越界"); }else{ //若整數(shù)沒有越界,則給TABLE增加一個TableElement對象// TABLE.addElement(newtab(id,k,num,0,0)); TABLE.addElement(newtab(name,k,num,0,0)); } }elseif(k.equals("variable")) {// TABLE.addElement(newtab(id,k,0,lev,dx)); TABLE.addElement(newtab(name,k,0,lev,dx)); dx=dx+1; }elseif(k.equals("procedure")) {// TABLE.addElement(newtab(id,k,0,lev,0)); TABLE.addElement(newtab(name,k,0,lev,0)); } }//符號表注冊完成 /** *在TABLE中查找標(biāo)識符名字 */ publicintsearch(Stringid)//查找名字表 { inti=0; while(i<TABLE.size() &&(!((tab)TABLE.get(i)).getName().equals(id))) { i++; } if(i>=TABLE.size()) { return-1; }//如果沒有找到,則返回負(fù)值 else { returni; } } /** *處理當(dāng)前遇到的語句 *賦值語句、call語句、條件語句、begin、while、read、write *賦值語句:調(diào)用expression *if語句:調(diào)用condition、statement *begin:調(diào)用statement *while:調(diào)用condition、statement *write:調(diào)用expression * */ publicvoidstatement() { inti; intcx1; intcx2; //所謂語句可能是賦值語句,以標(biāo)識符開頭; if(word.getSym().equals("ident")) { i=search(word.getName());//在符號表中找到該標(biāo)識符所在位置; if(i==-1)//如果返回的i為負(fù)值,則表示沒有找到;拋出11號錯誤 { errorNumber++; error.error(word.getLineNum(),11); } elseif(!((tab)TABLE.get(i)).getKind().equals("variable")) { //如果在符號表中找到了,但是該標(biāo)識符不是變量名,則拋出12號錯誤 errorNumber++; error.error(word.getLineNum(),12); i=-1;//并將i置為-1做為錯誤的標(biāo)志; } word=CiFa.GetWord();//繼續(xù)讀取下一個word,正常應(yīng)該是賦值符號 if(word.getSym().equals(":=sym")) { word=CiFa.GetWord();//如果是賦值符號,則繼續(xù)讀取一個word,正常應(yīng)該是一個表達(dá)式; }else { errorNumber++; error.error(word.getLineNum(),13);//如果不是賦值符號,則拋出13號錯誤 } expression();//進(jìn)行表達(dá)式的處理; //如果i不是負(fù)值,則表示未曾出錯,i所表示的是當(dāng)前語句左邊標(biāo)識符在符號表中的位置; if(i!=-1) {//生成一條把表達(dá)式的值寫往指定內(nèi)存的代碼; CODE.addElement(newCode("sto",lev-((tab)TABLE.get(i)).getLev(), ((tab)TABLE.get(i)).getAdr())); } } //如果遇到了call語句 elseif(word.getSym().equals("callsym")) { word=CiFa.GetWord();//讀取一個word,正常應(yīng)該是一個過程名型的標(biāo)識符 if(!word.getSym().equals("ident"))//如果不是標(biāo)識符,拋出14號錯誤 { errorNumber++; error.error(word.getLineNum(),14); }else { i=search(word.getName());//查找符號表 //如果沒有找到,拋出11號錯誤 if(i==-1) { errorNumber++; error.error(word.getLineNum(),11); } elseif(((tab)TABLE.get(i)).getKind().equals( "procedure")) {//生成call指令,call這個過程 CODE.addElement(newCode("cal",lev-((tab)TABLE.get(i)).getLev(), ((tab)TABLE.get(i+1)).getAdr())); //為什么是get(i+1).getAdr()??? }else { errorNumber++; error.error(word.getLineNum(),15); }//如果找到的不是過程名,拋出15號錯誤 word=CiFa.GetWord(); } } //如果是if語句 elseif(word.getSym().equals("ifsym")) { word=CiFa.GetWord();//if后正常是條件,所以執(zhí)行condition函數(shù) condition(); if(word.getSym().equals("thensym")) { word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),16); }//如果if后不是then則拋出16號錯誤! cx=CODE.size(); cx1=cx; CODE.addElement(newCode("jpc",0,0)); //if后需要繼續(xù)判斷后邊的語句,即Then后面的語句 statement(); ((Code)CODE.get(cx1)).setA(CODE.size()); } elseif(word.getSym().equals("beginsym")) { word=CiFa.GetWord(); statement(); //begin后需要繼續(xù)判斷后邊的語句 while(word.getSym().equals(";sym") ||word.getSym().equals("beginsym") ||word.getSym().equals("callsym") ||word.getSym().equals("ifsym") ||word.getSym().equals("whilesym")) { if(word.getSym().equals(";sym")) { word=CiFa.GetWord(); }//為什么其它的就是出錯??? else { errorNumber++; error.error(word.getLineNum(),10); } statement(); } if(word.getSym().equals("endsym")) { word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),17); } } elseif(word.getSym().equals("whilesym")) { cx=CODE.size(); cx1=cx;//記錄當(dāng)前代碼分配位置,這是while循環(huán)的開始位置 word=CiFa.GetWord();//讀取word,應(yīng)該是一個條件表達(dá)式 condition(); //while后邊肯定有條件語句 cx=CODE.size(); cx2=cx;//記錄當(dāng)前代碼位置,這是while循環(huán)的do中的語句的開始位置 CODE.addElement(newCode("jpc",0,0));//生成條件跳轉(zhuǎn)指令,跳轉(zhuǎn)位置暫時填0 if(word.getSym().equals("dosym"))//判斷是否是do,否則拋出18號錯誤 { word=CiFa.GetWord(); }else { errorNumber++; error.error(word.getLineNum(),18); } statement();//開始分析do后的語句塊 //跳轉(zhuǎn)到cx1處,即再次進(jìn)行判斷是否進(jìn)行循環(huán) CODE.addElement(newCode("jmp",0,cx1)); //把剛才跳轉(zhuǎn)暫時填0的位置改成當(dāng)前位置,完成對循環(huán)的處理 //即do之前的跳轉(zhuǎn)到while語句的結(jié)尾 ((Code)CODE.get(cx2)).setA(CODE.size()); } elseif(word.getSym().equals("readsym")) { word=CiFa.GetWord();//如果遇到了“讀”語句塊,則繼續(xù)讀取word,應(yīng)該是左括號 if(word.getSym().equals("(sym")) { word=CiFa.GetWord(); if(word.getSym().equals("ident")) { i=search(word.getName()); if(i==-1) { errorNumber++; error.error(word.getLineNum(),11); }else { CODE.addElement(newCode("opr",0,16));//生成16號讀指令,從鍵盤讀取數(shù)字 CODE.addElement(newCode("sto",lev-((tab)TABLE.get(i)).getLev(), ((tab)TABLE.get(i)).getAdr()));//生成sto指令,存入指定變量 } } word=CiFa.GetWord(); //循環(huán)得到read語句的參數(shù),直到該參數(shù)后不是逗號為止 while(word.getSym().equals(",sym")) { word=CiFa.GetWord(); if(word.getSym().equals("ident")) { i=search(word.getName()); if(i==-1) { errorNumber++; error.error(word.getLineNum(),11); }else { CODE.addElement(newCode("opr",0,16)); //sto將棧頂?shù)膬?nèi)容送到某變量中,即將讀入的數(shù)據(jù)送到對應(yīng)的變量上去。 CODE.addElement(newCode("sto",lev-((tab)TABLE.get(i)).getLev(), ((tab)TABLE.get(i)).getAdr())); } } word=CiFa.GetWord(); } if(!word.getSym().equals(")sym")) { errorNumber++; error.error(word.getLineNum(),9); }//如果不是預(yù)想的右括號,拋出9號錯誤 } //如果不是左括號,拋出0號錯誤 else { errorNumber++; error.error(word.getLineNum(),0); } word=CiFa.GetWord(); } elseif(word.getSym().equals("writesym")) { word=CiFa.GetWord(); if(word.getSym().equals("(sym")) { word=CiFa.GetWord(); expression(); CODE.addElement(newCode("opr",0,14)); while(word.getSym().equals(",sym")) { word=CiFa.GetWord(); expression(); CODE.addElement(newCode("opr",0,14)); } if(!word.getSym().equals(")sym")) { errorNumber++; error.error(word.getLineNum(),9); }else { word=CiFa.GetWord(); } }//??? CODE.addElement(newCode("opr",0,15)); } } /** *處理條件語句 *調(diào)用expression */ publicvoidcondition()//條件語句的處理 { //存儲運算符 Stringrelop=null; if(word.getSym().equals("oddsym"))//如果是一元運算符 { word=CiFa.GetWord(); expression();//對一元運算的表達(dá)式進(jìn)行分析 CODE.addElement(newCode("opr",0,6));//生成奇偶判斷指令 }else //不是一元運算符則是二元運算符 { expression();//對左邊的表達(dá)式進(jìn)行分析 relop=word.getSym();//把二元運算符保存起來 word=CiFa.GetWord(); expression();//對右邊的表達(dá)式進(jìn)行分析然后根據(jù)剛才保存的運算符,生成相應(yīng)判斷指令 if(relop.equals("=sym")) { CODE.addElement(newCode("opr",0,8)); }elseif(relop.equals("#sym")) { CODE.addElement(newCode("opr",0,9)); }elseif(relop.equals("<sym")) { CODE.addElement(newCode("opr",0,10)); }elseif(relop.equals(">=sym")) { CODE.addElement(newCode("opr",0,11)); }elseif(relop.equals(">sym")) { CODE.addElement(newCode("opr",0,12)); }elseif(relop.equals("<=sym")) { CODE.addElement(newCode("opr",0,13)); }else { System.out.println(word.getName()+""+relop); errorNumber++; error.error(word.getLineNum(),20); }//如果剛才保存的不是邏輯運算符,則拋出20號錯誤 } }//條件分析完畢 /** *處理表達(dá)式 *調(diào)用term */ publicvoidexpression()//表達(dá)式的處理 { Stringaddop=null;//保存表達(dá)式開頭的符號用于表示正負(fù) if(word.getSym().equals("+sym")||word.getSym().equals("-sym")) { //把正負(fù)號保存在string類型的addop中,繼續(xù)讀取一個word,正常應(yīng)該為表達(dá)式的一個項 addop=word.getSym(); word=CiFa.GetWord(); term();//進(jìn)行項的分析 if(addop.equals("-sym"))//如果保存下來的是個負(fù)號,則生成一條1號指令,取反運算 { CODE.addElement(newCode("opr",0,1)); } }else //如果不是正負(fù)號開頭,就應(yīng)該是一個表達(dá)式的項開頭,直接進(jìn)行項的分析 { term(); } //項后應(yīng)該應(yīng)該是加運算或者減法運算 while(word.getSym().equals("+sym")||word.getSym().equals("-sym")) { addop=word.getSym();//把運算符保存在addop中 word=CiFa.GetWord(); term();//分析項 if(addop.equals("+sym"))//項分析完畢后,如果剛才保存的是加號,則生成加法指令 { CODE.addElement(newCode("opr",0,2)); }else //否則生成減法指令 { CODE.addElement(newCode("opr",0,3)); } } }//表達(dá)式分析完畢 /** *項的處理(乘法和除法也屬于項) *調(diào)用element */ publicvoidterm() { Stringmulop=null; element();//每個項都是由一個因子開頭,所以直接調(diào)用因子分析方法 while(word.getSym().equals("*sym")||word.getSym().equals("/sym"))//因子后應(yīng)該遇到乘號或是除號 { mulop=word.getSym();//把運算符保存在mulop中(乘法或是除法) word=CiFa.GetWord(); element(); //運算符后應(yīng)該是一個因子,進(jìn)行因子分析 if(mulop.equals("*sym"))//如果剛才保存的運算符為乘號則生成opr4號乘法指令, { CODE.addElement(newCode("opr",0,4)); }else //如果剛才保存的不是乘號,則生成除法運算指令 { CODE.addElement(newCode("opr",0,5)); } } }//項分析完畢 /** *因子的分析處理 */ publicvoidelement()//因子的分析處理; { inti; while(word.getSym().equals("ident")||word.getSym().equals("number") ||word.getSym().equals("(sym"))//循環(huán)處理因子 { if(word.getSym().equals("ident"))//如果遇到的是標(biāo)識符,則查符號表 { i=search(word.getName()); if(i==-1)//如果查符號表后返回負(fù)值,則表示沒有找到,拋出11號錯誤 { errorNumber++; error.error(word.getLineNum(),11); } //如果返回的不是負(fù)值,則表示在符號表中的找到了該標(biāo)識符,getKind返回該標(biāo)識符的類型 elseif(((tab)TABLE.get(i)).getKind().equals( "constant")) //如果該標(biāo)識符為常量,則生成lit指令,把val放到棧頂 { //4lit010是在這里產(chǎn)生的。為什么??? CODE.addElement(newCode("lit",0, ((tab)TABLE.get(i)).getVal()));System.out.println("aaa"+

溫馨提示

  • 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論