编译原理实验:自下而上语法分析

  • 1. 实验题目:自下而上语法分析
    • 实验目的
    • 实验内容
    • 实验要求
    • 输入输出
  • 2. 设计思想
  • 3. 算法流程
  • 4. 源程序
  • 5. 调试数据

1. 实验题目:自下而上语法分析

实验目的

  1. 给出PL/0文法规范,要求编写PL/0语言的语法分析程序。
  2. 通过设计、编制、调试一个典型的自下而上语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。
  3. 选择最有代表性的语法分析方法,如算符优先分析法、LR分析法;或者调研语法分析器的自动生成工具YACC的功能与工作原理,使用YACC生成一个自底向上的语法分析器。

实验内容

 已给 PL/0 语言文法,构造表达式部分的语法分析器。
 分析对象〈算术表达式〉的 BNF 定义如下:
 <表达式> ::= [+|-]<项>{<加法运算符> <项>}
 <项> ::= <因子>{<乘法运算符> <因子>}
 <因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
 <加法运算符> ::= +|-
 <乘法运算符> ::= *|/
 <关系运算符> ::= =|#|<|<=|>|>=

实验要求

  1. 将实验一“词法分析”的输出结果,作为表达式语法分析器的输入,进行语法解析,对于语法正确的表达式,报告“语法正确法错误的表达式,报告“语法错误”, 指出错误原因。
  2. 把语法分析器设计成一个独立一遍的过程。
  3. 采用算符优先分析法或者LR分析法实现语法分析;或者调研语法分析器的自动生成工具YACC的功能与工作原理,使用YACC生成一个自底向上的语法分析器。

输入输出

输入:
 PL/0 表达式,用实验一的输出形式作为输入。例如:对于 PL/0 表达式,(a+15)*b 用下列形式作为输入:
 (lparen,( )
 (ident, a)
 (plus, + )
 (number, 15)
 (rparen,) )
 (times, * )
 (ident, b )
输出:
 对于语法正确的表达式,报告“语法正确”;
 对于语法错误的表达式,报告“语法错误”, 指出错误原因

2. 设计思想

对于文法G:
  <表达式> ::= [+|-]<项>{<加法运算符> <项>}
  <项> ::= <因子>{<乘法运算符> <因子>}
  <因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
  <加法运算符> ::= +|-
  <乘法运算符> ::= *|/
  <关系运算符> ::= =|#|<|<=|>|>=

可以改成如下:
  S’-><表达式>
  <表达式>-><项>
  <表达式>-><表达式>+<项>
  <表达式>-><表达式>-<项>
  <项>-><因子>
  <项>-><项>*<因子>
  <项>-><项>/<因子>
  <因子>->(<表达式>)
  <因子>-><标识符>
  <因子>-><无符号整数>
  算符优先分析是定义在算符之间的某种优先关系,借助于这种优先关系寻找可规约串和进行规约。

算符文法的定义:
  所有产生式的右部都不是两个相继并列的非终结符设有一个文法G,如果G中没有形如A→…BC…的产生式,其中B和C为非终结符,则称G为算符文法。
算符优先文法的特点:
  一旦我们构造了算符优先语法分析器,就可以忽略原来的文法,栈中的非终结符仅仅作为与这些非终结符相关的属性的占位符,难以处理像减号这样有不同优先级的符号,由于分析的语言的文法和算符优先语法分析器本身的关系不是很紧密,所以不能肯定语法分析器接受的就是所期望的语言。
对于优先关系进行如下定义:
a的优先级小于b
  (1) a<b: 当且仅当文法G中有形如A→…aR…的产生式而R⇒+b…或R⇒+Qb…
a的优先级等于b
  (2) a=b:当且仅当文法G中有形如A→…ab…或者A→…aQb…的产生式
a的优先级高于b
  (3) a>b:当且仅当文法G中有形如A→…Rb…的产生式,而R⇒+…a或R⇒+…aR
  如果一个算符文法G中的任何终结符对(a,b)至多满足下述三关系之一:
  a<b,a=b,a>b
