实验一利用子集法构造DFA
DFA的编程实现(含源代码、实验报告)剖析

实验一(一)程序设计语言及其编译器实现概览(2小时)实验目的:学习一门简单的程序设计语言的定义及其编译器实现实验任务:针对一门简单的程序设计语言,阅读其定义文档,初步了解其编译器的源代码。
实验内容:(1)选择一门语言:TINY或其它语言也可(需自备其编译器的源代码)。
(2)阅读其定义文档,了解语言定义的方法,包括:词法、语法、语义、运行时环境、目标机器、目标语言等内容。
(3)了解其编译器源代码。
•对TINY语言编译器,其源代码由多个文件组成,请弄清楚每个文件的作用是什么。
详情请见《编译原理及实践》第 1.7节。
请做一个C++工程文件(Win32 Console Application, tiny.dsp),把它们组织起来,然后编译成可执行文件(tiny.exe),即为TINY 语言编译器。
然后用它编译TINY语言示例源代码(sample.tny)。
看看编译生成的目标文件(sample.tm)是怎样的。
要运行目标程序,还需要一个虚拟机,名为TM机。
TM 机是以软件形式存在的,其源代码为tm.c,需要编译生成可执行文件tm.exe。
然后将目标程序作为TM机的输入运行TM机即可得到所期待的结果。
要求读懂main.c、globals.h、util.h、scan.h和util.c、scan.c等文件,三人一组进行讨论,给每一行加上注释,总结你们各自对程序的理解和阅读程序的收获,每组提交1份加了注释的文件和心得。
有能力的同学可加上tm.c。
实验一(二)DFA的编程实现(2小时)实验目的:通过本次实验,加深对DFA及其识别的语言的理解,学习对一般的DFA的表达方法与编程实现方法。
实验任务:编写一个C语言程序,模拟实现DFA识别字符串的过程。
实验内容:(1)DFA的输入;(2)DFA的存储与读写;(3)DFA的正确性检查;(4)DFA 的语言集列表显示;(5)DFA的规则字符串判定;内容说明:(1)DFA的输入:分别输入DFA的“字符集”、“状态集”、“开始状态”、“接受状态集”、“状态转换表”等内容,并保存在设定的变量中。
五元组构造dfa代码

五元组构造dfa代码在计算机科学中,确定有限状态自动机(Deterministic Finite Automaton,简称DFA)是一种用来识别和处理特定类型文本模式的机器模型。
DFA是一种能够判断给定字符串是否属于某种特定语言的模型,也是计算机科学中非常重要的概念之一。
在DFA的构造过程中,五元组构造方式是最为常用的。
本文将详细介绍五元组构造DFA的过程以及相关的代码实现。
一、什么是五元组构造法五元组法是指将DFA用五个元素(五元组)来描述的构造方法,五元组法常用于表示DFA,用来表达DFA的最基本的信息。
五元组法包含了五个元素:Q、Σ、δ、q0、F。
下面将详细介绍这五个元素的含义:1. Q :Q表示一组有限的状态集合。
状态集合是指某个状态转移中出现的所有状态所组成的集合。
2. Σ :Σ表示字母表,也就是说一个有限个字符的集合。
3. δ :δ表示状态转移函数,它是从Q×Σ到Q的映射函数。
也就是说,对于DFA的一个状态q和一个输入符号a,它总有一个确定的下一状态p=δ(q,a)。
4. q0 :q0表示DFA的初始状态,它必须属于状态集合Q。
5. F :F表示一组终结符集合,是状态集合Q的子集。
∀q∈F,则状态q是DFA的终态。
五元组构造法是一种从给定的正则表达式,构造DFA模型的方法。
根据正则表达式可以得到NFA(非确定有限状态自动机),然后通过子集构造法,将NFA转化为DFA。
DFA的构造过程能够帮助我们更好地理解DFA的工作原理,并进一步优化DFA的性能,提高程序的运行效率和速度。
二、代码实现在实现五元组构造法时,我们需要编写相应的代码实现。
下面是基于Python语言的五元组构造DFA代码实现:``` python class DFA: def __init__(self, Q, Sigma, delta, q0, F): self.Q = Qself.Sigma = Sigma self.delta = delta self.q0 = q0 self.F = Fdef transition_function(self, state,input_symbol): if input_symbol inself.Sigma: returnself.delta[state][input_symbol] else: raise ValueError("Invalid Input Symbol")def simulate(self, input_string):current_state = self.q0 for symbol ininput_string: current_state =self.transition_function(current_state, symbol)return current_state in self.Fdef from_nfa(nfa): states = set()alphabet = set(nfa.alphabet) delta = {}start_state = frozenset([nfa.start]) end_states= set()def dfs(state): if state in states: return states.add(state) ifnfa.start in state: start_state =frozenset(state) if nfa.accepts(state): end_states.add(frozenset(state))transitions = {} for symbol inalphabet: next_states =set(nfa.move(state, symbol)) fornext_state in next_states:dfs(next_state) if next_states !=set(): transitions[symbol] =frozenset(next_states)delta[frozenset(state)] = transitionsdfs(nfa.start) return DFA(states,alphabet, delta, start_state, end_states) ```上述代码中,我们定义了DFA类,其中包括有限状态集合Q,字母表Σ,状态转移函数δ,初始状态q0和终结符集合F。
编译原理课后习题答案ch4

注意:本题应该理解为对图(a)进行确定化和对图(b)进行最小化。提供的答案没有对图(a)确 定化。
盛威网()专业的计算机学习网站 14
《编译原理》课后习题答案第四章
第5题 构造一个 DFA,它接收 Σ={0,1}上所有满足如下条件的字符串:每个 1 都有 0 直接跟在 右边。并给出该语言的正规式。 答案: 按题意相应的正规表达式是(0*10)*0*, 或 0*(0 | 10)*0* 构造相应的 DFA, 首先构造 NFA 为
7
《编译原理》课后习题答案第四章
注意:这个题,也可以这样构造 NFA(用最少的ε,但注意不能出错) :
a,b 0 a a 2 a,b 1 a b 3
盛威网()专业的计算机学习网站
8
《编译原理》课后习题答 ε X b A ε F B a C b ε b G b H ε ε D ε E a I b Y
除 X,A 外,重新命名其他状态,令 AB 为 B、AC 为 C、ABY 为 D,因为 D 含有 Y(NFA 的终态),所以 D 为终态。 . X A B C D DFA 的状态图:: 0 . A C A C 1 A B B D B
(2)先构造 NFA: 0 ε X 1 A ε ε F B 1 C 1 0 ε 0 D 1 E 1 0 ε 用子集法将 NFA 确定化 ε X T0=X A T1= ABFL Y CG T2= Y T3= CGJ DH K T4= DH EI T5= ABFKL T6= ABEFIL EJY T7= ABEFGJLY EHY CGK T8= ABEFHLY EY CGI T9= ABCFGJKL DHY T10= ABEFLY T11= CGJI DHJ T12= DHY T13= DHJ EIK T14= ABEFIKL ABEFIKL EJY CG DHJ ?正确 DHJG EI EIK DHY EY DHJ CG K ABEFLY CGJI DHY CGK ABEFHLY ABCFGJKL EY CGI ABEFGJLY EHY CGK ABEFIL Y EJY CG CG DH ABFKL EI DH K Y CGJ ABFL Y CG X A 0 1 1 ε L ε K ε J 0 Y
利用子集法构造DFA

实验一:利用子集法构造DFA一.实验目的掌握将非确定有限自动机确定化的方法和过程。
二.实验要求、内容及步骤实验要求:1.输入一个NFA,输出一个接受同一正规集的DFA;2.采用C++语言,实现该算法;3.编制测试程序;4.调试程序。
实验步骤:1.输入一个NFA关系图;2.通过一个转换算法将NFA转换为DFA;3.显示DFA关系图。
三.实验设备计算机、Windows 操作系统、Visual C++ 程序集成环境。
四.实验原理转换原理:从NFA的矩阵表示中可以看出,表项通常是一状态的集合,而在DFA的矩阵表示中,表项是一个状态,NFA到相应的DFA的构造的基本思路是:DFA的每一个状态对应NFA的一组状态。
DFA使用它的状态去记录在NFA读入一个输入符号后可能到达的所有状态。
输入:一个NFA N输出:一个接受同样语言的DFA D方法:为D构造转换表Dtran,DFA的每个状态是NFA的状态集。
D的状态集合用Dstates表示。
D的开始状态为ε-closure(s0),s0是N的开始状态。
使用下列算法构造D的状态集合Dstates和转换表Dtran。
如果D的某个状态是至少包含一个N的接受状态的NFA状态集,那么它是D的一个接受状态。
2.子集构造法:初始时, ε-closure(S0) 是Dstates中唯一的状态且未被标记;while Dstates中存在一个未标记的状态T do begin标记T;for 每个输入符号a do beginU := ε-closure ( move (T, a) );if U 没在Dstates中then将U作为一个未被标记的状态添加到 Dstates.Dtran [ T, a ] := Uendend3.ε-closure的计算:将T中所有状态压入栈stack;将ε-closure (T) 初始化为T;while stack不空 do begin将栈顶元素t弹出栈;for 每个这样的状态u:从t到u有一条标记为ε的边do if u不在ε-closure ( T )中 do begin将u 添加到ε-closure ( T );将u压入栈stack中endend五.程序设计1.总体设计2.子程序设计识别模块FFF六.程序中的结构说明1.结构体2.符号编码表3.重要函数介绍tokentype recogid(char ch) 数代码#include <>#include <>#include <>#include <>ymbol);if(flag==0) dname,word);if(fflag==0) ddress;break;} }if(fflag!=0){ fs=fopen("","a"); dname, word);a[k].address=k;a[k].type=25;=25;=k;for(j=0;j<9;j++)fprintf(fs,"%c",word[j]);fprintf(fs,"%c",'\t');fprintf(fs,"%d",a[k].address);fprintf(fs,"%c",'\t');fprintf(fs,"%d",a[k].type);fprintf(fs,"%c",'\n');fclose(fs);k=k+1;} }strcpy, word);um==num){ flag=1;=26;=d[j].address;break;}if(flag!=1){ d[t].num=num;d[t].address=t;=26;=t;t=t+1;}sprintf, "%d", num);dname,a[i].address,a[i].type);printf("************************************\n"); printf("输出常数表如下:\n");printf("%s\t%s\n","num","address");for(i=0;i<=t-1;i++)printf("%d\t%d\n",d[i].num,d[i].address);printf("\n\n");system("pause");}八.程序测试Source源文件程序截图main(){If a!=35end;do whileend;36}九.实验小结子集构造法的基本思想是构造得到的DFA的每个状态对应于NFA的一个状态集合。
编译原理教程课后习题参考答案——

