编译原理课程设计LL1文法.docx
- 文档编号:25125961
- 上传时间:2023-06-05
- 格式:DOCX
- 页数:15
- 大小:72.63KB
编译原理课程设计LL1文法.docx
《编译原理课程设计LL1文法.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计LL1文法.docx(15页珍藏版)》请在冰豆网上搜索。
编译原理课程设计LL1文法
LL
(1)文法分析及程序设计
1.设计目的
通过设计、编制、调试LL
(1)语法分析程序,加深对LL
(1)语法分析原理的理解。
2.设计要求
(1)写出符合LL
(1)分析方法要求的文法,给出分析的算法思想、步骤、程序结构以及最终完成语法分析程序设计。
(2)编制完成分析程序后,选取几个例子,上机测试并通过所设计的分析程序。
3.设计方案
用LL
(1)分析法判别给定文法是否为LL
(1)文法,提供其分析过程与结果,最终根据结果设计算法分析程序,对输入的符号串进行分析。
4.设计内容
4.1设计基本思想
设计一个LL
(1)文法分析器,构造出预测分析表,通过预测分析表,判别用户输入的字符串是否符合LL
(1)文法。
并给出分析过程与结果。
4.2LL
(1)文法的基本原理与算法
一个上下无关的文法是LL
(1)文法的充要条件时,对每个非终结符A的两个不同产生式,A->α,A->β满足
SELECT(A->α)∩SELECT(A->β)=φ,其中α和β不同时推出ξ。
如果某个文法满足上述条件,称该文法为LL
(1)文法。
LL
(1)分析法是一种采用确定的自顶向下的语法分析技术,其含义是:
第一个L表明自顶向下分析是从左向右扫描输入串,第二个L表明分析过程中将用最左推导,1表明只需向右看一个符号便可以决定如何推导,即便选择哪个产生式规则进行推导。
4.3LL
(1)判别分析步骤
4.3.1求出能推出ξ的非终结符
(1)将数组X[]中对应的每一个非终结符的标记为“未定”。
(2)扫描文法中的产生式。
1.删除所有右部含有终结符的产生式。
若使得以某一非终结符为左部的所有产生式都被删除,则将数组中对应的非终结符的标记值改为“否”,说明该终结符不能推出ξ。
2.若某一非终结符的某一个产生式右部为ξ,则将数组中对应该非终结符的标志置为“是”,并从文法中删除该非终结符的所有产生式。
(3)扫描产生式右部的每一个符号。
1.若所扫描到的非终结符号在数组中对应的标志是“是”,则删去该非终结符,若使得产生式右部为空,则对产生式右部的非终结符在数组中对应的标志改为“是”,并删除该非终结符为左部的所有的产生式。
2.若所扫描到的非终结符号在数组中对应的标志是“是”,则删除该产生式。
若这使得产生式左部非终结符的有关产生式都被删除,则把在数组中该非终结符对应的标志改为“否”。
(4)重复(3),直到扫描完一遍文法的产生式,数组中的非终结符对应的特征再没有改变为止。
4.3.2求FIRST集合
1)A->aα则a∈first(A)
2)A->Bα则first(B)∈first(A)
3)A->^则^∈first(A)
4.3.3计算FOLLOW集合
1)A->αBaβ则a∈follow(B)
2)A->αBCβ则first(C)∈follow(B)
3)A->αB则follow(A)∈follow(B)
3)由产生式形成
(1)
(2)(3)
A->αBDaβ,D->^,则a∈follow(B),a∈follow(D)
4.3.4计算SELECT集
4.4数据结构
数组A实现分析栈,数组B存储剩余分析串;一维数组V1存放文法终结符,一维数组V2存放文法非终结符。
将产生式类型定义为结构体变量。
4.5算法描述
1.首先将#压入堆栈中,将开始符号S也压入堆栈中,读取第一个输入符号到a。
循环执行2~4:
2.栈顶符号弹出放入X中,如果X为终结符号:
当X==a!
=#时,表明成功匹配a符号,然后读取下一个符号到a,否则出错;当X==a=#时,分析结束,接受句子,跳出循环.
3.如果X!
=a,进行出错处理.
4.如果X为非终结符号,则查分析表M:
如果M[X,a]为空,进行出错处理;如果M[X,a]=X1X2X3...Xn,则将右部Xn...X2X1反序压入堆栈中.
4.6对给定文法进行LL
(1)分析的过程
给定文法:
E->TG
G->+TG|^
T->FS
S->*FS|^
F->i|(E)
对上述文法进行分析判断:
4.6.1求各非终结符的FIRST集
FIRST(E)=FIRST(T)=FIRST(F)={(,i}
FIRST(G)={+,^}
FIRST(T)={(,i}
FIRST(S)={*,^}
FIRST(F)={(,i}
4.6.2求各非终结符的FOLLOW集
FOLLOW(E)={),#}
FOLLOW(G)=FOLLOW(E)={),#}
FOLLOW(T)=FIRST(G)∪FOLLOW(E)={+,),#}
FOLLOW(S)=FOLLOW(T)={+,),#}
FOLLOW(F)=FIRST(S)∪FOLLOW(E)∪FOLLOW(T)={*,+,),#}
4.6.3求各个产生式的SELECT集
SELECT(E->TG)={(,i}
SELECT(G->+TG)={+}
SELECT(G->^)={#,)}
SELECT(T->FS)={(,i}
SELECT(S->*FS)={*}
SELECT(S->^)={+,},#}
SELECT(F->(E))={(}
SELECT(F->i)={i}
4.6.4构造预测分析表
由以上步骤可知,该文法是LL
(1)文法。
对其建立预测分析表。
对于每个终结符或#,用a表示。
若a∈SELECT(A->α),则把A->α放入M[A,a]中。
把所有无定义的M[A,a]标上出错标记。
预测分析表如下:
i
+
*
(
)
#
E
->TG
->TG
G
->+TG
->^
->^
T
->FS
->FS
S
->^
->*FS
->^
->^
F
->i
->(E)
4.7程序函数流程图
输出分析栈:
输出剩余串:
主函数:
4.8程序测试结果
4.8.1当输入的字符串错误时:
4.8.2对输入字符串进行分析:
1)输入i+i*i#得到分析结果如下
2)如果不适合LL
(1)文法,则显示输入错误。
例如输入i++i*i#,分析结果如下:
4.9源代码
#include
#include
#include
#include
charA[20];/*分析栈*/
charB[20];/*剩余串*/
charv1[20]={'i','+','*','(',')','-','/','#'};/*终结符*/
charv2[20]={'E','G','T','S','F'};/*非终结符*/
intj=0,b=0,top=0,l;/*l为输入串长度*/
typedefstructtype/*产生式类型定义*/
{
charorigin;/*大写字符*/
chararray[5];/*产生式右边字符*/
intlength;/*字符个数*/
}type;
typee,t,g,g1,s,s1,f,f1;/*结构体变量*/
typeC[10][10];/*预测分析表*/
voidprint()/*输出分析栈*/
{
inta;
for(a=0;a<=top+1;a++)
printf("%c",A[a]);
printf("\t\t");
}
voidprint1()/*输出剩余串*/
{
intj;
for(j=0;j
printf("");
for(j=b;j<=l;j++)
printf("%c",B[j]);
printf("\t\t\t");
}
voidmain()
{
intm,n,k=0,flag=0,finish=0;
charch,x;
typecha;/*用来接受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';
g1.array[0]='^';
g1.length=1;
s.origin='S';
strcpy(s.array,"*FS");
s.length=3;
s1.origin='S';
s1.array[0]='^';
s1.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<=7;n++)
C[m][n].origin='N';/*全部赋为空*/
C[0][0]=e;C[0][3]=e;/*填充分析表*/
C[1][1]=g;C[1][4]=g1;C[1][7]=g1;
C[2][0]=t;C[2][3]=t;
C[3][1]=s1;C[3][2]=s;C[3][4]=C[3][5]=C[3][7]=s1;
C[4][0]=f1;C[4][3]=f;
printf("请输入要分析的字符串:
");
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("接受!
\n");
getchar();
getchar();
exit
(1);
}
if(x==ch)
{
print();
print1();
printf("%c匹配\n",ch);
ch=B[++b];/*下一个输入字符*/
flag=0;/*恢复标记*/
}
else/*出错处理*/
{
print();
print1();
printf("%c出错\n",ch);/*输出出错终结符*/
exit
(1);
}
}
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 printf("%c",cha.array[j]); printf("\n"); for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/ A[++top]=cha.array[j]; if(A[top]=='^')/*为空则不进栈*/ top--; } else/*出错处理*/ { print(); print1(); printf("%c出错\n",x);/*输出出错非终结符*/ exit (1); } } }while(finish==0); } 5.总结 通过这次的课程设计,我比原来更加了解了LL (1)文法的分析过程及实现方法,学会设计、编制、调试语法及语义分析程序,加深了对语法及语义分析原理的理解。 在课程设计前,我想过很多种实现LL (1)文法的办法,最完美的一种就是通过输入表达式,进行判定分析是否属于LL (1)文法,从而要进行First集、Follow集和SELECT集的计算分析,由于时间和水平的有限,最终只能选取最终一步,就是对输入符号串的分析,前提是必须事先人工分析完成LL (1)文法,我觉得这是一个不完美的地方。 对这次课程设计给我的感觉是,进行文法分析的过程还是很有趣的,不过也觉得蛮深奥的,不容易弄明白的地方也有很多。 有机会的话还是希望自己能在以后的学习中不断学习了解,争取有更好的进步。 6.参考文献 [1]杨德芳等.编译原理实用教程.北京: 中国水利水电出版社,2008
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 课程设计 LL1 文法
![提示](https://static.bdocx.com/images/bang_tan.gif)