【编译原理】【实验】利用子集法构造DFA

一、实验目的

掌握将非确定有限自动机确定化的方法和过程。

二、实验要求、内容

1.输入一个NFA,输出一个接受同一正规集的DFA;
2.采用任意语言,实现该算法;
3编制测试程序;
4.调试程序。

三、实验设备

计算机、Windows 7操作系统、Eclipse Luna程序集成环境、JDK 12。

四、实验原理(或程序框图)及步骤

对给定的NFA状态,程序在利用子集构造法将其转换为对应的DFA状态时,首先需要获取NFA状态转换图中的对应信息,包括字母表、状态集以及初始状态。为方便程序处理,可将每个状态实例化为一个类State,其类图如图4-1所示,函数详细定义及功能见附录。状态转换图中,某状态经过字母表中某字符串可达某状态集,构成了当前状态、某个字符串和某个状态集三者的映射关系,则可对特定状态用字符串与状态集间的映射关系准确描述三者的关系,即构建键值对<字符串,可达状态集>(变量path)描述特定状态。此外,程序中还涉及某状态处理时的标记与否(变量flag)和状态名(变量name)。

图4-1 状态类类图
如果将初始状态规定为状态输入的状态0(记为S0),则只需前二者。获取相应信息后,首先对S0构造其ε闭包集合A作为DFA的开始状态。随后对字母表中的每一个字母,依次在原NFA状态集中对其做A中包含所有状态的闭包运算,获得A在经过该字母的转换后得到的下一状态集。对获取的每一个状态,如果其不在状态集合中,则将其作为一个新状态。对于获取的每一个新状态,重复在A状态上执行的动作,直到没有任何状态产生为止。在执行闭包运算时,对集合中的每一个状态,将该状态能经过当前字符串转换得到的所有状态加入当前集合的闭包集中。主程序流程图和闭包算法流程图流程图如图4-2所示。
图4-2 主程序流程图(左)和闭包算法流程图(右)

五、程序源代码

计算DFA的while循环如下所示,此时已经完成了所有状态信息的输入、初始化并且计算出了DFA的首个状态加入transState列表中,此列表即为最终所求的DFA的状态集,其中每个状态的状态名均此状态包含的NFA状态集。tState被用于标记当前状态,是自定义的状态类State的实例,其中包含状态姓名、是否被标记以及此状态和所有字母上的转换关系,其类图见图4-1,详细定义见附录。flag为其是否被标记的布尔类型变量,transTable中包含所有找到的构造DFA的状态集合(原NFA的子集),在循环中通过path标记当前找到的可以构造DFA的状态。包含文件处理和输入输出的完整主程序以及类State的定义见附录。

while (!flag) 
{
   
	tState.markFlag(true);
	List<String> state = new LinkedList<String>();
	for (int i = 0; i < transTable.size(); i++) 
	{
   
		state = transTable.get(i);
		if (state.toString().equals(tState.name()))		break;
	}
	// 找到当前状态的原始转换列表
	String[] path = new String[state.size()];
	k = 0;	
	for (String m : state)	path[k++] = m;
	// 取到当前状态
	for (String s : sigma) 
	{
   
		// 按字母表填转换表
		if (s.equals("$"))		break;
		String[] move = new String[state.size()];
		move = move(states, totalStates, path, s);
		// 第一次move
		// 如果这个状态得到这个字符串,执行e-closure运算
		if (!move[0].equals("#"))		
			 move = move(states, totalStates, move, "$");
		stateList = new LinkedList<>();
		for (String q : move)	stateList.add(q);
		tState.put(s, stateList);// 将得到的状态填入对应的状态
		System.out.println(tState);
		if (!transTable.contains(stateList) && !stateList.contains("#")) 
		{
   
			transTable.add(stateList);//扩充状态转换列表
			State sa = new State(stateList.toString(), sigma,	totalSignals);
			sa.put("$", "#");
			transState.add(sa);	
		}
		// 找下一个状态,改变对应flag的值用以控制循环
		for (State s : transState) 
		{
   
			if (!s.isFlag()) 
			{
   
				tState = s;flag = tState.isFlag();
				break;
			} else	flag = true;	
		}
	}	
}

计算闭包的函数如下所示,相关描述见注释。

	/**算法描述:(1)将T中所有状态压入栈stack; 将closure (T) 初始化为T; 
	 * (2)若stack不空 将栈顶元素t弹出栈; 
	 * (3)对每个从t到u有一条标记为 ε的边的状态u:
 如果 u 不在ε-closure ( T ) do 将u 添加到closure ( T );
	 * (4)将u压入栈stack中 closure算法
	 * @param states 状态列表
	 * @param totalStates,所有状态数
	 * @param location,待转换状态在原始状态列表中的位置
	 * @param str,将要执行对该字符串的闭包运算
	 * @return 转换后的字符串集合 */
public static String[] closure(State[] states, int totalStates,			int location, String str)
{
   
	LinkedList<String> list = (LinkedList<String>) states[location].get(str);
	LinkedList<String> current = new LinkedList<String>();
	Stack<String> stack = new Stack<>();
	if (list.contains("#"))
	{
   
		if (str.equals("$")) 	current.add(states[location].name());
	}  
	else 
	{
   
		stack.push(states[location].name());
		for (String i : list)	stack.push(i);
		while 
  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值