第二章 词法分析2.1 完成下列选择题:(1) 词法分析器的输出结果是 。
a. 单词的种别编码b. 单词在符号表中的位置c. 单词的种别编码和自身值d. 单词自身值(2) 正规式M1和M2等价是指 。
a. M1和M2的状态数相等b. M1和M2的有向边条数相等c. M1和M2所识别的语言集相等d. M1和M2状态数和有向边条数相等(3) DFA M(见图2-1)接受的字集为 。
a. 以0开头的二进制数组成的集合b. 以0结尾的二进制数组成的集合c. 含奇数个0的二进制数组成的集合d. 含偶数个0的二进制数组成的集合【解答】(1) c (2) c (3) d图2-1 习题2.1的DFA M2.2 什么是扫描器?扫描器的功能是什么?【解答】 扫描器就是词法分析器,它接受输入的源程序,对源程序进行词法分析并识别出一个个单词符号,其输出结果是单词符号,供语法分析器使用。
通常是把词法分析器作为一个子程序,每当词法分析器需要一个单词符号时就调用这个子程序。
每次调用时,词法分析器就从输入串中识别出一个单词符号交给语法分析器。
2.3 设M=({x,y}, {a,b}, f, x, {y})为一非确定的有限自动机,其中f 定义如下:f(x,a)={x,y} f {x,b}={y}f(y,a)=Φ f{y,b}={x,y}试构造相应的确定有限自动机M ′。
【解答】 对照自动机的定义M=(S,Σ,f,So,Z),由f 的定义可知f(x,a)、f(y,b)均为多值函数,因此M 是一非确定有限自动机。
先画出NFA M 相应的状态图,如图2-2所示。
图2-2 习题2.3的NFA M 用子集法构造状态转换矩阵,如表表2-1 状态转换矩阵1b将转换矩阵中的所有子集重新命名,形成表2-2所示的状态转换矩阵,即得到 M ′=({0,1,2},{a,b},f,0,{1,2}),其状态转换图如图2-3所示。
表2-2 状态转换矩阵将图2-3所示的DFA M ′最小化。
编译原理实验dfa的最小化

