1. 程式人生 > >第二章 Javac編譯原理

第二章 Javac編譯原理

注:本文主要記錄自《深入分析java web技術內幕》"第四章 javac編譯原理"

1、javac作用

  • 將*.java原始碼檔案轉化為*.class檔案

2、編譯流程

流程:

  • 詞法分析器:將原始碼轉換為Token流
    • 將原始碼劃分成一個個Token(Token包含的元素型別看3.2)
  • 語法分析器:將Token流轉化為語法樹
    • 將上述的一個個Token組成一句句話(或者說成一句句程式碼塊),檢查這一句句話是不是符合Java語言規範
  • 語義分析器:將語法樹轉化為註解語法樹
    • 將複雜的語法轉化成簡單的語法(eg.註解、foreach轉化為for迴圈)並做一些檢查,新增一些程式碼
  • 程式碼生成器:將註解語法樹轉化為位元組碼

3、詞法分析

3.1、作用

  • 將原始碼轉換為Token流。

3.2、流程

一個位元組一個位元組的讀取原始碼,形成規範化的Token流。規範化的Token包含:

  • java關鍵詞:package、import、public、class、int等
  • 自定義單詞:包名、類名、變數名、方法名
  • 符號:=、;、+、-、*、/、%、{、}等

3.3、示例

程式碼:

1 package compile;
2 
3 /**
4  * 詞法
5  */
6 public class Cifa {
7     int
a; 8 int c = a + 1; 9 }
View Code

以上程式碼轉化為的Token流:

說明:完成以上示例的是JavacParser的parseCompilationUnit()方法,原始碼見文章開頭的書籍。

注意:上邊的token流符合java語言規範

3.4、疑問

  • 怎樣判斷package是java關鍵詞還是自定義變數?
    • JavacParser會根據java語言規範來控制什麼順序、什麼地方出現什麼Token(這個檢視parseCompilationUnit()原始碼就知道了),所以package在檔案的最開頭出現,我們會知道是一個Token.PACKAGE型別,而非自定義的Token.IDENTIFIER型別。
    • 一條實踐:在編寫程式的時候,不要用java關鍵詞來定義變數名、類名、包名、方法名,而是採取一定有意義的單詞來定義,當然,你再eclipse中編寫程式碼的時候,如果使用了java關鍵詞來定義變數,eclipse會提醒你這是一個錯誤的定義。
  • 怎樣確定package是一個Token,而packa不是?
    • 我的理解是,主要看空格和符號(符號見3.2),對於package是一個單詞,中間沒有空格也沒有符號,所以是一個Token
    • 一條實踐:在編寫程式碼時,例如:int a = b + c;//a與=中間有一個空格、=與b之間有一個空格、b與+之間有一個空格、+與c之間有一個空格,當然,這裡沒有空格也行,因為每一個變數之間正好都是由符號來隔開的,但是之前看了一個視訊說,如果上邊這句話沒有這些空格的話,可能編譯不通過,所以我們最好還是加上空格,當然加上空格後顯得整個程式碼也清晰

4、語法分析

4.1、作用

  • 將進行詞法分析後形成的Token流中的一個個Token組成一句句話,檢查這一句句話是不是符合Java語言規範。

4.2、語法分析三部分:

  • package
  • import
  • 類(包含class、interface、enum),一下提到的類泛指這三類,並不單單是指class

4.3、示例

程式碼:

 1 package compile;
 2 
 3 /**
 4  * 語法
 5  */
 6 public class Yufa {
 7     int a;
 8     private int c = a + 1;
 9     
10     //getter
11     public int getC() {
12         return c;
13     }
14     //setter
15     public void setC(int c) {
16         this.c = c;
17     }
18 }
View Code

最終語法樹:

