没有合适的资源?快使用搜索试试~ 我知道了~
首页编译原理的词法分析器实验 及程序
资源详情
资源评论
资源推荐

语法分析器的设计
(说明)
一. 要求:
建立一个针对 LL(1)文法编译器的自动生成器。要完成此编译器的生成器需
对源文件进行两遍处理:第一遍词法分析,第二遍语法分析。语法分析程序用
LL(1)语法分析方法。首先输入定义好的文法书写文件(所用的文法可以用 LL(1)
分析),然后建立词法分析器,包括词法分析主程序、扫描器部分、关键字表等。
经词法分析后分别计算所输入的文法的每个非终结符号的 FIRST 集合,每个非
终结符号的 FOLLOW 集合,以及每个规则的 SELECT 集合,并判断任意一个
非终结符号的任意两个规则的 SELECT 集的交集是不是都为空,如果是则输入
文法符合 LL(1)文法则可以进行分析。
二. 语法分析器实现
语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,
从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行词法检查,
为语义分析和代码生成作准备。这里采用自顶向下的 LL(1)分析方法。
语法分析程序的流程图如图 5-4 所示。
1.计算 FIRST 集
对于文法 G 的任意一个符号串=X
1
X
2
…X
n
可按下列步骤构造其 FIRST()集
合:
令 FIRST()=Æ,i=1;
(1) 若 X
i
V
T
,则 X
i
FIRST();
(2) 若 X
i
V
N
:
① 若 e FIRST(X
i
),则 FIRST(X
i
) FIRST();
② 若 eFIRST(X
i
),则 FIRST(X
i
)-{e} FIRST();
i=i+1;
重复(1)(2),直到(X
i
V
T
(i=2,3,…,n)或 X
i
V
N
且 e FIRST(X
i
)或 i>n 为止)。
(3)若对于一切 1≤i≤n,eFIRST(X
i
),则将 e 符号加进 FIRST()。
实例中求单个符号的 FIRST 集的算法描述如下:
void findSingleFIRST(int i){
开始
读入文法
有
效?
判断句型
报错
结束
语法分析程序流程图
是 LL(1) 文法?

参数 i 为符号在所有输入符号中的序号
X 等于指示器 i 所指向的符号
在保存终结符元素的 terSymbol[]数组查找 X
if X 为终结符(X∈V
T
),then
FIRST(X)={X}
在保存终结符元素的 non_ter[]数组查找 X
if X 是非终结符(X∈V
N
)
在所有产生式中查找 X 所在的产生式
if 产生式右部第一个字符为终结符或空 (即 X→a (a∈V
T
)或 X→ε)
then
把 a 或 ε 加进 FIRST(X)
if 产生式右部第一个字符为非终结符 then
if 产生式右部的第一个符号等于当前字符 then
跳到下一条产生式进行查找
求当前非终结符在所有字符集中的位置
if 当前非终结符还没求其 FIRST 集 then
查找它的 FIRST 集并标识此符号已求其 FIRST 集
求得结果并入到 X 的 FIRST 集.
if 当前产生式右部符号可推出空字且当前字符不是右部的最后一个字
符 then
获取右部符号下一个字符在所有字符集中的位置
if 此字符的 FIRST 集还未查找 then
找其 FIRST 集,并标其查找状态为 1
把求得的 FIRST 集并入到 X 的 FIRST 集.
if 当前右部符号串可推出空且是右部符号串的最后一个字符 (即产生式
为 X→Y
1
Y
2
…Y
k
,若对一切 1≤i≤k,均有 ε∈FIRST(Y
i
),则将 ε∈符号加
进 FIRST(X) ) then
把空字加入到当前字符 X 的 FIRST 集.
else
不能推出空字则结束循环
标识当前字符 X 已查找其 FIRST 集. }
2. 计算 FOLLOW 集
FOLLOW 集的构造可用如下方法来求:
对于文法中的符号 X V
N
,其 FOLLOW(A)集合可反复应用下列规则计算,
直到 FOLLOW(A)集合不再增大为止。
(1)对于文法开始符号 S,因为 SS,故#FOLLOW(S);
(2)若 A→B,其中 BV
N
,(V
T
V
N
)
*
、(V
T
V
N
)
+
,则
FIRST()-{e}FOLLOW(B);
(3)若 A→B 或 A→B ( e),则
FOLLOW(A) FOLLOW(B)。
FOLLOW 集的算法描述如下:
void FOLLOW(int i)
X 为待求的非终结符