编译原理实验dfa的最小化编译原理是一门基础学科,是计算机科学和工程中的重要分支之一。
在现代计算机系统中,编译器扮演着重要的角色,它们能将高级语言编写的程序转化为机器可执行的二进制代码,从而实现程序的正确性和高效性。
自动机理论是编译原理中一个重要的知识点,特别是有限状态自动机(DFA)的最小化。
DFA最小化是实现语言识别和编译器优化的重要方法之一。
DFA最小化是指将一个给定的DFA自动机,构造出一个等价的、状态数量最小的DFA自动机。
在编译器优化中,通过对DFA的最小化,可以减小指令译码的复杂度,加快程序的执行速度。
DFA最小化的方法主要有两种,分别是Hopcroft算法和划分算法。
这里主要介绍Hopcroft算法。
Hopcroft算法Hopcroft算法是一种直接的构造算法,其基本思想是先将DFA的所有状态按不可区分性划分成若干个集合,然后根据每个字符的转移关系,对划分后的集合进行合并,最后得到一个等价的、状态数量最小的DFA自动机。
Hopcroft算法所需的时间复杂度为O(m log n),m为DFA的边数,n为DFA的状态数。
下面分步骤介绍该算法。
第一步,将所有状态分为接受状态和非接受状态,并将它们分别放入两个集合中。
即S = {S acc, S non-acc},S acc为所有接受状态的集合,S non-acc为所有非接受状态的集合。
第二步,对S中的每个集合进行划分。
这里采用动态规划的思想,从初始状态开始,不断重复以下操作,直到不能再继续为止:步骤1:将当前状态集合划分成若干个等价的子集,得到新的状态集合。
步骤2:检查新的状态集合是否与前一个状态集合相等,如果是,则停止操作;否则,将新的状态集合作为下一轮操作的初始状态。
步骤1中,可以采用如下的方法进行划分。
设定两个状态x和y,如果存在一个字符a,使得x经过字符a的转移后所到达的状态与y经过字符a的转移后所到达的状态在S中属于不同的集合,则称状态x和y不可区分,将它们放入同一个集合中。
DFA编程实现报告
实验一 DFA的编程实现一、实验目的:通过本次实验,加深对DFA及其识别的语言的理解,学习对一般的DFA的表达方法与编程实现方法。
二、实验任务:编写一个C语言程序,模拟实现DFA识别字符串的过程。
三、实验内容:(1)DFA的输入;(2)DFA的存储与读写;(3)DFA的正确性检查;(4)DFA的语言集列表显示;(5)DFA的规则字符串判定;四、实验分析:DFA的初始化一个DFA的基本信息状态集、字符集、开始状态、结束状态集、状态转换表;在程序中状态集、字符集、开始状态、结束状态集都用string类型来表示,即可不用考虑用户输入内容的长度。
但缺点是字符集只能是字符而不可以是字符串。
状态转换表:为三个字符的字符串,第一个为当前状态,第二个为输入字符,第三个为下一状态。
用vector容器存放转换函数的内容字符串判断初始化一个DFA,后可以通过一下算法判断一个字符串是否符合该DFA。
判定算法概要:准备:开始状态s0, 接受状态集F, 状态转换表T(s, c), s∈S, c∈∑c = getchar();s = 开始状态s0;while ( c != EOF ) // 输入未结束则循环…{s = T(s, c);if (s == NULL)error();c = getchar();if (s 接受状态集F)accept ();elseerror ();在实际编写代码中的体现为void identify() //判断字符串{cout<<"请输入字符串"<<endl;string str;cin>>str;int i=0;char present=StartStates;while(i<str.length()){present=move(present,str[i]);//move函数即去遍历转换表,返回下个状态if(present=='N') // N 即为move返回错误的状态,{break;}i++;}if(FinalStates.find(present)!=FinalStates.npos)//如果返回的状态用find函数属于最终状态集则表示识别cout<<"该自动机识别此字符串"<<endl;elsecout<<"该自动机不识别此字符串"<<endl;}对DFA的存储与读写将DNF的信息写入文件中,第一行:字符集;第二行:状态集;第三行:开始状态;第四行:结束状态集;以下行写入状态转换表按照既定的规定读取文件中的数据将其赋值,然后初始化DFA即可;DFA的语言集列表显示:这一个模块应该是这个实验中比较难的一部分了。
编译原理第4章答案
第四章 词法分析1.构造下列正规式相应的DFA :(1) 1(0|1)*101(2) 1(1010*| 1(010)*1)*0 (3) a((a|b)*|ab *a)*b (4) b((ab)*| bb)*ab 解:(1)1(0|1)*101对应的NFA 为下表由子集法将NFA 转换为DFA :(2)1(1010*| 1(010)*1)*0对应的NFA 为 10,1下表由子集法将NFA转换为DFA:(3)a((a|b)*|ab *a)*b (略) (4)b((ab)*| bb)*ab (略)2.已知NFA=({x,y,z},{0,1},M,{x},{z})其中:M(x,0)={z},M(y,0)={x,y},M(z,0)={x,z},M(x,1)={x}, M(y,1)=φ,M(z,1)={y},构造相应的DFA 。
解:根据题意有NFA 图如下下表由子集法将NFA 转换为DFA :0,1下面将该DFA最小化:(1)首先将它的状态集分成两个子集:P1={A,D,E},P2={B,C,F}(2)区分P2:由于F(F,1)=F(C,1)=E,F(F,0)=F并且F(C,0)=C,所以F,C等价。
由于F(B,0)=F(C,0)=C,F(B,1)=D,F(C,1)=E,而D,E不等价(见下步),从而B与C,F可以区分。
有P21={C,F},P22={B}。
(3)区分P1:由于A,E输入0到终态,而D输入0不到终态,所以D与A,E可以区分,有P11={A,E},P12={D}。
(4)由于F(A,0)=B,F(E,0)=F,而B,F不等价,所以A,E可以区分。
(5)综上所述,DFA可以区分为P={{A},{B},{D},{E},{C,F}}。
所以最小化的DFA如下:3.将图确定化:1101111解:下表由子集法将NFA 转换为DFA :4.把图的(a)和(b)分别确定化和最小化:(a) (b)解: (a):下表由子集法将NFA 转换为DFA :0,1a可得图(a1),由于F(A,b)=F(B,b)=C,并且F(A,a)=F(B,a)=B,所以A,B 等价,可将DFA 最小化,即:删除B ,将原来引向B 的引线引向与其等价的状态A ,有图(a2)。
DFA的化简
DFA(确定的有穷自动机)的化简1. 实验内容输入一个DFA M,输出一个与之等价的最小化的DFA M’,设计并实现将NFA确定化为DFA的子集构造算法,输入非确定有限(穷)状态自动机,输出确定化的有限(穷)状态自动机编写一个程序,将一个非确定有限自动机转换为确定有限自动机。
2. 实验设计分析2.1 实验设计思路首先输入边集找到状态与边的关系,然后输入终结点,这样一个没有简化的NFA图就表示出来了,然后利用求闭包的方式求move集合,画出状态转化图,重命名后进行集合划分,再次重新画出状态转换矩阵,输出简化后的DFA。
2.2 实验算法(1)构造具有两个组的状态集合的初始划分I:接受状态组 F 和非接受状态组Non-F。
(2)对I采用下面所述的过程来构造新的划分I-new.For I 中每个组G doBegin当且仅当对任意输入符号a,状态s和读入a后转换到I的同一组中;/*最坏情况下,一个状态就可能成为一个组*/用所有新形成的小组集代替I-new中的G;end(3)如果I-new=I,令I-final=I,再执行第(4)步,否则令I=I=new,重复步骤(2)。
(4)在划分I-final的每个状态组中选一个状态作为该组的代表。
这些代表构成了化简后的DFA M'状态。
令s是一个代表状态,而且假设:在DFA M 中,输入为a时有从s到t转换。
令t所在组的代表是r,那么在M’中有一个从s到r的转换,标记为a。
令包含s0的状态组的代表是M’的开始状态,并令M’的接受状态是那些属于F的状态所在组的代表。
注意,I-final的每个组或者仅含F中的状态,或者不含F中的状态。
(5)如果M’含有死状态(即一个对所有输入符号都有刀自身的转换的非接受状态d),则从M’中去掉它;删除从开始状态不可到达的状态;取消从任何其他状态到死状态的转换。
2.3 实验流程1. 输入NFA各边信息(起点条件[空为*] 终点),以#结束2. 输入终态3. 求e-clouse闭包,将结点移入相应的闭包集合,并重新排序4. 输出状态转换矩阵,转换成DFA并重命名5. 执行DFA最简化6. 重命名DFA,输出最简化DFA状态转换矩阵2.4 实验的基本技术设计方案实验中含有一些数据结构的知识,假设I是NFA M状态集K的一个子集(即I∈K),则定义ε-closure(I)为:若Q∈I,则Q∈ε-closure(I);若Q∈I,则从Q出发经过任意条ε弧而能到达的任何状态Q’,则Q’∈ε-closure(I)。
编译原理 NFA转DFA
实验一:利用子集法构造DFA一.实验目的掌握将非确定有限自动机确定化的方法和过程。
二.实验要求、内容及步骤实验要求:1.输入一个NFA,输出一个接受同一正规集的DFA;2.采用C++语言,实现该算法;3.编制测试程序;4.调试程序。
实验步骤:1.输入一个NFA关系图;2.通过一个转换算法将NFA转换为DFA;3.显示DFA关系图。
三.实验设备计算机、Windows 操作系统、Visual C++ 程序集成环境。
四.实验原理1.NFA-DFA转换原理:从NFA的矩阵表示中可以看出,表项通常是一状态的集合,而在DFA的矩阵表示中,表项是一个状态,NFA到相应的DFA的构造的基本思路是:DFA的每一个状态对应NFA的一组状态。
DFA使用它的状态去记录在NFA读入一个输入符号后可能到达的所有状态。
输入:一个NFA N输出:一个接受同样语言的DFA D方法:为D构造转换表Dtran,DFA的每个状态是NFA的状态集。
D的状态集合用Dstates表示。
D的开始状态为ε-closure(s0),s0是N的开始状态。
使用下列算法构造D的状态集合Dstates和转换表Dtran。
如果D的某个状态是至少包含一个N的接受状态的NFA状态集,那么它是D的一个接受状态。
2.子集构造法:初始时, ε-closure(S0) 是Dstates中唯一的状态且未被标记;while Dstates中存在一个未标记的状态T do begin标记T;for 每个输入符号a do beginU := ε-closure ( move (T, a) );if U 没在Dstates中then将U作为一个未被标记的状态添加到 Dstates.Dtran [ T, a ] := Uendend3.ε-closure的计算:将T中所有状态压入栈stack;将ε-closure (T) 初始化为T;while stack不空 do begin将栈顶元素t弹出栈;for 每个这样的状态u:从t到u有一条标记为ε的边do if u不在ε-closure ( T )中 do begin将u 添加到ε-closure ( T );将u压入栈stack中 endend五.程序设计1.总体设计2.子程序设计识别模块读入字符识别模块识别标识符识别分界符、运算符识别常数输出六.程序中的结构说明1.结构体Symbolrecord 结构体结构体成员名 成员属性Symbol[10] 用于存储关键字编码名 id用于存储关键字对应的编码读取字符字母识别标识符数字识别数字/识别注释打印并结束FTFTFTentrytype结构体结构体成员名成员属性idname[10] 用于存储识别后标识符名address 用于存储标识符的地址type 用于存储标识符的类型digittype结构体结构体成员名成员属性num 用于存储识别后的数字address 用于存储标识符数字的地址tokentype结构体结构体成员名成员属性id 用于存储被识别的类型名entry 用于存储标识符的地址idname[10] 用于存储被识别的标识符名2.符号编码表符号编码表符号名代码符号名代码Begin 0 } 14End 1 ( 15If 2 ) 16 Then 3 < 17 Else 4 <= 18for 5 = 19do 6 != 20while 7 > 21+ 8 >= 22- 9 := 23* 10 ‘’24/ 11 Id 25; 12 Const 26{ 133.重要函数介绍tokentype recogid(char ch)//识别标识符算法tokentype recogdig(char ch) ///识别数字函数tokentype recogdel(char ch) //识别算符和界符函数tokentype handlecom(char ch) //handlecom函数,识别注释函数void sort(char ch) //sort函数,读取文件内容,并根据读入内容调用不同的识别函数void scanner()//scanner函数,打开文件七.函数代码#include <stdio.h>#include <string.h>#include <ctype.h>#include <stdlib.h>;-----------------------定义单词编码表的数据结构-------------------- struct symbolrecord{ char symbol[10];int id;} ;;-------------------------定义符号表的数据结构---------------------- struct entrytype{ char idname[10];int address;int type;};;-------------------------定义常数表的数据结构---------------------- struct digittype{ int num;int address;};;---------------------------Token字的数据结构----------------------- struct tokentype{ int id;int entry;char idname[10];};FILE *fp; //源文件指针struct digittype d[10]; //定义常数表,个数指针struct entrytype a[40];int k=0,t=0;;---------------------------单词编码表初始化------------------------ struct symbolrecord s[26]={ "Begin",0,"End",1,"If",2,"Then",3, "Else",4, "for",5, "do",6,"while",7, "+",8,"-",9,"*",10,"/",11,";",12,"{",13,"}",14,"(",15,")",16,"<",17,"<=",18, "=",19,"!=",20, ">",21,">=",22, ":=",23, " ",24,"const",26 };;---------------------------识别标识符算法-------------------------- tokentype recogid(char ch){ tokentype tokenid;FILE *fs;int flag,fflag;char word[10]={0};int i,j;i=0;while(isalpha(ch)||isdigit(ch)){ word[i]=ch;ch=fgetc(fp);i=i+1;}ungetc(ch,fp);word[i]='\0';for(j=0;j<=8;j++){ flag=strcmp(word, s[j].symbol);if(flag==0) //是关键字{ tokenid.id=j;tokenid.entry=-1;break;} }if(flag!=0){ for(j=0;j<=k;j++){ fflag=strcmp(a[j].idname,word);if(fflag==0) //在符号表中可以找到{ tokenid.id=25;tokenid.entry=a[j].address;break;} }if(fflag!=0){ fs=fopen("symbol.txt","a"); //符号表中不存在的标识符 strcpy(a[k].idname, word);a[k].address=k;a[k].type=25;tokenid.id=25;tokenid.entry=k;for(j=0;j<9;j++)fprintf(fs,"%c",word[j]);fprintf(fs,"%c",'\t');fprintf(fs,"%d",a[k].address);fprintf(fs,"%c",'\t');fprintf(fs,"%d",a[k].type);fprintf(fs,"%c",'\n');fclose(fs);k=k+1;} }strcpy(tokenid.idname, word);//自行添加的return tokenid;};-----------------------------识别数字函数-------------------------- tokentype recogdig(char ch){ int flag;int i=0,j;int num=0;tokentype tokenid;while(isdigit(ch)){ num=(ch-48)+num*10;ch=fgetc(fp);i=i+1;}for(j=0;j<=t;j++)if(d[j].num==num){ flag=1;tokenid.id=26;tokenid.entry=d[j].address;break;}if(flag!=1){ d[t].num=num;d[t].address=t;tokenid.id=26;tokenid.entry=t;t=t+1;}sprintf(tokenid.idname, "%d", num);//int>>charreturn tokenid;};------------------------识别算符和界符函数------------------------- tokentype recogdel(char ch){ tokentype tokenid;switch(ch){ case'{':{ tokenid.id=13;strcpy(tokenid.idname, "{");//自行添加的}break;case'}':{ tokenid.id=14;strcpy(tokenid.idname, "}");}break;case';':{ tokenid.id=12;strcpy(tokenid.idname, ";");}break;case'=':{ tokenid.id=19;strcpy(tokenid.idname, "=");}break;case':':ch=fgetc(fp);if(ch=='=') tokenid.id=23; break;case'!':{ ch=fgetc(fp);if(ch=='=') tokenid.id=20;strcpy(tokenid.idname, "!="); } break;case'<':{ch=fgetc(fp);if(ch=='='){ tokenid.id=18;strcpy(tokenid.idname, "<=");}else{ tokenid.id=17;strcpy(tokenid.idname, "<");ungetc(ch,fp);}}; break;case'>':ch=fgetc(fp);if(ch=='='){tokenid.id=22;strcpy(tokenid.idname, ">=");}else { tokenid.id=21;strcpy(tokenid.idname, ">");ungetc(ch,fp);}; break;case'+':{ tokenid.id=8;strcpy(tokenid.idname, "+");}break;case'*':{ tokenid.id=10;strcpy(tokenid.idname, "*");}break;case'(':{ tokenid.id=15;strcpy(tokenid.idname, "(");}break;case')':{ tokenid.id=16;strcpy(tokenid.idname, ")");}break;}tokenid.entry=-1;return tokenid;};---------------------------handlecom函数--------------------------- tokentype handlecom(char ch){ tokentype tokenid;char ch1;int flag=0;if(ch!='*' ){ tokenid.id=25;tokenid.entry=-1;}else{ while(flag==0){ ch1=ch;ch=fgetc(fp);if((ch1='*')&&(ch='/'))flag=1;}}return tokenid;};---------------------------sort函数---------------------------- void sort(char ch){struct tokentype tokenword;FILE * fq = fopen("tokenfile.txt","a");if(isalpha(ch))tokenword=recogid(ch); //字母else if(isdigit(ch))tokenword=recogdig(ch); //数字else if(ch=='/')tokenword=handlecom(ch);elsetokenword=recogdel(ch);printf("%s\t%d\t%d\n",tokenword.idname,tokenword.id,tokenword.entry) ;fprintf(fq,"%d",tokenword.id);fprintf(fq,"%c",'\t');fprintf(fq,"%d",tokenword.entry);fprintf(fq,"%c",'\n');fclose(fq);};--------------------------scanner函数---------------------------- void scanner(){ char ch;fp=fopen("source.txt","r");ch=getc(fp);while(ch!=EOF){ if(!isspace(ch)){ sort(ch);}ch=fgetc(fp);}fclose(fp);};------------------------------主函数------------------------------ int main(){ int i;printf("输出token字如下:\n");printf("idname\ttype\taddress\n");scanner();printf("************************************\n");printf("输出符号表如下:\n");printf("%s\t%s\t%s\n","idname","address","type");for(i=0;i<=k-1;i++)printf("%s\t%d\t%d\n",a[i].idname,a[i].address,a[i].type);printf("************************************\n"); printf("输出常数表如下:\n");printf("%s\t%s\n","num","address");for(i=0;i<=t-1;i++)printf("%d\t%d\n",d[i].num,d[i].address);printf("\n\n");system("pause");}八.程序测试Source源文件程序截图main(){If a!=35end;do whileend;36}九.实验小结子集构造法的基本思想是构造得到的DFA的每个状态对应于NFA的一个状态集合。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
int k=0;
int m=0;
num=0;
stack<int> S;
S.push(t);
int j;
while(!S.empty())
{
j=S.top();
S.pop();
m=0;
while(m<nk)
{
if(Ekong[m].start==j)
{
result[num++]=Ekong[m].end;
{
temp.H[temp.count++]=search_result[j];
STACK.push(search_result[j]);
}
}
}
for(k=0;k<temp.count;k++)
{
if(f[temp.H[k]]==1)
{
temp.flag=1;
break;
}
if(f[temp.H[k]]==0)
{
stack<int> STACK;
State temp;
int i,j,k;
for(i=0;i<T.count;i++)
{
STACK.push(T.H[i]);
temp.H[i]=T.H[i];
}
temp.count=T.count;
temp.mark=T.mark;
while(!STACK.empty())
实验一 利用子集法构造DFA
一、实验目的
掌握将非确定有限自动机确定化的方法和过程
2、实验要求及内容
实验要求:
1.输入一个NFA,输出一个接受同一正规集的DFA;
2.采用C++语言,实现该算法;
3.编制测试程序;
4.调试程序。
实验步骤:
1.输入一个NFA关系图;
2.通过一个转换算法将NFA转换为DFA;
using namespace std;
struct edge{
int start,end;
char c;
}
E[100],Ekong[100];//E保存所有的边,Ekong保存转换字符为空的边
struct State{
int H[100];//状态集合
int count;//状态集合中的元素个数
int flag;//是否是接受状态
{
temp.flag=0;
break;
}
}
sort(temp.H,temp.H+temp.count);
for(i=0;i<numof_Dtran;i++)
{
if(temp.count!=DFA[i].count)
{
j=0;
while(j<n)
{
if(E[j].start==T.H[i]&&E[j].c==s)
{temp.H[temp.count++]=E[j].end;
}
j++;
}
}
return temp;
}
void arriveBynone(int t,int result[],int& num)//搜索状态t通过一个或多个空字符到达的状态,结果存在result中
Ekong[nk].end=e;
Ekong[nk].c=ch;
nk++;
}
}
}
State move(State T,char s)//c!='#'
{
State temp;
temp.count=0;
temp.mark=T.mark;
int i,j=0,k=0;
for(i=0;i<T.count;i++)
S.push(Ekong[m].end);
}
m++;
}
}
}
bool check(int i,State T)//判断状态i是否在T中
{
int j;
for(j=0;j<T.count;j++)
{
if(T.H[j]==i)
return e;
}
return false;
}
State closure(State T)//求闭包
int mark;//状态编号
};
int n;//n:边数
int nk=0;//空字符转换的边数
int first,accept;//开始状态,接受状态
char alpha[100];//输入字母表,#代表空串
int numof_char=0;//字母表中的字符个数
int useof_char[256];//该转换字符是否用过
for(i=0;i<n;i++)
{
cin>>s>>e>>ch;
E[i].start=s;
E[i].end=e;
E[i].c=ch;
if(ch!='#'&&!useof_char[ch])
{
alpha[numof_char++]=ch;
useof_char[ch]=1;
}
if(ch=='#')
{
Ekong[nk].start=s;
memset(useof_char,0,sizeof(useof_char));
f[first]=0;
cin>>accept;
while(accept!=-1)
{
f[accept]=1;
cin>>accept;
}
cout<<"请输入NFA,起点,终点,转换字符('#'表示空字符):"<<endl;
int k=0;
{
int t=STACK.top();
STACK.pop();
//搜索状态t通过一个或多个空字符到达的状态
int search_result[100];
int num;
arriveBynone(t,search_result,num);
for(j=0;j<num;j++)
{
if(!check(search_result[j],temp))
void input()
{
int i,s,e;
char ch;
cout<<"请输入转换的有向边数n:"<<endl;
cin>>n;
cout<<"请输入NFA的开始状态:"<<endl;
cin>>first;
cout<<"请输入NFA的接受状态(输入-1结束):"<<endl;
memset(f,-1,sizeof(f));
int f[200];//状态属性标志:0表示始态,1表示接受态,-1表示中间态
State DFA[100];//DFA状态集
int useof_DFA[100];//标志构造出来的状态是否已存在
int numof_Dtran=0;//最后得到的DFA中的状态数
char Dtran[100][100];//DFA状态转换表
3.显示DFA关系图。
三、实验环境
计算机、Windows操作系统、Visual C++程序集成环境。
4、程序代码
#include "stdafx.h"
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<string>