編譯原理SLR(1)文法的C++實現(基於SLR(1)分析法的語法制導翻譯及中間程式碼生成程式設計原理與實現)
阿新 • • 發佈:2019-02-11
程式功能描述
完成以下描述賦值語句 SLR(1)文法語法制導生成中間程式碼四元式的過程。
G[A]:
A→V=E
E→E+T∣E-T∣T
T→T*F∣T/F∣F
F→(E)∣i
V→i
[設計說明] 終結符號i為使用者定義的簡單變數,即識別符號的定義。
[設計要求]
(1)構造文法的SLR(1)分析表,設計語法制導翻譯過程,給出每一產生式對應的語義動作;
(2)設計中間程式碼四元式的結構;
(3)輸入串應是詞法分析的輸出二元式序列,即某賦值語句“專題1”的輸出結果,輸出為賦值語句的四元式序列中間檔案;
設計兩個測試用例(儘可能完備),並給出程式執行結果四元式序列。
主要資料結構描述
在實驗中主要使用結構體進行各類屬性的封裝。此外,還用到了stack和list的結構,其中stack主要由陣列進行簡易實現,便於輸出棧內內容;list使用C++ STL中的list進行動態的新增。以下對每一部分進行詳細說明。
此處使用sentence結構體對於專案集族中的每個產生式的屬性進行封裝。finish表示該產生式是否完成規約,即點操作是否進行完畢;tag即用來表示當前點的位置,因產生式包含有左部和->符號,故從3開始計數;string類的str用於儲存產生式的字串。
typedef struct
{
int finish = 0; //是否結束
int tag = 3; //當前圓點的位置
string str;
}sentence;
此處用act結構體對構造的ACTION表進行儲存。在實驗中,我並沒有使用二維陣列進行ACTION表的儲存,而是選用了一維的結構體:I代表輸入的目前的狀態,Vt代表輸入的終結符號,tag用於表示是r類還是s類,action用於記錄對應的r類的產生式標號或s類狀態標號。
typedef struct
{
int I; //當前狀態
char Vt; //終結符號
char tag; //r||s
int action; //動作
}act;
同上,此處使用結構體go對GOTO表進行儲存。I表示輸出的當前狀態,Vn表示輸入的非終結符,next_I表示GOTO的轉移結果,形如GOTO(I, Vn) = next_I。
typedef struct
{
int I; //當前狀態
char Vn; //非終結符
int next_I; //轉移狀態
}go;
此處使用I進行構造專案集族時狀態的儲存。number對應於該專案的序號,如I0/I1等;l則為list<sentence>型別,用於儲存該狀態中的產生式。
typedef struct
{
int number; //編號
list<sentence> l;
}I; //狀態
此處使用siyuanshi進行四元式的儲存,形同四元式:(op, arg1, arg2, result)。在此不再贅述。
typedef struct
{
char op;
char arg1;
char arg2;
char result;
}siyuanshi;
此處使用var進行符號表的儲存。在構造四元式的過程中,需要對於上一次的操作中新生成的結果進行記錄,以便生成新的四元式時作為引數加入其中;故結構體中的name代表某一運算結果的變數名,如A/B/C/D;string類的value表示該變數對應的算術表示式(屬性)。
typedef struct
{
char name;
string value; //place
}var; //變數
以下是一些變數的定義。在這些過程中用到了大量的list:首先進行狀態集的定義,以list的形式對狀態進行儲存;之後是list-char的FIRST與FOLLOW集的定義;之後是list形式的ACTION表和GOTO表的定義,以及list-char的Vn/Vt集。最後,input用來儲存輸入串,在分析過程中也會使用input來主要進行分析。
list<I> DFA; //狀態集
list<char> *First; //FIRST集
list<char> *Follow; //FOLLOW集
list<act> ACTION; //ACTION[i][j]
list<go> GOTO; //GO[i][j]
list<char> Vt; //終結符號集
list<char> Vn; //非終結符號集
char input[100];
下面是分析棧、符號棧以及其屬性棧的定義,分別儲存狀態號、符號以及其代表的屬性,並且設立棧頂指標。下面使用list結構進行四元式的儲存、記錄可以產生四元式的產生式標號以及變量表中變數的儲存。最後,在G[]陣列中,進行文法的定義。本實驗為自動造表,故此處可修改文法,僅作細微改動即可。
int S[100]; //分析棧
int S_top = 0; //分析棧棧頂
char T[100]; //符號棧 棧頂與分析棧總相同
string value[100]; //儲存符號的屬性
list<siyuanshi> L_sys; //四元式
list<int> sys; //產生四元式的狀態集
list<var> V; //變量表
int result_count = 0;
string G[11] = { "S->A", "A->V=E","E->E+T","E->E-T","E->T","T->T*F","T->T/F","T->F","F->(E)","F->i","V->i" };
程式結構描述:
整個程式較為龐大,自動構造文法分析所需的表,包括Vt/Vn/FIRST/FOLLOW/ACTION/ GOTO/變量表,之後進行SLR(1)分析,並且構造四元式。在這裡進行詳細說明:
完成整個程式的思路是:
->讀取檔案(獲取輸入的實驗一執行結果、得到表示式)
->掃描文法(構建終結符號、非終結符號集、First/Follow集)
->造表(構造專案集族、構造ACTION/GOTO、設定四元式)
->SLR分析(判斷是否可以被分析程式接受、生成四元式)
讀取檔案:readfile()將檔案中的實驗一的執行結果讀入,整合為字元陣列,準備好以待匹配,同前幾次試驗,在此不做贅述。
掃描文法:scan()將文法陣列G[]中的string字串進行掃描,構造終結符號集和非終結符號集;之後按照SLR(1)文法中FIRST集和FOLLOW集的構造方法進行這兩個集合的構造。在構造FIRST集時,用到了find函式,用來不斷地遞迴查詢產生式首符號為非終結符號的產生式,以構造FIRST集;在構造FOLLOW集時,使用到了findVn函式,用來返回指定的非終結符對應的標號,以進行FOLLOW集的計算。同時,通過不斷的迴圈、加入,當所有非終結符的FOLLOW集總大小不變時,跳出迴圈,構造完成。至此,造表前的準備工作全部完成,接下來進入造表階段。
造表:table()完成整個專案集族的生成以及ACTION/GOTO的構造,以及在造表過程中對於四元式的標註,也是個人認為整個程式中最難的部分。
首先,進行初始設定:新增文法的起始符號對應的產生式,用以從初態進行迭代;之後將該產生式(點還處在最開始的部位tag=3, 尚未進入規約狀態finish=0)加入第一個狀態I0中,接下來進行一波迴圈操作:首先對於當前所有的專案集族進行閉包操作,該功能被封裝在閉包函式closure()中(函式中對於每一個點操作的非終結符均進行閉包操作,加入該狀態中,最終返回經過閉包操作的該狀態);之後對於當前狀態的每一條待移進的產生式分別進行移進操作,並新增為新的狀態,等待迴圈到該狀態時的閉包操作。在移進過程中,對於不是規約的(即尚可移進的)產生式,若點操作為非終結符,置GOTO(當前狀態, 非終結符) = 新狀態號;若為終結符,則置ACTION(當前狀態,終結符號) = s+新狀態號。若存在移進時的相同符號,則加入同一狀態中,不再另設新狀態。之後即為對於新狀態的加入判斷:若新狀態的閉包操作closure()已經在已形成的專案集族中出現了,則不再新增這個新狀態,並且修改對應的ACTION或者GOTO(一個pop()操作+一個push()操作);否則新增。對於需要規約的產生式,首先對其進行判斷是否可以產生四元式:若可以,則進行記錄,以便之後判斷;否則不進行記錄。至此,造表結束,接下來正式進入分析階段。
SLR分析:SLR()完成最終整個SLR(1)文法的分析任務,也包括分析過程中完成的四元式構建。在分析過程起始時,首先將狀態I0壓入棧中,分析開始:若ACTION(棧頂,當前符號)不是acc(在程式中為r0),則開始迴圈:如果是err(在程式中使用0代替),報錯;否則如果是sj,狀態棧、符號棧、屬性棧均壓棧,讀取下一個符號;如果是ri,則通過需要規約第i條產生式,對於三個棧,執行第i條產生式右部的符號數次pop()操作,同時更新屬性棧,用以後續的四元式生成工作;在生成四元式時,首先判斷正在規約的產生式是否可以產生四元式,同時確定四元式的op,其次判斷兩個引數(arg1,arg2)是否為變數or變數組成的表示式。如果是表示式,則查詢之前的符號表,進行代替操作。若中間不報錯而跳出迴圈,則成功匹配。至此,按照事先約定好的輸出格式進行輸出,分析任務完成。
程式測試:
測試用例
在本程式中,使用檔案進行讀取表示式的操作。測試輸入串放在text.txt中,測試用例如下:
測試用例1:
測試結果
測試1:
學習總結:
起初,只是想動手做一個手動造表的SLR程式。後來在實際操作的過程中,聽說這次實驗比較難,涉及到分析過程、還包括四元式,就有些覺得不是那麼容易。不過,後來還是鐵了心,想完成一個自動造表的程式,從開始到結尾沒有人為設定的表和其他設定。剛開始做的時候還是比較不太舒服,畢竟規則還沒有掌握清楚,開始上手做時還是不太順利的。到後來慢慢了解整個演算法的原理,再到後來不去翻書也大概明白整個演算法是怎麼回事,主動去迎接一個不是那麼輕鬆就可以完成的實驗...個人感覺收穫還是很大的。目前實驗的不足是部分輸出還不是很規範(不包括在字元介面還是對齊的棧到了word裡面不知道為什麼就不齊了),還有提升空間。
附:完整實現程式碼(詳見.cpp檔案)
完成以下描述賦值語句 SLR(1)文法語法制導生成中間程式碼四元式的過程。
G[A]:
A→V=E
E→E+T∣E-T∣T
T→T*F∣T/F∣F
F→(E)∣i
V→i
[設計說明] 終結符號i為使用者定義的簡單變數,即識別符號的定義。
[設計要求]
(1)構造文法的SLR(1)分析表,設計語法制導翻譯過程,給出每一產生式對應的語義動作;
(2)設計中間程式碼四元式的結構;
(3)輸入串應是詞法分析的輸出二元式序列,即某賦值語句“專題1”的輸出結果,輸出為賦值語句的四元式序列中間檔案;
設計兩個測試用例(儘可能完備),並給出程式執行結果四元式序列。
主要資料結構描述
在實驗中主要使用結構體進行各類屬性的封裝。此外,還用到了stack和list的結構,其中stack主要由陣列進行簡易實現,便於輸出棧內內容;list使用C++ STL中的list進行動態的新增。以下對每一部分進行詳細說明。
此處使用sentence結構體對於專案集族中的每個產生式的屬性進行封裝。finish表示該產生式是否完成規約,即點操作是否進行完畢;tag即用來表示當前點的位置,因產生式包含有左部和->符號,故從3開始計數;string類的str用於儲存產生式的字串。
typedef struct
{
int finish = 0; //是否結束
int tag = 3; //當前圓點的位置
string str;
}sentence;
此處用act結構體對構造的ACTION表進行儲存。在實驗中,我並沒有使用二維陣列進行ACTION表的儲存,而是選用了一維的結構體:I代表輸入的目前的狀態,Vt代表輸入的終結符號,tag用於表示是r類還是s類,action用於記錄對應的r類的產生式標號或s類狀態標號。
typedef struct
{
int I; //當前狀態
char Vt; //終結符號
char tag; //r||s
int action; //動作
}act;
同上,此處使用結構體go對GOTO表進行儲存。I表示輸出的當前狀態,Vn表示輸入的非終結符,next_I表示GOTO的轉移結果,形如GOTO(I, Vn) = next_I。
typedef struct
{
int I; //當前狀態
char Vn; //非終結符
int next_I; //轉移狀態
}go;
此處使用I進行構造專案集族時狀態的儲存。number對應於該專案的序號,如I0/I1等;l則為list<sentence>型別,用於儲存該狀態中的產生式。
typedef struct
{
int number; //編號
list<sentence> l;
}I; //狀態
此處使用siyuanshi進行四元式的儲存,形同四元式:(op, arg1, arg2, result)。在此不再贅述。
typedef struct
{
char op;
char arg1;
char arg2;
char result;
}siyuanshi;
此處使用var進行符號表的儲存。在構造四元式的過程中,需要對於上一次的操作中新生成的結果進行記錄,以便生成新的四元式時作為引數加入其中;故結構體中的name代表某一運算結果的變數名,如A/B/C/D;string類的value表示該變數對應的算術表示式(屬性)。
typedef struct
{
char name;
string value; //place
}var; //變數
以下是一些變數的定義。在這些過程中用到了大量的list:首先進行狀態集的定義,以list的形式對狀態進行儲存;之後是list-char的FIRST與FOLLOW集的定義;之後是list形式的ACTION表和GOTO表的定義,以及list-char的Vn/Vt集。最後,input用來儲存輸入串,在分析過程中也會使用input來主要進行分析。
list<I> DFA; //狀態集
list<char> *First; //FIRST集
list<char> *Follow; //FOLLOW集
list<act> ACTION; //ACTION[i][j]
list<go> GOTO; //GO[i][j]
list<char> Vt; //終結符號集
list<char> Vn; //非終結符號集
char input[100];
下面是分析棧、符號棧以及其屬性棧的定義,分別儲存狀態號、符號以及其代表的屬性,並且設立棧頂指標。下面使用list結構進行四元式的儲存、記錄可以產生四元式的產生式標號以及變量表中變數的儲存。最後,在G[]陣列中,進行文法的定義。本實驗為自動造表,故此處可修改文法,僅作細微改動即可。
int S[100]; //分析棧
int S_top = 0; //分析棧棧頂
char T[100]; //符號棧 棧頂與分析棧總相同
string value[100]; //儲存符號的屬性
list<siyuanshi> L_sys; //四元式
list<int> sys; //產生四元式的狀態集
list<var> V; //變量表
int result_count = 0;
string G[11] = { "S->A", "A->V=E","E->E+T","E->E-T","E->T","T->T*F","T->T/F","T->F","F->(E)","F->i","V->i" };
程式結構描述:
整個程式較為龐大,自動構造文法分析所需的表,包括Vt/Vn/FIRST/FOLLOW/ACTION/ GOTO/變量表,之後進行SLR(1)分析,並且構造四元式。在這裡進行詳細說明:
完成整個程式的思路是:
->讀取檔案(獲取輸入的實驗一執行結果、得到表示式)
->掃描文法(構建終結符號、非終結符號集、First/Follow集)
->造表(構造專案集族、構造ACTION/GOTO、設定四元式)
->SLR分析(判斷是否可以被分析程式接受、生成四元式)
讀取檔案:readfile()將檔案中的實驗一的執行結果讀入,整合為字元陣列,準備好以待匹配,同前幾次試驗,在此不做贅述。
掃描文法:scan()將文法陣列G[]中的string字串進行掃描,構造終結符號集和非終結符號集;之後按照SLR(1)文法中FIRST集和FOLLOW集的構造方法進行這兩個集合的構造。在構造FIRST集時,用到了find函式,用來不斷地遞迴查詢產生式首符號為非終結符號的產生式,以構造FIRST集;在構造FOLLOW集時,使用到了findVn函式,用來返回指定的非終結符對應的標號,以進行FOLLOW集的計算。同時,通過不斷的迴圈、加入,當所有非終結符的FOLLOW集總大小不變時,跳出迴圈,構造完成。至此,造表前的準備工作全部完成,接下來進入造表階段。
造表:table()完成整個專案集族的生成以及ACTION/GOTO的構造,以及在造表過程中對於四元式的標註,也是個人認為整個程式中最難的部分。
首先,進行初始設定:新增文法的起始符號對應的產生式,用以從初態進行迭代;之後將該產生式(點還處在最開始的部位tag=3, 尚未進入規約狀態finish=0)加入第一個狀態I0中,接下來進行一波迴圈操作:首先對於當前所有的專案集族進行閉包操作,該功能被封裝在閉包函式closure()中(函式中對於每一個點操作的非終結符均進行閉包操作,加入該狀態中,最終返回經過閉包操作的該狀態);之後對於當前狀態的每一條待移進的產生式分別進行移進操作,並新增為新的狀態,等待迴圈到該狀態時的閉包操作。在移進過程中,對於不是規約的(即尚可移進的)產生式,若點操作為非終結符,置GOTO(當前狀態, 非終結符) = 新狀態號;若為終結符,則置ACTION(當前狀態,終結符號) = s+新狀態號。若存在移進時的相同符號,則加入同一狀態中,不再另設新狀態。之後即為對於新狀態的加入判斷:若新狀態的閉包操作closure()已經在已形成的專案集族中出現了,則不再新增這個新狀態,並且修改對應的ACTION或者GOTO(一個pop()操作+一個push()操作);否則新增。對於需要規約的產生式,首先對其進行判斷是否可以產生四元式:若可以,則進行記錄,以便之後判斷;否則不進行記錄。至此,造表結束,接下來正式進入分析階段。
SLR分析:SLR()完成最終整個SLR(1)文法的分析任務,也包括分析過程中完成的四元式構建。在分析過程起始時,首先將狀態I0壓入棧中,分析開始:若ACTION(棧頂,當前符號)不是acc(在程式中為r0),則開始迴圈:如果是err(在程式中使用0代替),報錯;否則如果是sj,狀態棧、符號棧、屬性棧均壓棧,讀取下一個符號;如果是ri,則通過需要規約第i條產生式,對於三個棧,執行第i條產生式右部的符號數次pop()操作,同時更新屬性棧,用以後續的四元式生成工作;在生成四元式時,首先判斷正在規約的產生式是否可以產生四元式,同時確定四元式的op,其次判斷兩個引數(arg1,arg2)是否為變數or變數組成的表示式。如果是表示式,則查詢之前的符號表,進行代替操作。若中間不報錯而跳出迴圈,則成功匹配。至此,按照事先約定好的輸出格式進行輸出,分析任務完成。
程式測試:
測試用例
在本程式中,使用檔案進行讀取表示式的操作。測試輸入串放在text.txt中,測試用例如下:
測試用例1:
測試用例2:12,<i> 32,<=> 12,<a> 23,<*> 28,<(> 12,<b> 21,<+> 12,<c> 29,<)> 33,</> 12,<d>
12,<r>
32,<=>
28,<(>
12,<a>
21,<+>
12,<e>
29,<)>
33,</>
12,<b>
23,<*>
28,<(>
12,<c>
22,<->
12,<d>
29,<)>
測試結果
測試1:
測試用例2:讀入實驗一結果: 12,<i> 32,<=> 12,<a> 23,<*> 28,<(> 12,<b> 21,<+> 12,<c> 29,<)> 33,</> 12,<d> 輸入串為:i=a*(b+c)/d# 終結符號集:=+-*/()i# 非終結符號集:SAVETF FIRST S i A i V i E ( i T ( i F ( i FOLLOW S # A # V = E # + - ) T # + - * / ) F # + - * / ) 狀態0: S->·A A->·V=E V->·i 狀態1: S->A· 狀態2: A->V·=E 狀態3: V->i· 狀態4: A->V=·E E->·E+T E->·E-T E->·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態5: A->V=E· E->E·+T E->E·-T 狀態6: E->T· T->T·*F T->T·/F 狀態7: T->F· 狀態8: F->(·E) E->·E+T E->·E-T E->·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態9: F->i· 狀態10: E->E+·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態11: E->E-·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態12: T->T*·F F->·(E) F->·i 狀態13: T->T/·F F->·(E) F->·i 狀態14: F->(E·) E->E·+T E->E·-T 狀態15: E->E+T· T->T·*F T->T·/F 狀態16: E->E-T· T->T·*F T->T·/F 狀態17: T->T*F· 狀態18: T->T/F· 狀態19: F->(E)· GOTO(0, A) = 1 GOTO(0, V) = 2 GOTO(4, E) = 5 GOTO(4, T) = 6 GOTO(4, F) = 7 GOTO(8, E) = 14 GOTO(8, T) = 6 GOTO(8, F) = 7 GOTO(10, T) = 15 GOTO(10, F) = 7 GOTO(11, T) = 16 GOTO(11, F) = 7 GOTO(12, F) = 17 GOTO(13, F) = 18 ACTION(0, i) = s3 ACTION(1, #) = r0 ACTION(2, =) = s4 ACTION(3, =) = r10 ACTION(4, () = s8 ACTION(4, i) = s9 ACTION(5, #) = r1 ACTION(5, +) = s10 ACTION(5, -) = s11 ACTION(6, #) = r4 ACTION(6, +) = r4 ACTION(6, -) = r4 ACTION(6, )) = r4 ACTION(6, *) = s12 ACTION(6, /) = s13 ACTION(7, #) = r7 ACTION(7, +) = r7 ACTION(7, -) = r7 ACTION(7, *) = r7 ACTION(7, /) = r7 ACTION(7, )) = r7 ACTION(8, () = s8 ACTION(8, i) = s9 ACTION(9, #) = r9 ACTION(9, +) = r9 ACTION(9, -) = r9 ACTION(9, *) = r9 ACTION(9, /) = r9 ACTION(9, )) = r9 ACTION(10, () = s8 ACTION(10, i) = s9 ACTION(11, () = s8 ACTION(11, i) = s9 ACTION(12, () = s8 ACTION(12, i) = s9 ACTION(13, () = s8 ACTION(13, i) = s9 ACTION(14, )) = s19 ACTION(14, +) = s10 ACTION(14, -) = s11 ACTION(15, #) = r2 ACTION(15, +) = r2 ACTION(15, -) = r2 ACTION(15, )) = r2 ACTION(15, *) = s12 ACTION(15, /) = s13 ACTION(16, #) = r3 ACTION(16, +) = r3 ACTION(16, -) = r3 ACTION(16, )) = r3 ACTION(16, *) = s12 ACTION(16, /) = s13 ACTION(17, #) = r5 ACTION(17, +) = r5 ACTION(17, -) = r5 ACTION(17, *) = r5 ACTION(17, /) = r5 ACTION(17, )) = r5 ACTION(18, #) = r6 ACTION(18, +) = r6 ACTION(18, -) = r6 ACTION(18, *) = r6 ACTION(18, /) = r6 ACTION(18, )) = r6 ACTION(19, #) = r8 ACTION(19, +) = r8 ACTION(19, -) = r8 ACTION(19, *) = r8 ACTION(19, /) = r8 ACTION(19, )) = r8 分析棧:(| |中的為非終結符號的屬性) 0 3 i 0 2 V |i| 0 2 4 V |i| = 0 2 4 9 V |i| = a 0 2 4 7 V |i| = F |a| 0 2 4 6 V |i| = T |a| 0 2 4 6 12 V |i| = T |a| * 0 2 4 6 12 8 V |i| = T |a| * ( 0 2 4 6 12 8 9 V |i| = T |a| * ( b 0 2 4 6 12 8 7 V |i| = T |a| * ( F |b| 0 2 4 6 12 8 6 V |i| = T |a| * ( T |b| 0 2 4 6 12 8 14 V |i| = T |a| * ( E |b| 0 2 4 6 12 8 14 10 V |i| = T |a| * ( E |b| + 0 2 4 6 12 8 14 10 9 V |i| = T |a| * ( E |b| + c 0 2 4 6 12 8 14 10 7 V |i| = T |a| * ( E |b| + F |c| 0 2 4 6 12 8 14 10 15 V |i| = T |a| * ( E |b| + T |c| 0 2 4 6 12 8 14 V |i| = T |a| * ( E |b+c| 0 2 4 6 12 8 14 19 V |i| = T |a| * ( E |b+c| ) 0 2 4 6 12 17 V |i| = T |a| * F |b+c| 0 2 4 6 V |i| = T |a*b+c| 0 2 4 6 13 V |i| = T |a*b+c| / 0 2 4 6 13 9 V |i| = T |a*b+c| / d 0 2 4 6 13 18 V |i| = T |a*b+c| / F |d| 0 2 4 6 V |i| = T |a*b+c/d| 0 2 4 5 V |i| = E |a*b+c/d| 0 1 A |i=a*b+c/d| 匹配成功! 四元式: (+,c,b,A) (*,A,a,B) (/,d,B,C) 請按任意鍵繼續. . .
讀入實驗一結果: 12,<r> 32,<=> 28,<(> 12,<a> 21,<+> 12,<e> 29,<)> 33,</> 12,<b> 23,<*> 28,<(> 12,<c> 22,<-> 12,<d> 29,<)> 輸入串為:r=(a+e)/b*(c-d)# 終結符號集:=+-*/()i# 非終結符號集:SAVETF FIRST S i A i V i E ( i T ( i F ( i FOLLOW S # A # V = E # + - ) T # + - * / ) F # + - * / ) 狀態0: S->·A A->·V=E V->·i 狀態1: S->A· 狀態2: A->V·=E 狀態3: V->i· 狀態4: A->V=·E E->·E+T E->·E-T E->·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態5: A->V=E· E->E·+T E->E·-T 狀態6: E->T· T->T·*F T->T·/F 狀態7: T->F· 狀態8: F->(·E) E->·E+T E->·E-T E->·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態9: F->i· 狀態10: E->E+·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態11: E->E-·T T->·T*F T->·T/F T->·F F->·(E) F->·i 狀態12: T->T*·F F->·(E) F->·i 狀態13: T->T/·F F->·(E) F->·i 狀態14: F->(E·) E->E·+T E->E·-T 狀態15: E->E+T· T->T·*F T->T·/F 狀態16: E->E-T· T->T·*F T->T·/F 狀態17: T->T*F· 狀態18: T->T/F· 狀態19: F->(E)· GOTO(0, A) = 1 GOTO(0, V) = 2 GOTO(4, E) = 5 GOTO(4, T) = 6 GOTO(4, F) = 7 GOTO(8, E) = 14 GOTO(8, T) = 6 GOTO(8, F) = 7 GOTO(10, T) = 15 GOTO(10, F) = 7 GOTO(11, T) = 16 GOTO(11, F) = 7 GOTO(12, F) = 17 GOTO(13, F) = 18 ACTION(0, i) = s3 ACTION(1, #) = r0 ACTION(2, =) = s4 ACTION(3, =) = r10 ACTION(4, () = s8 ACTION(4, i) = s9 ACTION(5, #) = r1 ACTION(5, +) = s10 ACTION(5, -) = s11 ACTION(6, #) = r4 ACTION(6, +) = r4 ACTION(6, -) = r4 ACTION(6, )) = r4 ACTION(6, *) = s12 ACTION(6, /) = s13 ACTION(7, #) = r7 ACTION(7, +) = r7 ACTION(7, -) = r7 ACTION(7, *) = r7 ACTION(7, /) = r7 ACTION(7, )) = r7 ACTION(8, () = s8 ACTION(8, i) = s9 ACTION(9, #) = r9 ACTION(9, +) = r9 ACTION(9, -) = r9 ACTION(9, *) = r9 ACTION(9, /) = r9 ACTION(9, )) = r9 ACTION(10, () = s8 ACTION(10, i) = s9 ACTION(11, () = s8 ACTION(11, i) = s9 ACTION(12, () = s8 ACTION(12, i) = s9 ACTION(13, () = s8 ACTION(13, i) = s9 ACTION(14, )) = s19 ACTION(14, +) = s10 ACTION(14, -) = s11 ACTION(15, #) = r2 ACTION(15, +) = r2 ACTION(15, -) = r2 ACTION(15, )) = r2 ACTION(15, *) = s12 ACTION(15, /) = s13 ACTION(16, #) = r3 ACTION(16, +) = r3 ACTION(16, -) = r3 ACTION(16, )) = r3 ACTION(16, *) = s12 ACTION(16, /) = s13 ACTION(17, #) = r5 ACTION(17, +) = r5 ACTION(17, -) = r5 ACTION(17, *) = r5 ACTION(17, /) = r5 ACTION(17, )) = r5 ACTION(18, #) = r6 ACTION(18, +) = r6 ACTION(18, -) = r6 ACTION(18, *) = r6 ACTION(18, /) = r6 ACTION(18, )) = r6 ACTION(19, #) = r8 ACTION(19, +) = r8 ACTION(19, -) = r8 ACTION(19, *) = r8 ACTION(19, /) = r8 ACTION(19, )) = r8 分析棧:(| |中的為非終結符號的屬性) 0 3 r 0 2 V |r| 0 2 4 V |r| = 0 2 4 8 V |r| = ( 0 2 4 8 9 V |r| = ( a 0 2 4 8 7 V |r| = ( F |a| 0 2 4 8 6 V |r| = ( T |a| 0 2 4 8 14 V |r| = ( E |a| 0 2 4 8 14 10 V |r| = ( E |a| + 0 2 4 8 14 10 9 V |r| = ( E |a| + e 0 2 4 8 14 10 7 V |r| = ( E |a| + F |e| 0 2 4 8 14 10 15 V |r| = ( E |a| + T |e| 0 2 4 8 14 V |r| = ( E |a+e| 0 2 4 8 14 19 V |r| = ( E |a+e| ) 0 2 4 7 V |r| = F |a+e| 0 2 4 6 V |r| = T |a+e| 0 2 4 6 13 V |r| = T |a+e| / 0 2 4 6 13 9 V |r| = T |a+e| / b 0 2 4 6 13 18 V |r| = T |a+e| / F |b| 0 2 4 6 V |r| = T |a+e/b| 0 2 4 6 12 V |r| = T |a+e/b| * 0 2 4 6 12 8 V |r| = T |a+e/b| * ( 0 2 4 6 12 8 9 V |r| = T |a+e/b| * ( c 0 2 4 6 12 8 7 V |r| = T |a+e/b| * ( F |c| 0 2 4 6 12 8 6 V |r| = T |a+e/b| * ( T |c| 0 2 4 6 12 8 14 V |r| = T |a+e/b| * ( E |c| 0 2 4 6 12 8 14 11 V |r| = T |a+e/b| * ( E |c| - 0 2 4 6 12 8 14 11 9 V |r| = T |a+e/b| * ( E |c| - d 0 2 4 6 12 8 14 11 7 V |r| = T |a+e/b| * ( E |c| - F |d| 0 2 4 6 12 8 14 11 16 V |r| = T |a+e/b| * ( E |c| - T |d| 0 2 4 6 12 8 14 V |r| = T |a+e/b| * ( E |c-d| 0 2 4 6 12 8 14 19 V |r| = T |a+e/b| * ( E |c-d| ) 0 2 4 6 12 17 V |r| = T |a+e/b| * F |c-d| 0 2 4 6 V |r| = T |a+e/b*c-d| 0 2 4 5 V |r| = E |a+e/b*c-d| 0 1 A |r=a+e/b*c-d| 匹配成功! 四元式: (+,e,a,A) (/,b,A,B) (-,d,c,C) (*,C,B,D) 請按任意鍵繼續. . .
學習總結:
起初,只是想動手做一個手動造表的SLR程式。後來在實際操作的過程中,聽說這次實驗比較難,涉及到分析過程、還包括四元式,就有些覺得不是那麼容易。不過,後來還是鐵了心,想完成一個自動造表的程式,從開始到結尾沒有人為設定的表和其他設定。剛開始做的時候還是比較不太舒服,畢竟規則還沒有掌握清楚,開始上手做時還是不太順利的。到後來慢慢了解整個演算法的原理,再到後來不去翻書也大概明白整個演算法是怎麼回事,主動去迎接一個不是那麼輕鬆就可以完成的實驗...個人感覺收穫還是很大的。目前實驗的不足是部分輸出還不是很規範(不包括在字元介面還是對齊的棧到了word裡面不知道為什麼就不齊了),還有提升空間。
附:完整實現程式碼(詳見.cpp檔案)
/*
完成以下描述賦值語句 SLR(1)文法語法制導生成中間程式碼四元式的過程。
G[A]:
A→V=E
E→E+T∣E-T∣T
T→T*F∣T/F∣F
F→(E)∣i
V→i
[設計說明] 終結符號 i 為使用者定義的簡單變數, 即識別符號的定義。
[設計要求]
(1)構造文法的 SLR(1)分析表,設計語法制導翻譯過程,給出每一產生式對應的語義動作;
(2)設計中間程式碼四元式的結構;
(3)輸入串應是詞法分析的輸出二元式序列,即某賦值語句“專題 1”的輸出結果,
輸出為賦值語句的四元式序列中間檔案;
(4)設計兩個測試用例(儘可能完備),並給出程式執行結果四元式序列。
*/
#include "stdafx.h"
#include <string>
#include <list>
#include <stack>
#include <iostream>
using namespace std;
typedef struct
{
int finish = 0; //是否結束
int tag = 3; //當前圓點的位置
string str;
}sentence;
typedef struct
{
int I; //當前狀態
char Vt; //終結符號
char tag; //r||s
int action; //動作
}act;
typedef struct
{
int I; //當前狀態
char Vn; //非終結符
int next_I; //轉移狀態
}go;
typedef struct
{
int number; //編號
list<sentence> l;
}I; //狀態
typedef struct
{
char op;
char arg1;
char arg2;
char result;
}siyuanshi;
typedef struct
{
char name;
string value; //place
}var; //變數
list<I> DFA; //狀態集
list<char> *First; //FIRST集
list<char> *Follow; //FOLLOW集
list<act> ACTION; //ACTION[i][j]
list<go> GOTO; //GO[i][j]
list<char> Vt; //終結符號集
list<char> Vn; //非終結符號集
char input[100];// = { 'i','=','a','*','(','b','+','c',')','/','d','#' };
void readfile()
{
cout << "讀入實驗一結果:" << endl;
char read[10]; //讀取檔案
FILE *fp;
fp = fopen("text.txt", "r+");
int num = 0;
while (fgets(read, 10, fp) != NULL)
{
int i;
cout<<read;
for (i = 0; i < 10; i++)
if (read[i] == ',')
{
break;
}
input[num] = read[i + 2];
num++;
}
cout << endl;
input[num] = '#';
cout << endl << "輸入串為:" << input << endl << endl;
}
int S[100]; //分析棧
int S_top = 0; //分析棧棧頂
char T[100]; //符號棧 棧頂與分析棧總相同
string value[100]; //儲存符號的屬性
list<siyuanshi> L_sys; //四元式
list<int> sys; //產生四元式的狀態集
list<var> V; //變量表
int result_count = 0;
string G[11] = { "S->A", "A->V=E","E->E+T","E->E-T","E->T","T->T*F","T->T/F","T->F","F->(E)","F->i","V->i" };
act getACTION(int i,char b)
{
char c = b;
if (b >= 'a'&&b <= 'z')
b = 'i';
list<act>::iterator it;
for (it = ACTION.begin(); it != ACTION.end(); it++)
{
if (it->I == i &&it->Vt == b)
{
return *it;
}
}
return {0,0,0,0}; //ERROR
}
int getGOTO(int i, char b)
{
list<go>::iterator it;
for (it = GOTO.begin(); it != GOTO.end(); it++)
{
if (it->I == i &&it->Vn == b)
return it->next_I;
}
return -1; //ERROR
}
char newTemp()
{
char c = 'A';
result_count++;
return c + result_count-1;
}
void SLR()
{
int V_num = 0; //符號表
int index = 0;
S[0] = 0; //init
cout << "分析棧:(| |中的為非終結符號的屬性)" << endl;
while (getACTION(S[S_top],input[index]).tag != 'r' || getACTION(S[S_top], input[index]).action != 0) //acc
{
/* if (input[index] >= 'a'&&input[index] <= 'z')
{
string str = "i";
str += to_string(V_num);
V_num++;
V.push_back({ str,input[index] });
}
for (list<var>::iterator v = V.begin(); v != V.end(); v++)
{
cout << v->name << " " << v->value << endl;
}
*/
if (getACTION(S[S_top], input[index]).tag == 0) //ERROR
{
cout<<"error!"<<endl; //出錯處理
return;
}
else if (getACTION(S[S_top], input[index]).tag == 's')
{ // push
S[S_top + 1] = getACTION(S[S_top], input[index]).action; //push操作
T[S_top + 1] = input[index];
value[S_top + 1] = input[index];
S_top++;
index++; //advance();讀取下一個符號
}
else if(getACTION(S[S_top], input[index]).tag == 'r')
{
char arg1, arg2, result; //四元式
int i = getACTION(S[S_top], input[index]).action; //要規約的產生式
string str = "";
for (int j = 0; j < G[i].length() - 3; j++)
{
// pop操作
if (value[S_top] != "(" && value[S_top] != ")")
{
string ss = "";
ss += value[S_top];
ss += str;
str = string(ss);
}
if (j == 0)
if (value[S_top].length() == 1) //只是單個符號
arg1 = value[S_top][0];
else //查表,查詢符號
{
for (list<var>::iterator v = V.begin(); v != V.end(); v++)
{
if (v->value == value[S_top])
{
arg1 = v->name;
break;
}
}
}
if (j == 2)
if (value[S_top].length() == 1)
arg2 = value[S_top][0];
else
for (list<var>::iterator v = V.begin(); v != V.end(); v++)
{
if (v->value == value[S_top])
{
arg2 = v->name;
break;
}
}
S[S_top] = -1;
T[S_top] = 0;
value[S_top] = "";
S_top--;
}
for (list<int>::iterator ii = sys.begin(); ii != sys.end(); ii++) //生成四元式
if (i == *ii)
{
result = newTemp();
V.push_back({ result,str });
L_sys.push_back({ G[i][4],arg1,arg2,result });
break;
}
//push
S[S_top + 1] = getGOTO(S[S_top], G[i][0]);
T[S_top + 1] = G[i][0];
value[S_top + 1] = str; //屬性傳遞
S_top++;
}
for (int tt = 0; tt <= 15; tt++)
{
if (tt <= S_top)
if (S[tt] >= 10)
cout << S[tt] << " ";
else
cout << S[tt] << " ";
else
cout << " ";
}
for (int tt = 0; tt <= S_top; tt++)
{
if (tt <= S_top)
{
cout << T[tt]<<" ";
if(isupper(T[tt]))
cout << "|" << value[tt] << "| ";
}
else
cout << " ";
}
cout << endl;
}
cout << endl << "匹配成功!" << endl;
cout << endl << "四元式:" << endl;
for (list<siyuanshi>::iterator s = L_sys.begin(); s != L_sys.end(); s++)
{
cout << '(' << s->op << "," << s->arg1 << "," << s->arg2 << ',' << s->result << ')' << endl;
}
}
void print(sentence s)
{
int r;
cout << " ";
for (r = 0; r < s.str.length(); r++)
if (r == s.tag)
cout << "·" << s.str[r];
else
cout << s.str[r];
if (r == s.tag)
cout << "·";
cout << endl;
}
void find(char ch, int tag_Vn)
{
for (int qq = 0; qq < 11; qq++)
{
if (ch == G[qq][0])
{
if (G[qq][3] >= 'A'&&G[qq][3] <= 'Z')
if (G[qq][3] == ch) //避免死迴圈重複查詢
;
else
find(G[qq][3], tag_Vn);
else
{
int tag = 0;
for (list<char>::iterator i = First[tag_Vn].begin(); i != First[tag_Vn].end(); i++)
{
if (*i == G[qq][3])
{
tag = 1;
break;
}
}
if (tag == 0)
First[tag_Vn].push_back(G[qq][3]);
}
}
}
}
int findVn(char c)
{
int tag = -1;
for (list<char>::iterator i = Vn.begin(); i != Vn.end(); i++)
{
tag++;
if (c == *i)
return tag;
}
return -1;
}
void scan() //構造符號集
{
for (int i = 0; i < 11; i++)//文法長度
{
for (int j = 0; j < G[i].length(); j++)
{
if (j == 1 || j == 2)
continue;
if (isupper(G[i][j]))
{
if (find(Vn.begin(), Vn.end(), G[i][j]) == Vn.end())
Vn.push_back(G[i][j]);
}
else
{
if (find(Vt.begin(), Vt.end(), G[i][j]) == Vt.end())
Vt.push_back(G[i][j]);
}
}
}
Vt.push_back('#');
First = new list<char>[Vn.size()];
int tag_Vn = -1;
for (list<char>::iterator ch = Vn.begin(); ch != Vn.end(); ch++)
{
tag_Vn++;
for (int qq = 0; qq < 11; qq++)
{
if (*ch == G[qq][0])
{
if (G[qq][3] >= 'A'&&G[qq][3] <= 'Z')
{
find(G[qq][3], tag_Vn);
}
else
{
First[tag_Vn].push_back(G[qq][3]);
}
}
}
}
Follow = new list<char>[Vn.size()];
Follow[0].push_back('#');
int follow_sum = 0; //follow集數量總和
int previous_sum = -1; //之前的總和
while (follow_sum != previous_sum)
{
for (int i = 0; i < 11; i++)
{
for (int j = 3; j < G[i].length() - 1; j++)
{
if (isupper(G[i][j]))
if (!isupper(G[i][j + 1])) //是終結符號
{
int tag = 0;
for (list<char>::iterator ii = Follow[findVn(G[i][j])].begin(); ii != Follow[findVn(G[i][j])].end(); ii++)
{
if (*ii == G[i][j + 1])
{
tag = 1;
break;
}
}
if (tag == 0)
Follow[findVn(G[i][j])].push_back(G[i][j + 1]);
}
else //是非終結符號
{
for (list<char>::iterator ii = Follow[findVn(G[i][j + 1])].begin(); ii != Follow[findVn(G[i][j + 1])].end(); ii++)
{
if (find(Follow[findVn(G[i][j + 1])].begin(), Follow[findVn(G[i][j + 1])].end(), *ii) == Follow[findVn(G[i][j + 1])].end()) //不重複
Follow[findVn(G[i][j])].push_back(*ii);
}
}
}
if (isupper(G[i][G[i].length() - 1]))
for (list<char>::iterator ii = Follow[findVn(G[i][0])].begin(); ii != Follow[findVn(G[i][0])].end(); ii++)
{
if (find(Follow[findVn(G[i][G[i].length() - 1])].begin(), Follow[findVn(G[i][G[i].length() - 1])].end(), *ii) == Follow[findVn(G[i][G[i].length() - 1])].end()) //不重複
Follow[findVn(G[i][G[i].length() - 1])].push_back(*ii);
}
}
previous_sum = follow_sum;
follow_sum = 0;
for (int ii = 0; ii < Vn.size(); ii++)
{
follow_sum += Follow[ii].size();
}
}
list<char>::iterator iter;
cout<<"終結符號集:";
for (iter = Vt.begin(); iter != Vt.end(); iter++)
{
cout<<*iter;
}
cout << endl;
cout<<"非終結符號集:";
for (iter = Vn.begin(); iter != Vn.end(); iter++)
{
cout << *iter;
}
cout << endl;
int pp;
cout << "FIRST" << endl;
for (pp = 0, iter = Vn.begin(); pp < Vn.size(); pp++, iter++)
{
cout << *iter << " ";
for (list<char>::iterator ch = First[pp].begin(); ch != First[pp].end(); ch++)
{
cout << *ch << " ";
}
cout << endl;
}
cout <<"FOLLOW"<< endl;
for (pp = 0, iter = Vn.begin(); pp < Vn.size(); pp++, iter++)
{
cout << *iter << " ";
for (list<char>::iterator ch = Follow[pp].begin(); ch != Follow[pp].end(); ch++)
{
cout << *ch << " ";
}
cout << endl;
}
}
I closure(I &dfa)
{
list<sentence>::iterator iter;
for (iter = dfa.l.begin(); iter != dfa.l.end(); iter++)
{
if ((iter->tag <= iter->str.length()))
if ((iter->str[iter->tag] >= 'A'&&iter->str[iter->tag] <= 'Z'))
{
for (int tt = 0; tt < 11; tt++) //查詢對應的產生式
{
if (iter->str[iter->tag] == G[tt][0])
{
int q = 0;
list<sentence>::iterator it;
sentence x;
x.str = G[tt];
for (it = dfa.l.begin(); it != dfa.l.end(); it++)
{
if ((it->str == x.str) && (it->tag == x.tag))
{
q = 1;
break;
}
}
if (q == 0)
{
dfa.l.push_back(x);
}
}
}
}
}
return dfa;
}
int compare(I a, I b) //是否相等
{
if (a.l.size() != b.l.size())
return 1;
else
{
for (list<sentence>::iterator iii = a.l.begin(), jjj = b.l.begin(); iii != a.l.end() || jjj != b.l.end(); iii++, jjj++)
if (iii->str != jjj->str || iii->tag != jjj->tag) //判斷是否相等
{
return 1;
}
}
return 0;
}
void table()
{
int num = 0;
sentence first; //起始符號
first.str = G[0];
I L;
L.number = 0;
L.l.push_back(first);
DFA.push_back(L);
list<I>::iterator dfa;
for (dfa = DFA.begin(); dfa != DFA.end(); dfa++)
{
list<sentence>::iterator iter;
closure(*dfa);
for (iter = dfa->l.begin(); iter != dfa->l.end(); iter++) //對狀態中的每一產生式右部進行處理
if (iter->finish == 0)
{
I C; //新狀態
C.number = DFA.size();
if (iter->tag < iter->str.length()) //尚未完成
{
sentence s;
s.str = iter->str;
if (iter->str[iter->tag] >= 'A'&&iter->str[iter->tag] <= 'Z')
{
GOTO.push_back({ dfa->number,iter->str[iter->tag],C.number });
}
else
{
ACTION.push_back({ dfa->number,iter->str[iter->tag],'s',C.number });
}
s.tag = iter->tag + 1;
iter->finish = 1;
C.l.push_back(s);
list<sentence>::iterator i;
for (i = iter, i++; i != dfa->l.end(); i++)
if (i->str[i->tag] == iter->str[iter->tag])
{
s.str = i->str;
s.tag = i->tag + 1;
i->finish = 1;
C.l.push_back(s);
}
int judge = 0, count = 0;
for (list<I>::iterator ii = DFA.begin(); ii != DFA.end(); ii++, count++) //判斷是否有重複
{
judge = compare(*ii, closure(C)); //修改C
if (judge == 0)
break;
}
if (judge == 0)
{
if (iter->str[iter->tag] >= 'A'&&iter->str[iter->tag] <= 'Z')
{
GOTO.pop_back();
GOTO.push_back({ dfa->number,iter->str[iter->tag], count });
}
else
{
ACTION.pop_back();
ACTION.push_back({dfa->number,iter->str[iter->tag],'s',count});
}
}
else
DFA.push_back(C);
}
else //已經完成
{
int cc = 0, tt;
for (tt = 0; tt < 11; tt++)
{
if (iter->str == G[tt])
break;
}
for (list<char>::iterator c = Vn.begin(); c != Vn.end(); c++, cc++)
if (*c == iter->str[0])
break;
for (list<char>::iterator c = Follow[cc].begin(); c != Follow[cc].end(); c++)
{
ACTION.push_back({ dfa->number,*c,'r',tt }); //對應的第j條產生式
for (int ss = 3; ss < G[tt].length(); ss++) //查詢四元式對應的產生式
if ( G[tt][ss] == '+' || G[tt][ss] == '-' || G[tt][ss] == '*' || G[tt][ss] == '/')
{
sys.push_back(tt);
}
}
}
}
}
num = 0;
for (dfa = DFA.begin(); dfa != DFA.end(); dfa++)
{
cout << "狀態" << num++ << ":" << endl;
for (list<sentence>::iterator iii = dfa->l.begin(); iii != dfa->l.end(); iii++)
{
print(*iii);
}
}
for (list<go>::iterator g = GOTO.begin(); g != GOTO.end(); g++)
{
cout <<"GOTO("<< g->I << ", " << g->Vn << ") = " << g->next_I <<endl;
}
for (list<act>::iterator a = ACTION.begin(); a != ACTION.end(); a++)
{
cout << "ACTION(" << a->I << ", " << a->Vt << ") = " << a->tag << a->action << endl;
}
cout << endl;
}
int main()
{
readfile();
scan();
table();
SLR();
return 0;
}