编译原理实验四
编译原理语法分析实验报告
编译原理语法分析实验报告第一篇:编译原理语法分析实验报告实验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-逆波兰
计算机硬件实验室实验报告姓名学号班级成绩设备名称及软件环境逆波兰一、实验目的:将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
二、实验要求:输出的格式如下:(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:语法分析实
验报告
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编译程序实验指的是一项编译器开发实验,旨在让学生通过实践掌握编译器的设计和实现原理。
该实验一般分为以下几个步骤:
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 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 掌握C++语言编译的语法分析程序2 分别掌握LL(1)、算符优先、LR等语法分析方法的构造。
二、实验环境Microsoft Visual C++ 6.0三、实验内容给定某一文法,试构造其简单优先矩阵(或LL(1)矩阵),并编制程序。
给出相应句子的语法分析过程,判其正确性。
例如:给定文法G:E→T E1E1→+TE1/εT→FT1T1→*F/εF→id/(E)(1)先构造其SELECT集合,判定其是否为LL(1)文法(2)是则构造其分析表(3)给出句子id+id*id$的语法分析过程四、设计说明LL(1):#include<stdio.h>#include<string>typedef int datatype;char a[N3]={'$','E'};char c[N4]={'$','z','*','z','+','z'};char *B[N1][N2]={" ", "z ", "+ " , "*" , "(" , ")", "$ ","E " , "xT", " " , " ", "xT", " ", " ","x ", " ", "xT+", " ", " ", "", "","T ", "yF", " ", " ", "yF ", " ", " ","y ", " ", "", "yF*", " ", "" , "","F ", "z", " ", " ", ")E(", " ", " ",};void FXB(){int i,j;cout<<"分析表为: "<<endl;for(i=0;i<N1;i++){for(j=0;j<N2;j++){cout<<B[i][j]<<" "; }cout<<endl;}}void WF(){ int s;char *w[5]={"E->TE'","E'->TE'/e","T->FT'","T'->*F/e","F->(E)/id"}; cout<<"文法为: "<<endl;for(s=0;s<5;s++){cout<<w[s]<<endl;}}void SELECT(){cout<<"SELECT集合为:"<<endl;cout<<"1. select(E->TE')=FIRST(TE')={(,id}"<<endl;cout<<"2. select(E'->+TE')=FIRST(+TE')={+}"<<endl;cout<<"3. select(E'->e)=FIRST(E)UFOLLOW(E')-{e}={$,)}"<<endl;cout<<"4. select(T->FT')={(,id}"<<endl;cout<<"5. select(T'->*F)={*}"<<endl;cout<<"6. select(T'->e)={+,),$}"<<endl;cout<<"7. select(F->(E))={(}"<<endl;cout<<"8. select(F->id)={id}"<<endl;cout<<"为LL(1)文法"<<endl;}void showa(){ int i;cout<<"分析栈为:"<<endl;for(i=0;i<N3;i++){if(a[i]!=0) cout<<a[i];}cout<<endl;}void showb(){ int j;cout<<"输入流为:"<<endl;for(j=0;j<N4;j++){if(c[j]!=NULL) cout<<c[j];}cout<<endl;}void FX(){cout<<"分析如下:"<<endl;showa();showb();int i,j,m,n;i=I();j=J();m=M();n=N();while(a[m]!='$'){if ((a[m]!=c[n])&&(B[i][j]!=NULL)){a[m]=B[i][j][0];a[m+1]=B[i][j][1];a[m+2]=B[i][j][2];showa();showb();m=M();n=N();if(a[m]==c[n]){ }else{m=M();n=N();i=I();j=J();}}else if(a[m]==c[n]){a[m]=NULL; c[n]=NULL;showa();showb();m=M();n=N();i=I();j=J();}}}void main(){WF();SELECT();FXB();FX();}算符优先:void main(){ int i,j,k=0;printf("请输入文法规则数:");scanf("%d",&r);printf("请输入文法规则:\n");for(i=0;i<r;i++){scanf("%s",st[i]);//存储文法规则,初始化FIRSTVT集和LASTVT集first[i][0]=0;/*first[i][0]和last[i][0]分别表示st[i][0]非终极符的FIRSTVT集和LASTVT集中元素的个数*/last[i][0]=0;}for(i=0;i<r;i++) //判断文法是否合法{for(j=0;st[i][j]!='\0';j++){if(st[i][0]<'A'||st[i][0]>'Z'){printf("不是算符文法!\n"); exit(-1);}if(st[i][j]>='A'&&st[i][j]<='Z'){if(st[i][j+1]>='A'&&st[i][j+1]<='Z'){printf("不是算符文法!\n");exit(-1);}}}}for(i=0;i<r;i++){for(j=0;st[i][j]!='\0';j++){if((st[i][j]<'A'||st[i][j]>'Z')&&st[i][j]!='-'&&st[i][j]!='>'&&st[i][j]!='|')lable[k++]=st[i][j];}}lable[k]='#';lable[k+1]='\0'; table();printf("每个非终结符的FIRSTVT集为:\n"); //输出每个非终结符的FIRSTVT集for(i=0;i<r;i++){ printf("%c: ",st[i][0]);for(j=0;j<first[i][0];j++){printf("%c ",first[i][j+1]);}printf("\n");}printf("每个非终结符的LASTVT集为:\n"); //输出每个非终结符的LASTVT集for(i=0;i<r;i++){ printf("%c: ",st[i][0]);for(j=0;j<last[i][0];j++){printf("%c ",last[i][j+1]);}printf("\n");}printf("算符优先分析表如下:\n");for(i=0;lable[i]!='\0';i++)printf("\t%c",lable[i]);printf("\n");for(i=0;i<k+1;i++){ printf("%c\t",lable[i]);for(j=0;j<k+1;j++){printf("%c\t",data[i][j]);}printf("\n");}printf("请输入文法输入符号串以#结束:");scanf("%s",input);deal();}int deal(){ int i,j;int x,y;int z; //输入串的长度k=1;s[k]='#'; //栈置初值for(i=0;input[i]!='\0';i++); //计算输入串的长度z=i--;i=0;while((a=input[i])!='\0'){ if(zhongjie(s[k]))j=k;elsej=k-1;x=xiabiao(s[j]);y=xiabiao(a);if(data[x][y]=='>'){ out(1,k,s);printf("%c",a);out(i+1,z,input);printf("规约\n");do{ q=s[j];if(zhongjie(s[j-1]))j=j-1;else j=j-2;x=xiabiao(s[j]);y=xiabiao(q);}while(data[x][y]!='<');int m,n,N;for(m=j+1;m<=k;m++){for(N=0;N<r1;N++)for(n=1;string[N][n]!='\0';n++){if(!zhongjie(s[m])&&!zhongjie(string[N][n])){if(zhongjie(s[m+1])&&zhongjie(string[N][n+1])&&s[m+1]==string[N][n+1]){s[j+1]=string[N][0]; break;}}elseif(zhongjie(s[m]))if(s[m]==string[N][n]){s[j+1]=string[N][0]; break;}}}k=j+1;if(k==2&&a=='#'){ out(1,k,s);printf("%c",a);out(i+1,z,input);printf("结束\n");printf("输入串符合文法的定义!\n");return 1; //输入串符合文法的定义}}elseif(data[x][y]=='<'||data[x][y]=='='){ //移进out(1,k,s);printf("%c",a);out(i+1,z,input);printf("移进\n");k++;s[k]=a;i++;}else{printf("\nflase");return 0;}}printf("\nflase");return 0;}SLR(1):void main(){string a[12][9]={{"s5","e","e","s4","e","e", "1","2","3"},{"e","s6","e","e","e","ACC", "e","e","e"},{"e","r2","s7","e","r2","r2", "e","e","e"},{"e","r4","r4","e","r4","r4", "e","e","e"},{"s5","e","e","s4","e","e", "8","2","3"},{"e","r6","r6","e","r6","r6", "e","e","e"},{"s5","e","e","s4","e","e", "e","9","3"},{"s5","e","e","s4","e","e", "e","e","a"},{"e","s6","e","e","sb","e", "e","e","e"},{"e","r1","s7","e","r1","r1", "e","e","e"},{"e","r3","r3","e","r3","r3", "e","e","e"},{"e","r5","r5","e","r5","r5", "e","e","e"}};string s[7]={"","E6","E2","T6", "T2","F6","F2"};char c,cc;string myss="";int flag=0; //看数字或标示符是否结束list<char> ss,ll;list<char>::iterator myit;cout<<"请输入要分析的表达式:"<<endl;while((c=getchar())!='\n'){flag=0;while(isdigit(c)||isalpha(c)){flag=1;c=getchar();}if(flag) ss.push_back('I');if(c=='\n')break;ss.push_back(c);}ss.push_back('$');ll.push_back('$');ll.push_back('0');while(1){if(get(ss.front())!=-1) //输入栈myss=a[getI(ll.back())][get(ss.front())];else {cout<<"错误!"<<endl;break;}if(myss.at(0)=='s') {ll.push_back(ss.front()); //i进入ss.pop_front(); //将I删除ll.push_back(myss.at(1)); //5进入}else if(myss.at(0)=='r'){for(int i=0;i<s[myss.at(1)-48].at(1)-48;i++)ll.pop_back(); //出栈n位cc=ll.back(); //保存当前状态ll.push_back(s[myss.at(1)-48].at(0)); //大写字母ll.push_back(a[getI(cc)][get(ll.back())].at(0));}else if(myss.at(0)=='e') {cout<<"错误!"<<endl;break;}else if(myss.at(0)=='A') {cout<<"匹配成功!"<<endl;break;}for(myss="",myit=ll.begin();myit!=ll.end();myit++)myss+=*myit;cout<<left<<setw(18)<<myss;for(myss="",myit=ss.begin();myit!=ss.end();myit++)myss+=*myit;cout<<right<<setw(16)<<myss;cout<<endl;}cout<<"分析完毕!"<<endl;}运行结果:输入流:算符优先:五、实验总结通过编写算法,对三种方法都有了更好的了解,对编译原理这门课也有了更清晰的认识。
编译原理实验大纲
编译原理实验大纲1.实验简介-介绍编译原理实验的目的和意义。
-解释编译原理实验的基本原理和流程。
2.实验环境搭建-说明实验所需的软件工具和开发环境。
-指导学生安装和设置实验环境。
3.实验一:词法分析器设计-介绍词法分析器的作用和原理。
-分析需求,设计词法分析器的数据结构和算法。
-实现基于所设计算法的词法分析器。
-编写测试用例,验证词法分析器的功能和正确性。
4.实验二:语法分析器设计-介绍语法分析器的作用和原理。
-分析需求,设计语法分析器的数据结构和算法。
-实现基于所设计算法的语法分析器。
-编写测试用例,验证语法分析器的功能和正确性。
5.实验三:语义分析器设计-介绍语义分析器的作用和原理。
-分析需求,设计语义分析器的数据结构和算法。
-实现基于所设计算法的语义分析器。
-编写测试用例,验证语义分析器的功能和正确性。
6.实验四:中间代码生成-介绍中间代码生成的作用和原理。
-分析需求,设计中间代码生成的数据结构和算法。
-实现基于所设计算法的中间代码生成器。
-编写测试用例,验证中间代码生成器的功能和正确性。
7.实验五:目标代码生成-介绍目标代码生成的作用和原理。
-分析需求,设计目标代码生成的数据结构和算法。
-实现基于所设计算法的目标代码生成器。
-编写测试用例,验证目标代码生成器的功能和正确性。
8.实验六:优化与调试-介绍编译优化和调试的基本概念。
-分析已实现的编译器的性能和问题。
-提出优化方案,并实现相应的优化功能。
-进行性能测试和调试,验证优化效果和解决问题。
9.实验七:实验报告撰写-分析实验过程和结果,总结经验和收获。
-撰写实验报告,包括实验目的、原理、实现过程、结果分析等内容。
-提交实验报告并进行评分评比。
10.总结与展望-对实验进行总结,回顾实验目标和实现情况。
-展望未来的发展方向和对编译原理的深入研究。
以上为编译原理实验的大纲,通过完成这些实验,学生可以深入理解编译原理的基本原理和算法,并掌握编译器的设计与实现方法。
《编译原理》实验教学大纲
《编译原理》实验教学大纲一、实验目的和任务编译原理是计算机科学与技术专业的一门重要课程,它主要研究的是将高级语言程序翻译成机器语言程序的方法和技术。
通过本实验课程的学习,旨在使学生掌握编译原理的基本原理和方法,培养学生对编译器结构与构造技术的专门知识和技能,为学生今后进行编译器设计与实现打下基础。
二、实验设备和工具1.计算机和相关硬件设备2. 编程语言的开发环境,如C/C++或Java三、实验内容1.实验一:词法分析器设计与实现a)实验目的:学习词法分析器的原理和设计方法,掌握正则表达式、DFA和NFA的转换方法。
b)实验任务:i.设计并实现一个词法分析器的原型,能够正确地识别出给定的程序中的词法单元。
ii. 使用给定的正则表达式设计并实现识别给定程序中的关键字、标识符、常量等的词法分析器。
2.实验二:语法分析器设计与实现a)实验目的:学习语法分析器的原理和设计方法,掌握上下文无关文法和LR分析表的构造方法。
b)实验任务:i.学习并理解上下文无关文法和LR分析表的构造方法。
ii. 设计并实现一个简单的递归下降语法分析器。
3.实验三:语义分析器设计与实现a)实验目的:学习语义分析器的原理和设计方法,掌握语义动作的定义和处理方法。
b)实验任务:i.学习并理解语义分析器的原理和设计方法。
ii. 设计并实现一个简单的语义分析器,能够对给定的程序进行语义分析和语义动作的处理。
4.实验四:中间代码生成器设计与实现a)实验目的:学习中间代码生成器的原理和设计方法,掌握中间代码的生成和优化方法。
b)实验任务:i.学习并理解中间代码生成器的原理和设计方法。
ii. 设计并实现一个简单的中间代码生成器,能够将给定的程序翻译成中间代码。
5.实验五:目标代码生成器设计与实现a)实验目的:学习目标代码生成器的原理和设计方法,掌握目标代码的生成和优化方法。
b)实验任务:i.学习并理解目标代码生成器的原理和设计方法。
ii. 设计并实现一个简单的目标代码生成器,能够将中间代码翻译成目标代码。
编译原理实验教案
一、实验目的与要求1. 实验目的(1) 理解编译原理的基本概念和流程。
(2) 掌握常用的编译方法和技术。
(3) 熟练使用编译器开发工具。
2. 实验要求(1) 熟悉计算机专业基础知识。
(2) 掌握C/C++编程语言。
(3) 了解基本的编译原理。
二、实验环境1. 硬件环境(1) 计算机一台。
(2) 编译器开发工具(如GCC、Clang等)。
2. 软件环境(1) 操作系统(如Windows、Linux等)。
(2) 文本编辑器或集成开发环境(如Visual Studio、Eclipse等)。
三、实验内容1. 实验一:词法分析(1) 实现一个简单的词法分析器,识别出关键字、标识符、常量等。
(2) 分析输入的程序,输出词法分析结果。
2. 实验二:语法分析(1) 实现一个简单的语法分析器,根据给定的语法规则分析输入的程序。
(2) 分析输入的程序,输出语法分析树。
3. 实验三:语义分析(1) 实现一个简单的语义分析器,检查程序中的语义错误。
(2) 分析输入的程序,输出语义分析结果。
4. 实验四:中间代码(1) 实现一个简单的中间代码器,将转换为中间代码表示。
(2) 对输入的程序进行转换,输出中间代码。
5. 实验五:目标代码(1) 实现一个简单的目标代码器,将中间代码转换为目标代码。
(2) 对输入的中间代码进行转换,输出目标代码。
四、实验步骤与方法1. 实验一:词法分析(1) 编写词法分析器的代码。
(2) 测试并调试词法分析器。
2. 实验二:语法分析(1) 编写语法分析器的代码。
(2) 测试并调试语法分析器。
3. 实验三:语义分析(1) 编写语义分析器的代码。
(2) 测试并调试语义分析器。
4. 实验四:中间代码(1) 编写中间代码器的代码。
(2) 测试并调试中间代码器。
5. 实验五:目标代码(1) 编写目标代码器的代码。
(2) 测试并调试目标代码器。
五、实验注意事项1. 按照实验要求编写代码,注意代码规范和可读性。
《编译原理》课程实验报告(词法分析)完整版
《编译原理》课程实验报告题目词法分析专业计算机指导教师签名华东理工大学信息学院计算机系2013年4月10日一.实验序号:《编译原理》第一次实验二.实验题目:词法分析三.实验日期:2013.3.27-2013.4.10四.实验环境(操作系统,开发语言)操作系统:Windows开发语言:C五.实验要求●修改词法:1)将标识符的词法改为“以大写字母或小写字母开头,后面可以跟大写字母或小写字母或数字或下划线”。
把while ((isalpha(buffer))||(isdigit(buffer)))改成while ((isalpha(buffer))||(isdigit(buffer))||buffer==’_’)2)将<条件>中的表示相等关系的单词“=”改为“= =”char *relation[6]={"<","<=","=",">",">=","<>"};把其中的=改成==即可3)将原来无小数的数改为可以有小数的数把while (isdigit(buffer))改成while (isdigit(buffer)||buffer==’.’)●用C语言开发词法分析程序。
读入用PL/0语言编写的测试用例源程序,将识别出的一个个单词组成单词流依序同时输出到屏幕和文件中。
六.实验步骤1)根据修改词法后的PL/0语言编写测试用例源程序。
2)用C语言编写词法分析程序。
读入PL/0语言的测试用例源程序,进行词法分析,将识别出的一个个单词组成单词流依序同时输出到屏幕和文件中。
3)设立断点,单步运行词法分析程序,依次单个输出单词。
分析和理解词法分析程序,解释词法分析程序中的数据和变量变化的原因和输出结果。
七.实验结果(测试用例源程序,运行结果部分截图,词法分析函数主要部分源程序PL0程序:const a=6,b=81;var x,y;procEdure p;procedure q;x:=2;beginx:=1;write(x);end;begincall p;end.C程序:#include <stdio.h>#include <ctype.h>#include <malloc.h>#include <stdlib.h>#include <string.h>#define NULL 0FILE *fp;char cbuffer;char*key[19]={"auto","break","case","char","const","continue","default","do"," double","else","enum","extern","float","for","goto","if","int","long","register"};char *border[6]={",",";","{","}","(",")"};char *arithmetic[4]={"+","-","*","/"};char *relation[6]={"<","<=","=",">",">=","<>"};char *consts[11]={"0","1","2","3","4","5","6","7","8","9","."};char *label[20];int labelnum=0;int search(char searchchar[],int wordtype){ int i=0;switch (wordtype) {case 1:for (i=0;i<=18;i++){ if (strcmp(key[i],searchchar)==0){return(1);}}return(0);break;case 2:{for (i=0;i<=5;i++){ if (strcmp(border[i],searchchar)==0)return(i+1);} return(0);}break;case 3:{for (i=0;i<=3;i++){ if (strcmp(arithmetic[i],searchchar)==0){ return(1);}}return(0);}break;case 4:{for (i=0;i<=5;i++){ if (strcmp(relation[i],searchchar)==0){ return(1);}}return(0);}break;case 5:{for (i=0;i<=10;i++){ if (strcmp(consts[i],searchchar)==0){return;}}return(0);}break;}}char alphaprocess(char buffer){ int atype;int i=-1;char alphatp[20];while ((isalpha(buffer))||(isdigit(buffer))){ alphatp[++i]=buffer;buffer=fgetc(fp);}alphatp[i+1]='\0';atype=search(alphatp,1);if(atype==1){printf("%s \t 保留字\n",alphatp);}//结束if(atype==0){printf("%s \t 标示符\n",alphatp);}return(buffer);}char digitprocess(char buffer){ int i=-1;char digittp[20];int dtype;while (isdigit(buffer)){ digittp[++i]=buffer;buffer=fgetc(fp);}digittp[i+1]='\0';dtype=search(digittp,5);if(dtype==1)printf("%s \t 数字\t %s\n",digittp,digittp);return(buffer);}char otherprocess(char buffer){ int i=-1;char othertp[20];int otype,otypetp;othertp[0]=buffer;othertp[1]='\0';otype=search(othertp,3);if (otype==1){ printf("%s \t 运算符\n",othertp);buffer=fgetc(fp);goto out;}otype=search(othertp,4);if (otype==1){ buffer=fgetc(fp);othertp[1]=buffer;othertp[2]='\0';otypetp=search(othertp,4);if (otypetp==1){ printf("%s \t 运算符\n",othertp);goto out;}elseothertp[1]='\0';printf("%s \t 运算符\n",othertp);goto out;}if (buffer==':'){ buffer=fgetc(fp);if (buffer=='=')printf(":= \t 运算符\n");buffer=fgetc(fp);goto out;}else{ if (otype=search(othertp,2)){ printf("%s \t 界符\n",othertp);buffer=fgetc(fp);goto out;}}if ((buffer!='\n')&&(buffer!=' '))printf("%c error,not a word\n",buffer);buffer=fgetc(fp);out: return(buffer);}void main(){if ((fp=fopen("example.txt","r"))==NULL)printf("error");else{cbuffer = fgetc(fp);while (cbuffer!=EOF){if (isalpha(cbuffer))cbuffer=alphaprocess(cbuffer);else if (isdigit(cbuffer))cbuffer=digitprocess(cbuffer);elsecbuffer=otherprocess(cbuffer);}printf("over\n");getchar();}}八.实验体会(词法分析程序修改的地方,解决问题的方法、心得体会等)通过本次试验,了解了词法分析的主要步骤,就是把标识符,保留字区分,并且能识别出空格,并把数据能从文件中读出来,主要识别标识符和保留字,主要通过比较参照一个事先建好的数组,里面包含了所有的保留字,不在其中的便是标识符。
编译原理实验4 算符优先语法分析- 解析
步骤3:构造算符优先分析表
优先关系:
设G是一个不含 产生式的算符文法,令 a、b是任意两个VT , P、Q、R ∈ VN ,则:
(1) ab 当且仅当文法G中含有形如P …ab…或P …aQb…的产生式 (2) a<b 当且仅当G中含有形如P …aR…的产生式,R而Rb… 或R Qb… (3) a>b 当且仅当G中含有形如P …Rb…的产生式,R而R…a 或R …aQ
<
i
i )#
#N*(N+ i >
)
)#
#N*(N+N >
)
)#
*i ⋖⋖ ⋗⋖ ⋗ ⋖⋖ ⋗ ⋖⋖
动作
移进
归约
移进
移进
移进
归约
移进
移进
归约
归约
()
#
⋖⋗ ⋗
⋖⋗ ⋗
⋗⋗
⋖
⋗⋗
⋖
最左素短语
i
i
i N+N
分析过程
示例:描述句子i*( i+i )的 分析过程。
栈
关系 当前符
+ +⋗ *⋗ i⋗ (⋖ )⋗ #⋖
如何识别最左素短语?
• 素短语
– 是指这样一种短语,它至少包含一个终结符,并且除 自身之外,不再包含其它更小的素短语。
• 最左素短语
– 句型最左边的那个素短语。
如何识别最左素短语?
定理:
一个OPG文法G的任何句型: #N1a1N2a2…NnanNn+1# (其中Ni可空) 的最左素短语Nj aj … Ni ai Ni+1 是满足如下三个条件的最 左子串: (1)aj-1 ⋖ aj (2)aj =·aj+1 =·… =·ai-1 =·ai (3)ai ⋗ ai+1
编译原理实验报告
编译原理实验报告编译原理实验报告一、引言编译原理是计算机科学中的重要课程之一,它研究的是如何将高级语言程序转化为机器语言程序的过程。
在本次实验中,我们将学习并实践编译原理中的一些基本概念和技术,包括词法分析、语法分析和语义分析等。
二、词法分析词法分析是编译过程中的第一步,它负责将源程序中的字符序列转化为有意义的词法单元。
在本次实验中,我们使用了Flex工具来生成词法分析器。
通过定义一系列正则表达式和对应的动作,我们可以将源程序中的字符序列识别为不同的词法单元,如标识符、关键字、运算符等。
三、语法分析语法分析是编译过程中的第二步,它负责将词法单元序列转化为抽象语法树。
在本次实验中,我们使用了Bison工具来生成语法分析器。
通过定义一系列文法规则和对应的动作,我们可以将词法单元序列转化为抽象语法树,并进行语法错误的检测和恢复。
四、语义分析语义分析是编译过程中的第三步,它负责对抽象语法树进行语义检查和语义动作的执行。
在本次实验中,我们通过自定义语义规则和对应的动作,对抽象语法树进行类型检查、符号表管理等操作。
同时,我们还实现了一些简单的语义动作,如计算表达式的值、生成中间代码等。
五、中间代码生成中间代码生成是编译过程中的一项重要任务,它负责将源程序转化为机器无关的中间表示形式。
在本次实验中,我们使用了三地址码作为中间表示形式。
通过对抽象语法树的遍历和一系列的转换规则,我们可以将源程序转化为等价的三地址码表示形式。
六、实验结果与分析通过对一些简单的测试程序的编译,我们验证了我们所实现的词法分析、语法分析、语义分析和中间代码生成的正确性。
同时,我们还进行了一些性能测试,对比了不同算法和数据结构在编译过程中的效率差异。
实验结果表明,我们所实现的编译器在处理大规模程序时具有较好的性能。
七、结论通过本次实验,我们深入了解了编译原理中的一些基本概念和技术,并通过实践加深了对编译过程的理解。
同时,我们也意识到编译器的设计和实现是一项复杂而有挑战性的任务,需要综合运用多种算法和数据结构。
编译原理教程实验报告
一、实验目的本次实验旨在使学生通过编译原理的学习,了解编译程序的设计原理及实现技术,掌握编译程序的各个阶段,并能将所学知识应用于实际编程中。
二、实验内容1. 词法分析2. 语法分析3. 语义分析4. 中间代码生成5. 代码优化6. 目标代码生成三、实验步骤1. 词法分析(1)设计词法分析器,识别输入源代码中的各种词法单元;(2)使用C语言实现词法分析器,并进行测试。
2. 语法分析(1)根据文法规则设计语法分析器,识别输入源代码的语法结构;(2)使用C语言实现语法分析器,并进行测试。
3. 语义分析(1)设计语义分析器,检查语法分析后的语法树,确保语义正确;(2)使用C语言实现语义分析器,并进行测试。
4. 中间代码生成(1)设计中间代码生成器,将语义分析后的语法树转换为中间代码;(2)使用C语言实现中间代码生成器,并进行测试。
5. 代码优化(1)设计代码优化器,对中间代码进行优化,提高程序性能;(2)使用C语言实现代码优化器,并进行测试。
6. 目标代码生成(1)设计目标代码生成器,将优化后的中间代码转换为特定目标机的汇编语言;(2)使用C语言实现目标代码生成器,并进行测试。
四、实验结果与分析1. 词法分析实验结果:成功识别输入源代码中的各种词法单元,包括标识符、关键字、运算符、常量等。
2. 语法分析实验结果:成功识别输入源代码的语法结构,包括表达式、语句、程序等。
3. 语义分析实验结果:成功检查语法分析后的语法树,确保语义正确。
4. 中间代码生成实验结果:成功将语义分析后的语法树转换为中间代码,为后续优化和目标代码生成提供基础。
5. 代码优化实验结果:成功对中间代码进行优化,提高程序性能。
6. 目标代码生成实验结果:成功将优化后的中间代码转换为特定目标机的汇编语言,为程序在目标机上运行做准备。
五、实验心得1. 编译原理是一门理论与实践相结合的课程,通过本次实验,我对编译程序的设计原理及实现技术有了更深入的了解。
《编译原理》科学实验指导说明书
《编译原理》实验指导书实验一词法分析器的设计一、实验目的和要求加深对状态转换图的实现及词法分析器的理解。
熟悉词法分析器的主要算法及实现过程。
要求学生掌握词法分析器的设计过程,并实现词法分析。
二、实验基本内容给出一个简单语言的词法规则,画出状态转换图,并依据状态转换图编制出词法分析程序,能从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单Error”,然后跳过错误部分继续显示)词法规则如下:三、实验时间:上机三次。
第一次按照自己的思路设计一个程序。
第二、三次在理论课学习后修改程序,使得程序结构更加合理。
四、实验过程和指导:(一)准备:1.阅读课本有关章节(c/c++,数据结构),花一周时间明确语言的语法,写出基本算法以及采用的数据结构和要测试的程序例。
2.初步编制好程序。
3.准备好多组测试数据。
(二)上课上机:将源代码拷贝到机上调试,发现错误,再修改完善。
(三)程序要求:程序输入/输出示例:输入如下一段:main(){/*一个简单的c++程序*/int a,b; //定义变量a = 10;b = a + 20;}要求输出如右图。
要求:(1) 剔除注解符(2) 常数为无符号整数(可增加实型数,字符型数等)(四)练习该实验的目的和思路:程序开始变得复杂起来,可能是大家以前编过的程序中最复杂的,但相对于以后的程序来说还是简单的。
因此要认真把握这个过渡期的练习。
程序规模大概为200行及以上。
通过练习,掌握对字符进行灵活处理的方法。
(五)为了能设计好程序,注意以下事情:1.模块设计:将程序分成合理的多个模块(函数/类),每个模块(类)做具体的同一事情。
2.写出(画出)设计方案:模块关系简图、流程图、全局变量、函数接口等。
3.编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
4.程序设计语言不限,建议使用面向对象技术及可视化编程语言,如C++,VC,JA V A,VJ++等。
编译原理实验报告
实验五: 设计一个算法,求出任一上下文无关文法中所有导空符号,并输出。
实验六: 检查某段C源程序中,标识符的使用是否正确,即是否先声明后使用,或重复声明。假设数据类型只有int,float,double,char。
break;
}
if(temp[n*13+n2]=='k'&&zt[m]==0) //那些不能推出 空,但是因为要加入 其他非终结符的first集 而可能含有 空
n2++;
else if(n3>=n1) //for循环结束是因为n3而不是break ,即无相同字符
while(temp[n*13+n2]!='\0') //把z[n]对应的first加入temp[m*13+n1]这个first中,每个字符依次加在最后
{
for(n3=0;n3<n1;n3++) //循环判定是否有相同的字符
{
if(temp[m*13+n3]==temp[n*13+n2])
}
n++;
}
break; //break位于if(gs[n]==z2[m]),对于gs[n]已找到z2[m]完成任务跳出for循环
}
}
n2=m; //存放该for循环中m的值
n++;
}
//进一步处理集除去非终结符
m=0;n=0;n1=0;n2=0;
else n2++;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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);}}。