编译原理实验:NFA转化为DFA

一:实验目的

将NFA转化为DFA

二:实验内容

编程序实现NFA转化为DFA。

三:实验过程

1.实验步骤

(1)源代码

#include <iostream>
#include <fstream>
#include <queue>
#include <cstring>
#include <map>

using namespace std;

int i = 0;

struct Node {
	//DFA节点
	int s;
	bool flag;
	//标记一个DFA节点集合是否包含NFA结束态,即表示DFA中是否是一个结束态
	Node(int ss, bool f) {
		s = ss;
		flag = f;
	}
};

struct Edge {
	//DFA边
	int from, to;
	char c;
	Edge(int x, int y, char z) {
		from = x;
		to = y;
		c = z;
	}
};

const int MAX = 101;
//字符数
int zf;
//字符集
char zfj[MAX];
//状态数,0开始
int zt;
//起始和结束态
int Begin, End;
//存边
char G[MAX][MAX]; 
//标记NFA状态是否被访问,求闭包用到
int vis[MAX];
//DFA节点集
vector<Node> V;
//DFA边集
vector<Edge> edge;
//求过的闭包保存以后用
int eps_clos[MAX];
queue<int> eq;

//求eps闭包
int E_closure(int x) {
	if (eps_clos[x] != -1) {
		return eps_clos[x];
	}
	queue<int> q;
	memset(vis, 0, sizeof(vis));
	int S = 0;
	S = S | (1 << x);
	q.push(x);
	while (!q.empty()) {
		//BFS求闭包
		int v = q.front();
		q.pop();
		for (int w = 0; w < zt; w++) {
			if (G[v][w] == '#'&&!vis[w]) {
				vis[w] = 1;
				S |= (1 << w);
				q.push(w);
			}
		}
	}
	eps_clos[x] = S;
	return S;
}

int set_edge(int s, char c) {
	//求一个状态集吃字符到达的状态集
	int i, j;
	int S = 0;
	for (i = 0; i < zt; i++) {
		if ((s >> i) & 1) {
			for (j = 0; j < zt; j++) {
				if (G[i][j] == c)
					S |= E_closure(j);
			}
		}
	}
	return S;
}

bool check(int s) {
	//检查DFA节点集是否出现过
	for (int i = 0; i < V.size(); i++) {
		if (V[i].s == s) return true;
	}
	return false;
}

bool is_end(int s) {
	//状态集是否包含终结点
	return (s >> End) & 1;
}

void ZJGZ() {
	//子集构造算法
	int i;
	queue<int> work;
	work.push(E_closure(0));
	//加入DFA节点集
	V.push_back(Node(E_closure(0), is_end(E_closure(0))));
	while (!work.empty()) {
		int v = work.front();
		work.pop();
		for (i = 0; i < zf; i++) {
			//遍历字符集
			//生成NFA吃完该字符所能到达的所有状态
			int s = set_edge(v, zfj[i]);
			if (s != 0) {
				edge.push_back(Edge(v, s, zfj[i]));
				if (!check(s)) {
					V.push_back(Node(s, is_end(s)));
					work.push(s);
				}
			}
		}
	}
}

void out_put(int i, int s, bool f) {
	printf("DFA状态:q%d 包含的NFA中的状态为:", i);
	for (int j = 0; j < zt; j++)
		if ((s >> j) & 1) printf("s%d ", j);
	if (f) printf("包含结束态\n");
	else printf("不包含结束态\n");
}

int main()
{
	memset(eps_clos, -1, sizeof(eps_clos));
	ifstream in("nfa.txt");
	ofstream out("dfa.txt");
	in >> zf;
	for (i = 0; i < zf; i++) {
		in >> zfj[i];
	}
	in >> zt;
	in >> Begin >> End;
	//NFA边数
	int n;
	in >> n;
	int x, y;
	char c;
	for (i = 0; i < n; i++) {
		in >> x >> c >> y;
		G[x][y] = c;
	}
	in.close();
	ZJGZ();

	out << zf << endl;
	for (i = 0; i < zf; i++) {
		out << zfj[i] << ' ';
	}
	out << endl;
	//DFA状态集映射到从0开始的状态标号
	map<int, int> mp;
	out << V.size() << endl;
	for (i = 0; i < V.size(); i++) {
		out << i << ' ' << V[i].flag << endl;
		mp[V[i].s] = i;
	}
	out << edge.size() << endl;
	for (i = 0; i < V.size(); i++)
		out_put(i, V[i].s, V[i].flag);
	for (i = 0; i < edge.size(); i++) {
		out << mp[edge[i].from] << ' ' << mp[edge[i].to] << ' ' << edge[i].c << endl;
		printf("状态q%d -> 状态q%d,吃入字符%c\n", mp[edge[i].from], mp[edge[i].to], edge[i].c);
	}
	out.close();
}

2.实验结果记录

(1)输入文本

3
a b c
10
0
9
12
0 a 1
1 # 2
2 # 3
2 # 9
3 # 4
3 # 6
4 b 5
6 c 7
5 # 8
7 # 8
8 # 9
8 # 3

(2)输出文本

3
a b c 
4
0 0
1 1
2 1
3 1
7
0 1 a
1 2 b
1 3 c
2 2 b
2 3 c
3 2 b
3 3 c

(3)运行结果

image.png

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
厦门理工学院编译原理实验二是指在学习编译原理课程中进行的实验,具体涉及到了NFA(非确定有限自动机) DFA(确定有限自动机)的相关内容。 NFADFA都属于有限状态自动机,用于描述形式语言的模型。NFA相对于DFA而言具有更高的表达能力,因为它在某些状态下可以有多个后继状态。而DFA则是在NFA的基础上进行了优化,通过消除不确定性,使得状态移更加明确和确定。 实验二的主要目的是通过实践操作,加深对NFADFA的理解,并且掌握NFADFA的方法。在实验中,我们会先根据给定的正则表达式或自动机图设计一个NFA,然后通过确定状态、换表和终态等步骤,将NFA换为DFA。这个换过程需要考虑NFA中的ε-移以及多个状态同时移的情况,从而得到一个等价的DFA实验的步骤主要包括:通过给定的正则表达式构建NFA、确定NFA的状态集、计算每个状态的ε-闭包、根据输入符号和ε-闭包进行状态换,并得到新的状态集和换表,最后确定DFA的终态。通过这些步骤,我们可以将一个NFA换为一个等价的DFA,实现了从非确定性到确定性的变。 在实验过程中,我们需要注意各个状态的换规则以及ε-闭包的计算和使用,这些是实验中较为重要的部分。通过实际操作和计算,我们可以更好地理解NFADFA之间的关系,并且加深对编译原理中有限状态自动机的理解与应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北溪入江流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值