实验三 语法分析的C语言实现
语法分析程序

语法分析程序的设计与实现实验内容:编写语法分析程序,实现对算术表达式的语法分析。
要求所分析算术表达式由如下的文法产生。
E→E+T|E-T|TT→T*F|T/F|FF→id|(E)|num实验要求:在对输入表达式进行分析的过程中,输出所采用的产生式。
方法:编写LL(1)语法分析程序,要求如下。
(1) 编程实现算法4.2,为给定文法自动构造预测分析表。
(2) 编程实现算法4.1,构造LL(1)预测分析程序。
编译环境:Windows XP环境下Visual C++ 6.0。
算法:定义栈的基本操作函数,定义有关构成LL(1)分析器的基本函数,定义LL(1)分析器的辅助函数,如FIRST 集、FOLLOW集等,设置文法表,存储P代表E',Q代表T',e代表ε,i代表id,n代表num。
源代码:#include <stdio.h>#include <stdlib.h>#define PRO_NUM 11 //产生式个数#define PRO_MAXLEN 8 //产生式最大长度#define TER_NUM 9 //终结符个数#define UNTER_NUM 5 //非终结符个数#define F_MAXLEN 8 //FIRST集和FOLLOW集的大小#define STR_MAXLEN 50 //待分析的输入表达式的最大长度#define IDNUM_MAXLEN 10 //待分析的输入表达式中id和num的的最大长度#define ERROR -1 //分析表项为空白,错误入口#define SYNCH -2 //分析表项为同步信息synch,同步错误入口#define STACK_INIT_SIZE 10 //栈空间初始分配量#define STACK_INCREMENT 5 //栈空间分配增量#define ID 1 //字母标记#define NUM 2 //数字标记#define OTHER 0 //其他字符标记#define TRUE 1#define FALSE 0#define NOTFOUND -1#define OVERFLOW -2typedef int Status; //返回状态类型typedef struct{char *top; //栈顶指针char *bottom; //栈底指针int stacksize; //当前已分配的存储空间}Stack;char grammar[PRO_NUM][PRO_MAXLEN]; //文法表char ter_symbol[TER_NUM]; //终结符表char unter_symbol[UNTER_NUM]; //非终结符表char FIRST[UNTER_NUM][F_MAXLEN]; //FIRST集char FOLLOW[UNTER_NUM][F_MAXLEN]; //FOLLOW集int M[UNTER_NUM][TER_NUM]; //LL(1)语法预测分析表char str[STR_MAXLEN+1]; //输入缓冲区Stack S; //栈//构成LL(1)分析器基本函数void Initial (void); //初始化void Create_Analysis (void); //构造LL(1)语法预测分析表void GetString (void); //获取待分析输入表达式void Analyse_Output (void); //使用LL(1)语法预测分析表分析输入的表达式并输出分析结果//LL(1)分析器辅助函数int GetStrLen (void); //获取输入表达式的长度Status Judge_Ter (char ch); //判断字符ch是否为终结符Status Judge_Unter (char ch); //判断字符ch是否为非终结符int Get_Ter_Num (char ch); //返回终结符ch在终结符表中的下标int Get_Unter_Num (char ch); //返回非终结符ch在终结符表中的下标Status In_FIRST (char A, char ch); //判断终结符ch是否在非终结符A的FIRST集中Status In_FOLLOW (char A, char ch); //判断终结符ch是否在一个非终结符A的FOLLOW集中void Output_Pro (int i); //打印分析过程中输出的产生式void Output_Stack (void); //打印当前栈中的符号void Output_Buffer (int ip); //打印当前输入缓冲区中的符号串Status Judge_Id (char ch); //判断字符ch是否为构成id的字母Status Judge_Num (char ch); //判断字符ch是否为构成num的数字Status Judge_Exceed (void); //判断输入表达式中代表id和num的子串是否超过最大长度//栈的基本操作void InitStack (void); //构造一个空栈void DestroyStack (void); //销毁栈void Push (char e); //把一个字符压入栈顶void Pop (void); //弹出栈顶字符char Gethead (void); //获取栈顶字符main (){Initial(); //初始化Create_Analysis(); //构造LL(1)语法预测分析表GetString(); //获取待分析输入表达式Analyse_Output (); //使用LL(1)语法预测分析表分析输入的表达式并输出分析结果DestroyStack (); //销毁栈return 0;}void InitStack (void) //构造一个空栈{S.bottom = (char *) malloc (STACK_INIT_SIZE * sizeof (char));if (! S.bottom)exit (OVERFLOW); //存储分配失败S.top = S.bottom;S.stacksize = STACK_INIT_SIZE;}void DestroyStack (void) //销毁栈{int i;for (i = S.stacksize - 1; i >= 0; i--) //依次释放分配的栈存数单元free (S.bottom + i);S.bottom = S.top = NULL;S.stacksize = 0;}void Push (char e) //把一个字符压入栈顶{if (S.top - S.bottom >= S.stacksize) //栈满,追加分配存储空间{S.bottom = (char *) realloc (S.bottom, (S.stacksize + STACK_INCREMENT) * sizeof(char));if (! S.bottom)exit (OVERFLOW); //存储分配失败S.top = S.bottom + S.stacksize;S.stacksize += STACK_INCREMENT;}*S.top++ = e; //把字符压入栈顶}void Pop (void) //弹出栈顶字符{if (S.bottom != S.top)S.top --;}char Gethead (void) //获取栈顶字符{char e;if (S.bottom != S.top)e = *(S.top - 1);return e;}void Initial (void) //初始化{int i, j;InitStack ();Push ('$');Push ('E'); //初始化栈:构造空栈,并压入'$'与'E'//设置文法表,存储P代表E',Q代表T',e代表ε,i代表id,n代表numstrcpy (grammar[0], "E#TP#"); //E →TE'strcpy (grammar[1], "P#+TP#"); //E' →+TE'strcpy (grammar[2], "P#-TP#"); //E' →-TE'strcpy (grammar[3], "P#e#"); //E' →εstrcpy (grammar[4], "T#FQ#"); //T →FT'strcpy (grammar[5], "Q#*FQ#"); //T' →*FT'strcpy (grammar[6], "Q#/FQ#"); //T' →/FT'strcpy (grammar[7], "Q#e#"); //T' →εstrcpy (grammar[8], "F#i#"); //F →idstrcpy (grammar[9], "F#(E)#"); //F →(E)strcpy (grammar[10], "F#n#"); //F →numfor (i = 0; i < UNTER_NUM; i++) //LL(1)语法预测分析表初始化:所有表项置为错误ERROR for (j = 0; j < TER_NUM; j++)M[i][j] = ERROR;strcpy (ter_symbol, "+-*/()in$"); //初始化终结符表strcpy (unter_symbol, "EPTQF"); //初始化非终结符表//初始化FIRST集strcpy (FIRST[0], "(in#");strcpy (FIRST[1], "+-e#");strcpy (FIRST[2], "(in#");strcpy (FIRST[3], "*/e#");strcpy (FIRST[4], "(in#");//初始化FOLLOW集strcpy (FOLLOW[0], ")$#");strcpy (FOLLOW[1], ")$#");strcpy (FOLLOW[2], "+-)$#");strcpy (FOLLOW[3], "+-)$#");strcpy (FOLLOW[4], "+-*/)$#");}Status Judge_Ter (char ch) //判断字符ch是否为终结符{if (ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch=='(' || ch==')' || ch=='i' || ch=='n' || ch=='$') return TRUE;elsereturn FALSE;}Status Judge_Unter (char ch) //判断字符ch是否为非终结符{if (ch=='E' || ch=='P' || ch=='T' || ch=='Q' || ch=='F')return TRUE;elsereturn FALSE;}int Get_Ter_Num (char ch) //返回终结符ch在终结符表中的下标{int i;for (i = 0; i < TER_NUM; i++)if (ch == ter_symbol[i])return i;return NOTFOUND;}int Get_Unter_Num (char ch) //返回非终结符ch在非终结符表中的下标{int i;for (i = 0; i < UNTER_NUM; i++)if (ch == unter_symbol[i])return i;return NOTFOUND;}Status In_FIRST (char A, char ch) //判断终结符ch是否在非终结符A的FIRST集中{int i, j;i = Get_Unter_Num (A);for (j = 0; FIRST[i][j] != '#'; j++)if (ch == FIRST[i][j])return TRUE;return FALSE;}Status In_FOLLOW (char A, char ch) //判断终结符ch是否在非终结符A的FOLLOW集中{int i, j;i = Get_Unter_Num (A);for (j = 0; FOLLOW[i][j] != '#'; j++)if (ch == FOLLOW[i][j])return TRUE;return FALSE;}void Create_Analysis (void) //构造LL(1)语法预测分析表{int i, j;int n1, n2;char ch, A;for (i = 0; i < PRO_NUM; i++) //对于每个产生式A →α{A = grammar[i][0];ch = grammar[i][2];if (Judge_Unter (ch)) //若a∈FIRST(α),M[A,a]中应放入产生式A →α{for (j = 0; j < TER_NUM; j++){if (In_FIRST (ch, ter_symbol[j])){n1 = Get_Unter_Num (A);M[n1][j] = i;}}}else if (Judge_Ter (ch)){n1 = Get_Unter_Num (A);n2 = Get_Ter_Num (ch);M[n1][n2] = i;}else if (ch == 'e') //若ε∈FIRST(α),且b∈FOLLOW(A),M[A,b]中应放入产生式A →α{n1 = Get_Unter_Num (A);for (j = 0; FOLLOW[n1][j] != '#'; j++){n2 = Get_Ter_Num (FOLLOW[n1][j]);M[n1][n2] = i;}}}for (i = 0; i < UNTER_NUM; i++) //置同步出错信息{for (j = 0; FOLLOW[i][j] != '#'; j++) //若b∈FOLLOW(A),且M[A,b]为ERROR,则把M[A,b]赋值为为同步信息SYNCH{n1 = Get_Ter_Num (FOLLOW[i][j]);if (M[i][n1] == ERROR)M[i][n1] = SYNCH;}}}int GetStrLen (void) //获取输入表达式的长度{int count;for (count = 0; str[count] != '\0'; count++);return count;}Status Judge_Exceed (void) //判断输入表达式中代表id和num的子串是否超过最大长度{int ip, bp, width;char a;int flag1 = OTHER, flag2 = OTHER; //字符类型标记int toolong = FALSE; //过长标记for (ip = 0; (str[ip] != '\0') && (! toolong); ip += width){a = str[ip];if (a=='+' || a=='-' || a=='*' || a=='/' || a=='(' || a==')' || a=='$')width = 1;else //对输入表达式中代表id和num的子串的长度进行判断{bp = ip;width = 0;if (Judge_Id (a)) //根据代表id和num的子串的首字符确定串的类型,并进行标记flag1 = flag2 = ID;if (Judge_Num (a))flag1 = flag2 = NUM;bp ++;do //获取输入表达式中代表id和num的子串的长度{a = str[bp];width ++;if (width > IDNUM_MAXLEN) //若大于子串的最大长度,标记过长并跳出循环{toolong = TRUE;break;}if (Judge_Id (a))flag2 = ID;else if (Judge_Num (a))flag2 = NUM;elseflag2 = OTHER;bp ++;} while (flag1 == flag2); //两个标记相等,即子串没有结束,继续循环}}return toolong; //返回过长标记}void GetString (void) //获取待分析输入表达式{int len = 0; //待分析的输入表达式的长度int flag = FALSE;do{printf ("请输入待分析的表达式,以'$'结束:\n");scanf ("%s", &str);len = GetStrLen ();if (str[len-1] != '$') //若每输入结尾符'$',将其补在待分析输入表达式的最后{str[len] = '$';str[len+1] = '\0';len ++;}if (len > STR_MAXLEN) //判断输入表达式是否过长printf ("此表达式过长,请重新输入!\n");flag = Judge_Exceed (); //判断输入表达式中代表id和num的子串是否过长if (flag)printf ("此表达式中代表id和num的子串过长,请重新输入!\n");} while (len > STR_MAXLEN || flag);}Status Judge_Id (char ch) //判断字符ch是否为构成id的字母{if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))return TRUE;elsereturn FALSE;}Status Judge_Num (char ch) //判断字符ch是否为构成num的数字{if (ch >= '0' && ch <= '9')return TRUE;elsereturn FALSE;}void Output_Pro (int i) //打印分析过程中输出的产生式{printf (" 输出产生式:");switch (i) //根据产生式的标号打印出对应是输出产生式{case 0:printf ("E →TE'\n");break;case 1:printf ("E' →+TE'\n");break;case 2:printf ("E' →-TE'\n");break;case 3:printf ("E' →ε\n");break;case 4:printf ("T →FT'\n");break;case 5:printf ("T' →*FT'\n");break;case 6:printf ("T' →/FT'\n");break;case 7:printf ("T' →ε\n");break;case 8:printf ("F →id\n");break;case 9:printf ("F →(E)\n");break;case 10:printf ("F →num\n");break;default:break;}}void Output_Stack (void) //打印当前栈中的符号{char *sp = NULL;printf (" 栈:");for (sp = S.bottom; sp != S.top; sp++){switch (*sp){case 'P': //将P转换为E'输出printf ("E'");break;case 'Q': //将Q转换为T'输出printf ("T'");break;case 'i': //将i转换为id输出printf ("id");break;case 'n': //将n转换为num输出printf ("num");break;default: //其他情况直接输出printf ("%c", *sp);break;}}printf ("\n");}void Output_Buffer (int ip) //打印当前输入缓冲区中的符号串{int i;printf (" 输入:");for (i = ip; str[i] != '$'; i++)printf ("%c", str[i]);printf ("$\n");}void Analyse_Output (void) //使用LL(1)语法预测分析表分析输入的表达式并输出分析结果{int ip = 0; //输入缓冲区指针int step = 0; //分析步数char X, a, c;int i, j, n1, n2, bp;int width = 0; //输入表达式中代表id和num的子串的长度char b[IDNUM_MAXLEN+1]; //存储输入表达式中代表id和num的子串int flag1 = OTHER, flag2 = OTHER; //字符类型标记do{step ++;printf ("第%d步:\n", step);X = Gethead (); //获取栈顶符号a = str[ip]; //获取输入串中将要进行分析的符号for (j = 0; j <= IDNUM_MAXLEN; j++) //对存储输入串中代表id和num的子串的数组进行初始化b[j] = '\0';if (a=='+' || a=='-' || a=='*' || a=='/' || a=='(' || a==')' || a=='$') //对输入串中将要进行分析的符号进行处理{width = 1;b[0] = a;}else //处理输入表达式中代表id和num的子串,分别将它们转化为'i'和'n'进行分析{bp = ip;width = 0;if (Judge_Id (a)) //根据代表id和num的子串的首字符确定串的类型,并进行标记flag1 = flag2 = ID;if (Judge_Num (a))flag1 = flag2 = NUM;bp ++;c = a;do //获取输入表达式中代表id和num的子串,将其存入数组b{width ++;b[width-1] = c;c = str[bp];if (Judge_Id (c))flag2 = ID;else if (Judge_Num (c))flag2 = NUM;elseflag2 = OTHER;bp ++;} while (flag1 == flag2); //两个标记相等,即子串没有结束,继续循环if (flag1 == ID) //将输入表达式中代表id和num的子串分别转化为'i'和'n'进行分析a = 'i';if (flag1 == NUM)a = 'n';}Output_Stack (); //打印当前栈中的符号Output_Buffer (ip); //打印当前输入缓冲区中的符号串if (Judge_Ter (X)) //栈顶符号是终结符:不论正确与否,都弹出栈顶符,ip前移{if (X == a){Pop ();ip += width;}else //若栈顶终结符与ip指向的字符不匹配,提示错误{Pop ();ip += width;printf (" 输出:错误!\n");}}else //栈顶符号是非终结符{n1 = Get_Unter_Num (X);n2 = Get_Ter_Num (a);if (M[n1][n2] != ERROR && M[n1][n2] != SYNCH) //正确情形:分析表项M[X][a]是非终结符X 的一个产生式{Pop (); //弹出栈顶符i = M[n1][n2];if (grammar[i][2] != 'e') //如果产生式右边不是ε,将对应产生式的右边逆序压入栈中{for (j = 2; grammar[i][j] != '#'; j++); //将对应产生式的右边逆序压入栈中for (j--; j >= 2; j--)Push (grammar[i][j]);}Output_Pro (i); //输出产生式}else if (M[n1][n2] == ERROR) //分析表项M[X][a]为空,ip前移,跳过当前输入字符(串){ip += width;printf (" 输出:错误!跳过%s\n", b);}else if (M[n1][n2] == SYNCH) //分析表项M[X][a]为同步信息,则弹出栈顶符{Pop ();printf (" 输出:错误!弹出栈顶");switch (X){case 'P': //将P转换为E'输出printf ("E'");break;case 'Q': //将Q转换为T'输出printf ("T'");break;default: //其他情况直接输出printf ("%c", X);break;}printf ("\n");}}} while (X != '$');}。
语法分析程序的设计与实现

◆词法分析 用户必须提供一个词法分析器来读取输入流并把记号(带有值, 如果需要的话)传达到解析器。词法分析器使叫做 yylex 的整数值的 函数。这个函数返回一个整数的记号编号,它表示读取的记号的种类。 如果这个记号关联着一个值,应当把它赋予外部变量 yylval。 为使通信得以发生,解析器和词法分析器必须在记号编号上达成 一致。编号可以由 Yacc 或用户来选择。在这两种情况下,使用 C 语 言的“# define”机制允许词法分析器使用符号来返回这些编号。例如, 假定在 Yacc 规定文件的声明段中已经定义记号名字 DIGIT。 它的意图是返回一个 DIGIT 记号编号,和等于这个数字的数值 的一个值。倘若词法分析器代码位于规定文件的程序段,标识符 DIGIT 将被定义为与记号 DIGIT 关联的记号编号。 这种机制导致清晰的、易于修改的词法分析器;唯一的缺点是在 文法中需要避免使用任何在 C 语言或解析器中保留的或有意义的记 号名字;例如,使用记号名字 if 或 while 就一定会导致编译词法分 析器时出现严峻的困难。记号名字 error 保留给错误处理,不应该随 便使用。 同上所述,记号编号可以由 Yacc 或用户来选择。在缺省的条件 下,编号由 Yacc 选择。文字字符的缺省记号编号是它在本地字符集 中的字符数值。其他名字赋予从 257 开始的记号编号。 要把一个记号编号赋予一个记号(包括文字),可以在声明段中记 号或文字的第一次出现时直接跟随着一个非负整数。这个整数被接受
第四:YACC 内部名称: ................................................................................................ 7 第五:运行结果(源代码见附录).............................................................................. 8 第六:实验总结 ............................................................................................................... 8 第七:附录 ..................................................................................................................... 10
语法分析实验报告(1)

语法分析实验报告一.实验目的1. 在语法分析器原理学习和词法分析器实验基础上,自行实现一个高级语言语法分析器,通过实验能够把原理和实现方法应用到如描述语言语法分析等词法分析器的设计中去。
2. 利用c语言编制递归下降分析程序,并对简单语言进行语法分析。
二.实验原理1. 待分析的简单语言的语法:0.txt:ghy.txt2. TEST语法规则:(1)<program>::={<declaration_list><statement_list>}(2) <declaration_list>::=<declaration_list><declaration_stat>|ε(3) <declaration_stat>::=int ID;(4) <statement_list>::=<statement_list><statement>|ε(5)<statement>::=<if_stat>|<while_stat>|<for_stat>|<compound_stat>|<expression_stat>(6) <if_stat>::=if(<expression>)<statement>[else<statement>](7) <while_stat)::=while(<expr>)<statement>(8)<for_stat>::=for(<expression>;<expression>;<expression>)<statement>(9) <write_stat>::=write<expression>(10) <read_stat>::=read<ID>(11) <compound_stat>::={<statement_list>}(12) <expression_stat>::=<exxprssion>;|;(13) <expression>::=ID=<bool_expr>|<bool_expr>(14)<bool_expr>::=<additive_expr>|<additive_expr>(<|>|<=|>=|==|!=)<additive_expr >(15) <additive_expr>::=<term>{+|-)<term>}(16) <term>::=<factor>{*|/)<factor>)(17) <factor>::=(<expression>)|ID|NUM三.实验步骤:1.用VC++编辑、编译和运行教材P221~230的语法分析程序。
编译原理课程设计报告C语言词法与语法分析器的实现

编写原理课程设计报告题目:编译原理课程设计C语言词法和语法分析器的实现C-词法和语法分析器的实现1.课程设计目标(1)题目的实用性C语言具有完整语言的基本属性,写C语言的词法分析和语法分析对理解编译原理的相关理论和知识会起到很大的作用。
通过编写C语言词法和语法分析程序,可以对编译原理的相关知识:正则表达式、有限自动机、语法分析等有一个清晰的认识和掌握。
(2)C语言的词法描述①语言的关键词:else if int返回void while的所有关键字都是保留字,必须小写。
②特殊符号:+ - * / < <= > >= == != = ;, ( ) [ ] { } /* */③其他标记是ID和NUM,它们由以下正则表达式定义:ID =字母字母*NUM =数字数字*字母= a|..|z|A|..|Zdigit = 0|..|9注:ID表示标识符,NUM表示数字,letter表示字母,digit表示数字。
小写字母和大写字母是有区别的。
④它由空格、换行符和制表符组成。
空格通常会被忽略。
⑤用常用的C语言符号/*将注释括起来...*/.注释可以放在任何空白位置(也就是注释不能放在标记上),可以多行。
注释不能嵌套。
(3)规划目标能够正确分析程序的词法和语法。
2.分析和设计(1)设计理念a.词汇分析词法分析的实现主要使用有限自动机理论。
有限自动机可以用来描述识别输入字符串中模式的过程,因此也可以用来构造扫描程序。
词法分析器可以很容易地用有限自动机理论来设计。
b.语法分析语法分析采用递归下降分析法。
递归下降法是语法分析中最容易理解的方法。
其主要原理是根据每个非终结符的产生式结构为其构造相应的解析子程序,其中终结符生成匹配命令,非终结符生成过程调用命令。
这种方法被称为递归子例程下降法或递归下降法,因为语法递归的相应子例程也是递归的。
子程序的结构与产生式的结构几乎相同。
(2)程序流程图主程序流程图:词法分析:语法分析:词汇分析子流程图:语法分析子流程图:3.程序代码实现整个词法与语法程序设计在同一个项目中,包含八个文件,分别是main.cpp、parse.cpp、scan.cpp、util.cpp、scan.h、util.h、globals.h和parse.h,其中scan.cpp和scan.h是词法分析程序。
编译原理语法分析实验报告(含有源代码)

《编译原理》实验报告
四、实验过程原始记录(数据、图表、计算等)
输入begin a:=9;x:=2*3;b:=a+x end #
输出success
输入x:=a+b*c end #
输出error
五、实验结果及分析,以及心得体会
通过学习了语法分析,再经过实验,让我对语法分析有了深刻的认识和了解。
递归下降分析法,是一种确定的自顶向下分析技术,它的实现思想是,对文法中分别代表一种语法成分的每个非终结符号编写一个子程序,已完成非终结符号所对应的语法成分的分析任务。
在分析过程中调用一系列过程或函数,对源程序进行语法语义分析直到整个程序处理结束。
编译原理语法分析实验报告

语法分析实验报告实验目的编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。
二、实验要求利用C语言编制递归下降分析程序,并对简单语言进行语法分析。
2.1 待分析的简单语言的语法用扩充的BNF表示如下:1)<程序>::=begin<语句串>end2)<语句串>::=<语句>{;<语句>}3)<语句>::=<赋值语句>4)<赋值语句>::=ID:=<表达式>5)<表达式>::=<项>{+<项> | -<项>}6)<项>::=<因子>{*<因子> | /<因子>7)<因子>::=ID | NUM | (<表达式>)2.2 实验要求说明输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”。
例如:输入 begin a:=9; x:=2*3; b:=a+x end #输出语法分析成功输入 x:=a+b*c end #输出语法分析2.3 语法分析程序的酸法思想1)主程序示意图如图2-1所示。
图2-1 语法分析主程序示意图2)递归下降分析程序示意图如图2-2所示。
3)语句串分析过程示意图如图2-3所示。
图2-2 递归下降分析程序示意图图2-3 语句串分析示意图4)statement语句分析程序流程如图2-4、2-5、2-6、2-7所示。
图2-4 statement语句分析函数示意图图2-5 expression表达式分析函数示意图图 2-6 term分析函数示意图图2-7 factor 分析过程示意图三、语法分析程序的C 语言程序源代码#include <stdio.h>#include <stdlib.h>#include <string.h>char prog[100],ch,token[8];int p=0,syn,n,i;char *keyword[6]={"begin","then","if","while","do","end"};void scaner();void Irparse();void statement();void expression_r();void term();void factor();void main(){int select=-1;p=0;printf("please input sentence, end of '#' !\n");do{ch=getchar();prog[p++]=ch;}while(ch!='#');p=0;printf("请输入1 或 2 \n 1.词法分析\n 2.语法分析\n");scanf("%d",&select);if(select==1){do{scaner();switch(syn){case -1:printf("词法分析出错\n");break;default :printf("<%d,%s>\n",syn,token);break; }}while(syn!=0);printf("词法分析成功\n");}else if(select==2){scaner();if(syn==1){Irparse();}//beginelse{printf("语法分析出错! 请检查begin关键字\n");return;} if(syn==6)//end{scaner();if(syn==0){printf("恭喜语法分析成功\n");}else{printf("语法分析出错! 请检查是否缺少'#'\n");} }else{printf("语法分析出错! 请检查是否缺少'end'\n");}}getchar();}void scaner(){for(n=0;n<8;n++){token[n]='\0';}n=0;ch=prog[p++];while(ch==' '){ch=prog[p++];}if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){do{token[n++]=ch;ch=prog[p++];}while((ch>='a'&&ch<='z')||(ch>='a'&&ch<='z')||(ch>='0'&&ch <='9'));syn=10;for(n=0;n<6;n++){if(strcmp(token,keyword[n])==0){syn=n+1;}}p--;//return;}else if(ch>='0'&&ch<='9'){p--;do{token[n++]=prog[p++];ch=prog[p];}while(ch>='0'&&ch<='9');syn=11;return;}else{//ch=prog[p++];switch(ch){case '+':syn=13;token[0]=ch;break;case '-':syn=14;token[0]=ch;break;case '*':syn=15;token[0]=ch;break;case '/':syn=16;token[0]=ch;break;case ':':syn=17;token[0]=ch;ch=prog[p++];if(ch=='='){token[1]=ch;syn++;}else p--;break;case '<':syn=20;token[0]=ch;ch=prog[p++];if(ch=='>'){token[1]=ch;syn++;}else if(ch=='='){token[1]=ch;syn=syn+2;} else p--;break;case '>':syn=23;token[0]=ch;ch=prog[p++];if(ch=='='){token[1]=ch;syn++;}else p--;break;case '=':syn=25;token[0]=ch;break;case ';':syn=26;token[0]=ch;break;case '(':syn=27;token[0]=ch;break;case ')':syn=28;token[0]=ch;break;case '#':syn=0;token[0]=ch;break;default: printf("词法分析出错! 请检查是否输入非法字符\n");syn=-1;break;}//return;}}void Irparse(){scaner();statement();while(syn==26)//;{scaner();statement();}}void statement(){if(syn==10){scaner();if(syn==18){scaner();expression_r();}else{printf("语法分析出错! 请检查表达式是否正确\n");return;}}else{printf("语法分析出错! 请检查语句是否正确\n");return; }}void expression_r(){term();while(syn==13||syn==14)//+ -{scaner();term();}}void term(){factor();while(syn==15||syn==16)//* /{scaner();factor();}}void factor(){if(syn==10||syn==11){scaner();}else if(syn==27){scaner();expression_r();if(syn==28){scaner();}else {printf("语法分析出错! 请检查是否缺少')'\n");return;}}else {printf("语法分析出错! 请检查是否输入非法字符\n");return;}}四、程序测试结果1)开始调试的界面2)对源程序begin a:=9; x:=2*3; b:=a+x end #的源文件,经过语法分析后如下图4-1所示:图 4-1 正确结果输出3)对源程序x:=a+b*c end #的源文件,经过语法分析后如下图4-2所示:图 4-2 错误结果输出五、总结通过对语法分析程序的设计和编写,使自己获得了很大的收获,并且使自己对语法分析程序的功能有了更进一步认识。
编译原理词法分析和语法分析报告+代码(C语言版)

编译原理词法分析和语法分析报告+代码(C语言版)-CAL-FENGHAI.-(YICAI)-Company One1信息工程学院实验报告(2010 ~2011 学年度第一学期)姓名:柳冠天学号:2081908318班级:083词法分析一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。
二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符: = + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:表2.1 各种单词符号对应的种别码2.3 词法分析程序的功能:输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
3.1 主程序示意图:主程序示意图如图3-1所示。
其中初始包括以下两个方面:⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
编译原理词法分析和语法分析报告+代码(C语言版)[1]
![编译原理词法分析和语法分析报告+代码(C语言版)[1]](https://img.taocdn.com/s3/m/6a025cd1240c844769eaee6f.png)
词法分析一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。
二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
3.1 主程序示意图:主程序示意图如图3-1所示。
其中初始包括以下两个方面:⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。
关键字表为一个字符串数组,其描述如下:Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};图3-1(2)程序中需要用到的主要变量为syn,token和sum3.2 扫描子程序的算法思想:首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。
c语言实现语法分析器

实验报告姓名:张静学号:13031121【实验名称】一种绘图语言的词法分析器【实验目的】采用c语言完成词法分析器,练习使用。
【实验内容】一、问题描述设计一种简单的函数绘图语言的词法分析器,该绘图语言可以提供一条循环绘图语句,图形变换语句,注释语句,他的词法分析器部分是读取源程序——字符序列,并根据构词规则将其转换为记号流。
它可以完成三个任务:(1)滤掉源程序中的注释和无用的成分(如空格,TAB等);(2)输出记号,供语法分析器使用;(3)识别非法输入,并将非法输入作为出错记号提供给语法分析器,以便进行出错处理。
二、问题分析词法分析器的构造步骤:正规式——NFA——DFA——最小DFA ——编写程序——测试。
1、记号的设计记号一般有两部分组成:极好的类别,记号的属性。
根据函数绘图语言的特点,可以将记号设计为如下的数据结构:Struct Token{ Token_Type type;----------类别char* lexeme;--------------属性,原是输入的字符串double value;----------属性,若记号是常数则是常数的值double (*FuncPtr)(double);--属性,若记号是函数则是函数指针};函数绘图语言的记号类别划分如下:Enum Token_Type{ ORGIN, SCALE, ROT, IS, ------------保留字TO, STEP, DRAW, FOR, FROM,---------保留字T,--------------------------------参数SEMICO, L_BRACKET, R_BRACKET, COMMA--分隔符PLUS, MINUS, MUL, DIV, POWER,------运算符FUNC,--------------------------函数CONST_ID,-------------------常数NONTOKEN,-----------------空记号ERRTOKEN-------------------出错记号};2、模式的正规式表示函数绘图语言的此法可用下是正规式集合表示,其中的letter和digit是辅助定义描述词法的正规式Letter = [a-zA-Z]Digit = [0-9]COMMENT =“//”|“--”WHITE_SPACE =(“”|\t|\n)+SEMICO =“;”L_BRACKET = “(”R_BRACKET = “)”COMMA = “,”PLUS = “ +”MINUS = “-”MUL =“ *”DIV =“ /”POWER =“ **”CONST_ID =digit+(“.”digit*)?ID =letter+(letter|digit)*用于我们是手工构造词法分析器,而正规越少越便于程序的编写,因此设计上采用相同模式的记号公用一个正规式的方法。
编译原理语法分析实验报告

编译原理语法分析实验报告南华⼤学计算机科学与技术学院实验报告(2007 ~2008 学年度第⼆学期)编译原理课程名称语法分析实验名称姓名寻友旭学号20054350227 专业软件⼯程班级软件⼯程052班地点6—413 教师陈星1.实验⽬的及要求编制⼀个递归下降分析程序,实现对词法分析程序所提供得单词序列得语法检查和结构分析。
软件、硬件环境VC6.0要求:利⽤C语⾔编制递归下降分析程序,并对简单语⾔进⾏语法分析。
待分析的简单语⾔得语法:E→E+T | E-T | TT→T*F | T/F |FF→(E) | i输⼊单词串,以“#”结束,如果是⽂法正确的句⼦,则输出成功信息,打印“Accept! Right Expression!”,否则输出“Error”。
语法分析:a) ∵E=>E+T=>E+T*F=>E+T*(E)即有E=>E+T*(E)存在左递归。
⽤直接改写法消除左递归,得到如下:E →TE’E’ → +TE’ | ?TE’|εT →FT’T’ →*FT’ | /FT’|εF → (E) | ib) 对于以上改进的⽅法。
可得:对于E’:FIRST( E’ )=FIRST(+TE’)∪FIRST(-TE’)∪{ε}={+,?,ε}对于T’:FIRST( T’ )=FIRST(*FT’)∪FIRST(/FT’)∪{ε}={*,⁄,ε}⽽且:FIRST( E ) = FIRST( T ) = FIRST( F )=FIRST((E))∪FIRST(i)={(,i }由此我们容易得出各⾮终结符的FOLLOW集合如下:FOLLOW( E )= { ),#}FOLLOW( T’ ) = FOLLOW( T ) ={+,?,),#}FOLLOW( F )=FIRST(T’)\ε∪FOLLOW(T’)={*,⁄,+,?,),#}由以上FOLLOW集可以我们可以得出SELECT集如下:对E SELECT(E→TE’)=F IRST(TE’)=FIRST(T)={ (,i }对E’ SELECT(E’ →+TE’)={ + }SELECT(E’ →?TE’)={ ? }SELECT(E’ →ε)={ε,),#}对T SELECT(T→FT’)={(,i}对T’ SELECT(T’ →*FT’)={ * }SELECT(T’ →⁄FT’)={ ⁄}SELECT(T’ →ε)={ε,+,?,),#}对F SELECT(F→(E) )={ ( }SELECT(F→i)={ i }∴SELECT(E’ →+TE’)∩SELECT(E’ →?TE’)∩SELECT(E’ →ε)=ΦSELECT(T’ →*FT’)∩SELECT(T’ →⁄FT’)∩SELECT(T’ →ε)=ΦSELECT(F→(E) )∩SELECT(F→i)= Φ由上可知,有相同左部产⽣式的SELECT集合的交集为空,所以⽂法是LL(1)⽂法。
编译原理语法分析实验报告

编译原理语法分析实验报告编译原理实验报告二、语法分析(一) 实验题目编写程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析。
(二) 实验内容和要求1. 要求程序至少能分析的语言的内容有:1) 变量说明语句2) 赋值语句3) 条件转移语句4) 表达式(算术表达式和逻辑表达式)5) 循环语句6) 过程调用语句2. 此外要处理:包括依据文法对句子进行分析;出错处理;输出结果的构造。
3. 输入输出的格式:输入:单词文件(词法分析的结果)输出:语法成分列表或语法树(都用文件表示),错误文件(对于不合文法的句子)。
4. 实现方法:可以采用递归下降分析法,LL(1)分析法,算符优先法或LR分析法的任何一种,也可以针对不同的句子采用不同的分析方法。
(三) 实验分析与设计过程1. 待分析的C语言子集的语法:该语法为一个缩减了的C语言文法,估计是整个C语言所有文法的60%(各种关键字的定义都和词法分析中的一样),具体的文法如下:语法:100: program -> declaration_list101: declaration_list -> declaration_list declaration | declaration 102: declaration -> var_declaration|fun_declaration103: var_declaration -> type_specifier ID;|type_specifier ID[NUM]; 104: type_specifier -> int|void|float|char|long|double|105: fun_declaration -> type_specifier ID (params)|compound_stmt 106: params -> params_list|void107: param_list ->param_list,param|param108: param -> type-spectifier ID|type_specifier ID[]109: compound_stmt -> {local_declarations statement_list}110: local_declarations -> local_declarations var_declaration|empty 111: statement_list -> statement_list statement|empty11编译原理实验报告112: statement -> epresion_stmt|compound_stmt|selection_stmt|iteration_stmt|return_stmt113: expression_stmt -> expression;|;114: selection_stmt -> if{expression)statement|if(expression)statement else statement115: iteration_stmt -> while{expression)statement116: return_stmt -> return;|return expression;117: expression -> var = expression|simple-expression118: var -> ID |ID[expression]119: simple_expression ->additive_expression relop additive_expression|additive_expression 120: relop -> <=|<|>|>=|= =|!=121: additive_expression -> additive_expression addop term | term 122: addop -> + | -123: term -> term mulop factor | factor124: mulop -> *|/125: factor -> (expression)|var|call|NUM126: call -> ID(args)127: args -> arg_list|empty128: arg_list -> arg_list,expression|expression该文法满足了实验的要求,而且多了很多的内容,相当于一个小型的文法说明:把文法标号从100到128是为了程序中便于找到原来的文法。
实验三语法分析的C语言实现

实验三语法分析的C 语言实现一、实验目的加深对语法分析器工作过程的理解;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法分析。
二、实验要求1、在实验一(用C 语言实现词法分析的程序)的基础上,实现编写语法分析程序,语法分析程序的实现可以采用任何一种编程工具。
2、对语法规则有明确的定义;3、编写的分析程序能够对实验一的结果进行正确的语法分析;4、对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成语法分析过程;三、实验分工个人完成四、程序说明有文法G[E] :E->TGT->FSG->+TG|S->*FS|=E|F->(E)|i1.1 判断LL(1) 文法当我们需选用自顶向下分析技术时,首先必须判别所给文法是否是LL(1) 文法,分析所给文法可知文法中不含左公因子,也不存在左递归,因而再对给定文法计算First 集、Follow 集以及Select 集,对于求出的每个产生式的Select 集,看对于同一个左部非终结符是否存在交集,如果它们的交为空则表示所给文法是LL(1) 文法,否则不是L(1) 文法。
若所给文法是LL(1) 文法,再根据求得的Select 集合构造预测分析表,对于一个输入串,根据已知的预测分析表分析它是否是文法的句子。
各非终结符的First 集以及Follow 集如下表所示:表1-1SelectSelect(E->TG)={(,i}Select(T->FS)={(,i}Select(G->+TG)={+} Select(G-> ε)={#,)}Select(S->*FS)={*} Select(S-> ε)={+,#,)} Select(S->=E)={=}Select(F->(E))={(} Select(F->i)={i}由各产生式的Select 集可以看出,每个非终结符的Select 集交集为空,则可以确定该文法是LL(1) 文法。
实验三 语法分析的C语言实现

实验三语法分析的C语言实现一、实验目的加深对语法分析器工作过程的理解;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法分析。
二、实验要求1、在实验一(用C语言实现词法分析的程序)的基础上,实现编写语法分析程序,语法分析程序的实现可以采用任何一种编程工具。
2、对语法规则有明确的定义;3、编写的分析程序能够对实验一的结果进行正确的语法分析;4、对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成语法分析过程;三、实验指导1(实现算术表达式的运算)(一)准备1.阅读课本有关章节,参考P63的表6.3优先关系表。
2.初步编制程序。
3.准备一组测试数据。
(二)程序要求1.程序输入/输出示例:输入如下一段C语言源程序:3+2*(5.5-5)输出:输出运算的结果4.0。
2. 建议:实验一的词法分析结果保存到文件input.c,实验二直接从input.c读取一个token,将用到的文法规则输出并保存到文件output.c。
(注:NUM由词法分析器返回)3.可选功能:可以根据自身的情况完善语法分析程序的错误处理功能,如对遇到的语法错误给出准确的位置和错误类型提示。
三、实验指导2(用递归下降分析器实现语法分析)(一)准备1.阅读课本有关章节,特别是P49的代码,明确语言的语法。
2.初步编制程序。
3.准备一组测试数据。
(二)程序要求1.程序输入/输出示例:输入如下一段C语言源程序(实现赋值语句或者if语句或者while语句,或者都实现):main(){a = 10*(b+2);if (a>b) a=b else a=c;while (a!=0) a=3+21*a;}输出:依次输出所用到的文法规则或出错信息。
2. 建议:实验一的词法分析结果保存到文件input.c,实验二直接从input.c读取一个token,将用到的文法规则输出并保存到文件output.c。
语法分析实验

实验题目:语法分析实验08计科2班 20084011011 姚黎涵一、实验目的:熟悉并实现一个递归下降语法分析器二、实验设备(环境):VC++6.0 ,windows XP系统三、实验内容:描述:递归下降语法分析器。
分析如下方法:E->T{+T}|{-T}T->F{*F}|{/F}F->i|‘(’E‘)’输入:一个表达式。
输出:分析成功或不成功信息。
四、实验代码代码如下:/************************************************************************ * 文件名:ana.c* 文件描述:递归下降语法分析器。
分析如下方法:* E->E+T | E-T | T* T->T*F | T/F |F* F->(E) | i* 输入:每行含一个表达式的文本文件。
* 输出:分析成功或不成功信息。
** 版本号:.0***********************************************************************/#include<stdio.h>#include<malloc.h>#include<stdlib.h>#define READ(ch) ch=getc(fp) /*宏:READ(ch)*/char ch; /*声明为全局变量*/int right=0;FILE *fp;struct struCH{char ch;struct struCH *next;}struCH,*temp,*head,*shift;/*head指向字符线性链表的头结点*//*shift指向动态建成的结点(游标)*/void E (); /* P(E) */void T (); /* P(T) */void F (); /* P(F) */void E(){T();if(shift->ch=='+'||shift->ch=='-'){shift=shift->next;E();}else{if(shift->ch=='#'||shift->ch==')')return;elseright=0;}}void T(){F();if(shift->ch=='*'||shift->ch=='/'){shift=shift->next;T();}else{if(shift->ch!='#'&&shift->ch!=')'&&shift->ch!='+'&&shift->ch!='-') right=0;}}void F(void){if(shift->ch=='i')shift=shift->next;else{if(shift->ch=='('){shift=shift->next;E();if(shift->ch==')')shift=shift->next;elseright=0;}elseright=0;}}void main(int argc,char *argv[]){int errnum=0,k=0,m=0,countchar=0,rownum;int charerr=0; /*开关控制量*//************************以只读方式打开文件*********************/if((fp=fopen("C:\\Documents and Settings\\Administrator\\桌面\\1.txt","r"))==NULL){printf("\n\tCan not open file %s,or not exist it!\n",argv[1]);exit(0); /*文件不存在or打不开时,正常退出程序*/}else printf("\n\tSuccess open file: %s\n",argv[1]); /*成功打开文件*//******************遍历整个文件检测是否有非法字符********************//*如果用while(!feof(fp))语言,将会多出一个字符*所以这里采用以下方法遍历整个文件检测其否有非法字符*//*[1]计算文件中字符数量*/while(!feof(fp)){READ(ch); /*这里读取字符只是让文件指针往前移*/countchar++; /*统计文件中的字符数(包括换行符及文件结束符)*/ }rewind(fp); /*将fp文件指针重新指向文件头处,以备后面对文件的操作*/if(countchar==0){ /*空文件*/printf("\t%s is a blank file!\n",argv[1]);exit(0); /*正常退出本程序*/}/*[2]开始遍历文件*/while(k<(countchar-1)){ /*加换行符后countchar仍多了一个,不知为何*/ ch=getc(fp);if(!(ch=='('||ch==')'||ch=='i'||ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='#'||ch=='\n')){ charerr=1;errnum++; /*charerror出错标记,errnum统计出错个数*/ }k++;}rewind(fp); /*将fp文件指针重新指向文件头处,以备后面的建链表操作*/ if(charerr==1){ /*文件中有非法字符*/printf("\n\t%d Unindentify characters in file %s \n",errnum,argv[1]);exit(0); /*正常退出本程序*/}/*******************非空且无非法字符,则进行识别操作*****************/ for(rownum=1;m<(countchar-1);rownum++){ /*识别所有行,rownum记录行号*/ /*初始变量及堆栈和*/right=1;/*初始存放待识别的表达式的线性链表头*/shift=(struct struCH *)malloc(sizeof(struct struCH));/**/shift->next=NULL;head=shift;/*读取一行形成线性链表*/READ(ch);putchar(ch);m++;while(ch!='\n'&&m<(countchar)){ /*行末or到文件尾。
语法分析程序实验报告及代码

LL(1)语法分析实验报告一、实验题目 LL(1)语法分析二、实验目的通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,检查语法错误,进一步掌握常用的语法分析方法。
三、实验内容构造LL(1)语法分析程序,任意输入一个文法符号串,并判断它是否为文法的一个句子。
程序要求为该文法构造预测分析表,并按照预测分析算法对输入串进行语法分析,判别程序是否符合已知的语法规则,如果不符合则输出错误信息。
消除递归前的文法消除递归和提取公因子后的等价文法S →S ∨ a T | a T | ∨ a T S→aTS’ |vaTS’T →∧ a T | ∧a S’→ vaTS’ |εT→∧ a T’T’→∧ aT’ |ε根据已建立的分析表,对下列输入串:a∧ a∧ a进行语法分析,判断其是否符合文法。
四、实验要求1.根据已由的文法规则建立LL(1)分析表;2.输出分析过程。
请输入待分析的字符串: a∧ a∧ a符号栈输入串所用产生式#S a∧ a∧ a##S’Ta a∧ a∧ a# S→aTS’#S’T ∧ a∧ a## S’T’a∧∧ a∧ a# T→∧ a T’# S’T’a a∧ a## S’T’∧ a## S’T’a∧∧ a# T’→∧ aT’# S’ T’a a## S’ T’## S’ # T’→ε# # S’→ε五、程序思路模块结构:1、定义部分:定义常量、变量、数据结构。
2、初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体等);3、运行程序:让程序分析一个text文件,判断输入的字符串是否符合文法定义的规则;4、利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示简单的错误提示。
六、程序源代码/* 程序名称: LL(1)文法分析程序 *//* S->S>aT|aT|>aT *//* T-> <aT|<a*//************************************//********************************************//* 程序相关说明 *//* A=S’ B=T’ *//* 0=S 1=S’ 2=T 3=T’*//* 0=a 1=< 2=#*//************************************/#include"iostream.h"#include "stdio.h"#include "malloc.h"#include "conio.h"struct Lchar{char char_ch;struct Lchar *next;}Lchar,*p,*h,*temp,*top,*base;char curchar;char curtocmp;int right;int table[4][3]={{1,0,0},{0,0,1},{0,1,0},{0,1,1}};int i,j;void push(char pchar){temp=(struct Lchar*)malloc(sizeof(Lchar));temp->char_ch=pchar;temp->next=top;top=temp;}void pop(void){curtocmp=top->char_ch;if(top->char_ch!='#')top=top->next;}void doforpush(int t){switch(t){case 3:push('A');push('T');push('a');push('<');break; case 0:push('A');push('T');push('a');break;case 6:push('T');push('a');push('<');break;case 21:push('B');push('a');push('<');break;case 31:push('T');break;}}void changchartoint(){switch(curtocmp)case 'S':i=0;break;case 'A':i=1;break;case 'T':i=2;break;case 'B':i=3;break;}switch(curchar){case 'a':j=0;break;case '<':j=1;break;case '#':j=2;}}void dosome(void){int t;for(;;){pop();curchar=h->char_ch;printf("\n%c\t%c",curchar,curtocmp);if(curtocmp=='#' && curchar=='#')break;if(curtocmp=='S'||curtocmp=='A'||curtocmp=='T'||curtocmp=='B')if(curtocmp!='#') {changchartoint();if(table[i][j]){t=10*i+j;doforpush(t); continue;}else{right=0;break;}}elseif(curtocmp!=curchar) {right=0;break;}elsebreak;elseif(curtocmp!=curchar){right=0;break;}else{h=h->next;continue;}}}void main(void){char ch;cout<<"* 文件名称: 语法分析"<<endl;cout<<" "<<endl;cout<<"/* 程序相关说明 */"<<endl;cout<<"---------------------------------------------------------------------"<<endl;cout<<"-/* A=S’ B=T’ */"<<endl;cout<<"-* 目的: 对输入LL(1)文法字符串,本程序能自动判断所给字符串是 -"<<endl;cout<<"-* 否为所给文法的句子,并能给出分析过程。
编译原理实验之语法分析程序

《编译原理》实验报告——之语法分析程序姓名:卢旭学号:U200917806班级:软工0901班2011年10月22日目录一、实验题目 (3)一、实验题目编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。
单词符号语法结构定义:<表达式> ::= <项>{ +<项>|-<项>}<项> ::= <因子>{*<因子>|/<因子>}<因子> ::=ID|num|(<表达式>)num::=( +|-|ε) 数字数字*(.数字数字* | ε)( e ( +|-|ε) 数字数字*|ε)ID::=字母(字母|数字)*字母::=a|b|c…|z|A|B|C…|Z数字::=0|1|2…|9二、实验目的1)练习用C语言来编写语法分析程序2)加深对编译原理中语法分析流程的理解三、实验要求输入单词串,以‘#’结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”。
例如:输入:begin a:=9; x:=2*3; b:=a+x end #输出success输入x:= a+b*c end #输出error四、实验设计基本设计思路1)关键字表置初值:char *rwtab[6]={"begin","if","then","while","do","end"};识别出标识符,然后查这个关键字表,给出相应的种别码;2)识别无符号整数是将数字串转换为无符号整数。
3)设计扫描函数scanner(),扫描程序每次读取1个独立意义的单词符号,并判断单词类型;4)递归下降分析法是对文法的每个非终结符编制一个递归过程(函数),按规则右部符号串的顺序编写:若为终结符,则读下一个单词符号;非终结符,调用相应的递归过程(函数)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三语法分析的C语言实现一、实验目的加深对语法分析器工作过程的理解;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法分析。
二、实验要求1、在实验一(用C语言实现词法分析的程序)的基础上,实现编写语法分析程序,语法分析程序的实现可以采用任何一种编程工具。
2、对语法规则有明确的定义;3、编写的分析程序能够对实验一的结果进行正确的语法分析;4、对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成语法分析过程;三、实验分工个人完成四、程序说明有文法G[E]:E->TGT->FSG->+TG|εS->*FS|=E|εF->(E)|i1.1 判断LL(1)文法当我们需选用自顶向下分析技术时,首先必须判别所给文法是否是LL(1)文法,分析所给文法可知文法中不含左公因子,也不存在左递归,因而再对给定文法计算First集、Follow集以及Select集,对于求出的每个产生式的Select 集,看对于同一个左部非终结符是否存在交集,如果它们的交为空则表示所给文法是LL(1)文法,否则不是L(1)文法。
若所给文法是LL(1)文法,再根据求得的Select集合构造预测分析表,对于一个输入串,根据已知的预测分析表分析它是否是文法的句子。
各非终结符的First集以及Follow集如下表所示:表1-1Select(E->TG)={(,i}Select(T->FS)={(,i}Select(G->+TG)={+} Select(G->ε)={#,)}Select(S->*FS)={*} Select(S->ε)={+,#,)} Select(S->=E)={=} Select(F->(E))={(} Select(F->i)={i}由各产生式的Select集可以看出,每个非终结符的Select集交集为空,则可以确定该文法是LL(1)文法。
1.2 构造预测分析表主要函数介绍:1、void print();输出分析栈2、void print1();输出剩余串3、int main();程序主函数,在其中调用自定义函数,完成文法产生式的赋值,预测分析表的构建,以及对输入串的分析等主要功能。
程序主要代码:1、初始化程序即分析栈、剩余串、非终结符与终结符的初始化char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','*','(',')','#',';','='};/*终结符 */ char v2[20]={'E','G','T','S','F'};/*非终结符 */int j=0,b=0,top=0,l;/*L为输入串长度 */2、结构体的定义及结构体变量定义typedef struct type/*产生式类型定义 */{char origin;/*大写字符 */char array[5];/*产生式右边字符 */int length;/*字符个数 */}type;type c,e,t,g,g1,s,s1,f,f1,s2;/*结构体变量 */type C[10][10];/*预测分析表 */3、输出分析栈函数定义void print(){int a;for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}4、输出剩余串函数定义void print1(){int j;for(j=0;j<b;j++)printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}5、在main函数中定义结构体,把文法产生式赋值给结构体/*把文法产生式赋值结构体*/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;s2.origin='S';strcpy(s2.array,"=E");s2.length=2;6、预测分析表的初始化及构造for(m=0;m<=7;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][5]=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]=s1;C[3][7]=s2;C[4][0]=f1;C[4][3]=f;7、读入分析串,对输入串进行分析,判断输入串是否符合文法的定义,是否有非法字符,是否在分析过程中出现错误信息,是否被接受为文法的句子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("accept!\n");/*接受 */getchar();getchar();exit(1);}if(x==ch){print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",ch);/*输出出错终结符*/ exit(1);}/*else*/}/*if*/else/*非终结符处理*/{for(j=0;j<=7;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<cha.length;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--;}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}}}while(finish==0);}编程中遇到的问题:栈的判断出错,无法对应和自行从终结符中提取预测分析表出错,定义后无法识别可改进的地方:1、由于一个人实验,工作量实在太大,实力不足,总有很多问题卡住,于是根据书本先行使用书本文法进行编辑,先行使用i替换所有的字母数字2、由于时间关系,没法对i进行改动区分开所有的字母数字,仍旧使用i进行操作判断3、由于没对i进行编辑改动,导致了while以及if语句未能插入代码中,只能识别出赋值语句4、做这份代码是太多太多的辛酸,认识到了实力不足时团队的重要性,还望老师谅解五、截图六、#include<stdio.h>#include<iostream>#include<stdlib.h>#include<dos.h>#include<string>using namespace std;char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','*','(',')','#',';','='};/*终结符*/ char v2[20]={'E','G','T','S','F'};/*非终结符*/int j=0,b=0,top=0,l;/*L为输入串长度*/ typedef struct type/*产生式类型定义*/ {char origin;/*大写字符*/char array[5];/*产生式右边字符*/int length;/*字符个数*/}type;type c,e,t,g,g1,s,s1,f,f1,s2;/*结构体变量*/ type C[10][10];/*预测分析表*/void print()/*输出分析栈*/{int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}void print1()/*输出剩余串*/{int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}int main(){int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受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;s2.origin='S';strcpy(s2.array,"=E");s2.length=2;for(m=0;m<=7;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][5]=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]=s1;C[3][7]=s2;C[4][0]=f1;C[4][3]=f;printf("提示:本程序只能对由'i','+','*','(',')'构成的以'#'结束的字符串进行分析,\n"); printf("请输入要分析的字符串:");FILE * fpin;char in_fn[30]; //存放地址for(;;){cin>>in_fn;if((fpin=fopen(in_fn,"r"))!=NULL) //判断文件是否存在break;elsecout<<"文件路径错误!";}do/*读入分析串*/{ch=fgetc(fpin);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("accept!\n");/*接受*/getchar();getchar();exit(1);}if(x==ch){print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/{for(j=0;j<=7;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<cha.length;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--;}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}}}while(finish==0);}七、测试语句I=(i+i)*i#四、实验报告1. 实验目的2. 实验分工3. 程序说明:实现的文法说明、主要函数介绍4. 其他说明:包括可选功能的实现介绍、编程中遇到的主要问题、可改进的地方5. 运行结果截图显示6. 源程序:要求有一定的注释。