首页 > 其他分享 >《编译原理》实验三:自下而上语法分析(算符优先分析法)

《编译原理》实验三:自下而上语法分析(算符优先分析法)

时间:2023-06-01 10:57:40浏览次数:41  
标签:算符 grammer ident 终结符 int number 编译 vector 语法分析

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

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


一. 设计思想

1. 文法

因实验二中的文法不是算符优先文法,所以本次实验采用了新的文法。

(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

2. FIRSTVT集和LASTVT集

FIRSTVT(E) = {(,b,z,+,-,*,/} LASTVT(E) = {),b,z,+,-,*,/}
FIRSTVT(T) = {(,b,z,*,/} LASTVT(T) = {),b,z,*,/}
FIRSTVT(F) = {(,b,z} LASTVT(F) = {},b,z}

满足算符优先文法的条件,是算符优先文法。

3.终结符之间的优先关系定义

  • a = b:a的优先级等于b
  • a < b:a的优先级小于b
  • a > b:a的优先级大于b

4. 优先关系表

  + - * / ( ) b z #
+ > > < < < > < < >
- > > < < < > < < >
* > > > > < > < < >
/ > > > > < > < < >
( < < < < < = < <  
) > > > > >   >   >
b > > > >   >     >
z > > > >   >     >
# < < < < <   < < =

二. 算法流程

三. 源程序

  1 #include <iostream>
  2 #include <string>
  3 #include <vector>
  4 #include <map>
  5 #include <stack>
  6 #include <set>
  7 using namespace std;
  8 
  9 const int nt_num=10;    // 非终结符数目
 10 const int t_num=10;     // 终结符数目
 11 
 12 vector<string> grammer;   // 文法
 13 vector<vector<char> > FirstVT(nt_num,vector<char>(0));
 14 vector<vector<char> > LastVT(nt_num,vector<char>(0));   // FirstVT集和LastVT集
 15 vector<vector<string> > input;   // 输入(','两边)
 16 
 17 vector<char> nonterminal,terminal;   // 非终结符数组 终结符数组
 18 map<char,int> ntchar2idx;   // 非终结符转下标
 19 map<char,int> tchar2idx;   // 终结符转下标
 20 vector<vector<int> > table(nt_num,vector<int>(nt_num,-5));   // 优先关系表:>为1;=为0;<为-1;5为error
 21 stack<char> s1,s2;   // s2作为临时存储
 22 
 23 void getNonterminal(string s)   // 得到非终结符
 24 {
 25     nonterminal.push_back(s[0]);   // 文法的首字母一定为非终结符,且'->'后不用考虑
 26 }
 27 
 28 void getTerminal(string s,set<char>& temp_terminal)   // 得到终结符,当s="over"时说明可将临时set存入永久vector了
 29 {
 30     if (s=="over")
 31     {
 32         for (set<char>::iterator it=temp_terminal.begin();it!=temp_terminal.end();++it)
 33         {
 34             terminal.push_back(*it);
 35         }
 36         terminal.push_back('#');
 37     }
 38     else
 39     {
 40         for (int i=3;i<(int)s.size();++i)   // '->'后除'|'和非终结符的均为终结符
 41         {
 42             if (s[i]!='|' && (s[i]<'A' || s[i]>'Z'))
 43             {
 44                 temp_terminal.insert(s[i]);
 45             }
 46         }
 47     }
 48     return;
 49 }
 50 
 51 bool isTerminal(const char& ch)   // 判断是否为终结符
 52 {
 53     for (int i=0;i<(int)terminal.size();++i)
 54     {
 55         if (ch==terminal[i])
 56         {
 57             return true;
 58         }
 59     }
 60     return false;
 61 }
 62 
 63 void char2idx()   // (非)终结符转下标
 64 {
 65     char ch;
 66     for (int i=0;i<(int)nonterminal.size();++i)
 67     {
 68         ch=nonterminal[i];
 69         ntchar2idx[ch]=i+1;
 70     }
 71     for (int i=0;i<(int)terminal.size();++i)
 72     {
 73         ch=terminal[i];
 74         tchar2idx[ch]=i+1;
 75     }
 76 }
 77 
 78 void createTable()   // 创建优先关系表
 79 {
 80     if (isTerminal('(') && isTerminal(')'))   // 存在终结符'('和')',则优先关系表中为=,0
 81     {
 82         table[tchar2idx['(']][tchar2idx[')']]=0;
 83     }
 84     for (int i=0;i<grammer.size();++i)
 85     {
 86         for (int j=3;j<grammer[i].size();++j)
 87         {
 88             if (grammer[i].size()>4 && isTerminal(grammer[i][j]))
 89             {
 90                 int id=tchar2idx[grammer[i][j]];
 91                 if (!isTerminal(grammer[i][j-1]))   // 前一个字符为非终结符,考虑LASTVT集,>,1
 92                 {
 93                     char ch1=grammer[i][j-1];
 94                     for (int k=0;k<LastVT[ntchar2idx[ch1]].size();++k)
 95                     {
 96                         char ch2=LastVT[ntchar2idx[ch1]][k];
 97                         table[tchar2idx[ch2]][id]=1;
 98                     }
 99                 }
100                 if (!isTerminal(grammer[i][j+1]))   // 后一个字符为非终结符,考虑FIRSTVT集,<,-1
101                 {
102                     char ch1=grammer[i][j+1];
103                     for (int k=0;k<FirstVT[ntchar2idx[ch1]].size();++k)
104                     {
105                         char ch2=FirstVT[ntchar2idx[ch1]][k];
106                         table[id][tchar2idx[ch2]]=-1;
107                     }
108                 }
109             }
110         }
111     }
112     char head=grammer[0][0];   // 起始符
113     // '#'
114     table[tchar2idx['#']][tchar2idx['#']]=0;
115     int id=ntchar2idx[head];
116     for (int i=0;i<LastVT[id].size();++i)
117     {
118         char ch=LastVT[id][i];
119         table[tchar2idx[ch]][tchar2idx['#']]=1;
120     }
121     for (int i=0;i<FirstVT[id].size();++i)
122     {
123         char ch=FirstVT[id][i];
124         table[tchar2idx['#']][tchar2idx[ch]]=-1;
125     }
126     return;
127 }
128 
129 bool ERROR(int pos)
130 {
131 //    cout<<"wrong_pos = "<<pos<<endl;
132     return false;
133 }
134 
135 bool opPriorityAnalyse()   // 算符优先分析程序
136 {
137     s1.push('#');
138     int i=0;
139     string t0;
140     char t1;
141     while (!s1.empty() && i<(int)input.size())
142     {
143         t0=input[i][0];
144         if (t0=="ident")
145         {
146             t1='b';
147         }
148         else if (t0=="number")
149         {
150             t1='z';
151         }
152         else
153         {
154             t1=input[i][1][0];   //非number,右边一定只有一个字符,取[0]即可
155         }
156 
157         if (!isTerminal(s1.top()))   // 栈顶为非终结符,则要跳过它(即压入临时栈s2)
158         {
159             s2.push(s1.top());
160             s1.pop();
161         }
162         int x=tchar2idx[s1.top()],y=tchar2idx[t1];
163         if (table[x][y]==-1 || table[x][y]==0)   // < 或 =,进栈,++i
164         {
165             if (!s2.empty())
166             {
167                 s1.push(s2.top());
168                 s2.pop();
169             }
170             s1.push(t1);
171             ++i;
172         }
173         else if (table[x][y]==1)   // >,归约
174         {
175             int last=x,cur=y;
176             while (table[last][cur]!=-1)   // 直到找到<
177             {
178                 if (table[last][cur]==5) return ERROR(0);   // 找到了ERROR
179                 s2.push(s1.top());
180                 s1.pop();
181                 if (!isTerminal(s1.top()))   // 栈顶为非终结符,则要跳过它(即压入临时栈s2)
182                 {
183                     s2.push(s1.top());
184                     s1.pop();
185                 }
186                 cur=last,last=tchar2idx[s1.top()];
187             }
188             // 对s2中的符号归约
189             string str="";
190             while (!s2.empty())
191             {
192                 str+=s2.top();
193                 s2.pop();
194             }
195             if (str.size()==3 && (str[1]=='+' || str[1]=='-'))
196             {
197                 s1.push('E');
198             }
199             else if (str.size()==3 && (str[1]=='*' || str[1]=='/'))
200             {
201                 s1.push('T');
202             }
203             else if ((str.size()==3 && str[0]=='(') || (str.size()==1 && (str[0]=='b' || str[0]=='z')))
204             {
205                 s1.push('F');
206             }
207             else
208             {
209                 return ERROR(1);
210             }
211         }
212         else   // ERROR
213         {
214             return ERROR(5);
215         }
216     }
217     if (s1.size()==3 && s2.empty())
218     {
219         return true;
220     }
221     else
222     {
223         return ERROR(2);
224     }
225 }
226 
227 vector<char> getFirstVT(char head)   // 求非终结符head的FIRSTVT
228 {
229     if (FirstVT[ntchar2idx[head]].size())
230     {
231         return FirstVT[ntchar2idx[head]];   // 已经求过了,直接返回
232     }
233     set<char> vt;
234     for (int i=0;i<grammer.size();++i)
235     {
236         if (grammer[i][0]==head)
237         {
238             if (grammer[i].size()==4 && grammer[i][3]>='A' && grammer[i][3]<='Z')   // 非终结符->非终结符
239             {
240                 vector<char> temp=getFirstVT(grammer[i][3]);
241                 for (int j=0;j<temp.size();++j)   // 存入
242                 {
243                     vt.insert(temp[j]);
244                 }
245             }
246             else if (grammer[i].size()==4)   // 非终结符->终结符
247             {
248                 vt.insert(grammer[i][3]);
249             }
250             else   // 非终结符->终结符与非终结符的组合
251             {
252                 for (int j=3;j<grammer[i].size();++j)
253                 {
254                     if (isTerminal(grammer[i][j]))
255                     {
256                         vt.insert(grammer[i][j]);
257                         break;
258                     }
259                 }
260             }
261         }
262     }
263     vector<char> ret;
264     for (set<char>::iterator it=vt.begin();it!=vt.end();++it)
265     {
266         ret.push_back(*it);
267     }
268     return ret;
269 }
270 
271 vector<char> getLastVT(char head)   // 求非终结符head的LASTVT
272 {
273     if (LastVT[ntchar2idx[head]].size())
274     {
275         return LastVT[ntchar2idx[head]];   // 已经求过了,直接返回
276     }
277     set<char> vt;
278     for (int i=0;i<grammer.size();++i)
279     {
280         if (grammer[i][0]==head)
281         {
282             if (grammer[i].size()==4 && grammer[i][3]>='A' && grammer[i][3]<='Z')   // 非终结符->非终结符
283             {
284                 vector<char> temp=getLastVT(grammer[i][3]);
285                 for (int j=0;j<temp.size();++j)   // 存入
286                 {
287                     vt.insert(temp[j]);
288                 }
289             }
290             else if (grammer[i].size()==4)   // 非终结符->终结符
291             {
292                 vt.insert(grammer[i][3]);
293             }
294             else   // 非终结符->终结符与非终结符的组合
295             {
296                 for (int j=grammer[i].size()-1;j>=3;--j)
297                 {
298                     if (isTerminal(grammer[i][j]))
299                     {
300                         vt.insert(grammer[i][j]);
301                         break;
302                     }
303                 }
304             }
305         }
306     }
307     vector<char> ret;
308     for (set<char>::iterator it=vt.begin();it!=vt.end();++it)
309     {
310         ret.push_back(*it);
311     }
312     return ret;
313 }
314 
315 void inputGrammer()   // 输入文法
316 {
317     string s,str="";
318     set<char> temp_terminal;   // 临时的termina数组,定义为set防止重复
319     cout<<"请输入文法句数:";
320     int T;cin>>T;
321     cout<<"请输入文法:"<<endl;
322     while (T--)
323     {
324         cin>>s;
325         getNonterminal(s),getTerminal(s,temp_terminal);   // 对每句文法分析得到非终结符和终结符
326         char head=s[0];
327         for (int i=3;i<s.size();++i)   // 将'|'左右的子文法拆开
328         {
329             if (s[i]=='|')
330             {
331                 str="->"+str;
332                 str=head+str;
333 //                cout<<"str="<<str<<endl;
334                 grammer.push_back(str);
335                 str="";
336                 continue;
337             }
338             str+=s[i];
339         }
340         str="->"+str;
341         str=head+str;
342 //        cout<<"str="<<str<<endl;
343         grammer.push_back(str);
344         str="";
345     }
346     getTerminal("over",temp_terminal);
347 
348     char2idx();
349 
350     int id;
351     vector<char> v;
352     for (int i=0;i<nonterminal.size();++i)   // 逐个非终结符求FIRSTVT集和LASTVT集
353     {
354         cout<<nonterminal[i]<<endl;
355         id=ntchar2idx[nonterminal[i]];
356         v=getFirstVT(nonterminal[i]);
357         for (int j=0;j<v.size();++j)
358         {
359             FirstVT[id].push_back(v[j]);
360         }
361         v=getLastVT(nonterminal[i]);
362         for (int j=0;j<v.size();++j)
363         {
364             LastVT[id].push_back(v[j]);
365         }
366     }
367     createTable();
368     return;
369 }
370 
371 int main()
372 {
373     inputGrammer();
374 
375     cout<<"请输入词法分析的结果:"<<endl;
376     string str;
377     vector<string> vec;
378     while (cin>>str)
379     {
380         int pos=str.find(',');
381         vec.clear();
382         vec.push_back(str.substr(1,pos-1));
383         vec.push_back(str.substr(pos+1,str.size()-pos-2));
384         input.push_back(vec);
385     }
386     vec.clear();
387     vec.push_back("#");vec.push_back("#");
388     input.push_back(vec);
389 
390     if (opPriorityAnalyse())
391     {
392         cout<<"Yes,it is correct."<<endl;
393     }
394     else
395     {
396         cout<<"No,it is wrong."<<endl;
397     }
398 
399     return 0;
400 }
View Code

四. 调试数据

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和:=等符号均未引入。

五. 实验调试情况及体会

标签:算符,grammer,ident,终结符,int,number,编译,vector,语法分析
From: https://www.cnblogs.com/hell0er/p/17428986.html

相关文章

  • 【博学谷学习记录】超强总结,用心分享 | python基础学习(数据类型,运算符)
    【博学谷IT技术支持】基础数据类型Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建赋值方式直接赋值a=1#整型变量b=1.0#浮点型变量c='abc'#字符串多个赋值a=b=c=1a,b,c=1,2,3标准数据类型标准数据类型......
  • 编译原理大复习
    Todo:代码优化消除左递归及提取左公因式题型一图解决问题。不再赘述由语言构造文法虽然有五种方法,但是把卷子做完一遍以后,最有效的应该还是分解法,能用到的两种方法记录一下。分解法这个分解法已经写的很清楚了,但是还是拿一个卷子上的例题来记一下:\[S->a^m(ab)^nb^m(m>=1,n>......
  • qt5.15.9 静态编译 msvc 2017
    软件准备:VisualStudio2017ActivePerlPythonopenssl1.1以上版本QT5.15.9源码: https://download.qt.io/archive/qt/5.15/5.15.9/single/ 第一步命令:D:\qt-everywhere-src-5.15.9>configure.bat-prefixD:\Qt\Qt5.15.9-static-static-static-runtime-confirm-li......
  • 关系型运算符 == ,不同字符类型比较,会有个转换
    publicstaticvoidmain(String[]args)throwsException{charc='建';System.out.println((int)c);booleanflag=24314==c;//--不同的字符类型,这里有个自动转型的支持System.out.println(flag);}数据类型之间,提供有转型支......
  • 编译器绕过拷贝构造函数和返回值优化
    写在前面:在拷贝初始化(也就是用等号初始化,注意使用拷贝构造函数创建一个新的对象不属于拷贝初始化)过程中,编译器可以(但不是必须)跳过拷贝构造函数或者移动构造函数,直接创建对象。1stringnull_book="999";2//可以改写为3stringnull_book("999");这里面”999“隐式的转换为......
  • MS SQL Server 中的存储过程是一种预编译的代码块,可以接收输入参数并返回输出结果,用于
    MSSQLServer中的存储过程是一种预编译的代码块,可以接收输入参数并返回输出结果,用于完成特定的数据库操作。它们是SQLServer中存储逻辑业务的一种常见方式。下面是存储过程的优势和劣势:优势:更高的性能:存储过程在首次执行时会被编译和优化,然后将编译后的执行计划缓存起来,......
  • 数据类型与运算符
    数据类型instanceof作用classParent{}classChildextendsParent{}classChild2extendsParent{}publicstaticvoidmain(String[]args){Parentitem=newChild();System.out.println(iteminstanceofObject);System.out.println(itemins......
  • C++ 运算符
     运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C++内置了丰富的运算符,并提供了以下类型的运算符:算术运算符关系运算符逻辑运算符位运算符赋值运算符杂项运算符本章将逐一介绍算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和其他运算符。ht......
  • 开源软件架构总结之——Bash(readline做输入交互式,词法语法分析,进程交互)
    第3章TheBourne-AgainShellBash的主要组件:输入处理,解析,单词展开(wordexpansion)和其他命令处理,管道(pipeline)中的命令执行。这些组件构成一个流水线(pipeline),从键盘或脚本中获取字符,然后逐步转化为命令。图3.1Bash组件结构 3.7.经验教训3.7.1.什么是重要的参与到Bash项目......
  • 【解决一个小问题】macbook m2 上交叉编译 gozstd
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯已知zstd是一个优秀的压缩库,gozstd封装了这个库。一开始在macbookm2芯片的笔记本上开发包含了gozstd的程序时,一切正常。发布的时候,需要分别编译linux+arm64......