說明:

  • 每一個包package下的所有類都會放在一個JCCompilationUnit節點下,在該節點下包含:package語法樹(作為pid)、各個類的語法樹
  • 每一個從JCClassDecl發出的分支都是一個完整的程式碼塊,上述是四個分支,對應我們程式碼中的兩行屬性操作語句和兩個方法塊程式碼塊,這樣其實就完成了語法分析器的作用:將一個個Token單片語成了一句句話(或者說成一句句程式碼塊)
  • 在上述的語法樹部分,對於屬性操作部分是完整的,但是對於兩個方法塊,省略了一些語法節點,例如:方法修飾符public、方法返回型別、方法引數。

疑問:

import節點的語法樹與package的相似,但是import語法樹放在了哪一個地方?

5、語義分析

5.1、作用

  • 將語法樹轉化為註解語法樹

5.2、步驟

  • 新增預設的無參構造器(在沒有指定任何有參構造器的情況下
  • 處理註解
  • 標註:檢查語義合法性、進行邏輯判斷
    • 檢查語法樹中的變數型別是否匹配(eg.String s = 1 + 2;//這樣"="兩端的型別就不匹配)
    • 檢查變數、方法或者類的訪問是否合法(eg.一個類無法訪問另一個類的private方法)
    • 變數在使用前是否已經宣告、是否初始化
    • 常量摺疊(eg.程式碼中:String s = "hello" + "world",語義分析後String s = "helloworld")
    • 推導泛型方法的引數型別
  • 資料流分析
    • 變數的確定性賦值(eg.有返回值的方法必須確定有返回值)
    • final變數只能賦一次值,在編譯的時候再賦值的話會報錯
    • 所有的檢查型異常是否丟擲或捕獲
    • 所有的語句都要被執行到(return後邊的語句就不會被執行到,除了finally塊兒)
  • 進一步語義分析
    • 去掉永假程式碼(eg.if(false))
    • 變數自動轉換(eg.int和Integer)
    • 去掉語法糖(eg.foreach轉化為for迴圈,assert轉化為if,內部類解析成一個與外部類相關聯的外部類)
  • 最後,將經過上述處理的語法樹轉化為最後的註解語法樹

6、生成位元組碼

6.1、作用

  • 將註解語法樹轉化成位元組碼,並將位元組碼寫入*.class檔案。

6.2、步驟

  • 將java的程式碼塊轉化為符合JVM語法的命令形式,這就是位元組碼
  • 按照JVM的檔案組織格式將位元組碼輸出到*.class檔案中

具體的原始碼與步驟檢視com.sun.tools.javac.jvm.Gen類與《分散式Java應用:基礎與實踐》P42

6.3、class檔案包含的內容

在生成的*.class檔案中不只包含位元組碼資訊,具體包含:

  • 結構資訊
    • class檔案格式版本號
    • 各部分的數量與大小
  • 元資料
    • 類、父類、實現介面的宣告資訊
    • 屬性宣告資訊
    • 方法宣告資訊
    • 常量池
  • 方法資訊
    • 位元組碼
    • 異常處理器表
    • 區域性變數區的大小
    • 運算元棧的大小
    • 運算元棧的型別記錄
    • 除錯用符號資訊

這裡提到的區域性變數區和運算元棧組成了了方法棧,可以參看第一章 JVM記憶體結構

總結:

對於編譯這一塊兒,我們在實際操作中不會直接去操作這些程式碼,不像類載入器機制,我們可能需要自己編寫類載入工具,也不像Java記憶體管理那樣,我們會直接在伺服器配置堆疊方法區空間、配置GC收集器等,但是瞭解javac編譯,對於我們瞭解以後的類檔案結構、類載入機制有一定的幫助,也有利於我們掌握整個Java程式碼的執行流程,對於我們瞭解編譯期間編譯器做的一些檢查工作也有很大幫助,瞭解這些檢查工作有利於我們在寫程式碼的時候更加小心,例如,檢查型異常都需要捕獲或丟擲,每一條語句都要被執行到(即可達)等。雖然,這些工作eclipse會在我們寫程式碼的時候為我們自動去檢查,包括檢查語句是否可達,但是瞭解這些還是有好處的。

相關推薦

第二 Javac編譯原理

注:本文主要記錄自《深入分析java web技術內幕》"第四章 javac編譯原理" 1、javac作用 將*.java原始碼檔案轉化為*.class檔案 2、編譯流程 流程: 詞法分析器:將原始碼轉換為Token流 將原始碼劃分成一個個Token(Token包含的元素型別

Javac 編譯原理

技術 width 開發 pan 安裝 spa 判斷 開發者 開發環境 寫在前面 JDK & JRE JRE(Java Runtime Enviroment)是Java的運行環境。面向Java程序的使用者,而不是開發者。如果你僅下載並安裝了JRE,那麽你的系統只

【第一編譯原理基礎

數組 down 生成 符號表 代碼生成 符號 輸入 必須 高性能 編譯器的結構 主要分為2個部分:分析(analysis)部分和綜合(synthesis)部分 分析部分:源程序分解為多個組成要素,並再要素上加上語法結構,創建一個中間表示,相關信息存入符號表。 綜合部分

Question20180104 對比編譯器、解釋器與Javac編譯原理

即時編譯 inf ali pro 友好 pre 目標 缺點 java、 編譯器與Javac編譯原理   在前文我們知道了Java是一種編譯語言和解釋語言,它的源代碼經過編譯器Javac編譯為能夠被JVM識別的二進制語言,然後JVM將其解釋為能夠被平臺識別的機器語言。那麽什

深入分析 Javac 編譯原理

源碼分析 3.2 inter 計算機 out 詞法分析器 基本 image 包含 通常,一個java文件會通過編譯器編譯成字節碼文件.class,再又java虛擬機JVM翻譯成計算機可執行的文件。 我們所知道的java語言有它自己的語法規範,同樣的JVM也有它的語法規範,如

0day安全:軟體漏洞分析技術 第二 棧溢位原理及實踐

_stdcall呼叫約定下,函式呼叫時用到的指令序列大致如下:push 引數3push 引數2push 引數1call 函式地址;a)向棧中壓入當前指令在記憶體中的位置,即儲存儲存返回地址。b)跳轉到所呼叫函式的入口push ebp 儲存舊棧幀的底部mov ebp,esp 設定新棧幀的底部(棧幀切換)sub

javac編譯原理

每個人在學習Java的時候都配置過環境變數,檢查是否配置成功的時候,我們總會在命令列敲入兩個命令,一個是 java,一個是 javac。剛開始我們都不知道這兩個命令代表的含義,隨著學習的深入,我們知道了 java 命令就是檢查是否找得到執行環境,而 j

第二 CSS工作原理(剖析CSS規則)

  一 簡述:CSS樣式與HTML的關係 第 1 章我們瞭解了怎麼通過 HTML 來建立文件結構。本章,我們來說一說 CSS 規則怎麼為 HTML 新增樣式,並解釋層疊的工作機制——當元素的同一個樣式屬性有多4 種樣式值的時候,CSS 就要靠層疊機制來決定最終應用哪種樣

JAVA虛擬機器(五):Javac編譯原理

1、Javac編譯器的基本結構 Javac主要有4個模組:詞法分析、語法分析、語義分析、程式碼生成。 2、詞法分析 (1)功能:讀取原始檔的字元流,解析出符合Java語言規範的Token序列。 (2)關鍵類: com.sun.tools.javac.pars

現代編譯原理——第二:語法分析之LL(K)

  轉自: http://www.cnblogs.com/BlackWalnut/p/4472122.html   LL(K)語法分析技術是建立在預測分析的技術之上的。我們先來了解預測分析技術。考慮以下文法:         當使用該文法對(1*2-3)+4和(1

編譯原理第二 一個簡單的語法制導翻譯器

一,語法定義         1)文法:對語言結構的定義與描述。即從形式上用於描述和規定語言結構的稱為“文法”(或稱為“語法”),而未 涉及語義問題。                                   例:有一句子:“我是大學生” 。這是一個在語法、語義上

