我發起並創立了一個 C 語言編譯器 開源項目 InnerC

本文是 VMBC / D#  項目 的 系列文章,html

有關 VMBC / D# ,  見 《我發起並創立了一個 VMBC 的 子項目 D#》(如下簡稱 《D#》)  http://www.javashuo.com/article/p-zziqptgy-s.html    。java

 

VMBC  須要一個 內置 的  C 編譯器,   想來想去, 以爲仍是本身寫一個,數組

計劃用  C 語言 寫,  由於 VMBC 的  C 編譯器 要求是一個 本地庫,  若是不要求是 本地庫,  我就用 C# 寫了, 呵呵呵 。函數

 

爲何 是 庫 呢 ?   由於這是一個 內置編譯器,  是由  ILBC 運行時 來 調用的 (ILBC 見 《D#》),  因此 是一個 庫  。spa

這個 庫  最好 能 儘量的  小 。操作系統

 

C 語言 寫的 代碼 是 最貼近 底層(彙編) 的,  因此  C 語言 寫的 庫 應該是 最緊湊 的, 因此用  C 語言 來寫 。指針

 

還有一個 緣由 是, 我會的 語言 很少,  C 算是 相對 更熟一點的,    So  。htm

 

有 網友 說 C 語言 不適合 寫 編譯器, C 的抽象過低了,  建議用 函數式 語言寫,對象

又舉例    Rust  最先是用  OCaml  寫的,   而後又用 Rust 寫了一遍  。blog

 

好吧,   但  Rust 、OCaml   這些語言 的 名字 我都 沒怎麼聽過,   仍是用 C 吧  。

另外用  C  的話, 應該不用擔憂 操做系統 的 支持 的 問題  。

 

這個 項目 我只 實現    語法分析   和   類型檢查    的 部分,      語法分析 包含了 語法檢查  。

生成目標代碼     連接(連接外部庫)  這  2 個 部分   你們 若是有興趣, 對 彙編 和 操做系統 瞭解 的話, 能夠來補充 。

 

InnerC  是   ansi C   的 子集 + 擴展, 只支持   ansi C   的 部分特性, 同時還會加入一些  新特性  。

總的來講,  InnerC  會 比  ansi C  簡單 。

 

好比,  InnerC   不支持  結構體(Struct),  由於 InnerC 是 做爲 中間語言, 只須要是一種  「高級彙編語言」  就能夠 。

不用   Struct, 那用什麼 ?

用 數組, 包括 靜態數組 和 從 堆 裏 分配 的 數組 。

根據 偏移量 向 數組 的 相應位置 寫入 字段 的 值,  這就是 Struct,  也是 對象 。

去掉 Struct 能夠 省掉 很多 語法分析 的 開銷 和  人力上的 研發成本 。

 

但  C 語言 裏好像沒有 按值 傳遞 數組 的 特性, 因此  InnerC  須要 加入 按值傳遞數組(拷貝傳遞數組) 的 特性 。

好比, InnerC 應該 增長  T [ n ]  類型, 用於 參數 和 返回值,

T [ n ]  類型 表示 按值傳遞數組(拷貝傳遞數組),

 

假設 A() 方法 調用 B() 方法,  B() 方法有一個  T [ n ]  arr  參數,  那麼 A() 方法 傳給 T [ n ]  arr  參數 的 是一個 數組的 首地址 arr, 編譯器會處理成 把 A() 裏的 arr 數組 以 長度 n 拷貝到 B() 的 arr 裏,  因此 B() 的  arr 也是 數組 的 首地址, 可是是 拷貝到 B() 的 堆棧 裏的 數組 的 首地址 。 

T [ n ]  arr  表示 arr 參數 是 長度 爲 n 的 數組, 編譯器 會爲 arr 在 B 的 堆棧 裏 分配 長度爲 n * sizeof(T)  的 內存空間 。 這個空間是 編譯器 分配的, 是 靜態分配 的,  等價於  聲明一個   T arr[ n ]   這樣的 靜態數組 。

 

同理, 假設 B() 的 返回值 是 T [ n ]  類型,  B() 實際返回的是一個 數組 的 首地址 arr,  A() 裏 用來 接收 B() 的 返回值 的 是一個    T arr[ n ]  arr ;   靜態數組 變量, 編譯器會處理成 把 B() 裏的  arr 數組 以 長度 n 拷貝到 A() 的 arr 裏 。

 

InnerC   也不支持 對 函數指針 進行 類型檢查,

不對 函數指針 類型檢查 是指 函數指針 能夠調用 任意 的 參數列表,  固然, 出了錯 是 調用者 本身 負責 。^^

不過 對於 中間語言 來講, 基本上 不用擔憂 這個問題 。

 

InnerC  的 語法分析 能夠 生成一個 表達式對象樹,  把 表達式對象樹 序列化 獲得一個    byte []  (byte 數組),

這個  byte[]    就至關於  .Net  的  Op Code,  或者  java  的  Byte Code,   咱們能夠把 這個  byte[]  稱爲   ILBC Byte Code (簡稱 Byte Code)  。

這樣一來, 問題就明朗了,

若是  開發期 編譯 生成的 目標代碼 就是   ILBC Byte Code,   那  JIT 速度 較慢 的 問題 就 解決了  。

這就是說, 能夠把   C 語言 做爲 第一級 中間代碼,   Byte Code 做爲 第二級 中間代碼  。

 

這樣,  InnerC  就能夠由  2 個模塊 組成:

1   InnerC   to   Byte Code

2   Byte Code   to   Native Code

 

固然, 能夠在 開發期 編譯 直接 生成  Native Code (本地代碼),     這是  AOT  。

相關文章
相關標籤/搜索