语法分析器实验报告

合集下载

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

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

编译原理语法分析试验报告语法分析是编译原理中的重要内容之一,主要用于对源程序进行语法检查,判断其是否符合给定的语法规则。

本次试验通过使用ANTLR工具,对C语言的子集进行了语法分析的实现。

一、实验目的:1.了解语法分析的基本概念和方法;2.使用ANTLR工具生成语法分析器;3.掌握ANTLR工具的基本使用方法;4.实现对C语言子集的语法分析。

二、实验内容:本次试验主要内容是使用ANTLR工具生成C语言子集的语法分析器,并对给定的C语言子集进行语法分析。

三、实验步骤:1.学习ANTLR工具的基本概念和使用方法;2.根据C语言子集的语法规则,编写ANTLR的语法文件(.g文件);3.使用ANTLR工具生成语法分析器;4.编写测试代码,对给定的C语言子集进行语法分析。

四、实验结果:经过以上的步骤,得到了一个完整的C语言子集的语法分析器,并且通过测试代码对给定的C语言子集进行了语法分析。

五、实验总结:通过本次实验,我对语法分析有了更深入的了解,掌握了使用ANTLR工具生成语法分析器的基本方法,同时也巩固了对C语言的基本语法规则的理解。

在实验过程中,遇到了一些问题,例如在编写ANTLR的语法文件时,对一些特殊语法规则的处理上有些困惑,但通过查阅资料和与同学的探讨,最终解决了这些问题。

本次试验对于我的学习有很大的帮助,我了解到了编译原理中的重要内容之一,也更深入地理解了语法分析的基本原理和方法。

通过实验,我发现使用ANTLR工具能够更方便地生成语法分析器,大大提高了开发效率。

总之,本次试验让我对编译原理中的语法分析有了更深入的了解,并且提高了我的编程能力和分析问题的能力。

在今后的学习和工作中,我将继续深入研究编译原理相关的知识,并应用到实际项目中。

语法法分析实验报告

语法法分析实验报告

一、实验目的1. 理解语法分析的基本概念和原理。

2. 掌握语法分析器的构建方法。

3. 培养实际操作能力,提高编程水平。

二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 开发工具:PyCharm三、实验内容1. 语法分析概述2. 词法分析3. 语法分析4. 实验实现四、实验步骤1. 语法分析概述(1)了解语法分析的定义、作用和意义。

(2)掌握语法分析的基本原理和流程。

2. 词法分析(1)编写词法分析器代码,将源代码分解成单词序列。

(2)实现词法分析器的各个功能,如:识别标识符、关键字、运算符等。

3. 语法分析(1)设计语法分析器,将单词序列转换为抽象语法树(AST)。

(2)实现语法分析器的各个功能,如:识别表达式、语句、函数等。

4. 实验实现(1)创建Python项目,导入相关库。

(2)编写词法分析器代码,实现单词序列的分解。

(3)编写语法分析器代码,实现抽象语法树的构建。

(4)测试语法分析器,验证其正确性。

五、实验结果与分析1. 词法分析结果实验中,我们成功地将源代码分解成单词序列,包括标识符、关键字、运算符等。

词法分析器的输出结果如下:```identifier: akeyword: intoperator: +identifier: boperator: =integer: 5```2. 语法分析结果通过语法分析器,我们将单词序列转换成抽象语法树。

以下是一个示例的抽象语法树:```Program├── Declaration│ ├── Type│ │ ├── Identifier│ │ └── Integer│ └── Identifier│ └── a└── Statement├── Expression│ ├── Identifier│ └── a└── Operator└── =└── Expression├── Identifier└── b└── Integer└── 5```从实验结果可以看出,我们的语法分析器能够正确地将源代码转换为抽象语法树。

语法分析器报告

语法分析器报告
While S[j]>a do
Begin
Repeat
Q:=S[j]
If S[j-1]∈VTthenj:=j-1elsej:=j-2
UntilS[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 then
j++;
}
strings[m+1]='#';
strings[m+2]='\0';
cout<<"算术表达式"<<id<<"为: "<<oldstrings<<endl;
cout<<"转换为输入串: "<<strings<<endl;
cout<<" 步骤号符号栈优先关系当前分析符剩余输入串动作";
prior_analysis();
cout<<" # < < < < < e3 < ="<<endl;
if((fp=fopen("预处理.txt","r"))==NULL)
{
cout<<"请先将实验文件夹中的预处理.txt文件复制到实验文件夹中!"<<endl;
system("pause");
exit(0);
}
charch=fgetc(fp);

国开电大 编译原理 实验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语言子集的语法,用EBNF表示如下:<程序>→main()<语句块><语句块> →‘{’<语句串>‘}’<语句串> → <语句> {; <语句> };<语句> → <赋值语句> |<条件语句>|<循环语句><赋值语句>→ID=<表达式><条件语句>→if‘(‘条件’)’<语句块><循环语句>→while’(‘<条件>’)‘<语句块><条件> → <表达式><关系运算符> <表达式><表达式> →<项>{+<项>|-<项>}<项> → <因子> {* <因子> |/ <因子>}<因子> →ID|NUM| ‘(’<表达式>‘)’<关系运算符> →<|<=|>|>=|==|!=二、实验原理及基本技术路线图(方框原理图或程序流程图)三、所用仪器、材料(设备名称、型号、规格等或使用软件)1台PC以及VISUAL C++6.0软件四、实验方法、步骤(或:程序代码或操作过程)#include <iostream>#include <string>using namespace std;char prog[80],token[8];char ch;int syn,p,m,n,sum,k=0;char *key[6]={"main","int","char","if","else","while"};void scaner();void lrparser();void yucu();void statement();void expression();void term();void factor();void main(){p=0;cout<<"语法分析"<<endl;cout<<"请输入字符串,以“@”结尾:"<<endl;do {ch = getchar(); prog[p++]=ch;}while(ch!='@');p=0;scaner();lrparser();}void scaner(){sum=m=0;for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' ') ch=prog[p++];if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9')) {token[m++]=ch; ch=prog[p++];}token[m++]='\0';p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,key[n])==0){syn=n+1; break;}}else if(ch>='0'&&ch<='9'){while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=20;}elseswitch(ch){case '<': m=0;token[m++]=ch;ch=prog[p++];if(ch=='<') {syn=33; token[m++]=ch;}else if(ch=='=') {syn=35; token[m++]=ch;}break;case '>': m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=34; token[m++]=ch;}else {syn=32; p--;}break;case '=':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=36;token[m++]=ch;}else{ syn=21;p--;}break;case ':': m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=18; token[m++]=ch;}else {syn=17; p--;}break;case '+': syn=22; token[0]=ch; break;case '-': syn=23; token[0]=ch; break;case '*': syn=24; token[0]=ch; break;case '/': syn=25; token[0]=ch; break;case ';': syn=31; token[0]=ch; break;case '(': syn=26; token[0]=ch; break;case ')': syn=27; token[0]=ch; break;case '@': syn=0; token[0]=ch; break;default : syn=-1;}}void lrparser(){if(syn==1){scaner();yucu();if(syn=6){scaner();if(syn==0 && (k==0))cout<<"\nsuccess\n"<<endl;}else{if(k!=1)cout<<"\nwhile error\n"<<endl;k=1;}}else{cout<<"\nmain error\n"<<endl;k=1;}return;}void yucu(){statement();while(syn==31){scaner();statement();}return;}void statement(){if(syn==10){scaner();if(syn==18){scaner();expression();}else{cout<<"\nscentence error\n"<<endl;k=1;}}return;}void expression(){term();while(syn==22||syn==23){scaner();term();}return;}void term(){factor();while(syn==24||syn==25){scaner();factor();}return;}void factor(){if(syn==10||syn==20)scaner();else if(syn==26){scaner();expression();if(syn==27)scaner();else{cout<<"( error"<<endl;k=1;}}else{cout<<"expression error"<<endl;k=1;}return;}五、实验过程原始记录( 测试数据、图表、计算等)六、实验结果、分析和结论(误差分析与数据处理、成果总结等。

词法分析器语法分析器试验报告

词法分析器语法分析器试验报告

词法分析器、语法分析器试验报告一.程序思路1.词法分析器对输入的程序进行分析,将关键字,保留字与系统标识符分开,并对其属性进行说明。

