第一篇:編譯原理課程報(bào)告(共)
編譯原理課程報(bào)告
學(xué)院: 信息工程學(xué)院專業(yè): 軟件工程 姓名: 賴杰學(xué)號: 09927212 指導(dǎo)老師: 朱文華完成時(shí)間: 2012.5.19
編譯原理是計(jì)算機(jī)專業(yè)的一門重要專業(yè)課,旨在介紹編譯程序構(gòu)造的一般原理和基本方法,在計(jì)算機(jī)本科教學(xué)中占有十分重要的地位。
編譯程序是現(xiàn)代計(jì)算機(jī)系統(tǒng)的基本組成部分之一,而且多數(shù)計(jì)算機(jī)系統(tǒng)都配有不止一個(gè)高級語言的編譯程序,對有些高級語言甚至配置了幾個(gè)不同性能的編譯程序。從功能上講,一個(gè)編譯程序就是一個(gè)語言翻譯程序。語言翻譯程序把一種源語言書寫的程序翻譯成另一種目標(biāo)語言的等價(jià)程序,所以總的說編譯程序是一種翻譯程序,其源程序是高級語言,目標(biāo)語言程序是低級語言。
編譯程序完成從源程序到目標(biāo)程序的翻譯工作,是一個(gè)復(fù)雜的整體的過程。從概念上來講,一個(gè)編譯程序的整個(gè)工作過程是劃分成幾個(gè)階段進(jìn)行的,每個(gè)階段將源程序的一種表示形式轉(zhuǎn)換成另一種表示形式,各個(gè)階段進(jìn)行的操作在邏輯上是緊密連接在一起的。一般一個(gè)編譯過程是詞法分析、語法分析、語義分析、中間代碼生成、代碼優(yōu)化和目標(biāo)代碼生成。
編寫編譯器的原理和技術(shù)具有十分普遍的意義,以至于在每個(gè)計(jì)算機(jī)工作者的職業(yè)生涯中,本書中的原理和技術(shù)都會(huì)反復(fù)用到。在這本書中,向我們介紹了文法的概念,在講詞法分析的章節(jié)中講述了構(gòu)造一個(gè)有窮自動(dòng)機(jī)的方法,以及如何將一個(gè)不確定的有窮自動(dòng)機(jī)轉(zhuǎn)化成確定的有窮自動(dòng)機(jī)和有窮自動(dòng)機(jī)的最小化等方法。
該門課中主要講述的是兩種分析方法,即自上而下分析的方法和自下而上分析的方法。自上而下分析法是從文法的開始符號出發(fā),反復(fù)使用各種產(chǎn)生式,尋找“匹配”于輸入符號串的推導(dǎo)。自下而上的分析方法是從輸入符號串開始,逐步進(jìn)行“歸約”到文法的開始符號。
1.自上而下的分析法主要的就是LL(1)文法,首先要判斷某個(gè)文法是否是
LL(1)文法,如果是就可以按照LL(1)文法分析的方法去判斷某一個(gè)輸入串是否為該文法的句子。LL(1)f分析方法是,首先根據(jù)判斷是否為LL(1)文法求出每一個(gè)非終結(jié)符的SELECTE集合來構(gòu)造該文法的預(yù)測分析表,然后根據(jù)預(yù)測分析表去分析輸入串得出結(jié)果;如果不是LL(1)文法,比如說文法產(chǎn)生式中含有左遞歸和相同的因子,就要消去左遞歸或公共因子,再根據(jù)每一個(gè)非終結(jié)符的SELECT集合來判斷是否為LL(1)文法。利用LL(1)文法分析一個(gè)輸入串是不是某一個(gè)文法的句子,根據(jù)預(yù)測分析表是比較直觀的,而且分析的效率也是比較高的。
2.自下而上的分析方法主要是算符優(yōu)先分析方法。算符優(yōu)先分析的基本思
想是只規(guī)定算符之間的優(yōu)先關(guān)系,也就是只考慮終結(jié)符之間的優(yōu)先關(guān)系,由于算符優(yōu)先分析不考慮非終結(jié)符之間的優(yōu)先關(guān)系,在歸約的過程中只要找到可歸約串就歸約,沒有考慮非終結(jié)符之間的優(yōu)先關(guān)系,所以說算符優(yōu)先歸約不是規(guī)范規(guī)約。算符優(yōu)先分析首先是要構(gòu)造算符
優(yōu)先關(guān)系矩陣;然后就是分析輸入串,根據(jù)關(guān)系矩陣進(jìn)行移進(jìn)或歸約操作;最后分析得出判斷的結(jié)果。
3.算符優(yōu)先分析是有缺點(diǎn)的,由于算符優(yōu)先分析方法在分析的過程中不知
道如何確定句柄。下面要說的就是LR(0)文法,這種方法能夠根據(jù)當(dāng)前分析棧中的符號串就可以惟一的確定分析器的動(dòng)作是移進(jìn)還是歸約,并且是用哪一個(gè)產(chǎn)生式。根據(jù)規(guī)則寫出LR(0)的分析的項(xiàng)目集,再由項(xiàng)目集構(gòu)造LR(0)的分析表,其次根據(jù)分析棧的元素和狀態(tài),查看分析表,找出相關(guān)的句柄,是歸約還是移進(jìn),最后就是分析得出結(jié)果了。SLR(0)文法是以LR(0)文法為基礎(chǔ)的文法,是為了解決程序設(shè)計(jì)語言的文法不能夠滿足LR(0)文法條件的另一種文法分析的方法,大致的與LR(0)的分析過程相似,只是在項(xiàng)目集的組合上有些區(qū)別。
該課程理論性與實(shí)踐性都很強(qiáng),我在學(xué)習(xí)時(shí)普遍感到內(nèi)容非常抽象,不易理解,內(nèi)容多且繁瑣,難以完整、全面地掌握編譯原理的有關(guān)知識(shí),更不用說靈活運(yùn)用編譯原理知識(shí)從事相關(guān)設(shè)計(jì)或應(yīng)用于其他領(lǐng)域。雖然只有少數(shù)人從事編譯方面的工作,但是這門課在理論、技術(shù)、方法上都對我提供了系統(tǒng)而有效的訓(xùn)練,有利于提高軟件人員的素質(zhì)和能力。
在我學(xué)習(xí)編譯原理以前,都認(rèn)為編譯原理只能應(yīng)用在寫程序語言的編譯器上,覺得用處不大,學(xué)習(xí)興趣不高。而在后來的學(xué)習(xí)中,我逐漸認(rèn)識(shí)到計(jì)算機(jī)專業(yè)的學(xué)生,除了要會(huì)編寫程序語言之外,還應(yīng)該了解它是如何被計(jì)算機(jī)所識(shí)別,這才是真正并且透徹地學(xué)習(xí)軟件。另外,編譯器中每一個(gè)模塊的編寫,都能對我的編程能力的提高有很大幫助。在今后若從事軟件工程,這門課程也能夠?qū)帉懗绦蛴兴鶐椭?/p>
為了能夠系統(tǒng)掌握這門專業(yè)課,我把編譯原理分為以下幾個(gè)模塊:①語言和文法;②詞法分析;③語法分析;④語義分析和中間代碼生成;⑤代碼優(yōu)化和目標(biāo)代碼生成。
在學(xué)習(xí)的開始,我需要掌握什么是編譯,編譯分為哪些階段,編譯程序和解釋程序的區(qū)別等等。在做好了這些方面的準(zhǔn)備后,開始了系統(tǒng)的學(xué)習(xí)。
語言和文法部分的知識(shí)包括文法基本概念及文法的二義性?;靖拍钣形姆ǘx、推導(dǎo)、句型、句子等等。二義性文法是通過畫語法樹的方法來證明。
詞法分析中的重點(diǎn)是有窮自動(dòng)機(jī)DFA的生成以及DFA和正規(guī)式與正規(guī)文法的關(guān)系。還要熟練掌握NFA轉(zhuǎn)換為DFA的方法及DFA的化簡。
語法分析包括自上而下和自下而上分析。自上而下分析著重掌握LL(1)文法,自下而上分析重點(diǎn)掌握算符優(yōu)先文法和LR(0)、SLR(1)文法。
語義分析重點(diǎn)是其功能,中間代碼生成和語法制導(dǎo)翻譯定義與方法。
最后,優(yōu)化分為局部優(yōu)化和循環(huán)優(yōu)化,重點(diǎn)理解一些關(guān)鍵詞,如基本塊、流圖等,要學(xué)會(huì)自己畫出程序流圖。用DAG圖進(jìn)行局部優(yōu)化是重點(diǎn)。
在學(xué)習(xí)文法時(shí),對文法的組成,用法都較為明了,而在真正做題時(shí)卻感到十分吃力。例如給出了一個(gè)語言,要求寫出它的上下文無關(guān)文法,就感到十分棘手,所以今后在這方面要加大練習(xí)量,以熟練掌握。
而在之后的詞法分析和語法分析中,我感到在看基本原理時(shí)十分困難,通常要長時(shí)間鉆研才能夠有所了解,而一旦掌握了基本原理,做題時(shí)就感到十分順暢了。例如,在剛接觸到LR(0)文法時(shí),我用了大量的時(shí)間去學(xué)習(xí)它的原理,掌
握之后,在列LR(0)分析表和寫分析過程時(shí),只要思路清晰,就會(huì)比較順暢,而且不會(huì)犯錯(cuò)。
通過這學(xué)期的對編譯原理課程的學(xué)習(xí),這么課程讓我學(xué)會(huì)了如何去編譯程序的一個(gè)理論知識(shí),知道編譯程序是通過怎樣的方法把程序員編寫的源程序翻譯成計(jì)算機(jī)能夠執(zhí)行的機(jī)器語言的,我覺得主要的是大大加深了我對程序設(shè)計(jì)的理解,也對計(jì)算機(jī)的理論和軟件編譯有了深一步的理解。這學(xué)期的編譯原理的實(shí)驗(yàn)使我知道了編譯程序的工作的基本過程及其各階段的基本任務(wù),了解了 編譯程序流程框圖,編譯程序的生成過程、構(gòu)造工具及其相關(guān)的技術(shù)對課本上的知識(shí)有了更深的理解,可以說這是將書本上的理論知識(shí)的應(yīng)用,是對理論知識(shí)的更深一步的理解和掌握。
第二篇:編譯原理課程-教學(xué)計(jì)劃
編譯原理教學(xué)大綱2001,9
周次課內(nèi)學(xué)時(shí)課內(nèi)安排(講授內(nèi)容)建議課外安排備注
12編譯原理概述閱讀PL/0程序文本
24介紹PL/0編譯程序閱讀PL/0程序文本
32詞法分析程序自動(dòng)構(gòu)造閱讀PL/0程序文本
(正規(guī)式,有窮自動(dòng)機(jī))
44(2)詞法分析程序自動(dòng)構(gòu)造練習(xí)題
Lex(Flex)介紹,布置PP1實(shí)踐題一PP1
52文法和語言練習(xí)題
64自頂向下語法分析練習(xí)題提交PP1LL(1)文法
72自底向上語法分析練習(xí)題
LR文法
84LR分析練習(xí)題
期中考試
92Yacc介紹,布置PP2實(shí)踐題一PP2
104習(xí)題課
語法分析方法比較提交PP2 112語法制導(dǎo)翻譯,布置PP3實(shí)踐題一PP3
124語法制導(dǎo)翻譯
運(yùn)行時(shí)存儲(chǔ)組織提交PP3 132運(yùn)行時(shí)存儲(chǔ)組織練習(xí)題144代碼優(yōu)化, 布置PP4實(shí)踐題一PP4
152代碼生成164實(shí)踐題目總結(jié)答辯
習(xí)題課
附1 實(shí)踐題目(從中選一)
實(shí)踐題一 Deacf編譯程序的設(shè)計(jì)和實(shí)現(xiàn).實(shí)踐題二Pl/0編譯程序擴(kuò)充,用Lex和 Yacc實(shí)現(xiàn)一個(gè)小解釋器.實(shí)踐題三 java實(shí)現(xiàn)的Mini-Triangle編譯程序.(限少數(shù)同學(xué)選,在第四周作選題報(bào)告)附2 課程評分
1課堂小測驗(yàn),作業(yè)抽查 10%期中考試20%
3實(shí)踐題一 40% 實(shí)踐題二20% 實(shí)踐題三 50%
4期末考試 完成實(shí)踐題一 30% 完成實(shí)踐題二50% 完成實(shí)踐題三 20%
第三篇:編譯原理課程和助教工作總結(jié)
編譯原理課程和助教工作總結(jié)
時(shí)間如流水般,轉(zhuǎn)眼,一學(xué)期將至,每個(gè)人為了能交上一份滿意的答卷,無時(shí)無刻不在傾注著汗水,揮灑著熱淚。掩卷長思,細(xì)細(xì)品味,這學(xué)期的點(diǎn)點(diǎn)滴滴不禁又浮上心頭,現(xiàn)在讓我們一起回顧一下,希望可以對今后的教學(xué)工作有所幫助。
編譯原理是我們北京師范大學(xué)信息科學(xué)與技術(shù)學(xué)院計(jì)算機(jī)專業(yè)本科生的專業(yè)必修課,它旨在介紹編譯程序構(gòu)造的一般原理和基本方法,其內(nèi)容主要包括語言和文法、詞法分析、語法分析、語法制導(dǎo)翻譯、中間代碼生成、存儲(chǔ)管理、代碼優(yōu)化和目標(biāo)代碼生成等。這門課程關(guān)注的是編譯器方面的產(chǎn)生原理和技術(shù)問題,似乎和計(jì)算機(jī)的基礎(chǔ)領(lǐng)域不沾邊,但是編譯原理課程是所有計(jì)算機(jī)專業(yè)學(xué)生應(yīng)該習(xí)得的一門重要課程,因?yàn)殡m然在將來并不是所有人都會(huì)從事編譯方面的工作,但是通過編譯原理的學(xué)習(xí)之后,可從許多不同的角度來觀察編譯器的結(jié)構(gòu),編譯器的物理結(jié)構(gòu)、操作的順序等等,會(huì)涉及到數(shù)據(jù)結(jié)構(gòu)、計(jì)算機(jī)組成原理等課程,所以同學(xué)們在理論、技術(shù)和方法上都能得到系統(tǒng)而有效的訓(xùn)練,而且有利于將來希望從事軟件開發(fā)的學(xué)生的相關(guān)素質(zhì)和能力的進(jìn)一步提高,更能夠讓每個(gè)學(xué)生更清楚的了解和熟悉一段程序從源代碼到可執(zhí)行文件之間具體的轉(zhuǎn)換過程,這樣能夠更好的理解代碼的編譯和計(jì)算機(jī)內(nèi)部的工作原理,對學(xué)生以后計(jì)算機(jī)相關(guān)的學(xué)習(xí)乃至工作從業(yè)都會(huì)有非常大的幫助。
編譯原理這門課程是計(jì)算機(jī)專業(yè)課程中偏難的一門課,不管是在平時(shí)的課堂教學(xué)上,還是在上機(jī)實(shí)驗(yàn)的過程中,學(xué)生都會(huì)產(chǎn)生很多困惑之處,在這些方面我們的編譯原理助教就承擔(dān)了相當(dāng)重要的工作和任務(wù):
每周課堂隨堂聽課,跟進(jìn)教學(xué)進(jìn)度,并且上課之前做好復(fù)習(xí)工作,對每節(jié)課同學(xué)們可能會(huì)產(chǎn)生的問題提前做好歸納,以便更好的在課余時(shí)間跟同學(xué)們討論,給同學(xué)們提供答疑解惑的機(jī)會(huì);
能動(dòng)手編寫代碼完成變異原理實(shí)驗(yàn)是本課程技能培養(yǎng)的重要一環(huán),在每周的上機(jī)實(shí)驗(yàn)時(shí),助教幫助同學(xué)們進(jìn)行分組,以小組合作的方式來完成每次的實(shí)驗(yàn)任務(wù),依照課程進(jìn)度循序漸進(jìn)的給同學(xué)們分派布置實(shí)驗(yàn)任務(wù),在實(shí)驗(yàn)課上跟同學(xué)們隨時(shí)交流,一同調(diào)試代碼,一對一的解答實(shí)驗(yàn)疑惑等,并且協(xié)助同學(xué)們理解實(shí)驗(yàn)原理和內(nèi)容,輔助同學(xué)們能夠順利完成上機(jī)實(shí)驗(yàn),通過上機(jī)實(shí)驗(yàn)的手動(dòng)操作,同學(xué)們也可以更直接、更具體的理解編譯程序代碼過程中一些具體的原理和方法;實(shí)驗(yàn)課我選取的是基于C++或者是基于flex和bison的實(shí)驗(yàn),助教會(huì)主動(dòng)和實(shí)驗(yàn)課本的作者老師聯(lián)系溝通,獲得更多實(shí)驗(yàn)相關(guān)的資料,比如書上給出代碼的電子版和用例測試等。
助教在課后會(huì)主動(dòng)收集同學(xué)們課堂上課或者實(shí)驗(yàn)過程中遇到的問題向我反映,這樣可以及時(shí)發(fā)現(xiàn)同學(xué)們在課堂中理解較為模糊甚至有偏差的地方,并在課堂或者實(shí)驗(yàn)課上進(jìn)行一個(gè)集中的講解,更利于同學(xué)們的學(xué)習(xí);
每次課結(jié)束之后,我會(huì)布置課后作業(yè)來讓同學(xué)們對課堂教學(xué)內(nèi)容進(jìn)行鞏固和查漏補(bǔ)缺,助教認(rèn)真批改同學(xué)們的課后作業(yè)、所交的實(shí)驗(yàn)報(bào)告和運(yùn)行的代碼,做好每位同學(xué)的評分與登記,對課后作業(yè)、實(shí)驗(yàn)報(bào)告和代碼中關(guān)鍵性的錯(cuò)誤做出標(biāo)記,并要求學(xué)生改正。登記課后成績時(shí),按10分制來決定,登記實(shí)驗(yàn)成績時(shí)按照20分制來決定。在每次批改作業(yè)結(jié)束后,助教會(huì)及時(shí)整理,匯總學(xué)生的成績和作業(yè)實(shí)驗(yàn)中出現(xiàn)的問題,助教通過批改課后作業(yè)和實(shí)驗(yàn)來了解同學(xué)們真實(shí)的學(xué)習(xí)情況,從而能夠更好的輔助教學(xué)工作的進(jìn)行。
平時(shí)為了同學(xué)們能獲得更好的學(xué)習(xí)體驗(yàn),會(huì)進(jìn)行一些與國外教授的視頻課程或者相關(guān)活動(dòng)等,助教會(huì)組織同學(xué)們進(jìn)行視頻授課前的預(yù)習(xí)工作,同大家一起討論上課形式,提出可能遇到的問題等等,在課前會(huì)負(fù)責(zé)批教室,布置桌椅場地,設(shè)置視頻授課環(huán)境,調(diào)試攝像頭、話筒和音響等相關(guān)的設(shè)備,為進(jìn)行正常的視頻授課或其他活動(dòng)做準(zhǔn)備。
對自己的要求:
一、師德方面:加強(qiáng)修養(yǎng),塑造“師德”,我始終認(rèn)為作為一名教師應(yīng)把“師德”放在一個(gè)極其重要的位置上,因?yàn)檫@是教師的立身之本?!皩W(xué)高為師,身正為范”,這個(gè)道理古今皆然。從踏上講臺(tái)的第一天,我就時(shí)刻嚴(yán)格要求自己,力爭做一個(gè)有崇高師德的人,為每一個(gè)學(xué)生“傳道授業(yè)解惑”。
二、認(rèn)真?zhèn)湔n,不但備學(xué)生而且備教材備教法,根據(jù)教材內(nèi)容及學(xué)生的實(shí)際,設(shè)計(jì)課的類型,擬定采用的教學(xué)方法,并對教學(xué)過程的程序及時(shí)間安排都作了詳細(xì)的安排,認(rèn)真寫好教案。每一課都做到“有備而來”,每堂課都在課前做好充分的準(zhǔn)備,并制作各種有利于吸引學(xué)生注意力的有趣教具,課后及時(shí)對該課作出總結(jié),并認(rèn)真搜集每課書的知識(shí)要點(diǎn),歸納總結(jié)。
三、增強(qiáng)上課技能,提高教學(xué)質(zhì)量,使講解清晰化,條理化,準(zhǔn)確化,生動(dòng)化,做到線索清晰,言簡意賅,深入淺出。在課堂上特別注意調(diào)動(dòng)學(xué)生的積極性,讓學(xué)生多動(dòng)手,從而加深理解掌握知識(shí)。加強(qiáng)師生交流,充分體現(xiàn)學(xué)生的主動(dòng)作用,讓學(xué)生學(xué)得容易,學(xué)得輕松,學(xué)得愉快;注意精講精練,在課堂上老師講得盡量少,學(xué)生動(dòng)口動(dòng)手動(dòng)腦盡量多;同時(shí)在每一堂課上都充分考慮每一個(gè)層次的學(xué)生學(xué)習(xí)需求和學(xué)習(xí)能力,讓各個(gè)層次的學(xué)生都得到提高。
四、認(rèn)真批改作業(yè):布置作業(yè)做到精讀精練。有針對性,有層次性。同時(shí)對學(xué)生的作業(yè)批改及時(shí)、認(rèn)真,分析并記錄學(xué)生的作業(yè)情況,將他們在作業(yè)過程中出現(xiàn)的問題作出分類總結(jié),進(jìn)行透切的評講,并針對有關(guān)情況及時(shí)改進(jìn)教學(xué)方法,做到有的放矢。對學(xué)生:
“不積跬步,無以致千里;不積小流,無以成江?!?,學(xué)生要從點(diǎn)點(diǎn)滴滴做起,一步一個(gè)腳印,一份耕耘,一份收獲。學(xué)習(xí)要靠你們自己,踏踏實(shí)實(shí)做事,所謂“行百里路半九十”,學(xué)習(xí)要鍥而不舍,奮進(jìn)永遠(yuǎn)是核心,讓努力充實(shí)自己,厚積而薄發(fā),達(dá)到“書香引蝶宜養(yǎng)蘭,胸中點(diǎn)墨繪新顏”的水平。
第四篇:《編譯原理》課程培訓(xùn)心得體會(huì)
《編譯原理》課程培訓(xùn)心得體會(huì)
天津科技大學(xué) 吳江紅
首先感謝全國高校教師網(wǎng)絡(luò)培訓(xùn)中心為我們這些工作在教學(xué)第一線的教師提供一個(gè)提高自己教學(xué)水平、方法和能力的機(jī)會(huì),使得我們學(xué)習(xí)到更好的方法能更好地為學(xué)生服務(wù)。經(jīng)過本次培訓(xùn)之后,我個(gè)人覺得可以通過以下幾個(gè)方面提高教學(xué)質(zhì)量。
1、認(rèn)清編譯原理,明確學(xué)習(xí)意義,激發(fā)學(xué)生的熱情 幫助學(xué)生認(rèn)清編譯原理的作用和地位。給學(xué)生介紹清楚可以通過編譯原理的學(xué)習(xí),有助于學(xué)生快速理解、定位和解決在程序編譯、測試與運(yùn)行中出現(xiàn)的問題。幫助學(xué)生克服畏難心理,提高學(xué)生的興趣。編譯原理中的原理除了可以用于分析編譯器以外,還對諸如人工智能、并行處理技術(shù)等課程的學(xué)習(xí)具有指導(dǎo)作用。本門課程學(xué)習(xí)對其它課程的學(xué)習(xí)和今后很多領(lǐng)域的理論研究具有深遠(yuǎn)的意義,如計(jì)算機(jī)軟件技術(shù)領(lǐng)域、計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)領(lǐng)域、人工智能系統(tǒng)的機(jī)器學(xué)習(xí)領(lǐng)域、并行處理技術(shù)等領(lǐng)域。
2、優(yōu)化教學(xué)內(nèi)容,搞好課堂教學(xué)
可以采用以人本主義學(xué)習(xí)理論為基礎(chǔ),充分發(fā)揮學(xué)生的學(xué)習(xí)主動(dòng)性,注重啟發(fā)式教學(xué),注重提高學(xué)生的素質(zhì)、培養(yǎng)學(xué)生的創(chuàng)新能力。使得學(xué)生對編譯原理課程的興趣提高,能主動(dòng)學(xué)習(xí),理解、體會(huì)前輩們在解決相應(yīng)問題時(shí)是如何考慮的,同學(xué)們自己又是如何考慮的。
編譯系統(tǒng)中的一些概念很抽象,學(xué)生無法理解,就只會(huì)死記硬背,當(dāng)然更無興趣可言。在講解的過程中,可以選用學(xué)生最熟悉的一些實(shí)例,通過類比使抽象的概念更容易被理解。我本人覺著對于工學(xué)學(xué)科的同學(xué)來說,不用在數(shù)學(xué)定義上花費(fèi)太多時(shí)間,因?yàn)樗麄儗?shù)學(xué)符號不敏感,而應(yīng)該盡量多安排例子,使得同學(xué)們能把數(shù)學(xué)符號代表的含義通過例子理解清楚,以及知道如何使用。
有效地利用教學(xué)輔助手段,增強(qiáng)課堂教學(xué)效果。由于本課程涉及形式語言、有窮自動(dòng)機(jī)等抽象內(nèi)容,學(xué)生在學(xué)習(xí)過程中接受起來較困難。為了提高學(xué)生的學(xué)習(xí)興趣、增強(qiáng)課堂教學(xué)效果,可以將教學(xué)過程中一些需要教師在黑板上動(dòng)態(tài)演示的過程做成CAI課件,既可在課堂上演示,也可在課后由學(xué)生自己觀摩,有助于加深學(xué)生對所學(xué)知識(shí)的理解。
同時(shí)可在課堂上和習(xí)題中,多準(zhǔn)備了一些從實(shí)際程序的編譯和運(yùn)行時(shí)碰到的問題中抽象出來的例子,供學(xué)生用所學(xué)的知識(shí)去分析、理解、并加以解決。通過采用這種實(shí)例教學(xué)方式,既能夠?qū)η捌谡n程起到復(fù)習(xí)鞏固的作用,又能讓學(xué)生切實(shí)體會(huì)到本課程的實(shí)際價(jià)值,從而有力地激發(fā)了學(xué)生學(xué)習(xí)編譯原理和技術(shù)的積極性。
3、選取合適的教材
把理論知識(shí)具體化、通俗化,教材在教學(xué)過程中起關(guān)鍵作用。一本好的教材不僅對老師教的過程很重要,同時(shí)在學(xué)生進(jìn)行預(yù)習(xí)和復(fù)習(xí)時(shí)也是相當(dāng)重要的。我們可以選擇蔣宗禮教授編寫的編譯原理教材來達(dá)到我們的目標(biāo)。
4、精心設(shè)計(jì)實(shí)驗(yàn)教學(xué)內(nèi)容
編譯原理課程對實(shí)踐的要求比較高,所以實(shí)驗(yàn)課是培養(yǎng)學(xué)生實(shí)踐能力的重要環(huán)節(jié),是鞏固和驗(yàn)證所學(xué)理論知識(shí),培養(yǎng)學(xué)生分析問題、解決問題能力的重要環(huán)節(jié)。因此為了能達(dá)到好的實(shí)驗(yàn)效果,極大地促進(jìn)學(xué)生對原理的理解,可以通過認(rèn)真設(shè)計(jì)合適的實(shí)驗(yàn)內(nèi)容、采用適當(dāng)?shù)膶?shí)驗(yàn)形式以及教師的耐心指導(dǎo)等途徑。
第五篇:編譯原理課程設(shè)計(jì)報(bào)告
武 漢 紡 織 大 學(xué)
編譯原理課程設(shè)計(jì)實(shí)驗(yàn)報(bào)告
學(xué)院:數(shù)學(xué)與計(jì)算機(jī) 專業(yè):計(jì)算機(jī) 姓名: 班級: 學(xué)號: 編譯原理
編譯原理課設(shè)報(bào)告
一、實(shí)驗(yàn)?zāi)康?/p>
加強(qiáng)對編譯程序的整體認(rèn)識(shí)和了解,鞏固《編譯原理》課程所學(xué)知識(shí)。通過本次課程設(shè)計(jì)掌握編譯程序調(diào)試技巧和設(shè)計(jì)編譯程序一般的原則,加深對詞法分析、語法分析、語義分析等編譯階段及實(shí)用編譯系統(tǒng)的認(rèn)識(shí)。使學(xué)生能將編譯理論與實(shí)際應(yīng)用結(jié)合起來,提高學(xué)生軟件開發(fā)的能力。
二、實(shí)驗(yàn)內(nèi)容
1)仔細(xì)閱讀PL/0編譯程序文本(編譯原理(第二版)張素琴 呂映芝 蔣維杜 戴桂蘭 主編
清華大學(xué)出版社),并上機(jī)調(diào)試通過。
2)對PL/0語言進(jìn)行下列擴(kuò)充(1)擴(kuò)充一維整型數(shù)組。
擴(kuò)充var數(shù)組:VAR <數(shù)組標(biāo)識(shí)名>(<下界>:<上界>)〈下界〉和〈上界〉可用常量標(biāo)識(shí)名。
(2)擴(kuò)充條件語句的功能使其為:IF<條件>THEN<語句>[ELSE<語句>](3)增加repeat重復(fù)語句: REPEAT<語句>{;<語句>}UNTIL<條件> 可根據(jù)自己具體情況從中選擇2個(gè)以上題目進(jìn)行擴(kuò)充。
三、實(shí)驗(yàn)原理
PL/0語言可以看成PASCAL語言的子集,它的編譯程序是一個(gè)編譯解釋執(zhí)行系統(tǒng)。PL/0的目標(biāo)程序?yàn)榧傧霔J接?jì)算機(jī)的匯編語言,與具體計(jì)算機(jī)無關(guān)。
PL/0的編譯程序和目標(biāo)程序的解釋執(zhí)行程序都是用PASCAL語言書寫的,因此PL/0語言可在配備PASCAL語言的任何機(jī)器上實(shí)現(xiàn)。其編譯過程采用一趟掃描方式,以語法分析程序?yàn)楹诵?,詞法分析和代碼生成程序都作為一個(gè)獨(dú)立的過程,當(dāng)語法分析需要讀單詞時(shí)就調(diào)用詞法分析程序,而當(dāng)語法分析正確需要生成相應(yīng)的目標(biāo)代碼時(shí),則調(diào)用代碼生成程序。
用表格管理程序建立變量、常量和過程表示符的說明與引用之間的信息聯(lián)系。
當(dāng)源程序編譯正確時(shí),PL/0編譯程序自動(dòng)調(diào)用解釋執(zhí)行程序,對目標(biāo)代碼進(jìn)行解釋執(zhí)行,并按用戶程序的要求輸入數(shù)據(jù)和輸出運(yùn)行結(jié)果。
四、實(shí)驗(yàn)分析
PL/0語言編譯程序采用以語法分析為核心、一遍掃描的編譯方法。詞法分析和代碼生成作為獨(dú)立的子程序供語法分析程序調(diào)用。語法分析的同時(shí),提供了出錯(cuò)報(bào)告和出錯(cuò)恢復(fù)的功能。在源程序沒有錯(cuò)誤編譯通過的情況下,調(diào)用類PCODE解釋程序解釋執(zhí)行生成的類PCODE代碼。
詞法分析子程序分析:
詞法分析子程序名為GETSYM,功能是從源程序中讀出一個(gè)單詞符號(TOTAKEN),把它的信息放入全局變量 SYM、ID和NUM中,字符變量放入CH中,語法分析器需要單詞時(shí),直接從這三個(gè)變量中獲得。Getch過程通過反復(fù)調(diào)用Getch子過程從源程序過獲取字符,并把它們拼成單詞。GETCH過程中使用了行緩沖區(qū)技術(shù)以提高程序運(yùn)行效率。
詞法分析器的分析過程:調(diào)用GETSYM時(shí),它通過GETCH過程從源程序中獲得一個(gè)字符。如果這個(gè)字符是字母,則繼續(xù)獲取字符或數(shù)字,最終可以拼成一個(gè)單詞,查保留字表,如果查到為保留字,則把SYM變量賦成相應(yīng)的保留字類型值;如果沒有查到,則這個(gè)單詞應(yīng)是一個(gè)用戶自定義的標(biāo)識(shí)符(可能是變量名、常量名或是過程的名字),把SYM置為IDENT,把這個(gè)單詞存入ID變量。查保留字表時(shí)使用了二分法查找以提高效率。如果Getch獲得的字符是數(shù)字,則繼續(xù)用Getch獲取數(shù)字,并把它們拼成一個(gè)整數(shù)或?qū)崝?shù),然后把SYM置為 INTEGER或REAL,并把拼成的數(shù)值放入NUM變量。如果識(shí)別出其它合法的符號(比如:賦值號、大于號、小于等于號等),則把SYM則成相應(yīng)的類型。如果遇到不合法的字符,把SYM置成NUL。
語法分析子程序分析:
語法分析子程序采用了自頂向下的遞歸子程序法,語法分析同時(shí)也根據(jù)程序的語義生成相應(yīng)三元代碼,并提供了出錯(cuò)處理的機(jī)制。語法分析主要由分程序分析過程(BLOCK)、參數(shù)變量分析過程(ParaDeclaration)、參數(shù)變量處理過程(ParaGetSub)、數(shù)組處理過程(ParaGetSub)、常量定義分析過程(ConstDeclaration)、變量定義分析過程(Vardeclaration)、語句分析過程(Statement)、表達(dá)式處理過程(Expression)、項(xiàng)處理過程(Term)、因子處理過程(Factor)和條件處理過程(Condition)構(gòu)成。這些過程在結(jié)構(gòu)上構(gòu)成一個(gè)嵌套的層次結(jié)構(gòu)。除此之外,還有出錯(cuò)報(bào)告過程(Error)、代碼生成過程(Gen)、測試單詞合法性及出錯(cuò)恢復(fù)過程(Test)、登錄名字表過程(Enter)、查詢名字表函數(shù)(Position)以及列出類 PCODE代碼過程(Listcode)作過語法分析的輔助過程。
由PL/0的語法圖可知:一個(gè)完整的PL/0程序是由分程序和句號構(gòu)成的。因此,本編譯程序在運(yùn)行的時(shí)候,通過主程序中調(diào)用分程序處理過程block來分析分程序部分(分程序分析過程中還可能會(huì)遞歸調(diào)用block過程),然后,判斷最后讀入的符號是否為句號。如果是句號且分程序分析中未出錯(cuò),則是一個(gè)合法的PL/0程序,可以運(yùn)行生成的代碼,否則就說明源PL/0程序是不合法的,輸出出錯(cuò)提示即可。
if-then-else語句的處理:
按if語句的語法,首先調(diào)用邏輯表達(dá)式處理過程處理if語句的條件,把相應(yīng)的真假值放到數(shù)據(jù)棧頂。接下去記錄下代碼段分配位置(即下面生成的jpc指令的位置),然后生成 條件轉(zhuǎn)移jpc指令(遇0或遇假轉(zhuǎn)移),轉(zhuǎn)移地址未知暫時(shí)填0。然后調(diào)用語句處理過程處理 then語句后面的語句或語句塊。then后的語句處理完后,如果遇到else,就調(diào)用語句處理過程處理else語句后面的語句或語句塊,這時(shí)當(dāng)前代碼段分配指針的位置就應(yīng)該是上面的jpc指令的轉(zhuǎn)移位置。通過前面記錄下的jpc指令的位置,把它的跳轉(zhuǎn)位置改成當(dāng)前的代碼段指針位置,否則沒遇到else,那么此時(shí)的當(dāng)前代碼段分配指針的位置也是上面jpc指令的轉(zhuǎn)移位置,也是通過前面記錄下的jpc位置指令的位置,把它的跳轉(zhuǎn)到當(dāng)前的代碼段指針位置。
Repeat語句的處理:
首先用CX1變量記下當(dāng)前代碼段分配位置,作為循環(huán)的開始位置。然后通過遞歸調(diào)用語句分析過程分析,直到遇到until保留字,如果未對應(yīng)until則出錯(cuò)。調(diào)用條件表達(dá)式處理過程生成相應(yīng)代碼把結(jié)果放在數(shù)據(jù)棧頂,再生成條件轉(zhuǎn)移指令,轉(zhuǎn)移位置為上面記錄的CX1。
五、相關(guān)代碼及運(yùn)行結(jié)果
實(shí)驗(yàn)代碼; PL0.h代碼: #include
#ifndef WIRTH_ZYC_ #define WIRTH_ZYC_ using namespace std;
const int norw = 16;
// no.of reserved words 保留字的個(gè)數(shù)
const int txmax = 100;
// length of identifier table 標(biāo)示符表的長度(容量)const int al = 10;
// length of identifiers 標(biāo)示符的最大長度
const int nmax = 14;
// max.no.of digits in numbers 數(shù)字的最大長度 const int amax = 2047;
// maximum address 尋址空間
const int levmax = 3;
// maximum depth of block nesting 最大允許的塊嵌套層數(shù) const int cxmax = 200;
// size of code array 類PCODE目標(biāo)代碼數(shù)組長度(可容納代碼行數(shù))
const int lineLength = 82;// 行緩沖區(qū)長度
typedef enum {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,READSYM,DOSYM,CALLSYM,CONSTSYM,VARSYM,PROCSYM,ELSESYM,REPEATSYM,UNTILSYM} symbol;// symobl類型標(biāo)識(shí)了不同類型的詞匯
typedef char alfa[al+1];
// alfa類型用于標(biāo)識(shí)符 typedef enum {CONSTANT,VARIABLE,PROCEDURE,ARRAY} obj0;
// 三種標(biāo)識(shí)符的類型 typedef enum {LIT,OPR,LOD,STO,CAL,INT,JMP,JPC} fct;
// functions typedef set
struct instruction{ fct f;// function code int l;// level,cann't big than levmax
int a;// displacement address,cann't big than amax };
// 類PCODE指令類型,包含三個(gè)字段:指令f、層差l和另一個(gè)操作數(shù)a
/******************************************* * lit 0,a: load constant a
* * opr 0,a: execute operation a
* * lod l,a: load variable l,a
* * sto l,a: store variable l,a
* * cal l,a: call procedure a at level l
* * int 0,a: increment t-register by a
* * jmp 0,a: jump to a
* * jpc 0,a: jump conditional to a
* *******************************************/
typedef struct{ alfa name;obj0 kind;union {
struct{int level,adr,size;}inOther;
int val;}other;} Table;
class PL0 {
protected:
bool listswitch,sourceEnd;char ch;
// last character read symbol sym;
// last symbol read alfa id;
// last identifier read int num;
// last number read
int cc;
// character count int ll;
// line length int kk,err;int cx;
// code allocation index int codeNo;
// code line no.static string errStr[];
// error string
char line[lineLength];
// code line vector
// error array alfa a;
// 詞法分析器中用于臨時(shí)存放正在分析的詞
instruction code[cxmax+1];
// destination code array
alfa word[norw+1];
// 保留字表
symbol wsym[norw+1];
// 保留字表中每一個(gè)保留字對應(yīng)的symbol類型
symbol ssym[100];
// 一些符號對應(yīng)的symbol類型表
合 char mnemonic[8][6];
// 類PCODE指令助記符表
symset declbegsys,statbegsys,facbegsys;// 聲明開始、表達(dá)式開始和項(xiàng)開始符號集 Table table[txmax+1];
// 符號表
FILE* fin,*fout;
public:
PL0(char* source,char*destination);
~PL0(){fclose(fin),fclose(fout);}
void error(int n);
位置和出錯(cuò)代碼
void getsym();
個(gè)單詞
void getch();
個(gè)字符
void gen(fct x,int y,int z);
程序區(qū)
void test(symset s1,symset s2,int n);
合法
void block(int lev,int tx,symset fsys);
void enter(obj0 k,int &tx,int &dx,int lev);
int position(alfa id,int tx);的位置
void constdeclaration(int&tx,int&dx,int lev);
void vardeclaration(int&tx,int&dx,int lev);
void listcode(int cx0);
void statement(symset fsys,int tx,int lev);
void expression(symset fsys,int tx,int lev);
void term(symset fsys,int tx,int lev);
void factor(symset fsys,int tx,int lev);
void condition(symset fsys,int tx,int lev);
void arraydeclaration(int& tx,int& dx,int lev);
void interpret();
執(zhí)行程序
int base(int l,int b,int s[]);
基地址
void SaveCode();
// 構(gòu)造函數(shù)
// 析構(gòu)函數(shù)
// 出錯(cuò)處理,打印出錯(cuò)
// 詞法分析,讀取一
// 漏掉空格,讀取一// 生成目標(biāo)代碼,并送入目標(biāo)
// 測試當(dāng)前單詞符號是否
// 分程序分析處理過程
// 登入名字表
// 查找標(biāo)示符在名字表中
// 常量定義處理
// 變量說明處理
// 列出目標(biāo)代碼清單
// 語句部分處理
// 表達(dá)式處理
// 項(xiàng)處理
// 因子處理
// 條件處理
// 數(shù)組說明處理
// 對目標(biāo)代碼的解釋
// 通過靜態(tài)鏈求出數(shù)據(jù)區(qū)的 // 保存代碼
};#endif PL0.cpp代碼: #include “pl0.h”
// 錯(cuò)誤字符串?dāng)?shù)組
string PL0::errStr[]={“",”error 0001: 常數(shù)說明中“=”寫成“:=”“, ”error 0002: 常數(shù)說明中的“=”后應(yīng)為數(shù)字“, ”error 0003: 常數(shù)說明中的標(biāo)識(shí)符后應(yīng)是“=”“, ”error 0004: const,var,procedure后應(yīng)為標(biāo)識(shí)符“, ”error 0005: 漏掉了‘,’或‘;’“, ”error 0006: 過程說明后的符號不正確(應(yīng)是語句開始符或過程開始符)“, ”error 0007: 應(yīng)是語句開始符“, ”error 0008: 過程體內(nèi)語句部分的后跟符不正確“, ”error 0009: 程序皆為丟了句號‘.’“, ”error 0010: 語句之間漏了‘;’“, ”error 0011: 標(biāo)識(shí)符沒說明“, ”error 0012: 賦值語句中,賦值號左部標(biāo)識(shí)符屬性應(yīng)是變量“, ”error 0013: 賦值語句左部標(biāo)識(shí)符應(yīng)是賦值號:=“, ”error 0014: call后應(yīng)為標(biāo)識(shí)符“, ”error 0015: call后標(biāo)識(shí)符屬性應(yīng)為過程“, ”error 0016: 條件語句中丟了then“, ”error 0017: 丟了end或;“, ”error 0018: while型循環(huán)語句中丟了do“, ”error 0019: 語句后的標(biāo)識(shí)符不正確“, ”error 0020: 應(yīng)為關(guān)系運(yùn)算符“, ”error 0021: 表達(dá)式內(nèi)標(biāo)識(shí)符屬性不能是過程“, ”error 0022: 表達(dá)式中漏掉了右括號‘)’“, ”error 0023: 因子后的非法符號“, ”error 0024: 表達(dá)式開始符不能是此符號“, ”error 0025: 文件在不該結(jié)束的地方結(jié)束了“, ”error 0026: 結(jié)束符出現(xiàn)在不該結(jié)束的地方“, ”error 0027: “,”error 0028: “,”error 0029: “,”error 0030: “, ”error 0031: 數(shù)越界“, ”error 0032: read語句括號中標(biāo)識(shí)符不是變量“, ”error 0033: else附近錯(cuò)誤“ , ”error 0034: repeat附近錯(cuò)誤“};
// PL0構(gòu)造函數(shù)
PL0::PL0(char* source,char*destination){ listswitch=true,sourceEnd=false;
strcpy(word[1],”begin“);
// 初始化存儲(chǔ)保留字
strcpy(word[2],”call“);strcpy(word[3],”const“);
strcpy(word[4],”do“);strcpy(word[5],”else“);strcpy(word[6],”end“);strcpy(word[7],”if“);strcpy(word[8],”odd“);strcpy(word[9],”procedure“);strcpy(word[10],”read“);
strcpy(word[11],”repeat“);strcpy(word[12],”then“);strcpy(word[13],”until“);strcpy(word[14],”var“);
strcpy(word[15],”while“);strcpy(word[16],”write“);
wsym[1]= BEGINSYM;
wsym[2]= CALLSYM;留字對應(yīng)的symbol類型
wsym[3]= CONSTSYM;
wsym[4]= DOSYM;wsym[5]= ELSESYM;
wsym[6]= ENDSYM;wsym[7]= IFSYM;
wsym[8]= ODDSYM;wsym[9]= PROCSYM;
wsym[10]= READSYM;
wsym[11]= REPEATSYM;wsym[12]= THENSYM;wsym[13]= UNTILSYM;wsym[14]= VARSYM;
wsym[15]= WHILESYM;wsym[16]= WRITESYM;
memset(code,0,sizeof(code));memset(ssym,0,100*sizeof(symbol));memset(table,0,sizeof(table));memset(line,0,sizeof(line));
ssym['+']= PLUS;
類型表
ssym['-']= MINUS;ssym['*']= TIMES;ssym['/']= SLASH;ssym['(']= LPAREN;ssym[')']= RPAREN;ssym['=']= EQL;ssym[',']= COMMA;ssym['.']= PERIOD;
// 初始化保留字表中每一個(gè)保
// 初始化一些符號對應(yīng)的symbol
ssym['#']= NEQ;ssym['<']= LSS;ssym['>']= GTR;ssym[';']= SEMICOLON;
strcpy(mnemonic[LIT],” lit “);
// 初始化類PCODE指令助記符表
strcpy(mnemonic[OPR],” opr “);strcpy(mnemonic[LOD],” lod “);strcpy(mnemonic[STO],” sto “);strcpy(mnemonic[CAL],” cal “);strcpy(mnemonic[INT],” int “);strcpy(mnemonic[JMP],” jmp “);strcpy(mnemonic[JPC],” jpc “);
declbegsys.insert(CONSTSYM),declbegsys.insert(VARSYM),declbegsys.insert(PROCSYM);// 初始化聲明開始符號集合 statbegsys.insert(BEGINSYM),statbegsys.insert(CALLSYM),statbegsys.insert(IFSYM),statbegsys.insert(WHILESYM);// 初始化表達(dá)式開始符號集合facbegsys.insert(IDENT),facbegsys.insert(NUMBER),facbegsys.insert(LPAREN);// 初始化項(xiàng)開始符號集合
err= 0;cc= 0;
// 行緩沖區(qū)指針
cx= 0;
// 代碼分配指針,代碼生成模塊總在cx所指位置生成新的代碼
ll= 0;
// 行緩沖區(qū)長度
ch= ' ';
// last character read
}
kk= al;
// 引入此變量是出于程序性能考慮 codeNo=0;
// code line no.fin=fopen(source,”r“);fout=fopen(destination,”w“);// 出錯(cuò)處理,打印出錯(cuò)位置和出錯(cuò)代碼 void PL0::error(int n){ char s[10];sprintf(s,”第 %d 行:“,codeNo);errorString.push_back(s+errStr[n]);err= err+1;//error count }//error end // 詞法分析,讀取一個(gè)單詞
void PL0::getsym(){ if(sourceEnd)
return;int i,j,k;while(ch ==' '||ch==9)
getch();
// cls space and tab if(isalpha(ch))// id or reserved word {
k=0;
memset(a,0,al+1);
// 檢測一個(gè)單詞長度 do{ if(k < al){
a[k]= ch;
k= k+1;} getch();if(sourceEnd)
return;}while(isalpha(ch)||isdigit(ch));if(k >= kk)kk = k;else { do{
a[kk]= ' ';
kk= kk-1;}while(kk > k);} strcpy(id,a);i= 1;j= norw;// 判斷是否是關(guān)鍵字(二分搜索)do{ k=(i+j)/ 2;if(strcmp(id, word[k])<=0)
j= k-1;if(strcmp(id,word[k])>=0)
i= k+1;}while(i<=j);if(i-1 > j)
sym= wsym[k];else
sym= IDENT;} else if(isdigit(ch))// number { k= 0;num= 0;sym= NUMBER;do{
num= 10 * num + ch-'0';
k= k+1;
getch();}while(isdigit(ch));if(k > nmax)
error(30);} else if(ch == ':'){ getch();if(ch == '='){
sym= BECOMES;
getch();} else
sym= NUL;} else if(ch == '<')
// extra stuff added to support <= { getch();if(ch== '='){
sym= LEQ;
getch();} else
sym= LSS;} else if(ch == '>'){ getch();if(ch == '='){
sym= GEQ;
getch();} else
sym= GTR;} else
// end of extra stuff { sym= ssym[ch];// 其它符號的賦值
getch();} }
// 漏掉空格,讀取一個(gè)字符
void PL0::getch(){ if(cc == ll){
if(feof(fin))
{
if(sym!=PERIOD)
error(25);
sourceEnd=true;
return;
}
cc= 0;
fgets(line,lineLength,fin);
codeNo++;
ll=strlen(line);
if(line[ll-1]==10)ll--;} ch= line[cc];cc= cc+1;}
// 生成目標(biāo)代碼,并送入目標(biāo)程序區(qū)void PL0::gen(fct x,int y,int z){ if(cx > cxmax){
cout<<”Program too longn“;
return;}
code[cx].f= x;code[cx].l= y;code[cx].a= z;
cx= cx+1;}//gen end
// 測試當(dāng)前單詞符號是否合法
void PL0::test(symset s1,symset s2,int n){ if(sourceEnd)
return;if(s1.find(sym)==s1.end()){
error(n);
symset::iterator it;
for(it=s2.begin();it!=s2.end();it++)
s1.insert(*it);//s1=s1+s2
while(s1.find(sym)==s1.end())
getsym();} }//test end
// 分程序分析處理過程
void PL0::block(int lev,int tx,symset fsys){ if(sourceEnd)
return;int dx;// data allocation index int tx0;// initial table index int cx0;// initial code index
dx= 3;
// 變量的個(gè)數(shù) tx0= tx;// 表指針
table[tx].other.inOther.adr= cx;gen(JMP,0,0);if(lev>levmax)error(32);do{
if(sym == CONSTSYM)
// 處理常量聲明
{
getsym();
do{
constdeclaration(tx,dx,lev);
while(sym == COMMA)
{
}
getsym();
constdeclaration(tx,dx,lev);} if(sym ==SEMICOLON)
getsym();else
error(5);}while(sym==IDENT);if(sym == VARSYM)
// 處理變量聲明 { getsym();do{
vardeclaration(tx,dx,lev);
while(sym == COMMA){
getsym();
vardeclaration(tx,dx,lev);
}
if(sym ==SEMICOLON)
getsym();
else
error(5);}while(sym==IDENT);} while(sym ==PROCSYM)
// 處理過程的聲明 { getsym();if(sym ==IDENT){
enter(PROCEDURE,tx,dx,lev);
getsym();} else
error(4);if(sym ==SEMICOLON)
getsym();else
error(5);symset tmp = fsys;tmp.insert(SEMICOLON);block(lev+1,tx,tmp);if(sym == SEMICOLON){
getsym();
symset tmp = statbegsys;
for(int i= IDENT;i<=PROCSYM;i++)
tmp.insert((symbol)i);
test(tmp,fsys,6);
}
else
error(5);
}
symset tmp=statbegsys;
tmp.insert(IDENT);
test(tmp,declbegsys,7);}while(declbegsys.find(sym)!=declbegsys.end());
code[table[tx0].other.inOther.adr].a= cx;table[tx0].other.inOther.adr= cx;// start adr of code table[tx0].other.inOther.size=dx;
cx0= cx;gen(INT,0,dx);symset tmp=statbegsys;for(int i=SEMICOLON;i <= ENDSYM;i++)
tmp.insert((symbol)i);statement(tmp,tx,lev);gen(OPR,0,0);// return symset s2;test(fsys,s2,8);listcode(cx0);}// block end
// 登入名字表
void PL0::enter(obj0 k,int &tx,int &dx,int lev){ tx= tx+1;strcpy(table[tx].name,id);table[tx].kind=k;switch(k){ case CONSTANT:
if(num>amax)
{
error(31);
num=0;
}
table[tx].other.val=num;
break;case VARIABLE:
table[tx].other.inOther.level=lev;
table[tx].other.inOther.adr=dx;
dx++;
break;case PROCEDURE:
table[tx].other.inOther.level=lev;
break;case ARRAY:
table[tx].other.inOther.size = lev;
break;} }//enter end
// 查找標(biāo)示符在名字表中的位置
int PL0::position(alfa id,int tx)//find identifier id in table { int i;strcpy(table[0].name, id);i= tx;while(strcmp(table[i].name,id)!=0)i--;return i;}//position end
// 常量定義處理
void PL0::constdeclaration(int&tx,int&dx,int lev){ if(sym == IDENT){
getsym();
if(sym>=EQL&&sym<=BECOMES)
{
if(sym ==BECOMES)
error(1);
getsym();
if(sym == NUMBER)
{
enter(CONSTANT,tx,dx,lev);
getsym();
}
else
error(2);
}
else
error(3);} else
error(4);}// constdeclaration end
// 變量說明處理
void PL0::vardeclaration(int&tx,int&dx,int lev){ if(sym == IDENT){
enter(VARIABLE,tx,dx,lev);
getsym();} else
error(4);}//vardeclaration end
// 數(shù)組說明處理
void PL0::arraydeclaration(int&tx,int&dx,int lev){
int upscript=0,downscript=0;getsym();if(sym == NUMBER || sym == CONSTSYM){
if(num == 0)
{
upscript = num;
getsym();
}
else
error(32);} if(sym == COMMA)
getsym();else
error(32);if(sym == NUMBER || sym == CONSTSYM){
downscript = num;
getsym();} if(sym!= RPAREN)
} error(32);else { enter(ARRAY,tx,dx,downscript+1);getsym();} // 列出目標(biāo)代碼清單
void PL0::listcode(int cx0)//list code generated for this block { int i;if(listswitch)
for(i= cx0;i cout<<”“< <<”“< // 語句部分處理 void PL0::statement(symset fsys,int tx,int lev){ if(sourceEnd) return;int i,cx1,cx2;if(sym ==IDENT){ i= position(id,tx); if(i == 0) error(11); else if(table[i].kind!=VARIABLE) { error(12); i= 0; } getsym(); if(sym ==BECOMES) getsym(); else error(13); expression(fsys,tx,lev); if(sym!= SEMICOLON) error(10); if(i!= 0) gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr); } else if(sym == READSYM){ getsym();if(sym!=LPAREN) error(34);else do{ getsym(); if(sym==IDENT) i=position(id,tx); else i=0; if(i==0) error(35); else { gen(OPR,0,16); gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr); } getsym(); }while(sym == COMMA); if(sym!= RPAREN) { error(33); while(fsys.find(sym)!=fsys.end())getsym(); } else getsym();} else if(sym == WRITESYM){ getsym();if(sym==LPAREN){ do{ getsym(); symset tmp=fsys; for(int t=RPAREN;t<=COMMA;t++) tmp.insert((symbol)t); expression(tmp,tx,lev); gen(OPR,0,14); }while(sym==COMMA); if(sym!=RPAREN) error(33); else getsym();} gen(OPR,0,15);} else if(sym ==CALLSYM){ getsym();if(sym!=IDENT) error(14);else { i= position(id,tx); if(i == 0) error(11); else if(table[i].kind = PROCEDURE) gen(CAL,lev-table[i].other.inOther.level,table[i].other.inOther.adr); else error(15); getsym();} } else if(sym ==IFSYM){ getsym();symset tmp=fsys;for(int i = THENSYM;i<= DOSYM;i++) tmp.insert((symbol)i);condition(tmp,tx,lev);if(sym == THENSYM) getsym();else error(16);cx1= cx;gen(JPC,0,0);tmp.insert(ELSESYM);statement(tmp,tx,lev);getsym(); code[cx1].a= cx; if(sym == ELSESYM){ getsym(); cx2=cx; gen(JMP,0,0); code[cx1].a=cx; statement(fsys,tx,lev); code[cx2].a=cx;} } else if(sym ==BEGINSYM){ getsym();symset tmp=fsys;for(int i=SEMICOLON;i<=ENDSYM;i++) tmp.insert((symbol)i);statement(tmp,tx,lev);tmp=statbegsys;tmp.insert(SEMICOLON);while(tmp.find(sym)!=tmp.end()){ if(sourceEnd)return; if(sym ==SEMICOLON||sym ==ENDSYM) getsym(); else if(sym=PERIOD) { error(26); getsym(); } else error(10); tmp=fsys; for(i=SEMICOLON;i<=ENDSYM;i++) tmp.insert((symbol)i); if(sourceEnd)return; if(sym==ENDSYM) break; statement(tmp,tx,lev);} if(sym ==ENDSYM) getsym();else if(!sourceEnd) error(17);} else if(sym ==WHILESYM){ cx1= cx; // 記下當(dāng)前代碼分配位置,這是while循環(huán)的開始位置 getsym();symset tmp=fsys;tmp.insert(DOSYM);condition(tmp,tx,lev); cx2= cx; // 記下當(dāng)前代碼分配位置,這是while的do中的語句的開始位置 gen(JPC,0,0); if(sym ==DOSYM) getsym(); else error(18); statement(fsys,tx,lev); gen(JMP,0,cx1); code[cx2].a= cx;} else if(sym == REPEATSYM){ symset temp1, temp2; temp1= fsys,temp1.insert(SEMICOLON),temp1.insert(UNTILSYM); cx1= cx; getsym(); statement(temp1,tx,lev); temp2 = statbegsys; temp2.insert(SEMICOLON); while(temp2.find(sym)!= temp2.end()) { if(sym == SEMICOLON) getsym(); else error(34); statement(temp1,tx,lev); } if(sym == UNTILSYM) { getsym(); condition(fsys,tx,lev); gen(JPC,0,cx1); } else error(34); } symset setT;test(fsys,setT,19);}//statement end // 表達(dá)式處理 void PL0::expression(symset fsys,int tx,int lev){ symbol addop;symset tmp=fsys;for(int t=PLUS;t<=MINUS;t++) tmp.insert((symbol)t);if(sym>=PLUS&&sym<=MINUS){ addop= sym; getsym(); term(tmp,tx,lev); if(addop ==MINUS) gen(OPR,0,1);} else term(tmp,tx,lev);while(sym >=PLUS&&sym<=MINUS){ addop= sym; getsym(); term(tmp,tx,lev); if(addop ==PLUS) gen(OPR,0,2); else gen(OPR,0,3);} }// expression end // 項(xiàng)處理 void PL0::term(symset fsys,int tx,int lev){ if(sourceEnd) return;symbol mulop;symset tmp=fsys;for(int t=TIMES;t<=SLASH;t++) tmp.insert((symbol)t);factor(tmp,tx,lev);while(sym>=TIMES && sym<=SLASH){ mulop= sym; getsym(); factor(tmp,tx,lev); if(mulop ==TIMES) gen(OPR,0,4); else gen(OPR,0,5);} }// term end // 因子處理 void PL0:: factor(symset fsys,int tx,int lev){ int i;test(facbegsys,fsys,24);while(facbegsys.find(sym)!=facbegsys.end()){ if(sym ==IDENT) { i= position(id,tx); if(i == 0) error(11); else switch(table[i].kind) { case CONSTANT: gen(LIT,0,table[i].other.val); break; case VARIABLE: gen(LOD,lev-table[i].other.inOther.level,table[i].other.inOther.adr); break; case PROCEDURE: error(21); break; } getsym(); } else if(sym ==NUMBER) { if(num>amax) { error(31); num= 0; } gen(LIT,0,num); getsym(); } else if(sym ==LPAREN) { getsym(); symset tmp=fsys; tmp.insert(RPAREN); expression(tmp,tx,lev); if(sym == RPAREN) getsym(); else error(22); } test(fsys,facbegsys,23);} }//factor end // 條件處理 void PL0::condition(symset fsys,int tx,int lev){ symbol relop;symset tmp=fsys;tmp.insert(EQL),tmp.insert(NEQ),tmp.insert(LSS),tmp.insert(LEQ),tmp.insert(GTR),tmp.insert(GEQ); if(sym == ODDSYM){ getsym(); expression(fsys,tx,lev); gen(OPR,0,6);} else { expression(tmp,tx,lev); if(tmp.find(sym)==tmp.end()) error(20); else { relop= sym; getsym(); expression(fsys,tx,lev); switch(relop) { case EQL: gen(OPR,0,8); break; case NEQ: gen(OPR,0,9); break; case LSS: gen(OPR,0,10); break; case GEQ: gen(OPR,0,11); break; case GTR: gen(OPR,0,12); break; case LEQ: gen(OPR,0,13); break; } } } }//condition end // 對目標(biāo)代碼的解釋執(zhí)行程序 void PL0::interpret(){ int err1=errorString.size();if(err1>0){ cout<<”存在%d個(gè)錯(cuò)誤:“< cout< t= t+1; s[t]= i.a; break;case OPR: switch(i.a)//operator { case 0:// return t= b-1; p= s[t+3]; b= s[t+2];break;case 1: s[t]=-s[t];break;case 2: t= t-1;s[t]= s[t]+s[t+1];break;case 3: t= t-1;s[t]= s[t]-s[t+1];break;case 4: t= t-1;s[t]= s[t]*s[t+1];break;case 5: t= t-1;s[t]= s[t] / s[t+1];break;case 6: if(s[t]%2) s[t]=1;else s[t]=0;break;case 8: t= t-1;if(s[t]==s[t+1]) s[t]=1;else s[t]=0;break;case 9: t= t-1;if(s[t]==s[t+1]) s[t]=0;else s[t]=1;break; case 10: t= t-1;if(s[t] s[t]=1;else s[t]=0;break;case 11: t= t-1;if(s[t]>=s[t+1]) s[t]= 1;else s[t]=0;break;case 12: t= t-1;if(s[t]>s[t+1]) s[t]= 1;else s[t]=0;break;case 13: t= t-1;if(s[t]<=s[t+1]) s[t]= 1;else s[t]=0;break;case 14: cout<<”“< t= t+1; s[t]= s[base(i.l,b,s)+i.a]; break; case STO: s[base(i.l,b,s)+i.a]= s[t]; t= t-1; break; case CAL:// generate new block mark s[t+1]= base(i.l,b,s); s[t+2]= b; s[t+3]= p; b= t+1; p=i.a; break; case INT: t= t+i.a; break; case JMP: p= i.a; break; case JPC: if(s[t] == 0) p= i.a; t= t-1; break; }//switch end }while(p!=0); cout<<” End PL/0n“;} // interpret end // 通過靜態(tài)鏈求出數(shù)據(jù)區(qū)的基地址 int PL0::base(int l,int b,int s[]){ int b1;b1= b;//find base l levels down while(l>0){ b1= s[b1]; l= l-1;} return b1;} // 保存代碼 void PL0::SaveCode(){ if(fout) for(int i=0;i fprintf(fout,”%d %s %d %dn “,i,mnemonic[code[i].f],code[i].l,code[i].a);} TestPL0.cpp代碼: #include ”pl0.h“ void main(){ PL0 cp(”testPas2.txt“,”nasm.txt"); symset fsys; fsys.insert(PERIOD);fsys.insert(CONSTSYM),fsys.insert(VARSYM),fsys.insert(PROCSYM);fsys.insert(BEGINSYM),fsys.insert(CALLSYM),fsys.insert(IFSYM),fsys.insert(WHILESYM);cp.getsym(); // 詞法分析,分析一個(gè)詞 cp.block(0,0,fsys); // 分程序分析處理功能 cp.SaveCode(); // 保存代碼 cp.interpret(); // 對目標(biāo)代碼的解釋執(zhí)行程序 } 實(shí)驗(yàn)運(yùn)行結(jié)果: 運(yùn)行的的文件見下圖右側(cè):實(shí)驗(yàn)中我是固定了文件名的,可以是改寫成動(dòng)態(tài)輸入,由于在測試中我把所有的測試語句都放在同一個(gè)文件中了,沒有太多的必要。 六、心得體會(huì) 在編譯程序?qū)崿F(xiàn)的過程中反復(fù)使用了遞歸調(diào)用的思想,且也使用了模塊化處理問題的思想,使用模塊化的思想關(guān)鍵是在抽象階段要抽象出對應(yīng)的模塊,且模塊的層次必須是清晰的。 在實(shí)現(xiàn)此程序中,由于要實(shí)現(xiàn)關(guān)鍵字和符號表中字段的搜索,實(shí)現(xiàn)中就必須注意快速查找的方法,而在實(shí)現(xiàn)的過程中多次用到了二分搜索的方法,這是個(gè)比較快的搜索方法。 由于此程序的實(shí)現(xiàn)相對比較復(fù)雜,且不方便調(diào)試,改進(jìn)時(shí)可以把此程序的詞法分析,語法分析和執(zhí)行原代碼作為單獨(dú)的測試程序來測試,這樣也方便大家來調(diào)試。 通過本次的課設(shè)我知道了一個(gè)算法的設(shè)計(jì)是需要靜下心來仔細(xì)的研究的,且實(shí)現(xiàn)中必須先了解程序的整個(gè)流程,也就是說在編程中首先必須看懂那些對應(yīng)的UML圖,只有在圖的指導(dǎo)下,編程中才不會(huì)盲目,也有一定的方向性。同樣在編程中必須注意代碼的規(guī)范,多寫一些對應(yīng)的注釋是很必要的,要時(shí)刻想這代碼并不是給你自己看的,而是必須要給別人看,因此我覺得代碼的規(guī)范是相當(dāng)重要的。>s[t];break;};break;case LOD: