编译原理实验报告5-语法分析程序的设计(2)

合集下载

编译原理 实验报告

编译原理 实验报告

编译原理实验报告编译原理实验报告引言编译原理是计算机科学中的重要课程,它研究的是如何将高级语言程序转化为机器语言程序的过程。

在本次实验中,我们学习了编译原理的基本概念和技术,并通过实践来加深对这些概念和技术的理解。

本报告将对我们在实验中遇到的问题、解决方案以及实验结果进行总结和分析。

实验目的本次实验的主要目的是设计并实现一个简单的编译器,能够将类C语言的源代码翻译成目标代码。

通过这个实验,我们可以更好地理解编译器的工作原理,掌握编译器设计的基本方法和技术。

实验过程在实验中,我们首先对给定的类C语言的语法进行了分析,并根据语法规则设计了相应的语法分析器。

然后,我们使用了自顶向下的递归下降分析法来实现语法分析器。

在实现语法分析器的过程中,我们遇到了一些问题,例如如何处理语法规则中的左递归、如何处理语法规则中的优先级和结合性等。

通过仔细研究相关的文献和资料,我们成功地解决了这些问题,并完成了语法分析器的设计和实现。

接下来,我们对语法分析器进行了测试,并对测试结果进行了分析。

通过测试,我们发现语法分析器在处理简单的源代码时能够正确地识别出语法错误,并给出相应的错误提示。

然而,在处理复杂的源代码时,语法分析器可能会出现一些错误,例如无法正确地处理嵌套的语法结构、无法正确地处理运算符的优先级和结合性等。

为了解决这些问题,我们对语法分析器进行了改进,并进行了多次测试,最终得到了令人满意的结果。

实验结果通过本次实验,我们成功地设计并实现了一个简单的编译器,能够将类C语言的源代码翻译成目标代码。

在实验中,我们对编译器的工作原理有了更深入的了解,掌握了编译器设计的基本方法和技术。

同时,我们也发现了一些问题,并通过不断地改进和测试,最终得到了令人满意的结果。

结论编译原理是一门重要的计算机科学课程,它研究的是如何将高级语言程序转化为机器语言程序的过程。

通过本次实验,我们对编译原理的基本概念和技术有了更深入的了解,并通过实践来加深了对这些概念和技术的理解。

编译原理实验报告

编译原理实验报告

编译原理实验报告一、实验目的和要求本次实验旨在对PL_0语言进行功能扩充,添加新的语法特性,进一步提高编译器的功能和实用性。

具体要求如下:1.扩展PL_0语言的语法规则,添加新的语法特性;2.实现对新语法的词法分析和语法分析功能;3.对扩展语法规则进行语义分析,并生成中间代码;4.验证扩展功能的正确性。

二、实验内容1.扩展语法规则本次实验选择扩展PL_0语言的语句部分,添加新的控制语句,switch语句。

其语法规则如下:<switch_stmt> -> SWITCH <expression> CASE <case_list><default_stmt> ENDSWITCH<case_list> -> <case_stmt> , <case_stmt> <case_list><case_stmt> -> CASE <constant> : <statement><default_stmt> -> DEFAULT : <statement> ,ε2.词法分析和语法分析根据扩展的语法规则,需要对新的关键字和符号进行词法分析,识别出符号类型和记号类型。

然后进行语法分析,建立语法树。

3.语义分析在语义分析阶段,首先对switch语句的表达式进行求值,判断其类型是否为整型。

然后对case语句和default语句中的常量进行求值,判断是否与表达式的值相等。

最后将语句部分生成中间代码。

4.中间代码生成根据语法树和语义分析的结果,生成对应的中间代码。

例如,生成switch语句的跳转表,根据表达式的值选择相应的跳转目标。

5.验证功能的正确性设计一些测试用例,验证新语法的正确性和扩展功能的实用性。

三、实验步骤与结果1.扩展语法规则,更新PL_0语法分析器的词法规则和语法规则。

