第二章 Javac編譯原理

来源:http://www.cnblogs.com/java-zhao/archive/2016/02/17/5194064.html
-Advertisement-
Play Games

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


註:本文主要記錄自《深入分析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會在我們寫代碼的時候為我們自動去檢查,包括檢查語句是否可達,但是瞭解這些還是有好處的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 環境 Badboy version 2.1.1 JDK: 1.7.0_67 Apache JMeter-2.11 ---------------------------------------------------------------------------------------------
  • 給出一個整數n(n<=2000)(代碼可適用n<=10^31)和k個變換規則(k<=15)。 規則:1、1個數字可以變換成另1個數字; 2、規則中右邊的數字不能為零。 BFS 1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 1000
  • 思路: 用迴圈提取最裡面的括弧,再進行運算 運算時利用正則表達式尋找相應的運算符 先進行乘除,再進行加減 (參考武sir和金角大王的代碼) 流程圖: 代碼: 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import re 4 def chen
  • C語言數據結構之棧:中綴表達式的計算
  • 安裝環境: CentOS release 6.3 (Final) about 64bit cpu 1, http://www.oracle.com下載最新版的javase的jdk環境 比如我下載的是:jdk-8u73-linux-x64.tar.gz 2,上傳到 /usr/java下 3,tar -
  • public static void main(String[] args) { Integer i1 = new Integer(1); Integer i2 = new Integer(1); // i1,i2分別位於堆中不同的記憶體空間 System.out.println("i1 == i2:
  • 引用計數 Python預設的垃圾收集機制是“引用計數”,每個對象維護了一個ob_ref欄位。它的優點是機制簡單,當新的引用指向該對象時,引用計數加1,當一個對象的引用被銷毀時減1,一旦對象的引用計數為0,該對象立即被回收,所占用的記憶體將被釋放。它的缺點是需要額外的空間維護引用計數,不過最主要的問題是
  • session原理,session如何存儲,如何使用redis/分散式文件系統/資料庫存儲session,負載均衡中如何解決session不一致問題
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...