基本思想:( $ 表示空,即ε)
(1)first集的算法思想
如果产生式右部第一个字符为终结符,则将其计入左部first集
如果产生式右部第一个字符为非终结符执行以下步骤
求该非终结符的first集
将该非终结符的非 $ first集计入左部的first集
若存在 $,则将指向产生式的指针右移
若不存在 $ ,则停止遍历该产生式,进入下一个产生式
若已经到达产生式的最右部的非终结符,则将$加入左部的first集
处理数组中重复的first集中的终结符

(2)follow集的算法思想
对于文法G中每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直到每个FOLLOW不在增大为止.
对于文法的开始符号S,置#于FOLLOW(S)中;
若A->aBb是一个产生式,则把FIRST(b)加至FOLLOW(B)中;
若A->aB是一个产生式,或A->aBb是一个产生式而b=>$ (即$∈FIRST(b))则把FOLLOW(A)加至FOLLOW(B)中

(3)生成预测分析表的算法思想
构造分析表M的算法是:
对文法G的每个产生式A->a执行第二步和第三步;
对每个终结符a∈FIRST(a),把A->a加至M[A,a]中;
若$∈FIRST(a),则把任何b∈FOLLOW(A)把A->a加至M[A,b]中;
把所有无定义的M[A,a]标上出错标志.

参考了大佬的代码,代码贴在这里,注释尽快补上:
(使用了一些c++11的特性)

