实验三算符优先分析算法设计与实现
算符优先语法分析设计原理与实现技术实验报告

算符优先语法分析设计原理与实现技术实验报告变更说明一、实验目的:本实验的目的在于在教师的引导下以问题回朔与思维启发的方式,使学生在不断的探究过程中掌握编译程序设计和构造的基本原理和实现技术,启迪学生的抽象思维、激发学生的学习兴趣、培养学生的探究精神和专业素养,从而提高学生发现问题、分析问题和解决问题的能力。
二、实验内容:[实验项目]实现算符优先分析算法,完成以下描述算术表达式的算符优先文法的算符优先分析过程。
G[E]:E→E+T∣E-T∣TT→T*F∣T/F∣FF→(E)∣i[实验说明]终结符号i 为用户定义的简单变量,即标识符的定义。
[设计要求](1)输入串应是词法分析的输出二元式序列,即某算术表达式“实验项目一”的输出结果。
输出为输入串是否为该文法定义的算术表达式的判断结果;(2)算符优先分析过程应能发现输入串出错;(3)设计两个测试用例(尽可能完备,正确和出错),并给出测试结果。
三、实验环境:操作系统:Windows 7软件:VC++6.0四、程序功能描述:●提供了文件输入方式,且输入的内容为二元式序列;●能够对输入的字符串做出正确的算符优先分析判断,并给出判断结果,判断结果输出到文件,并显示在屏幕;●能发现输入串中的错误,包含非法字符,输入不匹配等;●能够处理一些可预见性的错误,如文件不存在,输入非法等。
五、数据结构设计:六、程序结构描述:●设计方法:本程序采用从文件读取的输入方式,输入的内容需为二元式序列,然后按照算符优先分析的方法对输入的字符串进行分析判断,分析完成后输出判断结果到文件,并在屏幕显示。
程序通过对输入串的检查能够发现输入串中的错误。
程序规定的单词符号及其种别码见下表:算符优先矩阵+ - * / ( ) i #+ > > < < < > < >- > > < < < > < >* > > > > < > < >/ > > > > < > < >( < < < < < = < >) > > > > > >i > > > > > ># < < < < < < < =●算符优先分析法简介基本思路是根据既定的规则构建算符优先矩阵,然后根据算符之间的优先关系寻找输入串中的最左素短语,若找到,则寻找与最左素短语匹配的产生式进行规约;否则进行移进操作,及输入的算符进分析栈。
算符优先实验报告

算符优先实验报告《算符优先实验报告》引言算符优先是一种用于解决算术表达式中运算符优先级的算法,它可以帮助我们在计算表达式时确定运算符的优先级,从而得到正确的计算结果。
本实验旨在通过编写算符优先算法的程序,来深入理解算符优先的原理和应用。
实验目的1. 了解算符优先算法的原理和应用。
2. 掌握算符优先算法的程序设计方法。
3. 实现一个能够正确解析算术表达式并计算结果的程序。
实验内容1. 算符优先算法的原理和应用算符优先算法是一种基于文法的算法,它通过分析运算符之间的优先级和结合性来确定表达式的计算顺序。
在算符优先算法中,每个运算符都有一个优先级,高优先级的运算符先进行计算,低优先级的运算符后进行计算。
此外,算符优先算法还要考虑到运算符的结合性,即左结合或右结合。
2. 算符优先算法的程序设计方法为了实现算符优先算法,我们需要首先定义运算符的优先级和结合性,然后编写程序来解析表达式并按照算符优先规则进行计算。
在程序设计中,我们可以使用栈来辅助进行运算符的优先级判断和计算顺序的确定。
3. 实现一个能够正确解析算术表达式并计算结果的程序在本实验中,我们将编写一个简单的算符优先算法程序,该程序能够正确解析算术表达式并按照算符优先规则进行计算,最终得到正确的计算结果。
实验结果通过本次实验,我们成功实现了一个能够正确解析算术表达式并计算结果的程序。
该程序能够正确地处理不同优先级和结合性的运算符,并得到正确的计算结果。
这表明算符优先算法是一种有效的算法,能够帮助我们正确地处理算术表达式中的运算符优先级问题。
结论通过本次实验,我们深入理解了算符优先算法的原理和应用,并掌握了算符优先算法的程序设计方法。
算符优先算法是一种重要的算法,它在计算表达式时能够帮助我们确定运算符的优先级,从而得到正确的计算结果。
在今后的学习和工作中,我们将继续深入研究算符优先算法,并将其应用到更多的实际问题中。
算符优先语法分析设计原理与实现技术实验报告及源代码北京交通大学

