1、编译原理实验报告一LL(1)文法分析1.设计要求(1)对输入文法,它能判断是否为 LL(1)文法,若是,则转( 2) ;否则报错并终止;(2)输入已知文法,由程序自动生成它的 LL(1)分析表;(3)对于给定的输入串,应能判断识别该串是否为给定文法的句型。2.分析该程序可分为如下几步:(1)读入文法 (2)判断正误 (3)若无误,判断是否为 LL(1)文法 (4)若是,构造分析表;(5)由总控算法判断输入符号串是否为该文法的句型。3.流程图是是开始读入文法有效?是 LL(1)文法?判断句型 报错结束4.源程序/*语法分析程序作者:xxx 学号:xxx*/#include#include#inc
2、lude/*/int count=0; /*分解的产生式的个数 */int number; /*所有终结符和非终结符的总数*/char start; /*开始符号*/char termin50; /*终结符号*/char non_ter50; /*非终结符号 */char v50; /*所有符号*/char left50; /*左部*/char right5050; /*右部*/char first5050,follow5050; /*各产生式右部的 FIRST 和左部的 FOLLOW 集合*/char first15050; /*所有单个符号的 FIRST 集合*/char select50
3、50; /*各单个产生式的 SELECT 集合*/char f50,F50; /*记录各符号的 FIRST 和 FOLLOW 是否已求过*/char empty20; /*记录可直接推出的符号*/char TEMP50; /*求 FOLLOW 时存放某一符号串的 FIRST 集合*/int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为 LL(1)文法*/int M2020; /*分析表*/char choose; /*用户输入时使用*/char empt20; /*求_emp()时使用*/char fo20; /*求 FOLLOW 集合时使用*
4、/*判断一个字符是否在指定字符串中*/int in(char c,char *p)int i;if(strlen(p)=0)return(0);for(i=0;i+)if(pi=c)return(1); /*若在,返回 1*/if(i=strlen(p)return(0); /*若不在,返回 0*/*得到一个不是非终结符的符号*/char c()char c=A;while(in(c,non_ter)=1)c+;return(c);/*分解含有左递归的产生式*/void recur(char *point) /*完整的产生式在 point中*/int j,m=0,n=3,k;char temp
5、20,ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_terk=ch;non_terk+1=0;for(j=0;j) printf(“ninput error!“);validity=0;return(0); /*检测输入错误*/for(k=0;k=0)firsti0=;firsti1=0;elseTEMP0=;TEMP1=0;elsefor(j=0;j+)if(vj=p0)break;if(i=0)memcpy(firsti,first1j,strlen(first1j);firstistrlen(first1j)=0;elsememcpy(TEMP
6、,first1j,strlen(first1j);TEMPstrlen(first1j)=0;else /*如果右部为符号串*/for(j=0;j+)if(vj=p0)break;if(i=0)merge(firsti,first1j,2);elsemerge(TEMP,first1j,2);for(k=0;k=0)merge(firsti,first1m,2);elsemerge(TEMP,first1m,2);else if(_emp(pk)=1temp1=0;if(i=0)merge(firsti,temp,1); elsemerge(TEMP,temp,1);else if(_emp(
7、pk)=0)break;/*求各产生式左部的 FOLLOW*/void FOLLOW(int i)int j,k,m,n,result=1;char c,temp20;c=non_teri; /*c 为待求的非终结符*/temp0=c;temp1=0;merge(fo,temp,1);if(c=start) /*若为开始符号*/temp0=#;temp1=0;merge(followi,temp,1);for(j=0;j=0;n-)Sp+=rightmn;Sq+strlen(rightm)=0;printf(“nS:%s str:“,S);for(p=j;p=0)printf(“M%d%d=%
8、d “,i,j,Mij);printf(“n“);menu();5.执行结果(1)输入一个文法(2)输入一个符号串(3)再次输入一个符号串,然后退出程序二词法分析一、 问题描述识别简单语言的单词符号识别简单语言的基本字、标识符、无符号整数、运算符和界符。1.题目选择计算机高级程序语言之一 C 语言,运用恰当的词法分析技术线路,设计和实现其对应的词法分析器。2.要求1). 给出一简单语言单词符号的种别编码。单词符号 种别编码begin 1if 2then 3while 4do 5end 6l ( l | d ) * 10dd * 112). 词法分析程序的功能 输入是源程序字符串,以# 结束。输
9、出是单词符号的二元组。分析器输出结果存入到磁盘文件中,具有出错处理功能。3). 建议和提示:技术线路选择如下两种之一:.正则式NFADFAmin DFA程序设计或 正则文法NFADFAmin DFA程序设计。二、 系统分析词法分析器对应的正则文法表达如下:S 标示符或关键字 |数字字符|运算符标示符或关键字 characterAA character|number| (标示符或关键字要以字母开头)数字字符 number| (数字字符只能由数字组成 )character a|b|c|y|z|A|B|C|Y|Znumber 0|1|2|3|4|5|6|7|8|9运算符 =|:|:=|+|-|*|/
10、|=|;|(|)|n该词法分析程序要识别的字符类别包括关键字,标示符,数字字符,运算符,结束符#。这里把关键字和标示符归为同一类,识别完之后根据查标示符表得到是标示符还是关键字。因此对于自动机 DFA 来说,有几个相应的状态,对应识别不同单词串。当然词法分析程序还要有过滤空格字符,注释符号,回车换行符等一些特殊字符。当词法分析器遇到符号# 的时候就表示词法分析已经完成,程序结束。三、 系统设计基于以上的讨论,我设计了本实验词法分析器的有限自动机的状态图。字母 数字字母或数字 数字特殊符号(无#)特殊符号(无#)空格或回车空格或回车 空格或回车DFA 图流程说明:每当读入完一个字符串后,自动机回
11、到开始状态 S,读入下一个字符串的第一个字母。这里所说的字符串是指标示符或者关键字或者数字或者特殊符号。当读入的第一个字符是字母的时候说明这个状态机要识别的是标示符或者字符串,后面的字符可以是字母或者数字。所以在标示符或关键字状态的时候读入的下一个字符是字母或者是数字的时候其状态还是会转向自己;当读入的下个字符是回S标示符或关键字 数字符号结束车或空格的时候表示识别完成;当读入的下个字符是特殊符号的时候(非字母或数字)按正常思维状态应转向出错处理,不过由于本实验是词法分析,标示符不合法应该是语义分析阶段做的事,所以本程序没有给出出错处理。识别字符串后还应区分这个单词是标示符还是关键字。实现过程
12、是查关键字表,将识别的字符串同关键字表中的每一个元素比较,若有相同则说明识别的是关键字,否则是标示符。当读入的第一个字符是数字的时候说明这个状态机要识别的是数字。后面的字符可以是数字,表示多位数。所以在数字状态的时候读入的下一个字符是数字的时候其状态还是会转向自己;当读入的下个字符是回车或空格的时候表示识别完成;当读入的下个字符非数字时候,会发生语义错误,本程序是词法分析所以没有给出。当读入的第一个字符是特殊字符的时候说明这个状态机要识别的是特殊字符。双目特殊字符(如:=,=等) 后面的字符还可以是特殊字符。所以在特殊字符状态的时候读入的下一个字符是特殊字符的时候其状态还是会转向自己;当读入的
13、下个字符是回车或空格的时候表示识别完成;当读入的下个字符非数字时候,状态机理应转向出错处理,不过本程序同样没有给出。最后程序读入符号#时,说明源程序读入完毕,程序结束。四系统实现程序流程图如下所示:NY其中 syn=0,表示读到的字符是# 。关键字表设置代码如下:char *rwtab6= “begin”, “if ”, “then”, “while”, “do” ,“end” ;打开要识别的源程序文件,初始化关键字表。调用扫描子程序,对每个字符串扫描,识别所属类型。输出每个单词二元组。Syn=0程序结束这里只给出了六个常用的关键字,真正的编译器的话应该给出所有的关键字。扫描子程序算法:字母
14、数字 运算符 空格回车 #标示符或关键字 数字 运算符 过滤掉 syn=0查关键字表 拼数 置对应的 syn 值匹配 否则 置 syn=11关键字 标示符置 syn=1-6 置 syn=10 程序源代码如下:#include#includechar prog80, token8; /prog 存储源程序字符串,token单词缓冲数组 token置为空。跳过空格,读入第一个字符。判断第一个字符存储单个字符char ch;FILE * fp;int syn, p, m, n ,sum ;char *rwtab6= “begin“,“if“,“then“,“while“,“do“,“end“ ;vo
15、id scaner();void main(int argc,char* argv) p=0;fp=fopen(“/input.txt“,“r“);if(!fp) printf(“File open error!n“);do ch=getc(fp);progp+=ch ; while ( ch!=#);p=0;fp=fopen(“/output.txt“,“w“);if(!fp) printf(“File open error!n“);do scaner();switch(syn)case 11:fprintf (fp,“%2d“,syn); fprintf (fp,“%8dn“,sum);break; /输出数字case -1:fprintf(fp,“inpu t errorn“); break; /出错case 29: break; /过滤回车default:fprintf (fp,“%2d“,syn); /输出保留字或者标识符fprintf (fp,“%8sn“,token);while (syn!=0);fclose(fp);void scaner() /词法扫描子程序 m=0,sum=0;for ( n=0; n=A