编译原理实验四

合集下载

编译原理语法分析实验报告

编译原理语法分析实验报告

编译原理语法分析实验报告第一篇:编译原理语法分析实验报告实验2:语法分析1.实验题目和要求题目:语法分析程序的设计与实现。

实验内容:编写语法分析程序,实现对算术表达式的语法分析。

要求所分析算术表达式由如下的文法产生。

E→E+T|E-T|TT→T*F|T/F|F F→id|(E)|num实验要求:在对输入表达式进行分析的过程中,输出所采用的产生式。

方法1:编写递归调用程序实现自顶向下的分析。

方法2:编写LL(1)语法分析程序,要求如下。

(1)编程实现算法4.2,为给定文法自动构造预测分析表。

(2)编程实现算法4.1,构造LL(1)预测分析程序。

方法3:编写语法分析程序实现自底向上的分析,要求如下。

(1)构造识别所有活前缀的DFA。

(2)构造LR分析表。

(3)编程实现算法4.3,构造LR分析程序。

方法4:利用YACC自动生成语法分析程序,调用LEX自动生成的词法分析程序。

实现(采用方法1)1.1.步骤:1)对文法消除左递归E→TE'E'→+TE'|-TE'|εT→FT'T'→*FT'|/FT'|εF→id|(E)|num2)画出状态转换图化简得:3)源程序在程序中I表示id N表示num1.2.例子:a)例子1 输入:I+(N*N)输出:b)例子2 输入:I-NN 输出:第二篇:编译原理实验报告编译原理实验报告报告完成日期 2018.5.30一.组内分工与贡献介绍二.系统功能概述;我们使用了自动生成系统来完成我们的实验内容。

我们设计的系统在完成了实验基本要求的前提下,进行了一部分的扩展。

增加了声明变量类型、类型赋值判定和声明的变量被引用时作用域的判断。

从而使得我们的实验结果呈现的更加清晰和易懂。

三.分系统报告;一、词法分析子系统词法的正规式:标识符(|)* 十进制整数0 |(1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)* 八进制整数0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)* 十六进制整数0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)* 运算符和分隔符 +| * | / | > | < | = |(|)| <=|>=|==;对于标识符和关键字: A5—〉 B5C5 B5—〉a | b |⋯⋯| y | z C5—〉(a | b |⋯⋯| y | z |0|1|2|3|4|5|6|7|8|9)C5|ε综上正规文法为: S—〉I1|I2|I3|A4|A5 I1—〉0|A1 A1—〉B1C1|ε C1—〉E1D1|ε D1—〉E1C1|εE1—〉0|1|2|3|4|5|6|7|8|9 B1—〉1|2|3|4|5|6|7|8|9 I2—〉0A2 A2—〉0|B2 B2—〉C2D2 D2—〉F2E2|ε E2—〉F2D2|εC2—〉1|2|3|4|5|6|7 F2—〉0|1|2|3|4|5|6|7 I3—〉0xA3 A3—〉B3C3 B3—〉0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f C3—〉(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)|C3|εA4—〉+ |-| * | / | > | < | = |(|)| <=|>=|==; A5—〉 B5C5 B5—〉a | b |⋯⋯| y | z C5—〉(a | b |⋯⋯| y | z |0|1|2|3|4|5|6|7|8|9)C5|ε状态图流程图:词法分析程序的主要数据结构与算法考虑到报告的整洁性和整体观感,此处我们仅展示主要的程序代码和算法,具体的全部代码将在整体的压缩包中一并呈现另外我们考虑到后续实验中,如果在bison语法树生成的时候推不出目标的产生式时,我们设计了报错提示,在这个词的位置出现错误提示,将记录切割出来的词在code.txt中保存,并记录他们的位置。

编译原理-实验报告4-逆波兰

编译原理-实验报告4-逆波兰

计算机硬件实验室实验报告姓名学号班级成绩设备名称及软件环境逆波兰一、实验目的:将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。

二、实验要求:输出的格式如下:(1)逆波兰式的生成及计算程序,编制人:姓名,学号,班级(2)输入一以#结束的中缀表达式(包括+—*/()数字#):在此位置输入符号串如(28+68)*2#(3)逆波兰式为:28&68+2*(4)逆波兰式28&68+2*计算结果为192备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;(2)在此位置输入符号串为用户自行输入的符号串。

注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);三、实验过程:(一)准备:1.阅读课本有关章节,2.考虑好设计方案;3.设计出模块结构、测试数据,初步编制好程序。

