编译原理词法分析(正规式转NFA)
文章目录
- 【问题描述】
- 【基本要求】
- 【测试用例】
- 【解决步骤】
- 正规式转NFA方法步骤:
- 图的构建过程:
- 完整代码:
【问题描述】
正规表达式→NFA问题的一种描述是:
编写一个程序,输入一个正规表达式,输出与该文法等价的有穷自动机。
【基本要求】
设置FA初始状态X,终态Y,过程态用数字表示:0 1 2 3………
【测试用例】
测试数据:
(a|b)*abb
输出结果应为:
X X - ~ ->3
Y
0 0-a->1
1 1-b->2
2 2-b->Y
3 3-~->0 3-a->3 3-b->3
【解决步骤】
正规式转NFA方法步骤:
- 判断一下正规式有没有错误,括号对不对,并添加符号“+”
- 运算符的优先级为:*>|>+
- 根据符号优先级,把中缀表达式转后缀表达式便于计算
- 根据后缀表达式依次构建图。有三种运算:*、|、+
图的构建过程:
(1) 定义边结构体用来储存边:edge
//NFA边
struct edge{int start;int end;char accept;
};
(2) 定义一个类用来表示图结构:grup
//NFA单元,一个大的NFA单元可以是由很多小单元通过规则拼接起来
class grup{public:vector<edge> edges; //这个NFA拥有的边int stateCount; //状态数int StartState; //开始状态int EndState; //结束状态
public:grup() {this->stateCount = 2;this->StartState = 0;this->EndState = 1;}
};
(3) 构建出的图结构边是从状态是从0开始编号的 构建过程:以(a|b)*abb为例
输入字符串添加+号,并判断是否合法:
算法:- 定义一个栈s用来匹配括号,判断括号是否符合条件。
从左往右扫描字符串,如果是字母或数字,则放入输出表达式后
然后判断后一个是什么符号判断是否要加上+号
对于类似如下几种情况需要加上+的:AA、A(、A、(、)A、)(。
完成后(a|b)abb变为:(a|b)+a+b+b
- 定义一个栈s用来匹配括号,判断括号是否符合条件。
中缀表达式转后缀表达式
算法:- 定义一个栈s,从左忘右扫描表达式,
遇见字母或数字拼接在输出表达式后
遇见“(”压入栈中
遇见“)”弹出栈中元素,直到遇到了“(”
遇到“、|、+”判断栈顶元素的优先级,把比自己优先级高或等的弹出去
然后自己再压栈。
扫描完成后再把栈中元素依次弹出,拼接在输出字符串后
完成后(a|b)+a+b+b应该变为:ab|*a+b+b+
核心算法:
- 定义一个栈s,从左忘右扫描表达式,
Void change_text(string text) {stack<char> s;string new_text = "";for (int i = 0; i<int(text.length()); i++) {if ((text[i] <= 'z' && text[i] >= 'a') || (text[i] <= 'Z' && text[i] >= 'A') || (text[i]<= '9' && text[i] >= '0')) {new_text = new_text + text[i];}else {if (text[i] == '(') {s.push(text[i]);}else if (text[i] == ')') {while (s.top() != '(') {new_text = new_text + s.top();s.pop();}s.pop();}else if (text[i] == '*') {s.push(text[i]);}else if (text[i] == '|') {if (s.empty()) {s.push(text[i]);}else {while (!s.empty()) {if (s.top() == '*') {new_text = new_text + s.top();s.pop();}else if (s.top() == '|') {new_text = new_text + s.top();s.pop();}else {break;}}s.push(text[i]);}}else if (text[i] == '+') {if (s.empty()) {s.push(text[i]);}else {while(!s.empty()){if (s.top() == '*') {new_text = new_text + s.top();s.pop();}
else if (s.top() == '+') {new_text = new_text + s.top();s.pop();}else if (s.top() == '|') {new_text = new_text + s.top();s.pop();}else {break;}}s.push(text[i]);}}}}while(!s.empty()) {new_text += s.top();s.pop();}return new_text;}
- 构架图结构:
算法:- 定义一个栈用来储存图结构,从左向右扫描后缀表达式
如果遇到的是字母或数字,构建一个如下状态的图:一条边两个状态
- 定义一个栈用来储存图结构,从左向右扫描后缀表达式
压入栈中
如果遇到运算符分三种情“、|、+”
遇到“”,栈顶元素出栈
遇到“+”
遇到“|”
- 核心算法:
getNFA(string text) {stack<grup> s;for (int i = 0; i < int(text.length()); i++) {if ((text[i] <= 'z' && text[i] >= 'a') || (text[i] <= 'Z' && text[i] >= 'A')||(text[i] <= '9' && text[i] >= '0')) {grup tempG;edge tempE;tempE.accept = text[i];tempE.start = 0;tempE.end = 1;tempG.edges.push_back(tempE);s.push(tempG);}else {if (text[i] == '+') {grup tempG2 = s.top();s.pop();grup tempG1 = s.top();s.pop();//图和图合成grup tempG = tempG1;tempG.stateCount = tempG1.stateCount + tempG2.stateCount-1;tempG.StartState = 0;tempG.EndState = tempG.stateCount - 1;//获取后一条边for (int i = 0; i < int(tempG2.edges.size());i++) {edge e2 = tempG2.edges[i];e2.start += tempG1.stateCount-1;e2.end += tempG1.stateCount-1;tempG.edges.push_back(e2);}//合成图压栈s.push(tempG);}else if (text[i] == '*') {grup tempG2 = s.top();s.pop();grup tempG;if (tempG2.StartState!=tempG2.EndState) {tempG.stateCount = tempG2.stateCount + 1;}else {tempG.stateCount = tempG2.stateCount + 2;}tempG.EndState = tempG.stateCount-1;//图内的边编号加1for (int i = 0; i < int(tempG2.edges.size());i++) {edge e2 = tempG2.edges[i];if (e2.end==tempG2.EndState) {e2.start += 1;e2.end = e2.start;}else {e2.start += 1;e2.end += 1;}tempG.edges.push_back(e2);}//添加两条边edge e1;e1.accept = '~';e1.start = 0;e1.end = 1;edge e2;e2.accept = '~';e2.start = tempG.EndState-1;e2.end = e2.start + 1;tempG.edges.push_back(e1);tempG.edges.push_back(e2);//合成图压栈s.push(tempG);}else if (text[i] == '|') {grup tempG2 = s.top();s.pop();grup tempG1 = s.top();s.pop();grup tempG;tempG.StartState = 0;tempG.EndState = 0;tempG.stateCount = tempG1.stateCount + tempG2.stateCount-3;for (int i = 0; i < int(tempG1.edges.size());i++) {edge e1 = tempG1.edges[i];if (e1.end == tempG1.EndState) {e1.end = 0;}tempG.edges.push_back(e1);}for (int i = 0; i < int(tempG2.edges.size());i++) {edge e2 = tempG2.edges[i];if (e2.end == tempG2.EndState) {e2.end = 0;}tempG.edges.push_back(e2);}//合成图压栈s.push(tempG);}}}return s.top();
}
- 输出图结构:
输出时按照格式输出,构建好的图状态为0到n,把0输出为X最后一个输出为Y中间状态减一就可以了
完整代码:
#include<iostream>
#include<fstream>
#include<stack>
#include<vector>
#include<string>
#define MAX 100
using namespace std;//NFA边
struct edge{int start;int end;char accept;
};//NFA单元,一个大的NFA单元可以是由很多小单元通过规则拼接起来
class grup
{public:vector<edge> edges; //这个NFA拥有的边int stateCount; //状态数int StartState; //开始状态int EndState; //结束状态
public:grup() {this->stateCount = 2;this->StartState = 0;this->EndState = 1;}
};class WordAnstary {private :string input_file = "testfile.txt";string output_file = "output.txt";
public://主函数int start();//整理字符串string clear_text(string text);//中缀表达式转后缀表达式 string change_text(string text);//根据正规式获得NFAgrup getNFA(string text);//输出结果void printNFA(grup out);
};
//主函数
int WordAnstary::start() {//文件操作工具ifstream read_file;//读取文件string text;//read_file.open(input_file);//read_file >> text;cin >> text;//cout << text;//分析正规式,得到有穷自动机//cout << "原表达式为:" << text << endl;string new_text = this->clear_text(text);if (new_text != "") {cout << "添加+的表达式:"<<new_text << endl;new_text = this->change_text(new_text);cout << "后缀表达式:"<<new_text << endl;grup out = this->getNFA(new_text);this->printNFA(out);}else {cout << "输入不合法" << endl;}read_file.close();return 0;
};void WordAnstary::printNFA(grup out) {cout << "X ";for (int j = 0; j < int(out.edges.size()); j++) {edge eX = out.edges[j];if (eX.start == 0) {cout << "X-" << eX.accept << "->";if (eX.end==out.stateCount-1) {cout << "Y ";}else {cout << eX.end - 1<<" ";}}}cout << endl;cout << "Y ";for (int j = 0; j < int(out.edges.size()); j++) {edge eX = out.edges[j];if (eX.start == out.stateCount - 1) {cout << "Y-" << eX.accept << "->";if (eX.end == out.stateCount - 1) {cout << "Y ";}else {cout << eX.end - 1<<" ";}}}cout << endl;for (int i = 1; i < out.stateCount - 1; i++) {cout << i - 1 << " ";for (int j = 0; j < int(out.edges.size()); j++) {edge e = out.edges[j];if (e.start == i&&e.accept=='~') {cout << e.start - 1 << "-" << e.accept << "->";if (e.end == out.stateCount - 1) {cout << "Y ";}else {cout << e.end - 1 << " ";}}}for (int j = 0; j < int(out.edges.size()); j++) {edge e = out.edges[j];if (e.start == i&&e.accept!='~') {cout << e.start - 1 << "-" << e.accept << "->";if (e.end == out.stateCount - 1) {cout << "Y ";}else {cout << e.end - 1<<" ";}}}cout << endl;}
}grup WordAnstary::getNFA(string text) {stack<grup> s;for (int i = 0; i < int(text.length()); i++) {if ((text[i] <= 'z' && text[i] >= 'a') || (text[i] <= 'Z' && text[i] >= 'A')||(text[i] <= '9' && text[i] >= '0')) {grup tempG;edge tempE;tempE.accept = text[i];tempE.start = 0;tempE.end = 1;tempG.edges.push_back(tempE);s.push(tempG);}else {if (text[i] == '+') {grup tempG2 = s.top();s.pop();grup tempG1 = s.top();s.pop();//图和图合成grup tempG = tempG1;tempG.stateCount = tempG1.stateCount + tempG2.stateCount-1;tempG.StartState = 0;tempG.EndState = tempG.stateCount - 1;//获取后一条边for (int i = 0; i < int(tempG2.edges.size());i++) {edge e2 = tempG2.edges[i];e2.start += tempG1.stateCount-1;e2.end += tempG1.stateCount-1;tempG.edges.push_back(e2);}//合成图压栈s.push(tempG);}else if (text[i] == '*') {grup tempG2 = s.top();s.pop();grup tempG;if (tempG2.StartState!=tempG2.EndState) {tempG.stateCount = tempG2.stateCount + 1;}else {tempG.stateCount = tempG2.stateCount + 2;}tempG.EndState = tempG.stateCount-1;//图内的边编号加1for (int i = 0; i < int(tempG2.edges.size());i++) {edge e2 = tempG2.edges[i];if (e2.end==tempG2.EndState) {e2.start += 1;e2.end = e2.start;}else {e2.start += 1;e2.end += 1;}tempG.edges.push_back(e2);}//添加两条边edge e1;e1.accept = '~';e1.start = 0;e1.end = 1;edge e2;e2.accept = '~';e2.start = tempG.EndState-1;e2.end = e2.start + 1;tempG.edges.push_back(e1);tempG.edges.push_back(e2);//合成图压栈s.push(tempG);}else if (text[i] == '|') {grup tempG2 = s.top();s.pop();grup tempG1 = s.top();s.pop();grup tempG;tempG.StartState = 0;tempG.EndState = 0;tempG.stateCount = tempG1.stateCount + tempG2.stateCount-3;for (int i = 0; i < int(tempG1.edges.size());i++) {edge e1 = tempG1.edges[i];if (e1.end == tempG1.EndState) {e1.end = 0;}tempG.edges.push_back(e1);}for (int i = 0; i < int(tempG2.edges.size());i++) {edge e2 = tempG2.edges[i];if (e2.end == tempG2.EndState) {e2.end = 0;}tempG.edges.push_back(e2);}//合成图压栈s.push(tempG);}}}return s.top();
}string WordAnstary::clear_text(string text) {//储存添加好+号的正规式string new_text = "";//分析栈用来分析()匹配stack<char> s;for (int i = 0; i < int(text.length()); i++) {if ((text[i] <= 'z' && text[i] >= 'a') || (text[i] <= 'Z' && text[i] >= 'A') || (text[i] <= '9' && text[i] >= '0')) {new_text = new_text + text[i];if (i < int(text.length()) - 1) {if ((text[i + 1] <= 'z' && text[i+1] >= 'a') || (text[i + 1] <= 'Z' && text[i + 1] >= 'A') || (text[i+1] <= '9' && text[i+1] >= '0')) {new_text = new_text + '+';}else if (text[i + 1] == '(') {new_text = new_text + '+';}}}else if (text[i] == '|') {new_text = new_text + text[i];continue;}else if (text[i] == '*') {new_text = new_text + text[i];if (i < int(text.length()) - 1) {if ((text[i + 1] <= 'z' && text[i+1] >= 'a') || (text[i + 1] <= 'Z' && text[i + 1] >= 'A') || (text[i] <= '9' && text[i] >= '0'))new_text = new_text + '+';else if (text[i + 1] == '(')new_text = new_text + '+';}}else if (text[i] == '(') {new_text = new_text + text[i];s.push(text[i]);}else if (text[i] == ')') {new_text = new_text + text[i];if (i < int(text.length()) - 1) {if ((text[i + 1] <= 'z' && text[i+1] >= 'a') || (text[i + 1] <= 'Z' && text[i + 1] >= 'A') || (text[i] <= '9' && text[i] >= '0'))new_text = new_text + '+';else if (text[i + 1] == '(')new_text = new_text + '+';}if (s.empty()) {return "";}else {s.pop();}}elsereturn "";}if (s.empty())return new_text;elsereturn "";
}string WordAnstary::change_text(string text) {stack<char> s;string new_text = "";for (int i = 0; i<int(text.length()); i++) {if ((text[i] <= 'z' && text[i] >= 'a') || (text[i] <= 'Z' && text[i] >= 'A') || (text[i] <= '9' && text[i] >= '0')) {new_text = new_text + text[i];}else {if (text[i] == '(') {s.push(text[i]);}else if (text[i] == ')') {while (s.top() != '(') {new_text = new_text + s.top();s.pop();}s.pop();}else if (text[i] == '*') {s.push(text[i]);}else if (text[i] == '|') {if (s.empty()) {s.push(text[i]);}else {while (!s.empty()) {if (s.top() == '*') {new_text = new_text + s.top();s.pop();}else if (s.top() == '|') {new_text = new_text + s.top();s.pop();}else {break;}}s.push(text[i]);}}else if (text[i] == '+') {if (s.empty()) {s.push(text[i]);}else {while(!s.empty()){if (s.top() == '*') {new_text = new_text + s.top();s.pop();}else if (s.top() == '+') {new_text = new_text + s.top();s.pop();}else if (s.top() == '|') {new_text = new_text + s.top();s.pop();}else {break;}}s.push(text[i]);}}}}while(!s.empty()) {new_text += s.top();s.pop();}return new_text;
}//int main() {// WordAnstary wordAustary;
// wordAustary.start();
//}```
编译原理词法分析(正规式转NFA)相关推荐
- 编译技术:正规式、NFA、DFA、最简DFA的转换
正规式.NFA.DFA.最简DFA的转换 在编译原理中,正规式.NFA(非确定有穷自动机).DFA.最简DFA的转换在词法分析中是十分重要的一个环节. 一般来说:我们经常碰到的问题类型都是如下类型的: ...
- 【编译原理】正规式转换成NFA
非确定有限自动机(NFA) 状态转换图 状态转换矩阵 识别语言 Σ中的符 ∑ 正规式转换成NFA 例题 具体步骤
- 编译原理(正规式、有限自动机)
正规文法(3型文法) 文法是编译原理的基础,是描述一门程序设计语言和实现其编译器的方法(文法是用于描述语言的语法结构的形式规则).由正规文法(3型文法)产生的语言称为正规集. 之所以用"正规 ...
- 编译原理 | 由正规式构造确定的有穷自动机DFA
词法分析: 由正规式构造确定的有穷自动机DFA 解题方法 1. 先由正规式构造转换系统 规则见下图: 2. 再由转换系统构造确定有穷自动机DFA (1) 求 Ia 假定 I 是转换图状态集 K 一个子 ...
- 编译原理:正规式转变成DFA算法
//将正规式转变成NFApackage hjzgg.formal_ceremony_to_dfa;import java.util.ArrayList;class Edge{public int u, ...
- c语言注释的正规文法 编译原理,编译原理:正规式、正规文法与自动机
1.正规式转换到正规文法 对任意正规式R选择一个非终结符Z生成规则Z→R 1.对形如A→ab的规则,转换成A→aB,B→b 2.将形如A→a|b的规则,转换成A→a,A→b(A→a|b) 3.将形如A ...
- 【编译原理】正规式和正规文法的转换
正规式和正规文法的转换 正规式-->正规文法 A->xy可分解成 A->xB,B->y A->x*y可分解成 A->xA,A->y A->x|y可分解成 ...
- 编译原理——正规式、NFA转换构造DFA、DFA的化简
一.DFA和NFA的区别 NFA:非确定有限自动机 DFA:确定有限自动机 NFA在同一状态,可以有多条出边,DFA在同一状态,只能有一条出边: NFA的初态可以具有多个,DFA的初态是唯一的: 比如 ...
- 正规式转换为NFA代码实现
问题引入 正规式是一种编译原理课程中经常提到的描述文法的语法规则,与正则表达式有相同之处,但并不是同一个概念.有效的正规式的字母表∑ = { a − z , A − Z } . 所有的正规式中的符号以 ...
最新文章
- linux进程通信:pipe实现进程同步
- 世界互联网大会上发布的《中国互联网发展报告2020》显示——中国人工智能专利申请数跃居世界第一...
- 建环计算机应用试题,环境建环和给水排水工程计算机应用教材内容
- 让对话框不显示边框_微信消息“无边框”模式搭配这款壁纸,简直绝了
- 用WEB技术栈开发NATIVE应用(二):WEEX 前端SDK原理详解
- 迅捷cad_迅捷功能
- java 数据库编程(一)JDBC连接Sql Server数据库
- 工具 | Procexp工具使用及案例说明
- 【毕业设计】基于stm32的示波器设计与实现 - 单片机 物联网
- 【毕业设计8】基于STM32的红外测距系统
- vuejs登陆页面_20个最佳Vuejs登陆页面模板
- MyExcel 3.9.8 版本发布
- 计算机系学生的梦想,编写我们的梦想——北大计算机系学生生活掠影-北京大学网络与信息.ppt...
- Linux系统安装与使用基础之第二篇熟悉Linux操作系统
- C语言基础语法(初学者必看)
- VIM的初学配置文件
- MathType的下载和安装以及添加到word中
- matlab的一点内容
- ML(10) - 模型训练技巧
- 1、英里与千米的转换
热门文章
- “最可怕”的搜索引擎 shodan
- 【PCIe 6.0】PCIe 6.0 新特性 - L0p 详解
- 基于K-L变换的人脸识别
- [原创] 如何给Blog 添加 计数器 和 广告
- 华为-ensp软件安装方法攻略
- 斯坦福自然语言处理课程笔记 Part 1
- 融资租赁租金表、收益指标、财务分摊等相关计算原理
- 【RDMA】11. RDMA之Shared Receive Queue
- 使用c++开发excel插件(第4章编写一个完整的xll)
- iPad看代码的方法