h5 網(wǎng)站建設(shè)網(wǎng)絡(luò)營銷活動方案
文章目錄
- 一、 設(shè)計(jì)目的及要求
- 1.1 設(shè)計(jì)目的
- 1.2 設(shè)計(jì)要求
- 1.2.1 要求一
- 1.2.2 要求二
- 1.2.3 要求三
- 二、程序設(shè)計(jì)
- 2.1 程序的組織結(jié)構(gòu)
- 2.1.1 PL/0編譯程序函數(shù)定義層次結(jié)構(gòu)
- 2.1.2 PL/0編譯程序函數(shù)過程或函數(shù)功能表
- 2.1.3 PL/0指令功能表
- 2.1.4 PL/0語言的出錯信息表
- 2.2程序流程圖
- 2.2.1 PL/0編譯程序和解釋執(zhí)行過程
- 2.2.2 PL/0程序語法分析
- 2.2.3 else語句流程圖
- 2.2.4 do-while-until語句流程圖
- 2.2.5 for語句流程圖
- 2.3 目標(biāo)代碼生成模式
- 2.3.1 if-then-else
- 2.3.2 do while-until
- 2.3.3 for-to/downto-do
- 三、系統(tǒng)實(shí)現(xiàn)
- 3.1 else語句擴(kuò)充
- 3.2 do-while-until語句擴(kuò)充
- 3.3 for語句擴(kuò)充
- 3.3.1 downto-do-end
- 3.3.2 to-do-end
- 四、程序源代碼
- 4.1 else語句擴(kuò)充
- 4.2 do-while- until語句擴(kuò)充
- 4.3 for語句擴(kuò)充
- 4.3.1 “變量=初值”部分代碼
- 4.3.2 “downto-do-end”部分代碼
- 4.3.3 “to-do-end”部分代碼
- 五、系統(tǒng)測試
- 5.1 else語句擴(kuò)充
- 5.2 do-while-until語句擴(kuò)充
- 5.3 for語句擴(kuò)充
- 六、設(shè)計(jì)總結(jié)
- 七、致謝
- 源碼與測試用例下載
一、 設(shè)計(jì)目的及要求
1.1 設(shè)計(jì)目的
根據(jù)所學(xué)的編譯原理理論知識,在符合 PL/0 語言基本詞法、語法規(guī)則的前提下,以原PL/0 編譯程序C語言版本代碼為基礎(chǔ),對 PL/0 語言的功能進(jìn)行擴(kuò)充。使理論與實(shí)踐相結(jié)合,加深對編譯原理的理解。
1.2 設(shè)計(jì)要求
1.2.1 要求一
1)擴(kuò)充語言成份:“if 條件 then 語句系列1 else 語句系列2”。
2)寫出相應(yīng)的編譯程序。
1.2.2 要求二
1)擴(kuò)充語言成份:“do while 語句系列 until 條件”,即循環(huán)執(zhí)行循環(huán)體內(nèi)的語句系列,直到條件為真為止。
2)寫出相應(yīng)的編譯程序
1.2.3 要求三
1)擴(kuò)充語言成份:
①“for 變量= 初值 to 終值 do begin 語句系列 end”
②“for 變量= 初值 downto 終值 do begin 語句系列 end”
其中,語句①中循環(huán)變量的步長為1,語句②中循環(huán)變量的步長為-1。
2)寫出相應(yīng)的編譯程序
二、程序設(shè)計(jì)
2.1 程序的組織結(jié)構(gòu)
2.1.1 PL/0編譯程序函數(shù)定義層次結(jié)構(gòu)
表1 層次結(jié)構(gòu)圖
2.1.2 PL/0編譯程序函數(shù)過程或函數(shù)功能表
表 2函數(shù)功能表
2.1.3 PL/0指令功能表
表 3指令功能表
2.1.4 PL/0語言的出錯信息表
表 4 出錯信息表
2.2程序流程圖
2.2.1 PL/0編譯程序和解釋執(zhí)行過程
圖 1 解釋執(zhí)行過程
2.2.2 PL/0程序語法分析
圖 2 語法分析流程圖
2.2.3 else語句流程圖
圖 3 else語句流程
表 5 else語句四元式序列
2.2.4 do-while-until語句流程圖
圖 4 do-while-until 語句流程
表 6 do-while-until 語句四元式序列
2.2.5 for語句流程圖
圖 5 for語句流程
表 7 for語句四元式序列
2.3 目標(biāo)代碼生成模式
2.3.1 if-then-else
2.3.2 do while-until
2.3.3 for-to/downto-do
三、系統(tǒng)實(shí)現(xiàn)
3.1 else語句擴(kuò)充
本部分程序首先判斷then語句塊的最后一個單詞是否為“;”。如果then最后一個字符是“;”,則需要跳過該符號之后再執(zhí)行else及之后的語句。接下來的符號是else時,先記錄當(dāng)前jmp指令的位置,并為jpc指令賦值,使if為false時能直接跳轉(zhuǎn)到else語句之后進(jìn)行代碼執(zhí)行,然后調(diào)用函數(shù)處理else之后的語句,最后為jmp指令賦值,使if執(zhí)行結(jié)束時能直接跳轉(zhuǎn)到if-else結(jié)束位置。
圖 6 else語句執(zhí)行流程和代碼結(jié)構(gòu)
3.2 do-while-until語句擴(kuò)充
本部分程序首先判斷當(dāng)前符號是否為do,然后讀取下一個字符并判斷是否為while。接著記錄當(dāng)前位置,此時為while循環(huán)體開始位置。接下來,允許while后能接的字符為until,然后執(zhí)行while循環(huán)體內(nèi)的語句。接著判斷while的最后一個字符是否是“;”,是,則跳過該符號執(zhí)行until及之后的語句。當(dāng)下一個符號是until時,執(zhí)行判斷語句。當(dāng)判斷條件為false時,執(zhí)行條件跳轉(zhuǎn),跳轉(zhuǎn)到while循環(huán)體的開始位置繼續(xù)運(yùn)行。
圖 7 do-while-until執(zhí)行流程和代碼結(jié)構(gòu)
3.3 for語句擴(kuò)充
首先識別當(dāng)前符號為for,然后執(zhí)行變量定位與賦值語句。
3.3.1 downto-do-end
識別當(dāng)前符號為downto,記錄當(dāng)前位置,即判斷當(dāng)前變量與終值大小關(guān)系的位置。將循環(huán)判斷變量取出并放到棧頂后,判斷循環(huán)變量條件并生成比較指令,判斷此戰(zhàn)頂是否大于等于棧頂,往后退兩個棧元素,結(jié)果值進(jìn)棧。再次記錄當(dāng)前位置,即do循環(huán)開始的位置。識別當(dāng)前符號是否為do,并在成立的情況下運(yùn)行do內(nèi)循環(huán)體。然后將循環(huán)變量取出放到棧頂,再將步長1取出放到棧頂,執(zhí)行指令,次棧頂減去棧頂,退兩個棧元素,結(jié)果值進(jìn)棧,最后將棧頂?shù)闹荡嫒胙h(huán)變量。這就完成了變量的自減。然后執(zhí)行無條件跳轉(zhuǎn)語句,跳轉(zhuǎn)到比較變量與終值大小關(guān)系的位置。最后地址回填,將jpc的目的地址賦值為do執(zhí)行完后的位置,即當(dāng)次棧頂小于棧頂時,結(jié)束for循環(huán)語句。
圖 8 do-while-until語句執(zhí)行流程和代碼結(jié)構(gòu)
3.3.2 to-do-end
與上述downto-do-end基本邏輯一致,只是將判斷的大于等于改為了小于等于,將變量的自減改為了自增。
圖 9 for語句執(zhí)行流程和代碼流程
四、程序源代碼
4.1 else語句擴(kuò)充
解決對編譯程序if-else的擴(kuò)展,補(bǔ)充了代碼中缺失的else語句塊
//添加處理else語句
cx2=cx; /*記錄jmp指令的位置,執(zhí)行完then語句后需要無條件轉(zhuǎn)移,出發(fā)地址為cx2 */
gendo(jmp,0,0); /*執(zhí)行完if為真后,無條件轉(zhuǎn)移,將來會直接跳轉(zhuǎn)到else后 */
bool isSemi=false; //分號;跳過
code[cx1]a = cx; /* 經(jīng)statement處理后,cx為else語句執(zhí)行開始的位置,它正是前面未定的跳轉(zhuǎn)地址 (回填cx1的地址,即if執(zhí)行為假) 為jpc指令賦值 */
if(sym==semicolon) //如果then語句塊的最后一個單詞為“;”,則跳過{getsymdo; //取下一個單詞 isSemi=true; //有";" }//接下來的符號是else
if(sym==elsesym) //若為else,執(zhí)行其中的語句{getsymdo;statementdo(fsys,ptx,lev); //處理else后的語句 code[cx2]a=cx; /*當(dāng)前是else后語句的結(jié)束位置,判斷正式結(jié)束,回填if執(zhí)行結(jié)束時的地址,為jmp指令賦值,if語句執(zhí)行后應(yīng)跳轉(zhuǎn)至此*/
}
//上述為添加的else語句處理過程
4.2 do-while- until語句擴(kuò)充
解決了do while until 語句的擴(kuò)充,在程序中添加了do while until語句塊。
//添加do while until 語句
if (sym == dosym) //此時識別的符號是do
{getsymdo;if (sym == whilesym) //do while 語句 {cx1 = cx; //記錄當(dāng)前的位置,即while循環(huán)體開始位置 getsymdo;memcpy(nxtlev, fsys, sizeof(bool)* symnum);nxtlev[untilsym] = true; //后跟符號為until statementdo(fsys, ptx, lev); //執(zhí)行while循環(huán)體 if (sym == semicolon) //分號,跳過 {getsymdo;}if (sym == untilsym) //為until 執(zhí)行條件語句 {getsymdo;conditiondo(nxtlev, ptx, lev); //執(zhí)行條件判斷 gendo(jpc, 0, cx1); //條件跳轉(zhuǎn),為flase是跳轉(zhuǎn)到while循環(huán)體內(nèi) }}
//以上為添加的do while until 語句
4.3 for語句擴(kuò)充
解決對編譯程序for語句的擴(kuò)展,補(bǔ)充了for-to和for-downto語句塊
4.3.1 “變量=初值”部分代碼
找到變量位置并為變量賦初值
if(sym==forsym) //準(zhǔn)備按照for語句處理
{getsymdo;if(sym==ident) //準(zhǔn)備按照賦值語句處理 {i=position(id,*ptx);if(i==0){error(11); //變量未找到 }else{if(table[i]kind!=variable){error(12); //賦值語句格式錯誤i=0; }else{getsymdo;if(sym==becomes) //變量賦初始值{getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[tosym]=true;nxtlev[downtosym]=true;nxtlev[dosym]=true;expressiondo(nxtlev,ptx,lev);}else{error(13); //沒有檢測到賦值符號 }if(i!=0){gen(sto,lev-table[i]level,table[i]adr);}
4.3.2 “downto-do-end”部分代碼
if(sym==downtosym)
{cx1=cx; //記錄當(dāng)前位置,即downto后開始判斷當(dāng)前變量與終值大小關(guān)系的位置 getsymdo; gendo(lod,lev-table[i]level,table[i]adr); //將循環(huán)判斷變量取出放到棧頂 nxtlev[beginsym]=true; //接下來識別的符號為begin expressiondo(nxtlev,ptx,lev); //判斷循環(huán)變量條件 gen(opr,0,11); //生成比較指令 次棧頂是否大于等于棧頂,退兩個棧元素,結(jié)果值進(jìn)棧 cx2=cx; //記錄循環(huán)開始地址gen(jpc,0,0); //條件跳轉(zhuǎn),暫時未知目的地址 ,用0代替 if(sym==dosym){getsymdo ;statementdo ( fsys, ptx, lev) ; //運(yùn)行do內(nèi)代碼 gen (lod, lev - table [i] level, table[i]adr); //將循環(huán)變量取出放在棧頂 gen (lit, 0, 1); //常數(shù)1添加到棧頂 即將步長取到棧頂 gen (opr, 0, 3); //循環(huán)變量減少1 次棧頂減去棧頂,退兩個棧元素,結(jié)果值進(jìn)棧gendo (sto, lev - table[i] level, table[i]adr); //將棧頂?shù)闹荡嫒胙h(huán)變量 gendo(jmp , 0, cx1); //無條件跳轉(zhuǎn),到判斷變量與終值大小關(guān)系的位置 code[cx2]a=cx; /*地址回填, jpc的目的地址時do執(zhí)行完后的位置
即當(dāng)次棧頂小于棧頂時,結(jié)束for循環(huán)語句*/ } else{error(18);}
}
4.3.3 “to-do-end”部分代碼
if(sym==tosym)
{cx1=cx; //記錄比較地址getsymdo;gendo(lod,lev-table[i]level,table[i]adr); memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[beginsym]=true;expressiondo(nxtlev,ptx,lev); //處理循環(huán)邊界表達(dá)式gen(opr,0,13); //生成條件比較表達(dá)式cx2=cx; //記錄條件跳轉(zhuǎn)地址gen(jpc,0,0);if(sym==dosym){getsymdo;statementdo(nxtlev,ptx,lev);gen(lod,lev-table[i]level,table[i]adr); //變量提到棧頂gen(lit,0,1); //常數(shù)1加到棧頂gen(opr,0,2); //循環(huán)變量增加到1gendo(sto,lev-table[i]level,table[i]adr); //賦值gen(jmp,0,cx1); //回條件判斷code[cx2]a=cx; //跳出循環(huán) } else{error(18); /* 缺少do */}
}
五、系統(tǒng)測試
5.1 else語句擴(kuò)充
5.2 do-while-until語句擴(kuò)充
5.3 for語句擴(kuò)充
六、設(shè)計(jì)總結(jié)
經(jīng)歷了長達(dá)一周的課程設(shè)計(jì)工作,我們小組終于完成了本次課程設(shè)計(jì)的代碼編寫及論文編撰任務(wù)。我們在確認(rèn)合作意向之后,很快就確定下來了各自的任務(wù)分工,在獨(dú)立完成各自任務(wù)的同時,我們也常常合作工作,指出對方的不足并解決,對方的一些問題很慶幸能與默契地搭檔一起進(jìn)行本次課程設(shè)計(jì)。
在課程設(shè)計(jì)的過程中,我們首先遇到的問題是龐大源代碼的閱讀,我們需要先初步閱讀并理解老師給出的基礎(chǔ)代碼之后,再在此基礎(chǔ)上進(jìn)行代碼的擴(kuò)充,基礎(chǔ)代碼的行數(shù)已經(jīng)多達(dá)上千行,我們采取分工的方式,一人讀懂一部分函數(shù)的功能,然后再以口述的方式給對方講解,節(jié)省理解代碼的時間。
接下來,我們先進(jìn)行的是if-else語句的擴(kuò)充這一部分的難點(diǎn)是理清jpc和jmp的跳轉(zhuǎn)以及地址的回填如何進(jìn)行。我們根據(jù)老師給出的指導(dǎo),仔細(xì)分析了代碼執(zhí)行流程和結(jié)構(gòu),確定了jpc和jmp的地址并根據(jù)網(wǎng)上查找到的資料,確定了地址回填的編寫方式在編寫過程中,我們起初將cx2=cx語句寫在了if(sym=elsesym)語句內(nèi)部,后來檢查的時候,我們經(jīng)過討論,認(rèn)為應(yīng)該放到if前,因?yàn)閠hen的語句執(zhí)行完之后即可跳轉(zhuǎn)到else語句末尾,而不必先識別else再跳轉(zhuǎn)。最后,我們還是放在了外部,因?yàn)槿绻旁谕獠?#xff0c;在編譯時無需再編譯else語句,能節(jié)省時間
dowhile語句的擴(kuò)充因?yàn)橛衑lse的語句擴(kuò)充作為基礎(chǔ),寫代碼并不困難,基本的邏輯思路是一致的,但是我們犯了一個邏輯上的錯誤,我們把題目的do-while-until理解成了do-while的結(jié)構(gòu),導(dǎo)致地址的跳轉(zhuǎn)邏輯錯誤。
for語句的難點(diǎn)是變量和終值大小的比較如何實(shí)現(xiàn),以及變量的自增與自減如何實(shí)現(xiàn)我們首先確定了for語句的代碼大致執(zhí)行順序與結(jié)構(gòu),但是接著的代碼編寫部分有些無從下筆我們決定先整理出函數(shù)表以及指令功能表,以便接下來的編寫能更清晰地調(diào)用相關(guān)函數(shù)實(shí)現(xiàn)目標(biāo)功能。for后的“變量=初值”部分的代碼直接使用的base代碼中已給出的賦值代碼,并未做修改。變量與終值的比較及變量的自增自減,我們在查找了相關(guān)的資料之后,才確定了gen的函數(shù)調(diào)用方式。
通過本次課設(shè),我們進(jìn)一步鞏固了編譯原理的理論知識,在課設(shè)過程中以實(shí)踐的方式,進(jìn)一步加深了對相關(guān)知識的理解與應(yīng)用。
七、致謝
在本次課程設(shè)計(jì)中,首先我們由衷地感謝臺安老師對于編譯原理課程的教授與指導(dǎo)。從課程設(shè)計(jì)正式開始到后期的完成,都離不開臺老師的悉心指導(dǎo)。臺老師嚴(yán)謹(jǐn)求時的治學(xué)態(tài)度,踏實(shí)堅(jiān)韌的工作精神,平易近人的待人方式給我們許多啟發(fā)和幫助。也正是因?yàn)槔蠋煹恼J(rèn)真負(fù)責(zé),為我們編譯原理的課設(shè)奠定了堅(jiān)實(shí)的理論基礎(chǔ)。在此,我們再次向臺老師致以誠摯的謝意和崇高的敬意。
其次,在本次課設(shè)中還要感謝我親愛的搭檔,我們兩個人分工明確,在確定了思路后就立刻開始完成自己的部分,在不理解的地方一起進(jìn)行討論,最終在規(guī)定的時間內(nèi)完成。
最后再次感謝所有在本次課程設(shè)計(jì)中幫助過我們的老師和同學(xué)們!
源碼與測試用例下載
https://download.csdn.net/download/weixin_47500703/85901408