軟件構造——SLR(1)語法分析


實驗目的

構造LR分析程序,利用它進行語法分析,判斷給出的符號串是否為該文法識別的句子,了解LR(K)分析方法是嚴格的從左向右掃描,和自底向上的語法分析方法。

實驗內容

對下列文法,用SLR(1)分析法對任意輸入的符號串進行分析:


(1)S->E

(2)E->E+T

(3)E->T

(4)T->T*F

(5)T->F

(6)F->(E)

(7)F->i

 

設計思想

(1)總控程序,也可以稱為驅動程序。對所有的LR分析器總控程序都是相同的。

(2)分析表或分析函數,不同的文法分析表將不同,同一個文法采用的LR分析器不同時,分析表將不同,分析表又可以分為動作表(ACTION)和狀態轉換(GOTO)表兩個部分,它們都可用二維數組表示。

(3)分析棧,包括文法符號棧和相應的狀態棧,它們均是先進后出棧。

分析器的動作就是由棧頂狀態和當前輸入符號所決定。

u  LR分析器由三個部分組成:

u  其中:SP為棧指針,S[i]為狀態棧,X[i]為文法符號棧。狀態轉換表用GOTO[i,X]=j表示,規定當棧頂狀態為i,遇到當前文法符號為X時應轉向狀態j,X為終結符或非終結符。

u  ACTION[i,a]規定了棧頂狀態為i時遇到輸入符號a應執行。動作有四種可能:

(1)移進:

    action[i,a]= Sj:狀態j移入到狀態棧,把a移入到文法符號棧,其中i,j表示狀態號。

(2)歸約:

    action[i,a]=rk:當在棧頂形成句柄時,則歸約為相應的非終結符A,即文法中有A- B的產生式,若B的長度為R(即|B|=R),則從狀態棧和文法符號棧中自頂向下去掉R個符號,即棧指針SP減去R,並把A移入文法符號棧內,j=GOTO[i,A]移進狀態棧,其中i為修改指針后的棧頂狀態。

(3)接受acc:

    當歸約到文法符號棧中只剩文法的開始符號S時,並且輸入符號串已結束即當前輸入符是'#',則為分析成功。

(4)報錯:

當遇到狀態棧頂為某一狀態下出現不該遇到的文法符號時,則報錯,說明輸入端不是該文法能接受的符號串。

【實驗要求】

1、編程時注意編程風格:空行的使用、注釋的使用、縮進的使用等。

2、如果遇到錯誤的表達式,應輸出錯誤提示信息。

3、程序輸入/輸出實例:

輸入一以#結束的符號串(包括+—*/()i#):在此位置輸入符號串

輸出過程如下:

步驟     狀態棧     符號棧      剩余輸入串            動 作 

 1          0             #          i+i*i#               移進 

【實驗結果】

代碼:

  1 Main.cpp
  2 #include<iostream>
  3 #include<stack>
  4 #include<string>
  5 #include <stdlib.h>
  6 using namespace std;
  7 string action[12][6] = { "S5", "0", "0", "S4", "0", "0",
  8 //ACTION 表
  9 "0", "S6", "0", "0", "0", "acc",
 10 "0", "r2", "S7", "0", "r2", "r2",
 11 "0", "r4", "r4", "0", "r4", "r4",
 12 "S5", "0", "0", "S4", "0", "0",
 13 "0", "r6", "r6", "0", "r6", "r6",
 14 "S5", "0", "0", "S4", "0", "0",
 15 "S5", "0", "0", "S4", "0", "0",
 16 "0", "S6", "0", "0", "S11", "0",
 17 "0", "r1", "S7", "0", "r1", "r1",
 18 "0", "r3", "r3", "0", "r3", "r3",
 19 "0", "r5", "r5", "0", "r5", "r5" };
 20 int gotoarr[12][3] = { 1, 2, 3, //GOTO 表
 21 0, 0, 0,
 22 0, 0, 0,
 23 0, 0, 0,
 24 8, 2, 3,
 25 0, 0, 0,
 26 0, 9, 3,
 27 0, 0, 10,
 28 0, 0, 0,
 29 0, 0, 0,
 30 0, 0, 0,
 31 0, 0, 0 };
 32 char vt[6] = { 'i', '+', '*', '(', ')', '#' }; //存放終結符
 33 char vn[3] = { 'E', 'T', 'F' }; //存放非終結符
 34 string Production[6] = { "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" };//產生式集合
 35 //int com= 0;//記錄當前進行處理的輸入字符串字符位置
 36 int com = 0;
 37 int line = 1;//記錄處理的步驟數
 38 bool flag = false;
 39 int StatusNumber = 1;//棧中狀態數
 40 string stacktd = "#";//記錄符號棧中內容
 41 int Status[50] = { 0 };//記錄狀態棧
 42 stack <char> Stack;//創建一個符號棧
 43 stack <int> status;//創建一個狀態棧
 44 void Judge(int &i, int j, char arr[], char ch, string s){//判斷輸入串是否由文法終結符組成
 45     flag = false;
 46     for (int l = 0; l<j; l++){
 47         if (ch == arr[l]){
 48             flag = true;
 49             i = l;
 50             break;
 51         }
 52     }
 53     if (flag == false){
 54         cout << "\tError" << endl;
 55         //com = s.size();
 56         com = s.size();
 57     }
 58 }
 59 void Outputstatus(){//輸出狀態集
 60     for (int i = 0; i<StatusNumber; i++)
 61         cout << Status[i];
 62 }
 63 void Outputstring(string s){//輸出未處理的字符串
 64     for (int i = com; i<s.size(); i++)
 65         cout << s.at(i);
 66 }
 67 void Output(string s){//輸出步驟、 狀態集、 符號集、 輸入串
 68     cout << line << "\t";
 69     Outputstatus();
 70     cout << "\t" << stacktd << "\t";
 71     Outputstring(s);
 72     cout << "\t\t";
 73     line++;
 74 }
 75 void Shift(int i, string s){//移進函數 S
 76     Output(s);
 77     cout << "ACTION[" << status.top() << "," << s.at(com) << "]=S" << i << ",狀態" << i << "入棧" << endl;
 78     status.push(i);//將狀態 i 壓進狀態
 79     Status[StatusNumber] = i;//Status 記錄狀態棧的內容
 80     Stack.push(s.at(com));//將當前面臨的輸入串符號壓進符號棧
 81     stacktd = stacktd + s.at(com);//stacktd 記錄符號棧的內容
 82     com++;//當前面臨的輸入串字符往后移一位
 83     StatusNumber++;//狀態數加一
 84 }
 85 void Goto(stack <int> st1, stack <char> st2, string s){//GoTo 語句
 86     int j = -1;
 87     int ch1 = st1.top();
 88     char ch2 = st2.top();
 89     Judge(j, 3, vn, ch2, s);//求得 ch2 在非終結符表中的位置
 90     if (gotoarr[ch1][j] == 0){
 91         cout << "\tError" << endl;
 92         com = s.size();
 93     }
 94     else{
 95         status.push(gotoarr[ch1][j]);//新狀態進棧
 96         Status[StatusNumber] = gotoarr[ch1][j];
 97         StatusNumber++;
 98     }
 99 }
