什麼是程序的執行?
程序可以看做一個函數,接受輸入和返回輸出?
什麼是編譯器?
將源程序編譯成 目標程序。
代表:
- c/c++
- go
- rust
什麼是解釋器?
代表:
- python
- lua
混合編譯器
- 中間代碼更容易被翻譯成目標程序、優化空間更大
- 中間語言的存在更利於編譯器的實現
- 讓虛擬機處理複雜的執行環境(跨平臺)
代表:
- java
即時編譯器(Just-in-time compiler)
- 一種提高效率的方法,中間代碼不是直接執行,而是先被編譯成機器碼執行。
- java
交叉編譯
- 在一個平臺編譯產生多個平臺的可執行代碼
不同方式優劣勢
- 解釋執行有性能問題,但也異常靈活,例如支持eval函數,eval 本質上 就是c語言的函數指針,將cs:ip 指向文本,這樣就能將一串文本 轉換成 代碼了。
- 直接交叉編譯技術難度是其次,跨平臺問題會多;一次編譯很多包也有分發問題----產品問題。
- 虛擬化技術提供更好的體驗,卻沒有 提供更好的性能(JIT完美解決這一點)。
編譯階段
詞法分析(Parser):
將字符序列轉換爲單詞(Token)序列的過程, 分詞斷句 + 判斷詞性的過程。
給定:
var a = 5 * 6.0 + 7;
token | 詞性 |
---|---|
var | 關鍵字 |
a | 變量 |
= | 運算符 |
5 | 整型 |
* | 運算符 |
6.0 | 浮點型 |
+ | 運算符 |
7 | 整形 |
語法分析(LEXical):
學過因爲的都知道,單詞不是隨便都能組合的,按照"主謂賓" i eat a apple 我們可以把一句話,生成一個ast抽象語法樹(Abstract Syntax Tree),用來輔助直接計算或者輔助編譯器生成字節碼的結構。
我們 對 這顆 AST樹進行後序(左、右、上) 輸出, 5、6.0 、* 、 7 、+ ,到了 這 我們 就可以很方便使用棧的數據結構模擬進行計算了。
語法 分析,可以從前往後 也可以從後往前,一般來說從前往後去解析語法比較方便,解析語法樹 我們可以通過 一個表達式,
expr -> number op expr|number
上面的表達式 比較抽象, 舉個例子
expr = 1 + 2 + 3 + 5 + 6
expr = 1 + expr1 = ↓
expr = 1 + 2 + expr2 =↓
expr = 1 + 2 + 3 + expr3 = ↓
expr = 1 + 2 + 3 + 5 + expr4
可以看到 expr3 = 5 + expr4 、此時 expr4 = 6 是一個number 那麼,遞歸節結束。
上面,的例子 expr表達式 就是將 一個問題 像套娃、分形圖 一樣拆解成 一個數 操作符 和 另一個更小規模的expr表達式 ,這就是遞歸的思維 表達式的最後一層套娃是一個number。
運行時環境
- 有的編譯器將代碼編譯成機器碼,按照操作系統約定編譯成一個應用,運行稱爲操作系統的進程.
- 有的編譯器將代碼編譯成中間代碼(字節碼、三地址代碼等),然後在操作系統中啓動一個虛擬容器(進程)來執行他們。
- JIT編譯器一邊執行中間代碼,一邊編譯他們。