編譯原理-第二 一個簡單的語法指導編譯器-2.4 語法制導翻譯

語法制導翻譯: 定義:語法制導翻譯是通過向一個文法的產生式附加一些規則或程式片段而得到的 功能:給定詞法單元流,通過向一個文法產生式附加一些語義動 作,語法制導分析產生語法分析樹,並實現翻譯動作 相關概念: 屬性:表示與某個程式構造相關的任意的量,因為用文法符號(終結符號或非終結符號)來表示程式構造,所以

【網絡原理】期末復習筆記 第二 物理層

計算機網絡第二章 物理層2.1物理層的基本概念物理層定義:解決如何在連接各種計算機的傳輸媒體上傳輸數據比特流,而不是具體的傳輸媒體。物理層的主要任務為:確定與傳輸媒體的接口的特性機械特性:接口形狀,大小,引線數目功能特性:電壓強度決定信號大小電器特性 :規定電壓範圍過程特性:建立連接時各個相關部件的工作步驟.

編譯原理第一學習(習題解答)

計算機 tran 輸出 fort 容易 工具 諾伊曼 架構 調試 編譯原理 第一章 引論 1.1 練習 1.編譯器和解釋器之間的區別是什麽? 首先,編譯器是一個軟件系統或者說是一個程序,解釋器是語言處理器。其次,編譯器是把程序翻譯成能被計算機執行的形式並報告翻譯過程中發

