文章目录

  • 【问题描述】
  • 【基本要求】
  • 【测试用例】
  • 【解决步骤】
    • 正规式转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. 判断一下正规式有没有错误,括号对不对,并添加符号“+”
  2. 运算符的优先级为:*>|>+
  3. 根据符号优先级,把中缀表达式转后缀表达式便于计算
  4. 根据后缀表达式依次构建图。有三种运算:*、|、+

图的构建过程:

(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,从左忘右扫描表达式,
      遇见字母或数字拼接在输出表达式后
      遇见“(”压入栈中
      遇见“)”弹出栈中元素,直到遇到了“(”
      遇到“、|、+”判断栈顶元素的优先级,把比自己优先级高或等的弹出去
      然后自己再压栈。
      扫描完成后再把栈中元素依次弹出,拼接在输出字符串后
      完成后(a|b)
      +a+b+b应该变为:ab|*a+b+b+
      核心算法:
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)相关推荐

  1. 编译技术:正规式、NFA、DFA、最简DFA的转换

    正规式.NFA.DFA.最简DFA的转换 在编译原理中,正规式.NFA(非确定有穷自动机).DFA.最简DFA的转换在词法分析中是十分重要的一个环节. 一般来说:我们经常碰到的问题类型都是如下类型的: ...

  2. 【编译原理】正规式转换成NFA

    非确定有限自动机(NFA) 状态转换图 状态转换矩阵 识别语言 Σ中的符 ∑ 正规式转换成NFA 例题 具体步骤

  3. 编译原理(正规式、有限自动机)

    正规文法(3型文法) 文法是编译原理的基础,是描述一门程序设计语言和实现其编译器的方法(文法是用于描述语言的语法结构的形式规则).由正规文法(3型文法)产生的语言称为正规集. 之所以用"正规 ...

  4. 编译原理 | 由正规式构造确定的有穷自动机DFA

    词法分析: 由正规式构造确定的有穷自动机DFA 解题方法 1. 先由正规式构造转换系统 规则见下图: 2. 再由转换系统构造确定有穷自动机DFA (1) 求 Ia 假定 I 是转换图状态集 K 一个子 ...

  5. 编译原理:正规式转变成DFA算法

    //将正规式转变成NFApackage hjzgg.formal_ceremony_to_dfa;import java.util.ArrayList;class Edge{public int u, ...

  6. 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 ...

  7. 【编译原理】正规式和正规文法的转换

    正规式和正规文法的转换 正规式-->正规文法 A->xy可分解成 A->xB,B->y A->x*y可分解成 A->xA,A->y A->x|y可分解成 ...

  8. 编译原理——正规式、NFA转换构造DFA、DFA的化简

    一.DFA和NFA的区别 NFA:非确定有限自动机 DFA:确定有限自动机 NFA在同一状态,可以有多条出边,DFA在同一状态,只能有一条出边: NFA的初态可以具有多个,DFA的初态是唯一的: 比如 ...

  9. 正规式转换为NFA代码实现

    问题引入 正规式是一种编译原理课程中经常提到的描述文法的语法规则,与正则表达式有相同之处,但并不是同一个概念.有效的正规式的字母表∑ = { a − z , A − Z } . 所有的正规式中的符号以 ...

最新文章

  1. linux进程通信:pipe实现进程同步
  2. 世界互联网大会上发布的《中国互联网发展报告2020》显示——中国人工智能专利申请数跃居世界第一...
  3. 建环计算机应用试题,环境建环和给水排水工程计算机应用教材内容
  4. 让对话框不显示边框_微信消息“无边框”模式搭配这款壁纸,简直绝了
  5. 用WEB技术栈开发NATIVE应用(二):WEEX 前端SDK原理详解
  6. 迅捷cad_迅捷功能
  7. java 数据库编程(一)JDBC连接Sql Server数据库
  8. 工具 | Procexp工具使用及案例说明
  9. 【毕业设计】基于stm32的示波器设计与实现 - 单片机 物联网
  10. 【毕业设计8】基于STM32的红外测距系统
  11. vuejs登陆页面_20个最佳Vuejs登陆页面模板
  12. MyExcel 3.9.8 版本发布
  13. 计算机系学生的梦想,编写我们的梦想——北大计算机系学生生活掠影-北京大学网络与信息.ppt...
  14. Linux系统安装与使用基础之第二篇熟悉Linux操作系统
  15. C语言基础语法(初学者必看)
  16. VIM的初学配置文件
  17. MathType的下载和安装以及添加到word中
  18. matlab的一点内容
  19. ML(10) - 模型训练技巧
  20. 1、英里与千米的转换

热门文章

  1. “最可怕”的搜索引擎 shodan
  2. 【PCIe 6.0】PCIe 6.0 新特性 - L0p 详解
  3. 基于K-L变换的人脸识别
  4. [原创] 如何给Blog 添加 计数器 和 广告
  5. 华为-ensp软件安装方法攻略
  6. 斯坦福自然语言处理课程笔记 Part 1
  7. 融资租赁租金表、收益指标、财务分摊等相关计算原理
  8. 【RDMA】11. RDMA之Shared Receive Queue
  9. 使用c++开发excel插件(第4章编写一个完整的xll)
  10. iPad看代码的方法