源代码仓库:CompilePrincipleLearning/experiment_4 · yusixian/CompilePrincipleLearning (github.com)

源代码在demo文件夹中~

一. 实验目的

  1. 掌握LR(1)分析法的基本原理
  2. 掌握LR(1)分析表的构造方法
  3. 掌握LR(1)驱动程序的构造方法

二. 实验内容及要求

构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。

根据某一文法编制调试LR(1)分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对LR(1)分析法的理解。

对下列文法,用LR(1)分析法对任意输入的符号串进行分析

(0)S’->E(1)E->E+T(2)E->T(3)T->T*F(4)T->F(5)F->(E)(6)F->i

输出的格式如下:

(1)LR(1)分析程序,编制人:姓名,学号,班级

(2)输入一以#结束的符号串(包括±*/()i#):在此位置输入符号串

(3)输出过程如下:

步骤 状态栈 符号栈**** 剩余输入串 动作
1 0 # i+i*i# 移进

(4)输入符号串为非法符号串或合法符号串

注意:

1.表达式中允许使用运算符(+|*)、分割符(括号)、字符i,结束符#;

2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);

3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;

4.可采用的其它的文法,但是必须是LR1分析方法。

三. 实验过程

1、构造识别LR(1)文法活前缀的DFA

如图:新标签页打开,不糊的。

action表和goto表如下:

2、采用的数据结构

// ACTION表
// + * ( ) i #
string action[12][6];
// goto表
// a b #
int _goto[12][3];
string vt = "+*()i#";      // 终结符表
string vn = "ETF";        // 非终结符表
string LR[6] = { "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" };   // 存放产生式
stack<char> chars;  // 符号栈
stack<int> state;   // 状态栈

3、头文件声明和全局变量定义

如下。

#include <iostream>
#include <string>
#include <fstream>
#include <stack>
#include <vector>
using namespace std;
const string ExpFileName = "./exp.txt";
const string GotoFileName = "./goto.txt";
const string ActionFileName = "./action.txt";
const int Null = -1;
// ACTION表
// + * ( ) i #
string action[12][6];
// goto表
// a b #
int _goto[12][3];
string vt = "+*()i#";      // 终结符表
string vn = "ETF";        // 非终结符表
string LR[6] = { "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" };   // 存放产生式

4、函数汇总

(1)函数汇总表

函数名称 功能简述
readFile 读取文件函数,返回一个string动态数组,以行数分割
init 初始化函数,在该函数中进行goto表和action表的初始化
printActions / printGotos 输出goto表与action表
isTerminator 判断当前字符c是否是终结符
findTerminator 返回终结符所处下标
findNonTerminator 返回非终结符所处下标
s2string 将栈转换为字符串返回,方便输出步骤
analyzeLR1 利用LR1分析法分析字符串exp,输出其分析步骤
main 主程序入口,调用读取文件函数开始分析

(2)函数的调用关系

(3)流程图

5、实验结果

输入

action.txt文件

N    N   s4  N   s5  N
s6  N   N   N   N   acc
r2  s7  N   r2  N   r2
r4  r4  N   r4  N   r4
N   N   s4  N   s5  N
r6  r6  N   r6  N   r6
N   N   s4  N   s5  N
N   N   s4  N   s5  N
s6  N   N   s11 N   N
r1  s7  N   r1  N   r1
r3  r3  N   r3  N   r3
r5  r5  N   r5  N   r5

goto.txt文件

1    2   3
N   N   N
N   N   N
N   N   N
8   2   3
N   N   N
N   9   3
N   N   10
N   N   N
N   N   N
N   N   N
N   N   N

exp.txt文件

i+(i*i)*(i+i)#
i*i+i*i#
i+i*i+i*(i+i*i)#
i+*(i)+i(i+i*i)#
i+i(i)#

输出

完整代码

