編譯原理 詞法分析

2021-09-10 12:56:33 字數 3662 閱讀 7509

在詞法分析的過程中還有乙個過稱是不能少的,就是在分析的時候一次讀入多少**。編譯乙個程式的時候,往往需要進行大量的字串讀入。前人做了比較多的優化,其中一項就是採用來個交替讀入的緩衝區。每個緩衝區大概能有4096的位元組,讀一句話是足夠的。讀入程式中維護了兩個指標:分別是lexemebegin 指標,顧名思義,就是當前詞素的開始處。以及forward 指標,就是試圖判斷詞素的結尾是什麼。這個很複雜我們會在接下來的章節中詳細介紹。可以想象,一旦確定了當前詞素的位置,那我們就把forward的位置+1之後賦值給lexemebegin,然後繼續上述的過程。但是簡單地做上面的工作會有乙個小小的問題,就是如果恰好乙個詞素被分開了怎麼辦,這就涉及到了哨兵標記。

當我們移動forward指標的時候,實際上同時做了兩件事情,第一件事情是判斷是否已經能夠完成詞素的匹配。並且要同時檢查我們是否到了緩衝區的結尾(如果到了結尾自然要選擇是不是要重新裝載緩衝區,是不是要大幅度移動forward指標),這個問題被 eof 很好的解決了。

一、詞法分析與正規表示式

程式語言可以認為是乙個字符集,字串是乙個有限的符號集,符號本身是有限的字母。當使用正規表示式的符號表示法時,每個正規表示式就代表乙個字串集。乙個詞法分析器的輸入是源**,本質上可以看做是乙個字串。而它的輸出是「記號」流。乙個「記號」由乙個模式來描述。凡是匹配該模式的字串都被標識成相同的記號。而記號的模式通常是乙個正規表示式,或者說正則文法。也就是說正規表示式是用來描述詞素的。是一種用來描述詞素模式的重要方法。

單詞的本質是字串,在詞法分析中為了用正規表示式描述單詞,使用語義函式為正規表示式和字串集合建立一種對映關係,使得正規表示式的語**釋被描述成字串的形式。

(1) (r) | (s) 是乙個正規表示式,其所對應的語言為 l(r)∪l(s)

(2) (r) (s) 是乙個正規表示式,其所對應的語言為 l(r)l(s)

(3) (r)* 是乙個正規表示式,其所對應的語言為 (l(r))∗

(4) (r) 是乙個正規表示式,只是說明在表示式左右加個括號是沒有影響的。

詞法分析生成器中常使用的規則:

優先規則:對於特定的初始字串,最先與之匹配的正規表示式決定了這個字串的記號型別。

這時先介紹一下關於正規表示式的數學原理:首先是因為集合論的出現導致世界可以由集合表示,同時集合是多種多樣的,所以正規表示式之中有幾種重要的集合:符號,邏輯預演算法(| . )其中.可以被省略,空(e),重複(*)或者說冪或者說克林。有了這些概念之後,在來看一下正則集合(0|1)*.0,首先*得含義表示的是括號呢內部的多次出現,而.的含義是指連線,指多個字元的連線,|表示兩個鐘出現乙個就可以,所以他的含義是前面的數字是前面是多個0或者1組成的字串,最後以0結尾的,表示含義為 以2的倍數組成的二進位制數。在舉乙個例子b*(abb*)*(a|e),可以發現a始終沒有連續的出現,因為指的是a和b組成。但是如果正規表示式每次都要使用各種符號來描述,那未免太過繁瑣,於是出現更簡潔的描述方式用[abcd]描述[a|b|c|d],甚至當字母連續時可以這樣[a-d]進行表示,當同時匹配幾段不同的字母時也可以[a-d1-9],m+可以表示m乘以m*。

二、詞法分析與有限自動機

由於正規表示式對於確定詞法記號很方便,但還是需要乙個將其實現的電腦程式方法。所以需要引入有限自動機,從正規表示式到有限自動機有兩種方法自頂向下逐步分解法和自下而上組合方法,所以正規表示式就是建立在自動機的理論基礎上的:使用者寫完正規表示式之後,正則引擎會按照這個表示式構建相應的自動機(可能是nfa,也可能是dfa,但它們必定是等價的),若輸入一串文字之後,自動機抵達了接受狀態,則這串文字可以「匹配」使用者指定的正規表示式。有窮狀態自動機按照轉移函式的不同,也就是有窮自動機容許轉移函式不確定,分成了「確定有窮狀態自動機」(dfa)和「非確定有窮自動機」(nfa)。nfa是基於表示式的,而dfa是基於文字的。兩類引擎要順利工作,都必須有乙個正則式和乙個文字串。dfa通過文字串去比較正則式,看到乙個子正則式就把可能的匹配串全標註出來,然後再看正則式的下乙個部分,根據新的匹配結果更新標註。而nfa是通過正則式去比文字,讀入乙個字元就把它跟正則式比較,匹配就記下來:「某時間在某處匹配上了」,然後接著往下尋找。一旦一直不匹配,就把剛吃的這個字元退出出來,乙個個的退出,直到回到上一次匹配的地方。

