本程序实现了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. Android拍照、摄像方向旋转的问题 代码具体解释

    近期做了个拍照.摄像的应用.遇到了拍照.摄像的图像相对于现实.翻转了90度.原因:相机这个硬件的角度是横屏的角度,所以会出现都是横屏的. 1.照相.摄影预览图像的正确角度显 示: public sta ...

  2. pycharm快捷键和一些常用的设置

    http://blog.csdn.net/pipisorry/article/details/39909057 在PyCharm /opt/pycharm-3.4.1/help目录下可以找到Refer ...

  3. Spring学习笔记——Spring中lazy-init与abstract具体解释

    Spring的懒载入的作用是为了避免无谓的性能开销,就是当真正须要数据的时候才去运行数据的载入操作.不只在Spring中.我们在实际的编码过程中也应该借鉴这种思想,来提高我们程序的效率. 首先我们看一 ...

  4. Android:内存控制及OOM处理

      1. OOM(内存溢出)和Memory Leak(内存泄露)有什么关系? OOM可能是因为Memory Leak,也可能是你的应用本身就比较耗内存(比如图片浏览型的).所以,出现OOM不一定是Me ...

  5. web 开发之js---ajax 异步处理

    本文介绍了如何创建能够适应不同浏览器的XMLHttpRequest实例,建立和发送请求,并响应服务器.您将开始接触最基本和基础性的有关Ajax的全部对象和编程方法:XMLHttpRequest对象.该 ...

  6. 辛星浅析一次ajax的实现过程

    说到ajax,那绝对是一个老生常谈的话题,近些年ajax技术的使用颇为盛行. 以下我们就以jQuery为例来从一个真实的项目中看一下ajax的实例. 首先是前端页面,这个页面我们使用的是bootstr ...

  7. scala wordcount kmeans

    scala wordcount   kmeans k-means算法的输入对象是d维向量空间的一些点,对一个d维向量的点集进行聚类. k-means聚类算法会将集合D划分成k个聚簇.

  8. 什么是 jQuery EasyUI

    jQuery EasyUI 是一个基于 jQuery 的框架,集成了各种用户界面插件. jQuery EasyUI 框架提供了创建网页所需的一切,帮助您轻松建立站点. easyui 是一个基于 jQu ...

  9. grails Domian对象转JSON去class以及自己定义字段的最佳方式

    grails:2.4.x IDE:Intellij IDEA 13.x grails的Domain对象之间假设存在环形引用.直接使用as JSON仅仅会输出关联对象的id.而且假设使用deep也会报错 ...

  10. HTTP要点概述:四,HTTP方法

    使用HTTP协议的时候,客户端可以通过HTTP方法告知服务器自己请求的意图. 看了这篇文章以后,谁再说HTTP方法只有GET和POST,你的眼睛是用来吃饭的嘛! 一,GET:获取资源 GET用来请求访 ...