(1)定义部分:定义常量、变量、数据结构。

(2)初始化:设立算符优先分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);(3)控制部分:从键盘输入一个表达式符号串;(4)利用算符优先分析算法进行表达式处理:根据算符优先分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。

(5)对生成的逆波兰式进行计算。

(二)上课上机:将源代码拷贝到机上调试,发现错误,再修改完善。

第二次上机调试通过。

四、实验结果(1)写出程序流程图(2)给出运行结果程序:#include<stdio.h>#include<math.h>#include<stdlib.h>#define max 100char ex[max]; /*存储后缀表达式*/void trans(){ /*将算术表达式转化为后缀表达式*/char str[max]; /*存储原算术表达式*/char stack[max]; /*作为栈使用*/char ch;int sum,i,j,t,top=0;// printf("*****************************************\n");printf("逆波兰式的生成及计算程序,编制人:武普泉,20号,1020562班\n");printf("输入一以#结束的中缀表达式(包括+ - * /()数字# ):");// printf("******************************************\n");// printf("算数表达式:");i=0; /*获取用户输入的表达式*/do{i++;scanf("%c",&str[i]);}while(str[i]!='#' && i!=max);sum=i;t=1;i=1;ch=str[i];i++;while(ch!='#'){switch(ch){case '(': /*判定为左括号*/top++;stack[top]=ch;break;case ')': /*判定为右括号*/while(stack[top]!='('){ex[t]=stack[top];top--;t++;}top--;break;case '+': /*判定为加减号*/case '-':while(top!=0&&stack[top]!='('){ex[t]=stack[top];top--;t++;}top++;stack[top]=ch;break;case '*': /*判定为乘除号*/case '/':while(stack[top]=='*'||stack[top]=='/'){ex[t]=stack[top];top--;t++;}top++;stack[top]=ch;break;case ' ':break;default:while(ch>='0'&&ch<='9'){ /*判定为数字*/ ex[t]=ch;t++;ch=str[i];i++;}i--;ex[t]='&';t++;}ch=str[i];i++;}while(top!=0){ex[t]=stack[top];t++;top--;}ex[t]='#';// printf("\n\t原来表达:");// for(j=1;j<sum;j++)// printf("%c",str[j]);printf("\n逆波兰式为:",ex);for(j=1;j<t;j++)printf("%c",ex[j]);}void compvalue(){ /*计算后缀表达式的值*/float stack[max],d; /*作为栈使用*/char ch;int t=1,top=0; /*t为ex下标,top为stack下标*/ch=ex[t];t++;while(ch!='#'){switch(ch){case '+':stack[top-1]=stack[top-1]+stack[top];top--;break;case '-':stack[top-1]=stack[top-1]-stack[top];top--;break;case '*':stack[top-1]=stack[top-1]*stack[top];top--;break;case '/':if(stack[top]!=0)stack[top-1]=stack[top-1]/stack[top];else{printf("\n\t除零错误!\n");exit(0); /*异常退出*/}top--;break;default:d=0;while(ch>='0'&&ch<='9'){d=10*d+ch-'0'; /*将数字字符转化为对应的数值*/ch=ex[t];t++;}top++;stack[top]=d;}ch=ex[t];t++;}printf("\n逆波兰式");for(int j=0;j<t-1;j++)printf("%c",ex[j]);printf("计算结果:%g\n",stack[top]);}void main(){trans();compvalue();}。

国开电大 编译原理 实验4:语法分析实验报告

国开电大 编译原理 实验4:语法分析实验报告

国开电大编译原理实验4:语法分析实
验报告
1. 实验目的
本实验的目的是研究和掌握语法分析的原理和实现方法。

2. 实验内容
本次实验主要包括以下内容:
- 设计并实现自顶向下的LL(1)语法分析器;
- 通过语法分析器对给定的输入串进行分析,并输出相应的分析过程;
- 编写测试用例,验证语法分析器的正确性。

3. 实验步骤
3.1 设计LL(1)文法
首先,根据实验要求和给定的语法规则,设计LL(1)文法。

3.2 构建预测分析表
根据所设计的LL(1)文法,构建预测分析表。

3.3 实现LL(1)语法分析器
根据预测分析表,实现自顶向下的LL(1)语法分析器。

3.4 对输入串进行分析
编写程序,通过LL(1)语法分析器对给定的输入串进行分析,并输出相应的分析过程和结果。

3.5 验证语法分析器的正确性
设计多组测试用例,包括正确的语法串和错误的语法串,验证语法分析器的正确性和容错性。

4. 实验结果
经过实验,我们成功设计并实现了自顶向下的LL(1)语法分析器,并对给定的输入串进行了分析。

实验结果表明该语法分析器具有较好的准确性和容错性。

5. 实验总结
通过本次实验,我们对语法分析的原理和实现方法有了更深入的了解。

同时,我们也学会了如何设计并实现自顶向下的LL(1)语
法分析器,并验证了其正确性和容错性。

这对于进一步研究编译原理和深入理解编程语言的语法结构具有重要意义。

6. 参考资料
- 《编译原理与技术》
- 课程实验文档及代码。

编译原理第四版附录c编译程序实验

编译原理第四版附录c编译程序实验

编译原理第四版附录c编译程序实验
编译原理第四版附录C编译程序实验指的是一项编译器开发实验,旨在让学生通过实践掌握编译器的设计和实现原理。

该实验一般分为以下几个步骤:
1. 了解编译器的基本原理和流程:这包括词法分析、语法分析、语义分析、代码生成等基本步骤,以及编译器的组成结构、工作流程等概念。

2. 设计编译器的语法和语义规则:在了解编译器的基本原理之后,需要根据具体的编译语言和需求设计语法和语义规则,通常采用自顶向下或自底向上的语法分析方法。

3. 实现编译器的核心算法和数据结构:编译器的核心算法包括词法分析器、语法分析器、语义分析器和代码生成器等,需要实现相应的数据结构和算法。

4. 测试和调试编译器:在完成编译器的实现之后,需要进行测试和调试,包括对编译器的正确性、效率和容错性进行测试和评估,以及对编译器的性能进行优化。

5. 扩展编译器的功能:在完成基本的编译器实现之后,可以考虑对编译器进行功能扩展,例如支持更丰富的语言特性、优化代码生成等。

总的来说,编译原理第四版附录C编译程序实验是一项非常有挑战性和实用性的实验,旨在让学生深入了解编译器的设计和实现原理,提高编程能力和实践经验。

编译原理中间代码生成实验报告

编译原理中间代码生成实验报告

竭诚为您提供优质文档/双击可除编译原理中间代码生成实验报告篇一:编译原理-分析中间代码生成程序实验报告课程名称编译原理实验学期至学年第学期学生所在系部年级专业班级学生姓名学号任课教师实验成绩计算机学院制开课实验室:年月日篇二:编译原理实验中间代码生成实验四中间代码生成一.实验目的:掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。

二.实验内容:1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。

用这种表示法表示的表达式也称做后缀式。

2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。

3、三元式:形式序号:(op,arg1,arg2)4、四元式:形式(op,arg1,arg2,result)三、以逆波兰式为例的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。