编译原理实验报告

编译原理实验报告

编译原理实验报告一、实验目的本次编译原理实验的主要目的是通过实践加深对编译原理中词法分析、语法分析、语义分析和代码生成等关键环节的理解,并提高实际动手能力和问题解决能力。

二、实验环境本次实验使用的编程语言为 C/C++,开发工具为 Visual Studio 2019,操作系统为 Windows 10。

三、实验内容(一)词法分析器的设计与实现词法分析是编译过程的第一个阶段,其任务是从输入的源程序中识别出一个个具有独立意义的单词符号。

在本次实验中,我们使用有限自动机的理论来设计词法分析器。

首先,我们定义了单词的种类,包括关键字、标识符、常量、运算符和分隔符等。

然后,根据这些定义,构建了相应的状态转换图,并将其转换为程序代码。

在实现过程中,我们使用了字符扫描和状态转移的方法,逐步读取输入的字符,判断其所属的单词类型,并将其输出。

(二)语法分析器的设计与实现语法分析是编译过程的核心环节之一,其任务是在词法分析的基础上,根据给定的语法规则,判断输入的单词序列是否构成一个合法的句子。

在本次实验中,我们采用了自顶向下的递归下降分析法来实现语法分析器。

首先,我们根据给定的语法规则,编写了相应的递归函数。

每个函数对应一种语法结构,通过对输入单词的判断和递归调用,来确定语法的正确性。

在实现过程中,我们遇到了一些语法歧义的问题,通过仔细分析语法规则和调整函数的实现逻辑,最终解决了这些问题。

(三)语义分析与中间代码生成语义分析的任务是对语法分析所产生的语法树进行语义检查,并生成中间代码。

在本次实验中,我们使用了四元式作为中间代码的表示形式。

在语义分析过程中,我们检查了变量的定义和使用是否合法,类型是否匹配等问题。

同时,根据语法树的结构,生成相应的四元式中间代码。

(四)代码优化代码优化的目的是提高生成代码的质量和效率。

在本次实验中,我们实现了一些基本的代码优化算法,如常量折叠、公共子表达式消除等。

通过对中间代码进行分析和转换,减少了代码的冗余和计算量,提高了代码的执行效率。

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

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

编译原理语法分析实验报告第一篇:编译原理语法分析实验报告实验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中保存,并记录他们的位置。

编译原理实验报告

编译原理实验报告

编译原理实验报告一、实验目的编译原理是计算机科学中的重要学科,它涉及到将高级编程语言转换为计算机能够理解和执行的机器语言。

本次实验的目的是通过实际操作和编程实践,深入理解编译原理中的词法分析、语法分析、语义分析以及中间代码生成等关键环节,提高我们对编译过程的认识和编程能力。

二、实验环境本次实验使用的编程语言为C++,开发环境为Visual Studio 2019。

此外,还使用了一些相关的编译工具和调试工具,如 GDB 等。

三、实验内容(一)词法分析器的实现词法分析是编译过程的第一步,其任务是将输入的源程序分解为一个个单词符号。

在本次实验中,我们使用有限自动机的理论来设计和实现词法分析器。

首先,定义了各种单词符号的类别,如标识符、关键字、常量、运算符等。

然后,根据这些类别设计了相应的状态转换图,并将其转换为代码实现。

在实现过程中,使用了正则表达式来匹配输入字符串中的单词符号。

对于标识符和常量等需要进一步处理的单词符号,使用了相应的规则进行解析和转换。

(二)语法分析器的实现语法分析是编译过程的核心环节之一,其任务是根据给定的语法规则,分析输入的单词符号序列是否符合语法结构。

在本次实验中,我们使用了递归下降的语法分析方法。

首先,根据实验要求定义了语法规则,并将其转换为相应的递归函数。

在递归函数中,通过对输入单词符号的判断和处理,逐步分析语法结构。

为了处理语法错误,在分析过程中添加了错误检测和处理机制。

