編譯器的前端中端和后端

前面說的詞法分析語法分析,確實是編譯器前端 (Front End) 最核心的兩個部分。但前端的工作還沒有結束。


編譯器各階段劃分

一個完整的編譯器通常可以分為三個部分:前端、中端 (Middle End)、后端 (Back End)

前端 (Front End)
  • 核心職責: 理解源代碼。它負責處理與源語言 (Source Language) 相關的所有事情。
  • 輸入: 源代碼文件 (e.g., program.c)。
  • 輸出: 中間表示 (Intermediate Representation, IR)。這是一種獨立于具體硬件平臺的、類似于“通用匯編語言”的代碼表示。
  • 主要工作流程:
    1. 詞法分析 (Lexical Analysis): 源代碼 -> Token 序列。
    2. 語法分析 (Syntax Analysis): Token 序列 -> 語法樹 (Syntax Tree)。
    3. 語義分析 (Semantic Analysis): 這是前端的第三個,也是非常重要的一個步驟

“語義分析”屬于前端。

  • 語義分析做什么?
    • 語法分析只管“結構對不對”,不管“意思對不對”。比如 int a = "hello"; 這句話,從語法結構上看(類型 標識符 = 字面量;),是完全正確的。
    • 但從**語義(意思)**上看,它是錯誤的,因為你不能把一個字符串賦值給一個整型變量。
    • 語義分析就是負責檢查這些“意思”層面的錯誤,主要包括:
      • 類型檢查: 運算符兩邊的類型是否匹配?函數調用的參數類型和數量是否正確?
      • 作用域分析: 變量在使用前是否已經聲明?是否存在重復定義的變量?
      • 等等…
    • 語義分析通常會向語法樹中添加額外的信息(比如每個節點的類型),形成一個“帶注解的語法樹”或直接生成中間表示。
中端 (Middle End) / 優化器 (Optimizer)
  • 核心職責: 優化代碼。它在一種獨立于具體機器的層面上,對代碼進行等價變換,讓它運行得更快、占用空間更小。
  • 輸入: 前端生成的中間表示 (IR)
  • 輸出: 優化后的中間表示 (IR)
  • 主要工作:
    • 生成中間代碼: 將語法樹(或帶注解的語法樹)轉換成一種更線性的、類似匯編的中間表示(如三地址碼)。
    • 代碼優化: 這是編譯技術中最復雜、最精華的部分之一。包括但不限于:
      • 刪除無用代碼 (Dead Code Elimination)
      • 常量折疊 (Constant Folding): 比如把 2 + 3 在編譯時直接算成 5
      • 循環優化 (Loop Optimizations)
      • 函數內聯 (Function Inlining)

所以,“生成中間代碼”和“代碼優化”屬于中端。

后端 (Back End)
  • 核心職責: 生成目標代碼。它負責處理與目標機器 (Target Machine) 相關的所有事情。
  • 輸入: (優化后的)中間表示 (IR)
  • 輸出: 目標機器的匯編代碼或機器碼 (e.g., program.s or program.o)。
  • 主要工作:
    1. 指令選擇 (Instruction Selection): 將通用的中間代碼指令,翻譯成特定CPU的指令(比如 x86 的 mov, add 指令)。
    2. 寄存器分配 (Register Allocation): 決定哪些變量應該放在CPU的高速寄存器里,哪些放在內存里。這是一個對性能至關重要的步驟。
    3. 指令調度 (Instruction Scheduling): 調整指令的順序以適應CPU的流水線特性,避免等待。
    4. 最終代碼生成: 輸出匯編代碼或二進制文件。

所以,“生成目標程序”屬于后端。


前端和后端的主要區別 (The “Why”)

這種“前-中-后”三段式的設計是現代編譯器的基石,其最大的好處是解耦 (Decoupling)復用 (Reuse)

  • 前端 (Source-Dependent, Target-Independent)

    • 只關心源語言: C++ 的前端和 Swift 的前端完全不同。
    • 不關心目標機器: C++ 的前端不在乎最終代碼是跑在 Intel CPU 上還是 ARM CPU 上。它只生成一份通用的 IR。
  • 后端 (Source-Independent, Target-Dependent)

    • 不關心源語言: 后端拿到的是通用的 IR,它根本不知道這份 IR 最初是由 C++ 還是 Swift 寫成的。
    • 只關心目標機器: 針對 Intel x86 的后端和針對 ARM 的后端是完全不同的。

