0.LR分析

用一个栈来保存文法符号和状态的信息,一个字符串保存输入信息。

使用栈顶的状态符号和当前的输入符号来检索分析表,来决定移进-归约分析的动作。

1.样例文法

  1. "E>E+T",
  2. "E>T",
  3. "T>T*F",
  4. "T>F",
  5. "F>(E)",
  6. "F>id",

2.分析表(未全部列出)

3.code

  1. //LR分析-demo2
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #include<string>
  6. #include<stack>
  7. #include<map>
  8. using namespace std;
  9. stack<string>stk, tmp, com; //stk是存入s0x1,即状态和符号的栈,tmp是用来输出的栈,
  10. //com是在归约时确定归约式子的栈(防止错误弹出元素)
  11. string input; //输入串
  12. string slr[15][15]; //slr表
  13. string action[] = { //slr表横轴动作+转换
  14. "id","+","*","(",")","$","E","T","F"
  15. };
  16. //i就是id
  17. string handle[] = { //文法
  18. " ",
  19. "E>E+T",
  20. "E>T",
  21. "T>T*F",
  22. "T>F",
  23. "F>(E)",
  24. "F>id",
  25. };
  26. map<string, int> act, status; //转移表
  27. map<string, int>::iterator it_act, it_trans;
  28. string transfer[] = {
  29. "E","T","F"
  30. };
  31. bool flag = false; //accept状态
  32. int now = 0; //当前扫描字符位置
  33. int handle_index = 0; //选中的规约式序号
  34. void init() { //初始化,
  35. int i = 0;
  36. for (i = 0; i < 9;i++) {
  37. act.insert(make_pair(action[i], i)); //建立分析表
  38. }
  39. int j = 0;
  40. while (j<12) {
  41. int i = j;
  42. string t;
  43. if (i < 10)
  44. t = '0' + i;
  45. else {
  46. t = ('0' + (i / 10));
  47. t += ('0' + i % 10);
  48. }
  49. status.insert(make_pair(t, j)); //将状态和数字对应
  50. j++;
  51. }
  52. slr[0][0] = slr[4][0] = slr[6][0] = slr[7][0] = "s5"; //保存slr表
  53. slr[1][1] = slr[8][1] = "s6";
  54. slr[2][1] = slr[2][4] = slr[2][5] = "r2";
  55. slr[2][2] = slr[9][2] ="s7";
  56. slr[0][3] = slr[6][3] = slr[4][3] = slr[7][3] = "s4";
  57. slr[1][5] = "acc";
  58. slr[3][1] = slr[3][2] = slr[3][4] = slr[3][5] = "r4";
  59. slr[5][1] = slr[5][2] = slr[5][4] = slr[5][5] = "r6";
  60. slr[9][1] = slr[9][4] = slr[9][5] = "r1";
  61. slr[8][4] = "s11";
  62. slr[10][1] = slr[10][2] = slr[10][4] = slr[10][5] = "r3";
  63. slr[11][1] = slr[11][2] = slr[11][4] = slr[11][5] = "r5";
  64. slr[0][6] = "1";
  65. slr[0][7] = slr[4][7] = "2";
  66. slr[0][8] = slr[4][8] = slr[6][8] = "3";
  67. slr[4][6] = "8";
  68. slr[6][7] = "9";
  69. slr[7][8] = "10";
  70. }
  71. void show() {
  72. int count_two_char = 0; //数栈中超过两个字符的元素
  73. while (!stk.empty()) { //用两个栈来回倒,输出字符
  74. tmp.push(stk.top());
  75. stk.pop();
  76. }
  77. while (!tmp.empty()) {
  78. cout << tmp.top();
  79. if (tmp.top().size()>1)
  80. count_two_char++;
  81. stk.push(tmp.top());
  82. tmp.pop();
  83. }
  84. cout.setf(ios::right);
  85. cout.width(11 - stk.size()- count_two_char);
  86. cout << "|";
  87. }
  88. //参数1是状态,参数2是符号,符号包括终结符和非终结符,作用是找到slr表中项目
  89. string slrFind(string stat,string ActionAndTransfer) {
  90. string s = stat, a = ActionAndTransfer;
  91. //cout << s + " " + a << endl;
  92. int t1 = status[s]; //取出状态对应下标
  93. int t2 = act[a]; //取出符号对应下标
  94. string tmp;
  95. if (slr[t1][t2] != "") //如果slr表中存在此项
  96. tmp = slr[t1][t2];
  97. else
  98. tmp = "";
  99. //cout << tmp << endl;
  100. return tmp; //返回slr表中的项目
  101. }
  102. //参数1和2同slrFind函数,index是选中的规约式子序号
  103. bool judge(string stat, string Transfer,int &index) {
  104. string judg = slrFind(stat, Transfer); //得到slr表中项目
  105. if (judg[0] != 'r') //如果这个项不是r开头,就不是归约
  106. return false; //非归约直接返回
  107. int i = judg[1] - '0'; //如果是归约,得到归约式子序号
  108. index = i;
  109. return true; //可以发起归约
  110. }
  111. void analysis(string s) {
  112. string w = s;
  113. //cout.setf(ios::right); //设置字符对其方式
  114. //cout.width(10); //设置字符宽度
  115. printf("----------|----------|----------\n");
  116. printf(" 栈 | 输入 | 动作 \n");
  117. printf("----------|----------|----------\n");
  118. while (!flag) { //处于非接受状态
  119. now = 0; //正在处理的输入串中的字符
  120. if (stk.empty()) { //一开始栈为空,直接移进符号
  121. stk.push("0");
  122. cout << "0 |";
  123. cout.setf(ios::right); //设置字符对其方式
  124. cout.width(10); //设置字符宽度
  125. cout << w;
  126. cout << "|移进" << endl;
  127. printf("----------|----------|----------\n");
  128. string t1, t2;
  129. t1 = stk.top();
  130. if (w[now] == 'i') { //移进符号为id
  131. t2 = "id";
  132. now = 2;
  133. }
  134. else { //移进符号不为id
  135. t2 = w[now];
  136. now = 1;
  137. }
  138. stk.push(t2); //将符号压入栈
  139. w = w.substr(now, w.size() - now); //丢弃已扫描的字符
  140. string lr = slrFind(t1, t2); //找到对应的动作
  141. if (lr[0] == 's') //此时是移进
  142. lr = lr.substr(1, lr.size() - 1);
  143. stk.push(lr);
  144. continue;
  145. }
  146. show();
  147. string serach;
  148. if(w[0]!='i') //获取输入串的开头符号
  149. serach =w.substr(0,1);
  150. else
  151. serach = w.substr(0, 2);
  152. //cout << w[0]+""<< endl; //转换字符串不能这么做
  153. if(judge(stk.top(), serach, handle_index)) { //归约,优先级最高
  154. cout.setf(ios::right); //设置字符对其方式
  155. cout.width(10); //设置字符宽度
  156. cout << w;
  157. cout << "|";
  158. cout.setf(ios::left);
  159. cout.width(10);
  160. cout << "按" + handle[handle_index] + "归约" << endl;
  161. printf("----------|----------|----------\n");
  162. string ttt = handle[handle_index].substr(2, handle[handle_index].size() - 2); //得到产生式右部符号
  163. while (ttt != "") {
  164. if (ttt[0] == 'i'){ //将产生式右部所有非终结符暂时压入一个栈中
  165. com.push("id");
  166. ttt=ttt.substr(2, ttt.size() - 2);
  167. }
  168. else
  169. {
  170. string t5;
  171. t5 = ttt[0];
  172. com.push(t5);
  173. ttt=ttt.substr(1, ttt.size() - 1);
  174. }
  175. }
  176. while (!com.empty()) { //用这个有产生式右部所有非终结符的栈和当前栈比对,确定归约式正确
  177. stk.pop();
  178. string cmp1 = stk.top();
  179. if (com.top()==cmp1) {
  180. stk.pop();
  181. com.pop();
  182. }
  183. }
  184. string t3 = handle[handle_index];
  185. t3 = t3[0]; //得到归约式的左部符号
  186. string t4 = slrFind(stk.top(),t3); //用此时左部符号和当前栈顶来确认下一个动作
  187. stk.push(t3);
  188. stk.push(t4);
  189. continue;
  190. }
  191. else { //移进操作--或者acc
  192. cout.setf(ios::right); //设置字符对其方式
  193. cout.width(10); //设置字符宽度
  194. cout << w;
  195. cout << "|";
  196. cout.setf(ios::left);
  197. cout.width(10);
  198. string t1, t2;
  199. t1 = stk.top();
  200. if (w[now] == 'i') { //移进符号为id
  201. t2 = "id";
  202. now = 2;
  203. }
  204. else { //移进符号不为id
  205. t2 = w[now];
  206. now = 1;
  207. }
  208. stk.push(t2); //将符号压入栈
  209. w = w.substr(now, w.size() - now); //丢弃已扫描的字符
  210. string lr = slrFind(t1, t2); //找到对应的动作
  211. if (lr[0] == 's'){ //如果是移进操作
  212. lr = lr.substr(1, lr.size() - 1);
  213. cout << "移进" << endl;
  214. }
  215. else if (lr == "acc") { //或者是接受状态
  216. cout << "接受" << endl;
  217. flag = true;
  218. }
  219. stk.push(lr);
  220. printf("----------|----------|----------\n");
  221. continue;
  222. }
  223. }
  224. }
  225. int main(void) {
  226. init();
  227. input = "id*id+id"; //输入串
  228. input += "$";
  229. analysis(input);
  230. return 0;
  231. }