(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。

(4)如果不是数字,该字符则是运算符,此时需比较优先关系。

做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。

如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。

倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。

(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。

四、程序代码://这是一个由中缀式生成后缀式的程序#include#include#include#include#definemaxbuffer64voidmain(){chardisplay_out(charout_ch[maxbuffer],charch[32]);//intcaculate_array(charout_ch[32]);staticinti=0;staticintj=0;charch[maxbuffer],s[maxbuffer],out[maxbuffer];cout cin>>ch;for(i=0;i {out[i]=ch[i];}cout while(out[j]!=#)cout j++;}cout display_out(s,out);//caculate_array;}chardisplay_out(charout_ch[32],charch[]) {inttop=-1;inti=0,data[maxbuffer],n;intj=0;charsta[20];while(ch[i]!=#){if(isalnum(ch[i])){while(isalnum(ch[i])){out_ch[j]=ch[i];j++;i++;}out_ch[j]=;j++;else{switch(ch[i]){case+:case-:if(sta[top]==(||top==-1) {top++;sta[top]=ch[i];i++;}else{//j--;out_ch[j]=sta[top];j++;top--;//i++;}break;//break;case*:case/:if(sta[top]==*/) {out_ch[j]=sta[top];j++;//i++;top--;}else{top++;sta[top]=ch[i];i++;}break;//break;case(:top++;sta[top]=ch[i];i++;break;case):if(sta[top]==() {top--;i++;}if(top==-1){//cout }else{//while(sta[top]!=?(?){ out_ch[j]=sta[top];top--;j++;//}break;}break;/*case?#?:out_ch[j]=?#?; j++;break;*/default:cout ch[i]=#;j=0;break;}}}while(top!=-1){out_ch[j]=sta[top];j++;top--;}out_ch[j]=#;n=0;co(:编译原理中间代码生成实验报告)utwhile(out_ch[n]!=#){cout n++;}cout j=0;returnout_ch[maxbuffer];}五、实验结果:要求:自己给出3个测试用例,观察结果。

《编译原理》预备实验四:MFC 中编写绘图程序

《编译原理》预备实验四:MFC 中编写绘图程序

《编译原理》预备实验四:在MFC中编写绘图程序实验目的:建立MFC Windows 程序设计的形象概念,激发程序设计兴趣。

实验要求:掌握MFC应用程序框架的建立;MFC菜单的编写;模态对话框及常用控件的编写;鼠标响应消息的编写;类的建立;了解用于图形编程的CDC类及OnDraw函数作用;了解C++的STL标准模板库。

实验内容:编写一个简单的画直线程序。

直线的生成既可以通过对话框方式(键盘方式),也可以通过鼠标方式。

主要思想:建立一个直线类CLine,直线由起点和终点构成,两个端点可以通过对话框或者鼠标指定。

将每次生成的直线放入STL的list链表中,在OnDraw函数中遍历list链表,只要list链表不空就依次取出每条直线并绘制。

实验步骤:一、建立MFC应用程序框架步骤一:打开Microsoft Visual C++ 6.0 应用程序。

如图1所示。

图1:VC应用程序界面步骤二:在菜单中选择“文件”—>“新建”打开建立用户应用程序对话框,在对话框的“工程”页面左边选择MFC AppWizard[exe];在右边“位置”编辑框中键入要建的项目存放位置,例如D盘根目录;在右边“工程”编辑框中键入要建的项目的名称,例如MFCTest,这时我们会看到“位置”编辑框中信息变为“D:\MFCTest”,表示我们的项目文件都将存放在这个目录中。

如图2所示。

图2:建立MFC应用程序1步骤三:我们点击“确定”按钮进行下一步设置。

在“MFC AppWizard – Step 1”对话框中有“S单个文档”、“M多个文档”“D基本对话框”三个选项。

“S单个文档”表示用户程序一次只能打开一个文档窗口;“M多个文档”表示用户程序除了一个文档主窗口外,还可以打开若干个显示不同文档的小窗口,即子窗口;“D基本对话框”表示用户程序的界面是对话框形式的。

这里我们选择“S单个文档”,然后,单击“下一个”按钮。

如图3所示。

图3:MFC AppWizard – Step 1步骤四:“MFC AppWizard – Step 2 of 6”对话框是关于所建立的程序是否用到数据库,我们选择“否”,然后,单击“下一个”按钮。

计算机编译原理实验报告

计算机编译原理实验报告

编译原理实验报告实验一词法分析设计一、实验功能:1、对输入的txt文件内的内容进行词法分析:2、由文件流输入test.txt中的内容,对文件中的各类字符进行词法分析3、打印出分析后的结果;二、程序结构描述:(源代码见附录)1、分别利用k[],s1[],s2[],s3[]构造关键字表,分界符表,算术运算符表和关系运算符表。

2、bool isletter(){} 用来判断其是否为字母,是则返回true,否则返回false;bool isdigit(){} 用来判断其是否为数字,是则返回true,否则返回false;bool iscalcu(){} 用来判断是否为算术运算符,是则返回true,否则返回false;bool reserve(string a[]){} 用来判断某字符是否在上述四个表中,是则返回true,否则返回false;void concat(){} 用来连接字符串;void getn(){} 用来读取字符;void getb(){} 用来对空格进行处理;void retract(){}某些必要的退格处理;int analysis(){} 对一个单词的单词种别进行具体判断;在主函数中用switch决定输出。

三、实验结果四、实验总结词法分析器一眼看上去很复杂,但深入的去做就会发现并没有一开始想象的那么困难。

对于一个字符的种别和类型可以用bool函数来判断,对于关键字和标示符的识别(尤其是3b)则费了一番功夫,最后对于常数的小数点问题处理更是麻烦。

另外,这个实验要设定好时候退格,否则将会导致字符漏读甚至造成字符重复读取。

我认为,这个实验在程序实现上大体不算困难,但在细节的处理上则需要好好地下功夫去想,否则最后的程序很可能会出现看上去没有问题,但实际上漏洞百出的状况。

将学过的知识应用到实际中并不简单,只有自己不断尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。

实验二LL(1)分析法一、实验原理:1、写出LL(1)分析法的思想:当一个文法满足LL(1)条件时,我们就可以为它构造一个不带回溯的自上而下的分析程序,这个分析程序是有一组递归过程组成的,每个过程对应文法的一个非终结符。

编译原理的实验报告

编译原理的实验报告

一、实验目的1. 理解编译原理的基本概念和原理。

2. 掌握编译器的各个阶段及其实现方法。

3. 能够运用编译原理的知识解决实际问题。

二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 20194. 实验内容:词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成三、实验内容1. 词法分析(1)实验目的:实现一个简单的词法分析器,将源代码中的字符序列转换为词法符号序列。

(2)实验步骤:1)定义词法符号类型,包括标识符、关键字、运算符、常量等。

2)设计词法分析器算法,对源代码进行遍历,将字符序列转换为词法符号序列。