這種設計的巨大優勢:
想象一下,我們要支持 M 種編程語言(C++, Swift, Rust, …)和 N 種目標CPU架構(x86, ARM, RISC-V, …)。

  • 如果沒有前后端分離: 我們需要為每一種語言和每一種CPU的組合都寫一個完整的編譯器。總共需要 M * N 個編譯器。
  • 有了前后端分離: 我們只需要為每種語言寫一個前端(共 M 個),為每種CPU寫一個后端(共 N 個)。然后像搭積木一樣,把它們通過統一的中間表示 (IR) 連接起來。總共只需要 M + N 個組件。

這就是像 LLVM 這樣的現代編譯器架構如此成功的原因。Clang 是 C/C++/Objective-C 的前端swiftc 是 Swift 的前端,它們都會生成 LLVM IR。然后,LLVM 提供了強大的中端優化器和針對各種CPU的后端,來完成剩下的工作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96593.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96593.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96593.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

黑馬Java進階教程,全面剖析Java多線程編程,并發和并行,筆記02

黑馬Java進階教程,全面剖析Java多線程編程,并發和并行,筆記02 一、并發和并行 并發:在同一時刻,有多個指令在單個CPU上交替執行 并行:在同一時刻,有多個指令在多個CPU上同時執行 二、為什么有…

20250908 背包DP總結

引子 ~ 我們都有一個家,名字叫背包 ~ 背包DP 顧名思義,背包DP是用來解決背包最值問題的。題目會給出背包的容量,以及幾個物品的屬性,比如重量,價值,限額等等,具體是什么看題目。 01背包 01…

Redis持久化之RDB:快照機制原理、配置與最佳實踐

Redis持久化之RDB:快照機制原理、配置與最佳實踐 1. RDB持久化概述 1.1 什么是RDB RDB(Redis Database)是Redis的默認持久化方式,它在指定的時間間隔內生成數據集的快照(snapshot),并將快照保…

daily notes[44]

文章目錄基礎references基礎 hello,world是幾乎所有編程語言的第一例子,rust也不例外。但和其它語言不一樣,Rust的源碼最好擁有自己的項目目錄。 $ mkdir ~/pro $ cd ~/pro $ mkdir helloWorld $ cd helloWorld源代碼文件名為main.rs,內容如…

JavaScript對象創建方式完全指南:從原始到現代的演進之路

前言 作為一名前端開發者,JavaScript中對象創建是很重要。在JavaScript這門基于原型的語言中,對象幾乎無處不在。今天,我將帶領大家回顧JavaScript對象創建的7種方式,從最原始的字面量到現代的ES6 class,每一步演進都解…

基于單片機的無線水塔監控系統設計(論文+源碼)

本設計為基于單片機的無線水塔監控系統設計,主要由以下幾部分組成:均采用STC89C52RC單片機為主控;主機:NRF24L01無線通訊模塊,1602LCD液晶顯示屏。從機:NRF24L01無線通訊模塊,水位傳感器&#x…

凌晨0-3點不睡,你熬的不是夜,是人生!

“熬夜”這個詞,早已成為現代生活的常態。有人為了工作加班到深夜,有人為了娛樂刷劇到天明,但你知道嗎?熬夜最“要命”的時間段,其實是凌晨0點到凌晨3點。別以為只是少睡幾個小時而已,這個時間段不睡&#…

大語言模型基石:Transformer

一、引言 如今火爆的 GPT、LLaMA、通義千問、ChatGLM 等大語言模型,背后都離不開一個核心架構——Transformer。 2017 年,Google 在論文《Attention Is All You Need》中首次提出 Transformer 模型,徹底改變了自然語言處理的發展方向。它摒…

【算法】【鏈表】160.相交鏈表--通俗講解

