今天来为大家分享一个编译原理中用正规表达式转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++的更多相关文章

  1. UVA 1672不相交的正规表达式

    题意 输入两个正规表达式,判断两者是否相交(即存在一个串同时满足两个正规表达式).本题的正规表达式包含如下几种情况: 单个小写字符 $c$ 或:($P | Q$). 如果字符串 $s$ 满足 $P$ ...

  2. 正规表达式与有限自动机和LEX

    正规式与有限自动机的等价性 一个正规式r与一个有限自动机M等价, L(r)=L(M) FA ->正规式,对任何FA M,都存在一个正规式r,使得L(r)=L(M). 正规式 -> FA, ...

  3. 学JS的心路历程-正规表达式Regular Expression

    今天我们来看正规表达式,在谈到为什么需要多学这个之前,先来看个示例. 假设需要判断输入字串是否含有“apple”: var text=“A apple a day keeps the doctor a ...

  4. 1.java实现——正规表达式判断

    目标:这个代码仅局限于所展示的正规表达式判断,也就是这是一个较单一的正规表达式判断(简易版). 既然是简易版的,所以若要修改这个正规表达式也是非常容易的,只要将二维数组中的数组修改即可.数组数据依据, ...

  5. Linux学习十七、正规表达式练习题

    情境模拟题一:透过 grep 搜寻特殊字串,并配合数据流重导向来处理大量的文件搜寻问题. 目标:正确的使用正规表示法: 前提:需要了解数据流重导向,以及透过子命令 $(command) 来处理档名的搜 ...

  6. 轻松学Shell之认识正规表达式

    离线下载观看:http://down.51cto.com/data/148117   650) this.width=650;" onclick='window.open("htt ...

  7. vs 2017 正规表达式替换整行多行数据

    ((<OutputFile>..*</OutputFile>)[\S\s])[\S\s] 从 <OutputFile> 开始 到 </OutputFile&g ...

  8. Swift中用正规表达式判断String是否是手机号码

    func isTelNumber(num:NSString)->Bool { var mobile = "^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$&qu ...

  9. C# 正规表达式

    在C#中怎么用正则表达式限制文本框内不能输入数字?只能输入数字:"^[0-9]*$".只能输入n位的数字:"^\d{n}$".只能输入至少n位的数字:" ...

随机推荐

  1. css文字超出显示省略号

    单号: white-space:nowrap; overflow:hidden; text-overflow:ellipsis; 多行: word-break: break-all; text-ove ...

  2. mysql的force index

    MSQL中使用order by 有个坑,会默认走order by 后面的索引.而不走where条件里应该走的索引.大家在使用时要绕过此坑. 如下语句因为order by 走了settle_id这个主键 ...

  3. CF 1008C Reorder the Array

    You are given an array of integers. Vasya can permute (change order) its integers. He wants to do it ...

  4. 多进程+协程 处理IO问题

    from multiprocessing import Pool import gevent,os import time def recursion(n): if n == 1 or n ==2: ...

  5. vue中使用cookie记住用户上次选择(本次例子中为下拉框)

    最近工作中碰到一个需求,添加一条数据时,自动记住上次选择的下拉框的数据,刚开始觉得没思路,后来请教了项目组长,组长直接一句,这不很简单吧,直接用cookie,我:....... 好吧,都王的差不多了, ...

  6. 转载-struts中logic标签使用

    Struts中Logic逻辑标签的作用及用法 Struts中Logic逻辑标签的作用及用法 2006年10月18日 星期三 21:34 Terry原创,转载请说明作者及出处 Logic标签大部分的功能 ...

  7. Linux入门(一)root密码设置和用户切换

    从这学期开始,本人将会亲自开一个Linux 专题学习包括Linux 常用命令,常见问题的一些解决方法,以及Linux系统下C和C++一些学习经验 下面这张图片是首次安装Ubuntu后第一次设置root ...

  8. type Iterator does not take parameters

    在ubuntu编译java程序时报错:type Iterator does not take parameters 源码如下: package object; import java.util.*; ...

  9. (二) Log4j 配置详解

    第一节: rootLogger 根配置 Log4j 根配置语法 log4j.rootLogger = [ level ] , appenderName, appenderName, … 指代 把指定级 ...

  10. Python 安装 pytesser 处理验证码出现的问题

    今天这个问题困扰了我好久,开始直接用 pip install pytesseract 安装了 pytesseract 然后出现了如下错误 Traceback (most recent call las ...