则称G是一个算符优先文法。
定义并构造FIRSTVT和LASTVT两个集合
FIRSTVT§={a|P⇒+a⋯或P⇒+Qa⋯}
LASTVT§={a|P⇒+⋯a或P⇒+⋯aQ}
在此构造文法的FIRSTVT集和LASTVT集
文法如下
 <表达式> ::= [+|-]<项>{<加法运算符> <项>}
 <项> ::= <因子>{<乘法运算符> <因子>}
 <因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
 <加法运算符> ::= +|-
 <乘法运算符> ::= *|/
 <关系运算符> ::= =|#|<|<=|>|>=

FIRSTVT(表达式)={+,-,(,, /,标识符,无符号整数 }
FIRSTVT(项)={
,/,(,标识符,无符号整数}
FIRSTVT(因子)={(,标识符,无符号整数}
FRTSTVT(加法运算符)={+,-}
FRTSTVT(乘法运算符)={,/}
LASTVT(表达式)={+,-,),
, /,标识符,无符号整数 }
LASTVT(项)={*,/,),标识符,无符号整数}
LASTVT(因子)={),标识符,无符号整数}

构造优先表

实验流程

  1. 根据文法求FIRSTVT集和LASTVT集
  2. 构造算符优先分析表
  3. 构造总控程序
    算法描述如下:
   stack S;k = 1;  //符号栈S的使用深度S[k] = ‘#’REPEAT把下一个输入符号读进a中;If S[k]   VT   then  j = k  else  j = k-1;While S[j] > a  doBeginRepeatQ = S[j];if  S[j-1]   VT  then  j = j-1  else   j = j-2until  S[j] < Q;把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;K = j+1;S[k] = N;end of whileif S[j] < a  or  S[j] = a  thenbegin  k = k+1; S[k] = a      endelse  error //调用出错诊察程序until a = ‘#’
  1. 对给定的表达式,给出准确与否的分析过程
  2. 给出表达式的计算结果。

3. 算法流程

4. 源程序