算法通俗講解推薦閱讀 【算法–鏈表】83.刪除排序鏈表中的重復元素–通俗講解 【算法–鏈表】刪除排序鏈表中的重復元素 II–通俗講解 【算法–鏈表】86.分割鏈表–通俗講解 【算法】92.翻轉鏈表Ⅱ–通俗講解 【算法–鏈表】109.有序鏈表轉換二叉搜索樹–通俗講解 【算法–鏈表…

MySQL——庫的操作

1、創建數據庫語法:CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name這里的CHARACTER SET表示指定數據庫采用的字符集…

Python ast模塊(Abstract Syntax Trees,抽象語法樹)介紹及使用

文章目錄 核心概念 基本使用流程 常用節點類型 示例代碼 實際應用場景 注意事項 `ast.literal_eval()` 功能說明 適用場景 使用示例 限制與安全特性 與 `eval()` 的對比 總結 Python 的 ast 模塊( Abstract Syntax Trees,抽象語法樹)允許你解析、分析和修改 Python 代碼的…

C++寬度優先搜索算法:隊列與優先級隊列

本期我們就來深入學習一下C算法中一個很重要的算法思想:寬度優先搜索算法 寬度優先算法是一個應用十分廣泛的算法思想,涉及的領域也十分繁多,因此本篇我們先只涉獵它的一部分算法題:隊列/優先級隊列,后續我們會進一步地…

類的property屬性

??Python 中的 property 特性詳解??property 是 Python 中用于??將方法轉換為屬性??的裝飾器,它允許開發者以訪問屬性的方式調用方法,同時可以添加邏輯控制(如數據校驗、計算屬性等)。以下是其核心用法和優勢:…

【Redis#9】其他數據結構

引言 Redis 除了我們最常用的 String、Hash、List、Set、ZSet(Sorted Set) 這五種基本數據結構外,還提供了很多高級或特殊用途的數據結構/類型 ,它們可以滿足更復雜的業務需求。 ? Redis 的“五大基本數據結構”回顧類型特點Stri…

AutoGen——自定義Agent

目錄引子自定義 AgentCountDownAgentArithmeticAgent在自定義 Agent 中使用自定義模型客戶端讓自定義 Agent 聲明式化Selector Group Chat示例:網頁搜索 / 數據分析代理(Agents)Workflow終止條件(Termination Conditions&#xff…

【重定向和轉發的核心理解】

重定向和轉發 不廢話: “轉發” 的核心定義: 服務端內部主導跳轉、客戶端無感知(僅 1 次請求)、瀏覽器 URL 不改變,與傳統 Web 開發中 “轉發” 的本質邏輯完全一致,只是實現載體(Nginx 路由層 …

生成對抗網絡詳解與實現

生成對抗網絡詳解與實現0. 前言1. GAN 原理2. GAN 架構3. 損失函數3.1 判別器損失3.2 生成器損失3.4 VANILLA GAN4. GAN 訓練步驟0. 前言 生成對抗網絡 (Generative Adversarial Network, GAN) 是圖像和視頻生成中的主要方法之一。在本節中,我們將了解 GAN 的架構、…

FPGA硬件開發-XPE工具的使用

目錄 XPE 工具概述? XPE 使用步驟詳解? 1. 工具獲取與初始化? 2. 器件選擇與配置? 3. 電源電壓設置? 4. 資源使用量配置? 5. 時鐘與開關活動配置? 6. 功耗計算與報告生成? 報告解讀與電源設計優化? 常見問題與最佳實踐? 與實際功耗的差異處理? 工具版本…

CentOS 7.9 RAID 10 實驗報告

文章目錄CentOS 7.9 RAID 10 實驗報告一、實驗概述1.1 實驗目的1.2 實驗環境1.3 實驗拓撲二、實驗準備2.1 磁盤準備2.2 安裝必要軟件三、RAID 10陣列創建3.1 創建RAID 10陣列3.2 創建文件系統并掛載3.3 保存RAID配置四、性能基準測試4.1 初始性能測試4.2 創建測試數據集五、故障…