/** @Author: cos* @Date: 2022-04-30 14:20:51* @LastEditTime: 2022-05-01 02:34:12* @LastEditors: cos* @Description: 实验4 LR(1) 分析法* @FilePath: \CompileTheory\experiment_4\demo\main.cpp*/
#include <iostream>
#include <string>
#include <fstream>
#include <stack>
#include <vector>
using namespace std;
const string ExpFileName = "./exp.txt";
const string GotoFileName = "./goto.txt";
const string ActionFileName = "./action.txt";
const int Null = -1;
// ACTION表
// + * ( ) i #
string action[12][6];
// goto表
// a b #
int _goto[12][3];
string vt = "+*()i#";      // 终结符表
string vn = "ETF";        // 非终结符表
string LR[6] = { "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" };   // 存放产生式
// 读文件
vector<string> readFile(string fileName) {vector<string> res;try {ifstream fin;fin.open(fileName);string temp;while (getline(fin, temp))res.push_back(temp);return res;}catch (const exception& e) {cerr << e.what() << '\n';return res;}
}
void printActions() {cout << "-----------------ACTION表------------------" << endl;cout << "+\t*\t(\t)\ti\t$" << endl;for (int i = 0; i < 12; ++i) {for (int j = 0; j < 6; ++j)cout << action[i][j] << "\t";cout << endl;}
}
void printGotos() {cout << "-----------------GOTO表------------------" << endl;cout << "E\tT\tF" << endl;for (int i = 0; i < 12; ++i) {for (int j = 0; j < 3; ++j)cout << _goto[i][j] << "\t";cout << endl;}
}
void init() {vector<string> actions = readFile(ActionFileName);for (int i = 0; i < 12; ++i) {int cnt = 0;string row = actions[i];int len = actions[i].length();for (int j = 0; j < len; ++j) {string temp = "";while (j < len && row[j] != ' ' && row[j] != '\t') {temp += row[j];++j;}while (j < len && (row[j] == ' ' || row[j] == '\t'))++j;--j;action[i][cnt++] = temp;}}printActions();vector<string> gotos = readFile(GotoFileName);for (int i = 0; i < 12; ++i) {int cnt = 0;string row = gotos[i];int len = row.length();for (int j = 0; j < len; ++j) {string temp = "";while (j < len && row[j] != ' ' && row[j] != '\t') {temp += row[j];++j;}while (j < len && (row[j] == ' ' || row[j] == '\t'))++j;--j;_goto[i][cnt++] = (temp == "N") ? Null : stoi(temp);}}printGotos();
}
bool isTerminator(char c) {return vt.find(c) != string::npos;
}
int findTerminator(char c) { // 返回终结符所处下标return vt.find(c);
}
int findNonTerminator(char c) { // 返回非终结符的下标return vn.find(c);
}
// 将栈转换为字符串返回
string s2string(stack<int> s) {string str = "";while(!s.empty()) {str += to_string(s.top()) + " ";s.pop();}return str;
}
// 输出剩余输入串
void printRestInput(string exp, int start, int len) {for(int i = start; i < len; ++i) cout << exp[i];cout << '\t';
}
void analyzeLR1(string exp) {  // 分析一个表达式int len = exp.length();stack<char> chars;  // 符号栈stack<int> state;   // 状态栈state.push(0);  // 初始状态为0chars.push('#');  // 初始符号为#string charsStr = "#";stack<int> copyState;copyState.push(0);int cnt = 0;    // 序号int idx = 0;  // 当前输入指针cout << "序号\t\t状态栈\t\t符号栈\t\t输入串\t\t描述" << endl;cout << cnt++ << '\t' << s2string(copyState) << '\t' << charsStr << '\t' << exp << '\t' << " 初始状态 " << endl;while(1) {int nowState = state.top();char nowChar = exp[idx];    // 当前输入字符int isT = findTerminator(nowChar);if(isT == Null) {   // 非终结符cout << "Error!" << "出现非法字符,程序错误退出" <<endl;return;}string actionStr = action[nowState][isT];if(actionStr == "acc") {cout << cnt++ << '\t' << s2string(copyState) << '\t' << charsStr << '\t' << exp << '\t' << " accept 接受! " << endl;return;} else if(actionStr == "N") {cout << cnt++ << '\t' << s2string(copyState) << '\t' << charsStr << '\t' << exp << '\t' << "Error! 程序异常退出" << endl;return;} else if(actionStr[0] == 'r') {   // 归约int num = stoi(actionStr.substr(1));    // 选用第几个产生式归约int len = LR[num-1].length()-3;while(len--) {chars.pop();        // 出栈,归约state.pop();charsStr = charsStr.substr(0, charsStr.length()-1);copyState.pop();   // 便于输出}chars.push(LR[num-1][0]);   // 产生式左部入符号栈charsStr += LR[num-1][0];int nowState = state.top();int gidx = findNonTerminator(LR[num-1][0]);int newState = _goto[nowState][gidx];state.push(newState);copyState.push(newState);cout << cnt++ << '\t' << s2string(copyState) << '\t' << charsStr  << '\t';printRestInput(exp, idx, len);cout << '\t' << " 归约 " << LR[num-1] << endl;} else if(actionStr[0] == 's') {    // 移进int newState =  stoi(actionStr.substr(1));state.push(newState);copyState.push(newState);chars.push(nowChar);charsStr += nowChar;++idx;  // 输入指针后移cout << cnt++ << '\t' << s2string(copyState) << '\t' << charsStr << '\t';printRestInput(exp, idx, len);cout << '\t' << actionStr << " 移进 " << endl;} else {cout << "Error!" << "程序异常退出" <<endl;return;}}
}
int main() {cout << "LR(1)分析程序,编制人:xxx xxxxxxxx xxxx班" << endl;cout << "提示:本程序只能对由'i','+','*','/','(',')'构成的以'#'结束的表达式进行分析,每行读入一个表达式" << endl;cout << "读取的文件名为:" << ExpFileName << endl; init();vector<string> exps = readFile(ExpFileName);int len = exps.size();for (int i = 0; i < len; i++) {string exp = exps[i];cout << "\n------------------待分析表达式" << i+1 << ":"<< exp << "--------------------" << endl;bool flag = true;for (int j = 0; j < exp.length(); j++) {if (!isTerminator(exp[j])) {cout << "第 "<<   i+1 << "行输入的字符串不合法,请重新输入" << endl;flag = false;break;}}if (flag) {cout << "表达式"  << i+1 << ":" << exp << "分析开始" << endl;analyzeLR1(exp);}}return 0;
}

