[心得] interpreter 環境與變數

作者: descent (「雄辯是銀,沉默是金」)   2016-11-25 11:09:20
變數就是字面上的意思, 寫程式的都知道, 但知道 interpreter 怎麼把這功能做出來的
程式員可能就不多了。
list 1
1 x=1;
2 x+5;
list 1 L2 怎麼把 x, 1 做個對應的呢? 就是靠《環境》, 他不是什麼神祕的東西, 用
c++ 來說明什麼是環境的話就是:
std::map<std::string, ASTNode *> env;
然後把 env["x"]=1 就完成 x=1 這個運算式。
不管你用什麼資料結構, 反正就是把 x 和 1 的關係存起來就對了。感覺很簡單, 但真實
世界上可沒這麼簡單, 不過教學就是要化繁為簡, 先知道這樣就夠了。
再來的 list 1 L2 在 x+5 要做 eval 時, eval 5 就回傳 5 ASTNode 本身, x 就到
env 去把他對應的數字找出來, 也就是 1, 所以傳回 1 的 ASTNode, 然後 + 就可以把
1, 5 作相加的運算, 6 就這麼算出來了。
那《環境》困難在哪裡呢? 在 function call。
p1
1 int x;
2 int f1()
3 {
4 2*3;
5 12+13;
6 }
7
8 int f2(int i)
9 {
9.5 int cc;
10 5*i;
11 }
12 int main()
13 {
14 int z;
15 61+2;
16 z=5;
17 f1();
18 f2(z);
19 }
如果像 p1 這樣, 掃描到 L1 時, 把 x 加入 global_env (table 1), 在 call main
時, 要產生 main_env (table 2), main_env 的上層 up_env 要指到 global_env, 當掃
描到 L 14 時, 把 z:0 加入到 main_env, 而掃描到 L 16 時, 把 5 的值至換到 z
(table 3), 在 call f2(z) 時 (L 18), 又要產生 f2_env (table 4), 再把 up_env 指
到 main_env, 並把 z/i 的對應存到 f2_env, cc 的對應也要存到 f2_env, 疑, cc 沒對
應的值阿, 隨便塞一個就好了, 這不就是 c 語言 auto 變數的行為嗎? 而上層 env 要指
到 main_env, 這樣層層下去, 讓整個環境建立起所有的變數名稱/變數值的對應關係。大
概像 env class 那樣。
table 1. global_env
up_env 0
x 0
table 2. main_env
up_env global_env
z 0
table 3 main_env
up_env global_env
z 5
table 4. f2_env
up_env main_env
i z
cc 0
所以在 f2() 裡頭用到 cc, i 時, 就去查 f2_env, 把對應的值找出來, 就可以知道這個
變數的值, 而在這層找不到, 就要去 up_env 找, 都找不到就發出錯誤訊息。
env class
14 class Environment
15 {
16 public:
17 Environment(Environment *outer=0, const char *name=0): outer_(outer)
18 {
21 }
22 Environment *outer_;
31 int free_frame_index_;
32 private:
33 std::map<std::string, ASTNode *> frame_;
34 };
觀念很簡單, 但實作還是會困難一點, 可參考以下範例程式碼。以下程式碼只有實作最簡
單的環境, 我還沒完成 function call 那複雜的環境。目前的版本我已經完成了
function call 和 return, 真是有種覺得自己很不簡單的感覺呢!
source code:
https://github.com/descent/simple_compiler ( https://goo.gl/FBON5s )
commit: 0452c23b770dad99b1d503e0f417cae45879ce72
除了加入變數, 函式的定義也一樣要加入環境, 當呼叫一個函式時, 就到環境來找這個函
式, 找到後把 parameter, argument 配對後, 就去執行該函式了。
至於函式的傳回值, 那又是另外一件事情了。
因為使用了「環境」來處理「變數」, 這便是「環境變數」名稱的由來。
打通整個 interpreter 流程並不容易, 當我滿懷好奇心將所有疑問抽絲剝繭, 最後接觸
到本質的那一刻, 我知道這些努力與堅持是值得的, 縱使我無法因為這樣而在工作上有立
即的幫助, 但滿足自己的好奇心就是驅使我這麼做的最大動力。
// 本文使用 Blog2BBS 自動將Blog文章轉成縮址的BBS純文字 http://goo.gl/TZ4E17 //
blog 原文
http://descent-incoming.blogspot.tw/2016/07/compiler-4.html
作者: Ommm5566 (56天團)   2016-11-25 19:22:00
排版
作者: wtchen (沒有存在感的人)   2016-11-25 20:22:00
推回來,我覺得排版沒問題阿
作者: art1 (人,原來不是人)   2016-11-26 08:31:00
掃到 L14 那裡有點看不懂,那一行是int z,但你的說明是把x:0 加到 main環境
作者: MOONRAKER (㊣牛鶴鰻毛人)   2016-11-26 13:06:00
ptt的排版就是 我看得順眼才叫排版 我看不順眼就噓排版一堆連報紙都沒看過的○○滿口排版 強!
作者: EdisonX (卡卡獸)   2016-11-26 21:08:00
請問有機會介紹 conditions 嗎?
作者: youtuuube000 (小孩)   2016-11-27 11:13:00
看不懂感覺很厲害先推再說XD
作者: EdisonX (卡卡獸)   2016-11-27 13:05:00
是的 我說的conditions 泛指條件判斷 含if else elsif switch case期待您的 part 2
作者: Ommm5566 (56天團)   2016-11-27 22:06:00
那很抱歉 補回來推
作者: eye5002003 (下一夜)   2016-11-28 09:55:00
這專案是用C++實現一個直譯器採用C做為腳本語言嗎?喔!我有做過類似的事,建議使用C++11的特性匿名函式用來寫parser很有幫助,個人意見
作者: EdisonX (卡卡獸)   2016-11-29 14:53:00
goo.gl/b70T6m
作者: CoNsTaR ((const *))   2016-11-29 17:53:00
這種時候就會覺得有 pattern matching 的語言真好 XDD
作者: littleshan (我要加入劍道社!)   2016-12-02 00:11:00
functional language 拿來做這種事超愉悅的 XD推薦coursera上由UW提供的programming languages課程從此人生打開了另一扇窗

Links booklink

Contact Us: admin [ a t ] ucptt.com