算符优先语法分析设计原理与实现技术XXX 1028XXX 计科1XXX 班功能描述能够有效识别以下算符优先文法E T E+T | E-TT T T*F | T/F | FF T (E) | i所描述算术表达式.主要数据结构描述程序结构描述设计方法2. 根据算符优先矩阵算数表达式的词法分析结果进行语法分析,分析算法为:数据结构:符号栈S ---存放所有读进的符号(计数i)K ---符号栈使用深度a ---工作单元R, Q ---变量分析算法:先找最左素短语的尾部(>)再找最左素短语的头部(<)以分析表达式i+i*i为例,详细过程如下:■算符优先关系矩阵例:舖入串i+i*i 的界苻优先分析过程(査界替优先关系矩体)1#N + N**<i■11# N + N*'■ 1#1#N + N J* N+<*># 接受# N + N#<+>## N结论:汁详iJt 文法的命法句子函数原型功能描述void in it()各种初始化操作,主要是建立符号与整 数、整数与行列号、整数与符号之间的映 射,也包括各全局变量的初始化void isVt(i nt )判断某整数所代表的符号是否是终结符##<i# i#<i>-l- #N#<+# N + +<i# N + i +<i>* # N+ N+<*分析栈优先关系号或’#'void comp(i nt a, int b) r比较两整数所代表的字符的优先关系—void adva nce() 从输入文件中读入一个词bool parser() 算符优先分析函数,根据算符优先矩阵进行语法分析int main (i nt argc, char *argv[]) 主函数,参数argv[1]代表输入文件函数调用关系程序执行图S(l)=#;i=l;k=Q;k~k+1: R=siiLrQ=SG); j=j-ij=j-i l| t=i 11i=讦丄;S(i)=R程序测试测试用例一:(a+b*c)+d+e+a*c/b 首先调用实验一的词法分析程序,得到如下分析结果:(19, '(')(12, 'a')(14, '+')(12, 'b')(16, '*')(12, 'c')(20, ')')(14, '+')(12, 'd')(14, '+')(12, 'e')(14, '+')(12, 'a')(16, '*')(12, 'c')(17, '/')(12, 'b')在以此分析结果作为本程序实验结果的输入,得到如下分析结果:taw Cf'v/indov^5\system32\cmd.exe该结果显示了详细的分析过程,且表明该表达式是一个符合该文法的表达式测试用例二:(a+b*c)+d*-a*c+(a+b同样调用实验--的词法分析程序,得到如下结果:(19, '(')(12, 'a')(14, '+')(12, 'b')(16, '*')(12, 'c')(20, ')')(14, '+') (12, 'd') (16, '*') (15, '-') (12, 'a') (16, '*') (12, 'c') (14, '+') (19, '(') (12, 'a') (14, '+') (12, 'b')以此分析结果作为本实验程序的输入,得到如下语法分析结果:实验结果表明,在分析过程中出现了错误,分析过程未完成,该样例是一个非法的表达式.学习总结按算符优先关系所确定的应被规约的子串恰好是当前举行的最左素短语.尽管算符优先分析也属于自底向上语法分析的范畴,但却不是严格的从左至右的规范分析,每步所得的句型自然也不是一个规范句型.采用上述策略进行算符优先分析时,尽管我们也指出了每一最左素短语应规约到的非终结符号,然而每次在查找最左素短语时,起主导作用的是终结符号间的优先关系,两终结符号之间究竟是哪个非终结符号无关宏旨.// operator_prior.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <stdio.h>#include <ctype.h>#include <map>#include <vector>#include <string>#define ID 12#define ADD 14#define SUB 15#define MUL 16#define DIV 17#define LP 19#define RP 20#define EOI 31#define SHARP 32#define EQ 0#define BT 1#define LT 2#define UD 3#define N_Base 1000 using namespace std;FILE *fp;int lookahead, yylineno;bool success;map<int, int> intToint; map<char, int> charToint; map<int, char> intTochar; string grammer[8] = {"E+T", "E-T", "T","T*F", "T/F", "F","(E)", n:n};int prior_matrix[9][9] = {{BT, BT, LT, LT, LT, BT, LT, BT},{BT, BT, LT, LT, LT, BT, LT, BT},{BT, BT, BT, BT, LT, BT, LT, BT},{BT, BT, BT, BT, LT, BT, LT, BT},{LT, LT, LT, LT, LT, EQ, LT, UD},{BT, BT, BT, BT, UD, BT, UD, BT},{BT, BT, BT, BT, UD, BT, UD, BT},{LT, LT, LT, LT, LT, UD, LT, EQ}};void init() {success = true;yylineno = 0;intToint[ADD] = 0; intToint[SUB] = 1;intToint[MUL] = 2; intToint[DIV] = 3;intToint[LP] = 4; intToint[RP] = 5;intToint[ID] = 6; intToint[SHARP] = 7;charToint['+'] = ADD; charToint['-'] = SUB;charToint['*'] = MUL; charToint['/'] = DIV;charToint['('] = LP; charToint[')'] = RP;charToint['i'] = ID;intTochar[ADD] = '+'; intTochar[SUB] = '-';intTochar[MUL] = '*'; intTochar[DIV] = '/';intTochar[LP] = '('; intTochar[RP] = ')';intTochar[ID] = 'i'; intTochar[SHARP] = '#';intTochar[N_Base] = 'N';}bool isVt(int a) {if (a >= N_Base) return false;else return true;}int comp(int a, int b) { int x = intToint[a];int y = intToint[b]; return prior_matrix[x][y]; }void advance() {if (fscanf(fp, "(%d", &lookahead) == EOF) { lookahead = SHARP;} else {char ch;do {ch = fgetc(fp);if (ch == '\n' || ch == EOF) break; } while (true);} yylineno++;}void parser() {int stack[100], top = 0;int i, j, k, ii, jj;stack[top++] = SHARP;advance();do {for (i = 0; i < top; i++) {printf("%c", intTochar[stack[i]]);}printf("\t%c\n", intTochar[lookahead]);for (i = top - 1; i >= 0; i--) { if (isVt(stack[i])) break;}int res = comp(stack[i], lookahead);if (res == LT || res == EQ) { stack[top++] = lookahead; advance();} else if (res == BT) {int temp = stack[i]; for (j = i - 1; j >= 0; j--) {if (isVt(stack[j])) {if (comp(stack[j], temp) == LT) {break;} else {temp = stack[j];}}}for (k = 0; k < 8; k++) {if ((int)grammer[k].length() == top - 1 - j) {ii = j + 1;jj = 0;do {if (grammer[k].at(jj) >= 'A' && grammer[k].at(jj) <= 'Z'){ if (isVt(stack[ii])) break;} else {if (charToint[grammer[k].at(jj)] != stack[ii]) break;}ii++;jj++;} while (ii < top && jj < (int)grammer[k].length());if (ii >= top) break;}}if (k >= 8) {success = false;return ;}top = j + 1;stack[top++] = N_Base;} else {success = false;return ;}if (stack[0] == SHARP && stack[1] == N_Base&& stack[2] == SHARP) { printf("#N#\n"); break;}} while (true);success = true;}int main(int argc, char *argv[]) {if (argc == 2) {fp = fopen(argv[1], "r");init();parser();if (success) printf("This is a legal expression."); else printf("Thisis a illegal expression.");} else {printf(" 参数错误!\n");}return 0;。
实验三_算符优先分析算法的设计与实现

