LR(1)分析表-语法树-四元式

 这学期的编译原理终于学完了,不愧是号称最难的科目。要用C++从头到尾实现一下小型编译器,还真不容易啊。不过总算是做完了。

 

首先上文法,这个文法是根据上一篇博客简化的,但还是有一点问题的,暂时发现有一个地方不符合LR1的规则(函数的返回类型如果是int就会报错)。

 

有了文法就可以生成LR1分析表了,如图所示,一共有187个项目集族,代码跑了2分50秒才出结果,要不是我优化了一个下午,剪掉了一些不必要的循环,以及把一个o(n)的改成了lg的,大概要跑10分钟吧。

具体的优化在代码中有注释。

 

生成的LR(1)表存到文件中,用err表示空格,便于从文件再读到程序中,如图所示:

 

接下来是输入程序:

 

转成Token,如果是ID或则NUM类型的,还需要存下对应的值。

 

下面的就是分析过程和“文本格式的语法树”了

 

同时dfs语法树生成了四元式:

 

代码:

  1 #include <map>
  2 #include <set>
  3 #include <list>
  4 #include <ctime>
  5 #include <queue>
  6 #include <stack>
  7 #include <string>
  8 #include <vector>
  9 #include <iomanip>
 10 #include <fstream>
 11 #include <sstream>
 12 #include <iostream>
 13 using namespace std;
 14 #define rep(i,a,n) for(int i=a;i<n;i++)
 15 #define per(i,a,n) for(int i=n-1;i>=a;i--)
 16 #define all(x) (x).begin(),(x).end()
 17 typedef pair<string, vector<string>> Production;        //产生式
 18 const int WIDTH = 16;    //setw(WIDTH)
 19 // head
 20 
 21 struct Project {        //项目集
 22     string left;    
 23     vector<string> right;
 24     set<string> expect;
 25 
 26     const bool operator<(const Project &p) const {
 27         if (left < p.left) return true;
 28         if (left > p.left) return false;
 29         if (right < p.right) return true;
 30         if (right > p.right) return false;
 31         if (expect < p.expect) return true;
 32         return false;
 33     }
 34 
 35     const bool operator==(const Project &p) const {
 36         if (left == p.left && right == p.right && expect == p.expect) return true;
 37         return false;
 38     }
 39 };
 40 
 41 namespace project {    //产生项目集族
 42     set<string> terminal;        //终结符
 43     set<string> not_terminal;    //非终结符
 44     set<string> all_symbol;        //所有的符号
 45     vector<string> sss;            //所有的符号
 46     map<string, int> Hash;        //符号哈希
 47     vector<Production> vp;        //所有的产生式,加·前
 48     set<Production> sp;            //所有的项目集,加·后
 49 
 50     void PROJECT() {
 51         ifstream fin("C:\\Users\\Flowersea\\Desktop\\Grammar.txt");
 52         string a, b;
 53         vector<string> c;
 54         while (fin >> a >> b) {
 55             not_terminal.insert(a);
 56             string str;
 57             getline(fin, str);
 58             stringstream ss;
 59             ss.str(str);
 60             c.clear();
 61             while (ss >> str) {
 62                 c.push_back(str);
 63                 int fg = 0;
 64                 rep(i, 0, str.size()) {
 65                     if (!(str[i] >= 'a' && str[i] <= 'z' || str[i] == '_')) {    //文法中非终结符都是小写字母和下划线组成的
 66                         fg = 1;
 67                         break;
 68                     }
 69                 }
 70                 if (fg) terminal.insert(str);    //如果含有小写字母和下划线以外的符号就是终结符
 71                 else not_terminal.insert(str);    //否则是非终结符
 72             }
 73             vp.push_back(Production(a, c));
 74         }
 75         terminal.insert("#");
 76         not_terminal.erase("program'");        //删掉program'
 77         all_symbol.insert(all(terminal));
 78         all_symbol.insert(all(not_terminal));
 79         for (auto it : terminal) sss.push_back(it);
 80         for (auto it : not_terminal) sss.push_back(it);    //sss其实是为了输出lr1表的表头
 81         rep(i, 0, sss.size()) Hash[sss[i]] = i;
 82         for (auto it : vp) {
 83             a = it.first, c = it.second;
 84             rep(i, 0, c.size() + 1) {
 85                 vector<string> d = c;
 86                 d.insert(d.begin() + i, ".");
 87                 sp.insert(Production(a, d));
 88             }
 89         }
 90     }
 91 
 92     void main() {
 93         PROJECT();
 94     }
 95 }
 96 
 97 namespace lr1 {    //生成lr表
 98     using namespace project;    
 99 
100     vector<set<Project>> vsp(1);    //项目集族
101     string lr1[1000][1000];        //lr1表
102     int n, m;                    //n行,m列
103 
104     set<string> FIRST(vector<string> X) {    //求FIRST集族
105         set<string> res;
106         if (terminal.find(X[0]) != terminal.end()) {
107             res.insert(X[0]);    //如果是终结符,直接insert返回
108             return res;
109         }
110         else {
111             rep(j, 0, vp.size()) {    //遍历所有的产生式
112                 if (vp[j].first == X[0]) {    
113                     if (terminal.find(vp[j].second[0]) != terminal.end())    //如果第一个是终结符
114                         res.insert(vp[j].second[0]);                            //插入到res中
115                     else {
116                         set<string> t = FIRST(vp[j].second);                    //否则递归求FIRST集
117                         res.insert(all(t));
118                     }
119                 }
120             }
121         }
122         return res;
123     }
124 
125     set<Project> GO(set<Project> I, string X) {    //GO函数
126         set<Project> J;
127         for (auto it : I) {
128             vector<string> vs = it.right;
129             auto pos = find(all(vs), ".");
130             if (pos == vs.end() - 1) continue;    //如果·是最后一个,continue
131             if (*(pos + 1) == X) {
132                 swap(*pos, *(pos + 1));            //交换·和后面的一个字符串
133                 J.insert(Project{ it.left, vs, it.expect });
134             }
135         }
136         return J;
137     }
138 
139     set<Project> CLOSURE(set<Project> I) {        //求closure
140         while (1) {
141             bool update = false;                    //判断此次循环是否有更新
142             for (auto it : I) {
143                 vector<string> B = it.right;        
144                 auto pos = find(all(B), ".");        //找到·的位置
145                 if (pos == B.end() - 1) continue;    //如果·是最后一个,continue
146                 string c = *(pos + 1);                //c等于·后面的字符
147                 if (terminal.find(c) != terminal.end()) continue;    //如果c是终结符,continue
148                 B.erase(B.begin(), pos + 2);            //删掉·后面的一个字符之前的所有字符,包括它自己
149                 string last;                            //为了剪枝,记录上一次求FIRST集的第一个字符串
150                 for (auto ite : it.expect) {    
151                     B.push_back(ite);                //把expect插入到B的后面
152                     if (last == B[0]) continue;        //如果B[0]和上次的last一样,就不求了,因为文法中没有空产生式
153                     else last = B[0];
154                     set<string> First = FIRST(B);    //求B的FIRST集
155                     B.pop_back();
  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值