4.样例输出

5. To be continued.

LR分析-demo2的更多相关文章

  1. 【转】LR分析法

    转自:http://guanjy0129.blog.163.com/blog/static/1115494452010614113333509/ LR分析法的归约过程是规范推导的逆过程,所以LR分析过 ...

  2. 编译原理(六)自底向上分析之LR分析法

    自底向上分析之LR分析法 说明:以老师PPT为标准,借鉴部分教材内容,AlvinZH学习笔记. 基本概念 1. LR分析:从左到右扫描(L)自底向上进行规约(R),是规范规约,也即最右推导(规范推导) ...

  3. 编译原理 LR分析(主要是LR(0)分析)

    一.LR分析的基本原理 1.LR分析的基本思想 LR方法的基本思想就是,在规范归约的过程中,一方面要记住已移进和归约出的整个字符串,也就是说要记住历史:一方面能够根据所用的产生式的推测未来可能碰到的输 ...

  4. 编译原理 算法3.8 LR分析 c++11实现

    LR分析简介 LR分析是应用最广泛的一类分析方法,它是实用的编译器功能中最强的分析器,其特点是: 1,采用最一般的无回溯移进-规约方法. 2,可分析的文法是LL文法的真超集. 3,能够及时发现错误,及 ...

  5. 《编译原理》LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析

    <编译原理>LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析 笔记 直接做题是有一些特定步骤,有技巧.但也必须先了解一些基本概念,本篇会通过例题形式解释概念,会容易理解和记忆,以 ...

  6. 编译原理--02 自顶向下、自底向上的LR分析复习(清华大学出版社第3版)

    前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 第4章 自顶向下的语法分析方法 确 ...

  7. 编译原理-第四章 语法分析-4.7 规范的LR分析

    规范的LR分析 一.规范LR(l)项 二.规范LR(l)项集族 1.构建项目集 2.例 三.规范LR(1)语法分析表 1.构造 2.例1 3.例2 四.LALR语法分析表 1.重要性 2.特点 3.构 ...

  8. LR分析Analysis火车票

    一.分析结果 1 研究 Vuser 的行为(F:\JMeter\0Tutorial-SCR\机票预订\机票_analysis-session) 筛选该图,仅查看所有 Vuser 同时运行的时间段 右键 ...

  9. LR(0)文法项目集规范族、DFA和分析表的构建实例

    最近在复习编译原理,考试之前以为自己懂了,眼高手低就没去实践.结果一考试出问题了.... 学习就要脚踏实地,容不得半点模糊.凭着侥幸心理很危险的.以后要引以为戒啊. 特别写出这篇文章 :一来总结一下这 ...