当遇到不符合语法规则的输入时,能够输出相应的错误信息,并尝试进行恢复。

(三)语义分析及中间代码生成语义分析的目的是对语法分析得到的语法树进行语义检查和语义处理,生成中间代码。

在本次实验中,我们使用了三地址码作为中间代码的表示形式。

在语义分析过程中,对变量的定义和使用、表达式的计算、控制流语句等进行了语义检查和处理。

对于符合语义规则的语法结构,生成相应的三地址码指令。

四、实验步骤(一)词法分析器的实现步骤1、定义单词符号的类别和对应的正则表达式。

编译原理_实验报告实验二__语法分析(算符优先) 2

编译原理_实验报告实验二__语法分析(算符优先) 2

华北水利水电学院编译原理实验报告一、实验题目:语法分析(算符优先分析程序)(1)选择最有代表性的语法分析方法算符优先法;(2)选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。

二、实验内容(1)根据给定文法,先求出FirstVt和LastVt集合,构造算符优先关系表(要求算符优先关系表输出到屏幕或者输出到文件);(2)根据算法和优先关系表分析给定表达式是否是该文法识别的正确的算术表达式(要求输出归约过程)(3)给定表达式文法为:G(E’): E’→#E#E→E+T | TT→T*F |FF→(E)|i(4) 分析的句子为:(i+i)*i和i+i)*i三、程序源代#include<stdlib.h>#include<stdio.h>#include<string.h>#include<iostream.h>#define SIZE 128char priority[6][6]; //算符优先关系表数组char input[SIZE]; //存放输入的要进行分析的句子char remain[SIZE]; //存放剩余串char AnalyseStack[SIZE]; //分析栈void analyse();int testchar(char x); //判断字符X在算符优先关系表中的位置void remainString(); //移进时处理剩余字符串,即去掉剩余字符串第一个字符int k;void init()//构造算符优先关系表,并将其存入数组中{priority[0][2]='<';priority[0][3]='<';priority[0][4]='>';priority[0][5]='>';priority[1][0]='>';priority[1][1]='>';priority[1][2]='<';priority[1][3]='<';priority[1][4]='>';priority[1][5]='>';priority[2][0]='>';priority[2][1]='>';priority[2][2]='$';//无优先关系的用$表示priority[2][3]='$';priority[2][4]='>';priority[2][5]='>';priority[3][0]='<';priority[3][1]='<';priority[3][2]='<';priority[3][3]='<';priority[3][4]='=';priority[3][5]='$';priority[4][0]='>';priority[4][1]='>';priority[4][2]='$';priority[4][3]='$';priority[4][4]='>';priority[4][5]='>';priority[5][0]='<';priority[5][3]='<';priority[5][4]='$';priority[5][5]='=';}void analyse()//对所输入的句子进行算符优先分析过程的函数{FILE *fp;fp=fopen("li","a");int i,j,f,z,z1,n,n1,z2,n2;int count=0;//操作的步骤数char a; //用于存放正在分析的字符char p,Q,p1,p2;f=strlen(input); //测出数组的长度for(i=0;i<=f;i++){a=input[i];if(i==0)remainString();if(AnalyseStack[k]=='+'||AnalyseStack[k]=='*'||AnalyseStack[k]=='i'||Analy seStack[k]=='('||AnalyseStack[k]==')'||AnalyseStack[k]=='#')j=k;elsej=k-1;z=testchar(AnalyseStack[j]);//从优先关系表中查出s[j]和a的优先关系if(a=='+'||a=='*'||a=='i'||a=='('||a==')'||a=='#')n=testchar(a);else //如果句子含有不是终结符集合里的其它字符,不合法{printf("错误!该句子不是该文法的合法句子!\n");break;}if(p=='$'){printf("错误!该句子不是该文法的合法句子!\n");return;}if(p=='>'){ for( ; ; ){Q=AnalyseStack[j];if(AnalyseStack[j-1]=='+'||AnalyseStack[j-1]=='*'||AnalyseStack[j-1]=='i'||AnalyseStack[j-1]=='('||AnalyseStack[j-1]==')'||AnalyseStack[j-1]=='#')j=j-1;elsej=j-2;z1=testchar(AnalyseStack[j]);n1=testchar(Q);p1=priority[z1][n1];if(p1=='<') //把AnalyseStack[j+1]~AnalyseStack[k]归约为N{count++;printf("(%d) %s\t%10c\t%5c%17s\t 归约\n",count,AnalyseStack,p,a,remain);fprintf(fp,"(%d) %s\t%17s\t %s\n",count,AnalyseStack,remain,"归约");k=j+1;i--;AnalyseStack[k]='N';int r,r1;r=strlen(AnalyseStack);for(r1=k+1;r1<r;r1++)AnalyseStack[r1]='\0';break;}else}}else{if(p=='<') //表示移进{count++;printf("(%d) %s\t%10c\t%5c%17s\t 移进\n",count,AnalyseStack,p,a,remain);fprintf(fp,"(%d) %s\t%17s\t %s\n",count,AnalyseStack,remain,"移进");k=k+1;AnalyseStack[k]=a;remainString();}else{if(p=='='){z2=testchar(AnalyseStack[j]);n2=testchar('#');p2=priority[z2][n2];if(p2=='='){count++;printf("(%d) %s\t%10c\t%5c%17s\t 接受\n",count,AnalyseStack,p,a,remain);fprintf(fp,"(%d) %s\t%17s\t %s\n",count,AnalyseStack,remain,"接受");printf("该句子是该文法的合法句子。