编译原理 实验四 LR(1)分析法程序相关推荐

  1. 编译原理 实验四 LR(0)分析法(LR0分析表的自动生成)

    写在前面 由于代码较长,csdn对文章总长度有字数限制,想只看完整代码的请移步另一篇博客. https://blog.csdn.net/qq_46640863/article/details/1257 ...

  2. 编译原理实验三 LR(1)分析法

    实验三 LR(1)分析法 构造 LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文 法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的 语法分析方法. 二.实验内 ...

  3. 编译原理 实验三 LR(1)分析法 Java

    1. 实验目的 构造 LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法. 2. 实验内容 对下列文 ...

  4. 编译原理 实验二 LL(1)分析法程序实现

    源代码仓库:CompilePrincipleLearning/experiment_2 · yusixian/CompilePrincipleLearning (github.com) 一. 实验目的 ...

  5. java编程实现算符优先分析法,编译原理实验三-算符优先分析法

    编译原理实验3-算符优先分析法 #include #include #include #include #define SIZE 128 char priority[6][6]; //算符优先关系表数 ...

  6. 编译原理-实验四-LR(0)语法分析程序的设计

    一.实验目的 了解LR(0)语法分析算法的基本思想,掌握LR(0)语法分析程序的构造方法. 二.实验内容 根据LR(0)语法分析算法的基本思想,设计一个对给定文法进行LR(0)语法分析的程序,并用C. ...

  7. 笔记-编译原理-实验四-语义分析与中间代码生成

    实验四. 语义分析及中间代码生成 设计思想 根据对属性文法及语义分析.中间代码生成的学习,可以将实验二.三的两种语法分析器进行一定的改造,以达到进行语法分析的同时进行语义分析并生成中间代码.根据PL0 ...

  8. 编译原理之语法分析(预测分析法)

    编译器之语法分析 自顶向下 上下文无关文法 语法树 NFA→CFG 预测分析法 改写CFG 原因 消除二义性 消除左递归 消除左公因子 消除空产生式 消除回路 自顶向下 上下文无关文法 CFG本质上就 ...

  9. 编译原理 | 语法分析(LL(1)分析法/算符优先分析法OPG)学习笔记及例子详解

    语法分析(自顶向下 / 自底向上) 自顶向下 递归下降分析法 这种带回溯的自顶向下的分析方法实际上是一种穷举的不断试探的过程,分析效率极低,在实际的编译程序中极少使用. LL(1)分析法 又称预测分析 ...

  10. 编译原理实验四:验证Yacc的使用

    所有实验的源代码:点此下载 实验目的: 熟悉语法分析器生成工具Yacc的使用,并学会在cygwin下使用bison工具编译Yacc文法说明文件.学习如何使用lex和yacc合作进行语法分析. 实验内容 ...

最新文章

  1. 三层交换机与路由器的主要区别
  2. ARM+linux+2440嵌入式开发相关经典书籍(转)
  3. 量变的一种坏结果是变质——以身说法结合实例论量与质,过程与结果2017-12-20
  4. python面向对象学习_Python 初识面向对象#学习猿地
  5. java a星寻路算法_用简单直白的方式讲解A星寻路算法原理
  6. java properties用法_java中Properties文件加载和使用方法
  7. phpMyAdmin出现错误 Access denied for user 'root'@'localhost' (using password: NO)
  8. 万恶之源-python基本数据类型
  9. 微软的软件下载,MSDN下载(方便,无广告,仅提供下载)
  10. AI产品--AlphaGo、AlphaGo Zero和master
  11. 【数字信号处理】基于Matlab GUI数字均衡器设计【含Matlab源码 904期】
  12. crackme 004
  13. 成功解决error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build Tools“
  14. TTL和CMOS输出端连接注意
  15. 用友U8+V13.0安装步骤
  16. 苹果手机计算机隐藏照片app,‎App Store 上的“秘密计算器 - 隐藏私人照片和视频”...
  17. 期待台湾出现 OpenNMS Certified Partner
  18. 《四大文明古国》读书笔记思维导图,感受人类文明
  19. xp系统为何无法登陆服务器,xp系统怎么登陆云服务器
  20. 【算法设计与分析】排序算法性能分析

热门文章

  1. MySQL 案例实战--MySQL数据库主从复制
  2. 英语听力学习-VOA
  3. DPDK——IP分片和重组库
  4. 计算机毕业设计——简单的网页设计
  5. 阿辉DirectX 11学习笔记一
  6. 大咖讲|中国AGV技术发展历程及关键点
  7. USB总线-Linux内核USB3.0控制器初始化代码分析(三)
  8. 在ubuntu中使用visual studio code对C/C++文件调试
  9. 巴西电商olist store订单数据分析
  10. onshape 做参考面等虚拟几何的装配和原点定位