题目描述

要求:

  1. 使用的文法如下:
    E->TE’
    E’->+TE’|ε
    T->FT’
    T’->*FT’|ε
    F->(E)|id
  2. 对于任意给定的输入串(词法记号流)进行语法分析,非递归预测分析方法可以任选其一来实现。
  3. 要有一定的错误处理功能。即对错误能提示,并且能在一定程度上忽略尽量少的记号来进行接下来的分析。可以参考书上介绍的同步记号集合来处理。
    可能的出错情况:ididid, id**id, (id+id, +id+id ……
  4. 输入串以#结尾,输出推导过程中使用到的产生式。例如:
    输入:id+idid#
    输出:
    E ->TE ’
    T ->FT’
    F ->id
    E’->+ TE ’
    T -> FT ’
    ……
    如果输入串有错误,则在输出中要体现是跳过输入串的某些记号了,还是弹栈,弹出某个非终结符或者是终结符了,同时给出相应的出错提示信息。比如:
    idid
    id对应的出错信息是:“输入串跳过记号id,用户多输入了一个id”;
    id**id对应的出错信息是:“弹栈,弹出非终结符F,用户少输入了一个id”
    (id+id对应的出错信息是:“弹栈,弹出终结符 ) ,用户少输入了一个右括号(或者说,括号不匹配)”

有余力的同学可进一步考虑如下扩展:
1.在语法分析的过程中调用词法分析的上机结果,即利用词法分析器来返回一个记号给语法分析器。
2.调用求first集合函数。
编写Follow函数,实现其求解过程。

程序说明

1.本程序采用非递归构造预测分析表的方法实现
2.终结符均采用单个字符(为了寻找终结符和非终结符方便)。处理后的文法如下,其中#代表空串:
E->TE’
E’->+TE’|#
T->FT’
T’->*FT’|#
F->(E)|i
3.程序中并没有给出FIRST集和FOLLOW集的构造方法,均为提前定义好的集合
想要用代码求出FIRST集和FOLLOW集,可以看我的另外一篇文章
编译原理------C++实现求First集和Follow集
4.同步符号(synch)处理存在问题,即第二个测试用例结果不对

代码实例及程序解释

类定义

class pre_analysis {public:set<string> productions;//产生式集合map<string,string> split_productions;//分解后的产生式集合set<string>nonfish;//非终结符set<string>finish;//终结符map<string, set<string>> mfirst;//first集map<string, set<string>>mfollow;//follow集map<map<string, string>, string>pretable;//预测分析表:<<非终结符,输入符号> 值 >void SSS();//将生成式分解成左右两部分void init();//读取文件,初始化生成式集合void getpretable();//构造预测分析表void printpretable();//打印预测分析表bool isInFollow(string nonFinish, string a);//判断一个输入字符是否在一个非终结符的FOLLOW集合中string matchpretable(string s1, string s2);//查找分析表void analysis(string s);//对输入串进行分析
};

初始化内容

1.读取存在文件中的产生式,并放入productions中
2.从产生式中拆分出终结符和非终结符,分别存于finish和nonfish中
3.构造出产生式的FITSR集和FOLLOW集,分别存于mfirst和mfollow中,本程序采用了直接定义的方式
找出终结符和非终结符的代码如下:

//获得终结符和非终结符for (set<string>::iterator it = productions.begin(); it != productions.end(); it++) {string temp = *it;for (int i = 0; i < temp.length(); i++) {if (temp[i] == '-' || temp[i] == '>' || temp[i] == '|')continue;//是大写字母if (temp[i] >= 'A' && temp[i] <= 'Z') {//后面带'if (temp[i + 1] == '\'') {nonfish.insert(temp.substr(i, 2));i++;}else {nonfish.insert(temp.substr(i, 1));}}//是终结符else{finish.insert(temp.substr(i, 1));}}}

构造预测分析表

算法说明:
如果一个产生式中含有“|”,最好对其进行拆分,然后再进行分析
(1)对文法的每个产生式A->@ ,执行(2)和(3)。
(2)对FIRST(@)的每个终结符a,把A ->@ 加入 M[A, a](即加入表中A行a列)。
(3)如果ε在FIRST(@)中,对FOLLOW(A)的每个终结符b(包括),把A−>@加入M[A,b]。(4)如果FOLLOW(A)的非终结符b(包括), 把A ->@ 加入M[A, b]。 (4)如果FOLLOW(A)的非终结符b(包括),把A−>@加入M[A,b]。(4)如果FOLLOW(A)的非终结符b(包括)的表项M[A, b]为空的话,把同步符号sync加入到表项中。
(4)M的其它没有定义的条目都是error。
代码:

//构造预测分析表
void pre_analysis::getpretable() {for (map<string,string>::iterator it = split_productions.begin(); it != split_productions.end(); it++) {bool flag = false;if (it->second.find("|") == it->second.npos) {//产生式不含有 |if (mfirst.count(it->first) > 0) {set<string> temp = mfirst[it->first];//找到first集for (set<string>::iterator i = temp.begin(); i != temp.end(); i++) {if (*i == "#") {//如果 # 在first集中flag = true;//把该产生式follow集中的元素加入到分析表set<string> temp_follow = mfollow[it->first];for (set<string>::iterator it_follow = temp_follow.begin(); it_follow != temp_follow.end(); it_follow++) {map<string, string> temppp;temppp[it->first] = *it_follow;pretable[temppp] = it->second;}}else {//如果 # 不在first集中map<string, string>tempp;tempp[it->first] = *i;pretable[tempp] = it->second;}}}}else//产生式含有 |{//处理 |string body = it->second;vector<string> v;istringstream iss(body);string token;while (getline(iss, token, '|')) {v.push_back(token);}for (string s : v) {if (mfirst.count(s) > 0) {set<string> have_temp = mfirst[s];//找到first集for (set<string>::iterator i = have_temp.begin(); i != have_temp.end(); i++) {if (*i == "#") {//如果 # 在first集中flag = true;//把该产生式follow集中的元素加入到分析表set<string> have_temp_follow = mfollow[it->first];for (set<string>::iterator it_follow = have_temp_follow.begin(); it_follow != have_temp_follow.end(); it_follow++) {map<string, string> have_temppp;have_temppp[it->first] = *it_follow;pretable[have_temppp] = "#";}}else {//如果 # 不在first集中map<string, string>have_tempp;have_tempp[it->first] = *i;pretable[have_tempp] = s;}}}}}//如果没有产生式可以推出空串,将其FOLLOW集添加同步集合if (flag == false) {set<string>no_follow = mfollow[it->first];for (set<string>::iterator i = no_follow.begin(); i != no_follow.end(); i++) {map<string, string>no_follow_tempp;no_follow_tempp[it->first] = *i;pretable[no_follow_tempp] = "synch";}}}
}

写的很繁琐,可以对其进行简化。。。。。。

根据预测分析表对输入串进行分析

算法在代码中有注释,就不介绍了,直接上代码(目前算法是有问题的,希望有大佬可以指正)

//输入式子,进行分析 式子以$结尾
void pre_analysis::analysis(string s) {stack<string> S;string content = "nothing";//content内存储查找预测分析表返回的内容,若分析表为空,content="nothing"S.push("$");S.push("E");//结束符和开始符号入栈cout << "输入" << s;cout << "分析结果:" << endl;/*1 查表,当前表项空白nothing,指向记号流的指针后移;2 查表,当前表项中含有同步记号synch,输入串指针后移,知道看到当前非终结符A的FOLLOW(A)中的元素,将当前栈中的非终结符A弹出栈;3 查表,当前表项中含有空串#,将当前栈中非终结符弹出;3 栈顶终结符和当前指针指向的终结符不匹配,将栈顶终结符弹出栈。4 其他,将当前表项反向压栈;*/for (int i = 0; i < s.length() && !S.empty() ; i++) {content = matchpretable(S.top(), s.substr(i,1));cout << "当前输入符号为" << s.substr(i, 1) <<"   当前栈顶符号为"<<S.top()<< endl;if (s.substr(i, 1) == "$" && S.top() == "$") {cout << "整个串匹配成功!!!!" << endl;}/*else if (s.substr(i, 1) == "$" && S.top() != "$"){i--;cout << "弹栈,弹出终结符" << endl;while (S.top() != "$") {cout << S.top();S.pop();}cout << ",用户少输入这些终结符" << endl;}*/else{if (content == "nothing") {cout << "输入串跳过记号" << s.substr(i, 1) << "用户多输入了一个" << s.substr(i, 1) << endl;}else if (content == "synch") {while (!isInFollow(S.top(),s.substr(i,1))&& i<s.length()){cout << "用户多输入" << s.substr(i,1) << endl;i++;}cout << "遇到synch,弹出栈顶非终结符" + S.top() << endl;i--;S.pop();}else {cout << S.top() << "->" << content << endl;//压栈-弹栈-压栈,相当于逆序压栈stack <string>ss;for (int j = 0; j < content.length(); j++) {if (content[j + 1] == '\'') {ss.push(content.substr(j, 2));j++;}else{ss.push(content.substr(j, 1));}}S.pop();while (!ss.empty()){S.push(ss.top());ss.pop();}if (finish.find(S.top()) != finish.end())//当前栈顶为终结符{if (S.top() == "#") {cout << "弹栈,因为栈顶为#" << endl;S.pop();i--;}else if (s.substr(i, 1) == "$") {//栈顶不是 $,但是当前字符是$cout << "弹栈,弹出" << S.top() << "用户少输了一个" << S.top() << endl;S.top();i--;}else if (S.top() != s.substr(i, 1))//栈顶终结符不匹配{cout << "弹栈,弹出终结符" << S.top() << "用户少输入了" << endl;S.pop();i--;}else if (S.top() == s.substr(i, 1)) //栈顶终结符匹配{cout << "终结符" << S.top() << "匹配成功" << endl;S.pop();}}else{i--;}}}}
}

源程序可以在此进行载//download.csdn.net/download/weixin_41920883/11988047

大连理工大学软件学院编译原理第四次上机-----非递归语法分析相关推荐

  1. 大连理工大学软件学院编译技术课程——MicroC词法分析上机实验

    大连理工大学软件学院编译技术课程--MicroC词法分析上机实验 题目 编写词法分析编译程序 实验目的:对循环语句和条件判断语句编写词法分析编译程序,只能通过一遍扫描完成. 实验要求: (1) 关键字 ...

  2. 【20保研】大连理工大学软件学院2019年优秀大学生学术夏令营通知

    点击文末的阅读原文或者公众号界面左下角的保研夏令营或者公众号回复"夏令营"是计算机/软件等专业的所有保研夏令营信息集合,会一直更新的. 一.院系与学科介绍  大连理工大学软件工程学 ...

  3. 大连理工计算机组成实验,大连理工大学软件学院计算机组成原理实验报告

    <大连理工大学软件学院计算机组成原理实验报告>由会员分享,可在线阅读,更多相关<大连理工大学软件学院计算机组成原理实验报告(57页珍藏版)>请在人人文库网上搜索. 1.大连理工 ...

  4. 山东大学软件学院编译原理2023期末考题

    2022-2023山东大学软件学院编译原理 乾宝回忆版 授课教师:高晓程 一. 简答题 1. 程序框图 2. 有穷自动机是什么?NFA和DFA的区别 3. 推导和规约的概念 4. 什么是语法制导定义( ...

  5. 大连理工大学c语言第三次上机作业答案,大连理工大学软件学院C语言上机第五六章课后题...

    大连理工大学软件学院C语言上机第五六章课后题 五.1. #includeint main() { int a,b,c; float X,Y,Z; scanf("%d%d%d",&a ...

  6. 编译原理第四章练习题

    目录 编译原理第四章作业 课本习题 补充习题 编译原理第四章作业 自己写的不包对,有错请指正 BY hllinyu 2023年3月31日 课本习题 编译原理 第三版 王生原- 清华大学出版社 的那本 ...

  7. 大连理工大学计算机考研调剂,2020年大连理工大学软件学院考研调剂公告

    考研调剂公告各院校已经发布出来了,下面由出国留学网小编为你精心准备了"2020年大连理工大学软件学院考研调剂公告",持续关注本站将可以持续获取更多的考试资讯! 2020年大连理工大 ...

  8. 大连理工大学软件学院博客地址

    大连理工大学软件学院CSDN高校俱乐部博客地址: http://blog.csdn.net/u010455967 转载于:https://www.cnblogs.com/FlightButterfly ...

  9. 计算机网络云南大学实验四,云南大学软件学院计算机网络原理实验四.doc

    云南大学软件学院计算机网络原理实验四 实验四.web服务器套接字编程实验指导 1.实验目的: 编写一个WEB服务器程序,可以接受来自浏览器的访问,并传输页面(包含多个对象)到浏览器.掌握Socket编 ...

最新文章

  1. java导出excel(easypoi)
  2. 手把手教你从系统层面优化深度学习计算
  3. 直流稳压电源的输出特性有哪些
  4. Entity Framework的事务提交
  5. BERT or XLNet,围观NLP巅峰烧钱大战。技术发展太快,如何才能跟得上节奏?
  6. MVC学习笔记2 认识项目的目录结构与核心的DLL
  7. Web服务器捉虫速记
  8. 网关服务Spring Cloud Gateway(三)
  9. 二、python_base
  10. STP协议:生成树协议(二层防环机制:防止网桥网络中冗余链路形成环路工作)
  11. AI(人工智能) TensorFlow 源码下载及编译安装
  12. 算法基本知识,入门必备
  13. Centos Siege测试使用
  14. 大话Ajax,详解~
  15. Spotlight搜索技巧
  16. 泛泛而谈:白话分布式一致性与共识算法
  17. vue3 + uni-app 封装音乐播放插件
  18. 解读大学里的软件工程专业以及其他专业,给高考完的学弟妹一点参考
  19. 计算机英语(编程词汇大全)
  20. 技术分享:应用于厚型气体电子倍增器的高耐压PCB研究

热门文章

  1. word流程图擦除_word画流程图 Word中绘制流程图的正确姿势,这招大多数人不知道...
  2. pymysql、mysqll、django的使用
  3. 微软android studio,Android 入门 - Visual Studio App Center | Microsoft Docs
  4. Java中利用qqemai发送QQ邮件
  5. 小程序图片自适应组件 仿微信聊天图片
  6. X86 栈溢出原理与实现
  7. bit byte 和各进制关系(位、字节、字符、进制)、常见编码格式
  8. PHP APP端支付宝支付
  9. 基于java校园二手物品交易系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  10. python 一行代码(不包含导包)实现1到10的累加_笔试题汇总,含参考答案(持续更新中。。。)...