dfa與nfa機制上的不同帶來5個影響:

1. dfa對於文字串裡的每乙個字元只需掃瞄一次,比較快,但特性較少;nfa要翻來覆去吃字元、吐字元,速度慢,但是特性豐富,所以反而應用廣泛,當今主要的正規表示式引擎都是nfa的。

2. 只有nfa才支援lazy和backreference等特性;

3. nfa急於邀功請賞,所以最左子正則式優先匹配成功,因此偶爾會錯過最佳匹配結果;dfa則是「最長的左子正則式優先匹配成功」。

4. nfa預設採用greedy量詞

5. nfa可能會陷入遞迴呼叫的陷阱而表現得效能極差。

有限自動機包含乙個有限的狀態集,狀態由箭頭連線,稱為邊。從乙個狀態指向到另外乙個狀態,每個邊都有乙個標記,其中包含乙個初始狀態和若干個終結狀態。詞法記號的有限自動機,圓圈表示狀態,雙圓圈表示終結狀態,開始狀態是乙個無輸入的邊。在不能確定是否正確讀人乙個單詞的時候,只能將乙個字母作為分析目標並根據下乙個字母來判斷是否應該判定該字母所屬型別,所以通過有限自動機來判斷字母所屬型別。在確定的有限自動機中,不存在兩個從同乙個狀態下出發且標記完全相同的邊。

確定的有限自動機的工作過程:從初始狀態出發,對於每個輸入字串中的字元,自動機都沿著相應的邊到達另一狀態,邊上必須標有輸入字元,對於有n個字元的字串,若在n次狀態轉換之後,自動機到達了終結狀態,那麼自動機就接受了字串,若未達到終結狀態,或者找不到與輸入字元匹配的邊,自動機就拒絕接受這個字串。每個終結狀態都要標明有限自動機所接收的記號型別。同時需要遵守最長匹配原則以及優先規則,因為詞法分析器的工作是找到原始的合法子字串的最長匹配,在解釋轉換過程中詞法分析器一直追蹤最長匹配的路徑和匹配的位置,追蹤最長匹配路徑就是用兩個變數儲存自動機上一次的結束狀態(last-final以及input-position-at-last-final)每次到達終結狀態時都需要更新這兩個變數,當到達停滯狀態時這些變數會記錄相匹配的記號和結束的位置。

可以將自動機表示為乙個轉換矩陣,乙個二維陣列下標表示狀態號和輸入字元,還有乙個停滯狀態0,其任何輸入字元都指回自身狀態,用該狀態來代替不存在的邊,還有乙個結束陣列,其作用是將狀態號與動作一一對應。

非確定有限自動機則存在多條從乙個狀態出發並且標記相同符號的邊,也可能存在標有空字串的邊即在不接收輸入字元時可進行狀態轉換。從初始狀態開始自動機就必須選擇乙個轉換方向,若存在可以接收的字串的選擇路徑,自動機就應該接受該字串。nfa是乙個很有用的概念,它會將乙個正規表示式轉換成乙個**的nfa,可以將任何乙個正規表示式轉換為含有乙個尾和乙個頭的nfa。

用電腦程式實現dfa是比較容易的但實現nfa就不容易了,因為計算機不能進行很好的猜測。將nfa轉換為dfa時,每個nfa的狀態集都對應著dfa的乙個狀態。dfa構造完成之後狀態陣列可能被丟棄,而轉換陣列則用於詞法分析。對於乙個已經形成的nfa,我們需要定義新的狀態來形成dfa,從nfa轉化到dfa的重點是重新組合nfa狀態。解決以下的兩種情形,就能將nfa轉為dfa:

(1)邊上的ε:ε閉包:遇到這種情況,後面的三個狀態完全可以合併,如果將後面的三個狀態合為乙個,那這個轉換圖里就沒有ε邊,也就滿足了dfa的條件。 對應的解決方法是找出ε閉包,也就是先找出該狀態的ε邊推出的所有狀態,再找那些狀態的ε邊推出的狀態,是乙個迭代的過程,直到找出乙個狀態的ε閉包。

(2)不確定的後續狀態:子集構造法:遇到這種情況,如果能將狀態2和狀態3合併到一起,就不會出現「面對相同的輸入狀態可能跳轉到多種狀態的情形了」,合併狀態2和狀態3這樣類似的狀態的方法叫做子集構造法。

編譯原理詞法分析

編譯原理實驗一 詞法分析練習 include include include define tokenmax 100 define progmax 1000 define k esc 27 void analytics 詞法分析 void scanner 輸入掃瞄 bool isletter cha...

詞法分析(編譯原理)

詞法分析 英語 lexical analysis 是電腦科學中將字串行轉換為單詞 token 序列的過程。進行詞法分析的程式或者函式叫作詞法分析器 lexical analyzer,簡稱lexer 也叫掃瞄器 scanner 詞法分析器一般以函式的形式存在,供語法分析器呼叫。完成詞法分析任務的程式稱...

編譯原理詞法分析

1 注意識別符號和無符號整數的重複問題,本人採用map解決。2 cin ch自動忽略空白字元。include include include include using namespace std struct pairs int isboundaries char ch return 3 case...