3)实现词法分析器程序,输出词法符号序列。

(3)实验结果:输入源代码:int a = 10;输出词法符号序列:{<int, int>, <a, a>, <=, =>, <10, 10>, <;, ;>}2. 语法分析(1)实验目的:实现一个简单的语法分析器,将词法符号序列转换为抽象语法树(AST)。

(2)实验步骤:1)定义语法规则,包括产生式、非终结符、终结符等。

2)设计语法分析算法,根据语法规则对词法符号序列进行解析,生成AST。

3)实现语法分析器程序,输出AST。

(3)实验结果:输入词法符号序列:{<int, int>, <a, a>, <=, =>, <10, 10>, <;, ;>}输出AST:```AST:- ExpressionStatement- Expression- BinaryExpression- Identifier: a- Operator: =- Constant: 10```3. 语义分析(1)实验目的:实现语义分析器,对AST进行语义检查,确保程序的正确性。

(2)实验步骤:1)定义语义规则,包括类型检查、作用域检查等。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编译原理实验报告实验名称NFA转换为DFA实验时间2014-5-18院系计算机科学与技术学院班级学号姓名1.试验目的不确定有限状态自动机的确定化(Affirmation of the indefinitely finite automata)2.实验原理一个确定的有限自动机(DFA)M可以定义为一个五元组,M=(K,∑,F,S,Z),其中:(1)K是一个有穷非空集,集合中的每个元素称为一个状态;(2)∑是一个有穷字母表,∑中的每个元素称为一个输入符号;(3)F是一个从K×∑→K的单值转换函数,即F(R,a)=Q,(R,Q∈K)表示当前状态为R,如果输入字符a,则转到状态Q,状态Q称为状态R的后继状态;(4)S∈K,是惟一的初态;(5)Z⊆K,是一个终态集。

由定义可见,确定有限自动机只有惟一的一个初态,但可以有多个终态,每个状态对字母表中的任一输入符号,最多只有一个后继状态。

对于DFA M,若存在一条从某个初态结点到某一个终态结点的通路,则称这条通路上的所有弧的标记符连接形成的字符串可为DFA M所接受。

若M的初态结点同时又是终态结点,则称ε可为M所接受(或识别),DFA M所能接受的全部字符串(字)组成的集合记作L(M)。

一个不确定有限自动机(NFA)M可以定义为一个五元组,M=(K,∑,F,S,Z),其中:(1)k是一个有穷非空集,集合中的每个元素称为一个状态;(2)∑是一个有穷字母表,∑中的每个元素称为一个输入符号;(3)F是一个从K×∑→K的子集的转换函数;(4)S⊆K,是一个非空的初态集;(5)Z⊆K,是一个终态集。

由定义可见,不确定有限自动机NFA与确定有限自动机DFA的主要区别是:(1)NFA的初始状态S为一个状态集,即允许有多个初始状态;(2)NFA中允许状态在某输出边上有相同的符号,即对同一个输入符号可以有多个后继状态。

即DFA中的F是单值函数,而NFA中的F是多值函数。

因此,可以将确定有限自动机DFA看作是不确定有限自动机NFA的特例。

和DFA一样,NFA也可以用矩阵和状态转换图来表示。

对于NFA M,若存在一条从某个初态结点到某一个终态结点的通路,则称这条通路上的所有弧的标记(ε除外)连接形成的字符串可为M所接受。

