0.LR分析

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

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

1.样例文法

"E>E+T",
"E>T",
"T>T*F",
"T>F",
"F>(E)",
"F>id",

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

3.code

//LR分析-demo2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<stack>
#include<map>
using namespace std; stack<string>stk, tmp, com; //stk是存入s0x1,即状态和符号的栈,tmp是用来输出的栈,
//com是在归约时确定归约式子的栈(防止错误弹出元素)
string input; //输入串
string slr[15][15]; //slr表
string action[] = { //slr表横轴动作+转换
"id","+","*","(",")","$","E","T","F"
};
//i就是id
string handle[] = { //文法
" ",
"E>E+T",
"E>T",
"T>T*F",
"T>F",
"F>(E)",
"F>id",
};
map<string, int> act, status; //转移表
map<string, int>::iterator it_act, it_trans;
string transfer[] = {
"E","T","F"
};
bool flag = false; //accept状态
int now = 0; //当前扫描字符位置
int handle_index = 0; //选中的规约式序号
void init() { //初始化,
int i = 0;
for (i = 0; i < 9;i++) {
act.insert(make_pair(action[i], i)); //建立分析表
}
int j = 0;
while (j<12) {
int i = j;
string t;
if (i < 10)
t = '0' + i;
else {
t = ('0' + (i / 10));
t += ('0' + i % 10);
}
status.insert(make_pair(t, j)); //将状态和数字对应
j++;
}
slr[0][0] = slr[4][0] = slr[6][0] = slr[7][0] = "s5"; //保存slr表
slr[1][1] = slr[8][1] = "s6";
slr[2][1] = slr[2][4] = slr[2][5] = "r2";
slr[2][2] = slr[9][2] ="s7";
slr[0][3] = slr[6][3] = slr[4][3] = slr[7][3] = "s4";
slr[1][5] = "acc";
slr[3][1] = slr[3][2] = slr[3][4] = slr[3][5] = "r4";
slr[5][1] = slr[5][2] = slr[5][4] = slr[5][5] = "r6";
slr[9][1] = slr[9][4] = slr[9][5] = "r1";
slr[8][4] = "s11";
slr[10][1] = slr[10][2] = slr[10][4] = slr[10][5] = "r3";
slr[11][1] = slr[11][2] = slr[11][4] = slr[11][5] = "r5";
slr[0][6] = "1";
slr[0][7] = slr[4][7] = "2";
slr[0][8] = slr[4][8] = slr[6][8] = "3";
slr[4][6] = "8";
slr[6][7] = "9";
slr[7][8] = "10";
}
void show() {
int count_two_char = 0; //数栈中超过两个字符的元素
while (!stk.empty()) { //用两个栈来回倒,输出字符
tmp.push(stk.top());
stk.pop();
}
while (!tmp.empty()) {
cout << tmp.top();
if (tmp.top().size()>1)
count_two_char++;
stk.push(tmp.top());
tmp.pop();
}
cout.setf(ios::right);
cout.width(11 - stk.size()- count_two_char);
cout << "|";
} //参数1是状态,参数2是符号,符号包括终结符和非终结符,作用是找到slr表中项目
string slrFind(string stat,string ActionAndTransfer) {
string s = stat, a = ActionAndTransfer;
//cout << s + " " + a << endl;
int t1 = status[s]; //取出状态对应下标
int t2 = act[a]; //取出符号对应下标
string tmp;
if (slr[t1][t2] != "") //如果slr表中存在此项
tmp = slr[t1][t2];
else
tmp = "";
//cout << tmp << endl;
return tmp; //返回slr表中的项目
} //参数1和2同slrFind函数,index是选中的规约式子序号
bool judge(string stat, string Transfer,int &index) {
string judg = slrFind(stat, Transfer); //得到slr表中项目
if (judg[0] != 'r') //如果这个项不是r开头,就不是归约
return false; //非归约直接返回
int i = judg[1] - '0'; //如果是归约,得到归约式子序号
index = i;
return true; //可以发起归约
} void analysis(string s) {
string w = s;
//cout.setf(ios::right); //设置字符对其方式
//cout.width(10); //设置字符宽度
printf("----------|----------|----------\n");
printf(" 栈 | 输入 | 动作 \n");
printf("----------|----------|----------\n");
while (!flag) { //处于非接受状态
now = 0; //正在处理的输入串中的字符
if (stk.empty()) { //一开始栈为空,直接移进符号
stk.push("0");
cout << "0 |";
cout.setf(ios::right); //设置字符对其方式
cout.width(10); //设置字符宽度
cout << w;
cout << "|移进" << endl;
printf("----------|----------|----------\n");
string t1, t2;
t1 = stk.top();
if (w[now] == 'i') { //移进符号为id
t2 = "id";
now = 2;
}
else { //移进符号不为id
t2 = w[now];
now = 1;
}
stk.push(t2); //将符号压入栈
w = w.substr(now, w.size() - now); //丢弃已扫描的字符
string lr = slrFind(t1, t2); //找到对应的动作
if (lr[0] == 's') //此时是移进
lr = lr.substr(1, lr.size() - 1);
stk.push(lr);
continue;
}
show();
string serach;
if(w[0]!='i') //获取输入串的开头符号
serach =w.substr(0,1);
else
serach = w.substr(0, 2);
//cout << w[0]+""<< endl; //转换字符串不能这么做
if(judge(stk.top(), serach, handle_index)) { //归约,优先级最高
cout.setf(ios::right); //设置字符对其方式
cout.width(10); //设置字符宽度
cout << w;
cout << "|";
cout.setf(ios::left);
cout.width(10);
cout << "按" + handle[handle_index] + "归约" << endl;
printf("----------|----------|----------\n");
string ttt = handle[handle_index].substr(2, handle[handle_index].size() - 2); //得到产生式右部符号
while (ttt != "") {
if (ttt[0] == 'i'){ //将产生式右部所有非终结符暂时压入一个栈中
com.push("id");
ttt=ttt.substr(2, ttt.size() - 2);
}
else
{
string t5;
t5 = ttt[0];
com.push(t5);
ttt=ttt.substr(1, ttt.size() - 1);
}
}
while (!com.empty()) { //用这个有产生式右部所有非终结符的栈和当前栈比对,确定归约式正确
stk.pop();
string cmp1 = stk.top();
if (com.top()==cmp1) {
stk.pop();
com.pop();
}
}
string t3 = handle[handle_index];
t3 = t3[0]; //得到归约式的左部符号
string t4 = slrFind(stk.top(),t3); //用此时左部符号和当前栈顶来确认下一个动作
stk.push(t3);
stk.push(t4);
continue;
}
else { //移进操作--或者acc
cout.setf(ios::right); //设置字符对其方式
cout.width(10); //设置字符宽度
cout << w;
cout << "|";
cout.setf(ios::left);
cout.width(10);
string t1, t2;
t1 = stk.top();
if (w[now] == 'i') { //移进符号为id
t2 = "id";
now = 2;
}
else { //移进符号不为id
t2 = w[now];
now = 1;
}
stk.push(t2); //将符号压入栈
w = w.substr(now, w.size() - now); //丢弃已扫描的字符
string lr = slrFind(t1, t2); //找到对应的动作
if (lr[0] == 's'){ //如果是移进操作
lr = lr.substr(1, lr.size() - 1);
cout << "移进" << endl;
}
else if (lr == "acc") { //或者是接受状态
cout << "接受" << endl;
flag = true;
}
stk.push(lr);
printf("----------|----------|----------\n");
continue;
}
}
}
int main(void) {
init();
input = "id*id+id"; //输入串
input += "$";
analysis(input);
return 0;
}

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. Java 之常用API(一)

    常用API  1 API概述  2 Scanner类与String类  3 StringBuilder类 NO.one API概述 1.1 API概述 API(Application Programm ...

  2. MyBatis学习笔记(一)

    测试Demo的目录结构: com.luohao.config ->MyBatisCongfig.xml ->userMapper.xml com.luohao.Test ->Test ...

  3. styling the SVG images

    SVG不像canvas,SVG的所有元素都是以DOM元素存在于文档中的,我们可以像给任何普通的dom元素添加css样式一样,可以对svg的元素做styling.不过SVG元素的css样式名称和普通ht ...

  4. Docker相关连接

    docker-compose文档:https://docs.docker.com/compose/compose-file/ dockerfile文档:https://docs.docker.com/ ...

  5. ThreadState属性

    这个属性代表了线程运行时状态,在不同的情况下有不同的值,我们有时候可以通过对该值的判断来设计程序流程. ThreadState 属性的取值如下: Aborted:线程已停止: AbortRequest ...

  6. Django路由系统---Django重点之url别名

    django重点之url别名[参数名必须是name,格式是name="XXX] 不论后台路径如何进行修改路径,前台访问的路径不变,永远是alias, 这样方便开发 前台根据 {{ url & ...

  7. Exchange 2007 前端 IIS 内存占用过高

    已经碰见了好几次,在Exchange2007的场景中,前端角色所在服务器的w3wp.exe进程总是占用大量内存,以至于触发反压组件,停止了正常的邮件流投递,造成业务中断. 终于下决心查一下到底问题问题 ...

  8. [BZOJ 3514]Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)

    [BZOJ3514] Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES) 题意 \(N\) 个点 \(M\) 条边的无向图,\(K\) 次询问保 ...

  9. python接口测试-项目实践(八) 完成的接口类和执行脚本

    脱敏后脚本 projectapi.py: 项目接口类 # -*- coding:utf-8 -*- """ xx项目接口类 2018-11 dinghanhua &quo ...

  10. N个苹果分给M个人,有多少种分法

    每次分配一个苹果出去,然后再分配N-1个苹果.这里有个注意的地方就是,分那1个苹果的时候,假设还有N个苹果,不是从第一个人开始分,而是从N+1个苹果分配的位置开始,不然的话会产生重复的解.所以i=p不 ...