编译实验报告(语法分析、词法分析)

编译实验报告(语法分析、词法分析)
search(digittp,3); //对该字符进行数字处理
printf("(3, %s)\n",digittp);










5、其他函数
char alphaprocess(char buffer)
char othertp [20];
othertp[0]=buffer;
othertp[1]='\0';
char *border[7]={",",";",".","(",")","{","}"}; //分格符
char *arithmetic[8]={"+","-","*","/","<",">","=","+="}; //运算符
////////////////////////////////////////////////////////////////////////////////////////
if (search(othertp,4)) do//判断字符是否是运算符
printf("(4, %s)\n",othertp);
buffer=fgetc(fp);
goto out;
if (search(othertp,5)) do //判断字符是否是分隔符
printf("(5, %s)\n",othertp);

编译原理实验报告

编译原理实验报告

编译原理实验报告一、实验目的编译原理是计算机科学中的重要课程,旨在让学生了解编译器的基本工作原理以及相关技术。

本次实验旨在通过设计和实现一个简单的编译器,来进一步加深对编译原理的理解,并掌握实际应用的能力。

二、实验环境本次实验使用了Java编程语言及相关工具。

在开始实验前,我们需要安装Java JDK并配置好运行环境。

三、实验内容及步骤1. 词法分析词法分析是编译器的第一步,它将源代码分割成一系列词法单元。

我们首先实现一个词法分析器,它能够将输入的源代码按照语法规则进行切割,并识别出关键字、标识符、数字、运算符等。

2. 语法分析语法分析是编译器的第二步,它将词法分析得到的词法单元序列转化为语法树。

我们使用自顶向下的LL(1)语法分析算法,根据文法规则递归地构建语法树。

3. 语义分析语义分析是编译器的第三步,它对语法树进行检查和转换。

我们主要进行类型检查、语法错误检查等。

如果源代码存在语义错误,编译器应该能够提供相应的错误提示。

4. 代码生成代码生成是编译器的最后一步,它将经过词法分析、语法分析和语义分析的源代码翻译为目标代码。

在本次实验中,我们将目标代码生成为Java字节码。

5. 测试与优化完成以上步骤后,我们需要对编译器进行测试,并进行优化。

通过多个测试用例的执行,我们可以验证编译器的正确性和性能。

四、实验心得通过完成这个编译器的实验,我收获了很多。

首先,我对编译原理的知识有了更深入的理解。

