項目的完整代碼在 C2j-Compilerhtml
在以前完成了詞法分析以後,獲得了Token流,那麼接下來就是實現語法分析器來輸入Token流獲得抽象語法樹 (Abstract Syntax Tree,AST)。可是在完成這個語法分析器不像詞法分析器,直接手擼就行了,仍是須要一些前置的知識。git
這些前置知識在以前的博文都有提起過github
以前的博文目錄算法
項目的完整代碼在 C2j-Compiler學習
若是咱們把詞法分析當作是組合單詞,輸出單詞流,那麼語法分析就能夠看做是檢查這些單詞是否是符合語法的過程。在詞法分析的時候用正則或者手工比對來驗證單詞,語法分析則是用上下文無關文法 (context-free grammar,CFG)。code
若一個形式文法 G = (N, Σ, P, S) 的產生式規則都取以下的形式:V -> w,則謂之。其中 V∈N ,w∈(N∪Σ) 。上下文無關文法取名爲「上下文無關」的緣由就是由於字符 V 總能夠被字符串 w 自由替換,而無需考慮字符 V 出現的上下文。一個形式語言是上下文無關的,若是它是由上下文無關文法生成的*orm
巴科斯範式(英語:Backus Normal Form,BNF)是一種用於表示上下文無關文法的語言。htm
看一個例子:遞歸
S –> AB A –> aA | ε B –> b | bB
其中S A B叫做非終結符,表明能夠經過推導產生新的符號,以前在Token類裏定義的也有這些非終結符;a b ε叫做終結符,表示其沒法再經過推導產生新的符號了,ε則表示空;token
上面的每一行就是一個產生式規則,也叫推導式,表明了一種非終結符的轉移方式;
S就是開始符號。
只有終結符的符號串稱爲句子 (sentence)。
好比經過這三個產生式,就能夠判定bbb符合語法規則。
和以前講的同樣,主要分爲自頂向上和自底向下兩種
以前在學習的時候稍微記錄了一下這幾種方法,在這裏就不說了
在這裏稍微的再說一下此次語法分析使用的方法,LALR(1),它也屬於自底向上的分析算法。
一個自底向上的語法分析過程對應爲一個輸入串構造語法分析書的過程,它從葉子節點開始,經過shift和reduce操做逐漸向上到達根節點
自底向上的語法分析須要一個堆棧來存放解析的符號,例如對於以下語法:
0. statement -> expr 1. expr -> expr + factor 2. | factor 3. factor -> ( expr ) 4. | NUM
來解析1+2
stack | input | |
---|---|---|
null | 1 + 2 | |
NUM | + 2 | 開始讀入一個字符,並把對應的token放入解析堆棧,稱爲shift操做 |
factor | + 2 | 根據語法推導式,factor -> NUM,將NUM出棧,factor入棧,這個操做稱爲reduce |
expr | + 2 | 這裏繼續作reduce操做,可是因爲語法推導式有兩個產生式,因此須要向前看一個符合才能判斷是進行shift仍是reduce,也就是語法解析的LA |
expr + | 2 | shift操做 |
expr + NUM | null | shift操做 |
expr + factor | null | 根據fator的產生式進行reduce |
expr | null | reduce操做 |
statement | null | reduce操做 |
此時規約到開始符號,而且輸入串也爲空,表明語法解析成功
因此實現自底向上的語法解析關鍵就是識別堆棧上是應該進行shift仍是reduce操做。
因此接下來的任務天然就是構建一個有限狀態自動機來可以指導語法分析器來進行操做。
所謂的前置知識其實也就是了解語法分析在幹什麼,和大概要怎麼幹。
語法分析就是檢查輸入的Token流是否是符合語法的過程,而完成這一步驟的語法分析算法,拿自底向上來講,也就是從葉子節點向上推導成樹頂端的過程。
另外個人github博客:https://dejavudwh.cn/