本程序实现了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. Fp关联规则算法计算置信度及MapReduce实现思路

    说明:參考Mahout FP算法相关相关源代码. 算法project能够在FP关联规则计算置信度下载:(仅仅是单机版的实现,并没有MapReduce的代码) 使用FP关联规则算法计算置信度基于以下的思 ...

  2. HDU 1824 Let&#39;s go home (2-SAT判定)

    Let's go home Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  3. Qt实现一个简单的TextEditor

    使用QT实现简单的TextEditor: 首先在窗口添加部件TextEditor,并设置中文字符 MainWindow::MainWindow(QWidget *parent) : QMainWind ...

  4. Ant中批量调用TestNG的XML文件,并调用TestNgXlst生成漂亮的html测试报告

    from:http://blog.csdn.net/bwgang/article/details/7865184 1.在Ant中设置如下: <target name="run_test ...

  5. Boost中的Timer的使用——计算时间流逝

    使用Boost中的Timer库计算程序的运行时间 程序开发人员都会面临一个共同的问题,即写出高质量的代码完毕特定的功能.评价代码质量的一个重要标准就是算法的运行效率,也就是算法的运行时间.为了可靠的提 ...

  6. Vue框架之组件系统

    1,Vue组件系统之全局组件 1.1Vue全局组件的在实例化调用Vue的模板中导入组件的名称 <!DOCTYPE html> <html lang="zh-cn" ...

  7. redis与spring整合·

    单机版: 配置spring配置文件applicationContext.xml <?xml version="1.0" encoding="UTF-8"? ...

  8. eclipse 重启/打开内置浏览器

    重启 Eclipse 重启选项允许用户重启 Eclipse. 我们可以通过点击 File 菜单选择 Restart 菜单项来重启 Eclipse. Eclipse 内置浏览器 Web 浏览器 Ecli ...

  9. 关于warning: Clock skew detected. Your build may be incomplete. 的解决方法【转】

    本文转载自:http://blog.csdn.net/jeesenzhang/article/details/40300127 今天发现电脑的系统时间不正确,因此将时钟进行了修改,回头编译Linux ...

  10. iOS 7 present/dismiss转场动画

    前言 iOS 7以后提供了自定义转场动画的功能,我们可以通过遵守协议完成自定义转场动画.本篇文章讲解如何实现自定义present.dismiss自定义动画. 效果图 本篇文章实现的动画切换效果图如下: ...