建立数组,将单词读入,对单词的ASCII码进行判断,将在ASCII码值在一定区间进行区分(使用if语句来判断),分开来后,对其所在ASCII值区间的不同,给予以不同的属性(比如:系统保留字…),词法分析器完成后要能识别+,-,=等字符。

2.语法分析器对输入的程序语句进行分析。

对每个非终结点定义单个函数,定义了它的后继节点。

然后用一个构造来的函数,使定义的后继节点符合语法,否则报错。

二.源程序cifafenxi:#includestring.h#includeiostream.h#includestdio.h#includeconio.h#define OK 1#define……#define……class word{ int ch;char code[50][50];public://word();int scan();int letter(int ch);int digit(int ch);int flag(int ch);int keyword(char * ch);int alpha(char * ch);int judge(char * ch);};int word::letter(int ch) //字符判断int word::alpha(char * ch) //字符属性设定数字判断// int word::digit(int ch)int word::flag(int ch){if(((ch>='0')&&(ch<='9'))||((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z'))||(ch=='+')||(ch=='-')||(ch=='*')||(ch=='/')||(ch=='=')||(ch=='==')||(ch=='%')||(ch=='<')||(ch=='>')||(ch=='(')||(ch==')'))return(1);else return(0);}int word::keyword(char * ch) //关键字判断{if((ch[0]=='i')&&(ch[1]=='n')&&(ch[2]=='t')&&(ch[3]==0)){ cout<<\<<The [int] is a keyword !<<\; return(INT); }if((ch[0]=='c')&&(ch[1]=='h')&&(ch[2]=='a')&&(ch[3]=='r')&&(ch[4]==0)) { cout<<\<<The [char] is a keyword !<<\; return(CHAR); }……………………………………………………{ cout<<\<<It is a keyword [if] !<<\; return(SWITCH); }return(0);}int word::judge(char * ch) //数字进位制判断if((ch[0]=='0')&&((ch[1]>='0')&&(ch[1]<='7'))){ cout<<\<<This is a OTC number, OTC value is<<[<<ch<<] !<<\;return(OTC); }……………………………………………………return(1);}int word::scan(){ int i=0,j=0,x=1;cout<<Please input !<<\; ch=getc(stdin);while((ch==' ')||(ch==10))ch=getc(stdin);if((flag(ch)==NO)){ cout<<\<<ERROR<<\; return(ERROR); }ungetc(ch,stdin);while(x) { ch=getc(stdin); if((letter(ch)==YES)){ i=0; while (letter(ch)||digit(ch)) {code[j][i]=ch;ch=getc(stdin);i++; }code[j][i]=0;if(keyword(code[j])==0) {if(alpha(code[j]))cout<<The identifier's ID is[<<j<<] !<<\;} j++;if(ch==10)x=0; }if((digit(ch)==YES))i=0;{while(digit(ch)||(ch=='x')||((ch>='a')&&(ch<='f'))){code[j][i]=ch;ch=getc(stdin);i++;}code[j][i]=0;judge(code[j]);cout<<The number's ID is [<<j<<] !<<\;j++;if(ch==10)x=0; }if(ch==':'){ i=0; code[j][i]=ch; ch=getc(stdin); if(ch=='='){ code[j][i++]=ch;cout<<The [<<code[j]<< is (ASSIGN-OP, -) .; j++; ch=getc(stdin); if(ch==10)x=0; }} switch(ch){case'+':{ i=0; code[j][i]=ch; code[j][i++]=0; cout<<\<<The [<<char(ch)<<] is aidentifier (PLUS-OP, AND) .<<\; } //ch=getc(stdin); if(ch==59)ungetc(ch,stdin); }break;case'-':{ i=0; code[j][i]=ch; code[j][i++]=0; cout<<\<<The [<<char(ch)<<] is aidentifier (MINUS-OP, SUB) .<<\; } //ch=getc(stdin);if(ch==59)ungetc(ch,stdin); }break;……………………………………………………break;case')':{ i=0; code[j][i]=ch; code[j][i++]=0; cout<<\<<The [<<char(ch)<<] is aidentifier (RELATION-OP, RP) .<<\;}// ch=getc(stdin); if(ch==59)ungetc(ch,stdin); }break;}if(ch==10)x=0;}return(OK);}int main(){char ch1;word word;while(ch1!='q'){word.scan();ch1=getch();}return(OK);}yufafenxi:#includestring.h#includeiostream.h#includestdio.h#includeconio.hclass word{ int ch;char code[MAX][MAX];public:// word ();int scan();int letter(int ch);int digit(int ch);int right(int ch);int keyword(char * ch);int alpha(char * ch);int judge(char * ch);int yufa(int ch);int match(int ch);int word _e();int word _t();int word _f();int word _s();int word _c();};int word::letter(int ch)……int word::alpha(char * ch)……int word::digit(int ch)……int word::right(int ch)……int word::match(int ch){ int i=0;int j=0;int x=1;ch=getc(stdin);while((ch==' ')||(ch==10))ch=getc(stdin);if((isright(ch)==NO)){ cout<<\<<ERROR<<\; return(ERROR); }ungetc(ch,stdin);while(x)while (isletter(ch)||isdigit(ch))i=0; { ch=getc(stdin); if((isletter(ch)==YES)) {{ code[j][i]=ch; ch=getc(stdin);i++; }code[j][i]=0;ungetc(ch,stdin);if(ch==10)x=0;j++;return(iskeyword(code[j-1]));}if((isdigit(ch)==YES)){ i=0; while(isdigit(ch)||(ch=='x')||((ch>='a')&&(ch<='f'))){code[j][i]=ch;ch=getc(stdin);i++; }code[j][i]=0;ungetc(ch,stdin); j++;if(ch==10)x=0;return(judge(code[j-1])); } if(ch==':'){ i=0; code[j][i]=ch; ch=getc(stdin); if(ch=='='){ code[j][i++]=ch; code[j][i++]=0; j++; return(ASSIGN);} }switch(ch){ case'+':{ i=0; code[j][i]=ch; code[j][i++]=0; return(AND); }case'-':{ i=0; code[j][i]=ch; code[j][i++]=0; return(SUB); } ……………………………………………………} if(ch==10)x=0;}return(OK);}int word:: word _t()……int word:: word _f()……int word::word_s()……int main(){char ch1;word word;while(ch1!='q'){clrscr();cout<<Please Input !<<\;lookhead=word.scan();word.fun_s();ch1=getch();}return(OK);}三.小节——心得体会这次小程序的编写让我对编译程序的工作有了个大概的了解,让我的编译程序的原理及设计有了长足的进步,使我明白和更好的体会到了编译程序的作用。

语法分析器实验报告

语法分析器实验报告

语法分析器一.需求分析1.1 题目背景描述编译器实现技术是一大宝库,一方面以编译器的实现为背景可以实践几乎全部在数据结构与算法分析课程中学到的主要数据结构与算法;另一方面,编译器设计中使用的问题求解方法、处理问题的思路被广泛地用于自动数据处理(转换)及其它一些新的研究领域。

没有编译器的出现就没有现代数字计算机的发展。

本次课设即以“语法规则的存储与显示”、“句子的生成”、“语法(分析)树的建立”等等这些编译器中的一些基本功能的实现为题,对高级程序设计语言在计算机中的表达和相关的处理有一个初步认识,提前领略“数据的自动转换与处理”这一计算机问题求解的核心技术。

尽管这些功能的实现并不涉及较深入的编译技术,但也需要带着问题预先学习、掌握有关形式语言、编译原理与技术的若干基本概念。

1.2 课程设计任务给定若干描述某种高级程序设计语言组成部分的语法规则及测试用例:1、设计恰当的数据结构实现语法规则的计算机存储并加以显示;2、对于给定语法规则的句子,能动态显示“句子的生成”;3、对于给定语法规则的句子(或句型),完成该句子(句型)的“语法(分析)树的建立”,并用图形界面显示;1.3 输入形式本程序用到的输入形式有键盘、鼠标和文件。

各输入说明及输入值范围说明如下:1.3.1 键盘输入可在“建立推导”窗口通过键盘输入任意句子建立推导,两符号间需要空格。

1.3.2 鼠标输入可在“文法管理系统”界面通过鼠标点击任意菜单选项,实现对应功能。

