给定正规式转化为等价的NFA代码实现

这篇博客详细介绍了如何将给定的正规式转化为等价的非确定有限自动机(NFA)。通过定义`state`和`unit`结构体,博主阐述了算法的核心思路,包括处理括号、或运算、星号运算以及普通字符的情况。同时,提供了源程序及测试结果,展示了一个具体的正规式转换实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

词法分析程序题

题目

给定正规式,转化为等价的NFA

算法

结构体介绍

state结构体

struct state//定义状态结构体

{

         string input;//输入符号集合

         vector<state*> *next;//输出状态集合,与输入符号集合一一对应

};

input[i]和(*next)[i]一一对应,若next.size()为0则表示到了终点

unit结构体

struct unit//正规文法单元,记录当前单元的开始状态地址和结束状态地址,最后不断壮大的单元即为所需的NFA

{

         char id;//0表示最小单元,()|*表示辅助字母,1表示曾通过()将状态绑定在一起以便更好区分(ab)*和ab*的处理

         state *begin;//开始状态地址

         state *end;//结束状态地址

};

该结构体采用正规文法的思想,使用正规文法到正规式转化的逆思想,将正规式不断单元化,最后再合并。

算法介绍

遍历正规式,对正规式每一个输入进行相应处理。

输入’(‘:构造unit单元,id设为’(‘,起始状态和终止状态都为NULL,压入unit栈

输入’|’: 构造unit单元,id设为’|‘,起始状态和终止状态都为NULL,压入unit栈

输入’)’:判断’()’内是否含有’|’,若有,则分’|’右边和左边,右边按出栈顺序依次联结成一个unit单元,左边也按出栈顺序依次联结成一个unit单元,然后构造空串,如下图

图1



若无’|’,则直接按出栈顺序依次联结’()’内单元

输入’*’:判断栈顶单元标识,若id==’1’,表示该单元内内容通过’()’进行过绑定,直接通过添加空串状态指向begin状态和begin状态指向空串,再次联结成一个新单元

若id==’0’,表示该单元内内容未通过’()’进行过绑定,直接通过添加空串状态指向end状态和end状态指向空串

输入其他字符:默认为输入字符,判断该字符是否为首字符或右边为’(‘或’|’,若是则创建新状态并构建新单元压入栈,否则创建新状态联结进栈顶单元

输入完毕:联结栈内所有单元,输出该单元

源程序

#include
#include
#include"d_stack.h"//栈类头文件
#include
using namespace std;
struct state//定义状态结构体
{
	string input;//输入符号集合
	vector *next;//输出状态集合,与输入符号集合一一对应
};
struct unit//正规文法单元,记录当前单元的开始状态地址和结束状态地址,最后不断壮大的单元即为所需的NFA
{
	char id;//0表示最小单元,()|*表示辅助字母,1表示曾通过()将状态绑定在一起以便更好区分(ab)*和ab*的处理
	state* begin;//开始状态地址
	state* end;//结束状态地址
};
class NFA
{
public:
	unit* REtoNFA(string RE)//regular expression to NFA
	{
		miniStack *s=new miniStack();
		for(int i=0;iid='(';//标识为'(',压入栈
					u1->begin=NULL;
					u1->end=NULL;
					s->push(u1);
					break;
				}
			case')':
				{
					unit* u1;
					unit* u2;
					unit* u3;
					u1=NULL;
					u3=NULL;
					bool exist=false;
					while(s->top()->id!='(')//联结'|"右边的单元
					{
						if(s->top()->id=='0'&&u1==NULL||s->top()->id=='1'&&u1==NULL)//当u1未初始化时
						{
							u1
### 编译原理中的正规转换NFA和DFA #### 将正规转换NFA的方编译原理中,通常采用三步走的方处理正规转换问题。首先,将给定正则表达(即正规转化为非确定有限状态自动机(NFA),这是因为相对于直接构建DFA而言更为简单直观[^3]。 对于具体的转化过程,存在一些基本规则用于指导从简单的模片段创建对应的NFA组件: - 对于单个字符`a`,可以建立一个只有两个节点的状态转移图,其中一条由初始态指向接受态的边标记着该字符; - 并运算(`|`)对应两条分别通往不同子路径的选择分支; - 连接操作意味着顺序执行多个模部分所代表的动作序列; - 星闭包(*)表示零次或多次重复前导元素/组的内容。 这些原则能够帮助理解更复杂的结构是如何逐步组装起来形成完整的NFA模型的[^2]。 ```python class State: def __init__(self, is_accept=False): self.transitions = {} self.is_accept = is_accept def re_to_nfa(pattern): stack = [] for char in pattern: if char == '|': # Or operation b, a = stack.pop(), stack.pop() new_start = State() new_end = State(True) new_start.transitions[''] = {a, b} a.transitions[''].add(new_end) b.transitions[''].add(new_end) stack.append((new_start, new_end)) elif char == '*': # Kleene star state = stack.pop()[0] new_start = State() new_end = State(True) new_start.transitions[''] = {state, new_end} state.transitions[''].add(new_end) stack.append((new_start, new_end)) else: # Single character start_state = State() end_state = State(True) start_state.transitions[char] = {end_state} stack.append((start_state, end_state)) return stack[-1][0] pattern = "ab*c" nfa_start_state = re_to_nfa(pattern) ``` 这段Python代码展示了如何基于上述提到的原则来实现一个简易版的正则表达NFA的功能函数 `re_to_nfa()` 。此函数接收字符串形正则表达作为参数,并返回其相应的NFA起始状态对象。 #### NFA到DFA的转换 一旦获得了针对特定正规NFA之后,则可以通过子集构造算将其进一步转变为等价的DFA。这一过程中涉及到的主要概念包括ε-closure(空移封闭集合)以及move(T,a)(当读入符号'a'时T集中各状态所能到达的新状态集合)[^4]。 以下是简化版本的伪码展示如何利用这两个辅助函数完成整个转变流程: ```python from collections import deque def epsilon_closure(states_set, nfa_states_dict): closure = set(states_set) queue = deque(closure.copy()) while queue: current_state_id = queue.popleft() if '' not in nfa_states_dict[current_state_id].transitions: continue next_states_ids = nfa_states_dict[current_state_id].transitions[''] for s in next_states_ids.difference(closure): closure.add(s) queue.append(s) return frozenset(closure) def move(states_frozenset, symbol, nfa_states_dict): result = set() for sid in states_frozenset: if symbol in nfa_states_dict[sid].transitions: result.update(nfa_states_dict[sid].transitions[symbol]) return frozenset(result) def nfa_to_dfa(nfa_initial_state, alphabet, nfa_states_dict): dfa_states = {} # Maps frozen sets of NFA states to DFA states. transitions = {} unprocessed_sets = [epsilon_closure({nfa_initial_state}, nfa_states_dict)] processed_sets = [] accept_states = set() while unprocessed_sets: current_set = unprocessed_sets.pop() processed_sets.append(current_set) if any(state.id in accept_states for state in current_set): accept_states.add(id(dfa_states[current_set])) for letter in alphabet: reachable_by_letter = move(current_set, letter, nfa_states_dict) ec_reachable_by_letter = epsilon_closure(reachable_by_letter, nfa_states_dict) if ec_reachable_by_letter and (ec_reachable_by_letter not in processed_sets + unprocessed_sets): unprocessed_sets.insert(0, ec_reachable_by_letter) if current_set in dfa_states.keys(): from_state_id = id(dfa_states[current_set]) else: from_state_id = len(dfa_states)+1 dfa_states[current_set] = f"D{len(dfa_states)}" if ec_reachable_by_letter in dfa_states.keys(): to_state_id = id(dfa_states[ec_reachable_by_letter]) else: to_state_id = None transitions[(from_state_id, letter)] = to_state_id initial_state = list(dfa_states.values())[list(dfa_states).index(frozenset([nfa_initial_state]))] return {'states':dfa_states,'initial_state':initial_state,'accepting_states':accept_states,'transition_function':transitions} alphabet = ['a', 'b', 'c'] # Assuming we have already defined the necessary dictionaries mapping between IDs and actual States objects... converted_dfa_info = nfa_to_dfa(initial_state=nfa_start_state, alphabet=alphabet, nfa_states_dict=all_nfa_states) ``` 这里给出了一套较为详细的Python风格伪代码用来说明怎样把之前得到的那个NFA实例化成最终的目标——DFA。注意这里的输入还包括了一个字母表(alphabet),它定义了合输入字符范围;另外还需要提供所有参与计算的NFA状态及其关联信息组成的字典(all_nfa_states)以便查询使用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值