前言:继上次的《自己写一个简单的C++单词扫描程序》之后,编译原理实验课要求做一个Regural Express 转NFA
图,这个在算法上没什么难度,在《编译原理与实践》书上介绍了Thompson的转换算法,该书对Thompson
算法做了详细的文字描叙,如想对该算法更深的了解参照:机械工业出版社,《编译原理与实践》译本P.45。
正文:
一、问题分析:
要求输入一个正则表达式,将其转换为NFA,并输出结果。转化的方法有多种,应用Thompson结
一、问题分析:
要求输入一个正则表达式,将其转换为NFA,并输出结果。转化的方法有多种,应用Thompson结
构的转换方法最为简单。Thompson结构:它利用epsilon—转换将正则表达式的机器片段“粘贴在一起”
以构成整个表达式相应的机器。它依照了正则表达式定义的结构:为每个基本正则表达式展示一个NFA,
接着通过连接子的运算将每个正则表达式运算,连接起来。正则表达式的运算有四种:连接,选择,闭包
,正闭包(本程序不支持该运算)。
二、系统设计:
总体设计:为了提高程序的可移植性,将其分为界面类,NFA图类,NFA_Node(NFA图结点)类,Converte
总体设计:为了提高程序的可移植性,将其分为界面类,NFA图类,NFA_Node(NFA图结点)类,Converte
r(转换器)类以及一个Transition(状态传输)结构体。
程序设计:选用C++Builder6.0(BCB6)作为开发工具。转换的运算类似普通的四则运算,Union的运算符
为“|”,Closure的运算符为“*”,而在表达式中的Connect连接运算表示为两个字符的连接 eg:ab,
则需要引入一个符号来区分是否为连接运算,在此引入“&”为连接符号,即上例变为a&b,为此便于编程
。三种运算的优先级从高到低依次为:*、&、| ,而运算的方法完全按照Thompson结构的算法,所以在此
不再螯述。参照普通的四则运算,在正则表达式的转换运算中,引入两个栈,一个为运算符栈,另一个为
运算数栈,而这里的运算数为局部的NFA图。栈的设计应用类模板,减少了没必要的重复代码,提高设计
的抽象程度。
三、部分程序源码:(为了省出切换输入法的时间,主要算法的注释用了英文描述,鉴于本人英文较差,
主要是写给自己看的,如果您看不懂注释,请见谅。)/*以下为界面的事件触发部分*//*对输入字符串做预处理,插入“&”和“=”*/
AnsiString __fastcall TForm1::preTreatStr(AnsiString InRegEx)
{
int i = 1;
char ch,prech;
InRegEx = InRegEx + '=';
prech = InRegEx[i++];
ch = InRegEx[i];while(InRegEx[i]!='=')
{if((isalpha(prech)&&isalpha(ch)) || (isalpha(prech)&&ch=='(') ||(prech==')'&&isalpha(ch)) || (prech=='*'&&isalpha(ch)) || (prech=='*'&&ch=='('))
{
InRegEx.Insert('&',i);
}
prech = InRegEx[i++];
ch = InRegEx[i];
}return InRegEx;
}/*遍历出NFA图*/
void __fastcall TForm1::Display(NFA Grap)
{
Memo1->Lines->Add("转换为NFA的结果为:");
Grap.Ncurrent = Grap.Nstart; //set current = start and begin scan
Memo1->Lines->Add(IntToStr(Grap.Ncurrent->stateID)+"开始状态");
while(Grap.Ncurrent->Nnext!=NULL)
{
if(Grap.Ncurrent->Thead->Tnext!=NULL) //while have transmit
{
Grap.Ncurrent->Tcurrent = Grap.Ncurrent->Thead->Tnext;
while(Grap.Ncurrent->Tcurrent->Tnext!=NULL)
{
if(Grap.Ncurrent->Tcurrent->incept!='@')
{Memo1->Lines->Add(IntToStr(Grap.Ncurrent->stateID)+"--->"+IntToStr(Grap.Ncurrent->Tcurrent->State)+"接收到:"+Grap.Ncurrent->Tcurrent->incept);
}
else
{Memo1->Lines->Add(IntToStr(Grap.Ncurrent->stateID)+"--->"+IntToStr(Grap.Ncurrent->Tcurrent->State)+"接收到:epsilon");
}
Grap.Ncurrent->Tcurrent = Grap.Ncurrent->Tcurrent->Tnext;
}
if(Grap.Ncurr