首页 > 其他分享 >《编译原理》实验四:自下而上的语法分析(SLR分析法)

《编译原理》实验四:自下而上的语法分析(SLR分析法)

时间:2023-06-17 15:33:47浏览次数:39  
标签:文法 ident 语法分析 样例 back SLR number 编译 push

本实验采用SLR分析法,对PL/0语言的算术运算进行语法分析。

本程序由我个人独立完成,代码为C++98,因此可能较丑陋,且不能保证完全正确,还请见谅 ( ̄□ ̄;)


一. 设计思想

1. 文法

因实验二、三中的文法均不是LR(0)文法,所以本次实验采用了实验三中的文法进行SLR分析。

(1)EBNF

<表达式> ::= [+|-]<项>{<加法运算符> <项>}

<项> ::= <因子>{<乘法运算符> <因子>}

<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’

<加法运算符> ::= +|-

<乘法运算符> ::= *|/

(2)对EBNF中的各对象简称

E:表达式

T:项

F:因子

b:标识符

z:无符号整数

(3)将文法改写成常规的产生式形式

E -> T|E+T|E-T

T -> F|T*F|T/F

F -> (E)|b|z

(4)拓展文法

(0) S -> E

(1) E -> T

(2) E -> E+T

(3) E -> E-T

(4) T -> F

(5) T -> T*F

(6) T -> T/F

(7) F -> (E)

(8) F -> b

(9) F -> z

2. 项目集规范族

其中,I1、I2、I12、I13中存在“移进”-“归约”冲突,所以该文法不是LR(0)文法。

