
摘要:編譯實習是深入學習和理解編譯原理和技術的重要手段,也是編譯課程的重要組成部分。針對當前計算平臺和系統的迅速演進和發展,北京大學在編譯實習的教學過程中進行創新嘗試,讓學生面向包括智能手機等在內的新型計算平臺開發一個完整的小型編譯器。文章介紹編譯實習課程的創新思路,對北京大學近3年來的實踐情況進行總結分析并提出展望。
關鍵詞:編譯原理;編譯實習;課程創新;移動平臺
0.引言
編譯原理是計算機科學與技術專業本科生的必修課程。國內外高校多年的教學實踐表明,編譯實習是深入理解編譯原理和技術的重要途徑,即所有學生都應該能夠自己動手實現一個面向某個簡單語言或語言子集的小型編譯器。編譯實習可以與編譯原理課程安排在同一個學期,也可以分開。由于編譯原理課程內容較多并且較難,目前北京大學采用的方法是在學生上完編譯原理課程的下一個學期開設編譯實習課程。
我們曾經嘗試過不同的編譯實習題目。例如,在20世紀90年代采用的是面向Pascal語言子集Mini-Pascal的編譯器,后來轉為實現C語言子集Mini-C的編譯器,隨著Java語言的流行,最近幾年改成了面向Java語言子集MiniJava的編譯器。雖然面向的語言不同,但總體目標都是要實現一個相對完整的編譯過程,包括詞法分析、語法分析、語義分析和類型檢查、中間代碼生成、編譯優化、寄存器分配等編譯階段,最后生成面向一種虛擬機的可執行目標代碼,編譯器產生的最終結果可以在虛擬機上執行和驗證。
進入21世紀以來,各種新型計算平臺和環境不斷涌現,特別是在2008年之后,隨著iOS、Android等移動智能計算平臺的流行,許多大學生都擁有了智能手機并熱衷于開發智能手機上的應用。如果能夠讓學生面向包括智能手機在內的新型計算平臺開發自己的編譯器,使生成的目標代碼可以在各種實際的計算機硬件和操作系統上運行,那么會激發學生對計算機技術和編譯技術的更大興趣。
基于此出發點,作為對編譯實習課程的創新探索,我們從2010年起在北京大學設立編譯實習實驗班(以下簡稱實驗班),提出把要實現的編譯器運行平臺從課程提供的虛擬機平臺,轉移到實際的計算機硬件和操作系統平臺上,如Java虛擬機(JVM)、Windows等傳統平臺以及較新的Android、iPhone等智能手機平臺。通過選修實驗班課程,學生可以利用編譯基本原理實現一個在實際平臺上運行的編譯器;也可以選擇面向新的語言實現編譯器或解釋器,如Ruby、Scheme等比較新的語言。另外,在編譯器實現過程中,我們通過數據流分析等技術,實現更深入的編譯優化功能,提高編譯器生成程序的執行效率。
1.設計目標與理念
1.1設計目標
在課程的設計上,實驗班專為編程能力較強、有結合最新計算平臺開發真實編譯器意愿的高年級學生開設。在編譯實習普通班上,我們僅僅要求編譯結果能在模擬器上運行,但這與實際平臺的運行還有一定距離。實驗班要求編譯結果能在最新出現的平臺上運行,如JVM、Android、Iphone/Ipad等,挑戰性更大,收獲也更大。編譯實習課的總體目標是培養學生具有良好的實踐能力,充分發揮學生的主動性和積極性,給學生上講臺的機會,以充分展示自己。
具體來說,實驗班希望學生達到以下主要目標:(1)深入掌握編譯技術并將其應用到編譯器的實現中;(2)深入掌握運行平臺的細節,在使用中得到更好的認識;(3)開闊視野,提高學習計算機科學的興趣愛好;(4)培養合作開發大型軟件能力以及工程實踐能力;(5)培養學生的演講和溝通能力。
1.2設計理念與特色
實驗班的主要目的是把要實現的編譯器的運行平臺從課程提供的虛擬機平臺,轉移到實際的計算機硬件和操作系統平臺上。實踐證明,雖然面向實際應用平臺開發編譯器原型系統挑戰很大,但是這可以在很大程度上提高學生對編譯器開發的興趣,在實際教學中取得很好的效果。通過近3年的實踐,我們打造了擁有以下特色的實驗班課程。
(1)面對新計算平臺不斷出現的特點,結合實際的計算平臺實現可用的編譯器。與普通班采用統一虛擬機作為編譯的目標平臺不同,實驗班要求學生選擇一個實際的計算平臺作為編譯的目標平臺,同時鼓勵學生選擇包括Android、iOS等移動平臺在內的新型計算設備作為編譯的目標平臺。在實踐中,學生對新型平臺非常感興趣,如在2011年的編譯實習實驗板上,4組學生都選擇面向Android平臺開發相應的編譯器。
(2)鼓勵學生自主探索相關領域的最新技術,如新計算平臺技術、新程序分析技術等。由于使用新的平臺需要學習許多新的知識,包括該平臺上的體系結構、目標代碼格式、相應的運行環境等內容,而這些內容無法通過課程講授完全獲得,因此我們鼓勵學生通過閱讀相關技術資料,特別是通過上網查找相應的資料以了解新的計算平臺相關技術。另外,我們也鼓勵學生結合新的計算平臺,采用新的程序分析技術對目標程序進行優化。
(3)鼓勵學生開展項目小組內和項目小組之間的合作。掌握新平臺的知識需要不斷學習,因此我們鼓勵小組內和小組間展開合作,學生在課程內和課程外通過組間交流互通有無,共同進步。例如,Android采用的Dalvik虛擬機上的DEX程序格式比較復雜,各小組之間可以通過分工學習和深入交流提高掌握的效率。學生反映組間的合作讓他們受益頗多。
2.教學實踐情況
從2010年開始的每年秋季學期,我們都在編譯實習課程中鼓勵學有余力的學生參與到實驗班的探索實踐中。3年來,共有37名學生分為17個項目小組參與到不同種類自選題目的實習項目中。2010-2012年實驗班的項目及選題人數見表1。
2.1第1年:初次嘗試自選題目
我們對編譯實習課程的改革嘗試始于2010年,共有5個小組10名學生選擇自選題目的編譯實習項目。首先有一組學生在教師的鼓勵下,嘗試面向JVM實現MiniJava編譯器。這個小組由2名學生組成,編程能力都很強,在跟著普通班上過前面幾次課之后,基本上就能夠自主開發完成面向JVM的MiniJava編譯器,并且最終實現的編譯器效果很好。
我們還與體系結構實習課程的任課教師合作,遴選3組學生面向北京大學自主研制的眾志處理器UniCore實現MiniC的編譯器,不僅要求他們嘗試面向新的平臺開發編譯器,而且還把編譯實習與體系結構實習有機結合在一起,進行有益的探索。
除此之外,我們還推薦學生實現更高級的程序分析技術,一組學生在老師的帶領下,實現了Java程序分析中一種非常重要的新的程序分析技術:污點分析(Taint Analysists)。這組學生通過自己查閱論文,分析現有的Java編譯器(Soot),自主實現污點分析的技術和相應工具,取得了很好的效果。
2.2第2年:移動平臺大受歡迎
從2011年開始,我們加大對實驗班的宣傳力度,共有19名學生參加并分為7組,嘗試開發面向JVM(1組)、Windows(1組)、Android(4組)的MiniJava編譯器,以及面向Unicore的MiniC編譯器(1組)。該年度最大的特點是很多學生對智能手機的應用開發產生濃厚興趣,北京大學有許多學生開發面向Android和iOS平臺的校園智能應用,有12名學生分為4組分別實現了面向Android平臺的MiniJava編譯器,該編譯器主要有以下特色。
(1)Android是一個相對較新的系統,雖然它采用的主要語言是Java,但是卻專門為移動平臺開發了新的Dalvik虛擬機,取代了JVM。JVM字節碼的指令采用的是棧式結構,而Dalvik字節碼采用的是寄存器風格的指令。由于Android系統的資料不是很全,許多信息需要在互聯網上查找,甚至要自己動手嘗試以分析代碼格式,因此對學生來講仍存在較大挑戰。
(2)一般來說,Android智能手機上的應用是一個APK包,其中除了Dalvik字節碼的目標碼格式的可執行文件之外,還有許多其他的輔助文件。要生成合法的可以在智能手機上安裝的應用,還需要在編譯完成之后進行許多復雜繁瑣的收尾工作。
(3)如果不僅可以生成在Android手機上運行的應用,而且還可以讓MiniJava編譯器在Android手機上運行,那就更好了。有一組學生完成了這個看似很具挑戰性的任務,即可以直接在手機上運行編譯器。
總的來說,這一年面向Android開發編譯器的嘗試,不僅對學生是一個挑戰,而且也讓任課教師收獲頗多。由于參與人數比較多,項目主要由學生自主完成,教師期間共組織了多次交流與討論,進行必要的引導與建議。最終的編譯器盡管差異較大,但總體效果非常好,多數學生在完成這個項目后,大大增強了開發大型項目的自信心。
2.3第3年:理性回歸+百花齊放
雖然2011年的嘗試很成功,但是由于參與的學生較多,難以管理,因此我們在2012年對學生的自選題目進行了更為嚴格的篩選,最終有8名學生分別進行了4個不同題目的開發。我們每年都會鼓勵學生選擇新的題目,因此2013年只有一組學生選擇了面向Android平臺的編譯器實現,而其他學生則分別根據自己的興趣選擇了不同的項目。
其中,2名學生在選擇函數式程序設計課程時,對Scheme語言產生濃厚興趣,在教師的鼓勵下,決定嘗試編寫Scheme語言的解釋器。作為一種函數式語言,Scheme的解釋器和C++、Java等命令式語言的編譯過程有較大區別。最開始2名學生作為一個小組,但是由于在項目中期出現實現理念上的沖突,因此2名學生分別實現了2個版本的Scheme解釋器。一個版本的解釋器效率較高,程序執行速度較快;另外一個版本的解釋器功能較強,可以支持更復雜的Scheme語言結構。2名學生都體現出了非常好的基礎素質以及對編譯原理和構造技術的深入理解。
另外2名學生也對Android等移動平臺感興趣,但是卻另辟蹊徑:編譯器的目標不是生成Dalvik虛擬機上執行的APK,而是生成可以在ARM平臺上執行的本地(Native)應用。由于之前還沒有學生嘗試過類似項目,因此還需要調研ARM指令的格式與ARM平臺上Linux相關庫的實現,以便最終實現的MiniJava編譯器可以生成在Android平板電腦上執行的本地程序。
值得一提的是,還有2名學生選擇實現一個支持Ruby語言子集的解釋器。這也是一個很有挑戰的項目,因為Ruby語言較新,資料不完整。2名學生雖然在前期表示出很大的信心和決心,也進行了較為詳細的調研工作,但是由于在中期遇到來自其他項目的壓力,無法投入足夠的時間完成最后的實現工作,很遺憾地選擇了中途退出。這個例子也提醒我們,在課程初期需要更加深入地考察學生的能力和所選擇項目的難度,盡可能提高每個項目的成功率。
經過3年的實踐,我們積累了較多經驗,收到的學生反饋也大多是正面和積極的。我們計劃將實驗班的課程作為一個長期的課程實踐開展下去。目前,2013年秋季的課程也再次列入計劃之中。
3.經驗與挑戰
在課程實踐過程中,我們發現選擇將新出現的計算平臺作為編譯目標平臺,挑戰性比較大。由于平臺新、發展快,資料更新快,教師提供的信息往往也不全面,因此這就要求學生有更強的自主解決問題能力。新計算平臺容易吸引學生,因為許多學生喜歡新技術,他們認為新技術實現空間大,也更能體現自己的能力,還能接受挑戰。這對于激發學生的熱情,釋放學生的創新能力很有意義。然而,在實踐過程中,我們也遇到了一些挑戰和問題。
(1)如何更好地傳承課程經驗?學生在結束開發工作后,都會按照要求提交實習報告,這些報告是課程的寶貴財富。如何充分利用好這些內容,值得我們繼續思考。
(2)如何與普通班進行更好的協調?盡管實驗班的題目與普通班有差異,但有些內容(如詞法、語法分析工具、編譯器的基本框架等)還是很接近的。這就需要我們在內容設置、評價細節等方面進行持續優化。
(3)如何設置更合理的選題?雖然我們鼓勵學生自選題目,但每年還是會在開課初提供一些選題列表,將前幾年的項目題目作為參考發給學生。學生比較容易被新穎的題目吸引,但還是會綜合考慮創新性和難度。
(4)如何更好地發揮教師的作用?對于自身編程能力較強的學生,教師除了為其提供好的題目之外,還應如何給予恰當的幫助?教師指導得好既使學生能夠快速獲取必要的信息而少走彎路,又避免因建議太多而束縛學生的思路。
(5)如何提高評價的客觀程度?盡管主觀評價是主要手段,但增加可行的客觀手段是非常好的補充,尤其對于相同題目,增加在目標碼的執行時間、內存開銷、編譯速度等方面的比較,更能激發學生優化編譯器的熱情。
4.結語
為了適應迅速發展的計算機硬件和系統平臺,我們在北京大學信息科學技術學院編譯實習課程中進行創新探索,并在實踐過程中獲得一些經驗,同時還解決實踐過程中出現的問題,希望能與各高校承擔編譯課程教學任務的教師進行廣泛交流,也希望大家多提寶貴意見。