在实验过程中,我深入学习了词法分析、语法分析、语义分析和代码生成等关键技术,对编译器的工作原理有了更系统的了解。

其次,我提高了编程能力。

实现一个完整的编译器需要处理复杂的数据结构和算法,这对我的编程能力是一个很好的挑战。

通过实验,我学会了合理地组织代码,优化算法,并注意到细节对程序性能的影响。

最后,我锻炼了解决问题的能力。

在实验过程中,我遇到了很多困难和挑战,但我不断地调试和改进代码,最终成功地实现了编译器。

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

实验5 语法分析程序的设计(2)一、实验目的通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析中算法优先分析方法。

二、实验内容设计一个文法的算法优先分析程序,判断特定表达式的正确性。

三、实验要求1、给出文法如下:G[E]E->T|E+T;T->F|T*F;F->i|(E);可以构造算符优先表如下:+ * ( ) i+*()i2、计算机中表示上述优先关系,优先关系的机内存放方式有两种1)直接存放,2)为优先关系建立优先函数,这里由学生自己选择一种方式;1、给出算符优先分析算法如下:k:=1; S[k]:=‘#’;REPEAT把下一个输入符号读进a中;IF S[k]∈V T THEN j:=k ELSE j:=k-1;WHILE S[j] a DOBEGINREPEATQ:=S[j];IF S[j-1]∈V T THEN j:=j-1 ELSE j:=j-2UNTIL S[j] Q把S[j+1]…S[k]归约为某个N;k:=j+1;S[k]:=N;END OF WHILE;IF S[j] a OR S[j]a THENBEGINk:=k+1;S[k]:=a ENDELSE ERROR UNTIL a=‘#’1、 根据给出算法,利用适当的数据结构实现算符优先分析程序;2、 利用算符优先分析程序完成下列功能:1) 手工将测试的表达式写入文本文件,每个表达式写一行,用“;”表示结束; 2) 读入文本文件中的表达式;3) 调用实验2中的词法分析程序搜索单词;4) 把单词送入算法优先分析程序,判断表达式是否正确(是否是给出文法的语言),若错误,应给出错误信息;5) 完成上述功能,有余力的同学可以对正确的表达式计算出结果。

四、实验环境PC 微机DOS 操作系统或 Windows 操作系统Turbo C 程序集成环境或 Visual C++ 程序集成环境五、实验步骤1、 分析文法中终结符号的优先关系;2、 存放优先关系或构造优先函数;3、利用算符优先分析的算法编写分析程序;4、写测试程序,包括表达式的读入和结果的输出;5、程序运行效果,测试数据可以参考下列给出的数据。