NFA M所能接受的全部字符串(字)组成的集合记作L(M)。

由于DFA是NFA的特例,所以能被DFA所接受的符号串必能被NFA所接受。

设M1和M2是同一个字母集∑上的有限自动机,若L(M1)=L(M2),则称有限自动机M1和M2等价。

由以上定义可知,若两个自动机能够接受相同的语言,则称这两个自动机等价。

DFA是NFA的特例,因此对于每一个NFA M1总存在一个DFA M2,使得L(M1)=L(M2)。

即一个不确定有限自动机能接受的语言总可以找到一个等价的确定有限自动机来接受该语言。

NFA确定化为DFA同一个字符串α可以由多条通路产生,而在实际应用中,作为描述控制过程的自动机,通常都是确定有限自动机DFA,因此这就需要将不确定有限自动机转换成等价的确定有限自动机,这个过程称为不确定有限自动机的确定化,即NFA 确定化为DFA。

下面介绍一种NFA的确定化算法,这种算法称为子集法:(1)若NFA的全部初态为S1,S2,…,S n,则令DFA的初态为:S=[S1,S2,…,S n],其中方括号用来表示若干个状态构成的某一状态。

(2)设DFA的状态集K中有一状态为[S i,S i+1,…,S j],若对某符号a∈∑,在NFA 中有F({ S i,S i+1,…,S j },a)={ S i’,S i+1’,…,S k’ }则令F({ S i,S i+1,…,S j},a)={ S i’,S i+1’,…,S k’}为DFA的一个转换函数。

若[ S i’,S i+1’,…,S k‘ ]不在K中,则将其作为新的状态加入到K中。

(3)重复第2步,直到K中不再有新的状态加入为止。

(4)上面得到的所有状态构成DFA的状态集K,转换函数构成DFA的F,DFA的字母表仍然是NFA的字母表∑。

(5)DFA中凡是含有NFA终态的状态都是DFA的终态。

对于上述NFA确定化算法——子集法,还可以采用另一种操作性更强的描述方式,下面我们给出其详细描述。

首先给出两个相关定义。

假设I是NFA M状态集K的一个子集(即I∈K),则定义ε-closure(I)为:(1)若Q∈I,则Q∈ε-closure(I);(2)若Q∈I,则从Q出发经过任意条ε弧而能到达的任何状态Q’,则Q’∈ε-closure(I)。

状态集ε-closure(I)称为状态I的ε闭包。

=ε-closure 假设NFA M=(K,∑,F,S,Z),若I∈K,a∈∑,则定义Ia(J),其中J是所有从ε-closure(I)出发,经过一条a弧而到达的状态集。

NFA确定化的实质是以原有状态集上的子集作为DFA上的一个状态,将原状态间的转换为该子集间的转换,从而把不确定有限自动机确定化。

经过确定化后,状态数可能增加,而且可能出现一些等价状态,这时就需要简化。

3.实验内容输入:非确定有限(穷)状态自动机。

输出:确定化的有限(穷)状态自动机4.实验心得此次实验采用了java可视化的界面来编程的,编程的主要思想是:首先构造NFA的状态的子集的算法,再来计算ε-closure。

完成这些子模块的设计后,再通过某一中间模块的总控程序对其调用,最后再由主程序总调用,也就实现了NFA转化为其等价的DFA,接下来就是在实现DFA的化简,最后加以验证,经多次代码的修改成型。

通过实验,我可以更好的掌握了NFA到DFA的转化的原理。

5.实验代码与结果5.1实验运行结果截图如下:左侧为输入的每个NFA的每个状态,右侧为显示的结果,显示了子集个数,和由NFA构造的·DFA状态。