随机推荐

  1. (WCF) 利用WCF实现两个Process之间的通讯。

    目的: 实现两个独立的Process 之间的通讯. 实现思路: 建立一个WCF Service,然后将其Host到一个Console 程序中,然后在另外一个Console程序中引用WCF的Servic ...

  2. 把KB转化为KB及以上单位

    /** * 把KB转化为KB及以上单位 * @param int $kb * @return string $new_val */ function return_over_kb($kb) { $kb ...

  3. Css3中拖拽效果的实例(带有注释~欢迎指教)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. RoCE、softRoCE与iWRAP

    RoCE - RDMA over Converged Ethernet 以太网在全球互联的广域网中毫无异议的老大,但在高带宽.低延时的专有网络领域却明显混不开.伴随网络融合概念兴起,IETF发布了DC ...

  5. c# 设计模式 之:工厂模式之---简单工厂

    1.uml类图如下: 具体实现和依赖关系: 实现:SportCar.JeepCar.HatchbackCar 实现 Icar接口 依赖: Factory依赖 SportCar.JeepCar.Hatc ...

  6. 转载:VMWARE虚拟机无法访问的三种方法分析

    bridged(桥接模式).NAT(网络地址转换模式)host-only(主机模式).理论认识:1.bridged(桥接模式)在这个地方模式.虚拟机等同于网络内的一台物理主机,可对手动设置IP,子网掩 ...

  7. 鸡肋提权之变态root利用

    你急有毛用,我电脑没带,怎么搞? 联系了基友adminlm牛看看吧,他说有防护软件啥的,有root,无法UDF,于是我让他去Mof,经历一番周折,知道了,对mof目录也锁定了权限,无法用root导出m ...

  8. mac本机svn命令使用

    公司项目用到svn,之前做版本管理用的是git. 现在对svn回顾学习了一下. 这里有一篇很好的入门教程 http://www.rubyrobot.org/tutorial/subversion-wi ...

  9. #Alpha Scrum6

    Alpha Scrum6 牛肉面不要牛肉不要面 Alpha项目冲刺(团队作业5) 各个成员在 Alpha 阶段认领的任务 林志松:督促和监督团队进度 陈彬:博客编写 吴沂章.林锃寒:代码功能完善 林志 ...

  10. Java虚拟机8:垃圾收集(GC)-3(垃圾收集算法)

    1.垃圾对象的判断 Java堆中存放着几乎所有的对象实例,垃圾收集器对堆中的对象进行回收前,要先确定这些对象是否还有用,判定对象是否为垃圾对象有如下算法: (1):引用计数算法 给对象添加一个引用计数 ...