六、测试数据输入数据:编辑一个文本文文件expression.txt ,在文件中输入如下内容: 正确结果:(1)10; 输出:正确 (2)1+2; 输出:正确(3)(1+2)*3+(5+6*7);输出:正确 (4)((1+2)*3+410; 1+2;(1+2)*3+(5+6*7); ((1+2)*3+4; 1+2+3+(*4+5); (a+b)*(c+d);((ab3+de4)**5)+1;输出:错误(5)1+2+3+(*4+5)输出:错误(6)(a+b)*(c+d)输出:正确(7)((ab3+de4)**5)+1输出:错误七、实验报告要求实验报告应包括以下几个部分:1、给定文法优先关系和存放方式;+ * ( ) i #+*( e1) e2 e2i e2 e2e4# e3引入“#”,将句型包含起来并填入出错标记。

使用二维数组将其存放。

2、算符优先分析程序的算法和结构;程序从文本文件中逐行读取表达式,每行以“;”做标记。

调用词法分析程序将这行数据分析出由一个个的单词组成的表达式,再逐个分析单词。

另外,由于文法中没写入关于标识符和常数的产生式,所以在对单词符号进行语法分析时,会将标识符和常数自动规约为“i”。

数据结构:优先关系表R:二维数组,存储了终结符+、*、(、)、i、#的优先关系。

符号W:结构体,有四个成员,包括:ch:char类型,非终结符和终结符的字符标记;po:int类型,只对终结符有效,和在R中的位置有关,有词法分析器提供;对于非终结符,其po无效;val:string类型,综合属性;对终结符i,其值由词法分析器提供;对非终结符,其值由规约时对应的产生式的规则计算得到;对界符或运算符,val无效;type:int类型,标记属性值类型,0为标识符,不可计算;1为可计算的数值;由词法分析器提供;注意:程序内部数值的计算和标记一律使用十进制,文本中的表达式必须为十进制整数,即如果在文本中使用八进制或十六进制,词法分析器分析后不会添加至缓冲区,在表达式语法正确且其中不含标志符时,计算得到的结果一律使用十进制。

例:对于文本中十进制数字10,其对应的初始结构体成员的值ch=’i’,po=5,val=”10”,type=1。

符号栈S:符号结构体的一维数组。

算法:说明:G[E]E->T|E+T;T->F|T*F;F->i|(E);算符优先文法并未对非终结符定义优先关系,无法对单非产生式进行规约,所以实际上在规约时,上面的E->T,T->F基本没有使用,而且规约时并不严格按照产生式的右部规约,只要待规约项符合句型#N1a1N2a2…NnanNn+1#(每个ai都是终结符,Ni是可有可无的非终结符),并且相对产生式,在相同位置有相同的非终结符即可规约,这样算符优先文法规约很快,但有些语法错误将无法识别,在本实验中,只要在要规约的地方准确的判断可规约的项,即符合句型,在不严格要求非终结符相同而终结符位置符号相同时,存在可匹配文法的产生式,即可规约,例如:F * F 可以匹配T*F继而规约为T。

定义用W[ch]表示字符名为ch的符号;实际程序中关于终结符优先关系的比较是利用R获取优先关系标志的,算法中为了可读性,直接将结构体进行比较了。

从文本文件读入一行数据,反复调用scanP()得到符号集合,用符号结构体数组E存储;k = 1; i = 0; S[k] = W[#];Do {A = E[i++];if(S[k] 是终结符)j = k;elsej = k – 1;while(S[j] > A) {Do {Q = S[j];If(S[j - 1] 是终结符)j = j – 1;elsej = j – 2;}while(S[j] < Q);N = Statute(S,j + 1,k);k = j + 1;S[k] = N;}If(S[j] < A || S[j] == A) {k++;S[k] = A;}else error(S[j].po,A.po);}while(A == W[#]);程序功能说明:程序从文本文件读入表达式,判断语法是否正确,正确则输出结果,其中有标识符的话,结果还是含有标识符的原表达式,语法错误的话,则输出错误信息。

源程序:程序中文本文件在桌面文件名为expression.txt#include<iostream>#include<string>#include<stdlib.h>using namespace std;#define NULL 0#define MAXSIZE 30 //单行表达式的符号总数最大值typedef struct grammar_symbol //文法符号{char ch;int po;string val;int type;}W;char pre[6][6] = { //优先关系表{ '>', '<', '<', '>', '<','>' },{ '>', '>', '<', '>', '<', '>' },{ '<', '<', '<', '=', '<', '1' },{ '>', '>', '2', '>', '2', '>' },{ '>', '>', '2', '>', '2', '>' },{ '<', '<', '<', '3', '<', '=' }};char GetChar(FILE* fp) { //读取文件中的一个字符char ch;ch = fgetc(fp);return ch;}char GetBC(FILE* fp) { //读取文件的字符直至ch不是空白char ch;do {ch = GetChar(fp);} while (ch == ' ' || ch == '\t' || ch == '\n');return ch;}void Concat(char ch, char strToken[]) { //将ch中的字符连接到strToken 之后char str[2];int len = strlen(strToken);strToken[len] = ch;strToken[len + 1] = '\0';}int IsLetter(char ch) { //布尔函数,判断ch中的字符是否为字母,是返回1,否则返回0int flag = 0;if (ch >= 'a' && ch <= 'z')flag = 1;return flag;}int IsDigit(char ch) { //布尔函数,判断ch中的字符是否为数字,是返回1,否则返回0int flag = 0;if (ch >= '0' && ch <= '9')flag = 1;return flag;}int Reserve(char strToken[]) { //整型函数,对strToken中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回0int code = 0, i;char keyWord[6][6] = { "if", "then", "else", "while", "do" };for (i = 0; i < 5; i++) {if (strcmp(strToken, keyWord[i]) == 0) {code = i + 1;break;}}return code;}int SearchOP(char ch) { //整型函数,对strToken中的字符串查找运算符和界符,若它是一个运算符或界符,则返回它的编码,否则返回0int code = 0, i;char OP[10] = { '+', '*',' (', ')', '-', '/', '<', '>', '=', ';' };for (i = 0; i < 10; i++) {if (ch == OP[i]) {code = i + 1;break;}}return code;}char Retract(FILE* fp, char ch) { //子函数,将搜索指示器回调一个字符位置,将ch置为空白字符ch = ' ';fseek(fp, -1L, 1);return ch;}void ProError() { //错误处理函数printf("输入错误!\n");return;}int scan(FILE* fp,W* E,int num) {W w;char ch;char strToken[10];strToken[0] = '\0'; //置strToken为空串ch = GetBC(fp); //先读取一个非空白的字符if (feof(fp)) return 0;if (ch == ';'){printf(";");return 0; //判断表达式尾,是则返回调用程序}if (IsLetter(ch)) { //判断标识符while (IsLetter(ch) || IsDigit(ch)) {Concat(ch, strToken);ch = GetChar(fp);}ch = Retract(fp, ch);if (Reserve(strToken)) { //判断关键字printf("<%s,->\n", strToken);}else //判断标识符{printf("%s", strToken);w.ch = 'i';w.po = 4;w.val = strToken;w.type = 0;E[num] = w;}}else if (ch >= '1' && ch <= '9') { //判断十进制整数while (IsDigit(ch)) {Concat(ch, strToken);ch = GetChar(fp);}ch = Retract(fp, ch);printf("%s", strToken);w.ch = 'i';w.po = 4;w.val = strToken;w.type = 1;E[num] = w;}else if (ch == '0') {ch = GetChar(fp);if (ch >= '1' && ch <= '7') { //判断八进制整数while (ch >= '0' && ch <= '7') {Concat(ch, strToken);ch = GetChar(fp);}ch = Retract(fp, ch);printf("<2,%s>\n", strToken);}else if (ch == 'x') { //判断十六进制整数ch = GetChar(fp);while (IsDigit(ch) || ch >= 'a' && ch <= 'f') {Concat(ch, strToken);ch = GetChar(fp);}ch = Retract(fp, ch);printf("<3,%s>\n", strToken);}else { //判断十进制的0ch = Retract(fp, ch);printf("0");w.ch = 'i';w.po = 4;w.val = "0";w.type = 0;E[num] = w;}}else if (SearchOP(ch) != 0) { //判断运算符和界符printf("%c", ch);int po = SearchOP(ch) - 1;w.ch = ch;w.po = po;E[num] = w;}else { //出错ProError();}return 1;}bool checkVt(char ch) {bool flag = false;int i;char Vt[6] = { '+', '*', '(', ')', 'i', '#' };for (i = 0; i < 6; i++) {if (ch == Vt[i]) {flag = true;}}return flag;}W Statute(W* S, int s, int e) { //规约子函数,将S中j+1到k的符号规约为N W N;if (S[s].ch == 'i' && s == e) {N.ch = 'F';N.val = S[s].val;N.type = S[s].type;}else if (S[s].ch == '(' && !(checkVt(S[s + 1].ch)) && S[e].ch == ')') {if (S[s + 1].type == 1) {N.ch = 'F';N.val = S[s + 1].val;N.type = S[s + 1].type;}else {N.ch = 'F';N.val = '('+ S[s + 1].val + ')';N.type = S[s + 1].type;}}else if (!(checkVt(S[s].ch)) && S[s + 1].ch == '+' && !(checkVt(S[e].ch))) {N.ch = 'E';if (S[s].type == 1 && S[e].type == 1) {N.type = 1;int v = atoi(S[s].val.data()) + atoi(S[e].val.data());char l[30];sprintf_s(l,30,"%d", v);N.val = l;}else {N.type = 0;N.val = S[s].val + S[s + 1].ch + S[e].val;}}else if ((s != e) && !(checkVt(S[s].ch)) && S[s + 1].ch == '*' && !(checkVt(S[e].ch))) {N.ch = 'T';if (S[s].type == 1 && S[e].type == 1) {N.type = 1;int v = atoi(S[s].val.data()) * atoi(S[e].val.data());char l[30];sprintf_s(l, 30,"%d", v);N.val = l;}else {N.type = 0;N.val = S[s].val + S[s + 1].ch + S[e].val;}}else if(S[s].ch == 'T' && s == e){N.ch = 'E';N.val = S[s].val;N.type = S[s].type;}else {N.ch = '#';}N.po = 4;return N;}void error(char errnum) { //错误处理子函数if (errnum == '1') {printf("错误,非法左括号\n\n");}else if(errnum == '2'){printf("错误,缺少运算符\n\n");}else if (errnum == '3'){printf("错误,非法右括号\n\n");}else if (errnum == '4'){printf("错误,缺少表达式\n\n");}}int syntax(W* E,int num) { //算法对应的主要实现程序W S[MAXSIZE];int k = 1, i = 0, j;W border, A, Q;border.ch = '#';border.po = 5;E[num] = border;S[k] = border;do {A = E[i++];if (checkVt(S[k].ch)) //判断S[k]是终结符j = k;elsej = k - 1;while (pre[S[j].po][A.po] == '>') {do {Q = S[j];if (checkVt(S[j - 1].ch))j = j - 1;elsej = j - 2;} while (pre[S[j].po][Q.po] != '<');W N = Statute(S, j + 1, k);if (N.ch == '#') {error('4');return 0;}k = j + 1;S[k] = N;}if (pre[S[j].po][A.po] == '<' || pre[S[j].po][A.po] == '=') { k++;S[k] = A;}else {error(pre[S[j].po][A.po]);return 0;}} while (A.ch != '#');if (A.ch == '#') {printf("正确,结果为:%s\n\n", S[k - 1].val.data());return 0;}int main() { FILE* fp; errno_t err;if ((err = fopen_s(&fp,"C:\\Users\\Administrator\\Desktop\\expression.txt", "r")) != NULL) { //以只读方式打开文件,失败则退出程序 printf(" not open!"); exit(0);}int n = 0;printf("语法分析结果如下:\n\n"); while (!feof(fp)) { //若不是文件尾则执行循环int num = 0; W E[MAXSIZE];//存储一行表达式GetBC(fp);if (!feof(fp)) { n++;fseek(fp, -1L, 1); printf("(%d)", n); } else { break;}while (1) {//只读一行,行末标志为“;”int flag = scan(fp, E,num); if (flag == 0)break;num++;}printf("\n 输出:"); syntax(E,num);}fclose(fp); //关闭文件fp = NULL;//避免指向非法内存}3、 程序运行流程;4、 程序的测试结果和问题; 实验报告源数据:输入表达式到文本程序开始是否是文件尾读取一行文本否调用syntax()判断语法是否正确 输出结果是否输出错误返回 退出程序是其它数据:问题:实验时是根据实验报告提供的算法编程的,但是原算法使用了类似Pascal的语言,而我用的是C,算法实现时具体的语法不同,例如Pascal的repeat…until和C 语言的do…while并一样,实验时不注意会使程序出错,二者的循环条件是相反的。

相关文档
最新文档