正规表达式 转 NFA C++
今天来为大家分享一个编译原理中用正规表达式转NFA的小程序
正规表达式就是类似正则一样的式子,例如:(a|b)*abb,最后应该转化为:
大致的处理流程为:
例子中的表达式:(a|b)*abb,|和*都是运算法则,而且容易识别,但是处理abb就不是你那么方便了,所以我们在abb中间加上+号,就可以像|*那样识别了,所以处理后为(a|b)*a+b+b
我们识别出来之后,首先根据书中提供的运算符->NFA部件的图转化为NFA部件,之后再根据优先级和各个部件组建NFA
运算符对应NFA中的各个部件图为:
ε符:
φ符:
输入符号:
| 符:
+符:
*符:
有一个问题,NFA的开始和终止都是状态集合,但是整改了好多次,没能设计出来,所以该程序产生的NFA均只有一个开始状态和一个终止状态
代码注释挺清楚的,我就不过多描述了
G[S]->NFA代码如下:
#ifndef _GNFA_
#define _GNFA_ /*
@author:Lv
@time:2018-11
@title:正规式转NFA
*/ #include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set> namespace GNFAs
{
#define stds std:: /*
@brief 记录NFA每一个状态
@member 记录名称
*/
struct state
{
stds string _staName;
//state(const stds string& name = "#") :_staName(name) { }
bool operator<(const state& b)const { return _staName < b._staName; }
}; /*
@brief 记录状态之间转换的边信息
@member 起始状态、终止状态、状态转换输入符号
*/
struct edge
{
state _edgStart;
state _edgEnd;
char _edgSymbol;
}; /*
NFA-class
*/
class NFA
{
public:
using ostream = stds ostream;
using istream = stds istream;
using exptype = stds string;
using map_sta = stds vector<edge>;
using container_sta = stds set<state>;
using container_sym = stds set<char>;
public:
/*
@brief nfaunit 用于记录NFA数据集合--NFA基本数据类型--NFA单元
@member K 状态集合
Σ 字母表
f 状态映射
S 开始状态
Z 终止状态集合
*/
typedef struct NFAunit
{
container_sta K;
container_sym Σ;
map_sta f;
state S;
state Z; NFAunit()
{
f.clear();
K.clear();
Σ.clear();
Z = state();
S = state();
} NFAunit(const NFAunit& other)
:K(other.K)
,Σ(other.Σ)
,f(other.f)
,S(other.S)
,Z(other.Z)
{ } NFAunit& operator=(const NFAunit& other)
{
if (this != &other)
{
K = other.K;
Σ = other.Σ;
f = other.f;
S = other.S;
Z = other.Z;
}
return *this;
} NFAunit& operator+=(const NFAunit& other)
{
K.insert(other.K.begin(), other.K.end());
Σ.insert(other.Σ.begin(), other.Σ.end());
f.insert(f.end(), other.f.begin(), other.f.end());
return *this;
}
} _type_; public:
NFA(); NFA(const NFA&); NFA& operator=(const NFA&); _type_ getNFA()const { return _data; } exptype getExpression()const { return _expression; } public:
/*
@brief 输入正规式
*/
void input(); /*
@brief 转成NFA
*/
void toNFA(); /*
@brief 展示NFA
*/
void show()const; /*
@brief 刷新数据
*/
void update(); /*
@brief 运行
*/
void run(); private:
/*
@brief 检查正规式是否合法
@retur 是否合法
*/
bool _checkExp()const; /*
@brief 检查正规式字符是否合法
@retur 是否合法
*/
bool _checkSym()const; /*
@brief 检查正规式语法,如:括号匹配
@retur 是否合法
*/
bool _checkSync()const; /*
@brief 做一些处理便于表达式转换
*/
void change(); /*
@brief 中缀转后缀
*/
void postexp(); /*
@brief 栈内优先级
*/
int inpriority(const char)const; /*
@brief 栈外优先级
*/
int outpriority(const char)const; /*
@brief 整合a|b
*/
_type_ _or(_type_, _type_); /*
@brief 整合ab
*/
_type_ _mul(_type_, _type_); /*
@brief 整合a*
*/
_type_ _star(_type_); /*
@brief 整合单元
*/
_type_ _unit(const char); private:
int _staNum;
ostream& _out;
istream& _in;
NFAunit _data;
exptype _expression;
};
} #endif //_GNFA_
#include "GNFA.h"
using namespace GNFAs; #include <stack> using stack_unit = stds stack<NFA::NFAunit>;
using stack_char = stds stack<char>; #define enter stds endl NFA::NFA()
:_staNum()
, _out(std::cout)
, _in(std::cin)
{ } void NFA::input()
{
_out << "请输入正规式:" << enter; while (!_checkExp()) _in >> _expression;
} bool NFA::_checkExp()const
{
if (!_checkSym())
{
_out << "含有非法字符!" << enter;
return false;
}
if (!_checkSync())
{
_out << "含有语法错误!" << enter;
return false;
}
return _expression != exptype();
} bool NFA::_checkSym()const
{
for (int i = ; i < _expression.size(); ++i)
{
if (islower(_expression[i])) continue;
else if (_expression[i] == '(' || _expression[i] == ')' || _expression[i] == '*' || _expression[i] == '|')
continue;
else
return false;
}
return true;
} bool NFA::_checkSync()const
{
stack_char stack;
for (int i = ; i < _expression.size(); ++i)
{
if (_expression[i] == '(')
stack.push('(');
else if (_expression[i] == ')')
{
if (stack.size() && stack.top() == '(')
stack.pop();
else return false;
}
if (_expression[i] == '*')
{
if (i &&_expression[i - ] != '|')
continue;
else return false;
}
}
if (stack.size())return false;
return true;
} void NFA::change()
{
exptype t; char s, e; for (int i = ; i < _expression.size(); ++i)
{
s = _expression[i];
e = _expression[i + ];
t += s; if (s != '(' && s != '|' && islower(e)) t += '+';
else if (e == '(' && s != '|' && s != '(') t += '+';
}
t += e;
_expression = t;
} int NFA::inpriority(const char c)const
{
switch (c)
{
case '#': return ;
case '(': return ;
case '*': return ;
case '|': return ;
case '+': return ;
case ')': return ;
}
return -;
} int NFA::outpriority(const char c)const
{
switch (c)
{
case '#': return ;
case '(': return ;
case '*': return ;
case '|': return ;
case '+': return ;
case ')': return ;
}
return -;
} void NFA::postexp()
{
_expression += '#';
exptype t = "";
stack_char s;
char ch = '#', ch1, op;
s.push(ch); //读一个字符
int read_location = ;
ch = _expression.at(read_location++);
while (!s.empty())
{
if (islower(ch))
{
t += ch;
ch = _expression.at(read_location++);
}
else
{
ch1 = s.top();
if (inpriority(ch1)<outpriority(ch))
{
s.push(ch);
ch = _expression.at(read_location++);
}
else if (inpriority(ch1)>outpriority(ch))
{
op = s.top();
s.pop();
t += op;
}
else
{
op = s.top();
s.pop(); if (op == '(')
ch = _expression.at(read_location++);
}
}
}
t.erase(t.end() - );
_expression = t;
} void NFA::toNFA()
{
char item;
_type_ left, right;
stack_unit stack; for (int i = ; i < _expression.size(); ++i)
{
item = _expression[i];
switch (item)
{
case '|':
right = stack.top();
stack.pop();
left = stack.top();
stack.pop();
_data = _or(left, right);
stack.push(_data);
break;
case '*':
left = stack.top();
stack.pop();
_data = _star(left);
stack.push(_data);
break;
case '+':
right = stack.top();
stack.pop();
left = stack.top();
stack.pop();
_data = _mul(left, right);
stack.push(_data);
break;
default:
_data = _unit(item);
stack.push(_data);
}
} _data = stack.top();
stack.pop();
} NFA::_type_ NFA::_or(_type_ unitl, _type_ unitr)
{
_type_ unit;
exptype name;
edge e1, e2, e3, e4; state start { name += _staNum++ + 'A' };
name = "";
state end{ name += _staNum++ + 'A' }; e1._edgStart = start;
e1._edgEnd = unitl.f[]._edgStart;
e1._edgSymbol = '#'; e2._edgStart = start;
e2._edgEnd = unitr.f[]._edgStart;
e2._edgSymbol = '#'; e3._edgStart = unitl.f[unitl.f.size() - ]._edgEnd;
e3._edgEnd = end;
e3._edgSymbol = '#'; e4._edgStart = unitr.f[unitr.f.size() - ]._edgEnd;
e4._edgEnd = end;
e4._edgSymbol = '#'; unit = unitl;
unit += unitr;
unit.f.push_back(e1);
unit.f.push_back(e2);
unit.f.push_back(e3);
unit.f.push_back(e4); unit.S = start;
unit.Z = end; return unit;
} NFA::_type_ NFA::_mul(_type_ unitl, _type_ unitr)
{
for (auto &it : unitr.f)
{
if (it._edgStart._staName == unitr.S._staName)
{
it._edgStart = unitl.Z;
_staNum--;
}
else if (it._edgEnd._staName == unitr.S._staName)
{
it._edgEnd = unitl.Z;
_staNum--;
}
}
unitr.S = unitl.Z;
unitl += unitr;
unitl.Z = unitr.Z; return unitl;
} NFA::_type_ NFA::_star(_type_ u)
{
_type_ unit;
exptype name;
edge e1, e2, e3, e4; state start{ name += _staNum++ + 'A' };
name = "";
state end{ name += _staNum++ + 'A' }; e1._edgStart = start;
e1._edgEnd = end;
e1._edgSymbol = '#'; e2._edgStart = u.Z;
e2._edgEnd = u.S;
e2._edgSymbol = '#'; e3._edgStart = start;
e3._edgEnd = u.Z;
e3._edgSymbol = '#'; e4._edgStart = u.Z;
e4._edgEnd = start;
e4._edgSymbol = '#'; unit = u; unit.f.push_back(e1);
unit.f.push_back(e2);
unit.f.push_back(e3);
unit.f.push_back(e4); unit.S = start;
unit.Z = end; return unit;
} NFA::_type_ NFA::_unit(const char ch)
{
_type_ unit;
exptype name;
edge e; state start{ name += _staNum++ + 'A' };
name = "";
state end{ name += _staNum++ + 'A' }; e._edgStart = start;
e._edgEnd = end;
e._edgSymbol = ch; unit.f.push_back(e);
unit.S = start;
unit.Z = end; return unit;
} void NFA::show()const
{
_out << "NFA 的起始状态:" << _data.S._staName << enter;
_out << "NFA 的结束状态:" << _data.Z._staName << enter << enter; for (auto it : _data.f)
{
_out << "from state: " << it._edgStart._staName
<< "\t to state: " << it._edgEnd._staName
<< "\t\tby ";
if (it._edgSymbol == '#') _out << R"+(ε)+" << enter;
else _out << it._edgSymbol << enter;
}
_out << enter;
} void NFA::update()
{
for (auto it : _data.f)
{
_data.K.insert(it._edgStart);
_data.K.insert(it._edgEnd);
_data.Σ.insert(it._edgSymbol);
}
} void NFA::run()
{
input(); change(); postexp(); toNFA(); show(); update();
}
#include "GNFA.h"
using namespace GNFAs; int main()
{
NFA nfa;
nfa.run();
}
测试结果:
感谢您的阅读,生活愉快~
正规表达式 转 NFA C++的更多相关文章
- UVA 1672不相交的正规表达式
题意 输入两个正规表达式,判断两者是否相交(即存在一个串同时满足两个正规表达式).本题的正规表达式包含如下几种情况: 单个小写字符 $c$ 或:($P | Q$). 如果字符串 $s$ 满足 $P$ ...
- 正规表达式与有限自动机和LEX
正规式与有限自动机的等价性 一个正规式r与一个有限自动机M等价, L(r)=L(M) FA ->正规式,对任何FA M,都存在一个正规式r,使得L(r)=L(M). 正规式 -> FA, ...
- 学JS的心路历程-正规表达式Regular Expression
今天我们来看正规表达式,在谈到为什么需要多学这个之前,先来看个示例. 假设需要判断输入字串是否含有“apple”: var text=“A apple a day keeps the doctor a ...
- 1.java实现——正规表达式判断
目标:这个代码仅局限于所展示的正规表达式判断,也就是这是一个较单一的正规表达式判断(简易版). 既然是简易版的,所以若要修改这个正规表达式也是非常容易的,只要将二维数组中的数组修改即可.数组数据依据, ...
- Linux学习十七、正规表达式练习题
情境模拟题一:透过 grep 搜寻特殊字串,并配合数据流重导向来处理大量的文件搜寻问题. 目标:正确的使用正规表示法: 前提:需要了解数据流重导向,以及透过子命令 $(command) 来处理档名的搜 ...
- 轻松学Shell之认识正规表达式
离线下载观看:http://down.51cto.com/data/148117 650) this.width=650;" onclick='window.open("htt ...
- vs 2017 正规表达式替换整行多行数据
((<OutputFile>..*</OutputFile>)[\S\s])[\S\s] 从 <OutputFile> 开始 到 </OutputFile&g ...
- Swift中用正规表达式判断String是否是手机号码
func isTelNumber(num:NSString)->Bool { var mobile = "^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$&qu ...
- C# 正规表达式
在C#中怎么用正则表达式限制文本框内不能输入数字?只能输入数字:"^[0-9]*$".只能输入n位的数字:"^\d{n}$".只能输入至少n位的数字:" ...
随机推荐
- ubuntu环境下eclipse的安装以及hadoop插件的配置
ubuntu环境下eclipse的安装以及hadoop插件的配置 一.eclipse的安装 在ubuntu桌面模式下,点击任务栏中的ubuntu软件中心,在搜索栏搜索eclipse 注意:安装过程需要 ...
- laravel更新某一个或几个字段
//更新会员状态status $ary_where = array(); $ary_where[] = ['id', '=', $int_id]; $result = $this->obj_ad ...
- D. Sum in the tree(树形+贪心)
题目链接;http://codeforces.com/contest/1099/problem/D 题目大意:给出一棵树,每个节点到根节点的路径上经过的所有点的权值之和,其深度为偶数的节点的信息全部擦 ...
- 未来人类T5 安装win10,ubuntu双系统
1.首先确保win10已经安装,u盘中已刻录好系统,下载好英伟达最新驱动保存在u盘中,压缩100g的磁盘空间给ubuntu. 2.设置双显卡模式,重启时按F7选择进入u盘启动. 3.进入安装界面,选择 ...
- jquery easyui 扩展验证
$.extend($.fn.validatebox.defaults.rules, { idcard : {// 验证身份证 validator : function(value) ...
- CodeForces 1096E: The Top Scorer
一道经典组合数学+容斥题. 题目传送门:CF1096E. 题意简述: \(p\) 个人,每个人有得分 \(a_i\). 总得分 \(\sum a_i = s\). 第一个人得分 \(a_1 \ge r ...
- Linux USB驱动学习总结(二)---- USB设备驱动
USB 设备驱动: 一.USB 描述符:(存在于USB 的E2PROM里面) 1. 设备描述符:struct usb_device_descriptor 2. 配置描述符:struct usb_c ...
- SSD固态硬盘检测工具AS SSD参数
一. 使用AS SSD Benchmark进行查看 包括了4个方面的测试(顺序读写.4K随机读写.64线程4K读写.寻道时间) AS SSD的主要测试,也是网上最常见得到测试成绩的,是它主界面上持续. ...
- MySQL 四种链接
1.内联接 INNER JOIN(典型的联接运算,使用像 = 或 <> 之类的比较运算符).包括相等联接和自然联接. 内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行. ...
- 洛谷P2016战略游戏
传送门啦 战略游戏这个题和保安站岗很像,这个题更简单,这个题求的是士兵人数,而保安站岗需要求最优价值. 定义状态$ f[u][0/1] $ 表示 $ u $ 这个节点不放/放士兵 根据题意,如果当前节 ...