对于I1,Follow(S) = {#} ∩ {+, -} = Ø;

对于I2,Follow(E) = {#, +, -, )} ∩ {*, /} = Ø;

对于I12,Follow(E) = {#, +, -, )} ∩ {*, /} = Ø;

对于I13,Follow(E) = {#, +, -, )} ∩ {*, /} = Ø;

所以,该文法是SLR文法。

3. SLR分析表

Follow(T) = {#, +, -, ), *, /};

Follow(F) = {#, +, -, ), *, /};

状态             ACTION   GOTO
+ - * / b z # E T F
0         S4   S5 S6   1 2 3
1 S7 S8             acc      
2 r1 r1 S9 S10   r1     r1      
3 r4 r4 r4 r4   r4     r4      
4         S4   S5 S6   11 2 3
5 r8 r8 r8 r8   r8     r8      
6 r9 r9 r9 r9   r9     r9      
7         S4   S5 S6     12 3
8         S4   S5 S6     13 3
9         S4   S5 S6       14
10         S4   S5 S6       15
11 S7 S8       S16            
12 r2 r2 S9 S10   r2     r2      
13 r3 r3 S9 S10   r3     r3      
14 r5 r5 r5 r5   r5     r5      
15 r6 r6 r6 r6   r6     r6      
16 r7 r7 r7 r7   r7     r7      

二. 算法流程

三. 源程序

  1 #include <iostream>
  2 #include <string>
  3 #include <vector>
  4 #include <map>
  5 #include <stack>
  6 using namespace std;
  7 
  8 vector<vector<string> > input;   // 输入(逗号两边)
  9 const int nt_num=10;    // 非终结符数目
 10 const int t_num=10;     // 终结符数目
 11 const int st_num=20;    // 状态数
 12 vector<char> nonterminal,terminal;   // 非终结符数组 终结符数组
 13 map<char,int> ntchar2idx;   // 非终结符转下标
 14 map<char,int> tchar2idx;   // 终结符转下标
 15 // SLR分析表——ACTION表:移进为正数,归约为负数,acc为100,其它为0,以省略s、r、acc符号
 16 vector<vector<int> > table_action(st_num,vector<int>(nt_num,0));
 17 vector<vector<int> > table_goto(st_num,vector<int>(t_num,0));   // SLR分析表——GOTO表
 18 vector<string> exgrammer;   // 拓展文法
 19 stack<int> state;   // 状态栈
 20 stack<char> symbol;   // 符号栈
 21 
 22 void getNonterminal()   // 非终结符数组
 23 {
 24     // TODO
 25     nonterminal.push_back('E');
 26     nonterminal.push_back('T');
 27     nonterminal.push_back('F');
 28 }
 29 
 30 void getTerminal()   // 终结符数组
 31 {
 32     // TODO
 33     terminal.push_back('+');
 34     terminal.push_back('-');
 35     terminal.push_back('*');
 36     terminal.push_back('/');
 37     terminal.push_back('(');
 38     terminal.push_back(')');
 39     terminal.push_back('b');
 40     terminal.push_back('z');
 41     terminal.push_back('#');
 42 }
 43 
 44 bool isTerminal(const char& ch)   // 判断是否为终结符
 45 {
 46     for (int i=0;i<(int)terminal.size();++i)
 47     {
 48         if (ch==terminal[i])
 49         {
 50             return true;
 51         }
 52     }
 53     return false;
 54 }
 55 
 56 void char2idx()   // (非)终结符转下标
 57 {
 58     char ch;
 59     for (int i=0;i<(int)nonterminal.size();++i)
 60     {
 61         ch=nonterminal[i];
 62         ntchar2idx[ch]=i;
 63     }
 64     for (int i=0;i<(int)terminal.size();++i)
 65     {
 66         ch=terminal[i];
 67         tchar2idx[ch]=i;
 68     }
 69 }
 70 
 71 void createTable()   // 创建SLR分析表
 72 {
 73     // TODO
 74     // ACTION表
 75     int temp_table_action[st_num][nt_num]={
 76                         {0,0,0,0,4,0,5,6,0},
 77                         {7,8,0,0,0,0,0,0,100},
 78                         {-1,-1,9,10,0,-1,0,0,-1},
 79                         {-4,-4,-4,-4,0,-4,0,0,-4},
 80                         {0,0,0,0,4,0,5,6,0},
 81                         {-8,-8,-8,-8,0,-8,0,0,-8},
 82                         {-9,-9,-9,-9,0,-9,0,0,-9},
 83                         {0,0,0,0,4,0,5,6,0},
 84                         {0,0,0,0,4,0,5,6,0},
 85                         {0,0,0,0,4,0,5,6,0},
 86                         {0,0,0,0,4,0,5,6,0},
 87                         {7,8,0,0,0,16,0,0,0},
 88                         {-2,-2,9,10,0,-2,0,0,-2},
 89                         {-3,-3,9,10,0,-3,0,0,-3},
 90                         {-5,-5,-5,-5,0,-5,0,0,-5},
 91                         {-6,-6,-6,-6,0,-6,0,0,-6},
 92                         {-7,-7,-7,-7,0,-7,0,0,-7}
 93     };
 94     for (int i=0;i<st_num;++i)
 95     {
 96         for (int j=0;j<nt_num;++j)
 97         {
 98             table_action[i][j]=temp_table_action[i][j];
 99         }
100     }
101 
102     // GOTO表
103     int temp_table_goto[st_num][t_num]={
104                         {1,2,3},
105                         {0,0,0},
106                         {0,0,0},
107                         {0,0,0},
108                         {11,2,3},
109                         {0,0,0},
110                         {0,0,0},
111                         {0,12,3},
112                         {0,13,3},
113                         {0,0,14},
114                         {0,0,15},
115                         {0,0,0},
116                         {0,0,0},
117                         {0,0,0},
118                         {0,0,0},
119                         {0,0,0},
120                         {0,0,0}
121     };
122     for (int i=0;i<st_num;++i)
123     {
124         for (int j=0;j<t_num;++j)
125         {
126             table_goto[i][j]=temp_table_goto[i][j];
127         }
128     }
129 }
130 
131 void getExpandedGrammer()   // 拓展文法
132 {
133     exgrammer.push_back("S->E");
134     exgrammer.push_back("E->T");
135     exgrammer.push_back("E->E+T");
136     exgrammer.push_back("E->E-T");
137     exgrammer.push_back("T->F");
138     exgrammer.push_back("T->T*F");
139     exgrammer.push_back("T->T/F");
140     exgrammer.push_back("F->(E)");
141     exgrammer.push_back("F->b");
142     exgrammer.push_back("F->z");
143 }
144 
145 bool ERROR(int pos)
146 {
147     //cout<<"wrong_pos = "<<pos<<endl;
148     return false;
149 }
150 
151 bool SLRAnalyse()   // SLR分析程序
152 {
153     state.push(0);
154     symbol.push('#');
155     int i=0;
156     string t0;
157     char t1;
158     while (i<(int)input.size())
159     {   //cout<<"state.size="<<state.size()<<" symbol.size="<<symbol.size()<<" i="<<i<<endl;
160         t0=input[i][0];
161         if (t0=="ident")
162         {
163             t1='b';
164         }
165         else if (t0=="number")
166         {
167             t1='z';
168         }
169         else
170         {
171             t1=input[i][1][0];
172         }
173 
174         int ret=table_action[state.top()][tchar2idx[t1]];
175         //cout<<"ret="<<ret<<" "<<state.top()<<" "<<t1<<endl;
176         if (ret==100)   // acc
177         {
178             return true;
179         }
180         else if (ret>0)   //移进
181         {
182             //shift()
183             state.push(ret);
184             symbol.push(t1);
185             ++i;
186         }
187         else if (ret<0)   // 归约
188         {
189             //reduce();
190             string g=exgrammer[-ret];
191             int len=g.size()-3;   // 需要归约的长度
192 
193             while (len--)
194             {
195                 state.pop();
196                 symbol.pop();
197             }
198             state.push(table_goto[state.top()][ntchar2idx[g[0]]]);
199             symbol.push(g[0]);
200         }
201         else
202         {
203             return ERROR(0);
204         }
205     }
206     return ERROR(100);   // 未到达acc
207 }
208 
209 int main()
210 {
211     getNonterminal();
212     getTerminal();
213     char2idx();
214     createTable();
215     getExpandedGrammer();
216 
217     string str;
218     vector<string> vec;
219     while (cin>>str)
220     {
221         int pos=str.find(',');
222         vec.clear();
223         vec.push_back(str.substr(1,pos-1));
224         vec.push_back(str.substr(pos+1,str.size()-pos-2));
225         input.push_back(vec);
226     }
227     vec.clear();
228     vec.push_back("#");vec.push_back("#");
229     input.push_back(vec);
230 
231     if (SLRAnalyse())
232     {
233         cout<<"Yes,it is correct."<<endl;
234     }
235     else
236     {
237         cout<<"No,it is wrong."<<endl;
238     }
239 
240     return 0;
241 }
View Code

其中,考虑到建表复杂,SLR分析表为手动填入。

四. 调试数据

1.样例输入:

1 (lparen,()
2 (ident,a)
3 (plus,+)
4 (number,15)
5 (rparen,))
6 (times,*)
7 (ident,b)

样例输出:

Yes,it is correct.

图片展示:

2.样例输入:

 1 (number,0)
 2 (plus,+)
 3 (number,10)
 4 (times,*)
 5 (ident,b)
 6 (minus,-)
 7 (lparen,()
 8 (ident,z)
 9 (slash,/)
10 (number,3)
11 (rparen,))

样例输出:

Yes,it is correct.

图片展示:

3.样例输入:

 1 (lparen,()
 2 (lparen,()
 3 (ident,a)
 4 (plus,+)
 5 (number,3)
 6 (rparen,))
 7 (times,*)
 8 (lparen,()
 9 (number,0)
10 (minus,-)
11 (ident,b)
12 (rparen,))
13 (minus,-)
14 (ident,c)
15 (slash,/)
16 (number,0)
17 (plus,+)
18 (lparen,()
19 (ident,a)
20 (times,*)
21 (ident,d)
22 (slash,/)
23 (ident,e)
24 (plus,+)
25 (ident,f)
26 (rparen,))
27 (rparen,))

样例输出:

Yes,it is correct.

图片展示:

4.样例输入:

1 (lparen,()
2 (ident,a)
3 (plus,+)
4 (number,15)
5 (rparen,))
6 (times,*)

样例输出:

No,it is wrong.

图片展示:

5.样例输入:

1 (ident,a)
2 (plus,+)
3 (number,15)
4 (rparen,))
5 (times,*)
6 (ident,b)

样例输出:

No,it is wrong.

图片展示:

6.样例输入:

 1 (number,0)
 2 (plus,+)
 3 (number,10)
 4 (times,*)
 5 (ident,b)
 6 (lparen,()
 7 (ident,z)
 8 (slash,/)
 9 (number,3)
10 (rparen,))

样例输出:

No,it is wrong.

图片展示:

注:文法只包含简单的+、-、*、/运算等,而像实验1中的const和:=等符号均未引入。

五. 实验调试情况及体会

标签:文法,ident,语法分析,样例,back,SLR,number,编译,push
From: https://www.cnblogs.com/hell0er/p/17432992.html

相关文章

  • Linux 使用交叉编译工具链编译boost
    参考:Boost交叉编译执行./bootstrap.sh后,会生成project-config.jam。修改project-config.jam文件:#if!gccin[feature.values<toolset>]#{#usinggcc:;#}if!gccin[feature.values<toolset>]{usinggcc::/cross-tools/aarch64-poky-linux-gcc--sysro......
  • CMakeLists --- 设置rpath_link方法 编译报错try using -rpath or -rpath-link)
    指令:add_link_options("LINKER:-rpath-link,${THIRD_LIBS_DIR}")THIRD_LIBS_DIR:需要链接的库的目录作用:编译生成一个可执行文件时,依赖一个动态库A,动态库A同时又依赖动态库B.如果我们没有显示集成动态库B时,链接器会去-rpath-link设置的目录中寻找依赖项。 例子:1.库A,依赖库B......
  • QGIS3.22.0+VS2019 window10编译
    首先感谢博客 济南友泉软件有限公司提供的顺序教程。博客地址:https://blog.csdn.net/qq_26221775/article/details/122792445这篇博客主要是表示编译时遇到的坑。1.一定使用vs2019进行编译。我刚开始想使用vs2017编译。因此遇到了两个坑。(1)vs2017编译qgis_cor......
  • 预处理和条件编译
    一、问题引入在编程过程中,使用预处理指令最多的是:#defineBUFFER_MAX_SIZE1024//明示常量#include"xxx.h"//头文件包含但其他预处理指令使用的稍微少点,例如:#ifdef#else#endif#ifndef#if#elif#line#error#pragma。二、解决过程2-1避免用户自定义头文件......
  • CMake命令行添加编译参数
    CMake命令行添加编译参数学习自coroserver例程:https://github.com/windoze/coroservercoroserver是一个应用Boost.Asio和Boost.Coroutine的多线程TCP服务器。README中有编译命令行示例:`CXXFLAGS="-std=c++11-stdlib=libc++"LDFLAGS="-stdlib=libc++"cmake[options]pa......
  • VC2010编译 thrift compiler
    VC2010编译thriftcompiler需flex,bison.bison依赖m4,regex.Pre-Buildevent中flex命令有误,-o与参数间不应该有空格。flex-o"src\\thriftl.cc"src/thriftl.llbison-y-o"src\thrifty.cc"--defines="src/thrifty.h"src/thrifty.yycompiler......
  • MinGw编译Boost
    MinGw编译Boost(金庆的专栏)在MinGwShell中运行bootstrap.sh失败Jinq@jinqing-pc/d/src/boost_1_52_0$bootstrap.shtoolset=gccBuildingBoost.Buildenginewithtoolsetgcc...FailedtobuildBoost.BuildbuildengineConsult'bootstrap.log......
  • Linux编译Windows共享目录下代码
    Linux编译Windows共享目录下代码(金庆的专栏)万神服务器代码是跨平台的。平时策划在Windows上开自己的服务器测试,测试和发布服务器为Linux.开发时,先在Windows上编译测试,再到Linux上编译测试。因为用VC开发,可以使用VAssist,MetalScroll工具辅助,开发效率......
  • C#将字符串编译成程序集并执行
    实现将字符串编译为代码并在程序中使用,实际应用可将字符串保存在文件中,程序启动后读取文件中字符转换为代码执行,这样只需要修改文件不改动代码就可以增删或修改程序功能,提高程序的灵活性。例如,要实现下面的代码:usingSystem;namespaceTestSpace{classTest{......
  • (2023.6.15)linux下can的调试工具交叉编译
    //源码包路径:https://public.pengutronix.de/software/libsocketcan/libsocketcan-0.0.11.tar.bz2https://public.pengutronix.de/software/socket-can/canutils/v4.0/canutils-4.0.6.tar.bz2//编译命令./configure--host=arm-linux-gnueabihf--prefix=/home/fangzeli/work/......