编译原理课程设计LL(1)文法 do while 三地址输出 报告加代码
WHILE循环语句的翻译程序设计(简单优先法,三地址输出)

目录1 问题域描述 (3)2 文法及属性文法的描述 (3)2.1 WHILE循环语句的文法 (3)2.2 WHILE循环语句的属性文法 (4)3 语法分析方法及中间代码形式的描述 (4)3.1语法分析方法 (4)3.2中间代码形式描述 (6)4 编译系统的概要设计 (7)4.1词法分析 (7)4.2语法制导翻译 (8)5 详细的算法描述 (8)5.1 文法设计 (8)5.2 算法描述 (8)5.3 源程序代码 (9)6 软件的调试过程和结果测试 (19)6.1调试过程 (19)6.2结果测试 (19)7 使用说明 (20)8 课设总结 (20)9 参考文献 (22)WHILE循环语句的翻译程序设计(简单优先法、输出三地址表示)1 问题域描述while循环语句的翻译程序设计(简单优先法,输出单地址表示),要求完成:(1)用C++语言正确编写程序,完成WHILE循环语句的翻译程序设计。
(2)求能正确进行词法分析,语法分析,并能正确的输出预期结果。
(3)根据指定的文法,判定程序的正确性。
本次课程设计中要求设计一个WHILE循环语句的词法﹑语法及语义分析程序,语法分析选择简单优先法,采用语法制导翻译输出中间代码三元式。
通过设计、编制、调试一个WHILE循环语句的语法及语义分析程序,加深对语法及语义分析原理的理解,实现功能。
while循环语句的格式为:while(P){do A},其中A为循环体,可为一个或多个赋值语句;P为循环控制条件。
while循环语句首先根据循环控制条件P进行判断,若满足条件则执行循环体A,否则执行下面的程序段;本次课程设计中系统首先要进行词法分析,即从左到右把源文件的字符序列逐个进行扫描,产生一个个的单词序列,作为语法分析的输入从而继续编译过程。
该程序的语法分析读入词法分析的结果,并判断输入语句是否满足while循环语句的文法所描述的形式。
通过简单优先法对语句进行分析,看是否能通过给定的输入串归约到文法的开始符号。
编译原理课程设计LL(1)文法

本次课程设计主要是介绍LL(1)文法的一般原理,根据给定的一文法编制调试LL(1)文法语法分析程序,以便对任意输入的符号串进行分析。
本次课程设计的目的主要是加深对预测分析LL(1)文法语法分析的理解,加深对自顶向下语法分析方法的认识。
具体如下:1、对语法规则有明确的定义;2、编写的分析程序能够对给定文法进行正确的语法分析;3、对输入给定的文法,手工计算First、Follow集合以及各产生式的Select 集合,再根据Select集合构造出预测分析表;4、对于输入串,应能根据预测分析表判断识别该输入串是否为给定文法的句子;5、对于遇到的错误,给出简单的错误信息提示,保证能够顺利完成语法分析过程。
前言------------------------------------------------------------- Ⅰ目录------------------------------------------------------------- Ⅱ一、系统分析------------------------------------------------------ 11.1 判断LL(1)文法---------------------------------------------- 11.2 构造预测分析表---------------------------------------------- 1二、系统设计------------------------------------------------------ 22.1 基本设计---------------------------------------------------- 22.2 程序流程图-------------------------------------------------- 2三、系统实现------------------------------------------------------ 33.1 程序主要函数------------------------------------------------ 33.2 程序主要代码------------------------------------------------ 3四、系统测试------------------------------------------------------ 7五、总结---------------------------------------------------------- 8 参考文献---------------------------------------------------------- 9一、系统分析有文法G[E]:E->TG T->FSG->+TG|ε S->*FS|ε F->(E)|i 1.1 判断LL(1)文法当我们需选用自顶向下分析技术时,首先必须判别所给文法是否是LL(1)文法,分析所给文法可知文法中不含左公因子,也不存在左递归,因而再对给定文法计算First 集、Follow 集以及Select 集,对于求出的每个产生式的Select 集,看对于同一个左部非终结符是否存在交集,如果它们的交为空则表示所给文法是LL(1)文法,否则不是L(1)文法。
编译原理实验报告《ll(1)语法分析器构造》

