本程序实现了egrep命令,首先将正则表达式转换为NFA,并实现模拟NFA的算法。

本程序使用flex实现词法分析,bison实现语法分析

若给定的一行字符串中存在一个字串能被该NFA接受,则输出整行。

所用语法如下:

S-->S|S

   |SS

   |S*

   |(S)

|a

bison程序:

%{
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <stack>
#include <algorithm>
#include <boost/foreach.hpp>
#include <set>
#include <map>
using namespace std;
typedef string state;
typedef set<string> states;
typedef map<string, states> transition;
class value
{
public:
string* symbol;
state *start;
state *final;
map<state,transition> *transitions;
};
char* filename;
int number;//用于生成状态号
int yylex(void);
void yyerror(char const *);
template<class TYPE>
string transfer(TYPE init);
void Scopy(value S,value &result);
void Skleen(value S,value &result);
void SconnectS(value S1,value S2,value &result);
void SorS(value S1,value S2,value &result);
states epsilonClosure(states T,map<state,transition> transitions);
states move(states T, string a,map<state,transition> transitions);
void simulateNFA(string str,value NFA);
%} %define api.value.type { class value }
//优先级为:闭包>连接>并
%token ASCII
%token LP
%token RP
%left OR
%left CONNECT
%left KLEEN
%expect 4
%%
lines: lines S '\n'
{
number=0;
ifstream in(filename);
string line;
while(getline(in,line))
simulateNFA(line,$2);
}
| lines '\n'
|
| error '\n' {yyerrok;}
;
S: S KLEEN
{Skleen($1,$$);}
|S S %prec CONNECT
{SconnectS($1,$2,$$);}
|S OR S
{SorS($1,$3,$$);}
|LP S RP
{Scopy($2,$$);}
|ASCII
{
$$.start=new string(transfer<int>(number++));
$$.final=new string(transfer<int>(number++));
states accetping;
accetping.insert(*$$.final);
$$.transitions=new map<state,transition>();
(*$$.transitions)[*$$.start][*$$.symbol]=accetping;
}
;
%%
#include "lex.yy.c" int main(int argc,char*argv[]) {
number=0;
filename=argv[1];
return yyparse();
} void yyerror(char const *s)
{
cout<<s<<endl;
}
states epsilonClosure(states T,map<state,transition> transitions)
{
stack<state> S;
BOOST_FOREACH(state u, T)
{ S.push(u); }
while (!S.empty())
{
state t = S.top();
S.pop();
BOOST_FOREACH(state u, transitions[t]["epsilon"])
{
if (T.count(u) == 0)
{
T.insert(u);
S.push(u);
}
}
}
return T;
} states move(states T,string a,map<state,transition> transitions)
{
states result;
BOOST_FOREACH(state u, T)
BOOST_FOREACH(state v, transitions[u][a])
{ result.insert(v); }
return result;
} void simulateNFA(string str,value NFA)
{
bool flag=false;
//穷举字串测试,若被NFA受则退出循环
for(int i=0;i<str.length();i++)
{
for(int j=0;j<=str.length()-i;j++)
{
string substr;
substr=str.substr(i,j);
states S;
string c;//转移符号
int count=0;
if(j==0)
{c="epsilon";}
else
{c=transfer<char>(substr[0]);}
S.insert(*NFA.start);
S=epsilonClosure(S,*NFA.transitions);
while(count<substr.length())
{
S=epsilonClosure(move(S,c,*NFA.transitions),*NFA.transitions);
c=substr[++count];
}
if (S.count(*NFA.final)!= 0)
{
flag=true;
break;
}
}
if(flag)
break;
}
if(flag)
cout<<str<<endl;
} template<class TYPE>
string transfer(TYPE init)
{
stringstream ss;
ss<<init;
string str;
ss>>str;
return str;
}
/*result-->(S)
直接拷贝S至转换表至result*/
void Scopy(value S,value &result)
{
result.start=new string(*S.start);
result.final=new string(*S.final);
result.transitions=new map<state,transition>();
copy((*S.transitions).begin(),(*S.transitions).end(),insert_iterator<map<state,transition> >
(*result.transitions,(*result.transitions).begin()));
}
/*result-->S*
首先拷贝s的转换表至result,然后对result生成新的开始态、结束态,
并将result的开始态连至S的开始态和result的结束态,边上符号为"epsilon";
将S的结束态连至S的开始态和result的结束态,边上符号为"epsilon"*/
void Skleen(value S,value &result)
{
result.start=new string(transfer<int>(number++));
result.final=new string(transfer<int>(number++));
result.transitions=new map<state,transition>();
copy((*S.transitions).begin(),(*S.transitions).end(),insert_iterator<map<state,transition> >
(*result.transitions,(*result.transitions).begin()));
states accepting;
accepting.insert(*S.start);
accepting.insert(*result.final);
(*result.transitions)[*result.start]["epsilon"]=accepting;
(*result.transitions)[*S.final]["epsilon"]=accepting;
}
/*result-->S1 S2
分别将S1、S2的转换表拷贝至result,再将S2的开始态改为S1的结束态*/
void SconnectS(value S1,value S2,value &result)
{
result.start=new string(*S1.start);
result.final=new string(*S2.final);
result.transitions=new map<state,transition>();
copy((*S1.transitions).begin(),(*S1.transitions).end(),insert_iterator<map<state,transition> >
(*result.transitions,(*result.transitions).begin()));
copy((*S2.transitions).begin(),(*S2.transitions).end(),insert_iterator<map<state,transition> >
(*result.transitions,(*result.transitions).end()));
map<state,transition>::iterator it;
if((it=(*result.transitions).find(*S2.start))!=(*result.transitions).end())
{
pair<state,transition> temp;
temp=make_pair(*S1.final,it->second);
(*result.transitions).erase(*S2.start);
(*result.transitions).insert(temp);
}
}
/*result-->S|S
分别将S1、S2的转换表拷贝至result,然后对result生成新的开始态、结束态,
并将result的开始态连至S1和S2的开始态,边上符号为"epsilon";将S1和S2的结
束态连至result的结束态,边上符号为"epsilon"*/
void SorS(value S1,value S2,value &result)
{
result.start=new string(transfer(number++));
result.final=new string(transfer(number++));
result.transitions=new map<state,transition>();
copy((*S1.transitions).begin(),(*S1.transitions).end(),insert_iterator<map<state,transition> >
(*result.transitions,(*result.transitions).begin()));
copy((*S2.transitions).begin(),(*S2.transitions).end(),insert_iterator<map<state,transition> >
(*result.transitions,(*result.transitions).end()));
states accepting;
accepting.insert(*S1.start);
accepting.insert(*S2.start);
(*result.transitions)[*result.start]["epsilon"]=accepting;
accepting.clear();
accepting.insert(*result.final);
(*result.transitions)[*S1.final]["epsilon"]=accepting;
(*result.transitions)[*S2.final]["epsilon"]=accepting;
}

