摘要:針對(duì)編譯原理教學(xué)實(shí)際,在分析和修改工業(yè)級(jí)開(kāi)源編譯器實(shí)現(xiàn)代碼的基礎(chǔ)上,提出一個(gè)基于Java的編譯原理課程案例教學(xué)過(guò)程,結(jié)合Java這種日益普及的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言,這種教學(xué)過(guò)程在編譯原理課程教學(xué)方面取得良好效果。
關(guān)鍵詞:Java字節(jié)碼;Java類(lèi)文件;Javac;Java編譯器;編譯原理
編譯原理是計(jì)算機(jī)與軟件專(zhuān)業(yè)的核心基礎(chǔ)課程,是關(guān)聯(lián)匯編語(yǔ)言程序設(shè)計(jì)、高級(jí)語(yǔ)言程序設(shè)計(jì)等相關(guān)課程的紐帶。如何深入進(jìn)行編譯原理課程教學(xué)改革,更好地幫助學(xué)生理解和掌握編譯器的設(shè)計(jì)原理與基本實(shí)現(xiàn)方法,更好地在教學(xué)過(guò)程中體現(xiàn)計(jì)算機(jī)軟件核心思想,更好地依托一個(gè)載體緊密結(jié)合工程實(shí)踐與理論研究,是新時(shí)期編譯原理課程教學(xué)面臨的挑戰(zhàn)。
1案例教學(xué)在編譯原理中的作用
1.1編譯原理課程的內(nèi)容組織
編譯原理在軟件學(xué)科中占據(jù)核心位置,起著重要作用。編譯原理包括詞法分析、語(yǔ)法分析、語(yǔ)義分析和中間代碼生成、代碼優(yōu)化、運(yùn)行時(shí)存儲(chǔ)組織等[1]。除了上述基本知識(shí)點(diǎn)外,了解編譯原理在現(xiàn)實(shí)世界中的廣泛應(yīng)用,知道編譯器在計(jì)算機(jī)與軟件專(zhuān)業(yè)課程體系中的關(guān)鍵地位,是激發(fā)學(xué)生認(rèn)真學(xué)習(xí)和掌握本門(mén)課程基礎(chǔ)知識(shí)及專(zhuān)業(yè)工具的有效手段。
1.2案例教學(xué)的作用
為了更有效地組織編譯原理課程的教學(xué)工作,避免傳統(tǒng)式教育存在的“重基礎(chǔ)、輕實(shí)踐”的弊端[2],針對(duì)新時(shí)期研究型大學(xué)本科生的特點(diǎn),我們提出了如下基于主流編譯器的編譯原理課程案例教學(xué)方法:先讓學(xué)生對(duì)編譯原理課程的教學(xué)載體,即一個(gè)較為完整的編譯器,建立初步認(rèn)識(shí),再借助學(xué)生較強(qiáng)的自學(xué)能力和動(dòng)手能力,在實(shí)踐中學(xué)習(xí)和體會(huì)程序設(shè)計(jì)語(yǔ)言編譯過(guò)程的基本原理,切實(shí)保證理論聯(lián)系實(shí)踐,尤其是強(qiáng)調(diào)“學(xué)中練、練中學(xué);練中闖、練中創(chuàng)”[3]。首先讓學(xué)生了解一個(gè)典型編譯器的輸入和輸出,同時(shí)通過(guò)圖形化方式使得學(xué)生對(duì)編譯過(guò)程的主要階段建立感性認(rèn)識(shí);進(jìn)而熟悉作為課程載體的一個(gè)編譯器原型,并對(duì)其進(jìn)行改造;最終達(dá)到學(xué)習(xí)編譯原理基礎(chǔ)知識(shí),并對(duì)規(guī)范化程序設(shè)計(jì)有所深入理解的目的。
2基于Java的編譯原理案例實(shí)驗(yàn)設(shè)計(jì)
作為一個(gè)主流的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言,Java已經(jīng)占據(jù)了近20%的份額[4],在計(jì)算機(jī)網(wǎng)絡(luò)等應(yīng)用中起著越來(lái)越重要的作用,不僅覆蓋了從大型網(wǎng)絡(luò)應(yīng)用系統(tǒng)開(kāi)發(fā)到SIM卡芯片上的認(rèn)證程序等大量應(yīng)用,而且保持著強(qiáng)勁的發(fā)展勢(shì)頭。鑒于此,本課程考慮基于Java的編譯原理案例教學(xué)。
2.1實(shí)驗(yàn)設(shè)計(jì)
基于Java的編譯原理實(shí)驗(yàn)包括了解實(shí)驗(yàn)?zāi)繕?biāo)和進(jìn)行具體實(shí)驗(yàn)操作兩階段。實(shí)驗(yàn)?zāi)繕?biāo)包括源、目的和轉(zhuǎn)換過(guò)程三部分,分別涉及對(duì)源語(yǔ)言(Java程序設(shè)計(jì)語(yǔ)言)的理解,對(duì)目標(biāo)語(yǔ)言(Java類(lèi)文件,包括Java字節(jié)碼)的理解,和對(duì)編譯過(guò)程的理解。鑒于前導(dǎo)課程Java語(yǔ)言程序設(shè)計(jì)已充分介紹了Java源程序,本課程主要介紹后兩部分。
具體的實(shí)驗(yàn)操作可以細(xì)分三個(gè)層面。一為使用現(xiàn)有詞法器/語(yǔ)法器的自動(dòng)生成工具(如JLex、CUP)實(shí)現(xiàn)一個(gè)Java編譯器,二為依據(jù)編譯原理的基礎(chǔ)理論手工設(shè)計(jì)實(shí)現(xiàn)一個(gè)Java編譯器,三為構(gòu)造詞法器/語(yǔ)法器等程序的自動(dòng)生成工具,并基于這些工具實(shí)現(xiàn)Java編譯器??筛鶕?jù)具體教學(xué)情況側(cè)重某一層面。
2.2Java類(lèi)文件的講授
Java類(lèi)文件包含常量池、接口表、域表、方法表和屬性表等信息。Java字節(jié)碼是Java類(lèi)文件的關(guān)鍵組成部分,字節(jié)碼序列出現(xiàn)在方法的Code屬性項(xiàng)中。為了讓學(xué)生了解Java源程序的編譯過(guò)程,并掌握J(rèn)ava類(lèi)文件的結(jié)構(gòu),采用如下案例。首先給出一個(gè)簡(jiǎn)單的Java源文件然后將上述文件編譯為Java類(lèi)文件,并通過(guò)“javap –c Act”命令展示對(duì)應(yīng)的字節(jié)碼序列,并向?qū)W生予以講解。接著,按十六進(jìn)制打印輸出Act.class文件(如圖1所示),并在課堂上作為補(bǔ)充材料發(fā)給學(xué)生。
進(jìn)一步地,我們通過(guò)一個(gè)Java Applet程序(如圖2所示)向?qū)W生逐步展示Java虛擬機(jī)是如何以流的方式單步裝載圖1中的Java類(lèi)文件的[5]150,并在補(bǔ)充材料上予以標(biāo)注學(xué)習(xí)。
2.3Java編譯過(guò)程的圖形化展示
在講解編譯過(guò)程時(shí),充分考慮以圖形化方法展示關(guān)鍵步驟,使學(xué)生們能夠首先建立感性認(rèn)識(shí),進(jìn)而研討具體的編譯算法并為此制作一些演示程序。例如,我們通過(guò)prefuse工具,制作了從源程序到詞法單元(token)流的映射過(guò)程。對(duì)于輸入的一段Java源程序,可以形象地以樹(shù)的方式展示其對(duì)應(yīng)的token集合。如圖3所示,對(duì)應(yīng)左側(cè)窗口的一個(gè)Java源程序,在右側(cè)窗口出現(xiàn)一個(gè)詞法單元序列。除了注釋符和空白符號(hào)外,源文件中的每個(gè)詞素都對(duì)應(yīng)一個(gè)詞法單元,包括詞法單元名字和屬性值。
在語(yǔ)法分析過(guò)程中,也通過(guò)可視化的方式將一個(gè)語(yǔ)句塊及其對(duì)應(yīng)的樹(shù)狀結(jié)構(gòu)予以形象表達(dá)。如圖4所示,對(duì)應(yīng)左側(cè)的一個(gè)語(yǔ)句塊,在右側(cè)以圖形化的方式表達(dá)出一個(gè)樹(shù)狀結(jié)構(gòu)。
3基于Java的編譯原理案例教學(xué)實(shí)踐
為了更好地講授編譯器的設(shè)計(jì)與實(shí)現(xiàn),以一個(gè)設(shè)計(jì)良好的工業(yè)級(jí)編譯器Javac為課程案例,展示編譯器的設(shè)計(jì)原理與實(shí)現(xiàn)方法。課堂上剖析的對(duì)象是OpenJDK中的Javac編譯器[6]。
3.1Javac的結(jié)構(gòu)及特點(diǎn)
OpenJDK中的編譯器Javac包括137個(gè)java文件。其重要的類(lèi)和包如表1所示。
Javac使用的是LL(1)遞歸下降分析方法,同時(shí)使用算符優(yōu)先分析方法對(duì)二元運(yùn)算表達(dá)式進(jìn)行分析。Javac具有模塊清晰、代碼風(fēng)格統(tǒng)一、注釋完善等優(yōu)點(diǎn),并且使用了大量典型的設(shè)計(jì)模式。
當(dāng)然,Javac編譯器的源代碼也存在一些不足,例如沒(méi)有充分應(yīng)用代碼優(yōu)化技術(shù)。但是,考慮到本科編譯原理教學(xué)的重點(diǎn)一般是詞法分析和語(yǔ)法分析,使用Javac在現(xiàn)階段還是可行的。此外,學(xué)生可以通過(guò)其它方式來(lái)學(xué)習(xí)和掌握一定的代碼優(yōu)化技術(shù)。
3.2Javac的教學(xué)實(shí)踐
在詞法分析階段,學(xué)生的任務(wù)是分析輸入的Java源程序并生成對(duì)應(yīng)的token流。在語(yǔ)法分析階段,學(xué)生的任務(wù)是用CUP工具生成LALR(1)語(yǔ)法分析器,并將其集成入Javac。其關(guān)鍵步驟是在com.sun.tools. javac.parser.ParserFactory中重寫(xiě)newParser方法,實(shí)現(xiàn)語(yǔ)法分析器的替換。具體如下所示:
public Parser newParser(CharSequencein