把当前字符放到一临时数组 tempFOLLOW[]中,标识求已求其 FOLLOW
集.避免循环递归
if X 为开始符号 then #∈FOLLOW(X)
对全部的产生式找一个右部含有当前字符 X 的产生式
注:比如求 FOLLOW(B)则找 A→αX 或 A→X( ε)的产生式
if X 在产生式右部的最后(形如产生式 A→X) then
查找非终结符 A 是否已经求过其 FOLLOW 集.避免循环递归
if 非终结符 A 已求过其 FOLLOW 集 then
FOLLOW(A)∈FOLLOW(X)
继续查下一条产生式是否含有 X
else
求 A 之 FOLLOW 集,并标识为 A 已求其 FOLLOW 集
else if X 不在产生式右部的最后(形如 A→B) then
if 右部 X 后面的符号串能推出空字 then
查找是否已经求过其 FOLLOW 集.避免循环递归
if 已求过的 FOLLOW 集 then
FOLLOW(A)∈FOLLOW(B)
结束本次循环
else if 不能推出空字 then
求 FIRST()
把 FIRST()中所有非空元素加入到 FOLLOW(B)中
标识当前要求的非终结符 X 的 FOLLOW 集已求过
3.计算 SELECT 集
SELECT 集的构造算法如下:
对所有的规则产生式 A→x:
(1)若 x 不能推出空字 e,则 SELECT(A→x) = FIRST(x);
(2)若 x 可推出空字 e,则 SELECT(A→x)=FIRST(x)–{e} FOLLOW(A)。
算法描述如下:
for(i=0;i<=产生式总数-1;i++)
先把当前产生式右部的 FIRST 集(一切非空元素,不包括 ε)放入到当前产
生式的 SELECT(i);
if 产生式右部符号串可推出空字 e then
把 i 指向的当前产生式左部的非终结符号的 FOLLOW 集并入到
SELECT(i)中
4.判断是否 LL(1)文法
要判断是否为 LL(1)文法,需要输入的文法 G 有如下要求:
具有相同左部的规则的 SELECT 集两两不相交,即:
SELECT(A→)∩ SELECT(A→)= Æ
如果输入的文法都符合以上的要求,则该文法可以用 LL(1)方法分析。
算法描述如下:
把第一条产生式的 SELECT(0)集放到一个临时数组 temp[]中
for(i=1;i<=产生式总数-1;i++)

求 temp 的长度 length
if i 指向的当前产生式的左部等于上一条产生式的左部 then
把 SELECT(i)并入到 temp 数组中
If temp 的长度小于 length 加上 SELECT (i)的长度
返回 0
else
把 temp 清空
把 SELECT (i)存放到 temp 中
结果返回 1;
源码
/***************************************************
LL(1)parsing grammar
25/4/2007
***************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <windows.h>
using namespace std;
/**************************************************/
//用于指向输入输出文件的指针
FILE *inparse,*outparse,*inscan;
//用于接收输入输出文件名
char inparsefile[300],outparsefile[300],inscanfile[300];
/**************************************************/
/***************定义产生式的语法集结构*************/
typedef struct
{
char formula[200]; //产生式
}grammarElement;
grammarElement gramOldSet[200];//原始文法的产生式集
grammarElement gramNewSet[200];//消除左递归后文法的产生式集
/*********************变量定义*********************/
int grammarNum=0; //原始的产生式数目
int Pcount=0; //分解的产生式的个数
char startSymbol; //开始符号

char terSymbol[200]; //终结符号
char non_ter[200]; //非终结符号
char allSymbol[400]; //所有符号
char leftStr[200]; //消除左递归后产生式左部(不包括"->")
char rightStr[200][200]; //消除左递归后产生式右部(不包括"->")
/***************************************************/
char firstSET[100][100];//各产生式右部的 FIRST 集合
char followSET[100][100]; //各产生式左部的 FOLLOW 集合
char singleFIRST[100][100]; //所有单个符号的 FIRST 集合,函数 findSingleFIRST(i)用到
char selectSET[100][100]; //各单个产生式的 SELECT 集合
char tempFOLLOW[100]; //求 FOLLOW 集合时使用
char FirstForFollow[100]; //求 FOLLOW 时存放某一符号串的 FIRST 集合
char firsted[100]; //记录各符号的 FIRST 是否已求过,0 和 1 表示其状态
char followed[100]; //记录各符号的 FOLLOW 是否已求过,0 和 1 表示其状态
char epsilon[100]; //记录可直接推出@("ε")的符号
char tempEpsilon[100]; //求 someDerivateEpsilon()时使用,标识此字符已查找其是否可推
出空字
/***************************************************/
int validity=1; //表示输入文法是否有效
int isLL1=1; //表示输入文法是否为 LL(1)文法
int M[200][200]; //分析表
char choice; //用户输入时使用
/***************************************************
设置彩色文字
***************************************************/
void setcolor(unsigned short ForeColor=4,unsigned short BackGroundColor=0)
{
HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hCon,ForeColor|BackGroundColor);
}
/**************************************************
查找字符是否在指定字符串中
**************************************************/
bool FindChar(char ch,char *p)
{
int i;
if(strlen(p)==0)
return false;
for(i=0;i<(int)strlen(p);i++)
{
//若存在,返回真
if(p[i]==ch)
return true;
}
剩余33页未读,继续阅读














安全验证
文档复制为VIP权益,开通VIP直接复制

评论1