实验三 算符优先分析算法的设计与实现(8学时)一、 实验目的根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。
通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。
二、 实验要求1、输入文法。
可以是如下算术表达式的文法(你可以根据需要适当改变):E→E+T|E-T|TT→T*F|T/F|FF→(E)|i2、对给定表达式进行分析,输出表达式正确与否的判断。
程序输入/输出示例:输入:1+2;输出:正确输入:(1+2)/3+4-(5+6/7);输出:正确输入:((1-2)/3+4输出:错误输入:1+2-3+(*4/5)输出:错误三、实验步骤1、参考数据结构char *VN=0,*VT=0;//非终结符和终结符数组char firstvt[N][N],lastvt[N][N],table[N][N];typedef struct //符号对(P,a){char Vn;char Vt;} VN_VT;typedef struct //栈{VN_VT *top;VN_VT *bollow;int size;}stack;2、根据文法求FIRSTVT集和LASTVT集给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。
算符描述如下:/*求 FirstVT 集的算法*/PROCEDURE insert(P,a);IF not F[P,a] thenbeginF[P,a] = true; //(P,a)进栈end;Procedure FirstVT;Beginfor 对每个非终结符 P和终结符 a doF[P,a] = falsefor 对每个形如 P a…或 P→Qa…的产生式 doInsert(P,a)while stack 非空begin栈顶项出栈,记为(Q,a)for 对每条形如 P→Q…的产生式 doinsert(P,a)end;end.同理,可构造计算LASTVT的算法。
算符优先分析器设计

算符优先分析器设计1实验目的(1)掌握算符优先分析法——一种自底向上的语法分析方法的思想。
(2)能识别算符优先分析法中的可规约串——最左素短语。
(3)领会算符优先关系表转换成优先函数的方法。
2实验内容和实验要求根据形式化算法,编制程序实现一个算符优先分析器,能对常见的算术表达式语句进行分析。
要求实现以下功能:1) 组织算术表达式的输入;2) 组织算符优先关系表或者优先函数的输入;3) 若输入的符号串是一个算术表达式语句,则输出一个分析树骨架(既每一步规约用到的最左素短语),否则输出一个错误信息。
3待分析的语法描述E->E+T|TT->T*F|FF->(E)| I4算法描述4.1算府分析法基本方法实现算法,转化成某种高级语言程序,实现一个算符优先分析器。
其中要用到分析栈和输入缓冲器,本实验采用的方法是一种自底向上的语法分析方法,所以是在词法分析的基础上进行的。
对于表达式结果的计算,要在算法中引入内部变量来保存结果,另外在分析过程中,除了移进、规约、接受、报错等动作外,还要引入计算的动作。
4.2实现方法(1)首先定义char precede(char a,char c),在这里规定算符(终结符之间)的优先规则,在分析文法的时候便于调用。
(2)再定义 isn(char c),判断是否为非终结符,返回值为1和0,用于循环调用。
(3)主函数,总控算法:1.定义栈堆Stack中的变量,以及控制指针(用于存发归约或者待形成最左素短语的符号串)。
2.用string工作单元存放当前输入的字符,归约成功的标志是当读入的输入字符是句子的结束符号#号时,即栈中只是剩下#T的时候(栈Stack中只剩下开始标志# 和终结符号T的时候)使用判断是否栈顶指针指向的是#,若不是,则继续顺序扫描子过程。
从输入符号串中依次读入字符到string中,调用char precede(char a,char c)中进行分析是否要归约,还是要移进输入符,再栈S中形成最左素短语。
算符优先_实验报告

一、实验目的1. 理解算符优先分析法的原理和过程。
2. 掌握算符优先分析法的实现方法。
3. 通过实验加深对自底向上语法分析方法的理解。
二、实验内容1. 算符优先分析法原理介绍算符优先分析法是一种自底向上的语法分析方法,它通过比较相邻算符的优先次序来识别句型中的句柄,进而执行归约。
该方法的核心是确立文法的终结符之间的优先关系。
2. 实验步骤(1)判断文法是否为OG文法:OG文法要求所有产生式右部至少有一个终结符。
(2)判断文法是否为OPG文法:计算FIRSTVT集、LASTVT集,并构建算符优先矩阵。
(3)对句子进行分析:根据分析表判断句子是否为文法的句子。
(4)实现程序:从文件和键盘读取输入,将结果输出到指定文件和屏幕,并具有一致性。
3. 实验数据(1)文法:g[e]:e->e+t|t(2)测试句子:12+t, t+12, 12+13t, 12+t13三、实验过程1. 判断文法是否为OG文法根据给定的文法,我们可以看到所有产生式右部至少有一个终结符,因此该文法为OG文法。
2. 判断文法是否为OPG文法,并构建算符优先矩阵(1)计算FIRSTVT集FIRSTVT(e) = {t}FIRSTVT(t) = {t}(2)计算LASTVT集LASTVT(e) = {t}LASTVT(t) = {t}(3)构建算符优先矩阵| + - ( ) t e $+ > - - - > > -- > - - - > > -> > > > > > >( > > > > > > >) - - - - - - -t - - - - - - -e - - - - - - -$ - - - - - - -3. 对句子进行分析(1)分析句子“12+t”根据分析表,我们可以得到以下分析过程:12+t -> 12+t -> 12+t -> t -> t(2)分析句子“t+12”根据分析表,我们可以得到以下分析过程:t+12 -> t+12 -> t+12 -> t+12 -> t+12 -> t -> t (3)分析句子“12+13t”根据分析表,我们可以得到以下分析过程:12+13t -> 12+13t -> 12+13t -> 12+13t -> 12+13t -> t -> t(4)分析句子“12+t13”根据分析表,我们可以得到以下分析过程:12+t13 -> 12+t13 -> 12+t13 -> 12+t13 -> 12+t13 -> t13 -> t13 -> t13 -> t -> t四、实验结果1. 测试句子“12+t”分析结果:正确2. 测试句子“t+12”分析结果:正确3. 测试句子“12+13t”分析结果:正确4. 测试句子“12+t13”分析结果:正确五、实验总结通过本次实验,我们深入了解了算符优先分析法的原理和实现方法。
算符优先实验报告

算符优先分析实验报告一、程序功能实现算符优先分析算法,完成以下描述算术表达式的算符优先文法的算符优先分析过程。
G[S]:S->#E#E->E+T|TT->T*F|FF->P^F | PP->(E)|i二、主要数据结构char VT[]定义符号表;struct type{char origin; char array[5]; int length;}定义产生式类型;table[][]定义优先关系矩阵。
三、程序结构int locate(char s[],char c) 辅助函数,在一个字符串中查找某特定字符;int Find(type G[],char s[],int m,int n) 查找与已搜索出的短语对应的产生式,返回该产生式的序号;void doScan()对输入串进行分析的主控函数;void print(char s[],int k,int tag,char str[],int i,char action[])输出分析过程的函数。
在find()和doScan()中调用locate()函数,在doScan()中调用find()和print()函数,在main()中调用doScan()函数。
流程图:Y成功四、程序测试测试句子:i+i*i结果:测试句子:(i+i)*i结果:五、实验总结本实验重点解决算符优先矩阵的构造和算符优先算法的实现,我认为难点是构造优先矩阵,这个就需要掌握方法多练习,优先算法只需将PPT上的流程图一步一步地转化为代码就可以了。
总体来说,本实验比较简单。
THANKS !!!致力为企业和个人提供合同协议,策划案计划书,学习课件等等打造全网一站式需求欢迎您的下载,资料仅供参考。
C.4-算符优先分析法-实验报告

学号
成绩
实 验 报 告
实验题目:算符优先分析法
课程名称:编译原理
主讲教师:
班 级:
实验日期:
提交日期:
1、
实验目的:
采用算符优先分析法对表达式(不包含括号运算)进行分析,并给出四元式。
二、实验内容
在实验1、2的基础上,用算符优先分析法编制语法分析程序。
分析过程:先在算符栈置“$”,然后开始顺序扫描表达式,若读来的单词符号是操作数,这直接进操作数栈,然后继续读下一个单词符号。分析过程从头开始,并重复进行;若读来的是运算符θ2 则将当前处于运算符栈顶的运算符θ1的入栈优先数f与θ2的比较优先函数g进行比较。
结果
四、我的感想
这次试验可以说是前两个试验的综合了,程序中也很多用到了前两次的代码。对于我自己来说,最难的部分在于将这些思想转换成代码实现出来,很大一部分在于自己平时没有多打代码以及就是对算符优先分析的思想理解得还不够透彻。在写main函数时,因为要调用很多函数,刚开始写的时候陷入了死循环,以及栈函数的各种调用发生错误,说明自己思路还不够清晰。因为这次实验是在考完试后做的,之前对算符优先分析以及四元式的理解不够明白,在这个实验实现成功后,自己能够透彻地了解,知道了算符文法的形式,对给定的算符文法能构造算符优先关系分析表,并判别所给出的文法是否为算符优先文法。同时我也算符优先文法的优缺点以及实际应用中的局限性。
三、程序的改写:
因为这次的实验与前面两次的实验有很大的重合,所以会用到很多之前两次的代码。首先,定义函数:
其中本次需要写的函数有:入栈优先函数f,比较优先函数g,compare,middle,栈函数以及主函数。
1.入栈优先函数f
书上已经给出了入栈优先函数的表,根据输入的符号赋予数值,以便后面方便比较。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三算符优先分析算法的设计与实现(8学时)一、实验目的根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。
通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。
二、实验要求1、输入文法。
可以是如下算术表达式的文法(你可以根据需要适当改变):E→E+T|E-T|TT→T*F|T/F|FF→(E)|i2、对给定表达式进行分析,输出表达式正确与否的判断。
程序输入/输出示例:输入:1+2;输出:正确输入:(1+2)/3+4-(5+6/7);输出:正确输入:((1-2)/3+4输出:错误输入:1+2-3+(*4/5)输出:错误三、实验步骤1、参考数据结构char *VN=0,*VT=0;//非终结符和终结符数组char firstvt[N][N],lastvt[N][N],table[N][N];typedef struct //符号对(P,a){char Vn;char Vt;} VN_VT;typedef struct //栈{VN_VT *top;VN_VT *bollow;int size;}stack;2、根据文法求FIRSTVT集和LASTVT集给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。
算符描述如下:/*求 FirstVT 集的算法*/PROCEDURE insert(P,a);IF not F[P,a] thenbeginF[P,a] = true; //(P,a)进栈end;Procedure FirstVT;Beginfor 对每个非终结符 P和终结符 a doF[P,a] = falsefor 对每个形如 P a…或 P→Qa…的产生式 doInsert(P,a)while stack 非空begin栈顶项出栈,记为(Q,a)for 对每条形如 P→Q…的产生式 doinsert(P,a)end;end.同理,可构造计算LASTVT的算法。
3、构造算符优先分析表依据文法和求出的相应FirstVT和 LastVT 集生成算符优先分析表。
算法描述如下:for 每个形如 P->X1X2…X n的产生式 dofor i =1 to n-1 dobeginif X i和X i+1都是终结符 thenX i = X i+1if i<= n-2, X i和X i+2 是终结符, 但X i+1 为非终结符 then X i = X i+2if X i为终结符, X i+1为非终结符 thenfor FirstVT 中的每个元素 a doX i < a ;if X i为非终结符, X i+1为终结符 thenfor LastVT 中的每个元素 a doa > X i+1 ;end4、构造总控程序算法描述如下:stack S;k = 1; //符号栈S的使用深度S[k] = ‘#’REPEAT把下一个输入符号读进a中;If S[k] ∈ VT then j = k else j = k-1;While S[j] > a doBeginRepeatQ = S[j];if S[j-1] ∈ VT then j = j-1 else j = j-2 until S[j] < Q;把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;K = j+1;S[k] = N;end of whileif S[j] < a or S[j]= a thenbegin k = k+1; S[k] = a endelse error //调用出错诊察程序until a = ‘#’5、对给定的表达式,给出准确与否的分析过程6、给出表达式的计算结果。
(本步骤可选作)四、实验报告要求1.写出编程思路、源代码(或流程图);2.写出上机调试时发现的问题,以及解决的过程;3.写出你所使用的测试数据及结果;4.谈谈你的体会。
5.上机8小时,完成实验报告2小时。
五、源代码#include<iostream.h>#include<string.h>#include<stdio.h>typedef struct{char R;char r;int flag;}array;typedef struct{char E;char e;}charLode;typedef struct{charLode *base;int top;}charstack;char str[80][80],arr[80][80],brr[80][80];array F[20];int m,kk,p,ppp,FF=1;char r[10];int crr[20][20],FLAG=0;char ccrr1[1][20],ccrr2[20][1];void Initstack(charstack &s)//定义栈{s.base=new charLode[20];s.top=-1;}void push(charstack &s,charLode w) //入栈{s.top++;s.base[s.top].E=w.E;s.base[s.top].e=w.e;}void pop(charstack &s,charLode &w) //出栈{w.E=s.base[s.top].E;w.e=s.base[s.top].e;s.top--;}int IsEmpty(charstack s) //判断是否到栈顶{if(s.top==-1)return 1;elsereturn 0;}int IsLetter(char ch) //判断是不是大写字母(非终结符)if(ch>='A'&&ch<='Z')return 1;elsereturn 0;}//judge1是判断是否是算符文法:若产生式中含有两个相继的非终结符则不是算符文法int judge1(int n){int j=3,flag=0;for(int i=0;i<=n;i++)while(str[i][j]!='\0'){char a=str[i][j];char b=str[i][j+1];if(IsLetter(a)&&IsLetter(b)) //两个非终结符相连,不是算符文法{flag=1;break;}elsej++;}if(flag==1) //根据flag设定返回值return 0;elsereturn 1;}//judge2是判断文法G是否为算符优先文法:若不是算符文法或若文法中含空字或终结符的优先级不唯一则不是算符优先文法void judge2(int n){for(int i=0;i<=n;i++)if(str[i][3]=='~'||FLAG==1)//'~'代表空{cout<<"文法G不是算符优先文法!"<<endl;FF=0;break;}if(i>n)cout<<"文法G是算符优先文法!"<<endl;}//search1是查看存放终结符的数组r中是否含有重复的终结符int search1(char r[],int kk,char a){for(int i=0;i<kk;i++)if(r[i]==a)break;if(i==kk)return 0;elsereturn 1;}//createF函数是用F数组存放每个终结符与非终结符和组合,并且值每队的标志位为0;F 数组是一个结构体void createF(int n){int k=0,i=1;char g;char t[10];//t数组用来存放非终结符t[0]=str[0][0];while(i<=n){if(t[k]!=str[i][0]){k++;t[k]=str[i][0];g=t[k];i++;}else i++;}kk=0;char c;for(i=0;i<=n;i++){int j=3;while(str[i][j]!='\0'){c=str[i][j];if(IsLetter(c)==0){if(!search1(r,kk,c))r[kk]=c;kk++;//r数组用来存放终结符}j++;}}m=0;for(i=0;i<k;i++)for(int j=0;j<kk-1;j++){F[m].R=t[i];F[m].r=r[j];F[m].flag=0;m++;}}//search函数是将在F数组中寻找到的终结符与非终结符对的标志位值为1 void search(charLode w){for(int i=0;i<m;i++)if(F[i].R==w.E&&F[i].r==w.e){F[i].flag=1;break;}}void FirstVT(int n)//求FirstVT{charstack sta;charLode w;int i=0;Initstack(sta);while(i<=n){int k=3;w.E=str[i][0];char a=str[i][k];char b=str[i][k+1];if(!IsLetter(a)) //产生式的后选式的第一个字符就是终结符的情况 {w.e=a;push(sta,w);search(w);i++;}else if(IsLetter(a)&&b!='\0'&&!IsLetter(b)) //产生式的后选式的第一个字符是非终结符的情况{w.e=b;push(sta,w);search(w);i++;}else i++;}charLode ww;while(!IsEmpty(sta)){pop(sta,ww);for(i=0;i<=n;i++){w.E=str[i][0];if(str[i][3]==ww.E&&str[i][4]=='\0'){w.e=ww.e;push(sta,w);search(w);break;}}}p=0;int k=1;i=1;while(i<m){if(F[i-1].flag==1){arr[p][0]=F[i-1].R;arr[p][k]=F[i-1].r;}while(F[i].flag==0&&i<m)i++;if(F[i].flag==1){if(F[i].R==arr[p][0])k++;else {arr[p][k+1]='\0';p++;k=1;}i++;}}}void LastVT(int n)//求LastVT{charstack sta;charLode w;for(int i=0;i<m;i++)F[i].flag=0;i=0;Initstack(sta);while(i<=n){int k=strlen(str[i]);w.E=str[i][0];char a=str[i][k-1];char b=str[i][k-2];if(!IsLetter(a)){w.e=a;push(sta,w);search(w);i++;}else if(IsLetter(a)&&!IsLetter(b)){w.e=b;push(sta,w);search(w);i++;}else i++;}charLode ee;while(!IsEmpty(sta)){pop(sta,ee);for(i=0;i<=n;i++){w.E=str[i][0];if(str[i][3]==ee.E&&str[i][4]=='\0') {w.e=ee.e;push(sta,w);search(w);}}}int k=1;i=1;ppp=0;while(i<m){if(F[i-1].flag==1){brr[ppp][0]=F[i-1].R;brr[ppp][k]=F[i-1].r;}while(F[i].flag==0&&i<m)i++;if(F[i].flag==1){if(F[i].R==arr[ppp][0])k++;else {brr[ppp][k+1]='\0';ppp++;k=1;} i++;}}}void createYXB(int n)//构造优先表{int i,j;for(j=1;j<=kk;j++)ccrr1[0][j]=r[j-1];for( i=1;i<=kk;i++)ccrr2[i][0]=r[i-1];for(i=1;i<=kk;i++)for(j=1;j<=kk;j++)crr[i][j]=0;int I=0,J=3;while(I<=n){if(str[I][J+1]=='\0') //扫描右部{I++;J=3;}else{while(str[I][J+1]!='\0'){char aa=str[I][J];char bb=str[I][J+1];if(!IsLetter(aa)&&!IsLetter(bb))//优先及等于的情况,用1值表示等于 {for(i=1;i<=kk;i++){if(ccrr2[i][0]==aa)break;}for(j=1;j<=kk;j++){if(ccrr1[0][j]==bb)break;}if(crr[i][j]==0)crr[i][j]=1;else {FLAG=1;I=n+1;}J++;}if(!IsLetter(aa)&&IsLetter(bb)&&str[I][J+2]!='\0'&&!IsLetter(str [I][J+2]))//优先及等于的情况{for(i=1;i<=kk;i++){if(ccrr2[i][0]==aa)break;}for(int j=1;j<=kk;j++){if(ccrr1[0][j]==str[I][J+2])break;}if(crr[i][j]==0)crr[i][j]=1;else{FLAG=1;I=n+1;}}if(!IsLetter(aa)&&IsLetter(bb))//优先及小于的情况,用2值表示小于 {for(i=1;i<=kk;i++){if(aa==ccrr2[i][0])break;}for(j=0;j<=p;j++){if(bb==arr[j][0])break;}for(int mm=1;arr[j][mm]!='\0';mm++){for(int pp=1;pp<=kk;pp++){if(ccrr1[0][pp]==arr[j][mm])break;}if(crr[i][pp]==0)crr[i][pp]=2;else {FLAG=1;I=n+1;}}J++;}if(IsLetter(aa)&&!IsLetter(bb))//优先及大于的情况,用3值表示大于 {for(i=1;i<=kk;i++){if(ccrr1[0][i]==bb)break;}for(j=0;j<=ppp;j++){if(aa==brr[j][0])break;}for(int mm=1;brr[j][mm]!='\0';mm++){for(int pp=1;pp<=kk;pp++){if(ccrr2[pp][0]==brr[j][mm])break;}if(crr[pp][i]==0)crr[pp][i]=3;else {FLAG=1;I=n+1;}}J++;}}}}}//judge3是用来返回在归约过程中两个非终结符相比较的值int judge3(char s,char a){int i=1,j=1;while(ccrr2[i][0]!=s)i++;while(ccrr1[0][j]!=a)j++;if(crr[i][j]==3)return 3;elseif(crr[i][j]==2)return 2;elseif(crr[i][j]==1)return 1;elsereturn 0;}void print(char s[],char STR[][20],int q,int u,int ii,int k)//打印归约的过程{cout<<u<<" ";for(int i=0;i<=k;i++)cout<<s[i];cout<<" ";for(i=q;i<=ii;i++)cout<<STR[0][i];cout<<" ";}void process(char STR[][20],int ii)//对输入的字符串进行归约的过程{cout<<"步骤"<<" "<<"符号栈"<<" "<<"输入串"<<" "<<"动作"<<endl;int k=0,q=0,u=0,b,i,j;char s[40],a;s[k]='#';print(s,STR,q,u,ii,k);cout<<"预备"<<endl;k++;u++;s[k]=STR[0][q];q++;print(s,STR,q,u,ii,k);cout<<"移进"<<endl;while(q<=ii){a=STR[0][q];if(!IsLetter(s[k])) j=k;else j=k-1;b=judge3(s[j],a);if(b==3)//大于的情况进行归约{while(IsLetter(s[j-1]))j--;for(i=j;i<=k;i++)s[i]='\0';k=j;s[k]='N';u++;print(s,STR,q,u,ii,k);cout<<"归约"<<endl;}else if(b==2||b==1)//小于或等于的情况移进{k++;s[k]=a;u++;q++;print(s,STR,q,u,ii,k);if(s[0]=='#'&&s[1]=='N'&&s[2]=='#')cout<<"接受"<<endl;else cout<<"移进"<<endl;}else{cout<<"出错"<<endl;break;}}if(s[0]=='#'&&s[1]=='N'&&s[2]=='#')cout<<"归约成功"<<endl;else cout<<"归约失败"<<endl;}void main(){int n,i,j;cout<<"请输入你要定义的文法G的产生式的个数n:"; cin>>n;cout<<"请输入文法产生式:"<<endl;for(i=0;i<n;i++){gets(str[i]);j=strlen(str[i]);str[i][j]='\0';}str[i][0]='Q'; //最末行添加扩展str[i][1]='-';str[i][2]='>';str[i][3]='#';str[i][4]=str[0][0];str[i][5]='#';cout<<"你定义的产生式如下:"<<endl;str[i][6]='\0';for(i=0;i<=n;i++)cout<<str[i]<<endl;if(judge1(n)==0) //判断文法G是否为算符文法cout<<"文法G不是算符文法!"<<endl;if(judge1(n)==1){cout<<"文法G是算符文法!"<<endl;}createF(n);FirstVT(n);LastVT(n);createYXB(n);for(i=0;i<=p;i++)//打印FirstVT{cout<<"FirstVT("<<arr[i][0]<<")={"; for(int l=1;arr[i][l+1]!='\0';l++)cout<<arr[i][l]<<",";cout<<arr[i][l]<<"}"<<endl;}cout<<"FirstVT(Q)={#}"<<endl;for(i=0;i<=ppp;i++)//打印LastVT{cout<<"LastVT("<<arr[i][0]<<")={"; for(int l=1;brr[i][l+1]!='\0';l++)cout<<brr[i][l]<<",";cout<<brr[i][l]<<"}"<<endl;}cout<<"LastVT(Q)={#}"<<endl;cout<<"优先表如下:"<<endl;for(i=1;i<kk;i++)//打印优先关系表{cout<<" ";cout<<ccrr1[0][i];}cout<<endl;for(i=1;i<kk;i++){cout<<ccrr2[i][0]<<" ";for(j=1;j<kk;j++){if(crr[i][j]==0)cout<<" ";else if(crr[i][j]==1)cout<<"=";else if(crr[i][j]==2)cout<<"<";else if(crr[i][j]==3)cout<<">";cout<<" ";}cout<<endl;}judge2(n);//判断文法G是否为算符优先文法 if(FF==1){char STR[1][20];cout<<"请输入要规约的字符串:"<<endl; gets(STR[0]);int ii=strlen(STR[0]);STR[0][ii]='#';cout<<"下面是规约的过程:"<<endl;process(STR,ii);}}。