flex程序:

%{
#include<string>
%}
escape "\\("|"\\)"|"\\|"|"\\*"
%%
[ \t]+
\n {return yytext[0];}
"(" {return LP;}
")" {return RP;}
"|" {return OR;}
"*" {return KLEEN;}
{escape} {
yylval.symbol=new string(transfer(yytext).substr(1,1));
return ASCII;
}
. {
yylval.symbol=new string(transfer(yytext));
return ASCII;
}

假设将bison程序拷至biaon.y,flex程序拷至flex.l。

运行如下:

flex lex.l

bison bison.y

g++ bison.tab.c -ly -ll

./a.out filname

最后可输入待测试正则表达式

版权声明:本文为博主原创文章,未经博主允许不得转载。

egrep命令的实现 分类: 编译原理 2014-06-01 23:41 329人阅读 评论(0) 收藏的更多相关文章

  1. 树莓派安装mjpg-streamer视频监控 分类: Raspberry Pi 2015-04-12 23:41 144人阅读 评论(0) 收藏

    原来使用Motion在树莓派上跑1280x720分辨率的三颗摄像头.占用内存太严重,关闭诸多功能之后还是不行.故转战mjpg-streamer. 首先安装所需软件 sudo apt-get insta ...

  2. HDU 1272 小希的迷宫(并查集) 分类: 并查集 2015-07-07 23:38 2人阅读 评论(0) 收藏

    Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就 ...

  3. Makefile 入门与基本语法 分类: C/C++ ubuntu 2015-05-18 11:16 466人阅读 评论(0) 收藏

    在我看来,学会写简单的Makefile,阅读较复杂的makefile,是每一个Linux程序员都必须拥有的基本素质.Makefile可以自动识别哪些源文件被更改过,需要重新编译,那些不需要.从而节省大 ...

  4. nginx 安装手记 分类: Nginx 服务器搭建 2015-07-14 14:28 15人阅读 评论(0) 收藏

    Nginx需要依赖下面3个包 gzip 模块需要 zlib 库 ( 下载: http://www.zlib.net/ ) zlib-1.2.8.tar.gz rewrite 模块需要 pcre 库 ( ...

  5. Mahout快速入门教程 分类: B10_计算机基础 2015-03-07 16:20 508人阅读 评论(0) 收藏

    Mahout 是一个很强大的数据挖掘工具,是一个分布式机器学习算法的集合,包括:被称为Taste的分布式协同过滤的实现.分类.聚类等.Mahout最大的优点就是基于hadoop实现,把很多以前运行于单 ...

  6. OC基础:内存(进阶):retain.copy.assign的实现原理 分类: ios学习 OC 2015-06-26 17:36 58人阅读 评论(0) 收藏

    遍历构造器的内存管理 a.遍历构造器方法内部使用autorelease释放对象 b.通过遍历构造器生成的对象.不用释放. 内存的管理总结 1.想占用某个对象的时候,要让它的引用计数器+1(retain ...

  7. Latex笔记(参考文献) 分类: LaTex 2014-11-08 17:41 239人阅读 评论(0) 收藏

    当你用LaTeX来写文档,在管理参考文献时,你可能会用到bibtex, 也许你会嫌麻烦,会选择用 \begin{thebibliography}{10} \bibitem xxxx \bibitem ...

  8. OC基础知识总结 分类: ios学习 OC 2015-06-26 17:58 58人阅读 评论(0) 收藏

    //OC: Objective-C, 面向对象的C语言 //OC与C的区别 //1.OC是C的超集, C语言的所有语法都可以在OC中使用 //2.OC是面向对象 //3.OC是一门运行时语言 //4. ...

  9. 解析ASP.NET Mvc开发之删除修改数据 分类: ASP.NET 2014-01-04 23:41 3203人阅读 评论(2) 收藏

    目录: 从明源动力到创新工场这一路走来 解析ASP.NET WebForm和Mvc开发的区别 解析ASP.NET 和Mvc开发之查询数据实例 解析ASP.NET Mvc开发之EF延迟加载 ------ ...

随机推荐

  1. 解决Win7 64bit + VS2013 使用opencv时出现提“应用程序无法正常启动(0xc000007b)”错误

    应用程序无法正常启动(0xc000007b) 记得以前也遇到过这样的问题:网上的解决方法就是修复什么 今天配置opencv2.4.8+vs2013的时候,发现用老版本的程序是不是都会出现这样的现象啊! ...

  2. 高端技巧:怎样使用#define定义变量

    Introduction 想在源文件里定义一个跟行号有关的变量,每次都手动输入实在是太慢了.本文介绍怎样使用宏定义来定义与行号有关的变量. 比如:我们想在源码的第10行定义A_10这种一个整形变量. ...

  3. 【Mongodb教程 第四课 】MongoDB 创建集合

    reateCollection() 方法 MongoDB db.createCollection(name, options) 是用来创建集合. 语法: 基本的 createCollection()  ...

  4. vs2013发布网站提示 “未能将文件**复制到**”

    原因:年久失修,原来在项目中的一些文件给删掉或移除了 解决方法:打开.csproj文件(记事本打开),把提示的文件给删除掉.

  5. Installation error: INSTALL_FAILED_CPU_ABI_INCOMPATIBLE

    解决方法: http://my.oschina.net/u/242764/blog/375909 当我们安装好Genymotion后,把Android运用部署到上面调试时,console 控制台会报错 ...

  6. 2016/3/10 PHP环境搭建 LAMP WAMP

    1. php成为服务器端的脚本语言.弱类型语言.$ JavaScript是弱类型语言.var Java强类型语言.byte short int long double float boolean 2. ...

  7. 2015/12/29 eclipse 设置要点 空间 项目 类 eclipse汉化

    开始使用eclipse,双击eclipse.exe文件,启动eclipse.程序会显示一个工作空间的对话框,工作空间用来存放你的项目文件,你可以使用程序默认的,点击确定即可,你也可以重新选择一个文件夹 ...

  8. Why was 80 Chosen as the Default HTTP Port and 443 as the Default HTTPS Port?

    https://www.howtogeek.com/233383/why-was-80-chosen-as-the-default-http-port-and-443-as-the-default-h ...

  9. jeesite快速开发平台

    兴致勃勃地下载下来准备好好研究一番,安装启动结果报错啦: java.lang.ClassNotFoundException: com.thinkgem.jeesite.modules.sys.list ...

  10. (转)Java中JSON字符串与java对象的互换实例详解

    在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JSON等,JSON作为一个轻量级的数据格式比xml效率要高,XML需要很多的标签,这无疑占据了网络流量,JSON在这方面则做的很好, ...