编译原理 实验三 LL(1)语法分析器的构造

合集下载

编译原理实验报告《ll(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("|");//

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

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

编译原理语法分析器实验报告班级:学号:姓名:实验名称语法分析器一、实验目的1、根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。

2、本次实验的目的主要是加深对自上而下分析法的理解。

二、实验内容[问题描述]递归下降分析法:0.定义部分:定义常量、变量、数据结构。

1.初始化:从文件将输入符号串输入到字符缓冲区中。

2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。

LL(1)分析法:模块结构:1、定义部分:定义常量、变量、数据结构。

2、初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体等);3、运行程序:让程序分析一个text文件,判断输入的字符串是否符合文法定义的规则;4、利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示简单的错误提示。

[基本要求]1. 对数据输入读取2. 格式化输出分析结果2.简单的程序实现词法分析public static void main(String args[]) {LL l = new LL();l.setP();String input = "";boolean flag = true;while (flag) {try {InputStreamReader isr = newInputStreamReader(System.in);BufferedReader br = new BufferedReader(isr);System.out.println();System.out.print("请输入字符串(输入exit退出):");input = br.readLine();} catch (Exception e) {e.printStackTrace();}if(input.equals("exit")){flag = false;}else{l.setInputString(input);l.setCount(1, 1, 0, 0);l.setFenxi();System.out.println();System.out.println("分析过程");System.out.println("----------------------------------------------------------------------");System.out.println(" 步骤| 分析栈| 剩余输入串| 所用产生式");System.out.println("----------------------------------------------------------------------");boolean b = l.judge();System.out.println("----------------------------------------------------------------------");if(b){System.out.println("您输入的字符串"+input+"是该文法的一个句子");}else{System.out.println("您输入的字符串"+input+"有词法错误!");}}}}//实现各函数并且加注释三、编程并上机调试运行运行结果如下图:四、实验小结通过这次实验,我对语法分析有了更深刻的了解,对它的形成有了更清楚得认识。

编译原理-实验3-LL(1)分析文法构造

编译原理-实验3-LL(1)分析文法构造

集美大学计算机工程学院实验报告课程名称:编译原理指导教师:付永钢实验成绩:实验编号:实验三实验名称:LL(1)语法分析器的构造班级:计算14姓名:学号上机实践日期:2017.6上机实践时间:6学时一、实验目的1、掌握LL(1)分析法的基本原理;2、掌握LL(1)分析表的构造方法;3、掌握LL(1)驱动程序的构造方法。

二、实验环境Ubuntu三、实验原理1、对文法要求LL(1)分析法属于自顶向下分析方法,因此需要预测匹配的产生式。

即在LL(1)分析法中,每当在符号栈的栈顶出现非终结符时,要预测用哪个产生式的右部去替换该非终结符。

LL(1)分析方法要求文法满足如下条件:对于任一非终结符A,其任意两个产生式A→α,A→β,都要满足下面条件:First(A→α)∩First(A→β)=∅2、分析表构造LL(1)分析表的作用是对当前非终结符和输入符号确定应该选择用哪个产生式进行推导。

它的行对应文法的非终结符,列对应终结符,表中的值有两种:一是产生式的编号,一是错误编号。

若用T表示LL(1)分析表,则T可表示如下:T: V N×V T→P∪{Error}T(A, t) = A→α,当t∈First(A→α)T(A, t) = Error,否则其中P表示所有产生式的集合。

显然,一个文法G是LL(1)文法,当且仅当T的元素包含唯一的一个产生式或Error。

3、驱动程序构造LL(1)分析主要包括以下四个动作,其中X为符号栈栈顶元素,a为输入流当前字符。

●替换:当X∈V N时选相应产生式的右部β去替换X。

●匹配:当X∈V T时它与a进行匹配,其结果可能成功,也可能失败,如果成功则符号栈中将X退栈并将输入流指针向前移动一位,否则报错。

●成功:当格局为(空,空)时报告分析成功。

●报错:出错后,停止分析。

四、实验内容已知文法G[E]:E→E+T|TT→T*F|FF→(E)|i说明:终结符号i为用户定义的简单变量, 即标识符的定义。

LL1语法分析器_B12040921

LL1语法分析器_B12040921
.
实验报告
(2014/2015 学年第二学期)
课程名称 实验名称 实验时间 指导单位 指导教师
编译原理
语法分析器的构造
2015
年 5 月 29 日
计算机学院软件工程系
蒋凌云
学生姓名 学院(系)
Cjj
班级学号
计算机学院 专业
B--------NIIT
成绩
批阅人
日期
.
.
实验报告
实验名称
语法分析器的构造
self.firstSet,
def Judge(self, string): """判断字符串是否为当前文法的句子 """ isMatch = False
1
.
analyseStack = ["#", self.start] StringStack = list(string) + ["#"] print u"="*25,u"判断字符串=%s"%string,u"="*25 print "%-30s%-12s%s"%(u"分析栈",u"余留输入串",u"所用生成式") try:
classAnalyseMachine(object):
def __init__(self): pass
def load(self, Grammers): """载入文法规则 参数 Grammers: 文法的规则列表 """
self.Grammers = Grammers self.noLeftRecursionGrammers = self.__NoLeftRecursion(self.Grammers) self.start = self.Grammers[0][0] self.nChars = self.__GetVn(self.noLeftRecursionGrammers) self.tChars = self.__GetVt(self.noLeftRecursionGrammers) self.firstSet = self.FirstSet(self.noLeftRecursionGrammers) self.followSet = self.FollowSet(self.noLeftRecursionGrammers) self.analyseTable = self.AnalyseTable(self.noLeftRecursionGrammers, self.followSet)

编译原理实验报告3-LL(1)文法构造

编译原理实验报告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、把实验结果写入一个新建立的文本文件。

编译原理课程设计LL文法分析器

编译原理课程设计LL文法分析器

目录引言 (1)第一章概述 (4)1.1设计内容 (4)1.2设计要求 (4)第二章设计的基本原理 (4)2.1预测分析表的构成原理 (4)2.2预测分析程序的生成 (5)第三章程序设计 (5)3.1总体方案设计 (6)3.2各模块设计 (6)第四章程序测试 (7)附录程序清单 (8)课 程 设 计L L (1)文法分析器2010 年 12 月设计题目学 号 专业班级 学生姓名指导教师合肥工业大学课程设计任务书第一章概述1.1 设计内容:1:预测分析表自动构造程序的实现2:预测分析程序的实现1.2 设计要求1:设计内容及要求:对于任意输入的一个LL(1)文法,构造其预测分析表。

要求:首先实现集合FIRST(X)构造算法和集合FOLLOW(A)构造算法,再实现教材P.79给出的预测分析表构造算法。

程序显示输出预测分析表或输出到指定文件中。

2:设计内容及要求:对文法 G: E→E+T|T 按教材P.76表4.1构造出G的预测分析程序,T→T*F|F 程序显示输出如P.78那样的匹配过程。

