?1.程序的解釋執行方式
程序語言強寫的計策機指令序列稱為“源程序”,計算機并不能直接執行用高級語言編寫的源程序,源程序必須通過“翻譯程序”翻譯成機器指令的形式,計算機才能項別和執行。源程序的翻譯有兩種方式:解釋執行和編譯執行。不同的程序語言,有不同的翻譯程序,這些翻譯程序稱為程序解釋器(也稱為虛擬機)或程序編譯器(簡稱為編譯器)。
1)程序的解釋執行過程
解釋程序的工作過程如下:首先,由語言解釋器(如Python)進行初始化準備工作。然后語言解釋器從源程序中讀取一個語句(指令),并對指令進行語法檢查,如果程序語法有錯,則輸出錯誤信息;否則,將源程序語句翻譯成機器執行指令,并執行相應的機器操作。返回后檢查解釋工作是否完成,如果未完成,語言解釋器繼續解釋下一語句,直至整個程序執行完成。否則,進行必要的善后處理工作。
語言解釋器一般包含在開發軟件或操作系統內,如IE瀏覽器帶有.Net腳本語言解釋功能;也有些語言解釋器是獨立的,如Python解釋器就包含在Python軟件包中。
2)解釋程序的特點
解釋程序的優點是實現簡單,交互性較好。動態程序語言(如Python、PHP、JavaScript、R、MATLIB等)一般采用解釋執行方式。
解釋程序有以下缺點:一是程序運行效率低,如源程序中出現循環語句時,解釋程序也要重復地解釋并執行這一組語句;二是程序的獨立性不強,不能在操作系統下直接運行,因為操作系統不一定提供這個語言的解釋器;三是程序代碼保密性不強,例如,要發布Python開發項目,實際上就是發布Python源代碼。
?2.程序的編譯執行方式
程序員編寫好源程序后,由編譯器將源程序翻譯成計算機可執行的機器代碼。程序編譯完成后就不再需要再次編譯了,生成的機器代碼可以反復執行。
源程序編譯是一個復雜的過程,這一過程分為以下步驟:源程序→預處理→詞法分析→語法分析→語義分析→生成中間代碼→代碼優化→生成目標程序→程序連接→生成可執行程序。事實上,某些步驟可能組合在一起進行。
在編譯過程中,源程序的各種信息被保存在不同表格里,編譯工作的各個階段都涉及構造、查找或更新有關表格。如果編譯過程中發現源程序有錯誤,編譯器會報告錯誤的性質和發生錯誤的代碼行,這些工作稱為出錯處理。
1)預處理
一個源程序有時可能分成幾個模塊存放在不同的文件里,預處理的工作之一是將這些源程序匯集到一起;其次,為了加快編譯速度,編譯器往往需要提前對一些頭文件及程序代碼進行預處理,以便在源程序正式編譯時節省系統資源開銷。例如,C語言的預處理包括文件合并、宏定義展開、文件包含、條件編譯等內容。
2)詞法分析
編譯器的功能是解釋程序文本的語義,不幸的是計算機很難理解文本,文本文件對計算機來說就是字節序列,為了理解文本的含義,就需要借助詞法分析程序。詞法分析是將源程序的字符序列轉換為標記(Token)序列的過程。詞法分析的過程是編譯器一個字符一個字符地讀取源程序,然后對源程序字符流進行掃描和分解,從而識別出一個個獨立的單詞或符號(分詞)。在詞法分析過程中,編譯器還會對標記進行分類。
單詞是程序語言的基本語法單位,一般有四類單詞:一是語言定義的關鍵字或保留字(如if、for等);二是標識符(如x、i、list等);三是常量(如0、3.14159等);四是運算符和分界符(如十、一、*、/、=、;等)。如何進行“分詞”是詞法分析的重要工作。
3)語法分析
語法分析過程是把詞法分析產生的單詞,根據程序語言的語法規則,生成抽象語法樹(AST),語法樹是程序語句的樹形結構表示,編譯器將利用語法樹進行語法規則分析。語法樹的每一個節點都代表著程序代碼中的一個語法結構,例如包、類型、標識符、表達式、運算符、返回值等。后續的工作是對抽象語法樹進行分析。
符號表是由一組符號地址和符號信息構成的表格。符號表中登記的信息在編譯的不同階段都要用到。在語法分析中,符號表登記的內容將用于語法分析檢查;在語義分析中,符號表所登記的內容將用于語義檢查和產生中間代碼;在目標代碼生成階段,當對符號名進行地址分配時,符號表是地址分配的依據。
4)語義分析
語義分析是對源程序的上下文進行檢查,審查有無語義錯誤。語義分析主要任務有靜態語義審查、上下文相關性審查、類型匹配審查、數據類型轉換、表達式常量折疊等。
源程序中有些語句按照語法規則判斷是正確的,但是它不符合語義規則。例如,使用了沒有聲明的變量;或者對一個過程名賦值;或者調用函數時參數類型不合適;或者參加運算的兩個變量類型不匹配等。當源程序不符合語言規范時,編譯器會報告出錯信息。
表達式常量折疊就是對常量表達式計算求值,并用求得的值來替換表達式,放入常量表。例如,s=1+2折疊之后為常量3,這也是一種編譯優化。
5)生成中間代碼
語義分析正確后,編譯器會生成相應的中間代碼。中間代碼是一種介于源程序和目標代碼之間的中間語言形式,它的目的是:便于后面做優化處理,便于程序的移植。中間代碼常見形式有四元式、三元式、逆波蘭表達式等。由中間代碼很容易生成目標代碼。
6)代碼優化
代碼優化的目的是為了得到高質量的目標程序。
7)生成目標程序
生成目標程序不僅與編譯技術有關,而且與機器硬件結構關系密切。例如,充分利用機器的硬件資源,減少對內存的訪問次數;根據機器硬件特點(如多核CPU)調整目標代碼,提高執行效率。生成目標程序的過程實際上是把中間代碼翻譯成匯編指令的過程。
8)鏈接程序
目標程序還不能直接執行,因為程序中可能還有許多沒有解決的問題。例如,源程序可能調用了某個庫函數等。鏈接程序的主要工作就是將目標文件和函數庫彼此連接,生成一個能夠讓操作系統執行的機器代碼文件(軟件)。
9)生成可執行程序(機器代碼)
機器代碼生成是編譯過程的最后階段。機器代碼生成不僅僅需要將前面各個步驟所生成的信息(語法樹、符號表、目標程序等)轉化成機器代碼寫入到磁盤中,編譯器還會進行少量的代碼添加和轉換工作。經過上述過程后,源程序最終轉換成可執行文件了。
?3.程序編譯失敗的主要原因
完美的程序不會一次就寫成功,都需要經過反復修改、調試和編譯。Google和香港科技大學的研究人員分析了Google工程師的2600萬次編譯,分析了編譯失敗的常見原因:一是編譯失敗率與編譯次數、開發者經驗無關;二是大約65%的Java編譯錯誤與依賴有關,如編譯器無法找到一個符號(占編譯錯誤的43%),或者是包文件不存在;在C++編譯中,53%的編譯錯誤是使用了未聲明的標識符和不存在的類變量。