安徽大学编译原理实验

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

则 SectionFirst(X1…Xj…Xn)=First(X1) 若 X1…Xn 全可推出ε 则 SectionFirst(X1…Xn)=FIRST(X1)∪…∪FIRST(Xn)∪{ε} 5.重复 4 直到每个符号的 FIRST 集合都不再增大为止。 Ⅱ、利用求出每个文法符号的 FIRST 集求符号串的 FIRST 集 设α=X1X2…Xn 1. 当 X1 ε,则 FIRST(α)=FIRST(X1)
编译原理实验报告
实验名称:
院系: 专业: 年级: 姓名: 学号:
实验 4 LL(1)文法分析
计算机学院 科技专业 11 级 XXX E01114xxx
实验 4 LL(1)文法判别
实验名称:
LL(1)文法的判别
实验要求:
输入一个文法 G[S],判别其是否为 LL(1)文法。 输入任意文法 消除左递归 消除左因子 测试任意输入语句是否合法 数据结构描述 算法说明 输出 first 集合输出 follow 集合输出 LL(1)表
Follow(B)=Follow(B)∪(First(y)-{ε})∪Follow(A) ☞ 若 a∈FOLLOW(A) ,则表明 S=>*…Aa…,由于 A→xBy,且 y=>*ε,则有 S=>*…Aa…=>…xBya=>…xBa…,即 S=>*…xBa…,所以 a∈FOLLOW(B) 3. 重复 2,直至对所有 AVN,Follow(A)不再扩大为止。 ☞ FOLLOW 集合中不能有ε ◆关系图法 ① 文法 G 中的每个符号和“#”对应图中的一个结点,对应 VT 和“#”的结 点用符号本身标记。对应 VN 的结点,则用 FOLLOW(VN)或 FIRST(VN)标记 ② 从结点 FOLLOW(S)到“#”号结点连一条箭弧 ③ 如果文法中有产生式 A→αBβVN,且β FIRST(VN)连一条箭弧
char c() { char c='A'; while(in(c,non_ter)==1) c++;
return(c); }//得到一个不是非终结符的符号
void recur(char *point)// 分解含有左递归的产生式 { int j,m=0,n=3,k; char temp[20],ch; ch=c(); k=strlen(non_ter); non_ter[k]=ch; non_ter[k+1]='\0'; for(j=0;j<=strlen(point)-1;j++) { if(point[n]==point[0]) { /*如果‘|’后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++) { while(point[j]!='|'&&point[j]!='\0') temp[m++]=point[j++]; left[count]=ch; memcpy(right[count],temp,m); right[count][m]=ch; right[count][m+1]='\0'; m=0; count++; if(point[j]=='|') { n=j+1; /*得到一个非终结符*/ /*完整的产生式在 point[]中*/
实验目Байду номын сангаас:
设计、编制、调试一个具体的 LL(1)语法分析程序,加深对语法分析原理的理解。 1.掌握 LL(1)分析法的基本原理 2.掌握 LL(1)分析表的构造方法 3.掌握 LL(1)驱动程序的构造方法 4.加深对预测分析 LL(1)分析法的理解。
实验原理:
1. LL(1)文法定义
一个上下文无关文法 G 是 LL(1)文法, 当且仅当对 G 中每个非终结符 A 的 任何两个不同的规则 A→α|β,满足 SELECT(A→α)∩SELECT(A→β) = Φ 其中α、β中至多只有一个能推出ε串。 ◆含义: 第一个 L 表示从左到右扫描输入串
3.对每个 AVN,若有产生式 A→a…,a∈VT,则 First(A)={a} 4.对每个产生式 A→X1…Xj…Xn 做: First(A)=First(A)SectionFirst(X1…Xj…Xn) 其中: SectionFirst(X1…Xj…Xn) = (First(X1)-{ε}) (First(X2)-{ε})… -{ε}) First(Xj+1) Xj+1 是产生式右部中第一个不能推出ε的符号 若 X1 ε (First(Xj)
char empty[20]; char TEMP[50]; int validity=1; int ll=1; int M[20][20]; char choose; char empt[20]; char fo[20];
/*记录可直接推出^的符号*/ /*求 FOLLOW 时存放某一符号串的 FIRST 集合*/ /*表示输入文法是否有效*/ /*表示输入文法是否为 LL(1)文法*/ /*分析表*/ /*用户输入时使用*/ /*求_emp()时使用*/ /*求 FOLLOW 集合时使用*/
4
ε,则从结点 FOLLOW(B)到结点
如果文法中有产生式 A→αBβVT,且β
ε,则从结 FOLLOW(B)到结点 VT
连一条箭弧
5 6 7 8 9
如果文法中有产生式 A→αBβ,且β
ε,则从
结点 FOLLOW(B)到结点 FOLLOW(A)连一条箭弧 对每一 FIRST(A)结点如果有产生式 A→αXβ,且 α ε, 则从结点 FIRST(A)到结点 FIRST(X)连一条箭弧
附录: #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]; /*分解的产生式的个数*/ /*所有终结符和非终结符的总数*/ /*开始符号*/ /*终结符号*/ /*非终结符号*/ /*所有符号*/ /*左部*/ /*右部*/ /*各产生式右部的 FIRST 和左
5. 计算每个非终结符 A 的 FOLLOW(A)集 ◆定义法 1.对所有 AVN 令 Follow(A)={ };对开始符 S,令 Follow(S)={#} 2. 对每条产生式 A→xBy,考察产生式右部的每一非终结符 B,x,y∈V*, 如果 y 不能推出ε Follow(B)=Follow(B)∪First(y) 否则
凡是从结点 FOLLOW(A)有路径可以到达的终结符或“#”号结点, 其所标记
的终结符或"#"号即为 FOLLOW(A)的成员
6.计算每个产生式 A→α的 SELECT(A→α)集 按定义计算 SELECT(A→α): • • 若α \* 若α * ε,则 SELECT(A→α)=FIRST(α)
ε,则 SELECT(A→α)=(FIRST(α)-{ε})∪FOLLOW(A)
3. 算法
◆初始化 置数组 X[ ]中对应每一非终结符的标记为初值 “未定”; ◆扫描文法中的产生式 ①删除右部含有终结符的产生式,假使以某一非终结符为左部的所有产 生式都被删除,并将数组中对应该非终结符的标记值改为“否”,说明该非 终结符不能推出ε; ②删除右部仅为ε的产生式,则将数组中对应该非终结符的标志置为 “是”,说明该非终结符能推出ε; ☞ 本次扫描后仅剩下产生式左右均为非终结符的产生式 ◆扫描产生式右部的每一符号 ①若所扫描到的非终结符号在数组中对应的标志为“是”, 则删去该非终 结符,若这使产生式右部为空,则对产生式左部的非终结符在数组中对应的 标志改“是”,并删除该非终结符为左部的所有产生式 ②若所扫描到的非终结符号在数组中对应的标志为“否”, 则删去该产生 式,若这使产生式左部非终结符的有关产生式都被删去,则把在数组中该非
2. 若对任何 j(1≤j<n)都有ε∈FIRST(Xj),且 Xj+1 不能导出空串,则 FIRST(α)=(FIRST(X1)-{ε})∪…∪(FIRST(Xj)-{ε}) ∪FIRST(Xj+1) 3. 若对所有 i(1≤i≤n),都有ε∈FIRST(Xi), 则 FIRST(α)=FIRST(X1)∪…∪FIRST(Xn)∪{ε}
char first[50][50],follow[50][50]; 部的 FOLLOW 集合*/ char first1[50][50]; char select[50][50]; char f[50],F[50];
/*所有单个符号的 FIRST 集合*/ /*各单个产生式的 SELECT 集合*/ /*记录各符号的 FIRST 和 FOLLOW 是否已求过*/
终结符对应的标志改成“否” ◆重复(3) 直到扫描完毕数组中非终结符对应的特征再没有改变为止。
4. 计算每个产生式右部α的 FIRST(α)集 ◆定义法 Ⅰ、首先对每一文法符号 X(XVTVN),求 FIRST(A)的算法: 1.对每个 aVT,First(a)={ a } 2.对每个 AVN,若 A ε,则 First(A)={ε}
int in(char c,char *p){ int i; if(strlen(p)==0) return(0); for(i=0;;i++) { if(p[i]==c) return(1); if(i==strlen(p)) return(0); } }//判断一个字符是否在指定字符串中 /*若不在,返回 0*/ /*若在,返回 1*/
count++; m=0; } } }
void non_re(char *point)// 分解不含有左递归的产生式 { int m=0,j; char temp[20]; for(j=3;j<=strlen(point)-1;j++) { if(point[j]!='|') temp[m++]=point[j]; else { left[count]=point[0]; memcpy(right[count],temp,m); right[count][m]='\0'; m=0; count++; } } left[count]=point[0]; memcpy(right[count],temp,m); right[count][m]='\0';
◆关系图法 ①每个文法符号对应图中一个结点,对应 VT 的结点时用符号本身标记,对应 VN 的结点用 FIRST(A)标记。这里 A 表示 VN ②如果文法中有产生式 A→VT,则从结点 FIRST(A)到结点 VT 连一条箭弧 ③如果文法中有产生式 A→αVNβ,且α FIRST(VN)连一条箭弧 ④凡是从 FIRST(A)结点有路径可到达的 VT 结点所标记的 VT 都为 FIRST(A)的 成员 由判别步骤 1 确定ε是否为某 VN 的 FIRST 集的成员,若是则将ε加入该 VN 的 FIRST 集中 ε,则从结点 FIRST(A)到结点
break; } } } else { left[count]=ch; right[count][0]='^'; right[count][1]='\0'; count++; for(j=n;j<=strlen(point)-1;j++) { if(point[j]!='|') temp[m++]=point[j]; else { left[count]=point[0]; memcpy(right[count],temp,m); right[count][m]=ch; right[count][m+1]='\0'; // printf(" count=%d ",count); m=0; count++; } } left[count]=point[0]; memcpy(right[count],temp,m); right[count][m]=ch; right[count][m+1]='\0'; /*如果‘|’后的首符号和左部不同*/
第二个 L 表示自上而下进行最左推导 1 表明只需向前看一个符号便可以决定选哪条产生式进行推导, 类似地 LL(k)文法需要向前看 k 个符号才可以确定选用哪个产生式。
2. LL(1)文法的判别
◆ 五步判别法 求能推出ε的非终结符集 计算每个产生式右部α的 FIRST(α)集 计算每个非终结符 A 的 FOLLOW(A)集 计算每个产生式 A→α的 SELECT(A→α)集 按 LL(1)文法的定义判别 ☞ 假定所给文法是经过压缩的(不包含多余规则)
相关文档
最新文档