#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
#define MAXN 9
using namespace std;
ifstream infile("C:\\Users\\46799\\Desktop\\编译原理\\第三次实验\\result.txt");
map<string,int> order;//定义终结符在优先表中的序号
stack<string> s,save;//s为符号栈,save为临时存储符号的容器
vector<string> Terminal;//用来存放终结符,以此来进行对照,检查是不是终结符
vector<string>::iterator result;//一个迭代器来判断是不是终结符
string reduction[100];//定义本次需要进行规约的符号串
string str;//读入的字符串
string sym;//用来指示读入的符号
int flag=0;
int prioritytable[MAXN][MAXN]={{0,0,1,1,1,1,1,2,2},//算符优先分析的优先表,0代表=,1代表<,2代表>,3代表空{0,0,1,1,1,1,1,2,2},{2,2,0,0,1,1,1,2,2},{2,2,0,0,1,1,1,2,2},{2,2,2,2,0,3,3,2,2},{2,2,2,2,3,0,3,2,2},{1,1,1,1,1,1,1,0,2},{2,2,2,2,3,3,0,2,2},{1,1,1,1,1,1,1,1,0}};
void init(){//进行初始化,定义终结符的序号,以及简化终结符的查找通过vector的find函数order["plus"]=0;order["minus"]=1;order["times"]=2;order["slash"]=3;order["ident"]=4;order["number"]=5;order["lparen"]=6;order["rparen"]=7;order["#"]=8;for(int i=0;i<9;i++){Terminal.push_back("plus");Terminal.push_back("minus");Terminal.push_back("times");Terminal.push_back("slash");Terminal.push_back("ident");Terminal.push_back("number");Terminal.push_back("lparen");Terminal.push_back("rparen");Terminal.push_back("#");}
}
int judgePrior(string a,string b){//从优先关系表中判断两个符号的优先关系int row_prior,column_prior;//行列优先关系定位指针row_prior=order[a];column_prior=order[b];if(prioritytable[row_prior][column_prior]==0){//=return 0;}else if(prioritytable[row_prior][column_prior]==1){//<return 1;}else if(prioritytable[row_prior][column_prior]==2){//>return 2;}else return 3;//空
}
int advance(){//用来读入下一个符号int found;if(!getline(infile,str)){flag++;if(flag==1){sym="#";return 1;}else if(flag>1){return 0;}}found=str.find(',',0);sym=str.substr(1,found-1);return 1;
}
int SearchSyn(string c){//根据相应字符返回其对应序号return order[c];
}
int SearchTerminal(string c){//判断是不是终结符result=find(Terminal.begin(),Terminal.end(),c);if(result == Terminal.end()){return 0;}else{return 1;}
}int Proc_Analysis(){//主控程序int k=1,j=0;string a,b,q;s.push("#");//符号栈S将#推入while(advance()){//把下一个输入符号读进a中;if(SearchTerminal(s.top())){j=k;q=s.top();}else{j=k-1;b=s.top();s.pop();save.push(b);q=s.top();}while(judgePrior(q,sym)==2){//判断优先关系While S[j] > a  doif(!SearchTerminal(s.top())){b=s.top();s.pop();save.push(b);}do{ //If S[k]   VT   then  j = k  else  j = k-1;如果不为终结符则将要跳到下一个字符b=s.top();s.pop();save.push(b);j--;if(SearchTerminal(s.top())){q=s.top();}else{save.push(s.top());s.pop();q=s.top();j--;}}while(judgePrior(q,b)!=1);for(int i=0;i<k-j;i++){//这里我对需要规约的串进行存储,以方便规约b=save.top();save.pop();reduction[i]=b;}for(int i=0;i<k-j;i++){cout<<reduction[i]<<" ";}cout<<endl;//如下为进行规约if(reduction[0]=="term"){//<表达式> ::= <项>{<加法运算符> <项>}if(!((k-j)%2)){printf("语法错误,表达式归约错误");return 0;}for(int i=0;i<k-j;i++){if(!(i%2)){if(reduction[i]!="term"){printf("语法错误,表达式归约错误");return 0;}}else{if(reduction[i]!="plus"||reduction[i]!="minus"){printf("语法错误,表达式归约错误");return 0;}}k=j+1;s.push("expression");}}else if(reduction[0]=="factor"){//<项> ::= <因子>{<乘法运算符> <因子>}if(!((k-j)%2)){printf("语法错误,项归约错误");return 0;}for(int i=0;i<k-j;i++){if(i%2){if(reduction[i]!="factor"){printf("语法错误,项归约错误");return 0;}}else{if(reduction[i]!="times"||reduction[i]!="slash"){printf("语法错误,项归约错误");return 0;}}}k=j+1;s.push("term");}else if(reduction[0]=="lparen"){//<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’if(reduction[0]=="lparen"){if((k-j)!=3){printf("语法错误,因子归约错误");return 0;}if(reduction[1]!="expression"||reduction[2]!="rparen"){printf("语法错误,因子归约错误");return 0;}}k=j+1;if(s.top()!="times"||s.top()!="slash"||sym!="times"||sym!="slash"){s.push("term");}else s.push("factor");//这里我直接将因子直接化成项,但正确性还有待考虑}else if(reduction[0]=="number"||reduction[0]=="ident"){//<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’k=j+1;if(s.top()!="times"||s.top()!="slash"||sym!="times"||sym!="slash"){s.push("term");}else s.push("factor");}else{printf("语法错误,字符错误");return 0;}}if(judgePrior(q,sym)==1||judgePrior(q,sym)==0){k++;s.push(sym);}}if(k==3){//如果最后为#表达式#则正确for(int i=0;i<3;i++){b=s.top();s.pop();if(i==0&&b!="#"){printf("语法错误,表达式错误");return 0;}else if(i==1&&b!="expression"){printf("语法错误,表达式错误");return 0;}else if(i==2&&b!="#"){printf("语法错误,表达式错误");return 0;}}return 1;}else{printf("语法错误,表达式错误");return 0;}
}
int main(){init();int right=Proc_Analysis();if(right){cout<<"语法正确"<<endl;}return 0;
}

5. 调试数据

待输入的文件流:

输出数据:

编译原理实验:自下而上语法分析相关推荐

  1. 编译原理--实验2 语法分析

    文章目录 前言 1.1实验目的 1.2 实验任务 1.3 实验内容 1.3.1 实验要求 1.3.2 输入格式 1.3.3 输出格式 1.3.4 样例 1.4 程序 1.4.1 程序流程图 1.4.2 ...

  2. 编译原理实验二:赋值语句的语法分析程序设计

    编译原理实验二:赋值语句的语法分析程序设计 1.1实验内容 目的: 在前面实验的基础上,通过设计.编制.调试一个典型的赋值语句的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查,进一步掌握 ...

  3. 编译原理实验:自上而下语法分析

    编译原理实验:自上而下语法分析 1. 实验题目:自上而下语法分析 实验目的 实验内容 实验要求 输入输出 2. 设计思想 3. 算法流程 4. 源程序 5. 调试数据 1. 实验题目:自上而下语法分析 ...

  4. 编译原理实验(三)——LR(0)语法分析

    编译原理实验(三)--LR(0)语法分析 实验要求 参考程序 实验结果 程序输入说明 截图 实验要求 根据LR(0)分析法编写一个语法分析程序 直接输入根据已知文法构造的分析表M;对于输入的文法和符号 ...

  5. 编译原理实验:代码生成作业(1)

    编译原理实验4:中间代码生成实验包-C++文档类资源-CSDN下载编译原理实验4:中间代码生成实验包更多下载资源.学习资料请访问CSDN下载频道.https://download.csdn.net/d ...

  6. 编译实验 lr c语言代码,编译原理-实验5-LR(1)分析法

    <编译原理-实验5-LR(1)分析法>由会员分享,可在线阅读,更多相关<编译原理-实验5-LR(1)分析法(6页珍藏版)>请在人人文库网上搜索. 1.编译原理实验报告项目名称 ...

  7. 编译原理实验三 语义分析程序设计与实现

    一.实验目的 在实现词法.语法分析程序的基础上,编写相应的语义子程序,进行语义处理,加深对语法制导翻译原理的理解,进一步掌握将语法分析所识别的语法范畴变换为某种中间代码(四元式)的语义分析方法,并完成 ...

  8. 编译原理实验二:Bison

    编译原理实验二:Bison 实验要求 1.了解Bision基础知识,如何将文法产生式转换为Bison语句 2.阅读/src/common/SyntaxTree.c,对应头文件 /include/Syn ...

  9. 编译原理上机实习c语言小子集编译程序的实现报告,合肥工业大学编译原理实验报告(完整代码版)...

    <合肥工业大学编译原理实验报告(完整代码版)>由会员分享,可在线阅读,更多相关<合肥工业大学编译原理实验报告(完整代码版)(58页珍藏版)>请在人人文库网上搜索. 1.计算机与 ...

最新文章

  1. python 连接sqlite及操作
  2. gearman简介及安装使用
  3. java设计模式观察者模式_Java设计模式(9)——观察者模式
  4. factorymenu什么意思_MENU是什么意思
  5. 线性代数知识点总结_2020考研数学线性代数强化复习重点知识点总结
  6. 指针在c语言中的运用,怎么理解C语言中的指针,如何运用?
  7. 在ubuntu13.04上安装Mac主题
  8. 春考本科2018招计算机的学校,山东2018春季高考本科普通批一志愿院校投档情况统计表...
  9. 《Linux命令行与shell脚本编程大全 第3版》
  10. python可以写前端吗_哪种ide能同时写java和前端代码?
  11. 2021-07-13
  12. Inkscape将位图转换为矢量图
  13. ios 表情符号 键盘_如何在iPhone和iPad上从键盘上删除表情符号按钮
  14. 【自考】数据结构导论
  15. java运维工程师简历_运维工程师个人简历怎么写?
  16. http状态码401
  17. Android检测仪开发---BleBluetooth 多连接
  18. 基于java二次元信息分享平台计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  19. Android软件开发之盘点界面五大布局(十六)
  20. 邵阳市计算机学校某灿,最近喜欢上一首歌。。 大家把自己觉得好听的歌和我分享分享吧。...

热门文章

  1. ActiveX插件的使用
  2. 为什么宝宝腹泻就一定要用中性乳糖酶?
  3. rstudio中ECM 误差校正模型代码
  4. 应用全攻略 10个常用数字证书应用实例
  5. 突破icesword实现文件隐藏
  6. Word2016给英文添加段落编号的方法:有截图
  7. 一分钟搞懂如何修改VOS上话机注册端口
  8. WINDOWS文本编辑器丨EmEditor功能简介
  9. Linux下结束进程的几种命令,linux下进程命令
  10. 【数据结构】【堆】堆的建立、插入和删除