第3章: 語法分析
- 語法(syntax): 組合單詞以形成詞組、從句或句子的方法。
- Lex 用一個符號代替某個正則表達式的縮寫機制
- 詞法分析器Lex實現縮寫形式的正則表達式:在將正則表達式翻譯成有限自動機前,用digits右部的式子替代正則表達式出現的所有digits
- 但這種方法不適用於sum-expr語言
- 我們需要遞歸的續寫形式
- 提出上下文無關文法
3.1: 上下文無關文法
- 語言由文法描述,文法有產生式結合(production),產生式右部有0至多個符號
- 終結符:來自該語言字符串字母表中的單詞
- 非終結符
- 開始符號(start symbol):區別對待的非終結符
3.1.1:推導
- 最左推導(leftmost derivation):總是擴展最左邊非終結符的推導
- 最右推導(rightmost derivation)
3.1.2:語法分析樹(parse tree)
- 與推導相結合
3.1.3:二義性文法(ambiguous)
- 二義性:一個文法能夠推導出具有兩棵不同語法樹的句子
- 編譯器利用語法分析樹來推導語義
- 二義性會給編譯帶來問題,所以文法需要是無二義性的
- 表達式(expression),項(term),因子(factor)
- 所以語言需要找到無二義性的文法表示,否則此語言不能作爲程序設計語言
3.1.4:文件結束符
- 用$符號來表示文件結束
- 設S是一文法的開始符號
- 爲了指明
必須出現在一個完整的S詞組之後,需要引入一個新的開始符號S′以及一個新的產生式S′->S
3.2:預測分析
- 用遞歸下降(recursive descent)算法對文法進行分析
- 算法實質:將每一個文法產生式轉變成遞歸函數的一個字句
- 遞歸下降分析也稱爲預測(predictive)分析
- 預測分析只適合於每個子表達式的第一個終結符號能夠爲產生式的選擇提供足夠信息的那種文法
3.2.1:FIRST集合和FOLLOW集合
- 給定一個由終結符和非終結符組成的字符串y,FIRST(y)是從y可以推導出的任意字符串中的開頭終結符組成的集合
- 如果兩個不同的產生式X->y1和X->y2具有相同的左部符號,並且它們的右部有重疊的FIRST集合,則這個文法不能用預測分析法分析
- 因爲如果存在某個終結符I,它既在FIRST(y1)中,又在FIRST(y2)中,則當輸入單詞爲I時,遞歸下降分析器中與X對應的函數將不知道該怎麼做
- 如果X-> ,Y-> ;那FIRST(XYZ)一定包含FIRST(Z)
- 所以,在計算FIRST集合時,我們必須跟蹤能產生空串的符號,這種符號稱爲可爲空的nullable符號,同時還必須跟蹤有可能跟隨在可爲空符號之後的其他符號
- FOLLOW(X)可直接跟隨於X之後的終結符集合
- nullable概念
- 算法:FIRST、FOLLOW和nullable的迭代計算
- 基於文法3-6使用算法,通過每一步迭代來理解運用算法
- 文法:
- 初始:
- 第一次迭代:
- 第二次迭代:
- 第三次迭代沒有發現新的信息,於是算法終止
3.2.2:構造一個預測分析器
- 考慮一個遞歸下降器。非終結符X的分析函數對X的每個產生式都有一個子句,因此該函數必須根據下一個輸入單詞T來選擇其中的一個子句。如果能夠爲每一個(X,T)選擇出正確的產生式,我們就能夠寫出這個遞歸下降分析器。我們需要的所有信息可以用一張關於產生式的二維表來表示,此表以文法的非終結符X和終結符T作爲索引,這張表稱爲預測分析表
- 預測分析表多重定義項的出現可能會導致二義性,我們需要一個無二義性的文法
- 若一個文法的預測分析表不含多重定義的項,則稱爲LL(1)文法
- LL(1)代表從左至右分析、最左推導和超前查看一個符號(Left-to-right parse, Leftmost-derivation,1-symbol lookahead)
- LL(k)分析表:表的行是非終結符,列是k個終結符的每一種序列
- 遞歸下降分析器完成起工作只需查看下一個輸入單詞,從不需要超前查看多於一個以上的單詞
3.2.3:消除左遞歸
- 左遞歸:E作爲E的產生式的第一個左部符號出現
- 右遞歸(引入非終結符E’)
- 爲了消除左遞歸,利用右遞歸來重寫產生式
3.2.4:提取左因子
- 當一個非終結符的兩個產生式以相同的符號開始時也會發生類似的問題
- 對文法提取左因子,即取出非公共的尾部
3.2.5:錯誤恢復
- 有了預測分析表,便很容易寫出遞歸下降分析器
- 錯誤恢復就是通過刪除、替代或插入單詞,來尋找一個與那個單詞串相似的句子