100 void Reduction(int i, string s){//歸約函數 R
101     Output(s);
102     cout << "r" << i << ":" << Production[i - 1] << "歸約, GoTo(";
103     int N = Production[i - 1].length() - 3;
104     for (int j = 0; j<N; j++){//消除要歸約的狀態及符號
105         status.pop();
106         Stack.pop();
107         StatusNumber--;
108         stacktd.erase(stacktd.length() - 1);
109     }
110     cout << status.top() << "," << Production[i - 1].at(0) << ")=";
111     Stack.push(Production[i - 1].at(0));//符號進棧
112     stacktd = stacktd + Stack.top();
113     Goto(status, Stack, s);
114     cout << status.top() << "入棧" << endl;
115     Status[StatusNumber] = status.top();
116 }
117 void Analyse(string s){//具體分析函數
118     Stack.push('#');//初始化
119     status.push(0);
120     s = s + "#";
121     int t = -1;//記錄 ch 在數組 vt 的位置
122     while (com<s.size()){
123         int i = status.top();
124         char ch = s.at(com);
125         Judge(t, 6, vt, ch, s);
126         if (flag == true){
127             if (action[i][t] != "acc"&&action[i][t] != "0"){
128                 if (action[i][t].at(0) == 'S'){
129                     action[i][t].erase(0, 1); //刪除 action[i][t]的首字母 S
130                     Shift(atoi(action[i][t].c_str()), s);//atoi(action[i][t].c_str()), 將action[i][t]轉換為整型
131                     action[i][t].insert(0, "S");//將 S 添加回 action[i][t]
132                 }
133                 else if (action[i][t].at(0) == 'r'){
134                     action[i][t].erase(0, 1);//刪除 action[i][t]的首字母 r
135                     Reduction(atoi(action[i][t].c_str()), s);//atoi(action[i][t].c_str()), 將action[i][t]轉換為整型
136                     action[i][t].insert(0, "r");//將 r 添加回 action[i][t]
137                 }
138             }
139             else if (action[i][t] == "0"){
140                 cout << "\tError" << endl;
141                 break;
142             }
143             else if (action[i][t] == "acc"){
144                 Output(s);
145                 cout << "acc" << "\t 分析成功" << endl;
146                 break;
147             }
148         }
149         else if (flag == false)
150             break;
151     }
152 }
153 int main(){
154     string s;
155     cout << "************************20173599周博*************************" << endl;
156     cout << "輸入的文法" << endl;
157     for (int j = 0; j < 6; j++)
158     {
159         cout << Production[j] << endl;
160     }
161     cout << "VT:" << endl;
162     for (int i = 0; i < 6; i++)
163     {
164         cout << vt[i] << "\t";
165     }
166     cout << endl;
167     for (int i = 0; i <3; i++)
168     {
169         cout << vn[i] << "\t";
170     }
171     cout << endl;
172     cout << "************************LR(1)分析*************************" << endl;
173     char T;
174         cout << "輸入字符串" << endl;
175         cin >> s;//輸入要分析的字符串
176         cout << "************************現進行如下分析*************************" << endl;
177         cout << "步驟" << "\t" << "狀態棧" << "\t" << "符號棧" << "\t" << "剩余輸入串" << "\t" << "動作說明" << endl;
178         Analyse(s);
179         com = 0;//記錄當前進行處理的輸入字符串字符位置
180         line = 1;//記錄處理的步驟數
181         stacktd = "#";
182         StatusNumber = 1;
183         while (!Stack.empty()){
184             Stack.pop();
185         }
186         while (!status.empty()){
187             status.pop();
188         }
189     
190     return 0;
191 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM