LR分析简介

  LR分析是应用最广泛的一类分析方法,它是实用的编译器功能中最强的分析器,其特点是:

  1,采用最一般的无回溯移进-规约方法。

  2,可分析的文法是LL文法的真超集。

  3,能够及时发现错误,及时从左扫描输入序列的最大可能。

  4,分析表较为复杂,难以手工构造。

实验内容

  根据LR分析表action和goto实现LR分析。

实验步骤

  输入 序列$\omega$和文法$G$的LR分析表action与goto。

  输出 若$\omega \in L(G)$,得到$\omega$的规范规约,否则指出一个错误。

具体实现

  见代码。

  1. #include <algorithm>
  2. #include <fstream>
  3. #include <iostream>
  4. #include <map>
  5. #include <set>
  6. #include <stack>
  7. #include <vector>
  8. using namespace std;
  9.  
  10. using Production = pair<string, vector<string>>;
  11.  
  12. const int max_state = ;
  13. const int delay_num = 5e8;
  14.  
  15. struct ParserLR
  16. {
  17.  
  18. map<string, int> mp_n; //非终结符映射
  19. map<string, int> mp_t; //终结符映射
  20. vector<Production> P; //产生式
  21. vector<string> N, T; //非终结符,终结符
  22. int state_num, operator_num, nonterminal_num, terminal_num, production_num;
  23. vector<string> action[max_state];
  24. vector<int> _goto[max_state];
  25. int init(string filename)
  26. {
  27. N.clear();
  28. T.clear();
  29. P.clear();
  30. mp_n.clear();
  31. mp_t.clear();
  32. for (int i = ; i < max_state; i++)
  33. {
  34. action[i].clear();
  35. _goto[i].clear();
  36. }
  37. state_num = operator_num = nonterminal_num = terminal_num = production_num = ;
  38. ifstream in(filename, ios::in);
  39. if (!in.is_open())
  40. return ;
  41. in >> terminal_num;
  42. for (int i = ; i < terminal_num; i++)
  43. {
  44. string tmp;
  45. in >> tmp;
  46. T.emplace_back(tmp);
  47. mp_t[tmp] = i;
  48. }
  49. in >> nonterminal_num;
  50. for (int i = ; i < nonterminal_num; i++)
  51. {
  52. string tmp;
  53. in >> tmp;
  54. N.emplace_back(tmp);
  55. mp_n[tmp] = i;
  56. }
  57. in >> production_num;
  58. for (int i = ; i < production_num; i++)
  59. {
  60. Production cur;
  61. in >> cur.first;
  62. int sz;
  63. in >> sz;
  64. for (int j = ; j < sz; j++)
  65. {
  66. string t;
  67. in >> t;
  68. cur.second.emplace_back(t);
  69. }
  70. P.emplace_back(cur);
  71. }
  72. in >> state_num;
  73. for (int i = ; i <= state_num; i++)
  74. for (int j = ; j < terminal_num; j++)
  75. {
  76. string tmp;
  77. in >> tmp;
  78. action[i].emplace_back(tmp);
  79. }
  80. for (int i = ; i <= state_num; i++)
  81. for (int j = ; j < nonterminal_num; j++)
  82. {
  83. int tmp;
  84. in >> tmp;
  85. _goto[i].emplace_back(tmp);
  86. }
  87. return ;
  88. }
  89. Production getProduction(int idx)
  90. {
  91. return P[idx - ];
  92. }
  93. pair<int, vector<Production>> analyze(vector<string> input) //first->出错位置,-1代表无错
  94. {
  95. vector<Production> error;
  96. vector<Production> success;
  97. stack<string> ch; //符号栈
  98. stack<int> st; //状态栈
  99. ch.emplace("#");
  100. st.emplace();
  101. input.emplace_back("#");
  102. int sz = input.size();
  103. for (int i = ; i < sz;)
  104. {
  105. string now = input[i];
  106. if (!mp_t.count(now))
  107. return make_pair(i, success);
  108. int ip = mp_t[now];
  109. int top = st.top(); //栈顶状态
  110. string at = action[top][ip];
  111. if (at[] == 'r') //规约
  112. {
  113. string res = at.substr(, at.size());
  114. int num = stoi(res);
  115. Production trans = getProduction(num);
  116. for (int i = ; i < trans.second.size(); i++)
  117. {
  118. st.pop();
  119. ch.pop();
  120. }
  121. top = st.top();
  122. string cur = trans.first;
  123. ch.emplace(cur);
  124. st.emplace(_goto[top][mp_n[cur]]);
  125. success.emplace_back(trans);
  126. }
  127. else if (at[] == 's') //移进
  128. {
  129. string res = at.substr(, at.size());
  130. int to_state = stoi(res);
  131. st.emplace(to_state);
  132. ch.emplace(now);
  133. i++;
  134. }
  135. else if (at == "acc") //接受
  136. return make_pair(-, success);
  137. else //error
  138. {
  139. if (now == "#")
  140. return make_pair(i - , success);
  141. return make_pair(i, success);
  142. }
  143. }
  144. return make_pair(, error);
  145. }
  146. };
  147. inline void delay()
  148. {
  149. for (int i = ; i < delay_num; i++)
  150. ;
  151. }
  152. inline void display(const pair<int, vector<Production>> &out)
  153. {
  154. if (out.first == -)
  155. {
  156. for (int i = ; i < out.second.size(); i++)
  157. {
  158. cout << out.second[i].first << "->";
  159. for (int j = ; j < out.second[i].second.size(); j++)
  160. cout << out.second[i].second[j];
  161. cout << "\n";
  162. }
  163. }
  164. else
  165. cout << "在第" << out.first + << "个终结符出错.\n";
  166. }
  167. int main(int argc, char const *argv[])
  168. {
  169. ParserLR app;
  170. string filename = "prj3_8_in.txt";
  171. if (app.init(filename))
  172. {
  173.  
  174. cout << "构建分析器中";
  175. delay();
  176. cout << ".";
  177. delay();
  178. cout << ".";
  179. delay();
  180. cout << ".\n";
  181. delay();
  182. cout << "构建成功.\n";
  183. cout << "请输入终结符个数:";
  184. int sz;
  185. cin >> sz;
  186. cout << "请输入包含" << sz << "个终结符的待分析序列, 终结符间需用空格分离:";
  187. vector<string> al;
  188. for (int i = ; i < sz; i++)
  189. {
  190. string tmp;
  191. cin >> tmp;
  192. al.emplace_back(tmp);
  193. }
  194. cout << "开始分析";
  195. delay();
  196. cout << ".";
  197. delay();
  198. cout << ".";
  199. delay();
  200. cout << ".\n";
  201. delay();
  202. cout << "分析结束.\n";
  203. pair<int, vector<Production>> out = app.analyze(al);
  204. cout << "分析成功,结果如下:\n";
  205. display(out);
  206. }
  207. return ;
  208. }

源代码

  1. id - * #
  2.  
  3. E T F
  4.  
  5. E E - T
  6. E T
  7. T T * F
  8. T F
  9. F - F
  10. F id
  11.  
  12. s4 s5 null null
  13. null s6 null acc
  14. null r2 s7 r2
  15. null r4 r4 r4
  16. null r6 r6 r6
  17. s4 s5 null null
  18. s4 s5 null null
  19. s4 s5 null null
  20. null r5 r5 r5
  21. null r1 s7 r1
  22. null r3 r3 r3
  23.  
  24. - - -
  25. - - -
  26. - - -
  27. - - -
  28. - -
  29. -
  30. - -
  31. - - -
  32. - - -
  33. - - -

输入文件

效果展示

代码使用部分c++11特性,如有本地编译需要,请确认环境。

欢迎下方留言。

编译原理 算法3.8 LR分析 c++11实现的更多相关文章

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

    <编译原理>构造 LL(1) 分析表的步骤 - 例题解析 易错点及扩展: 1.求每个产生式的 SELECT 集 2.注意区分是对谁 FIRST 集 FOLLOW 集 3.开始符号的 FOL ...

  2. 编译原理实验之SLR1文法分析

    ---内容开始--- 这是一份编译原理实验报告,分析表是手动造的,可以作为借鉴. 基于  SLR(1) 分析法的语法制导翻译及中间代码生成程序设计原理与实现1 .理论传授语法制导的基本概念,目标代码结 ...

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

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

  4. 【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

    近来复习编译原理,语法分析中的自上而下LL(1)分析法,需要构造求出一个文法的FIRST和FOLLOW集,然后构造分析表,利用分析表+一个栈来做自上而下的语法分析(递归下降/预测分析),可是这个FIR ...

  5. 编译原理实习(应用预测分析法LL(1)实现语法分析)

    #include<iostream> #include<fstream> #include<iomanip> #include<cstdio> #inc ...

  6. 编译原理 #02# 简易递归下降分析程序(js实现)

    // 实验存档 截图: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  7. 【编译原理】c++实现自下而上语法分析器

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  8. 编译原理根据项目集规范族构造LR(0)分析表

    转载于https://blog.csdn.net/Johan_Joe_King/article/details/79058597?utm_medium=distribute.pc_relevant.n ...

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

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