F→(E)|i第二章设计的基本原理2.1预测分析表的构成原理对于任意给定的LL(1) 文法G,为了构造它的预测分析表M,我们就必须构造与文法G有关的集合First和fellow.首先我们对每一个X∈V T U Vn ,构造FIRST(X),办法是,连续使用下面的规则,直至每个集合FIRST不再增大为止.(1)若X∈V T,,则FIRST(X)={X}.(2)若X∈Vn ,且有产生式X->a……,则把a加入到FIRST(X)中,若X->ε,也是一条产生式,则把ε也加到FIRST(X)中.(3)若X->Y……是一个产生式且Y∈Vn,则把FIRST(Y)中所有非ε-元素都加到FIRST(X)中,若X->Y1Y2……Y K ,是一个连续的产生式, Y1Y2……Y i-1 都是非终结符,而且,对于任何j,1≤j≤i-1,FIRST(Y j) 都含有ε(即Y1Y2……Y i-1=>ε),则把FIRST(Y i) 中的所有非ε-元素都加到FIRST(X)中,特别是,若所有的FIRST(Y j)均含有ε,j=1,2,……,k,则把ε加到FIRST(X)中.对于文法G中每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直到每个FOLLOW不在增大为止.(1)对于文法的开始符号S,置#于FOLLOW(S)中;(2)若A->aBb是一个产生式,则把FIRST(b)\{ ε}加至FOLLOW(B)中;(3)若A->aB是一个产生式,或A->aBb是一个产生式而b=>ε(即ε∈FIRST( b))则把FOLLOW(A)加至FOLLOW(B)中构造分析表M的算法是:(1)对文法G的每个产生式A->a执行第二步和第三步;(2)对每个终结符a∈FIRST(a), 把A->a加至M[A,a]中;(3)若ε∈FIRST(a),则把任何b∈FOLLOW(A)把A->a加至M[A,b]中;(4)把所有无定义的M[A,a]标上出错标志.2.2 预测分析程序的生成预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号行事的,对于任何(X,a),总控程序每次都执行下述三种可能的动作之一;(1)若X=a=”#”,则宣布分析成功,停止分析过程.(2)若X=a≠”#”,则把X从STACK栈顶逐出,让a指向下一个输入符号.(3)若X是一个非终结符,则查看分析表M,若M[A,a]中存放着关于X的一个产生式,那么,首先把X逐出STACK栈顶,然后,把产生式的右部符号串按反序一一推进STACK栈(若右部符号为ε,则意味着不推什么东西进栈).在把产生式的右部符号推进栈的同时应做这个产生式相应得语义动作,若M[A,a]中存放着”出错标志”,则调用出错诊察程序ERROR.第三章程序设计3.1 总体方案设计在看到这个题目后,首先想到的就是要分模块进行设计.(1)第一模块:把文本文件中的LL(1)文法读入到程序中grammer类中的数组成员g中.(2)第二模块:通过对已输入到数组g中的文法,进行扫描,把相应的非终结符和终结符输入到非终结符数组VN中和终结符数组VT中.(3)第三模块:生成所有的非终结符的FIRST集合(4)第四模块:生成所有的非终结符的FOLLOW集合(5)第五模块:生成文法的预测分析表(6)第六模块:生成文法的预测分析程序通过这六模块的设计,最后可连接成一个预测分析程序.3.2 各模块程序设计首先要建立两个类,分别是grammer类和SeqStack类Grammer类中有保存从文本文件读入的LL(1)文法,用一个二维字符数组g保存, 保存非终结符的字符数组VN,保存终结符的字符数组VT,文法开始符号字符变量begin ,元素对应first集合中的有空字符的非终结符数组emptychar,预测分析表为二维整形数组form.SeqStack类主要的作用为在预测分析时作为符号栈.(1)第一模块的设计:对于这个模块的设计,就是用输入流对文本文件中的文法进行读入当读到字符’|’或’/n’时意味着一个产生式已结束,那么相应数组中相应的下标变量+1;数组g[i][0]所存放着这个产生式对应的字符的数量.g[i][1]为这个产生式左边的非终结符.(2)第二模块的设计:在已把文法读入到数组g中后,那么相应的g[i][0]为每个产生式的非终结符,若此非终结符不在数组VN中,那么把此字符加入到VN中对终结符的读入,则是从每个g[i][2]开始扫描,若此字符不在非终结符数组VN中,也不在VT 中,那么就把此字符加入到VT中.(3)第三模块的设计:生成FIRST集合这个算法基本上按照书上的原理,如对每个产生式进行扫描,当扫描到非终结符时,把此字符加入到相应非终结符的FIRST集合中,若遇到非终结符时,需把此非终结符的FIRST集合中除了空字符外全加入到对应的非终结符的first集合中,这就涉及到算法的一个递归算法,我是利用在函数的参数表中设置俩个参数,一个是FIRST数组,另外一个是非终结符,在用到递归时,我是利用把FIRST数组设为本产生式第一个非终结符的FIRST数组,而非终结符参数则设置为在扫描产生式右部过程中所遇到的非终结符.然后通过循环对这个文法中的所有非终结符进行函数的调用,这样来求到所有非终结符的FIRST集合.(4)第四模块的设计:生成FOLLOW集合这个算法,关键就是求某非终结符A的FOLLOW集合,那么就是扫描到A后面的字符,若为终结符,则把此终结符加入到A的FOLLOW集合,那么若为非终结符,则把此非终结符的FIRST集合加入到A的FOLLOW集合中,若A为某个产生式最后一个字符,则把这个产生式的第一个字符的FOLLOW集合加入到A的FOLLOW集合中,在这个算法的过程中叶涉及到运用递归,此递归的方法同样与上述求FIRST集合中运用的递归方法类似(5)第五模块的设计:求预测分析表的过程同样是对每个产生式进行扫描,对每个产生式的FIRST集合中的元素,都把相应的产生式的编号写入到对应的预测分析表中对应的位置(6)第六模块的设计:生成预测分析程序,就是把’#’和文法开始符号进入到栈中,然后把相应的分析语句中当前的输入符号对应,在每一步过程中按照书上讲到的原理,在预测分析表中找到相应的产生式.第四章程序测试附录程序清单class SeqStack;//声明栈类class grammer//定义grammer类,此类的作用把文本文件中的文法保存,并且产生这个文法的非终结符集合,终结符集合,first集合,fellow集合,预测分析表等{public:grammer();~grammer();void openfile(char *);void prepareform();void buildform();void buildProcess(SeqStack& ss);private:char begin;char *vt;char **g;char *vn;char **first;//这时所有非终结符的first集合char **fellow;//这是所有非终结符的fellow集合char *emptychar;//这个集合中的元素为对应first集合中的有空字符的非终结符int **form;//这是对应文法的预测分析表int count;void buildVn();void buildVt();void buildemptychar();void buildfirst();void buildfellow();void fellowzh(char *,char);void firstzh(char *,char);int search(char *,char);void printform();void outputblank(int);};const int stackIncreament=20;class SeqStack//定义SeqStack类,这个类的主要作用是在对语句的预测分析过程中作符号栈{public:friend grammer;SeqStack(int sz=50);~SeqStack();void Push(char x);bool Pop(char& x);bool getTop(char& x);bool IsEmpty();bool IsFull();int getSize();void MakeEmpty();void showPlay();private:char *elements;int top;int maxSize;void overflowProcess();};#include<fstream>#include<iostream>#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<windows.h>#include "编译.h"using namespace std;grammer::grammer(){count=0;}grammer::~grammer(){int i;for(i=0;i<count;i++)delete g[i];delete g;delete vt;delete vn;}void grammer::openfile(char *file)//这个函数的主要功能在于对文本文件中的文法进行读入,并保存在对应的数组中,一并产生对应文法的终结符集合和非终结符集合{char ch;int i,j;ifstream infile(file,ios::in);//定义文件流if(!infile){cout<<"open error!"<<endl;exit(1);}while((ch=infile.get())!=EOF){if(ch=='-'){if((ch=infile.get())=='>'){count++;}else{infile.seekg(-1,ios::cur);}}else if(ch=='|'){count++;}else{}}g=new char *[count];for(i=0;i<count;i++){g[i]=new char [15];g[i][0]=0;}infile.clear();//能重新激活文件流infile.seekg(0,ios::beg);//定位i=0;j=1;while((ch=infile.get())!=EOF){if(ch=='-'){if(infile.get()!='>'){g[i][j]=ch;g[i][0]++;j++;if(ch==EOF)break;elseinfile.seekg(-1,ios::cur);}}else if(ch=='|'){i++;g[i][1]=g[i-1][1];g[i][0]=1;j=2;}else if(ch=='\n'){infile.seekg(-3,ios::cur);ch=infile.get();if(ch!='\n'){i++;j=1;}infile.seekg(2,ios::cur);}else{g[i][j]=ch;g[i][0]++;j++;}}cout<<count<<endl;for(i=0;i<count;i++){for(j=1;j<=g[i][0];j++){cout<<g[i][j]<<" ";}cout<<endl;}buildVn();//建立非终结符集合buildVt();//建立终结符集合}void grammer::buildVn()int i=1,j=0;vn=new char[count+1];vn[i]=g[j++][1];for(;j<count;j++)if(g[j][1]!=g[j-1][1]){i++;vn[i]=g[j][1];}vn[0]=i;begin=vn[1];cout<<"本文法开始符为:"<<begin<<endl;cout<<"本文法非终结符为:"<<" ";for(i=1;i<=vn[0];i++)cout<<vn[i]<<" ";cout<<endl;}void grammer::buildVt(){int i=1,j=0,t;char ch;vt=new char[100];vt[0]=0;for(;j<count;j++){t=2;for(;t<=g[j][0];t++){ch=g[j][t];if(!search(vt,ch)&&!search(vn,ch)){vt[i++]=g[j][t];vt[0]++;}}}cout<<"本文法终结符为:"<<" ";for(i=1;i<=vt[0];i++)cout<<vt[i]<<" ";cout<<endl;}int grammer::search(char *a,char ch)//搜索函数,用于在指定数组中对指定字符进行搜寻,若存在输出对应的序号,若不在则输出0for(int i=1;i<=a[0];i++){if(ch==a[i])return i;}return 0;}void grammer::buildemptychar()//建立对应first集合中含有空字符的的非终结符集合{int i=0,j=2,t=1;bool flag=true,flag1;emptychar=new char[vn[0]+1];emptychar[0]=0;for(;i<count;i++){if(g[i][2]=='@'&&!search(emptychar,g[i][1])){emptychar[t++]=g[i][1];emptychar[0]++;}}while(flag){flag=false;for(i=0;i<count;i++){for(j=2;j<=g[i][0];j++){if(search(emptychar,g[i][j])){flag1=true;}else{flag1=false;break;}}if(flag1==true&&!search(emptychar,g[i][1])){emptychar[t++]=g[i][1];emptychar[0]++;flag=true;}}cout<<"First集中含有空字符的有: ";for(i=1;i<=emptychar[0];i++){cout<<emptychar[i]<<" ";}cout<<endl;}void grammer::buildfirst(){int i;first=new char* [vn[0]];for(i=0;i<vn[0];i++){first[i]=new char[vt[0]+1];}for(i=0;i<vn[0];i++)first[i][0]=0;for(i=1;i<=vn[0];i++){firstzh(first[i-1],vn[i]);}}void grammer::buildfellow(){int i,j;fellow=new char* [vn[0]];for(i=0;i<vn[0];i++){fellow[i]=new char[vt[0]+1];}for(i=0;i<vn[0];i++)fellow[i][0]=0;for(i=1;i<=vn[0];i++){fellowzh(fellow[i-1],vn[i]);}for(i=0;i<vn[0];i++){cout<<vn[i+1]<<"的fellow集合为: ";for(j=1;j<=fellow[i][0];j++){cout<<fellow[i][j]<<" ";cout<<endl;}}void grammer::firstzh(char *a,char ch)//对指定非终结符建立对应的first集合{int i,j,t=1;for(i=0;i<count;i++){for(j=2;j<=g[i][0];j++){if(g[i][1]==ch){if(!search(vn,g[i][j])&&g[i][j]!='@')//找到对应产生式中的终结符时{if(!search(a,g[i][j])){a[t++]=g[i][j];a[0]++;}break;}else if(g[i][j]!='@')//找到对应的产生式中的非终结符时{firstzh(a,g[i][j]);//用递归的方法算出此非终结符的first集合if(!search(emptychar,g[i][j]))//当此非终结符的first集合中无空字符时,对此产生式扫描完毕break;}else{}}elsebreak;}}}void grammer::fellowzh(char *a,char ch)//对指定非终结符建立fellow集合{int i,j,k,m,n,t=a[0];if(ch==begin)//把#字符放入开始符的fellow集合{if(!search(a,'#'))a[++t]='#';a[0]++;}}for(i=0;i<count;i++){for(j=2;j<=g[i][0];j++){if(g[i][j]==ch){for(m=j;m<=g[i][0];m++){if(m==g[i][0]){if(g[i][1]!=ch)fellowzh(a,g[i][1]);//发现要求的非终结符在此产生式的末尾时elsebreak;}else{if(!search(vn,g[i][m+1]))//当此非终结符后面的字符为终结字符时,放入对应的fellow集合{if(!search(a,g[i][m+1])){a[++t]=g[i][m+1];a[0]++;}break;}else{k=search(vn,g[i][m+1]);//把此非终结符后面的非终结符的first集合中的元素放入对应的fellow集合for(n=1;n<=first[k-1][0];n++){if(!search(a,first[k-1][n])){a[++t]=first[k-1][n];a[0]++;}}if(!search(emptychar,g[i][m+1]))break;}}}}}}void grammer::prepareform(){int i,j;buildemptychar();buildfirst();buildfellow();for(i=0;i<vn[0];i++){if(search(emptychar,vn[i+1])){j=first[i][0];first[i][++j]='@';first[i][0]++;}}for(i=0;i<vn[0];i++){cout<<vn[i+1]<<"的first集合为: ";for(j=1;j<=first[i][0];j++){cout<<first[i][j]<<" ";}cout<<endl;}}void grammer::buildform(){int i,j,k,t,m,n;bool flag;form=new int*[vn[0]];for(i=0;i<vn[0];i++)form[i]=new int[vt[0]];for(i=0;i<vn[0];i++){for(j=0;j<vt[0];j++){form[i][j]=-1;}for(i=0;i<count;i++){t=search(vn,g[i][1]);flag=true;for(j=2;j<=g[i][0];j++){k=search(vt,g[i][j]);//若发现这个产生式的first集合中的对应的终结符时if(k){if(g[i][j]!='@'){if(form[t-1][k-1]!=-1){cout<<"本终结符错误!"<<endl;exit(1);}form[t-1][k-1]=i;flag=false;break;}else//若发现对应产生式中的first集合中含有空字符时{for(m=1;m<=fellow[t-1][0];m++){if(fellow[t-1][m]!='#')//可把对应的非终结符的fellow集合中的元素对应的表项中填入该产生式的标号{n=search(vt,fellow[t-1][m]);if(form[t-1][n-1]!=-1){cout<<"有终结符@本fellow集合中非#错误!"<<endl;exit(1);}form[t-1][n-1]=i;}else{if(form[t-1][k-1]!=-1){cout<<"有终结符@本fellow集合中#错误!"<<endl;exit(1);}form[t-1][k-1]=i;}flag=false;break;}}else//找到该产生式中的非终结符时{k=search(vn,g[i][j]);for(m=1;m<=first[k-1][0];m++){if(first[k-1][m]!='@'){n=search(vt,first[k-1][m]);if(form[t-1][n-1]!=-1){cout<<"本first集合中非@!"<<endl;exit(1);}form[t-1][n-1]=i;}else{}}if(!search(first[k-1],'@'))//若在此终结符对应的first集合中无空字符时{flag=false;break;}}}if(flag==true)//说明该产生式对应的first集合中含有空字符{for(m=1;m<=fellow[t-1][0];m++){if(fellow[t-1][m]!='#'){n=search(vt,fellow[t-1][m]);if(form[t-1][n-1]!=-1){cout<<"本fellow集合中非#错误!"<<endl;exit(1);}form[t-1][n-1]=i;}{n=search(vt,'@');if(form[t-1][n-1]!=-1){cout<<"本fellow集合中#错误!"<<endl;exit(1);}form[t-1][n-1]=i;}}}}printform();}void grammer::outputblank(int i){int j;for(j=0;j<i;j++)cout<<" ";}void grammer::printform(){int i,j,k,t,m;cout<<"-----------------------------预测分析表如下所示------------------------------"<<endl;outputblank(6);for(i=1;i<=vt[0];i++){if(vt[i]=='@'){cout<<"#";outputblank(10);}else{cout<<vt[i];outputblank(10);}}cout<<endl;for(i=0;i<vn[0];i++){cout<<" "<<vn[i+1];outputblank(4);{k=form[i][j];if(k==-1){Sleep(500);cout<<"error";outputblank(6);}else{Sleep(1000);t=9-g[k][0];cout<<g[k][1]<<"->";for(m=2;m<=g[k][0];m++){cout<<g[k][m];}outputblank(t);}}cout<<endl;}}void grammer::buildProcess(SeqStack& ss) {char *dia,ch;int i,j,inlen,m,n,index=0,proc=0;bool flag=true,flag1=false;dia=new char[20];cout<<"请输入待分析的字符串"<<endl;cin>>dia;for(i=0,inlen=0;i<20;i++){if(dia[i]!='\0')inlen++;elsebreak;}cout<<"步骤";outputblank(8);cout<<"符号栈";outputblank(15);cout<<"输入串";outputblank(15);cout<<"所用产生式"<<endl;dia[inlen++]='#';ss.Push('#');ss.Push(begin);while(flag){Sleep(1500);cout<<proc;if(proc>=10)outputblank(11);elseoutputblank(12);++proc;ss.showPlay();outputblank(21-ss.getSize());for(j=index;j<inlen;j++)cout<<dia[j];outputblank(21-inlen+index);if(flag1==true){cout<<g[form[m-1][n-1]][1]<<"->";for(j=2;j<=g[form[m-1][n-1]][0];j++)cout<<g[form[m-1][n-1]][j];cout<<endl;}elsecout<<endl;ss.getTop(ch);m=search(vn,ch);if(dia[index]!='#')n=search(vt,dia[index]);elsen=search(vt,'@');if(search(vt,ch))//当栈顶是终结符{if(ch==dia[index])//且此终结符与输入串此时检测的终结符符号相同{index++;ss.Pop(ch);flag1=false;}else{cout<<"该字符串不能由该文法推出"<<endl;exit(1);}}else if(ch=='#'){if(ch==dia[index]){cout<<endl;cout<<"---------------------------------分析完成------------------------------"<<endl;flag=false;}else{cout<<"该字符串不能由该文法推出"<<endl;exit(1);}}else if(form[m-1][n-1]!=-1)//当栈顶的非终结符与输入串对应的终结符在预测分析表中相应的项存在时{if(g[form[m-1][n-1]][2]!='@'){ss.Pop(ch);for(i=g[form[m-1][n-1]][0];i>=2;i--){ss.Push(g[form[m-1][n-1]][i]);}}elsess.Pop(ch);flag1=true;}else{cout<<"该字符串不能由该文法推出"<<endl;exit(1);}}}void SeqStack::overflowProcess(){char *newArray=new char[maxSize+stackIncreament];if(newArray==NULL){cerr<<"存储分配失败!"<<endl;exit(1);}for(int i=0;i<=top;i++)newArray[i]=elements[i];maxSize=maxSize+stackIncreament;delete []elements;elements=newArray;}void SeqStack::Push(char x){if(IsFull()==true)overflowProcess();elements[++top]=x;}bool SeqStack::Pop(char &x){if(IsEmpty()==true)return false;x= elements[top--];return true;}bool SeqStack::getTop(char &x){if(IsEmpty()==true)return false;x=elements[top];return true;}void SeqStack::showPlay(){for(int i=0;i<=top;i++)cout<<elements[i];}SeqStack::SeqStack(int sz):top(-1),maxSize(sz) {elements=new char[maxSize];assert(elements!=NULL);}SeqStack::~SeqStack(){delete []elements;}bool SeqStack::IsEmpty(){return(top==-1)?true:false;}bool SeqStack::IsFull(){return (top==maxSize-1)?true:false;}int SeqStack::getSize(){return top+1;}void SeqStack::MakeEmpty(){top=-1;}#include<iostream>#include"编译.h"using namespace std;void main(){//char ch;grammer ga;SeqStack ss;char filename[20];cout<<"欢迎来到本LL(1)文法预测分析表自动生成程序"<<endl;cout<<endl;cout<<endl;cout<<"请输入文法所在的文件名"<<endl;cin>>filename;ga.openfile(filename);ga.prepareform();ga.buildform();ga.buildProcess(ss);}。

