关于正则引擎ε-NFA -> NFA (仅通过边建立限制结束状态的两种尝试

来源:互联网 发布:什么学英文软件 编辑:程序博客网 时间:2024/06/04 01:03

对于自动机 一个状态是否为结束状态的判断


1一开始的方案


对于任何状态,设置初始状态为 true (这里的true为是否为结束状态),每当向后连接边的时候(即以状态为startstatus构造边时候)

构造非ε边的,把边的startstatus设置为false。构造ε边则不进行设置直接进行连接

这样做会产生一个错误

对于单个串联并联重复(紫色箭头表示最终去ε边后的NFA)  




这样做可行,因为当这三个图的去掉ε边最终指向的end均为true


然而当多个规则进行串联的时候,譬如对于a*b    单个重复规则与一个字符串联



对于上述图进行消去ε边得到的图  匹配a自环边的状态本应当为false 这里变成了true 也就是最终的正则规则变成了(a*|a*b)


如果仅仅从构造E边得时候进行限制 ,也就是与下一个规则连接的状态   与最终去ε边NFA边指向的状态并非一个的时候

这时候就会产生错误。

构造边的代码

Edge* NFA::make_edge(Status* status1, _MatchContent content, Status* status2,bool isAdd){if (isAdd&&content.left!=-1&&status1->IsFinal)                      //-1是是否为ε边的标志status1->IsFinal = false;                                           //将startstatus设置为falseauto edge = new Edge(status1, content, status2);if (isAdd)                                  {if (!_isStatusExist(status1))add_status(status1);if (!_isStatusExist(status2))add_status(status2);add_edge(edge);}return edge;                                       }


2把构造非ε边的限制去掉

也就是去掉if中content.left!=-1的判断 对于所有新建立的边,我们将其开始状态设置为false

Edge* NFA::make_edge(Status* status1, _MatchContent content, Status* status2,bool isAdd){if (isAdd&&status1->IsFinal)                      //-1是是否为ε边的标志status1->IsFinal = false;                                           //将startstatus设置为falseauto edge = new Edge(status1, content, status2);if (isAdd)                                  {if (!_isStatusExist(status1))add_status(status1);if (!_isStatusExist(status2))add_status(status2);add_edge(edge);}return edge;                                       }

对于单个并联来讲就已经产生错误,因为并联消去ε边指向的并非最终状态。见上文图

于是对于并联节点的构造

pair<Status*, Status*> NFA::gen_and(Node* node)             //处理and{And_Node* and_node = static_cast<And_Node*>(node);Status* s_start = nullptr;Status* s_end = nullptr;for (auto s : *(and_node->pool))   // 遍历这个  pool{auto tmp = gen_status(s);     //读出每个nodeif (!s_end)                 //如果没有结束{s_start=tmp.first;s_end = tmp.second;continue;}s_end->IsFinal = false;make_edge(s_end,tmp.first);  //就把他们连接起来s_end = tmp.second;}s_end->IsFinal= true;               //然后给最后一个为truereturn make_pair(s_start, s_end);}
添加一个特殊的节点设置,是的消去ε边指向节点为true。这两可以解决并联的内部问题。和a*b的问题

但实际上,对于多个并联之后的串联 或者单纯的a*又会造成问题

在消去ε边之后,并联之后的串联会同样有上述多出来结束状态问题,a*b解决,a*没有结束状态

因此,单单通过建立边确立正确结束状态是十分困难的

3应当正确的方法

vzch文档上写:如果存在一个有效状态可以仅通过E边到达结束状态,那么这个状态应该被标记为结束状态


一种解决方法是:在构造nfa的过程中,不考虑是否为结束状态。 在构造完成后,将整体的结束状态finish设置为true,(其他均为false)

对于结束状态,寻找能仅通过ε边到达结束状态的状态的反向闭包(与消去ε边方式寻找闭包的方向相反,不知道怎么叫),将这些状态设置为结束状态。


cknightx本人: 在构造nfa的过程中,不考虑是否为结束状态。 在构造完成后,将整体的结束状态finish设置为true,(其他均为false)


在消去ε边过程中,对每个有效状态寻找ε闭包,如果闭包中有结束状态,则将其设置为结束状态

部分图片参考自vczh《构造可配置词法分析器》和《正则表达式》

文章源代码参考cknightx 

原创粉丝点击