《呂鑫:VC++6.0就業培訓寶典之MFC視頻教程》學習筆記 -- 第二 MFC原理介紹

第一個 寶典 數據類型 對話 視頻 資源管理 bsp 程序開發 第二章 第二章 MFC原理介紹 2.1 第一個Win32軟件 2.2 Win32對話框程序開發 2.3 程序資源管理和Windows數據類型 2.4 Win32環境下的多對話框管理 2.5 初步學習MFC軟件

第二 並發機制的底層實現原理

帶來 The 集合 場景 實現原理 volatile 前綴 ava 語言 Java代碼在編譯後 編程Java字節碼,字節碼被類加載器加載到JVM裏,JVM執行字節碼,最終需要轉化為匯編指令在CPU上執行,Java中所使用的並發機制依賴於JVM的實現和CPU的指令。 vola

併發程式設計的藝術——第二Java併發機制的底層實現原理

第一節 volatile的應用 定義:Java程式語言允許執行緒訪問共享變數,為了確保共享變數能被準確和一致地更新,執行緒應該確保通過排他鎖單獨獲得這個變數。 為了提高處理速度,處理器不直接和記憶體進行通訊,而是先將系統記憶體的資料讀到內部快取後再進行操作 在多處理器下, 為了保證各個處

網路應用_計算機網路原理第二_自考本科段

概要:計算機網路原理本科段第二章知識點總結 1、網路應用體系結構 識記:網路應用體系結構與分類 (1)網路應用體系結構與分類:計算機網路應用從體系結構角度可分為 客戶/伺服器結構(C/S),純P2P結構(Peer to Peer)、混合結構。   領會:C/S網路應用;

編譯原理 第三 詞法分析(上)

3.1.1 為什麼編譯器要把詞法分析和語法分析分開 3.1.2 詞法單元、模式和詞素(重要)   例:   3.1.3 詞法單元的屬性(重要)   詞法單元的屬性是用來記錄相對應的詞素的一些相關屬性資訊。 例: int x = 10 + 20

編譯原理 第三 詞法分析(下)

3.6 有窮自動機(非常重要) 3.6.1 不確定的有窮自動機(重要) 例:  狀態0是開始狀態, 在狀態0上輸入符號b會進入狀態0,輸入a可能進去狀態0也有可能進入狀態1。所以對於狀態0來說一個確定的輸入符號a他有兩種離開狀態,這就是一種不確定的狀態。   &nbs