5.2代码:package wy;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Image;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.ArrayList;import javax.swing.*;class Node{ //每一个结点包含的有以该结点为起始的整条边的信息:String data; //本结点值String condition;//条件值空符号串用ε表示String next;//指向下一个结点的结点值Node(String d)//终止结点{data=d;condition=null;next=null;}Node(String d,String c,String s)//非终止结点{data=d;condition=c;next = s; //下一个结点的值}}public class NFA_DFA extends JFrame{public static void main(String[] args) {NFA_DFA nfa_dfa=new NFA_DFA();nfa_dfa.NFA_DFA();}public JLabel jl0 = new JLabel("----每条边的信息如下:----------------");public JLabel jl_start = new JLabel("起点状态:");public JLabel jl_condition = new JLabel("条件:");public JLabel jl_end = new JLabel("终点状态:");public JTextField jtf_start = new JTextField();public JTextField jtf_condition = new JTextField();public JTextField jtf_end = new JTextField();public JButton jbt0 = new JButton("确定");public JLabel jl_start0 = new JLabel("初态:");public JLabel jl_end0 = new JLabel("终态:");public JButton jbt1 = new JButton("确定");public JTextField jtf_start0 = new JTextField();public JTextField jtf_end0 = new JTextField();public JTextArea jta_display = new JTextArea();public JScrollPane sta1 = new JScrollPane(jta_display);public JButton jbt_result = new JButton("结果显示");public JTextArea jta_display1 = new JTextArea();public JScrollPane sta2 = new JScrollPane(jta_display1);public ArrayList<Node> node = new ArrayList<Node>();//非终止结点public ArrayList<Node> node_end = new ArrayList<Node>();//终止结点public ArrayList<String> condition = new ArrayList<String>();//条件符号public ArrayList<ArrayList<String>> C=new ArrayList<ArrayList<String>>();//子集族Cpublic ArrayList<String> CC=new ArrayList<String>();//重命名的Cpublic String start0;//初态值public void NFA_DFA(){this.setTitle("NFA转换为DFA----WY");this.setContentPane(new MyPanel5());this.setLayout(null);this.setSize(700, 700);jl_start0.setBounds(150, 35, 70, 30);add(jl_start0);jtf_start0.setBounds(200, 35,120, 30);add(jtf_start0);jl_end0.setBounds(350, 35, 70, 30);add(jl_end0);jtf_end0.setBounds(400, 35, 120, 30);add(jtf_end0);jbt1.setBounds(555, 35, 60, 30);add(jbt1);jl0.setBounds(200, 80,200, 30);add(jl0);jl_start.setBounds(145, 110, 70, 30);add(jl_start);jl_condition.setBounds(300, 110,50, 30);add(jl_condition);jl_end.setBounds(445, 110, 70, 30);add(jl_end);jtf_start.setBounds(130, 140, 80, 30);add(jtf_start);jtf_condition.setBounds(280, 140,80, 30);add(jtf_condition);jtf_end.setBounds(430, 140, 80, 30);add(jtf_end);jbt0.setBounds(555, 140, 60, 30);add(jbt0);sta1.setBounds(80, 250, 200, 400);add(sta1);sta2.setBounds(300, 250, 300, 400);add(sta2);jbt_result.setBounds(300, 200, 100, 30);add(jbt_result);this.setVisible(true);jta_display.append("每条边的显示:\n");jbt1.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {start0=jtf_start0.getText(); //初态String str3 = jtf_end0.getText();String[] ss3 = new String[100];ss3 = str3.split(","); // 终态在输入的时候以","隔开for (int i = 0; i < ss3.length; i++) {Node node_end0=new Node(ss3[i]);node_end.add(node_end0); //将终态加入终止结点中}}});jbt0.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {jta_display.append(jtf_start.getText()+"—>"+jtf_condition.getText()+"—>"+jtf_end.getText()+"\n");Node node_temp=new Node(jtf_start.getText(),jtf_condition.getText(),jtf_end.getText());node.add(node_temp); //加入非终止结点if(!condition.contains(jtf_condition.getText())&& !jtf_condition.getText().equals("ε"))condition.add(jtf_condition.getText()); //加入条件符号jtf_start.setText(null);jtf_condition.setText(null);jtf_end.setText(null);}});jbt_result.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {myNFA_DFA();}});}public void myNFA_DFA(){ArrayList<Boolean> flag=new ArrayList<Boolean>();//标记//1、找起始结点,计算起始结点的T0=e_closure(start0); 此时T0没有标记,是子集族C中唯一的元素ArrayList<String> T0=new ArrayList<String>();T0=e_closure(start0);C.add(T0);flag.add(false);//此时T0没有标记//2.标记T0;T1=e_closure(move(T0,a)),T2=e_closure(move(T0,b))····,将T1,T2加入C中,但是未标记flag.set(0,true);//标记T0for(int i=0;i<condition.size();i++){ ArrayList<String> T=new ArrayList<String>();ArrayList<String> t1=new ArrayList<String>();t1=move(T0,condition.get(i));T=e_closure0(t1);if(!C.contains(T)){C.add(T);flag.add(false);}}//3.分别标记flag=false的对应的C中的项while(flag.contains(false)){int index=flag.indexOf(false);flag.set(index,true);//标记C的index,即ArrayList<String> C_temp=new ArrayList<String>();C_temp=C.get(index);for(int i=0;i<condition.size();i++){ ArrayList<String> T=new ArrayList<String>();ArrayList<String> t1=new ArrayList<String>();t1=move(C_temp,condition.get(i));T=e_closure0(t1);if(!C.contains(T)){C.add(T);flag.add(false);}}}display();//在文本域中显示结果}public void display(){jta_display1.append("算法终止共构造了"+C.size()+"个子集:\n");for(int i=0;i<C.size();i++){jta_display1.append("T"+i+" = "+C.get(i)+"\n");CC.add("T"+i); //给新得的子集重新命名T1,T2,T3....}jta_display1.append("给定NFA构造的DFA为:\n");jta_display1.append("1、S={");for(int i=0;i<CC.size()-1;i++)jta_display1.append("["+CC.get(i)+"],");jta_display1.append("["+CC.get(CC.size()-1)+"]}\n");jta_display1.append("2、ε={");for(int i=0;i<condition.size()-1;i++)jta_display1.append(CC.get(i)+",");jta_display1.append(CC.get(CC.size()-1)+"}\n");ArrayList<String> D=new ArrayList<String>();D=transform(C);jta_display1.append("3、\n");for(int i=0;i<D.size();i++)jta_display1.append(D.get(i)+"\n");jta_display1.append("4、S0= ["+CC.get(0)+"]\n");jta_display1.append("5、St= ["+CC.get(CC.size()-1)+"]\n");}public ArrayList<String> transform(ArrayList<ArrayList<String>> c){ //转换函数DArrayList<String> r=new ArrayList<String>();ArrayList<String> r_temp = new ArrayList<String>();for(int i=0;i<c.size();i++){ArrayList<String> c_temp = new ArrayList<String>();c_temp=c.get(i);for(int j=0;j<condition.size();j++){r_temp=e_closure0(move(c_temp,condition.get(j)));for(int k=0;k<CC.size();k++){if(r_temp.equals(C.get(k)))r.add(" D( ["+CC.get(i)+"] , "+condition.get(j)+" ) = ["+CC.get(k)+"]");}}}return r;}public ArrayList<String> e_closure0(ArrayList<String> AA){ArrayList<String> T1=new ArrayList<String>();for(int i=0;i<AA.size();i++){ArrayList<String> T=new ArrayList<String>();T=e_closure(AA.get(i));for(int j=0;j<T.size();j++){T1.add(T.get(j));}}return T1;}public ArrayList<String> e_closure(String A){ArrayList<String> T=new ArrayList<String>();for(int k=0;k<node_end.size();k++){if(A.equals(node_end.get(k).data)){if(!T.contains(A))T.add(A); //e_closure()将自身也包含进去的}}for(int i=0;i<node.size();i++){if(A.equals(node.get(i).data) ){if(!T.contains(A))T.add(A); //e_closure()将自身也包含进去的if(node.get(i).condition.equals("ε")){T.add(node.get(i).next); //经过一条ε弧for(int j=0;j<node.size();j++){if(node.get(i).next.equals(node.get(j).data)&& node.get(j).condition.equals("ε")){T.add(node.get(j).next); //经过两条ε弧for(int k=0;k<node.size();k++){if(node.get(j).next.equals(node.get(k).data)&& node.get(k).condition.equals("ε")){T.add(node.get(k).next); //经过三条ε弧for(int m=0;m<node.size();m++){ if(node.get(k).next.equals(node.get(m).data)&&node.get(m).condition.equals("ε")){T.add(node.get(m).next); //经过四条ε弧}}}}}}}}}return T;}public ArrayList<String> move(ArrayList<String> TT,String a){ //move(I,a)函数ArrayList<String> T=new ArrayList<String>();for(int i=0;i<TT.size();i++){for(int j=0;j<node.size();j++){if(TT.get(i).equals(node.get(j).data) && node.get(j).condition.equals(a)){T.add(node.get(j).next);}}}return T;}}class MyPanel5 extends JPanel {public void paintComponent(Graphics g) {Graphics2D g2 = (Graphics2D) g;super.paintComponent(g);Image img = Toolkit.getDefaultToolkit().getImage("./src/1.jpg");g2.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);}}。

相关文档
最新文档