当文法或推导过长时,点击对应文本域滚动滚轮可查看余下全文。

1.3.3 文件输入可输入任意存储了正确文法的txt文件,默认有Pascal风格的文法和C语言风格的文法,格式如下:Pascal风格:St::=Assign|IfS|WhSAssign::=id := EE::=E + E|E - E|E * E|E / E|( E )|idIfS::=if BE then St|if BE then St else StBE::=id > id|id == id|id < idWhS::=while BE do StC语言风格:S::=assignS|ifS|whileSassignS::=id = E|id += E|id -= EE::=E + T|E - T|TT::=T * F|T / F|FifS::=if BE S|if BE S else SBE::=E > E|E == E|E < E|E >= E|E != E|E <= EwhileS::=while BE S1.4 输出形式输出到显示器。

语法分析器设计实验报告

语法分析器设计实验报告

语法分析器设计实验报告一、引言语法分析器是编译器中的重要组成部分,其主要功能是根据给定的文法规则,对输入的程序代码进行语法分析,判断其是否符合语法规范。

本实验旨在设计一个简单的语法分析器,通过实际实现一个基于LL(1)文法的语法分析器,深入了解语法分析的原理和实现方法。

二、实验目标本实验的目标是设计一个能够接受一个输入的程序代码并进行语法分析的程序。

具体而言,需要实现以下功能:1. 构建一个文法规则集合,用于描述程序代码的语法规范;2. 设计并实现一个LL(1)分析表,用于存储语法分析所需的预测分析表;3. 实现语法分析器,能够根据输入的程序代码,逐步地进行语法分析,并输出相应的结果。

三、实验环境本实验使用的是Java语言进行实现,操作系统环境为Windows 10。

使用的集成开发环境为Eclipse。

四、实验步骤1. 设计文法规则集合在语法分析器设计中,首先需要设计一个文法规则集合,用于描述需要分析的程序代码的语法规范。

文法规则集合的设计要符合LL(1)文法的要求,即每个非终结符的产生式至多有一个与输入符号串首符号相关的产生式。

2. 构建LL(1)分析表根据文法规则集合,构建一个LL(1)分析表,用于存储语法分析所需的预测分析表。

LL(1)分析表是一个二维表,其中行表示非终结符,列表示终结符。

表中的每个元素表示相应的产生式编号,用于指示语法分析器在分析过程中应该使用哪个产生式。

构建LL(1)分析表的方法包括:- 遍历文法规则集合,计算每个非终结符的FIRST集合和FOLLOW集合;- 根据计算得到的FIRST集合和FOLLOW集合,填充LL(1)分析表。

3. 实现语法分析器根据LL(1)分析表,实现一个语法分析器。

语法分析器的输入是一个程序代码,输出是语法分析器的分析结果。

实现语法分析器的主要过程包括:- 初始化分析栈,将文法规则的开始符号入栈;- 从输入的程序代码中读取下一个终结符;- 如果分析栈的栈顶是非终结符,根据LL(1)分析表中对应的产生式编号,将产生式右部的符号依次入栈;- 如果分析栈的栈顶是终结符,并且与输入的终结符相同,则将该终结符出栈,并继续读取下一个终结符;- 重复上述过程,直到分析栈为空或者无法继续推导。

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

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

组员学号姓名实验名称对各算术表达式进行语法分析实验室实验目的或要求实验目的:1、掌握语法分析器生成工具的使用和了解编译器的设计;2、了解自上而下语法分析器的构造过程;3、能够构造LR分析表,编写由该分析表驱动的语法分析器程序;4、借助语法制导翻译,可在语法分析的同时,完成对语义的翻译;5、借助语法分析,设计一个表达式的判断分析器,即从键盘上输入算术表达式,分析器将显示该表达式的正确与否。

实验原理(算法流程)实验算法流程图如下所示:开始输入表达式表达式保存到数ch第一个元素为)+-*/YCh[i]=’(’i++YNCh[i]=NULLNCh[i]是0~9i++YCh[i]是0~9Ch[i]=+ -*/)N多了+ -*/)Y其他错误NYCh[i]=* /Ni++YCh[i]=+ -*/NY多了+ -*/Ch[i]=+ -NNCh[i]=)Y少了)N错误首部多了) +-*/结束程序界面(效果图)实验结果界面:只选择几个典型的例子进行分析,可进行任意表达式输入。

1)未进行语法分析时的界面;2)输入正确的表达式(1+2)*(6-3)+1进行语法分析时的界面结果;3)输入错误的表达式1*2+(2+3并进行语法分析时的界面结果;程序界面(效果图)4)输入错误的表达式1+(+5+6)并进行语法分析时的界面结果;程序界面(效果图)程序代码 #include "stdafx.h"#include "grammer.h"#include "mfc_语法分析器.h"#include "mfc_语法分析器Dlg.h"int flag;int i,j;int length;CString string;int grammer(CString str){i=0;flag=0;char ch[MAX];length=str.GetLength();strcpy(ch,str);if(length!=0){F(ch);if(flag==0){MessageBox(NULL,"输入表达式符合文法","正确",MB_OK|MB_ICONINFORMATION);}//str=ch;//return flag;}else{MessageBox(NULL,"表达式为空","提示",MB_OK|MB_ICONW ARNING);//MessageBox(NULL,"表达式为空","提示",MB_OK|MB_ICONERROR);return -1;}return flag;}void F(char ch[]){if(ch[0]=='+'){程序代码flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR); MessageBox(NULL,"开始处多了+","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]=='-'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了-","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]=='*'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了*","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]=='/'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了/","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]==')'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了)","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}/*上述为对第一个字符的特殊处理*/elseif(ch[i]!=NULL){if(ch[i]=='('){i++;F(ch);程序代码if(ch[i]!=')'){if(flag==0){MessageBox(NULL,"输入表达式不符合文法1","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"少了')'","提示",MB_OK|MB_ICONINFORMATION);}flag=1;}else{i++;if(ch[i]!=NULL)T(ch);}}elseif(ch[i]<='9'&&ch[i]>='0'){while(ch[i]<='9'&&ch[i]>='0')i++;if(ch[i]!=NULL)T(ch);}else{if(flag==0){if(ch[i]!=NULL&&ch[i]!=')'){MessageBox(NULL,"输入表达式不符合文法2.1","错误",MB_OK|MB_ICONERROR);if(ch[i]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='+') {MessageBox(NULL,"多了'+'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]=='-') MessageBox(NULL,"多了'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='*') MessageBox(NULL,"多了'*'号","提示",MB_OK|MB_ICONINFORMA TION);程序代码else if(ch[i]=='/') MessageBox(NULL,"多了'/'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]==NULL){MessageBox(NULL,"输入表达式不符合文法2.2","错误",MB_OK|MB_ICONERROR);if(ch[i-1]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='+') MessageBox(NULL,"多了最后的'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='-') MessageBox(NULL,"多了最后的'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='*') MessageBox(NULL,"多了最后的'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='/') MessageBox(NULL,"多了最后的'/'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]!=NULL&&ch[i]==')'){MessageBox(NULL,"输入表达式不符合文法2.3","错误",MB_OK|MB_ICONERROR);if(ch[i-1]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='(') MessageBox(NULL,"含有一对空括号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='+') MessageBox(NULL,"多了最后的'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='-') MessageBox(NULL,"多了最后的'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='*') MessageBox(NULL,"多了最后的'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='/') MessageBox(NULL,"多了最后的'/'号","提示",MB_OK|MB_ICONINFORMA TION);}}flag=1;}}}void T(char ch[]){if(ch[i]=='*'||ch[i]=='/')程序代码{i++;if(ch[i]!=NULL&&ch[i]!='+'&&ch[i]!='-'&&ch[i]!='*'&&ch[i]!='/')F(ch);else{if(flag==0){MessageBox(NULL,"输入表达式不符合文法3","错误",MB_OK|MB_ICONERROR);if(ch[i]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='+') MessageBox(NULL,"多了'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='-') MessageBox(NULL,"多了'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='*') MessageBox(NULL,"多了'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='/') MessageBox(NULL,"多了'/'号","提示",MB_OK|MB_ICONINFORMA TION);}flag=1;}}elseE(ch);}void E(char ch[]){if(ch[i]=='+'||ch[i]=='-'){i++;if(ch[i]!=NULL&&ch[i]!='+'&&ch[i]!='-'&&ch[i]!='*'&&ch[i]!='/')F(ch);else{if(flag==0){if(ch[i]!=NULL){MessageBox(NULL,"输入表达式不符合文法4.1","错误",MB_OK|MB_ICONERROR);if(ch[i]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);程序代码else if(ch[i]=='+') MessageBox(NULL,"多了'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='-') MessageBox(NULL,"多了'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='*') MessageBox(NULL,"多了'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='/') MessageBox(NULL,"多了'/'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]==NULL){MessageBox(NULL,"输入表达式不符合文法4.2","错误",MB_OK|MB_ICONERROR);if(ch[i-1]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='+') MessageBox(NULL,"多了最后的'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='-') MessageBox(NULL,"多了最后的'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='*') MessageBox(NULL,"多了最后的'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='/') MessageBox(NULL,"多了最后的'/'号","提示",MB_OK|MB_ICONINFORMA TION);}}flag=1;}}else if(ch[i]!=')'){if(flag==0){MessageBox(NULL,"输入表达式不符合文法5","错误",MB_OK|MB_ICONERROR);if(ch[i]=='('&&ch[i+2]==')') MessageBox(NULL,"含有一对多余的括号","提示",MB_OK|MB_ICONINFORMA TION);else MessageBox(NULL,"其他类型的错误","提示",MB_OK|MB_ICONINFORMA TION);}flag=1;}}实验结果分析及心得体会实验结果分析:本次实验借助语法分析,设计一个表达式的判断分析器,从键盘上输入算术表达式,分析器对该表达式的正确与否进行分析。

