PL真有意思(二) 程式語言語法

2021-09-29 21:48:32 字數 4480 閱讀 4064

雖然標題是程式語言的語法,但是講的是對詞法和語法的解析,其實關於這個前面那個寫編譯器系列的描述會更清楚,有關語言語法的部分應該是穿插在整個設計當中的,也看語言設計者的心情了

和英語漢語這些自然語言不一樣,計算機語言必須是精確的,它們的語法和語義都必須保證沒有歧義,這當然也讓語法分析更加簡單

所以對於編譯器一項很重要的任務就是時別程式語言的結構規則,要完成這個目標就需要兩個要求:

第乙個要求主要由正規表示式和上下文無關文法來描述完成,而第二個要求就是由編譯器來完成,也就是語法分析了

對於詞法,都可以用三種規則描述出來:

拼接選擇

kleene(也就是重複任意多次)

比如乙個整數常量就可以是多個數字重複任意多次,也叫做正則語言。如果對於乙個字串,我們再加入遞迴定義即可以描述整個語法,就可以稱作上下文無關語法

對於程式語言,單詞的型別不外乎關鍵字、識別符號、符合和各種型別的常量

對於整數常量就可以用這樣的正規表示式來表示

integer -> digit digit* digit -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

一般正規表示式只適用於描述單詞,因為正規表示式無法描述巢狀結構,一般正規表示式的實現都是用有限狀態自動機,之前用python實現了乙個簡單的正規表示式引擎也是這樣,但是對於匹配任意深度的巢狀結構就需要有乙個任意大的狀態機,顯然不符合。而定義巢狀結構對於描述語法非常有用,所以就有了上下文無關文法

expr := id | number | - expr | ( expr ) | expr or expr

op := + | - | * | /

對於上下文無關文法,每條規則叫做乙個產生式,產生式左部的符合稱為非終結符,而右部則是多個終結符或者非終結符,最後所有規則都會推到至終結符上,而終結符就是正規表示式定義的單詞

乙個正確的上下文無關文法,就可以指導我們如何生成乙個合乎語法的終結符串

最簡單的就是從開始符號開始,用這個產生式的右部取代開始符合,再從得到的串選擇乙個非終結符繼續進行推導,直到沒有剩下的非終結符,這個過程就像遞迴構造乙個樹的過程

expr := expr op expr

:= expr op id

:= expr + id

:= expr op expr + id

:= expr op id + id

:= expr * id + id

:= id * id + id

但是對於給定的上下文語法有可能會推導出不止一顆語法分析樹,我們就說這個上下文語法是存在歧義性的。所以對於上面的上下文無關語法還有更好的文法

掃瞄也就是詞法分析,詞法分析完全可以不需要什麼正規表示式、自動機什麼的,徒手擼出來,現在業界為了更好的生成錯誤資訊,應該很多也是手工的詞法分析器

手工的詞法分析器,無非就是一直讀入字元,到能判斷出它的token在送入語法分析器

使用有限狀態機的詞法分析一般都是這樣的幾個步驟

其實對於任意的正規表示式都可以用拼接、選擇和kleene閉包來表示