随机推荐

  1. xms跨平台基础框架 - 基于.netcore

    背景 敝人经过多年开发,数百个项目“打磨(折磨)”,各种国内外框架平台都有涉及,没有一款称心顺手的,原因有三,一是设计反人类,二是不开源根本无法突破框架限制,三是即使开源也是阉割版,然后xms就开始萌 ...

  2. [转载]2.8 UiPath中断活动Break的介绍和使用

    一.Break的介绍 Break: 用于结束当前循环. 注意: Break控件只能用于For Each 循环中 二.Break在UiPath中结合For Each循环的使用 1.打开设计器,在设计库中 ...

  3. numpy---python数据分析

    最后大图可点开保存 文章目录 最后大图可点开保存 学习目标 3.1.1Numpy介绍 3.1.2 ndarray介绍 3.1.3 ndarray与Python原生list运算效率对比 3.1.4 nd ...

  4. Scrapy进阶知识点总结(一)——基本命令与基本类(spider,request,response)

    一.常见命令 scrapy全局命令可以在任何地方用,项目命令只能在项目路径下用 全局命令: 项目命令: startproject crawl genspider check settings list ...

  5. 关于vue ui组件

    一.vue ui  组件 1: vue 当前很火前端框架vue 针对PC用户 pc 端与移动端区别 (1)屏幕宽度:992px > (2)操作方式:鼠标 事件   手指:触碰操作 -饿了么:基于 ...

  6. [git]关于github的一些用法笔记(入门)

    本视频来自于观看尚硅谷B站教学:https://www.bilibili.com/video/av10475153?from=search&seid=9735863941344749813 而 ...

  7. 如何基于k8s快速搭建TeamCity(YAML分享)

    前言 最近有朋友基于之前的博客<Docker最全教程之使用TeamCity来完成内部CI.CD流程(十七)>搭建TeamCity时出现了一些问题,由于平常比较忙,没有及时答复,非常抱歉. ...

  8. mysql 创建用户及授权(2)

    一. MySQL初始密码 新安装的MySQL默认是没有密码的,设置初始密码可以用以下命 mysqladmin -u root password 'new-password' mysqladmin -u ...

  9. Anaconda 笔记

    Anaconda笔记 conda 功能 管理版本的切换 安装其他的包 conda 创建python27环境 conda create --name python27 python=2.7 conda ...

  10. 力扣(LeetCode)按奇偶排序数组II 个人题解

    给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数. 对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数:当 A[i] 为偶数时, i 也是偶数. 你可以返回任何满足上述条件的数组 ...