#include <bits/stdc++.h>using namespace std;const int maxn = 1005;struct node {char left;string right;
};map <char , int>mp , mp1; //记录非终结符和非终结符
vector <node> input;
vector <char> non_c , ter_c , sta , vs;
set <char> first[maxn];
set <char> follow[maxn];
int f[maxn] , f1[maxn];
int tableMap[maxn][maxn];
int n;void getFirst(char t) {if(!f[mp[t]]) return; for(int i = 0 ; i < n ; i++) {if(input[i].left == t) {if(!mp.count(input[i].right[0])) {first[mp[t]].insert(input[i].right[0]);}else {   int num = 0;for(int j = 0 ; j < input[i].right.length() ; j++) {if(!mp.count(input[i].right[j])) {first[mp[t]].insert(input[i].right[j]);break;}getFirst(input[i].right[j]);bool flag = 0;for(auto it = first[mp[input[i].right[j]]].begin() ; it != first[mp[input[i].right[j]]].end() ; it++) {if(*it == '$')flag = 1;else first[mp[t]].insert(*it);}if(!flag) break;else {num += flag; flag = 0;}}//cout << "num = " << num << "\n";if(num == input[i].right.length()) {first[mp[t]].insert('$');}}}}f[mp[t]] = 0;
}void getFollow(char tmp) {if(!f1[mp[tmp]])return;for(int i = 0 ; i < n ; i++) {int index = -1;for(int j = 0 ; j < input[i].right.length() ; j++) {if(input[i].right[j] == tmp) {index = j; break;}}if(index > -1 && index < input[i].right.length() - 1) {char nxt = input[i].right[index + 1];if(!mp.count(nxt)) {follow[mp[tmp]].insert(nxt);}else {int flag = 0 , j;for(j = index + 1; j < input[i].right.length() ; j++) {nxt = input[i].right[j];if(!mp.count(nxt)) {follow[mp[tmp]].insert(nxt);break;}for(auto it = first[mp[nxt]].begin() ; it != first[mp[nxt]].end() ; it++) {if(*it == '$')flag = 1;else follow[mp[tmp]].insert(*it);}if(!flag)break;}if(j == input[i].right.length() && flag) {getFollow(input[i].left);for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {follow[mp[tmp]].insert(*it);}     }}}else if(index == input[i].right.length() - 1 && input[i].left != input[i].right[index]) {getFollow(input[i].left);for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {follow[mp[tmp]].insert(*it);}}}f1[mp[tmp]] = 0;
}void getTable() {for(int i = 0 ; i < n ; i++) {char tmp = input[i].right[0];if(!mp.count(tmp)) {if(tmp != '$')tableMap[mp[input[i].left]][mp1[tmp]] = i;else {for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {tableMap[mp[input[i].left]][mp1[*it]] = i;}}}else {int j;bool flag = 0;for(j = 0; j < input[i].right.length() ; j++) {tmp = input[i].right[j];if(mp1.count(tmp)) {tableMap[mp[input[i].left]][mp1[tmp]] = i;break;}for(auto it = first[mp[tmp]].begin() ; it != first[mp[tmp]].end() ; it++) {if(*it == '$')flag = 1;else tableMap[mp[input[i].left]][mp1[*it]] = i;}if(!flag)break;}if(j == input[i].right.length() && flag) {for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {tableMap[mp[input[i].left]][mp1[*it]] = i;}       }} }
}void analyExp(string s) {for(int i = s.length() - 1 ; i >= 0 ; i--) {vs.push_back(s[i]);}sta.push_back('#');sta.push_back(non_c[0]);while(vs.size() > 0) {string outs , outs1; //输出分析栈for(int i = 0 ; i < sta.size() ; i++) {outs += sta[i];}for(int i = vs.size() - 1 ; i >= 0 ; i--) {outs1 += vs[i];}cout << setw(16) << outs << setw(16)<<outs1;char c1 = sta[sta.size() - 1] , c2 = vs[vs.size() - 1];if(c1 == c2) {if(c1 == '#') {cout << setw(16)<<"Accepted!\n";break;  }else {sta.pop_back(); vs.pop_back();cout << setw(16)<<c1 << "\n";}} else if(tableMap[mp[c1]][mp1[c2]] != -1) {int t = tableMap[mp[c1]][mp1[c2]];sta.pop_back();if(input[t].right != "$") {for(int i = input[t].right.length() - 1 ; i >= 0 ; i--)sta.push_back(input[t].right[i]);   }cout << setw(16) <<input[t].right << "\n";} else {cout <<setw(16) <<"error\n";break;}}
}void showFirst() {cout << "first集合\n";for(int i = 0 ; i < non_c.size() ; i++) {cout << non_c[i] << ":";for(auto it = first[mp[non_c[i]]].begin() ; it != first[mp[non_c[i]]].end() ; it++) {cout << *it << " ";}cout << "\n";}
}void showFollow() {cout << "follow集合\n";for(int i = 0 ; i < non_c.size() ; i++) {cout << non_c[i] << ":";for(auto it = follow[mp[non_c[i]]].begin() ; it != follow[mp[non_c[i]]].end() ; it++) {cout << *it << " ";}cout << "\n";}
}void showTable() {for(int i = 0 ; i < ter_c.size() ; i++) {cout <<setw(6)<< ter_c[i] ;}cout << "\n";for(int i = 0 ; i < non_c.size() ; i++) {cout << non_c[i] << ":";for(int j = 0 ; j < ter_c.size() ; j++) {if(tableMap[i][j] == -1) {cout << setw(6)<< "error";}else cout << setw(6)<< input[tableMap[i][j]].right;}cout << "\n";}
}int main() {cout << "请输入文法的行数\n";ios::sync_with_stdio(0);cin >> n;int flag = 0;cin.get();int tag;memset(tableMap , -1 ,sizeof(tableMap));for(int i = 0 ; i < n ; i++) {string s;node t;getline(cin , s);t.left = s[0];if(!mp.count(s[0])) {mp[s[0]] = non_c.size();f[non_c.size()] = f1[non_c.size()] = 1;non_c.push_back(s[0]);}tag = 0;for(int j = 1 ; j < s.length() ; j++) {if(!tag && s[j] == '-')tag = 1;else if(tag == 1 && s[j] == '>')tag = 2;else if(tag == 2) {if(!isupper(s[j]) && !mp1.count(s[j])){mp1[s[j]] = ter_c.size();if(s[j] != '$')ter_c.push_back(s[j]);}t.right += s[j]; }else {cout << "读入出错,程序自动关闭,请重新启动\n";return 0;}}input.push_back(t); }ter_c.push_back('#');mp1['#'] = ter_c.size() - 1;for(int i = 0 ; i < non_c.size() ; i++) {getFirst(non_c[i]);}showFirst();for(int i = 0 ; i < non_c.size() ; i++) {if(i == 0)follow[i].insert('#');getFollow(non_c[i]);}   showFollow();getTable();showTable();cout << "请输入要分析的字符串\n";string s;getline(cin , s);cout << setw(16) << "分析栈" << setw(16) << "剩余输入串" << setw(16) << "推导式" << endl;analyExp(s);return 0;
}

运行结果:

编译原理:LL1(1)文法的语法分析器(通过文法构造分析表)相关推荐

  1. 编译原理: 做一个LL(1)语法分析器

    本文实现了简易LL1语法分析器 最终效果 实验语言 实验环境 设计概要 补充 代码 代码1--- index.html 代码2--- tools.js 最终效果 实验语言 html.css.js 实验 ...

  2. 编译原理简单语法分析器(first,follow,分析表)源码下载

    编译原理(简单语法分析器下载) http://files.cnblogs.com/files/hujunzheng/%E5%8A%A0%E5%85%A5%E5%90%8C%E6%AD%A5%E7%AC ...

  3. 编译原理 - 实验三 - 递归下降语法分析器的调试及扩展

    一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任 ...

  4. 编译原理实验二 自上而下的语法分析器(算术表达式)

    1.语法分析器比之前的词法分析器简单一些,要做语法分析,首先我们需要词法分析器将输入的算术表达式进行分解,将其变为一个String数组,这样我们可以依次对每一个词进行匹配. 2.在执行匹配的时候,思想 ...

  5. 编译原理 LL1文法的判断和句子识别

    编译原理 LL1文法的判断和句子识别 LL1文法概述 点击查看百度百科 对文法G的句子进行确定的自顶向下语法分析的充分必要条件是,G的任意两个具有相同左部的 产生式A->α|β 满足下列条件: ...

  6. 【20200422】编译原理课程课业打卡十七之求解文法FirstVTLastVT构造文法算符优先关系表

    [20200422]编译原理课程课业打卡十七之求解文法FirstVT&LastVT&构造文法算符优先关系表 一.课业打卡十七之求解文法FirstVT&LastVT&构造 ...

  7. 编译原理(5):语法制导翻译

    声明:本系列文章,是根据中国大学MOOC网 哈工大的编译原理 这门课学习而成的学习笔记. 一.语法制导翻译概述 什么是语法制导翻译 语法制导翻译的基本思想 两个概念 语法制导定义(SDD) 语法制导翻 ...

  8. 编译原理陈意云3-20 (a) 证明下面文法 S→AaAb|BbBa A→ε B→ε 是LL(1)文法,但不是SLR(1)文法。

    思路:依次判断是否为LL(1)文法和SLR文法即可 证明: (1)首先该文法无左递归存在,没有公共左因子. 其次:对于S→AaAb|BbBa FIRST(AaAb)={a} FIRST(BbBa)={ ...

  9. 【编译原理】-- 第二章(一)(文法和语言的定义、递归规则与递归文法、例题)

    目录 形式化方法 语言的定义可采用下列三种方法 一.文法和语言的定义 1.字母表和符号串的基本概念和术语 (1)字母表 (2)符号串 (3)字母表∑上的符号串的递归定义. (4)符号串的前缀.后缀和字 ...

最新文章

  1. Windows 8部署系列PART2:部署先决条件准备
  2. 赛道公布之后,让我们一起DISS组委会
  3. 【CF582E】Boolean Function 树形DP+FWT
  4. 为什么 char 数组比 String 更适合存储密码?
  5. sdn体系的三个平面_软件定义网络基础---SDN控制平面
  6. xbox one s驱动_理想照进现实 理想ONE开始接受预定
  7. [ios] iOS中arc的设置与使用
  8. arcgis运行慢_ArcGIS Pro运行较慢的诊断方法
  9. Numpy包简单介绍
  10. -bash: vi: command not found -bash: ls: command not found
  11. 怎么把PDF文件转换成电子书?教你如何转换
  12. 2021年北京高考成绩排名查询,北京2021高考成绩排名榜单,北京各高中高考成绩喜报...
  13. 安装docker遇到的坑
  14. 【mpeg1】mpeg1相关资料
  15. 解决Ubuntu强制获取root权限后只剩下客人会话而无法正常登录
  16. 游戏世界三维坐标转换为屏幕坐标原理分析:三角函数转换与矩阵变换
  17. android屏幕分享软件,火萤Up - 视频分享
  18. c语言俄罗斯方块视频,c语言自己写俄罗斯方块(完整版)
  19. 微型计算机原理跟什么有关,微机原理 课后题 标准答案
  20. docker容器IP的设置

热门文章

  1. 统计每天、每月每天、每年每月的SQL语句怎么写?
  2. 量子力学是否证明了世界是唯心主义?物质到底是虚无还是实在的
  3. APS生产计划排产 — 排产结果拉动模具工装需求计划
  4. 数字图像处理笔记(七):频域低通滤波平滑图像
  5. VNC 桌面没有图标解决办法
  6. HAVE FUN | 源码解析活动最新进展
  7. GPRS的移动台类别
  8. 【Cirrodata】通过python头import导入连接行云数据库
  9. 续:ibatis使用高级篇,多表操作处理!
  10. xpath定位和css定位对比