LL(1)文法分析表的构造和分析过程示例

LL(1)文法分析表的构造和分析过程示例

LL(1)⽂法分析表的构造和分析过程⽰例在考完编译原理之后才弄懂,悲哀啊。

不过懂了就好,知识吗,不能局限于考试。

⽂法:E→TE'E'→+TE'|εT→FT 'T'→*FT'|εF→id| (E)⼀、⾸先判断是不是 LL(1)⽂法--------------------------------------------------------------------------------------------------------⽂法G的任意两个具有相同左部的产⽣式 A --> α|β满⾜下列条件:1、如果α和β不能同时推导出ε,则 FIRST(α)∩FIRST(β) = 空2、α和β⾄多有⼀个能推导出ε3、如果β --*--> ε ,则 FIRST(α)∩ FOLLOW(A)=空--------------------------------------------------------------------------------------------------------对于 E'→+TE'|ε,显然ε --> ε, First(+TE') = {+} ,Follow(E') = {{),#} 显然⼆者交集为空满⾜。

对于 F→id|(E) ,First(id) = {id} First((E)) = {(} 显然⼆者交集为空满⾜。

所以该⽂法是LL(1)⽂法。

⼆、计算出First集和Follow集参考:三、构建LL(1)分析表输⼊:⽂法G输出:分析表M步骤:1、对G中任意⼀个产⽣式 A --> α执⾏第2步和第3步2、for 任意a ∈ First(α),将 A --> α填⼊M[A,a]3、if ε∈ First(α) then 任意a ∈ Follow(A),将 A --> α填⼊M[A,a]if ε∈ First(α) & # ∈Follow(A), then 将 A --> α填⼊M[A,#] (觉得这步没⽤)4、将所有没有定义的M[A,b] 标上出错标志(留空也可以)--------------------------------------------------------------------------------------------------------过程就不赘述了,结果:四、分析过程步骤:1、如果 X = a = # 则分析成功并停机2、如果 X = a != # 则弹出栈顶符号X, 并将输⼊指针移到下⼀个符号上3、如果 X != a,查询分析表M[X,a] , 如果 M[X,a] = {X --> UVW},则⽤UVW (U在栈顶) 替换栈顶符号 X。

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

编译原理实验报告——实验三 语法分析分析器
8
//判断文法是否合法
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();
return六实验者自评主要从实验态度方法效果上给一个客观公正的自我评价这次实验编写了两个词法分析方法的程序但是在ll1分析器的编写中我只达到了最低要求就是自己手动输入的select集first集follow集然后通过程序将预测分析表构造出来了并且没有做出对输入串的分析
编译原理实验报告
实验名称: 实验类型: 指导教师: 专业班级: 姓 学 名: 号:
first[i][0]=0;
ቤተ መጻሕፍቲ ባይዱ
/*first[i][0]和 last[i][0]分别表示 st[i][0]非终极

《编译原理》构造LL(1)分析表的步骤-例题解析

《编译原理》构造LL(1)分析表的步骤-例题解析

《编译原理》构造LL(1)分析表的步骤-例题解析《编译原理》构造 LL(1) 分析表的步骤 - 例题解析易错点及扩展:1、求每个产⽣式的 SELECT 集2、注意区分是对谁 FIRST 集 FOLLOW 集3、开始符号的 FOLLOW 集包含 #4、各集合对对应的对象以及含义集对象含义FIRST 集是对产⽣式右部右部内部的所有终结符集,可能为εFOLLOW 集是对产⽣式左部(⾮终结符)⾮终结符后⾯紧跟的终结符,可能为 #,和该⾮终结符推导出的右部⽆关(因为LL(1)⽂法不包含递归,所以右部不会再有该⾮终结符,所以不能通过该右部判断该⾮终结符后跟集合)SELECT集是对产⽣式需要考虑产⽣式右部的不同情况,进⼀步确定是根据 FIRST 集还是 FOLLOW 集5、SELECT 集的定义注:注意区分 FIRST 集 FOLLOW 时是对α还是 A给定⽂法 G,对于产⽣式 A→α,α∈ V*,则可选集 SELECT(A→α) 有:(1)若α ≠ ε,且α ≠+> ε,则 SELECT(A→α) = FIRST(α)(2)若α ≠ ε,但α =+> ε,则 SELECT(A→α) = FIRST(α) ∪ FOLLOW(A)(3)若α = ε,则 SELECT(A→α) = FOLLOW(A)描述:第 1 条是,当α ≠ ε,且通过1次或多次推不出ε,SELECT(A→α) = FIRST(α)第 2 条是,当α ≠ ε,但α经有限步可推出ε,SELECT(A→α) = FIRST(α) ∪ FOLLOW(A)(注意是⼀个α,⼀个 A)第 3 条是,当α = ε,SELECT 集就等于左部 A 的 FOLLOW 集解题时,先判断是否为ε,是则⽤第(3)条,否则再判断能否通过1次或多次推出ε,是则⽤第(2)条,否则⽤第(1)条求 FIRST,FOLLOW,SELECT 集详细例题可参考:6、LL(1) 分析表的结构分析表是⼀个⼆维数组 M[A,a],其中 A 表⽰⾏,是⾮终结符,a 表式列是终结符或 #。

编译原理LL(1)分析器(C语言)

编译原理LL(1)分析器(C语言)
T FT ' 且T '
*

FOLLOW (T ) FOLLOW ( F )
,

FOLLOW(F)={*,+,),#}。 4 LL(1)分析表 知道了 FIRST 集和 FOLLOW 集, 我们就可以构造出 LL(1)分析表。 文法 G[E] 的分析表如表 1:
表1 i E E’ T T’ F + 文法 G[E]的分析表 * ( ) #
if(ch[l]!=cha) { if(ch[l]!=39) { switch(ch[l]) { case 'E': m=0;break; case 'T': m=2;break; case 'F': m=4;break; default: m=-1;break; } }/*if(ch[l]!=''')*/ else { switch(ch[l-1]) { case 'E': m=1;break; case 'T': m=3;break; default: m=-1;break; } }/*if(ch[l])=='''*/ }/*if ch[l]!=cha*/ if(m!=-1) { if(ch[l]!=cha) { how=ll1[m][j]; if(how==1) { printf("Pop %c,push E->TE' by reversing!\n",ch[l]); n=3; l=l+n-1; ch[l]='T'; ch[l-1]=39; ch[l-2]='E'; step=step+1; }/*if how==1*/

LL(1)语法分析实验报告

LL(1)语法分析实验报告

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

二、实验内容构造LL(1)语法分析程序,任意输入一个文法符号串,并判断它是否为文法的一个句子。

程序要求为该文法构造预测分析表,并按照预测分析算法对输入串进行语法分析,判别程序是否符合已知的语法规则,如果不符合则输出错误信息。

消除递归前的文法消除递归后的等价文法E→E+T E→TE’E→T E’→+TE’|εT→T*F T→FT’T→F T’→*FT’|εF→(E)|i F→(E)|i根据已建立的分析表,对下列输入串:i+i*i进行语法分析,判断其是否符合文法。

三、实验要求1.根据已由的文法规则建立LL(1)分析表;2.输出分析过程。

请输入待分析的字符串: i+i*i符号栈输入串所用产生式#E i+i*i# E→TE’#E’T i+i*i# T→FT’#E’T’F i+i*i# F→i#E’T’i i+i*i##E’T’ +i*i# T’→ε#E’ +i*i# E’→+TE’#E’T+ +i*i##E’T i*i# T→FT’#E’T’F i*i# F→i#E’T’i i*i##E’T’ *i# T’→*FT’#E’T’F* *i##E’T’F i# F→i#E’T’i i##E’T’ # T’→ε#E’ # E’→ε# #四、程序思路模块结构:1、定义部分:定义常量、变量、数据结构。

2、初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体等);3、运行程序:让程序分析一个text文件,判断输入的字符串是否符合文法定义的规则;4、利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示简单的错误提示。

五、程序流程图输入要分析的串判断输入串是否正确判断分析句型是否完全匹配?成功失败否是是否八、程序调试与测试结果运行后结果如下:九、实验心得递归下降分析法是确定的自上而下分析法,这种分析法要求文法是LL(1)文法。

编译原理-实验报告3-LL1

编译原理-实验报告3-LL1

计算机硬件实验室实验报告根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。

本次实验的目的主要是加深对预测分析LL(1)分析法的理解。

二、实验要求:对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG|—TG(3)G->ε(4)T->FS(5)S->*FS|/FS(6)S->ε(7)F->(E)(8)F->i输出的格式如下:(1)LL(1)分析程序,编制人:姓名,学号,班级(2)输入一以#结束的符号串(包括+—*/()i#):在此位置输入符号串(3)输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG(4)输入符号串为非法符号串(或者为合法符号串)备注:(1)在“所用产生式”一列中如果对应有推导则写出所用产生式;如果为匹配终结符则写明匹配的终结符;如分析异常出错则写为“分析出错”;若成功结束则写为“分析成功”。

(2) 在此位置输入符号串为用户自行输入的符号串。

(3)上述描述的输出过程只是其中一部分的。

注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、字符i,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);三、实验过程:1.模块设计:将程序分成合理的多个模块(函数),每个模块做具体的同一事情。

2.写出(画出)设计方案:模块关系简图、流程图、全局变量、函数接口等。

3.程序编写(1)定义部分:定义常量、变量、数据结构。

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

四、实验结果:(1)写出程序流程图(2)给出运行结果示例程序:注意:本示例只要修改分析的句子即可,不要改写文法/*LL(1)分析法源程序,只能在VC++中运行*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dos.h>char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','-','*','/','(',')','#'};/*终结符*/char v2[20]={'E','G','T','S','F'};/*非终结符*/int j=0,b=0,top=0,l;/*L为输入串长度*/typedef struct type/*产生式类型定义*/{char origin;/*大写字符*/char array[5];/*产生式右边字符*/int length;/*字符个数*/}type;type e,t,g,g1,g2,s,s2,s1,f,f1;/*结构体变量*/type C[10][10];/*预测分析表*/void print()/*输出分析栈*/{int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}/*print*/void print1()/*输出剩余串*/{int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}/*print1*/void main(){int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受C[m][n]*//*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g1.origin='G';strcpy(g1.array,"-TG");g1.length=3;g2.origin='G';g2.array[0]='^';g2.length=1;/////////////////////////////////////////////s.origin='S';strcpy(s.array,"*FS");s.length=3;s1.origin='S';strcpy(s1.array,"/FS");s1.length=3;s2.origin='S';s2.array[0]='^';s2.length=1;////////////////////////////////f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++)/*初始化分析表*/for(n=0;n<=5;n++)C[m][n].origin='N';/*全部赋为空*//*填充分析表*///char v1[20]={'i','+','-','*','/','(',')','#'};/*终结符*///char v2[20]={'E','G','T','S','F'};/*非终结符*/C[0][0]=e;C[0][5]=e;C[1][1]=g;C[1][2]=g1;C[1][3]=C[1][4]=C[1][7]=g2;C[2][0]=t;C[2][3]=t;C[2][5]=t;C[3][1]=C[3][2]=s2;C[3][3]=s;C[3][4]=s1;C[3][6]=C[3][7]=s2;C[4][0]=f1; C[4][5]=f;printf("LL(1)分析程序,编制人:武普泉,20号,1020562班\n");printf("输入一以#结束的符号串(包括+ - * / () i #):");do/*读入分析串*/{scanf("%c",&ch);if ((ch!='i') &&(ch!='+') &&(ch!='-')&&(ch!='*')&&(ch!='/')&&(ch!='(')&&(ch!=')')&&(ch!='#')) {printf("输入串中有非法字符\n");exit(1);}B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n");do{x=A[top--];/*x为当前栈顶字符*/printf("%d",k++);printf("\t\t");for(j=0;j<=7;j++)/*判断是否为终结符*/if(x==v1[j]){flag=1;break;}if(flag==1)/*如果是终结符*/{if(x=='#'){finish=1;/*结束标记*/printf("acc!\n");/*接受*/getchar();getchar();exit(1);}/*if*/if(x==ch){print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/{for(j=0;j<=4;j++)if(x==v2[j]){m=j;/*行号*/break;}for(j=0;j<=7;j++)if(ch==v1[j]){n=j;/*列号*/break;}cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/{print();print1();printf("%c->",cha.origin);/*输出产生式*/for(j=0;j<cha.length;j++)printf("%c",cha.array[j]);printf("\n");for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}/*else*/}/*else*/}while(finish==0);}/*main*。

编译原理,语法分析程序设计(LL(1)分析法)

编译原理,语法分析程序设计(LL(1)分析法)

编译原理,语法分析程序设计(LL(1)分析法)1.实验目得:掌握LL(1)分析法得基本原理,掌握LL(1)分析表得构造方法,掌握LL(1)驱动程序得构造方法。

2、实验要求:实现LR分析法(P147,例4、6)或预测分析法(P121,例4、3). 3、实验环境:一台配置为1G 得XP 操作系统得PC 机;Visual C++6、0、4、实验原理:编译程序得语法分析器以单词符号作为输入,分析单词符号串就是否形成符合语法规则得语法单位,如表达式、赋值、循环等,最后瞧就是否构成一个符合要求得程序,按该语言使用得语法规则分析检查每条语句就是否有正确得逻辑结构,程序就是最终得一个语法单位。

编译程序得语法规则可用上下文无关文法来刻画。

语法分析得方法分为两种:自上而下分析法与自下而上分析法.自上而下就就是从文法得开始符号出发,向下推导,推出句子.而自下而上分析法采用得就是移进归约法,基本思想就是:用一个寄存符号得先进后出栈,把输入符号一个一个地移进栈里,当栈顶形成某个产生式得一个候选式时,即把栈顶得这一部分归约成该产生式得左邻符号。

自顶向下带递归语法分析:1、首先对所以得生成式消除左递归、提取公共左因子2、在源程序里建立一个字符串数组,将所有得生成式都存在这个数组中. 3、给每个非终结符写一个带递归得匹配函数,其中起始符得函数写在main函数里。

这些函数对生成式右边从左向右扫描,若就是终结符直接进行匹配,匹配失败,则调用出错函数。

如果就是非终结符则调用相应得非终结符函数. 4、对输入得符号串进行扫描,从起始符得生成式开始。

如果匹配成功某个非终结符生成式右边得首个终结符,则将这个生成式输出。

匹配过程中,应该出现得非终结符没有出现,则出错处理。

5、软件设计与编程:对应源程序代码:#include <iostream、h>#include stdio、h#includ e〈stack>using namespace std;struct Node1 {charvn;charvt;char s[10]; }MAP[20];//存储分析预测表每个位置对应得终结符,非终结符,产生式int k;//用R代表E“,W代表T',e 代表空char start=’E';int len=8; charG[10][10]={"E-TR“,”R—+TR”,"R—e”,”T-FW",”W-〉*FW",”W-e”,”F-〉(E)","F—i"};//存储文法中得产生式char VN[6]={"E",’R",’T',"W",’F’};//存储非终结符char VT[6]={"i',’+’,"*’,"(’,’)’,'#'};//存储终结符charSELECT[10][10]={"(,i","+","),#","(,i”,"*","+,),#”,"(",”i"};//存储文法中每个产生式对应得SELECT集char Right[10][8]={"-〉TR”,"-+TR”,”-e”,”-〉FW","-*FW”,"—>e","-〉(E)”,"—stack 〈char stak;bool pare(char*a,char *b) {int i,la=strlen(a),j,lb=strlen(b);for(i=0;i〈la;i++) {)++j;bl0=j(rofﻩ{if(a[i]==b[j])return 1;}}return 0;}char*Find(char vn,char vt){inti;for(i=0;i<k;i++){if(MAP[i]、vn==vn &MAP[i]、vt==vt){};s、]i[PAM nruterﻩ} };”rorre" nruterﻩchar *Analyse(char * word) {char p,action[10],output;int i=1,j,l=strlen(word),k=0,l_act,m;while(!stak、empty()){stak、pop();}stak、push(’#’);;)trats(hsup、katsﻩprintf("___________________________________________________________\n”);printf("\n对符号串%s 得分析过程\n”,word);printf(” —-------—--——---——---—--——-——-—-—---—-—---———--—-——--—-—--—-—-——--————-\n");printf(”\n");p rintf ("步骤栈顶元素剩余输入串动作\n”);printf(” -—-———-——---—-—-—————----——----——-—--—--—--———-——-—-----————-—---—-—--—\n”);p=stak、top();while(p!=’#’){printf("%7d",i++);p=stak、top();stak、pop();printf(”%6c”,p);for(j=k,m=0;j<l;j++) {};]j[drow=]++m[tuptuoﻩﻩoutput[m]="\0';printf("%10s",output);if(p==word[k]){if(p=="#"){printf("分析成功\n”);return"SUCCESS";}printf(”匹配终结符%c\n”,p);k++;}else{strcpy(action,Find(p,word[k]));if(strcmp(action,”error")==0){printf("没有可用得产生式\n”);return ”ERROR"; }printf ("展开非终结符%c%s\n”,p,action);int l_act=strlen(action);if(action[l_act—1]=='e'){ };eunitnocﻩﻩfor(j=l_act—1;jj--){}}};)]j[noitca(hsup、katsﻩﻩ if(strcmp(output,"#")!=0)return "ERROR";}int main() {freopen("in、txt”,"r”,stdin);char source[100];inti,j,flag,l,m;printf("\n***为了方便编写程序,用R 代表E',W 代表T’,e 代表空*****\n\n”);printf("该文法得产生式如下:\n");for(i=0;i〈len;i++) {};)]i[G,"n\s%”(ftnirpﻩprintf("___________________________________________________________\n");printf("\n 该文法得SELECT集如下:\n");for(i=0;ilen;i++){printf("SELECT(%s)= { %s }\n",G[i],SELECT[i]);}ﻩprintf("___________________________________________________________\n");//判断就是否就是LL(1)文法flag=1;for(i=0;i〈8;i++){for(j=i+1;j〈8;j++){if(G[i]==G[j]){if(pare(SELECT[i],SELECT[j])){flag=0;ﻩﻩ} }};kaerbﻩ)8=!j(fiﻩ{break;}}if(flag){printf("\n有相同左部产生式得SELECT 集合得交集为空,所以文法就是LL(1)文法。

ll 1 语法分析实验报告

ll 1 语法分析实验报告

ll 1 语法分析实验报告语法分析实验报告一、引言语法分析是编译器中的重要步骤之一,它负责将输入的源代码转化为语法树或抽象语法树,以便后续的语义分析和代码生成。

本实验旨在通过实现一个简单的LL(1)语法分析器,加深对语法分析原理和算法的理解。

二、实验目的1. 理解LL(1)语法分析的原理和算法;2. 掌握使用LL(1)文法描述语言的方法;3. 实现一个简单的LL(1)语法分析器。

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

四、实验步骤1. 设计LL(1)文法在开始实现LL(1)语法分析器之前,我们需要先设计一个LL(1)文法。

LL(1)文法是一种满足LL(1)分析表构造要求的文法,它能够保证在语法分析过程中不会出现二义性或回溯。

通过仔细分析待分析的语言的语法规则,我们可以设计出相应的LL(1)文法。

2. 构造LL(1)分析表根据设计的LL(1)文法,我们可以构造出对应的LL(1)分析表。

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

表格中的每个元素表示在某个非终结符和终结符的组合下,应该进行的语法分析动作。

3. 实现LL(1)语法分析器基于构造的LL(1)分析表,我们可以开始实现LL(1)语法分析器。

分析器的主要工作是根据输入的源代码和LL(1)分析表进行分析,并输出语法树或抽象语法树。

五、实验结果与分析经过实验,我们成功实现了一个简单的LL(1)语法分析器,并对一些简单的语言进行了分析。

实验结果表明,我们设计的LL(1)文法和LL(1)分析表能够正确地进行语法分析,没有出现二义性或回溯。

六、实验总结通过本次实验,我们深入学习了LL(1)语法分析的原理和算法,并通过实现一个简单的LL(1)语法分析器加深了对其的理解。

实验过程中,我们发现LL(1)文法的设计和LL(1)分析表的构造是实现LL(1)语法分析器的关键。

同时,我们也意识到LL(1)语法分析器在处理复杂的语言时可能会面临一些困难,需要进一步的研究和优化。

编译原理实验 LL(1)分析

编译原理实验 LL(1)分析

实验三语法分析---LL(1)分析器目录一. 实验的目的与思路 (2)(1)目的 (2)(2)思路 (2)二. 基本的功能 (3)三.总体设计 (4)四.详细设计 (5)五.源程序清单 (6)六.源代码 (6)....................................................................................................................................................一. 实验的目的与思路(1)目的1. 用程序的方法实现语法分析的LL(1)方法。

(2)思路本程序是采用的LL(1)方法进行的语法分析,而LL(1)的分析方法是属于自上而下的方法。

自上而下分析的基本思想是:对任意输入串,试图用一切可能的方法,从文法开始符号(根结点)出发,自上而下为输入串建立一棵语法树。

从推导的角度看,它是从文法的开始符号出发,反复使用各种产生式,寻找与输入串匹配的推导。

在输入之前必须要进行该文法是不是LL(1)文法的判断,然后再构造相应的LL(1)分析表来用预测分析方法进行语法分析,依据下面的文法及分析表来设计程序实现预测分析的分析过程。

1.文法G[E]:E --> E+T|TT --> T*F|FF --> (E) | i2.通过观察可知道该文法是一个左递归文法,要进行语法分析就必须消除左递归才能继续判断它是不是LL(1)文法,然后才能用预测分析方法进行语法分析。

3.消除左递归:E -->TMM --> +TM|uT --> FQQ --> *FQ|uF --> (E) | i4.在进行LL(1)文法的判断:(1.)各非终结符的FIRST集如下:FIRST(E)= FIRST(TM)= {(,i }FIRST(M)= { + }FIRST(T)= {(,i }FIRST(Q)= { * }FIRST(F)= { (,i }(2.)各非终结符的FOLLOW集如下:FOLLOW(E)= { ),# }FOLLOW(M)= { ),# }FOLLOW(T)= { + ,),# }FOLLOW(Q)= { + ,),# }FOLLOW(F)= { * ,+ ,),# }(3.)各产生式的SELECT集如下:SELECT(E→TM)={ ( ,i }SELECT(M→+TM)={+}SELECT(M→u)={ }, #}SELECT(T→FQ)={ ( ,i }SELECT(Q→*FQ)={ *}SELECT(Q→u)={ +,), # }SELECT(F→(E))={ ( )SELECT(F→i)={ i }因为:SELECT(M→+TM)∩SELECT(M→u)=ФSELECT(Q→*FQ)∩SELECT(Q→u)=ФSELECT(F→(E))∩SELECT(F→i)=Ф因此可以判断该文法是一个LL(1)文法可以构造预测分析表。

LL(1)法分析器

LL(1)法分析器

LL(1)语法分析器实验报告书目录第一章概述 (3)1.1 开发平台 (3)1.2 实验目的 (3)1.3 实验要求 (3)第二章语法分析器的实现 (3)2.1 LL(1)语法分析器原理 (3)2.2 求出能推出空的终结符 (4)2.3 FIRST集的确定 (4)2.4 FOLLOW集的确定 (4)2.5 SELECT集的确定 (4)2.6 LL(1)文法的判别 (4)2.7 逻辑结构 (4)2.8 预测分析表的生成 (5)2.9 句子的判定 (5)2.10 其他说明 (5)第三章系统运行与测试 (6)3.1 程序运行环境 (6)3.2 运行界面 (6)3.3 系统测试 (8)第四章总述 (11)4.1 程序综述 (11)4.2小组工作总结 (11)第一章概述1.1 开发平台本程序基于Microsoft Visual Studio 2008开发,使用C#语言。

1.2 实验目的掌握LL(1)分析法的基本原理,掌握LL(1)分析表的构造方法,掌握LL(1)驱动程序的构造方法。

1.3 实验要求编写一个语法分析器,不限语言,方法。

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

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

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

语法分析程序流程图2.2 求出能推出空的终结符见许英俊报告2.3 FIRST集的确定见邹杰光报告2.4 FOLLOW集的确定见张志峰报告2.5 SELECT集的确定见叶凯翔报告2.6 LL(1)文法的判别见叶凯翔报告2.7 逻辑结构一个LL(1)分析器由一张分析表、一个分析栈和一个总控程序组成。

其逻辑结构如图2-1所式。

2.8 预测分析表的生成见许英俊报告2.9 句子的判定当一个文法确定是LL(1)文法时就可以对输入的语句进行判定了。

LL(!)语法分析

LL(!)语法分析

LL(1)语法分析一、实验目的:理解语法分析程序的主要任务和实现技术。

二、实验内容:为无二义性表达式文法G[E]构造语法分析程序G[E]: E->E+T|T T->T*F|F F->(E)|i三、实验要求:1.用递归下降分析方法实现,要求能够对正确的和错误的输入串进行分析,给出分析结果(accept/error)。

2.程序输入为形如i+i*i# 或者ii#的串,输出为推导所用的产生式序列四、程序流程图#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <stack>using namespace std;struct Node1{char vn;char vt;char s[10];}MAP[20];//存储分析预测表每个位置对应的终结符,非终结符,产生式int k;//用R代表E',W代表T',e代表空charG[10][10]={"E->TR","R->+TR","R->e","T->FW","W->*FW","W->e","F->( E)","F->i"};//存储文法中的产生式char VN[6]={'E','R','T','W','F'};//存储非终结符char VT[6]={'i','+','*','(',')','#'};//存储终结符char SELECT[10][10]={"(,i","+","),#","(,i","*","+,),#","(","i"};//存储文法中每个产生式对应的SELECT集charRight[10][8]={"->TR","->+TR","->e","->FW","->*FW","->e","->(E)","->i"} ;stack <char> stak,stak1,stak2;bool compare(char *a,char *b){int i,la=strlen(a),j,lb=strlen(b);for(i=0;i<la;i++)for(j=0;j<lb;j++){if(a[i]==b[j])return 1;}return 0;}char *Find(char vn,char vt){int i;for(i=0;i<k;i++){if(MAP[i].vn==vn && MAP[i].vt==vt)return MAP[i].s;}return "error";}//当非终结符遇到终结符时应采用哪个产生式来推导char * Analyse(char * word){char p,action[10],output[10];int i=1,j,l=strlen(word),k=0,l_act,m;while(!stak.empty())stak.pop();//清空了分析栈stak.push('#');stak.push('E');printf("_____________________________________________________________ ___________________\n");printf("\n 对符号串%s的分析过程\n",word);printf(" 步骤栈顶元素剩余输入串推到所用产生式或匹配\n");p=stak.top();while(p!='#'){printf("%7d ",i++);p=stak.top();stak.pop();//栈顶元素出栈printf("%6c ",p);for(j=k,m=0;j<l;j++)output[m++]=word[j];output[m]='\0';printf("%10s",output);//剩余的输入串if(p==word[k]){if(p=='#'){printf(" 接受\n");return "SUCCESS";}printf(" “%c”匹配\n",p);k++;}else{strcpy(action,Find(p,word[k]));if(strcmp(action,"error")==0){printf(" 没有可用的产生式\n");return "ERROR";}printf(" %c%s\n",p,action);int l_act=strlen(action);//产生式长度if(action[l_act-1]=='e')continue;for(j=l_act-1;j>1;j--)//如果不是空产生式stak.push(action[j]);//将推导用的产生式倒叙入栈}}if(strcmp(output,"#")!=0)return "ERROR";}int main (){char c;int e=0;//freopen("in.txt","r",stdin);// freopen("c:\out.txt","w",stdout);char source[100];int i,j,flag,l,m;printf("\n*****为了方便编写程序,用R代表E',W代表T',e代表空*****\n\n");printf("该文法的产生式如下:\n");for(i=0;i<8;i++)printf(" %s\n",G[i]);printf("_____________________________________________________________ ___________________\n");printf("\n该文法的SELECT集如下:\n");for(i=0;i<8;i++){printf(" SELECT(%s) = { %s }\n",G[i],SELECT[i]);}printf("_____________________________________________________________ ___________________\n");//判断是否是LL(1)文法flag=1;for(i=0;i<8;i++){for(j=i+1;j<8;j++){if(G[i][0]==G[j][0])//产生式左部相同{if(compare(SELECT[i],SELECT[j])){flag=0;break;}}}if(j!=8)break;}if(flag)printf("\n有相同左部产生式的SELECT集合的交集为空,所以文法是LL(1)文法。

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

3. 构造驱动程序
构造LL(1)驱动程序的算法: (1). 分析开始时,首先将标志符号#和文法开始符号S依次压入符号栈;输入流指针指向 第一个输入符号,即由符号栈和输入流构成的初始格局为: (#S, a1a2...an#) 然后,反复执行第2步所列的工作。 (2). 设在分析的某一步,符号栈及剩余的输入流处于如下的格局 (#X1X2...Xm-1Xm, aiai+1...an#) 其中,X1X2...Xm-1Xm为分析过程中所得的文法符号,此时,可视栈顶符号Xm的不同情况,分 别作如下动作: 若XmVN,则以Xm及ai组成的符号对(Xm,ai)查分析表T。设T(Xm,ai)为一产生 式,假设是XmUVW,此时将Xm从分析栈中退出,并将UVW压入栈中,从而得到新 的格局 (#X1X2...Xm-1WVU, aiai+1...an#) 但若T(Xm,ai)=Error,则调用出错处理程序进行处理; 若Xm=ai#,则表明栈顶符号已经与当前扫描的输入符号得到匹配,此时应将Xm(即 ai)从栈中退出,并将输入流指针向前移动一个位置。 若Xm=ai=#,则表明输入串已经完全得到匹配,此时即可宣告分析成功而结束分析。 其它情形,转错误处理程序。 程序见附录
LL(1)分析法属于自顶向下分析方法,因此需要预测匹配的产生式。即在LL(1)分析法中, 每当在符号栈的栈顶出现非终结符时,要预测用哪个产生式的右部去替换该非终结符。LL(1)分 析方法要求文法满足如下条件:对于任一非终结符A,其任意两个产生式A,A,都要满足下面条 件:First(A)∩First(A)= 2、分析表构造 LL(1)分析表的作用是对当前非终结符和输入符号确定应该选择用哪个产生式进行推导。它 的行对应文法的非终结符,列对应终结符,表中的值有两种:一是产生式的编号,一是错误编 号。若用T表示LL(1)分析表,则T可表示如下: T: VN×VTP∪{Error} T(A, t) = Aα,当tFirst(Aα) T(A, t) = Error,否则 其中P表示所有产生式的集合。显然,一个文法G是LL(1)文法,当且仅当T的元素包含唯一 的一个产生式或Error。 3、驱动程序构造 LL(1)分析主要包括以下四个动作,其中X为符号栈栈顶元素,a为输入流当前字符。 替换:当XVN时选相应产生式的右部去替换X。 匹配:当XVT时它与a进行匹配,其结果可能成功,也可能失败,如果成功则符号栈 中将X退栈并将输入流指针向前移动一位,否则报错。 成功:当格局为(空,空)时报告分析成功。 报错:出错后,停止分析。
FOLLOW(F)=FIRST 1、构造LL(1)分析表 采用手工操作构造LL(1)分析表。LL(1)分析表用一个二维矩阵表 示,其中每个非终结符对应一行,每个终结符对应一列,一个非终结符 和一个终结符可以确定矩阵中的一个元素,元素的值表示该非终结符和 该终结符对应的产生式。每个矩阵元素都是一个符号串,所有元素初始 化为””;构造LL(1)表时,根据文法和各个产生式的First集,填写LL(1) 分析表的内容。各产生式只要降右端填入到对应的表项中即可,用空串 表示Error。在根据LL(1)分析表选择产生式进行推导时,若查到的产生 式为空串表示无相应的产生式可选,不匹配错误;否则根据符号串得到 相应的产生式进行推导,即进行压栈操作。
sk.push('i'); c=sk.pop(); } else if(a[i]=='('){ System.out.println("F->(E)"); sk.push(')'); sk.push('E'); sk.push('('); c=sk.pop(); } else error(); } } private static void error() { System.out.println((i+1)+":"+a[i]+" error!"); i++; } }
七、实验结果
六、实验小结 1、在本次实验中,通过设计、编制、调试一个递归下降语法分析 程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分 析,掌握LL(1)分析法的基本原理、掌握LL(1)分析表的构造方法、掌握 LL(1)驱动程序的构造方法;
2、通过本次实验,对LL(1)递归下降分析程序的构造和设计有了更 为全面的认识,对LL(1)文法分析程序的实现有了进一步了解; 3、实验输入串以‘$’结束,才用栈的形式,依次弹出进行处理;
$EˊTˊF* (*,*)*匹配
2.数据结构 LL(1)语法分析程序共用到个栈,分别称为:符号栈,语法树栈, 操作符栈和操作数栈。其中,符号栈用于进行LL(1)语法分析;其它的 栈是为了在语法分析的过程中同时生成与源程序结构对应的语法树而 。语法树栈用于生成声明部分和语句部分的语法树;操作符栈和操作 数栈用于生成表达式部分的语法树。
集美大学计算机工程学院实验报告
课程名称:编译原理 实验编号: 实验三 班级:计算12 上机实践日期: 2014.12 指导教师:付永钢 姓名: 上机实践时间: 6学 时 实验成绩: 学号: 实验名称:LL(1)语法分析器的构造
一、实验目的 1、掌握LL(1)分析法的基本原理; 2、掌握LL(1)分析表的构造方法; 3、掌握LL(1)驱动程序的构造方法。 二、实验环境 Windows7 x64、VC6.0 三、实验原理 1、对文法要求
else if(a[i]==')'||a[i]=='$'){ System.out.println("E'->&"); c=sk.pop(); } else error(); } else if(c=='T'){ if(a[i]=='i'||a[i]=='('){ System.out.println("T->FT'"); sk.push('t'); sk.push('F'); c=sk.pop(); } else error(); } else if(c=='t'){ if(a[i]=='+'||a[i]==')'||a[i]=='$'){ System.out.println("T'->&"); c=sk.pop(); } else if(a[i]=='*'){ System.out.println("T'->*FT'"); sk.push('t'); sk.push('F'); sk.push('*'); c=sk.pop(); } else error(); } else if(c=='F'){ if(a[i]=='i'){ System.out.println("F->i");
} n++; a[n]='$'; } sk.push('$'); sk.push('E'); c=sk.pop(); do{ if(c==a[i]){ i++;c=sk.pop();} else if(a[i]=='$') break; else ll1(); } while(c!='$'); } private static void ll1() { if(c=='E'){ if(a[i]=='i'||a[i]=='('){ System.out.println("E->TE'"); sk.push('e'); sk.push('T'); c=sk.pop(); } else error(); } else if(c=='e'){ if(a[i]=='+'){ System.out.println("E'->+TE'"); sk.push('e'); sk.push('T'); sk.push('+'); c=sk.pop(); }
四、实验内容 已知文法G[E]: E→E+T|T
T→T*F|F F→(E)|i 说明:终结符号i为用户定义的简单变量, 即标识符的定义。 1、消除文法的左递归,构造对应文法的预测分析表; 2、根据构造的预测分析表,实现LL(1)分析中控制程序(表驱动程 序),并完成整个的LL(1)分析程序的界面设计、运行; 3、P104中,3.36写一个Yacc程序,把输入的算术表达式翻译成对 应的后缀表达式输出。要求转换正确,同时对于简单错误能够识别。 4、P104中,3.37,写一个Yacc“台式计算器”程序,它计算布尔表 达式,其中的词法分析器用Lex写。要求转换正确,同时对于简单错误 能够识别。 五、实验要求 1、输入串应是词法分析的输出二元式序列,即某算术表达式“实验 项目一”的输出结果。输出为输入串是否为该文法定义的算术表达式的 判断结果。 2、LL(1)分析过程应能发现输入串中的错误。 3、设计至少两个测试用例(尽可能完备,正确和出错),并给出测 试结果。 六、实验步骤、 1、分析文法 (1)E=>E+T=>E+T*F=>E+T*(E)即有E=>E+T*(E)存在左递归。用 直接改写法消除左递归,得到如下文法:G[E]: E→TE’ E’→+TE’|ε T→FT’ T’→*FT’|ε F→(E)|i (2)对于以上改进的文法,可以得到: FIRST(E’)=FIRST(+TE’)∪FIRST(-TE’)∪{ε}={+,ε} FIRST(T’)=FIRST(*FT’)∪FIRST(/FT’)∪{ε}={*,ε} FIRST(E)= FIRST( T ) = FIRST( F )=FIRST((E))∪FIRST(i)={(,i } 由此得到各非终结符的FOLLOW集合: FOLLOW(E)={ ),$} FOLLOW(E’)=FOLLOW(E)={),$} FOLLOW(T)=FIRST(E’)∪FOLLOW(E’)={ +,),$} FOLLOW(T’)=FOLLOW(T)={ +,),$}
相关文档
最新文档