规则右部首符号是终结
符
.
.
{ first[r].append(1,a); break;// 添加并结束
}
if(U.find(P[i][j])!=string::npos)// 规则右部首符号是非终结符 ,形如 X:: =Y1Y2...Yk
{
s=U.find(P[i][ j]);
//cout<<P[i][ j]<<":\n";
arfa=beta=""; for( j=0;j<100&&P[j][0]!=' ';j++) {
if(P[ j][0]==U[i]) {
if(P[ j][4]==U[i])// 产生式 j 有左递归 {
flagg=1;
.
.
for(temp=5;P[j][temp]!=' ';temp++) arfa.append(1,P[
{
int i,j,r,s,tmp;
string* first=new string[n];
char a;
int step=100;// 最大推导步数
while(step--){
// cout<<"step"<<100-step<<endl;
for(i=0;i<k;i++)
{
//cout<<P[i]<<endl;
j][temp]);
if(P[ j+1][4]==U[i]) arfa.append("|");//
《编译原理》课程设计说明书_DO_WHILE循环语句的翻译程序设计(LR方法、输出三地址表示)

DO-WHILE循环语句的翻译程序设计(LR方法、输出三地址表示)1.系统描述1.1设计目的通过设计、编制、调试一个DO-WHILE循环语句的语法及语义分析程序,加深对语法及语义分析原理的理解,并实现词法分析程序对单词序列的词法检查和分析。
1.2设计内容及步骤对循环语句:DO〈赋值语句〉WHILE 〈表达式〉按给定的题目写出符合自身语法分析方法要求的文法和属性文法描述。
(1)按给定的题目给出语法分析方法的思想及分析表设计。
(2)按给定的题目给出中间代码序列的结构设计。
(3)完成相应的词法分析、语法分析和语义分析程序设计。
(4)编制好分析程序后,设计若干用例,上机测试并通过所设计的分析程序。
2文法的描述本程序所用的文法如下:G[S]:(1)S->do{E;}while(B) {if B.true goto B.true else goto B.false;}(2)B->I1 rop I2 {B.type=bool;B.val=I1.val rop I2.val;}(3)E->I1=I2 op I3 {I1.val=I2.val op I3.val;}(4)I->id {I.val=id.val;}注意:rop is < or >,op is +,-,*,/, id is any number or identifier由上可知,非终结符B表示布尔表达式,E表示赋值表达式3.语法分析方法描述及语法分析表设计3.1语法分析方法描述本实验采用LR分析方法对DO-WHILE语句进行语法分析。
LR分析法是一种能根据当前分析栈中的符号串(通常以状态表示)和向右顺序查看输入串的K个(K>=0)符号就能惟一的确定分析器的动作是移进还是归约和用哪个产生式归约,因而也就能惟一的确定句柄。
LR分析法的归约过程是规范推导的逆过程,所以LR分析过程是一种规范过程。
一个LR分析器由3个部分组成:总控程序,也可以称为驱动程序。
编译原理实验二LL(1)语法分析实验报告

专题3_LL(1)语法分析设计原理与实现李若森 13281132 计科1301一、理论传授语法分析的设计方法和实现原理;LL(1) 分析表的构造;LL(1)分析过程;LL(1)分析器的构造。
二、目标任务实验项目实现LL(1)分析中控制程序(表驱动程序);完成以下描述算术表达式的 LL(1)文法的LL(1)分析程序。
G[E]:E→TE’E’→ATE’|εT→FT’T’→MFT’|εF→(E)|iA→+|-M→*|/设计说明终结符号i为用户定义的简单变量,即标识符的定义。
加减乘除即运算符。
设计要求(1)输入串应是词法分析的输出二元式序列,即某算术表达式“专题 1”的输出结果,输出为输入串是否为该文法定义的算术表达式的判断结果;(2)LL(1)分析程序应能发现输入串出错;(3)设计两个测试用例(尽可能完备,正确和出错),并给出测试结果。
任务分析重点解决LL(1)表的构造和LL(1)分析器的实现。
三、实现过程实现LL(1)分析器a)将#号放在输入串S的尾部b)S中字符顺序入栈c)反复执行c),任何时候按栈顶Xm和输入ai依据分析表,执行下述三个动作之一。
构造LL(1)分析表构造LL(1)分析表需要得到文法G[E]的FIRST集和FOLLOW集。
构造FIRST(α)构造FOLLOW(A)构造LL(1)分析表算法根据上述算法可得G[E]的LL(1)分析表,如表3-1所示:表3-1 LL(1)分析表主要数据结构pair<int, string>:用pair<int, string>来存储单个二元组。
该对照表由专题1定义。
map<string, int>:存储离散化后的终结符和非终结符。
vector<string>[][]:存储LL(1)分析表函数定义init:void init();功能:初始化LL(1)分析表,关键字及识别码对照表,离散化(非)终结符传入参数:(无)传出参数:(无)返回值:(无)Parse:bool Parse( const vector<PIS> &vec, int &ncol );功能:进行该行的语法分析传入参数:vec:该行二元式序列传出参数:emsg:出错信息epos:出错标识符首字符所在位置返回值:是否成功解析。
编译原理实验报告——词法分析器和LL(1)文法

《编译原理》综合性实验报告实验学期2016 至2017 学年第 1 学期专业计算机科学与技术班级1403学生姓名黄世增学号1411640305任课教师曦实验成绩《编译原理》课程综合性实验报告开课实验室:C210 2016年12月6日四、实验步骤编写程序时,先定义几个全局变量,key[]事先存放7个关键字,words[]用来存放识别出来的单词二元组,text用来存放从文件读取的容,word用于存放识别出来的单词,length存放字符个数,k存放识别出来的单词个数。
首先,将文本容读取到text中,文本容最后一个字符是空白符,然后调用scan 法,逐个扫描每个字符,如果word的第一个字符是字母,则进行拼字符串,再判断是关键字还是标识符;如果word的第一个字符是数字,则在word清空之前判断是否有识别出非数字字符,若有,则出错,若没有,则识别出来的字符串是常数;若word第一个字符是运算符或界限符,则各自存到words[]中。
最后扫描结束后输出。
五、实验结果及分析六、实验小结和思考通过这次实验,我对词法分析器有了进一步的了解,而且对词法分析和语法分析在实践中的应用有了深入的掌握, 让我对高级语言的学习有了更深的认识,了解得更透彻。
七、源程序清单#include<stdio.h>#include<stdlib.h>#include<string>using namespace std;#define MAX 10000struct WordString{string Word;//单词int category;//类别};char *key[7] = {"int","for", "while", "do", "return", "break", "continue"};//关键字WordString words[MAX]; //创建一个单词符号串string text; //读入的文本存入text中string word; //分割出的单词用word表示int length; //字符个数int k; //总单词个数开课实验室:C210 2016年12月8日六、实验小结和思考本实验加深了我对LL(1)分析法的算法和思想的理解。
编译原理--LL(1)文法 算法代码

/* LL(1)文法<古城童话>$为空字; 输入0,表示结束测试案例:案例1.(编译原理P76的LL(1)文法,E'改成了A,T'改成了B);E->TA A->+TA|$ T->FB B->*FB|$ F->(E)|i 0案例2. (First和Follow有非空交集)S->Ab A->a|B|$ B->b|$ 0*/#include <iostream>#include <string>using namespace std;const int MAX=100;int FirstNum=0,FollowNum=0; // First集合Follow集的数目string SaveStr[MAX]; //预存输入的字符串string TerStr="#"; //保存终结字符串int FlagError1=0; //左递归错误标志struct Assemble{int FlagLast,FlagFirst; //首尾标志int Position ; //字符串的位置char Data;Assemble *Next;};Assemble *First[MAX]; //定义Fist集Assemble *Follow[MAX]; //定义Follow集int IsNonterminal(char Cur) //判断是否为非终结符{if(Cur<='Z'&&Cur>='A')return 1;return 0;}int IsTerminal(char Cur) //判断是否为终结符{if(IsNonterminal(Cur)||Cur=='|')return 0;return 1 ;}int Exist(Assemble* L,char Cur,int Flag) //L的集合里面是否有Cur字符{ //Flag为1表示First,为0表示Followif(!L) return 0;Assemble *P;for(P=L->Next;P;P=P->Next)if(P->Data==Cur)return Flag ? P->Position:1 ;return 0;}int IsEmptyStr(char Cur) //字符串里面是否有${for(int i=0;i<FirstNum;i++)if(SaveStr[i][0]==Cur){ if(SaveStr[i].find('$')==-1)return 0;return 1;}}void HideSame(Assemble* &L) //消除相同的字符{Assemble *P,*Pa;for(P=L->Next;P->Next;P=P->Next)for(Pa=P->Next;Pa;Pa=Pa->Next)if(P->Data==Pa->Data) Pa->Data=3;}Assemble* FindAddFirst(char Cur) //查找要添加的First集{for(int i=FirstNum-1;i>=0;i--)if(First[i]->Data==Cur) return First[i];return NULL;}Assemble* FindAddFollow(char Cur) //查找要添加的Follow集{for(int i=0;i<FollowNum;i++)if(Follow[i]->Data==Cur) return Follow[i];return NULL;}void CreatFirst(Assemble* &L,string Str) //创建Firs集{Assemble *P=L,*Pa;int FlagLeft=0,Pos=3,j,i;L->FlagLast=0;for(i=3;Str[i];i++){int FlagGo=1,FlagLa=1;char Ch=L->Data;if(Ch==Str[3]||Str[i-1]=='|'&&Str[i]==Ch) FlagError1=1; //含有左递归while(i<Str.length()&&Str[i]!='|'){if(IsNonterminal(Str[i]))FlagGo=(IsEmptyStr(Str[i])? 1:0);Pa=new Assemble;Pa->Data=Str[i];Pa->Position=Pos;P->Next=Pa;P=Pa;if(!FlagGo||IsTerminal(Str[i])){ FlagLa=0; break; }i++;}if(!FlagLa)while(Str[i]&&Str[i]!='|')i++;else { L->FlagLast=1; }Pos=i+1;}P->Next=NULL;}void CreatFollow(string Str) //创建Follow集{int i,j,Num;for(i=3;Str[i];i++){Num=-1;if(IsNonterminal(Str[i])){ for(j=0;j<FollowNum;j++)if(Follow[j]->Data==Str[i]){ Num=j; break; }if(Num<0){Follow[FollowNum]= new Assemble;Follow[FollowNum]->Data=Str[i];Follow[FollowNum]->Next=NULL;Num=FollowNum++;}int FlagGo=0,FlagLa=0;Assemble *Pa,*Pb,*P=Follow[Num];for(j=i+1;Str[j]&&Str[j]!='|';j++){Pa=new Assemble;Pa->FlagLast=0;for(;P->Next;P=P->Next);FlagGo=Exist(FindAddFirst(Str[j]),'$',1)? 1:0;Pa->Data=Str[j];P->Next=Pa;Pa->Next=NULL;if(!FlagGo){ FlagLa=1; break; } //是否继续添加}if(!FlagLa) //非终结符位于末尾{for(;P->Next;P=P->Next);Pb=new Assemble;Pb->FlagLast=1;Pb->Data=Str[0];Pb->Next=P->Next;P->Next=Pb;}}}}void InitFollow(int Num) //初始化Follow集{for(int i=0;i<Num;i++){if(!i){Follow[FollowNum]=new Assemble;Follow[FollowNum]->Data=SaveStr[0][0];Follow[FollowNum]->Next=new Assemble;Follow[FollowNum]->Next->Data='#';Follow[FollowNum++]->Next->Next=NULL;}CreatFollow(SaveStr[i]);}}//增添Follow集,Num=1,增添First集,Num=0,增添Follow集void AddFollow(Assemble* &L, Assemble* Head,int Num){Assemble *Pa,*Pb,*Pc;for(Pc=Head->Next;Pc;Pc=Pc->Next){ for(Pa=L->Next;Pa;Pa=Pa->Next)if(Pa->Data==Pc->Data)break;if(!Pa){if(Pc->Data=='$'&&Num) continue;Pb=new Assemble;Pb->Data=Pc->Data;Pb->Next=L->Next;L->Next=Pb;}}}void GetFollow(Assemble* &L) //得到Follow集{Assemble *P,*Head;for(P=L->Next;P;P=P->Next)if(IsNonterminal(P->Data)){if(P->FlagLast) //位于末尾,增添Follow集{Head=FindAddFollow(P->Data);AddFollow(L,Head,0);}else //不位于末尾,增添First集{Head=FindAddFirst(P->Data);AddFollow(L,Head,1);}}}int GetFirst(Assemble* &L) //得到First集{Assemble *P,*Pa,*Pb,*Pc,*Head;for(P=L->Next;P;P=P->Next)if(IsNonterminal(P->Data)){Head=FindAddFirst(P->Data);if(!Head)return 0;for(Pc=Head->Next;Pc;Pc=Pc->Next)if(Pc->Data=='$'&&!L->FlagLast)continue;Pb=new Assemble;Pb->Data=Pc->Data;Pb->Position=P->Position;Pb->Next=L->Next;L->Next=Pb;}}}void KeepTerStr(string Str) //保存终结符{for(int i=3;Str[i];i++)if(IsTerminal(Str[i])&&Str[i]!='$'){if(TerStr.find(Str[i])==-1)TerStr+=Str[i];}}void ShowLL1(Assemble *L,int num)//输出LL(1)文法{Assemble *P=L,*Head;int i,npos;string Str=SaveStr[num];cout<<First[num]->Data<<"\t";for(i=0;TerStr[i];i++){if(npos=Exist(L,TerStr[i],1)){cout<<First[num]->Data<<"->";if(npos==1)npos=3;while(Str[npos]!='|'&&npos<Str.length()){cout<<Str[npos];npos++;}}else if(Exist(L,'$',0)){Head=FindAddFollow(First[num]->Data);if(Exist(Head,TerStr[i],0))cout<<First[num]->Data<<"->"<<"$";cout<<"____";}else cout<<"____";cout<<"\t ";}cout<<"\n\n";}int IsError2()//测试是否有左因子{string AddStr,Str;for(int i=0;i<FirstNum;i++){AddStr="";Str=SaveStr[i];for(int j=0;Str[j];j++)if(j==3||Str[j-1]=='|'){if(AddStr.find(Str[j])!=-1) return 1;AddStr+=Str[j];}}return 0;}Assemble* IsError3(char &Ch) //测试First和Follow是否有非交集{Assemble *P,*Pa,*Head;for(int i=0;i<FirstNum;i++){for(P=First[i]->Next;P;P=P->Next){Head=FindAddFollow(First[i]->Data);if(P->Data!='$'&&IsTerminal(P->Data)&&P->Data!=3)for(Pa=Head->Next;Pa;Pa=Pa->Next)if(Pa->Data==P->Data){ Ch=First[i]->Data; return P; }}}return NULL;}int ShowForm() //显示LL(1)文法的终结符{Assemble *P;char Cur;if(FlagError1){ cout<<"\n文法中含有左递归...!\n"; return 1; }if(IsError2()){ cout<<"\n文法中含有左因子...!\n"; return 1; }if(P=IsError3(Cur)){ printf("\n文法中First(%c)和Follow(%c)有非空交集%c...!\n",Cur,Cur,P->Data);return 1;}cout<<"\nLL(1)分析表:\n\n";for(int i=0;TerStr[i];i++)cout<<"\t "<<TerStr[i];cout<<endl;for(int i=0;i<FirstNum;i++)ShowLL1(First[i],i);}void GetFistrFollow(int Num){int i,j;FirstNum=Num;for(i=0;i<Num;i++){First[i]=new Assemble;First[i]->Data=SaveStr[i][0];CreatFirst(First[i],SaveStr[i]); //创建First集}for(j=0,i=FirstNum-1;i>=0;i--,j++) //得到First集{GetFirst(First[i]);GetFirst(First[j]);}InitFollow(Num); //初始化Follow集for(i=0;i<FollowNum;i++)GetFollow(Follow[i]); //得到Follow集}int main(){int i,j,Num=0;cout<<"请输入文法产生式(以输入0结束):\n";while(cin>>SaveStr[Num]&&SaveStr[Num][0]!='0') {KeepTerStr(SaveStr[Num]);Num++;}GetFistrFollow(Num); //获得First集合Follw集ShowForm(); //输出LL(1)文法表system("pause");}。
编译原理实验报告3-LL(1)文法构造

实验3 LL(1)文法构造一、实验目的熟悉LL(1)文法的分析条件,了解LL(1)文法的构造方法。
二、实验内容1、编制一个能够将一个非LL(1)文法转换为LL(1)文法;2、消除左递归;3、消除回溯。
三、实验要求1、将一个可转换非LL(1)文法转换为LL(1)文法,要经过两个阶段,1)消除文法左递归,2)提取左因子,消除回溯。
2、提取文法左因子算法:1)对文法G的所有非终结符进行排序2)按上述顺序对每一个非终结符Pi依次执行:for( j=1; j< i-1;j++)将Pj代入Pi的产生式(若可代入的话);消除关于Pi的直接左递归:Pi -> Piα|β ,其中β不以Pi开头,则修改产生式为:Pi —> βPi′Pi′—>αPi′|ε3)化简上述所得文法。
3、提取左因子的算法:A—>δβ1|δβ2|…|δβn|γ1|γ2|…|γm(其中,每个γ不以δ开头) 那么,可以把这些产生式改写成A —>δA′|γ1| γ2…|γmA′—>β1|β2|…|βn4、利用上述算法,实现构造一个LL(1)文法:1)从文本文件g.txt中读入文法,利用实验1的结果,存入实验1设计的数据结构;2)设计函数remove_left_recursion()和remove_left_gene()实现消除左递归和提取左因子算法,分别对文法进行操作,消除文法中的左递归和提出左因子;3)整理得到的新文法;4)在一个新的文本文件newg.txt输出文法,文法输出按照一个非终结符号一行,开始符号引出的产生式写在第一行,同一个非终结符号的候选式用“|”分隔的方式输出。
四、实验环境PC微机DOS操作系统或Windows操作系统Turbo C程序集成环境或VisualC++ 程序集成环境五、实验步骤1、学习LL(1)文法的分析条件;2、学习构造LL(1)文法的算法;3、结合实验1给出的数据结构,编程实现构造LL(1)文法的算法;4、结合实验1编程和调试实现对一个具体文法运用上述算法,构造它的LL(1)文法形式;5、把实验结果写入一个新建立的文本文件。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
学号:课程设计题目编译原理学院计算机科学与技术专业计算机科学与技术班级姓名指导教师2 年月日课程设计任务书学生姓名:专业班级:指导教师:工作单位:题目: DO-WHILE循环语句的翻译程序设计(LL(1)法、输出三地址表示)初始条件:理论:学完编译课程,掌握一种计算机高级语言的使用。
实践:计算机实验室提供计算机及软件环境。
如果自己有计算机可以在其上进行设计。
要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)(1)写出符合给定的语法分析方法的文法及属性文法。
(2)完成题目要求的中间代码三地址表示的描述。
(3)写出给定的语法分析方法的思想,完成语法分析和语义分析程序设计。
(4)编制好分析程序后,设计若干用例,上机测试并通过所设计的分析程序。
(5)设计报告格式按附件要求书写。
课程设计报告书正文的内容应包括:1 系统描述(问题域描述);2 文法及属性文法的描述;3 语法分析方法描述及语法分析表设计;4 按给定的题目给出中间代码形式的描述及中间代码序列的结构设计;5 编译系统的概要设计;6 详细的算法描述(流程图或伪代码);7 软件的测试方法和测试结果;8 研制报告(研制过程,本设计的评价、特点、不足、收获与体会等);9 参考文献(按公开发表的规范书写)。
时间安排:设计安排一周:周1、周2:完成系统分析及设计。
周3、周4:完成程序调试及测试。
周5:撰写课程设计报告。
设计验收安排:设计周的星期五第1节课开始到实验室进行上机验收。
设计报告书收取时间:设计周的次周星期一上午10点。
指导教师签名: 2011年 12月 23日系主任(或责任教师)签名: 2011年 12月 23日DO-WHILE语句的翻译程序设计(LL(1)文法输出3地址表达式)1课设的描述1.1课设要求首先按照课程设计的要求,写一个能识别do-while循环语句的文法,并使它符合LL(1)法的要求,按照这个文法编写一个程序,该程序能识别输入的语句是否符合do-while语句的文法,或者通过文法的开始符号能判断是否能推导出该语句。
程序应该包括词法分析器,能对输入的语句进行词法分析,对输入的源程序从左到右进行扫描并将其分解为一个个的单词符号。
然后再对结果进行语法分析。
词法分析器应能识别关键字,标识符,常量,操作符等。
该程序的语法分析器能对输入的语法进行分析,判断输入语句能否满足do-while循环语句的文法,如果不是则提示错误,如果满足do-while循环语句文法,判断是否符合LL(1)法,运用最左推导对其进行分析,看能否通过开始符号推导出来。
将语法和语义分析的结果用输出三地址形式表示出来。
1.2课设中所用概念1)词法分析:输入源程序,对构成源程序的字符串进行扫描和分解,识别出一个个的单词符号:关键字(do,while)、标识符、常量、操作符等。
2)语法分析:在词法分析的基础上,根据语法规则,把单词符号串分解成各类语法单位。
3)语义分析与中间代码产生:对语法分析所识别出的各类语法范畴,分析其含义,并进行初步翻译(产生中间代码)。
4)LL(1)文法:LL(1)文法是一种自上而下的语法分析方法。
第一个L是自上而下的分析,第二个L是从最左单词开始分析,1代表只通过下1个单词分析需要用到的语法。
5)预测分析程序:实现LL(1)法分析的一种有效方法,使用一张预测分析表和一个栈进行联合控制。
预测分析程序就是属于这种类型的LL(1)分析器。
2文法的描述2.1 do.. While 语句文法描述K->dLwS L->SPP->;SP P->εS->iQE E->TGG->+TG G->-TGG->εT->FRR->*FR R->/FRR->εF->(E)F->I Q->=Q->< Q->>非终结符集V N{K,L,P,S,G,R,E,F,Q,T}终结符集V*{ do,while,(,), ε,+,-,*,/,i,>,=,<,;}预测分析表i = < > + - * / ( ) do ε; while K dLwSL SPP ε;SPS iQEE -TG TGG +TG -TG εεεT FR FRR εε*FR /FR εεεF i (E)Q = < >3语法分析方法及中间代码形式的描述3.1语法分析方法描述LL(1)文法的定义:First 集:设G={VT ,VN,S,P}是上下文无关文法First(α)={a|α=>aβ,a∈VT,α,β∈V*}若a=>ε,则规定ε∈First(α),称为First(α)为α的开始符号集或首符号集。
FOLLOW 集:设G={VT ,VN,S,P}是上下文无关文法FOLLOW(A)={a|S=>μAβ且a∈VT ,a∈First(β),μ∈V*T,β∈V+ }若S=>μAβ,且β=>ε,则#∈FOLLOW(A)SELECT 集:给定上下文无关文法的产生式 A-->α A∈VN,α∈V* ,若α≠>ε,则SELECT(A-->α)=First(α)如果α=>ε,则SELECT(A-->α)=(First(α)-{ε})U FOLLOW(A).LL(1)文法:一个上下文无关文法是LL(1)文法的充分必要条件是,对每个非终结符A的两个不同的产生式,A-->α A-->β,满足SELECT(A-->α)∩SELECT(A-->β)= ф其中α,β不能同时推导出空.3.2 中间代码形式三地址码是由下面一般形式的语句构成的序列:x := y op z其中,x y z为名字、常数或临时变量;op代表运算符号。
每个语句中只能有一个运算符。
三地址码类似于汇编语言代码。
语句可以带有符号标号,而且存在各种控制流语句,本程序输出中用到了:复制语句x := y条件转移语句if x relop y goto L //L为带标号L的三地址语句无条件转移语句goto L //转移到标号为L的三地址语句。
4简要的分析与概要设计 4.1 基本框架输入do while 语句 → 词法分析 → 语法语义分析 → 输出三地址代码4.2 构成图4.2.1 主函数构成4.3 各个部分构成整个工程分为四个部分,词法分析部分,和语法分析部分,具体函数执行部分,以及语义分析部分(最终部分在main 函数中执行的)lexical() ----- 程序的入口点,读入输入的待分析的字符串后,把其装入一给定数组,先进行词法分析,然后输出生成的词法分析结果。
syntax() ----- 语法分析阶段,利用Wordanalyze() 中分析出的词法,进行语法 分析.如果不是LL(1)文法则输出语法出错,仅对LL(1)文法的输入进行分析.具体函数执行部分 ----- 定义了各种操作函数以方便调用,入读入输入的句字的函数,提 取字符函数,判断字符函数等等语义分析式部分-------主函数中进行的输出,形式为给定句子的三地址表达式词法分析语法语义分析Main( )控制输出三地址码5算法描述5.1词法分析的主要算法void lexical() //词法分析{int i,j,d;char ch;j=d=0;for(i=0;var[i]!='#';i++) //判断关键字{ch=var[i];if(ch=='d'&&var[i+1]=='o'){cout<<"do"<<'\t'<<"关键字"<<endl;queue[j++]='d';i+=1;}else if(ch=='w'){ch=var[i+1];if(ch=='h'){ch=var[i+2];if(ch=='i'){ch=var[i+3];if(ch=='l'){ch=var[i+4];if(ch=='e'){ch=var[i+5];}}}}cout<<"while"<<'\t'<<"关键字"<<endl;queue[j++]='w';i+=4;}else if(index(ch,VT)<=0) //判断标示符分隔符运算符{if(ch!='{'&&ch!='}'&&ch!='('&&ch!=')'){cout<<ch<<'\t'<<"标识符"<<endl;arr_i[d-1]=ch;queue[j++]='i';}else cout<<ch<<'\t'<<"分隔符"<<endl;}else if(index(ch,VT)>0){cout<<ch<<'\t'<<"运算符"<<endl;queue[j++]=ch;}}queue[j]='#';for(i=0;queue[i]!='#';i++)cout<<queue[i];cout<<endl;}语法分析主要算法void syntax() //语法分析{int n;count++;print();X=stack[sp];a=queue[front];if(X=='#'&&a=='#')f=4;if(X<'A'||X>'Z'){if(X==a){sp--;front++;if(a!='i'){if(a!='d'&&a!='w'&&a!=';'&&a!='#'){opr=index(a,VT);}else if(a==';'||a=='w'||a=='#'){opr=-2;}cout<<'\t'<<'\''<<a<<"'匹配"<<endl;}else{opd=c;cout<<'\t'<<'\''<<arr_i[c++]<<"'匹配"<<endl;}}else f=1; //字符不匹配,转去出错处理}else{int tx=index(X,VN);int ta=index(a,VT);n=M[tx][ta];td[t++]=M[tx][ta];if(ta==-1){f=2;cout<<a<<endl;} //字符没有出现在产生式终结符集VT中,转去出错处理else if(n==-1)f=3; //没有找到合适的候选产生式来做进一步推导,转去出错处理else{ //用产生式M[tx][ta]来做进一步推导sp--;cout<<'\t'<<X<<"->";if(len(p[n])!=0){for(int i=len(p[n])-1;i>=0;i--){stack[++sp]=p[n][i];cout<<p[n][len(p[n])-1-i];}cout<<endl;}else cout<<"空串"<<endl;}}if(f==0)syntax();else{td[t]='-1';err(f);}}具体执行函数:len 求字符串长度index 查找字符串中是否有ch 返回ch位置err 输出错误和错误原因print 打印6上机测试6.1测试方法在visual c++ 6.0 下调试并通过.输入不同的语句进行测试,测试的主要目的是看程序能否正确判断条件语句是否正确,赋值语句的格式有没有错误以及最后结果输出的三地址是否正确。