# Compiler (Online course) ## Week 1 (Introductiion & the Cool Programming Language) ![](https://i.imgur.com/6tGOeIV.png) ### Structure of compiler ![](https://i.imgur.com/zoEloo7.png) 1. Lexical Analysis (詞彙分析) 空白鍵為 token 之一 ![](https://i.imgur.com/FA5Bcdx.png) 2. Parsing (語法分析) 將一段程式碼分成 parsing tree ![](https://i.imgur.com/SsSOW0l.png) 3. Semantic Analysis (語意分析) 分析語意是否正確 4. Optimization (最佳化) - 注意有浮點數的情況,運算時要考慮值有可能是 `NAN` ![](https://i.imgur.com/YRen2fe.png) 5. Code generation 轉化為組合語言或機械語言 ### The economy of programming languages - 要在舊的程式語言當中新增新的功能會消耗相當大的成本,所以一直會有新的程式語言推出,除此之外在不同的領域內適合的程式語言也不一樣。新的程式語言會依循先前的語言所開發,使得程式開發者會需要花很多的時間適應新的程式語言。 ### cool overview (Classroom Object Oriented Language) 一隻為了 compiler 課程開發出來的程式語言,透過由 C++ 寫成的編譯器 (coolc) ,會將程式碼編譯成 MIPS 組合語言,並使用 (spim) 這個 simulator 來執行程式 範例 1: ```cpp= class Main inherits IO { main() : Object { out_string("Hello, world!\n") }; }; ``` - 程式一定要有 class Main,且裡面要有 main() 函式 - 函式冒號後面為 return type 範例 2: ![](https://i.imgur.com/IXbATfO.png) - a2i 表示 ACII to INT - if 的結尾要有 fi - 此程式為計算 n 階層數值大小 範例 3: ![](https://i.imgur.com/iWKh3C3.png) - 迭代版計算階層 - loop 結尾要加 pool - let 用來變數宣告,最後面還要加一次變數名稱 (不確定此用法,待驗證) - `=` 在 cool 裡面代表 comparison 範例 4: ![](https://i.imgur.com/1uOLJmF.png) ![](https://i.imgur.com/T8fT92U.png) - List 為一個用來串接字串用的 class,此 class 含有兩個 element ,`next` 為一個 `pointer` 指向下一個要被串接的字串 - `flatten` 為印出完整字串的函式 - case 用法 --> 依照 item type 而 return 不同的值 - cool 內沒有所謂的 `null` ,要用空指標就需要直接宣告一指標當空指標,注意 `isvoid` 用法 >[wiki](https://en.wikipedia.org/wiki/Cool_(programming_language)) [The Cool Reference Manual](https://theory.stanford.edu/~aiken/software/cool/cool-manual.pdf) > ## Week 2 (Lexical Analysis & Finite Automata) ### Lexical Analysis ![](https://i.imgur.com/NO6uWdw.png) ![](https://i.imgur.com/BhUI9fK.png) - Token Class (< token class, substring >) - Identifier (英文開頭) - Keyword (`while`, `if` ...) - Numbers - Whitespace (包含 `\t`, `\n`) - operator (包含標點(punctuation)) ![](https://i.imgur.com/4IgmwS0.png) #### Lookahead Problem ![](https://i.imgur.com/EJFdrZA.png) - 程式語言是否忽略空白 - 讀到第一個 `=` 時不確定是 `assignment` 或是 `equal` - 讀到第一個 `e` 時不確定是 `keyword` 還是 `variable` #### Unbounded Lookahead 以下程式語言的 `keyword` 可以拿來當作 `variable` 使用,欲知道 `DECLARE` 是 陣列名稱或是 `keyword` 需要先去最前面看是否有 `=` 存在才能判斷,然後裡面的 `ARG` 可以有無限多個,稱之為 `unbounded lookahead` ![](https://i.imgur.com/v2798L8.png) #### Conclusion ![](https://i.imgur.com/Vgg1WjS.png) ### Regular Language ![](https://i.imgur.com/I41JJy1.png) ![](https://i.imgur.com/R81XH3c.png) - Epslon 不是 `empty language` 而是有一個 `empty string` 的 `langa - Epsilon 永遠是 `Iteration` 的一個子集合 ![](https://i.imgur.com/ObzYVHq.png) - Regular Expression over `sigma` ,代表 `sigma` 內的 `element` 可以做以下運算 #### Example ![](https://i.imgur.com/FdyrbiP.png) - 1* 表示 `i` 個 1 做聯集 - (1 + 0)1 表示 1 和 0 做聯集再串接 1 - 紫色表示有多種形式皆能表示成等號右邊的樣子 #### Conclusion ![](https://i.imgur.com/wbu0eDi.png) ### Formal Language - regular language 為一種 formal language DEF: ![](https://i.imgur.com/ek8inkU.png) ![](https://i.imgur.com/9Rj8Yte.png) #### Meaning Function (L) 透過 `L` function 將 `expression` (syntax) 映射成 `sets string` (semantics) ![](https://i.imgur.com/Rf6CZhX.png) ![](https://i.imgur.com/iVmNUBG.png) #### Seperate syntax from semantics `syntax` 與 `semantics` 並不是 1 對 1 映射的,可以是多對一,例如:阿拉伯數字與羅馬數字符號雖不同,但語意是相同的 ![](https://i.imgur.com/4AsPEww.png) >compiler 的最佳化就用到此觀念 > ### Lexcical Specifications **Keyword specifications (keyword 的闡述)** ![](https://i.imgur.com/c6aStMv.png) **Integer specifications** ![](https://i.imgur.com/v4YxWrT.png) **Identifier specifications** ![](https://i.imgur.com/DRWQ6B8.png) **Whitespace specifications** ![](https://i.imgur.com/hBq4u9p.png) **floatint** ![](https://i.imgur.com/nh4ld8j.png) :::info 特殊符號 ![](https://i.imgur.com/xwxpS4u.png) ::: #### Step ![](https://i.imgur.com/uBkb7IY.png) ![](https://i.imgur.com/bVY8i5c.png) - `R` 為總集合 ![](https://i.imgur.com/tbzFWRn.png) - 反覆上述步驟分析 `input` - 將 `input` 歸類成多個 `token class` **特例 1** ![](https://i.imgur.com/dk9kTdN.png) - 總是取 `Maxmal Munch` >參考 [quiz1](https://lagunita.stanford.edu/courses/Engineering/Compilers/Fall2014/courseware/708cb92d25c24fbdad592929b4a80917/474787266e5f48e8a5af71a0f9b29978/?activate_block_id=i4x%3A%2F%2FEngineering%2FCompilers%2Fsequential%2F474787266e5f48e8a5af71a0f9b29978) - 右邊是拿 `==` 當作例子 (`assignment` or `equal`) **特例 2** ![](https://i.imgur.com/fNfPF5F.png) - 當有一個 `input` 符合多個 `token` 時,選擇優先權較高的適用 **特例 3** ![](https://i.imgur.com/p5Daduo.png) - 當 `input` 不符合任何 `token` 時,發出錯誤訊息 ![](https://i.imgur.com/dQefgKr.png) #### Conclusion ![](https://i.imgur.com/rMI6reN.png) ![](https://i.imgur.com/J37oikE.png) ### Finite Automata (有限狀態機) A good implementation modle for regular expression #### DEF: ![](https://i.imgur.com/bswB00b.png) ![](https://i.imgur.com/h6OOHpj.png) #### Example 1: ![](https://i.imgur.com/qfwHSvF.png) - 箭頭代表 `input poointer` - 當 get stuck in accepting state 的時候,若 `input pointer` 還沒指最底會發生 `reject` - 在 `start state` 收到沒有被定義的 `input` 時也會發生 `reject` #### Example 2: ![](https://i.imgur.com/d4lzAF0.png) #### Epsilon move: ![](https://i.imgur.com/vBiYrqU.png) #### DFA v.s. NFA ![](https://i.imgur.com/NFeCfvK.png) ![](https://i.imgur.com/lq9Dm3B.png) - DFA - 同一個 `input` 不能有兩條路境 - 不能有 `epsilon-moves` - 所需時間較短 (不用判斷多種 case ) - 所需空間較大 - NFA - 同一個 `input` 可以有多條路徑 - 所需時間較長 - 所需空間較小 ![](https://i.imgur.com/woZjPcp.png) ### Lexical analysis (流程) #### 流程圖 ![](https://i.imgur.com/FXRdqdI.png) - 前兩階段是"定義" `Regular expressions` - 後面為 `implementation` ![](https://i.imgur.com/t96Z26C.png) - 每個 rexp(regular expression) 都要定義一個 `NFA` #### Example 1: ![](https://i.imgur.com/aF1UPVA.png) ![](https://i.imgur.com/UEsQAUb.png) #### Example 2: ![](https://i.imgur.com/Q9seMgk.png) - 由內而外畫 - 先把 `(1 + 0)` 畫好 ### NFA -> DFA - 有時候要直接表示成 `DFA` 比較困難,需要先表示成 `NFA` 再轉換成 `DFA` - 轉換的原則是將合併後的 `state` 看成一個 `state`,例如: {q0,q1} 為一個 `state` - 在 `NFA` 當中有 `n` 個 `state`,則 `DFA` 最多會有 `2^n - 1` 個 `state` > `state` 的組成方式為 {q0, q1, q2.... qn} ,每個 `state` 都有"要"或者"不要"兩個選項,總共能組成 `2^n` 個不同的 `state` ,減掉全部都"不要",所以最多會有 `2^n - 1` 個 `state` > - 因為 `NFA` 轉 `DFA` 的 `state` 數目為有限值 `2^n - 1`,因此可以保證轉換一定成立 >範例 >[[Coursera][Automata] 自動機理論-Automata筆記-第一週Finite Automata](http://www.evanlin.com/moocs-coursera-automata-note1/) >[Theory of Computation | Conversion from NFA to DFA](https://www.geeksforgeeks.org/theory-of-computation-conversion-from-nfa-to-dfa/) > ### Table driven implementation ![](https://i.imgur.com/1nzGOk0.png) - 將 `DFA` 話成 table ,可用程式表示 - 使用二維陣列紀錄 ![](https://i.imgur.com/2ayV4s2.png) - 使用一維陣列用指標紀錄 - 可將一樣的狀況指向同一塊記憶體位址,進而節省空間 ![](https://i.imgur.com/g3zkBFA.png) - NFS 也可以畫成 table` - 速度較慢,空間較小 ### Quiz 1 回顧 - 記得 `Maximal munch` ,在做 `produces the tokenization` 時要找最長符合的結果 - 第三題的部份也是要找 `max` 所以答案為 3、4 則一,但不懂為什麼 3 的 `priority` 較高 - 第十題要從全部 `0、1` 能組合出的集合,扣掉題目所給的集合 ## Week 3 (Parsing & Top-Down Parsing) ### Introduction to Parsing `Lexer` 將 `input` 轉成 `tokens` 之後,下一步就是將 `token` 丟給 `parser` 做進一步的處理 ![](https://i.imgur.com/UHrIGWu.png) `Lexer` 無法 `check the syntax` ,例如:`Lexer` 無法明確分析出有幾個括號 (這對程式語言來說是很重要的),像是第二張圖,它就只能分析出有偶數個 `1` 或者奇數個,但這對於編譯器來說是不夠用的。 我們可以剖析( parse ) 一個字串,逐字對應至 `Grammar` 確立語法,進而判斷原本字串是不是 `Language` 當中的字串。 Regular Language 的極限:正規語言是循序性的語言,不具備從屬關係、階層關係、巢狀結構、樹狀結構、遞迴結構。 ![](https://i.imgur.com/T3EcvTC.png) ![](https://i.imgur.com/c5AXZ62.png) #### Parser Tree ![](https://i.imgur.com/kuxfn1g.png) ### Context Free Grammers (上下文無關文法) #### 定義 - Terminals: 定義好的符號 ex: {0,1} - non-terminals: 又稱 `variables` 有限集合的符號 ex: {A,B,S} - Start Symbol: 類似於 RE 中的 `start state` ex: S - Production: 稱為"投射",一種對應關係,將 `non-terminals` 映射到 `non-terminals` 或者 `terminals` 通常用 `->` 表示 ex: S->S|0|1 - Derivations: 稱為"推導",將 CFG 從 `Start symbol` 開始,投射多次後達到推導結果,符號為 `=>` >`Production` 指的是從 A 映射到 B 的"方法",`Derivations` 則是指從 `start symbol` 開始推導到我們想要的結果這段"推導過程" > #### 基本範例 先來點簡單的範例 ![](https://i.imgur.com/CAD3DPu.png) ![](https://i.imgur.com/LIAXTEP.png) 將 `derivation` 過程轉成 `parse tree` ![](https://i.imgur.com/GD80q1K.png) >`parse tree` 的規則 >![](https://i.imgur.com/lZ66g65.png) > #### 左衍生 vs. 右衍生 依照消除的順序不同又可以分成 `左衍生 leftmost derivation` 和 `右衍生 rightmost derivation` ,這兩種方法推導出來的字串"完全相等",可以任意互換 ![](https://i.imgur.com/mGR60Sr.png) #### 曖昧文法 (ambiguous Grammar) 曖昧文法指的是同一個 `string` 可以對應到兩顆不同的 `parse tree` ,再做 `parse` 時應避免曖昧文法的出現,ex: ![](https://i.imgur.com/7wDdpYS.png) 曖昧文法在 `parse tree` 上的結果 ![](https://i.imgur.com/UvCsKwA.png) **if else then 的例子** ```cpp if Expression then if Expression then else .... ``` 考慮上述情況,我們傾向將 `else` 看作離它最近的 `then` ,上述例子則會將 `else` 視為第二個 `if then` 的情況 ![](https://i.imgur.com/jJhKD2p.png) #### 解決曖昧文法 最直接的方法就是 `rewrite grammar` ![](https://i.imgur.com/bKS3f9E.png) 有時候 `rewrite grammar` 對我們來說是很困難的,我們可以使用較直覺的方法,設定 `優先權 precedence` 和 `關聯性 associativity` ![](https://i.imgur.com/EMXbDi6.png) > `associativity` -> 當 `priority` 相同時左邊優先於右邊處裡 ex: `1 - 2 + 3 = 0 != -4` > `precedence` -> 不同的優先權 ex: `+`、`*` > `associativity` 在 `wiki` 上的例子 >![](https://i.imgur.com/G0xizZh.png) > ### Error Handling 分為 `Lexical 詞彙的錯誤` , `syntax 語法的錯誤` , `Semantic 語意的錯誤` ![](https://i.imgur.com/8jyjOj1.png) ![](https://i.imgur.com/sQsr60C.png) Panic mode ![](https://i.imgur.com/klVmQId.png) ![](https://i.imgur.com/zx8B35R.png) Error correction - 試著修正錯誤的 program - 很難實現 - 會降低 `parsing` 的速度 - 修正錯誤 ![](https://i.imgur.com/bxyzLtv.png) #### Abstrct Syntax Trees (AST) `AST` 為一個資料結構,是簡化 `parse tree` 過後的結果 ex: 5 + (2 + 3) ![](https://i.imgur.com/r3pI7n7.png) ![](https://i.imgur.com/McSj9C3.png) ### Recursive Descent Parsing `Descent` 的意思是下降,`RDP` 是指程式碼用 `recursive top down` 的方法做 `parsing` ![](https://i.imgur.com/aMKIWaB.png) >影片中後半段有詳細的過程可以參考 >[參考](https://lagunita.stanford.edu/courses/Engineering/Compilers/Fall2014/courseware/0a40e5575adf4310a4046e8500760cfc/2e6a6dd7f3a54326aa132b36dbcd3d7d/?child=first) > 程式碼實踐 ![](https://i.imgur.com/nBYd7OA.png) >其中 `return` 得 `next = save` 是為了做 `backtrack` 使用,也就是說 `E1()` 若錯誤,需要把指向 `string` 的 `pointer` 歸還為初始位址 > **Recursive Descent Limitations** 當程式比對到第一個一樣時就會直接套用,`string` 後面如果不一樣則無法做 `backtrack` ,看例子比較好明白 ![](https://i.imgur.com/GaW1F0Q.png) - 上面程式應該要將 `T 換成 int * T` 才能有正確的結果,但 `recursive` 第一次比對到 `int` 和 `input string` 的最前面符合後,就無法做 `backtrack` 了 ![](https://i.imgur.com/z1WNeVT.png) >正常的演算法應該會避免此問題,但這裡為了簡單解釋就沒有考慮 > #### Left Recursion 此種狀況在 `recursive descent` 中會造成無限迴圈,因此在做 `recursive descent` 時要先將 `left Recursion` 消除 ![](https://i.imgur.com/OMaLG7A.png) ![](https://i.imgur.com/6GqIg7e.png) >參考文獻 >[自動機理論-Automata筆記-第三週: ](http://www.evanlin.com/moocs-coursera-automata-note3/) >[Language / Grammar](http://www.csie.ntnu.edu.tw/~u91029/Language.html) > ## Weeek 4 (Bottom-Up Parsing) ### 7-01 Predictive Parsing and LL(1) 介紹如何使用 `parsing table` ,之後舉 `LL(1)` 當例子,而 LL(1) 還是 `top down` 的 `parsing #### DEF - By looking at the next few tokens - No backtracking - lookahead restricted grammers - LL(K) (left-to-right, leftmost, k token lookahead) - 指透過 `parsing table` 達到 `predict` 的效果,不像之前需要每個可能都試試看,若錯誤再用遞迴修正。這裡的 `predict` 根上面的 `lookahead` 的 `k` 是不一樣的東西,`k` 是指往後看幾個 `input` (不確定有沒有理解錯誤) #### LL(1) - Top down parsing - At each step only one choice of production (改寫 `grammer` 使其只有唯一可能) ![](https://i.imgur.com/eajvENa.png) - By "Parsing table" (透過查表的方式可以避免遞迴) ![](https://i.imgur.com/mk4x7iG.png) #### Parsing table ![](https://i.imgur.com/8xqbQSP.png) - 若 `parsing table` 內對應到的為空,則代表 `error` 的發生 - `Parsing table` 的建立可以依靠下面所講的 `First()` 和 `Follow` 來實踐 ![](https://i.imgur.com/u8z7t6E.png) ![](https://i.imgur.com/2s1J3R6.png) ### First() and Follow() #### Why First() and Follow First() - 可用來避免遞迴的發生 - 有現在的 `state` 還有 `input` 再加上 `First() set` ,就可以知道目前的 `state` 拿到這個 `input` 後應該 `derive` 的結果 - Example ![](https://i.imgur.com/zoNQHcK.png) - 有了 `First()` 就可以知道 `A` 應該 derive 成 `a` 而不是 `bc` Follow() - can make a Non-terminal to vanish out if needed to generate the string from the parse tree. - Example ![](https://i.imgur.com/oSVQkiy.png) - 試想再沒有 `Follow()` 的情況下,若 `C` 沒能指向 `b` ,則結果會發生 `error` ,`Follow()` 感覺可以理解成 `lookahead` >參考 >[Compiler Design | Why FIRST and FOLLOW?](https://www.geeksforgeeks.org/compiler-design-why-first-and-follow/) #### First() - If there is a variable, and from that variable if we try to drive all the strings then the beginning Terminal Symbol is called the first. - 這個函數的集合是 `Terminal Symbol` - 集合是由 `Non terminal` 衍生出來的 - Example ![](https://i.imgur.com/gML57FU.png) 補充: - First(E) = First(T) = First(F)... ![](https://i.imgur.com/guxqubr.png) >參考 >[Compiler Design | FIRST Set in Syntax Analysis ](https://www.geeksforgeeks.org/compiler-design-first-in-syntax-analysis/) #### Follow() - What is the Terminal Symbol which follow a variable in the process of derivation. - 此函數的集合也是 `Terminal Symbol` - Rules ![](https://i.imgur.com/zwiqbrq.png) - Example ![](https://i.imgur.com/1KQ2JTf.png) ![](https://i.imgur.com/ASCHhWv.png) - 在找 `follow()` 的時候要特別注意 `non terminal` 可能會指向"空",如 `example2` 的 `Follow(A)` >參考 >[Compiler Design | FOLLOW Set in Syntax Analysis](https://www.geeksforgeeks.org/compiler-design-follow-set-in-syntax-analysis/) > #### convert to LL(1) Parsing table The table without `epsilon` (e) ![](https://i.imgur.com/rlVfDYW.png) ![](https://i.imgur.com/fRqsF5S.png) The table with `epsilon` (透過 `follow()` 決定) ![](https://i.imgur.com/NZNO1rL.png) >參考 >[Compiler Design | Construction of LL(1) Parsing Table](https://www.geeksforgeeks.org/compiler-design-construction-of-ll1-parsing-table/) > ### Bottom up Parsing - 較廣泛使用 - 分類 ![](https://i.imgur.com/9RDMrvU.png) - L -> left-to-right - R -> rightmost - SLR -> simple LR - Rightmost ![](https://i.imgur.com/Z3FOrB7.png) - a bottom-up parser traces a rightmost derivation in reverse - 從 `root` 開始看,每次做 `parsing` 都必須是對最右邊的 `non-terminal` 做 #### 一些術語介紹 **Right sentential forms** - 從右邊化簡的形式 **handle** - is a substring that matches the body of the prodution, and whose reduction represents one step along the reverse of rightmost derivation - 可以透過 `grammer` 做轉換的叫做 `production` ,而轉換結果最後能導致走向唯一對的路徑稱之為 `handle` - Example ![](https://i.imgur.com/HCQcxAP.png) - 按照 `grammer` (參考課本之),第三步驟的 `T` 可以變成 `E` ,但此一步驟會導致最後無法化簡成一個 `E` ,應此 `E -> T` 不是 `handle` - 決定 `handle` 的問題可以視為決定 `shift or reduction` 的問題 **Item** - item of grammer G is a production of G with a dot at some position of the body - example ![](https://i.imgur.com/cPKd3iw.png) **Closure** - ![](https://i.imgur.com/W3AlQOI.png) - 可以看成是某個 `item` 最後能走到的所有路徑到包含在 `closure` 裡面 - Example ![](https://i.imgur.com/xbNbF04.png) ![](https://i.imgur.com/hVa1l7v.png) **Viable Prefixes** - The prefixes of right sentential forms that can appear on the stack of a shift-reduce parser are called viable prefixes. - `stack` 放的東西是之後可以被 reduced 的 - 同一種 `viable prefix` 情況下可能會有多條可行路徑 - Example 例子中 (E + T *) 是 `viable prefix` 且有 3 條可行路徑 ![](https://i.imgur.com/Kf59Ppg.png) **GOTO function** - GOTO(I,X) - I is a set of items (ex: E -> T), also called `state` - X is a grammer symbol - specifies the transition from state for `I` under input `X` - Example ![](https://i.imgur.com/uo52Z8y.png) :::info `closure` 和 `GOTO function` 都是為了要描述 `bunttom up parsing` 的演算法所用的專有名詞 下面是一個 `LR(0)` 演算法的狀態圖 (automation) ,該圖中每個 `state` (I) ,都代表一個 `closur` ,而每個轉換 `state` 的箭頭都代表一個 `GOTO function` ![](https://i.imgur.com/oF8Zww4.png) ::: ### Shift-Reduce Parsing - 一種 `bottom-up parsing` - 用一個 `stack` 來儲存 `grammer symbol` (當前已經從 `input` 轉換成 `grammer symbol` 的部份) - 用一個 `input buffer` 來儲存還沒被 `parse` 的 `data` - `handle` 總會產生在 `stack` 的最上面 - 此演算法會有四種 `Action` ![](https://i.imgur.com/IyG6IDO.png) - Example ![](https://i.imgur.com/6iQZFWw.png) #### Conflicts During Shift-Reduce Parsing - 衝突的發生在於不知道要選擇做 `shift` 還是 `reduce` ,有可能做 `reduce` 的 `grammer` 並不是 `handle` 而導致錯誤 - Example ![](https://i.imgur.com/S3uoLYb.png) - 當遇到 if...then... 時不確定要作 `reduction` 或者 `shift`,有可能後面還有接 `else` ### Introduction to LR Parsing: Simple LR (SLR) - A table-driven parsing, like LL parsers - An LR parser makes shift-reduce decisions by maintain state (I) to keep track of where we are in a parse. - 簡而言之就是在一個狀態機上 `automaton` 根據拿到的 `input` 做移動,若不能移動就做 `reduction` ,最後會移動到 `accept state` - Algorithm ![](https://i.imgur.com/EWUKfM6.png) - 中間的 `parsing program` 不會改變,會改變的只有 `GOTO` 和 `ACTION` - `program` 拿到 `input` 後,拿 `(state,input)` 去 `table` 比對現在該做什麼事 - 做 `shift` 的話會改變 `state` ,但不會產生新的 `grammer` - 做 `reduce` 也會改變 `state` ,但會產生新的 `grammer` - `input` push 到 stack 後,完全用 `state` 表示 `input` ,一個 `state` 的順序只會對應到一組 `input` 順序 - start state `s0` dosen't represent a grammer symbol, and serves as a bottom-of-stack maker ![](https://i.imgur.com/CiFze75.png) - 做 `reduce` 完畢後把產生的 `grammer` 從 `stack` pop 出來,並用剩下的 `grammer` 代表的 `state` 做 `GOTO` 的動作 - example 1 (給予狀態圖表) ![](https://i.imgur.com/m1c7hIu.png) ![](https://i.imgur.com/uUn2i6r.png) - example 2 (給予 parsing table) ![](https://i.imgur.com/utTwrdO.png) ![](https://i.imgur.com/xGxt2TU.png) - 感覺這裡的 `Action` 做的事也符合 `GOTO function` 的定義,應該只是名詞問題 >龍書 273~279 未看 > :::warning # Some resource - [Writing your own programming language and compiler with Python](https://blog.usejournal.com/writing-your-own-programming-language-and-compiler-with-python-a468970ae6df) - [Create a working compiler with the LLVM framework, Part 1](https://www.ibm.com/developerworks/library/os-createcompilerllvm1/index.html) - [The Design of a Custom 32-bit RISC CPU and LLVM Compiler Backend](https://scholarworks.rit.edu/cgi/viewcontent.cgi?article=10699&context=theses) ::: ###### tags: `class note`