【实验目的】
构造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 }