1、语法分析器编译原理课程实验报告课程实验题目: 语法分析器 学 院: 计算机科学与技术 班 级: 软件工程1101班 学 号: 04113026 姓 名: 刘 宇 指导教师姓名: 陈 燕 完 成 时 间 : 2014年5月14日 1、实验目的 设计一个语法分析器,并更好的理解语法分析实现原理,掌握语法分析的方法(预测分析法、算符优先法)。2、实验要求 算符优先分析法基本要求:1) 任意输入一个文法G;2) 判断该文法是否为算符文法;3) 对文法中的每个非终结符自动生成并打印输出: FIRSTVT集; LASTVT集;4) 判断该文法是否为算符优先文法,5) 如果是自动生成并打印输出其算符优先矩阵
2、;6) 模拟分析过程:如输入一个句子,如果该句子合法则输出与句子对应的语法树;能够输出分析过程中每一步符号栈的变化情况以及根据当前最左素短语进行归约的过程。如果该句子非法则进行相应的报错处理。3、实验内容 算符优先分析法1) 文法通过读取相应的文件获取;2) 用大写字母和小写字母分别表示非终结符和终结符;3) 产生式使用-;4) 文法中的空字符串统一使用表示;5) 打印每一个非终结符的FIRSTVT集和LASTVT集和算符优先关系表;6) 判定给定的文法是否是算符优先文法;7) 对任意句子使用当前文法归约,打印分析过程。 4、采用的数据结构 两个结构体:/分析各非终结符的FIRSTVT集和LA
3、STVT集时的栈元素typedef struct char nonterm; /非终结符 char term; /终结符StackElement;/存放(A,a)的栈的初始化typedef struct StackElement *top; /栈顶 StackElement *bottom; /栈底 int stacksize; /个数stack;5、算法描述 算符优先分析法的具体过程如下:1) 按照实现定义的文件路径,使用ReadFile()函数中,将需要分析的文法通过输入流文件打开函数open()复制到senrowcol中。2) 利用FirstVt( )构造产生式senrowcol的非终结
4、符的FirstVt表。先找出形如A-a(a为第一个终结符)的产生式,把(A,a)压入Operator栈中。从Operator栈顶抛出项(A,a),填入first表相应位置。在找出形如B-A的产生式,把(B,a)压入Operator栈中。循环直到Operator栈为空,此时FirstVt表构造完毕。3) 将产生式右部翻转,调用FirstVt函数求出LastVt表。4) 调用OpPriotable()构造算符优先关系表opTable。先把产生式中所有终结符填入opTable表第一行和第一列,然后利用产生式和FirstVt表LastVt表分别找出满足=关系、关系的算符填表。若相应位已有关系,说明两个
5、终结符之间至少有两种优先关系,该文法不是算符优先文法。5) 调用InputAnalyse()对输入句子进行分析。初始化分析栈S,依次判断当前输入符a和分析栈中离栈顶最近的终结符S j 的关系,若S j a ,则a移近,若S j a,将S j -1到栈顶S k 规约,若S j = a ,如果S j =#,则接受,如果S j !=#,则移进。直到接受或者出错,算符优先分析结束。6、运行结果1. 非算符优先文法的文法分析结果:2. 是算符优先文法的文法分析结果:成功归约句子:归约句子失败:7、调试情况如下所示为测试的文法:其中文法不是算符优先文法,文法是算符优先文法。8、设计技巧及体会将算符优先法的
6、手工分析过程用程序的方式写出来,实现了算符优先法的判断过程,很容易理解。通过本次实验,我对算符优先法的分析过程更加熟练了,同时让我对本章内容有了更深入的理解。9、源程序清单(电子版)#include#include using namespace std;#define row 20#define col 20#define SIZE 20/两个重要结构体的定义/FIRSTVT表或LASTVT表中一个表项(A,a)结构体的初始化typedef struct char nonterm; /非终结符 char term; /终结符StackElement;/存放(A,a)的栈的初始化typedef
7、 struct StackElement *top; /栈顶 StackElement *bottom; /栈底 int stacksize; /个数stack;/读文件函数int ReadFile(char sencol) ifstream fin; int i = 0; fin.open(e:/in2.txt,ios:in); cout 文法的产生式为: sen0; for (i = 1; !fin.eof(); i+) fin seni; cout seni = S.stacksize) cout 栈已满,无法插入! nonterm = e.nonterm; S.top-term = e
8、.term; S.top+; /弹出栈顶(A,a)元素StackElement Pop(stack &S) StackElement e; e.nonterm = 0; e.term = 0; if (S.top = S.bottom) cout 栈为空,无法进行删除操作! nonterm; e.term = S.top-term; return e;/终结符与非终结符的判断函数(布尔类型)bool TerminalJud(char c) if (c = A & c = Z) return false; /非终结符返回false return true; /终结符返回true/判断非终结符在f
9、irst表中是否已存在bool ItemJud(char firstcol, int first_len, char C) for (int i = 0; i first_len; i+) if (firsti0 = C) return true; /如果first表中已存在此非终结符c,则返回true return false;/FIRSTVT表和LASTVT表中表项的初始化void ItemInit(char sencol, char firstcol, char lastcol, int sen_len, int &first_len) int i; first_len = 1; /是当
10、前first和last表的长度 / 初始化表 first00 = sen00; last00 = sen00; for (i = 1; i sen_len; i+) if (TerminalJud(seni0) = false & ItemJud(first, first_len, seni0) = false) firstfirst_len0=seni0; lastfirst_len0=seni0; first_len+; /构造FIRSTVT集void FirstVt(char sencol, char firstcol, int sen_len, int first_len) /sen_
11、len是产生式的个数 StackElement DFS, recordSIZE; stack Operator; /创建存放(A,a)的栈 int i,j,r=0; InitStack(Operator); /第一次扫描,将能直接得出的first(A,a)放进栈中 for (i = 0; i sen_len; i+) for (j = 3; senij != 0; j+) /候选式开始处 if (TerminalJud(senij) = true) /遇到的第一个终结符压入 int exist = 0; DFS.nonterm = seni0; DFS.term = senij; for (i
12、nt i1 = 0; i r; i+) /当前(A,a)是否已在栈中 if (recordi1.nonterm = seni0 & recordi1.term = senij) exist = 1; break; /如果不在则压入栈中 recordr.nonterm=seni0; recordr.term=senij; if (exist = 0) Insert(Operator,DFS); recordr.nonterm = seni0; recordr.term = senij; r+; break; /第二次扫描,考虑候选式第一个符号为非终结符的情况 int locationcol; /
13、记录first表中放入终结符的位置 for (i = 0; i first_len; i+) locationi = 1; while (!ifEmpty(Operator) int exist = 0; /标志位,记录即将入栈的元素是否已经存在 StackElement IDElement,DElement; DElement=Pop(Operator); /弹出栈顶元素 for (i = 0; i first_len; i+) if (firsti0 = DElement.nonterm) int n = locationi; firstin = DElement.term; /将终结符填
14、入相应的first表中 locationi+; break; for (j = 0; jsen_len; j+) if (senj3 = DElement.nonterm) /找出能推出当前非终结符的产生式的左部 IDElement.nonterm = senj0; IDElement.term = DElement.term; /判断将要放进栈里的元素曾经是否出现过,若没有,才压入栈 for (int r0 = 0; r0 r; r0+) /r记录record数组中的元素个数 if (recordr0.nonterm = IDElement.nonterm & recordr0.term =
15、 IDElement.term) /已存在在栈中 exist=1; break; if (exist = 0) /不存在则压入栈中 Insert(Operator,IDElement); recordr.nonterm = IDElement.nonterm; recordr.term = IDElement.term; r+; /构造LASTVT集void LastVt(char sencol, char lastcol, int sen_len, int first_len) /first_len表示last 表的行数 int i, j, i1, j1; char c, recordrow
16、col = 0; for (i = 0; i sen_len; i+) for(j = 0; senij != 0;j+) recordij = senij; j = j - 1; for (i1 = 3, j1 = j; i1 j1; i1+, j1-) /做翻转,就可以用求first的方法求last c = recordii1; recordii1 = recordij1; recordij1 = c; FirstVt(record, last, sen_len, first_len);/判断非终结符在term表中是否已存在bool TermTableJud(char termcol, i
17、nt term_len, char C) for(int i = 0; i term_len; i+) if (termi = C) return true; /如果first表中已存在此非终结符,则返回1 return false;/构造算符优先关系表bool OpPriotable(char sencol, char firstcol, char lastcol, char opTablecol, int sen_len, int first_len, int &opTable_len) int i, j, term_len=0; int i2, i3, opr, opc; char c1
18、, c2, c3; char termSIZE=0; for (i = 0; i sen_len; i+) /一维数组term记录关系表中存在的所有终结符 for (j = 3; senij !=0; j+) if (TerminalJud(senij) = true) if (TermTableJud(term, term_len, senij) = false) /term_len记录term表的长度 termterm_len = senij; term_len+; /得到终结符表 /给优先关系表赋初值,都等于空 for (i = 0; i term_len + 1; i+) for (j
19、 = 0; j term_len + 1; j+) opTableij = ; /设置优先关系表的表头,即将所有终结符存储 for (i = 1; i term_len + 1; i+) opTablei0 = termi - 1; opTable0i = termi - 1; /找等于关系 for (i = 0; i sen_len; i+) /形如 #E# 的情况 for (j = 5; senij != 0;j+) if (TerminalJud(senij - 2) = true & TerminalJud(senij - 1) = false & TerminalJud(senij)
20、 = true) c1=senij-2; c2=senij; /在opTable表中找到该存入的行标opr for (opr = 1; opr term_len + 1; opr+) if (opTableopr0 = c1) break; /在opTable表中找到该存入的列标opc for (opc = 1; opc term_len + 1; opc+) if(opTable0opc = c2) break; /若这两者优先级关系之前已定义了,则表示该文法非算符优先 if (opTableopropc != ) cout 不是算符优先文法! endl; return false; els
21、e opTableopropc = =; /形如 () 的情况 for (j = 4; senij != 0; j+) if (TerminalJud(senij - 1) = true & TerminalJud(senij) = true) c1 = senij - 1; c2 = senij; /在opTable表中找到该存入的行标opr for (opr = 1; opr term_len + 1; opr+) if (opTableopr0 = c1) break; /在opTable表中找到该存入的列标j2 for (opc = 1; opc term_len + 1; opc+)
22、 if (opTable0opc = c2) break; if (opTableopropc != ) cout 不是算符优先文法! endl; return false; else opTableopropc = =; /找小于关系 for (i = 0; i sen_len; i+) /形如 aA 情况 for (j = 3; senij != 0;j+) if (TerminalJud(senij) = true & TerminalJud(senij+1) = false) c1 = senij; /c1记录终结符 c2 = senij+1; /c2记录非终结符 /在opTable表
23、中找到该存入的行标opr for (opr = 1; opr term_len + 1; opr+) if (opTableopr0 = c1) break; /找出非终结符在first表中的列标opc for (opc = 0; opc first_len; opc+) if (firstopc0 = c2) break; for (i2 = 1; firstopci2 != 0; i2+) c3 = firstopci2; for (i3 = 1; i3 term_len + 1; i3+) if (opTable0i3 = c3) if (opTableopri3 != ) cout 不
24、是算符优先文法! endl; return false; else opTableopri3 = ; break; /找大于关系 for (i = 0; i sen_len; i+) /形如Aa情况 for (j = 3; senij != 0; j+) if (TerminalJud(senij) = false & senij + 1 != 0 & TerminalJud(senij + 1) = true) c1 = senij; /c1记录非终结符 c2 = senij + 1; /c2记录终结符 /在opTable表中找到该存入的列标j1 for (opr = 1; opr term_len + 1; opr+) if (opTable0opr = c2)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1