编译原理之正则表达式转NFA

本文介绍了一个编译原理实验项目,实现了将正则表达式转换为NFA(非确定有限状态自动机)的算法。文章详细讲解了Thompson算法,并展示了C++Builder6.0实现的程序设计,包括界面类、NFA图类、转换器类等。程序通过预处理输入字符串、建立NFA节点和状态转移来实现转换,最后以文字形式输出NFA图。
摘要由CSDN通过智能技术生成
前言:继上次的《自己写一个简单的C++单词扫描程序》之后,编译原理实验课要求做一个Regural Express 转NFA
图,这个在算法上没什么难度,在《编译原理与实践》书上介绍了Thompson的转换算法,该书对Thompson
算法做了详细的文字描叙,如想对该算法更深的了解参照:机械工业出版社,《编译原理与实践》译本P.45。
正文:
一、问题分析:
 要求输入一个正则表达式,将其转换为NFA,并输出结果。转化的方法有多种,应用Thompson结
构的转换方法最为简单。Thompson结构:它利用epsilon—转换将正则表达式的机器片段“粘贴在一起”
以构成整个表达式相应的机器。它依照了正则表达式定义的结构:为每个基本正则表达式展示一个NFA,
接着通过连接子的运算将每个正则表达式运算,连接起来。正则表达式的运算有四种:连接,选择,闭包
,正闭包(本程序不支持该运算)。
二、系统设计:
总体设计:为了提高程序的可移植性,将其分为界面类,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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
编译原理中的正则表达式转换NFA(非确定有限状态自动机)是一个重要的步骤。在这个过程中,首先我们需要理解正则表达式的语法规则和语义含义。 正则表达式是一种用于描述字符序列的模式的表示方法。它由一系列字符和操作符构成,这些操作符可以表示字符的集合、重复等。例如,字符"a"表示一个字符"a",字符集[a-z]表示从"a"到"z"的任意字符。 转换正则表达式NFA的方法是通过递归的方式对正则表达式进行解析和转换。具体步骤如下: 1. 将正则表达式的字符和操作符进行分组。 2. 对分组后的字符和操作符进行处理,生成对应的NFA片段。 3. 根据操作符的优先级,将NFA片段进行合并和连接。 4. 最后得到一个完整的NFA。 在处理正则表达式的过程中,需要考虑到操作符的优先级,例如,使用括号来指定操作符的优先级。同时,还需考虑到正则表达式中可能存在的特殊字符,比如*、+和|等。 通过正则表达式转换NFA,可以实现对字符串的匹配和识别。NFA可以支持更加复杂的模式匹配需求,并且具有较高的灵活性和效率。 总的来说,将正则表达式转换NFA编译原理中的一个重要步骤。它需要理解正则表达式的语法和语义,并通过递归和合并方式生成对应的NFA片段。通过这一过程,可以实现对字符串的高效匹配和识别。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值