语法分析器实验报告

语法分析器实验报告

语法分析器的设计实验报告一、实验内容语法分析程序用LL(1)语法分析方法。

首先输入定义好的文法书写文件(所用的文法可以用LL(1)分析),先求出所输入的文法的每个非终结符是否能推出空,再分别计算非终结符号的FIRST集合,每个非终结符号的FOLLOW集合,以及每个规则的SELECT集合,并判断任意一个非终结符号的任意两个规则的SELECT集的交集是不是都为空,如果是,则输入文法符合LL(1)文法,可以进行分析。

对于文法:G[E]:E->E+T|TT->T*F|FF->i|(E)分析句子i+i*i是否符合文法。

二、基本思想1、语法分析器实现语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行词法检查,为语义分析和代码生成作准备。

这里采用自顶向下的LL(1)分析方法。

语法分析程序的流程图如图5-4所示。

语法分析程序流程图该程序可分为如下几步:(1)读入文法(2)判断正误(3)若无误,判断是否为LL(1)文法(4)若是,构造分析表;(5)由句型判别算法判断输入符号串是为该文法的句型。

三、核心思想该分析程序有15部分组成:(1)首先定义各种需要用到的常量和变量;(2)判断一个字符是否在指定字符串中;(3)读入一个文法;(4)将单个符号或符号串并入另一符号串;(5)求所有能直接推出&的符号;(6)求某一符号能否推出‘& ’;(7)判断读入的文法是否正确;(8)求单个符号的FIRST;(9)求各产生式右部的FIRST;(10)求各产生式左部的FOLLOW;(11)判断读入文法是否为一个LL(1)文法;(12)构造分析表M;(13)句型判别算法;(14)一个用户调用函数;(15)主函数;下面是其中几部分程序段的算法思想:1、求能推出空的非终结符集Ⅰ、实例中求直接推出空的empty集的算法描述如下:void emp(char c){ 参数c为空符号char temp[10];定义临时数组int i;for(i=0;i<=count-1;i++)从文法的第一个产生式开始查找{if 产生式右部第一个符号是空符号并且右部长度为1,then将该条产生式左部符号保存在临时数组temp中将临时数组中的元素合并到记录可推出&符号的数组empty中。

语法分析实验报告

语法分析实验报告

语法分析实验报告一、实验目的语法分析是编译原理中的重要环节,本次实验的目的在于深入理解和掌握语法分析的基本原理和方法,通过实际操作和实践,提高对编程语言语法结构的分析能力,为进一步学习编译技术和开发相关工具打下坚实的基础。

二、实验环境本次实验使用的编程语言为 Python,使用的开发工具为 PyCharm。

三、实验原理语法分析的任务是在词法分析的基础上,根据给定的语法规则,将输入的单词符号序列分解成各类语法单位,并判断输入字符串是否符合语法规则。

常见的语法分析方法有自顶向下分析法和自底向上分析法。

自顶向下分析法包括递归下降分析法和预测分析法。

递归下降分析法是一种直观、简单的方法,但存在回溯问题,效率较低。

预测分析法通过构建预测分析表,避免了回溯,提高了分析效率,但对于复杂的语法规则,构建预测分析表可能会比较困难。

自底向上分析法主要包括算符优先分析法和 LR 分析法。

算符优先分析法适用于表达式的语法分析,但对于一般的上下文无关文法,其适用范围有限。

LR 分析法是一种功能强大、适用范围广泛的方法,但实现相对复杂。

四、实验内容(一)词法分析首先,对输入的源代码进行词法分析,将其分解为一个个单词符号。

单词符号包括关键字、标识符、常量、运算符、分隔符等。

(二)语法规则定义根据实验要求,定义了相应的语法规则。

例如,对于简单的算术表达式,可以定义如下规则:```Expression > Term | Expression '+' Term | Expression ''TermTerm > Factor | Term '' Factor | Term '/' FactorFactor >'(' Expression ')'| Identifier | Number```(三)语法分析算法实现选择了预测分析法来实现语法分析。

首先,根据语法规则构建预测分析表。

然后,从输入字符串的起始位置开始,按照预测分析表的指导进行分析。

语法分析实验报告

语法分析实验报告

语法分析实验报告一、语法分析功能与目的语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成作准备。

执行语法分析任务的程序叫语法分析程序或语法分析器。

语法分析程序以词法分析输出的符号串作为输入,在分析过程中检查这个符号串是否为该程序语言的句子。

如是,则输出该句子的分析数,否则就表示源程序存在语法错误,需要报告错误的性质和位置。

二、TEST语法规则①<程序>∶∶={<声明序列><语句序列>}②<声明序列>∶∶=<声明序列><声明语句>|ε③<声明语句>∶∶=int <标识符>;④<语句序列>::=<语句序列><语句>|ε⑤<语句>::=<if语句>|<while语句>|<do语句>|<for语句>|<read语句>|<write语句>|<复合语句>|<表达式语句>⑥<if语句>::=if(<表达式>)<语句>[else<语句>]⑦<while语句>::=while(<表达式>)<表达式>⑧<for语句>:=for(<表达式>;<表达式>;<表达式>)<语句>⑨<write语句>::=write<表达式>;⑩<read语句>::=read<标识符>;⑴<复合语句>::={<语句序列>}⑵<表达式语句>:=<表达式>;|;⑶<表达式>::=<标识符>=<布尔表达式>|<布尔表达式>⑷<布尔表达式>:=<算术表达式>|<算术表达式>(>|<|>=|<=|==|!=)<算术表达式>⑸<算术表达式>::=<项>{(+|-)<项>}⑹<项>::=<因子>{(*|/)<因子>}⑺<因子>::=(<表达式>)|<标识符>|<无符号整数>⑻<do语句>::=do<语句>while(<表达式>);三、实验四要求及改进思路实验要求:修改词法分析程序TESTscan.c和语法分析程序TESTparse.c这二个文件,使该程序能分析:(1) do语句(有关文法规则参见P77的习题8。

语法分析实验报告

语法分析实验报告

一、实验目的1. 了解语法分析的基本概念和原理。

2. 掌握语法分析的方法和步骤。

3. 提高对自然语言处理领域中语法分析技术的理解和应用能力。

二、实验内容1. 语法分析的基本概念语法分析是指对自然语言进行结构分析,将句子分解成词、短语和句子成分的过程。

通过语法分析,可以了解句子的结构、语义和语用信息。

2. 语法分析方法语法分析方法主要有两种:句法分析和语义分析。

(1)句法分析:句法分析是指根据语法规则,对句子进行分解和组合的过程。

常见的句法分析方法有:词法分析、短语结构分析、句法分析。

(2)语义分析:语义分析是指对句子进行分析,以揭示句子所表达的意义。

常见的语义分析方法有:词汇语义分析、句法语义分析、语用语义分析。

3. 语法分析步骤(1)词法分析:将句子中的单词进行分类,提取词性、词义和词形变化等特征。

(2)短语结构分析:将词法分析得到的词组进行分类,提取短语结构、短语成分和短语关系等特征。

(3)句法分析:根据短语结构分析的结果,将句子分解成句子成分,分析句子成分之间的关系。

(4)语义分析:根据句法分析的结果,分析句子所表达的意义。

三、实验过程1. 实验环境:Python 3.8,NLTK(自然语言处理工具包)。

2. 实验步骤:(1)导入NLTK库。

(2)加载句子数据。

(3)进行词法分析,提取词性、词义和词形变化等特征。

(4)进行短语结构分析,提取短语结构、短语成分和短语关系等特征。

(5)进行句法分析,分解句子成分,分析句子成分之间的关系。

(6)进行语义分析,揭示句子所表达的意义。

四、实验结果与分析1. 词法分析结果实验句子:“我喜欢吃苹果。

”词性标注:我/代词,喜欢/动词,吃/动词,苹果/名词。

2. 短语结构分析结果实验句子:“我喜欢吃苹果。

”短语结构:主语短语(我),谓语短语(喜欢吃苹果)。

3. 句法分析结果实验句子:“我喜欢吃苹果。

”句子成分:主语(我),谓语(喜欢),宾语(吃苹果)。

4. 语义分析结果实验句子:“我喜欢吃苹果。

语法分析器实验报告

语法分析器实验报告

语法分析器实验报告实验报告:语法分析器的设计与实现摘要:语法分析器是编译器的一个重要组成部分,主要负责将词法分析器输出的词法单元序列进行分析和解释,并生成语法分析树。

本实验旨在设计与实现一个基于上下文无关文法的语法分析器,并通过实现一个简单的编程语言的解释器来验证其功能。

1.引言在计算机科学中,编译器是将高级程序语言转化为机器语言的一种工具。

编译器通常由词法分析器、语法分析器、语义分析器、中间代码生成器、优化器和目标代码生成器等多个模块组成。

其中,语法分析器负责将词法分析器生成的词法单元序列进行进一步的分析与解释,生成语法分析树,为后续的语义分析和中间代码生成提供基础。

2.设计与实现2.1上下文无关文法上下文无关文法(CFG)是指一类形式化的语法规则,其中所有的产生式规则都具有相同的左部非终结符,且右部由终结符和非终结符组成。

语法分析器的设计与实现需要依据给定的上下文无关文法来进行,在本实验中,我们设计了一个简单的CFG,用于描述一个名为"SimpleLang"的编程语言。

2.2预测分析法预测分析法是一种常用的自顶向下的语法分析方法,它利用一个预测分析表来决定下一步的推导选择。

预测分析表的构造依赖于给定的上下文无关文法,以及文法的FIRST集和FOLLOW集。

在本实验中,我们使用了LL(1)的预测分析法来实现语法分析器。

2.3语法分析器实现在实现语法分析器的过程中,我们首先需要根据给定的CFG构造文法的FIRST集和FOLLOW集,以及预测分析表。

接下来,我们将词法分析器输出的词法单元序列作为输入,通过不断地匹配输入符号与预测分析表中的预测符号,进行语法分析和推导。

最终,根据CFG和推导过程,构建语法分析树。

3.实验结果与分析通过实验发现,自顶向下的预测分析法在对简单的编程语言进行语法分析时具有较高的效率和准确性。

语法分析器能够正确地识别输入程序中的语法错误,并生成相应的错误提示信息。

语法分析器实验报告

语法分析器实验报告

杭州电子科技大学班级: 12052312 专业: 计算机科学与技术实验报告【实验名称】实验二语法分析一. 实验目的编写一个语法分析程序, 实现对词法分析程序所提供的单词序列的语法检查和结构分析。

二. 实验内容利用编程语言实现语法分析程序, 并对简单语言进行语法分析。

2.1 待分析的简单语言的语法用扩充的BNF表示如下:⑴<程序>: : =begin<语句串>end⑵<语句串>: : =<语句>{;<语句>}⑶<语句>: : =<赋值语句>⑷<赋值语句>: : =ID: =<表达式>⑸<表达式>: : =<项>{+<项> | -<项>}⑹<项>: : =<因子>{*<因子> | /<因子>⑺<因子>: : =ID | NUM | (<表达式>)2.2 实验要求说明输入单词串, 以“#”结束, 如果是文法正确的句子, 则输出成功信息, 打印“success”, 否则输出“error”。

例如:输入begin a:=9; x:=2*3; b:=a+x end #输出success!输入x:=a+b*c end #输出error测试以上输入的分析, 并完成实验报告。

2.3 语法分析程序的算法思想(1)主程序示意图如图2-1所示。

图2-1 语法分析主程序示意图(2)递归下降分析程序示意图如图2-2所示。

(3)语句串分析过程示意图如图2-3所示。

图2-3 语句串分析示意图图2-2 递归下降分析程序示意图(4)statement 语句分析程序流程如图2-4.2-5.2-6.2-7所示。

图2-4 statement 语句分析函数示意图 图2-5 expression 表达式分析函数示意图图2-7 factor 分析过程示意图三.个人心得一、 通过该实验, 主要有以下几方面收获: 二、 对实验原理有更深的理解。

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

语法分析器的设计实验报告一、实验内容语法分析程序用LL(1) 语法分析方法。

首先输入定义好的文法书写文件(所用的文法可以用LL(1) 分析),先求出所输入的文法的每个非终结符是否能推出空,再分别计算非终结符号的FIRST 集合,每个非终结符号的 FOLLOW 集合,以及每个规则的 SELECT 集合,并判断任意一个非终结符号的任意两个规则的 SELECT 集的交集是不是都为空,如果是,则输入文法符合 LL(1) 文法,可以进行分析。

对于文法:G[E]:E->E+T|TT->T*F|FF->i|(E)分析句子 i+i*i 是否符合文法。

二、基本思想1、语法分析器实现语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行词法检查,为语义分析和代码生成作准备。

这里采用自顶向下的 LL(1) 分析方法。

语法分析程序的流程图如图5-4 所示。

开始读入文法有效?是 LL(1) 文法?判断句型结束报错语法分析程序流程图该程序可分为如下几步:(1)读入文法(2)判断正误(3)若无误,判断是否为LL(1) 文法(4)若是,构造分析表;(5)由句型判别算法判断输入符号串是为该文法的句型。

三、核心思想该分析程序有 15 部分组成:(1)首先定义各种需要用到的常量和变量;(2)判断一个字符是否在指定字符串中;(3)读入一个文法;(4)将单个符号或符号串并入另一符号串;(5)求所有能直接推出 & 的符号;(6)求某一符号能否推出‘& ’;(7)判断读入的文法是否正确;(8)求单个符号的 FIRST;(9)求各产生式右部的FIRST;(10)求各产生式左部的FOLLOW ;(11)判断读入文法是否为一个LL(1) 文法;(12)构造分析表 M ;(13)句型判别算法;(14)一个用户调用函数;(15)主函数;下面是其中几部分程序段的算法思想:1、求能推出空的非终结符集Ⅰ、实例中求直接推出空的empty 集的算法描述如下:void emp(char c){ 参数 c 为空符号char temp[10]; 定义临时数组int i;for(i=0;i<=count-1;i++) 从文法的第一个产生式开始查找{i f 产生式右部第一个符号是空符号并且右部长度为then 将该条产生式左部符号保存在临时数组将临时数组中的元素合并到记录可推出1,temp 中& 符号的数组empty中。

}Ⅱ、求某一符号能否推出'&' int _emp(char c){ // 若能推出& ,返回1;否则,返回int i,j,k,result=1,mark=0; char temp[20];temp[0]=c;temp[1]='\0';存放到一个临时数组 empt 如果c 在可直接推出空字的里,标识此字符已查找其是否可推出空字empty[] 中, 返回 1for(i=0;;i++){if(i==count)return(0);找一个左部为j=strlen(right [i]); c 的产生式//j为c 所在产生式右部的长度i fi f 右部长度为右部长度为1 且右部第一个字符在1 但第一个字符为终结符empty[] 中. then 返回 1(A->B,B 可推出空,then 返回 0(A->a,a 为终结符 ))else{for(k=0;k<=j-1;k++) {查找临时数组 empt[]. 并标记 mark-=1(A->AB) if 找到的字符与当前字符相同 (A->AB)结束本次循环 else(mark 等于 0)查找右部符号是否可推出空字 ,把返回值赋给 result 把当前符号加入到临时数组 empt[] 里 .}if 当前字符不能推出空字且还没搜索完全部的产生式 then 跳出本次循环继续搜索下一条产生式 else if // 当前字符可推出空字 , 返回 1 }}}2、计算每个符号的 first 集:实例中求单个符号的 FIRST 集的算法描述如下:void first2 (int i) {参数 i 为符号在所有输入符号中的序号 c 等于指示器 i 所指向的符号在保存终结符元素的 termin[] 数组查找 c if c 为终结符 (c ∈ VT ), thenFIRST(c)={c}在保存终结符元素的 non_ter[] 数组查找 c if c 是非终结符 (c ∈V N )在所有产生式中查找 c 所在的产生式if 产生式右部第一个字符为终结符或空 (即 c → a (a ∈ VT)或 c →&) then把 a 或 & 加进FIRST(c)if 产生式右部第一个字符为非终结符 thenif 产生式右部的第一个符号等于当前字符 then跳到下一条产生式进行查找求当前非终结符在所有字符集中的位置if 当前非终结符还没求其 FIRST 集 then查找它的 FIRST 集并标识此符号已求其 FIRST 集求得结果并入到 c 的 FIRST 集 .if 当前产生式右部符号可推出空字且当前字符不是右部的最后一个字符then获取右部符号下一个字符在所有字符集中的位置if 此字符的 FIRST 集还未查找 then找其 FIRST 集 ,并标其查找状态为1 把求得的 FIRST 集并入到 c 的 FIRST 集.if 当前右部符号串可推出空且是右部符号串的最后一个字符 ( 即产生式为 c →1 2⋯ Yki) ,则将 & ∈符号加进FIRST(c) )Y Y ,若对一切 1<=i<=k ,均有 & ∈FIRST(Ythen把空字加入到当前字符 c 的 FIRST 集 .else不能推出空字则结束循环标识当前字符c 已查找其FIRST 集 . }3. 计算 FOLLOW集FOLLOW 集的构造可用如下方法来求:对于文法中的符号X V N,其FOLLOW(A) 集合可反复应用下列规则计算,直到FOLLOW(A) 集合不再增大为止。

(1) 对于文法开始符号 S,因为 S S,故 # FOLLOW(S) ;(2) 若 A→ B ,其中 B V N,(V T V N)*、(V T V N) +,则FIRST( )-{ } FOLLOW(B) ;(3) 若 A→ B 或 A→ B ( ) ,则FOLLOW(A) FOLLOW(B) 。

FOLLOW 集的算法描述如下:void FOLLOW(int i)X为待求的非终结符把当前字符放到一临时数组 foll[] 中 ,标识求已求其 FOLLOW 集 .避免循环递归 if X 为开始符号 then #∈ FOLLOW(X)对全部的产生式找一个右部含有当前字符X 的产生式注:比如求FOLLOW(B) 则找 A→ αX 或 A →X ( ε )的产生式if X 在产生式右部的最后( 形如产生式 A→X) then查找非终结符A 是否已经求过其FOLLOW 集.避免循环递归if 非终结符A 已求过其FOLLOW 集thenFOLLOW(A) ∈FOLLOW(X)继续查下一条产生式是否含有Xelse求A 之 FOLLOW 集,并标识为 A 已求其 FOLLOW 集else if X 不在产生式右部的最后(形如 A→ B ) thenif 右部 X 后面的符号串能推出空字then查找是否已经求过其FOLLOW 集. 避免循环递归if 已求过的 FOLLOW 集thenFOLLOW(A) ∈FOLLOW(B)结束本次循环else if 不能推出空字then求FIRST( )把FIRST( )中所有非空元素加入到 FOLLOW(B) 中标识当前要求的非终结符X 的 FOLLOW 集已求过4. 计算 SELECT集SELECT 集的构造算法如下:对所有的规则产生式A→ x:(1) 若 x 不能推出空字,则 SELECT(A → x) = FIRST(x) ;(2) 若x 可推出空字,则SELECT(A →x)=FIRST(x) – { } FOLLOW(A) 。

算法描述如下:for(i=0;i<= 产生式总数-1;i++)先把当前产生式右部的FIRST 集 ( 一切非空元素, 不包括ε)放入到当前产生式的SELECT(i);i f 产生式右部符号串可推出空字then把 i 指向的当前产生式左部的非终结符号的FOLLOW集并入到SELECT(i) 中5.判断是否 LL(1) 文法要判断是否为LL(1) 文法,需要输入的文法G 有如下要求:具有相同左部的规则的SELECT 集两两不相交,即:SELECT(A →) ∩SELECT(A →)=如果输入的文法都符合以上的要求,则该文法可以用算法描述如下:把第一条产生式的SELECT(0) 集放到一个临时数组for(i=1;i<= 产生式总数 -1;i++)LL(1) 方法分析。

temp[] 中求temp 的长度 lengthif i 指向的当前产生式的左部等于上一条产生式的左部then 把SELECT(i) 并入到 temp 数组中If temp 的长度小于 length 加上 SELECT (i) 的长度返回 0else把temp 清空把SELECT (i) 存放到 temp 中结果返回 1;四、算法#include<stdlib.h>#include<stdio.h>#include<string.h>/*******************************************/int count=0; // 产生式的个数int number; // 所有终结符和非终结符的总数char start; // 开始符号char termin[50]; // 终结符号char non_ter[50]; //非终结符号char v[50]; // 所有符号char left[50]; // 左部char right[50][50]; //右部char first[50][50],follow[50][50]; //各产生式右部的FIRST 和左部的 FOLLOW 集合char first1[50][50]; // 所有单个符号的 FIRST 集合char select[50][50]; // 各个产生式的SELECT 集合char firstflag[50],followflag[50]; // 记录各符号的FIRST 和 FOLLOW 是否已求过char empty[20]; // 记录可推出 & 的符号char nonempty[20]; // 记录不可推出 & 的符号char empt[20]; // 求 _emp()时使用char TEMP[50]; // 求 FOLLOW 时存放某一符号串的FIRST 集合int validity=1; // 表示输入文法是否有效int ll=1; // 表示输入文法是否为 LL(1) 文法int M[20][20]; // 分析表char choose; // 用户输入时使用char foll[20]; // 求 FOLLOW 集合时使用/*******************************************判断一个字符c 是否在指定字符串p 中********************************************/int in(char c,char *p){int i;if(strlen(p)==0)return(0);for(i=0;;i++){if(p[i]==c)return(1); //若在,返回 1if(i==(int)strlen(p))return(0); //若不在,返回 0}}/*******************************************将单个符号或符号串并入另一符号串********************************************/void merge(char *d,char *s,int type){ // 是目标符号串,s 是源串, type= 1,源串中的 '&' 一并并入目串;//type= 2,源串中的 '&' 不并入目串int i,j;for(i=0;i<=(int)strlen(s)-1;i++){if(type==2&&s[i]=='&');else{for(j=0;;j++){if(j<(int)strlen(d)&&s[i]==d[j])break; // 若已存在,则退出,继续看下一个源串字符if(j==(int)strlen(d)) // 若不存在,则并入{d[j]=s[i];d[j+1]='\0';break;}}}}}/*******************************************读入一个文法********************************************/char grammer(char *t,char *n,char *left,char right[50][50]) {char vn[50],vt[50];char s;char p[50][50];int i,j;printf(" 请输入文法的非终结符号串:");scanf("%s",vn);getchar();i=strlen(vn);memcpy(n,vn,i);n[i]='\0';请输入文法的终结符号串:");printf("scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';请输入文法的开始符号:");printf("scanf("%c",&s);getchar();printf(" 请输入文法产生式的条数:scanf("%d",&i);getchar();count=i;for(j=1;j<=i;j++){");printf(" 请输入文法的第%d条(共%d 条)产生式:",j,i);scanf("%s",p[j-1]);getchar();}for(j=0;j<=i-1;j++){if(p[j][1]!='-'||p[j][2]!='>') // 检测输入错误{printf("\n 输入错误 !");validity=0;return('\0');}}return(s);}/*******************************************判断读入的文法是否正确********************************************/int judge(){int i,j;for(i=0;i<=count-1;i++){if(in(left[i],non_ter)==0){ // 若左部不在非终结符中,报错printf("\n 文法左部出错!");validity=0;return(0);}for(j=0;j<=(int)strlen(right[i])-1;j++){if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='&'){ // 若右部某一符号不在非终结符、终结符中且不为'&' ,报错printf("\n 文法右部出错!");validity=0;return(0);}}}return(1);}/******************************************* 求所有能直接推出& 的符号********************************************/ void emp(char c){char temp[10];int i;for(i=0;i<=count-1;i++){if(right[i][0]==c&&strlen(right[i])==1){temp[0]=left[i];temp[1]='\0';merge(empty,temp,1);// 求所有能直接推出 '&" 的符号 ,结果保存到empty[] 中 emp(left[i]);}}}/*******************************************求某一符号能否推'&'出********************************************/int _emp(char c){ // 若能推出 & ,返回 1;否则,返回0int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);// 存放到一个临时数组empt 里 ,标识此字符已查找其是否可推出空字if(in(c,empty)==1)// 如果 c 在可直接推出空字的 empty[] 中,返回 1 return(1);for(i=0;;i++){if(i==count)return(0);c 的产生式if(left[i]==c) // 找一个左部为{j=strlen(right[i]); //j 为 c 所在产生式右部的长度if(j==1&&in(right[i][0],empty)==1)// 右部长度为 1 且右部第一个字符在empty[]中. 返回 1(A->B,B 可推出空 )return(1);else if(j==1&&in(right[i][0],termin)==1)// 右部长度为 1 但第一个字符为终结符 ,返回 0(A->a,a 为终结符 )continue;else{for(k=0;k<=j-1;k++){if(in(right[i][k],empt)==1)// 查找临时数组empt[].(A->AB)mark=1;}if(mark==1)continue;else//(mar k{//找到的字符与当前字符相同// 结束本次循环等于 0)(A->AB)for(k=0;k<=j-1;k++){result*=_emp(right[i][k]);// 递归调用,查找右部符号是否可推出空字, 把返回值赋给 resulttemp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);// 把当前符号加入到临时数组empt[] 里,标记已查找}}}if(result==0&&i<count)// 如果当前字符不能推出空字且还没搜索完全部的产生式, 则跳出本次循环继续搜索下一条产生式 continue;else if(result==1&&i<count)// 当前字符可推出空字,返回 1 return(1);}}}/*******************************************求单个符号的FIRST********************************************/void first2(int i){ //i 为符号在所有输入符号中的序号char c,temp[20];int j,k,m;char ch='&'; c=v[i];emp(ch);// 求所有能直接推出空字的符号,结果保存到empty[] 中if(in(c,termin)==1) // 若为终结符--c∈ VT ,则FIRST(c)={c}{first1[i][0]=c;first1[i][1]='\0';}else if(in(c,non_ter)==1){// 若为非终结符for(j=0;j<=count-1;j++) //j 为所有产生式中的序列{if(left[j]==c) // 找一个左部为 c 的产生式{if(in(right[j][0],termin)==1||right[j][0]=='&'){// 若产生式右部第一个字符为终结符或空.--- 产生式 X → a (a∈ VT) 或 X →&, 则把 a 或 & 加进 FIRST(X)temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);}//------X → Y1Y2 ⋯ Yk 的产生式,若Y1∈ VN ,则把 FIRST(Y1) 中的一切非空符号加进FIRST(X)else if(in(right[j][0],non_ter)==1)// 产生式右部第一个字符为非终结符{if(right[j][0]==c)// 产生式右部的第一个符号等于当前字符,则跳到下一条产生式进行查找continue;for(k=0;;k++){if(v[k]==right[j][0])// 求右部第一个字符在所有字符集中的位置kbreak;}if(firstflag[k]=='0'){first2(k);// 求其 FIRST 集firstflag[k]='1';// 标识其为查找状态}merge(first1[i],first1[k],2);// 求得结果并入到X 的 FIRST 集.for(k=0;k<(int)strlen(right[j]);k++){empt[0]='\0';// 存放到一个临时数组里, 标识此字符已查找其是否可推出空字if(_emp(right[j][k])==1&&k<(int)strlen(right[j])-1){// 当前产生式右部符号可推出空字,且当前字符不是右部的最后一个字符for(m=0;;m++){if(v[m]==right[j][k+1])// 获取右部符号下一个字符在所有字符集中的位置break;}if(firstflag[m]=='0')// 如果此字符的 FIRST 集还未查找 ,则找其 FIRST 集 , 并标其查找状态为 1{first2(m);firstflag[m]='1';}merge(first1[i],first1[m],2);// 把求得结果并入到X的 FIRST集.}//---- 产生式为X → Y1Y2 ⋯ Yk, 若对一切1<=i<=k ,均有 & ∈FIRST(Yi) ,则将 & ∈符号加进FIRST(X)else if(_emp(right[j][k])==1&&k==(int)strlen(right[j])-1){// 当前右部符号串可推出空且是右部符号串的最后一个字符temp[0]='&';temp[1]='\0';merge(first1[i],temp,1);// 把空字加入到当前字符X 的 FIRST集.}elsebreak;// 不能推出空字则结束循环}}}}}firstflag[i]='1';// 标识当前字符 c 已查找其FIRST 集}/*******************************************求各产生式右部的FIRST********************************************/void FIRST(int i,char *p){ // 指针 p 指向右部符号串int length;// 标识右部符号串的长度int j,k,m;char temp[20];length=strlen(p);if(length==1) // 如果右部为单个符号{if(p[0]=='&')// 右部符号串字符为 "&" 空字{if(i>=0)//i 不为 -1 时是产生式的序号{first[i][0]='&'; // 把 "&" 加入到当前符号串的FIRST 集first[i][1]='\0'; }else//i 为 -1 时,表示求FOLLOW时用到的产生式右部的FIRST 集 ,保存在TEMP[]中{TEMP[0]='&';TEMP[1]='\0';}}else//右部符号串字符不为"&" 空字{for(j=0;;j++){if(v[j]==p[0])// 求右部符号的第一个字符p[0] 在所有字符集中的位置jbreak;}if(i>=0){memcpy(first[i],first1[j],strlen(first1[j]));// 把 j 所指向的单个符号的FIRST 集拷贝到该右部符号串的 FIRST 集first[i][strlen(first1[j])]='\0';}else{memcpy(TEMP ,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';}}}else // 如果右部为符号串{for(j=0;;j++){if(v[j]==p[0])// 求右部符号的第一个字符p[0] 在所有字符集中的位置jbreak;}if(i>=0)merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2);for(k=0;k<=length-1;k++){empt[0]='\0';if(_emp(p[k])==1&&k<length-1){ // 当前产生式右部符号可推出空字 ,且当前字符不是右部的最后一个字符 for(m=0;;m++){if(v[m]==right[i][k+1])break;}if(i>=0)merge(first[i],first1[m],2);elsemerge(TEMP,first1[m],2);}else if(_emp(p[k])==1&&k==length-1){// 当前右部符号串可推出空且是右部符号串的最后一个字符temp[0]='&';temp[1]='\0';if(i>=0)merge(first[i],temp,1);elsemerge(TEMP,temp,1);}else if(_emp(p[k])==0)break;}}}/*******************************************求各产生式左部的FOLLOW********************************************/void FOLLOW(int i){ // 参数 i 为该符号在非终结符中的位置int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; //c 为待求的非终结符temp[0]=c;temp[1]='\0';merge(foll,temp,1);// 把当前字符放到一临时数组foll[] 中 ,标识求已求其FOLLOW 集 .避免循环递归if(c==start){ //若为开始符号 ----- 开始符号 S,则 #∈ FOLLOW(S) temp[0]='#';temp[1]='\0';merge(follow[i],temp,1);}for(j=0;j<=count-1;j++){if(in(c,right[j])==1) // 找一个右部含有当前字符 c 的产生式{// 比如求 FOLLOW(B) 则找 A→ α B 或 A→ α Bβ( β =>*&) 的产生式for(k=0;;k++){if(right[j][k]==c)break; //k 为 c 在该产生式右部的序号,如B 在产生式A→ αB中的位置}for(m=0;;m++){if(v[m]==left[j])break; //m为产生式左部非终结符在所有符号中的序号}// 如果c 在产生式右部的最后,形如产生式A→ α B,则FOLLOW(A)∈ FOLLOW(B) if(k==(int)strlen(right[j])-1){if(in(v[m],foll)==1)//查找该非终结符是否已经求过其FOLLOW集 .避免循环递归{// 是则 FOLLOW(A) ∈ FOLLOW(B)merge(follow[i],follow[m],1);// 把 c 所在产生式的左部非终结符的 FOLLOW 集加入到 FOLLOW(c) 中continue;// 结束本次循环 ,进入 j++ 循环}if(followflag[m]=='0'){// 如果该非终结符的 FOLLOW 未求过FOLLOW(m);// 求之 FOLLOW 集followflag[m]='1';// 标识为 1}merge(follow[i],follow[m],1);//FOLLOW(A)∈ FOLLOW(B)}else{ // 如果 c 不在产生式右部的最后 for(n=k+1;n<=(int)strlen(right[j])-1;n++) { , 形如A→ α Bβempt[0]='\ 0';// 把empt[] 置空 , 因为求此字符是否可推出空字_emp(c) 时用到result*=_emp(right[j][n]);}if(result==1){ //如果右部c 后面的符号串能推出空,A → α Bβ(β =>*&) 则FOLLOW(A) ∈ FOLLOW(B)if(in(v[m],foll)==1){ //查找该非终结符是否已经求过其FOLLOW集 .避免循环递归merge(follow[i],follow[m],1);//FOLLOW(A)∈ FOLLOW(B)continue;}if(followflag[m]=='0'){FOLLOW(m);followflag[m]='1';}merge(follow[i],follow[m],1);}// 若 A→ α Bβ,其中 B∈ VN ,α∈ (VT U VN)* 、β∈ (VT U VN)+ ,则 FIRST( β)-{ ε } ∈FOLLOW(B) ;for(n=k+1;n<=(int)strlen(right[j])-1;n++){temp[n-k-1]=right[j][n];}temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);// 求 FIRST( β)merge(follow[i],TEMP ,2);// 把FIRST( β ) 中所有非空元素加入到FOLLOW(B) 中}}}followflag[i]='1';// 标识当前要求的非终结符的FOLLOW 集已求过}/*******************************************判断读入文法是否为一个LL(1) 文法********************************************/int LL1(){int i,j,length,result=1;char temp[50];for(j=0;j<=49;j++){ // 初始化first[j][0]='\0';follow[j][0]='\0';first1[j][0]='\0';select[j][0]='\0';TEMP[j]='\0';temp[j]='\0';firstflag[j]='0';// 用来记录该字符的followflag[j]='0';// 用来记录该字符的FIRST 集是否已求过 .1 表示已求 ,0 表示未求FOLLOW 集是否已求过 .1 表示已求 ,0 表示未求}for(j=0;j<=(int)strlen(v)-1;j++){first2(j); // 求单个符号的FIRST 集合 ,结果保存在first1[] 里}printf("\n 各非终结符推出的first集 :\n");for(j=0;j<=(int)strlen(v)-1;j++){printf("%c:%s",v[j],first1[j]);}printf("\n 能导空的非终结符集合:%s",empty); printf("\n_emp:");for(j=0;j<=(int)strlen(v)-1;j++)printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); //求FIRSTfor(j=0;j<=(int)strlen(non_ter)-1;j++){ // 求FOLLOW if(foll[j]==0){foll[0]='\0';FOLLOW(j);}}printf("\nfirst 集 :");for(i=0;i<=count-1;i++)printf("%s ",first[i]);printf("\nfollow 集合 :");for(i=0;i<=(int)strlen(non_ter)-1;i++) printf("%s ",follow[i]); for(i=;i<=count-1;i++){ // 求每一产生式的SELECT 集合memcpy(select[i],first[i],strlen(first[i]));//first[] 存放的是各产生式右部的select[i][strlen(first[i])]='\0';for(j=0;j<=(int)strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='&')// 形如产生式A->&FIRST 集result=1;if(result==1){for(j=0;;j++)if(v[j]==left[i])//j 为左部符号在所有字符集中的位置break;merge(select[i],follow[j],1);}}printf("\nselect 集合顺序是 :");for(i=0;i<=count-1;i++)printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0]));temp[strlen(select[0])]='\0';for(i=1;i<=count-1;i++)LL(1) 文法 */{ /* 判断输入文法是否为length=strlen(temp);if(left[i]==left[i-1]){merge(temp,select[i],1);if(strlen(temp)<length+strlen(select[i]))// 比较两个产生式的 SELECT 长度 return(0);}else{temp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';}}return(1);}/*******************************************构造分析表M********************************************/void MM(){int i,j,k,m;for(i=0;i<=19;i++){for(j=0;j<=19;j++)// 初始化分析表,全部置为空 (-1) {M[i][j]=-1;}}i=strlen(termin);termin[i]='#'; //将 #加入终结符数组termin[i+1]='\0';for(i=0;i<=count-1;i++)// 查看每个产生式的SELECT 集{for(m=0;;m++){if(non_ter[m]==left[i])break; //m 为产生式左部非终结符的序号}for(j=0;j<=(int)strlen(select[i])-1;j++)// 对每个 SELECT 集中的所有元素进行操作{if(in(select[i][j],termin)==1){for(k=0;;k++){if(termin[k]==select[i][j])break; //k 为产生式右部终结符的序号}M[m][k]=i;}}}}/*******************************************判断符号串是否是该文法的句型********************************************/void syntax(){int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf(" 请输入该文法的句型:");scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1){if(in(S[strlen(S)-1],termin)==1){if(S[strlen(S)-1]!=ch){printf(" 该符号串不是文法的句型!");return;}else if(S[strlen(S)-1]=='#'){printf(" 该符号串是文法的句型 .");return;}else{S[strlen(S)-1]='\0';j++;ch=str[j];}}else{for(i=0;;i++)if(non_ter[i]==S[strlen(S)-1])break;for(k=0;;k++){if(termin[k]==ch)break;if(k==(int)strlen(termin)){printf(" 词法错误! ");return;}}if(M[i][k]==-1){printf(" 语法错误! ");return;}else{m=M[i][k];if(right[m][0]=='@')S[strlen(S)-1]='\0';else{p=strlen(S)-1;q=p;for(n=strlen(right[m])-1;n>=0;n--)S[p++]=right[m][n];S[q+strlen(right[m])]='\0';}}}printf("S:%s str:",S);for(p=j;p<=(int)strlen(str)-1;p++)printf("%c",str[p]);printf(" \n");}}/*******************************************一个用户调用函数********************************************/void menu(){syntax();printf("\n 是否继续? (y or n):");scanf("%c",&choose);getchar();while(choose=='y'){menu();}}/*******************************************主函数********************************************/void main(){int i,j;start=grammer(termin,non_ter,left,right); // 读入一个文法printf("count=%d",count);printf("\n 开始符号为 :%c",start);strcpy(v,non_ter);strcat(v,termin);printf("\n 所有符号集为 :%s",v);printf("\n 非终结符集合 :{%s",non_ter);printf("}");--学习资料分享----printf("\n 终结符集合 :{%s",termin);printf("}");printf("\n 文法所有右边表达式依次是:");for(i=0;i<=count-1;i++){printf("%s ",right[i]);}printf("\n 文法所有左边开始符依次是:");for(i=0;i<=count-1;i++){printf("%c ",left[i]);}if(validity==1)validity=judge();printf("\nvalidity=%d",validity);if(validity==1){ll=LL1();printf("\nll=%d",ll);if(ll==0)printf("\n 该文法不是一个LL1 文法! ");else{printf("\n 该文法是一个LL(1) 文法! ");MM();printf("\n");for(i=0;i<=19;i++)for(j=0;j<=19;j++)if(M[i][j]>=0)printf("M[%d][%d]=%d ",i,j,M[i][j]);menu();}}}--学习资料分享----由于算法仍有很多错误,最终结果没能实现,这点很失望!五、实验心得通过本次实验,我收获了很多东西。

相关文档
最新文档