前言
一、什么是編譯器前端
讓機器理解代碼并生成可執行文件 , 這是一件很困難的事情,所以編譯器是一個非常浩大的工程 , 它內部工作過程十分復雜 。
不過計算機科學中有句名言 , 任何一個問題都可以通過增加一個中間層/抽象層來解決,這也是最常用的計算機分層思想 。
All problems in computer science can be solved by another level of indirection. —— David John Wheeler所以為了降低編譯器工程的復雜性,提高發展效率 , 一般把編譯器分為兩個完全解耦的兩個部分
- 編譯器前端 :只負責理解代碼,不考慮各種CPU指令不兼容等問題
- 編譯器后端 :只負責生成可執行文件,不考慮各種語言特性
這樣,兩個部分只需要約定好數據格式,就可以大幅度提高編譯器的發展效率,編譯器整個工作流程也變得非常簡單清晰了,如下圖所示,如果對圖中的編譯器前端不理解沒關系,接下來的 第二節《編譯器前端的原理》 會對這部分進行講解

文章插圖
結論 :所以編譯器前端就是編譯器中的前端部分,負責理解代碼并生成中間語言
二、編譯器前端的原理
既然編譯器前端的工作是理解代碼,那么它的原理是什么呢 , 首先看下面一段簡單的C語言代碼
int age = 18;復制代碼從人類閱讀代碼的角度來看,我們是如何理解上述代碼的呢1、局部理解
- 看到 int 關鍵字
- 看到 age 標識符
- 看到 = 賦值符號
- 看到 18 字面量數值
- 看到 ; 結束符
局部理解的過程,就是詞法分析的過程2、全局理解
通過聯系孤立的、局部的理解結果 , 可得到一個整體 int age = 18 ; , 對其在腦海中進行全局理解后,發現它符合C語言的整型賦值語法
整型賦值語法 -> 關鍵字 標識符 賦值符號 字面量關鍵字 -> int | long標識符 -> [a-zA-Z_]+[a-zA-Z+_*0-9]*字面量 ->[0-9]+復制代碼所以通過全局理解,最終可知道上面代碼是一個整型的賦值語句全局理解的過程,就是語法分析的過程3、總結
結合人類理解代碼的過程,編譯器前端主要可以分為局部理解和全局理解兩個步驟,其中
- 局部理解會生成一個一個的理解結果,稱為Token
- 全局理解會把孤立的token聯系成為一個整體,進行語法規則匹配,如果符合語法則理解成功,否則理解失敗
詞法分析器就是在做對字符序列的局部理解,每完成一次局部理解,就生成一個Token 。常見的Token包括操作符、符號、空白符、關鍵字、標識符、數字、浮點數、字符串、字符等 。
所以詞法分析器的工作內容也比較簡單,只要能把輸入的字符序列,生成一個有序的token列表即可 。
四、詞法分析器的原理
1、直接掃描法
直接掃描法的思路類似二重循環的暴力法,每一輪的掃描都是如下過程
- 先第一層的掃描,根據第一個字符判斷屬于哪種類型的token
- 進入第二層的掃描,向后依次讀?。?直到讀出一個完整的token為止,跳出第二層循環
- 繼續開始第一層的掃描
let end = s.length-1;for(let i=0; i<=end; i=n){ let tokenType = justTokenType(s[i]); switch(tokenType){ case "string": let queue = []; for(let j = i; j<=end-1; ++j){ if(!match){ break; } queue.push(s[j]); } let token = queue.join(''); tokens.push(token); n=j+1; break; }}復制代碼(2) 缺點- 邏輯非常復雜
- 可能存在回溯情況,可能需要記憶已匹配的前N個字符,效率低
- 大量IF判斷 , 可維護性差,擴展性差
DFA即deterministic finite automaton有限狀態自動機 , 其特點是可以實現狀態的自動轉移,可以用于解決字符匹配問題
(1) 核心構成
DFA的核心構成要素是狀態和狀態的轉移
- 定義自動機所具備的N種狀態,并定義初始狀態
- 定義上一個狀態轉移至下一個狀態的條件

文章插圖
(2) 應用實踐
如何用DFA實現詞法分析器呢,步驟如下
- 先定義不同的狀態 :如操作符狀態、數字狀態、符號狀態等
- 再定義狀態轉移條件 :如當前狀態是初始狀態 , 遇到數字則轉移至數字狀態 , 遇到符號則轉移至符號狀態
- 如果字符讀取完成,則整個轉移過程結束
let state = 0; // 當前狀態, 也是初始狀態while ((ch = nextChar()) !== false) { let match = false; // 獲取下一個狀態, 如果下一個狀態不是初始狀態, 則說明匹配成功 let nextState = getNextState(ch, state); if (nextState) { match = true; } // 如果匹配成功, 則字符讀取序列的下標+1,并轉移至下一個狀態 if (match) { incrSeq(); flowtoNextState(ch, nextState); } else { // 不匹配則生成token,并轉移至初始狀態,開始重新匹配 produceToken(); flowtoResetState(); }}復制代碼(4) 優點- 邏輯清晰簡單
- 可維護性高 , 可擴展能力高
- 時間復雜度為O(N),效率高
1) 匹配字符串

文章插圖
2) 匹配浮點數

文章插圖
3) 匹配字符

文章插圖
4) 匹配運算符

文章插圖
五、詞法分析器的實現
詞法分析器的詳細實現及源碼講解 , 參見 ***/WGrape/lexer 項目
六、結束語
【編譯程序中的詞法分析器的輸出是二元組】本文已結束,感謝閱讀,點擊查看原文
- 如何將微信文章中的復制下來,微信網頁版如何復制圖片文字嗎?
- c盤windows文件夾中的哪些文件可以刪
- 細胞中的遺傳物質都是DNA
- 岑參什么詩派代表詩人,長安十二時辰中的程參原型
- 計算機中的內碼是什么,在計算機中采用二進制的主要原因是
- 微信抱拳什么意思,微信中的抱拳與勝利是什么意思呢
- 智能化工廠的四個層次,智能工廠中的機器人技術特點是
- 膽堿在奶粉中的作用
- 如何殺死花壇中的葡萄藤,院子里的花壇的風水講究
- 蓋士人讀書中的士人指的是什么