而同樣的,有限自動機也可以通過這三種方式來表示,圖就不畫了,這個在之前寫python正規表示式引擎的文章裡都畫過了(溜了

將nfa轉換到dfa可以採用的是子集構造法,主要思想就是,在讀入給定輸入之後所到達的dfa狀態,表示的是原來nfa讀入同樣輸入之後可能澳大的所有狀態

對於最小化dfa的主要思想是,我們把dfa所有狀態分為兩個等價類,終止態狀態和非終止狀態。然後我們就反覆搜尋等價類x和輸入符合c,使得當給定c作為輸入時,x的狀態能轉換到位於k>1個不同等價類中的狀態。之後我們就把x劃分為k個類,使得類中所有轉台對於c都會轉移到同乙個老類的成員。直到無法再按這種方式找到劃分的類時,我們就完成了

這四個步驟在之前的寫的正規表示式引擎中都完成了,在那三篇文章裡會更詳細一點

一般語法分析器的輸入是token流,而輸出是一顆語法分析樹。其中分析方法一般可以分為自上而下和自下而上兩類,這些類中最重要的兩個分別稱為ll和lr

ll表示從左向右,最左推導,lr表示從左向右,最右推導。這兩類文法都是從左到右的順序讀取輸入,然後語法分析器試圖找出輸入的推導結果

一般自上而下的語法分析器比較符合之前的推導方法,從根節點開始像葉節點反覆的遞迴推導,直到當前的葉節點都是終結符

遞迴下降很符合上面說的從根節點出發進行推導,一般用於一些相對簡單一些的語言

read a

read b

sum := a + b

write sum

write sum / 2

比如對於這個程式的遞迴下降,語法分析器一開始呼叫program函式,在讀入第乙個單詞read後,program將呼叫stmt_list,再接著呼叫stmt才真正開始匹配read a。以這種方式繼續下去,語法分析器執行路徑將追溯出語法分析樹的從左向右、自上而下的遍歷

**驅動的ll是基於乙個語法分析**和乙個棧

分析流程是

初始化乙個棧

將開始符號壓入棧

彈出棧頂,然後根據棧頂的符號和當前的輸入符號查表

如果彈出的是非終結符,將會繼續查表來確定下乙個壓入棧中的產生式

如果是終結符將進行匹配

**集合

從上面可以看出來最重要的就是那個語法分析**了,語法分析**其實就是根據當前輸入字元對下乙個產生式的**,這裡就要用到乙個概念:**集合,也就是first和follow集合。這個在之前寫編譯器系列講的比較詳細,在這裡就不寫了

當然ll語法也會有很多處理不了的文法,所以也才會有其它的語法分析方法

在實踐中,自下而上的語法分析都是**驅動的,這種分析器在乙個棧中儲存所有部分完成的子樹的根。當它從掃瞄器中得到乙個新的單詞時,就會將這個單詞移入棧。當它發現位於棧頂的若干符號組成乙個右部時,它就會將這些符號歸約到對應的左部。

乙個自底向上的語法分析過程對應為乙個輸入串構造語法分析書的過程,它從葉子節點開始,通過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 +

2shift操作

expr + num

null

shift操作

expr + factor

null

根據fator的產生式進行reduce

expr

null

reduce操作

statement

null

reduce操作

此時規約到開始符號,並且輸入串也為空,代表語法解析成功

有限狀態自動機的構建

0.  s -> e

1. e -> e + t

2. e -> t

3. t -> t * f

4. t -> f

5. f -> ( e )

6. f -> num

先在起始產生式->右邊加上乙個.

s -> .e
對.右邊的符號做閉包操作,也就是說如果 . 右邊的符號是乙個非終結符,那麼肯定有某個表示式,->左邊是該非終結符,把這些表示式新增進來

s -> . e

e -> . e + t

e -> . t

對新新增進來的推導式反覆重複這個操作,直到所有推導式->右邊是非終結符的那個所在推導式都引入

把 . 右邊擁有相同非終結符的表示式劃入乙個分割槽,比如

e -> t .

t -> t . * f

就作為同乙個分割槽。最後把每個分割槽中的表示式中的 . 右移動一位,形成新的狀態節點

根據每個節點 . 左邊的符號來判斷輸入什麼字元來跳入該節點

比如, . 左邊的符號是 t, 所以當狀態機處於狀態0時,輸入時 t 時, 跳轉到狀態1。

最後對每個新生成的節點進行重複的構建,直到完成所有所有的狀態節點的構建和跳轉

這一篇主要是提了對詞法和語法的分析過程,因為想要結合語言設計和實踐,更詳細的應該去看前面的寫乙個編譯器系列

PL真有意思(八) 其它程式設計模型

在之前幾篇我們討論的語法 語義 命名 型別和抽象適用於所有語言。然而我們的注意力都主要集中在命令式語言上,現在這篇來看看其它正規化的語言。函式式和邏輯式語言是最主要的非命令式語言。命名和作用域問題出現在各種模型中,還有型別 表示式和選擇與遞迴等控制流概念等等。所有語言都必須經過掃瞄 語法分析和語義分...

labview呀,可是真有意思

感謝上面 的這個高手 c program files national instruments labview 7.1 cintools lvsbutil targetname d wkspdir outdir 這一句裡面應該是半形狀態下的引號和減號,大家注意一下 真是太搞笑了,輸入了一遍,出古怪的...

中國的防毒行業真有意思

中國的防毒行業真有意思,哈.今天早上到公司沒事看新聞.才知道最近防毒這個行業挺熱鬧.大致看了一下.才知道又新出來乙個什麼可牛.哈.金山和360的這場戰要乾到什麼時候結束呢.至於誰是誰對我真是看不清楚,不過相關人的人品.我早有耳聞,不過呢還得佩服.白貓黑貓逮著老鼠就是好貓.某個偉人說的名言.看完這些報...