编译原理实验报告(词法分析,语法分析)

来源:成人英语 发布时间:2020-09-15 点击:

 计算机专业类课程

  实验报告实验报告

 课程名称:

 编译原理

 学

 院:

 计算机科学与工程

 专

 业:

 计算机科学与技术

 学生姓名:

 林怡

 学

 号:

 2012060020023

 指导教师:

 陈昆

 日

 期:

 5 2015 年 年 6 6 月 月 5 5 日

 电 电 子 科 技 大 学 实 实

  验

  报

  告 实验一 一、 实验名称:

 词法分析器的设计与实现 二、 实验学时:4 三、 实验内容和目的:

 实验内容:

 求 n!的极小语言的源程序作为词法分析的输入程序,根据给定的文法对其进行词法分析并将单词符号与种别组成的二元式按指定格式输出到 out.dyd 文件中,同时将词法错误输出到 error.err 文件中。

 其中二元式文件 out.dyd 有如下要求:

  (1)二元式形式:

 单词符号  种别

  (2)每行后加上

  “...EOLN24”

  (3)文件结尾加上

  “...EOF25” 出错文件 error.err 中错误信息格式如下:

  ***LINE:行号  错误性质

 实验目的:

  通过设计并实现一个词法分析器,了解和掌握词法分析程序设计的原理及相应的程序设计方法,同时提高编程能力。

 四、 实验原理:

 1、编译程序要求对高级语言编写的源程序进行分析和合成,生成目标程序。词法分析是对源程序进行的首次分析,实现词法分析的程序为词法分析程序。像用自然语言书写的文章一样,源程序是由一系列的句子组成的,句子是由单词符号按一定的规则构成的,而单词符号又是由字符按一定规则构成,因此,源程序实际上是由满足程序语言规范的字符按照一定的规则组合起来构成的一个字符串。

 2、词法分析的功能是从左到右逐个地扫描源程序字符串,按照词法规则识别出 单词符号作为输出,对识别过程中发现的词法错误,输出相关信息。

 3、单词符号是程序语言最基本的语法符号,为便于语法分析,通常将单词符号分为五类(标识符,基本字,常数,运算符,界符),而本次实验中单词符号与其对应的种别如下图所示:

  4、状态转换图是有限有向图,是设计词法分析器的有效工具。图中的节点代表状态,节点间的有向边代表状态之间的转换关系,有向边上标记的字符表示状态转换的条件。本实验中的状态转换图如下图所示:

 5、本程序所设计主要方法及作用如下:

 ① int isletter(char c)

  判别字符 c 是否为字母 ② int isdigital(char c) 判别字符 c 是否为数字

 ③ int match_reserve(char *p)

  匹配字符串 p 是否为保留字 ④ void match_symbol(const char *p)

 匹配字符串 p 是否为标识符

 ⑤ void match_double_operator(char *p)

 匹配字符串 p 是否为双运算符 ⑥ void match_single_operator(char *p)

 匹配字符串 p 是否为单运算符 ⑦ void outfile()

 将词法分析所得的二元式按固定格式写入文件 out.dyd

 五、 实验器材(设备、元器件)

  C 语言+windows7+CodeBlocks+gcc 六、 实验步骤:

 1、将源程序保存到 in.pas 文件中; 2、从 in.pas 文件中读取字符串保存到 buf 数组,若整个输入文件已读取完毕,程序结束; 3、每次从 buf 数组中读入一个字符,若已读到 buf 最后一个字符,返回第 2 步继续执行; 3-a

 如果该字符是字母或数字将其连接到 temp 字符串尾部,buf 索引 index 加 1,判断 buf[index]是否为 0,若为 0 说明 temp 字符串为一完整单词,跳到第 4 步执行;若不为 0,继续执行第 3 步; 3-b 如果读入的不是字母/数字,首先判断并匹配 temp 中是否已出现保留字/标识符,如果没有,通过预读 buf 中的下一个字符来进一步判断 temp 中存放的是单运算符还是双运算符或换行符,最终写入相应二元式,返回第 3 步继续执行; 4、判断 temp 字符串是否为保留字,若不是保留字,进一步判断它是标识符还是常量,最终生成相应二元式,返回第 3 步继续执行;

 【注】

 这里省略了对于非法字符的出错处理

 七、 实验数据及结果 分析:

 1、 测试程序如图,在测试程序中故意添加了一些词法错误如:将保留字写成 beg

 in,常数 1kkk,符号 !=,用于检测本实验程序的查错能力;

 2、 程序运行完毕,得到 out.dyd 文件,内容如图所示:

  3、 报错文件 error.err 内容如图:

 由上图可以看出,本词法分析程序,可以识别部分非法的常数以及字母表以外的非法字符,但对于将 begin 写成 beg

 in 这一类的词法错误,并未做处理,而是将其放到语法分析的部分来处理。

  八、 实验结论、心得体会和改进建议:

 1、本词法分析程序可以正确的按照给定的文法识别出源程序中的单词符号及其对应的种别并生成相应的二元式文件,并具有一定的处理错误信息的能力;

 2、由实验结果截图可以看到,本实验仅能对一部分的词法错误作出响应,而一个完整的词法分析程序还应该能够识别出如标识符前缀为保留字等错误,并且错误信息文件.err 中还应该包括行号,所以还可以对本实验进行改进; 3、通过本次实验,我设计并实现了一个简单的词法分析器,在这个过程中加深了我对于词法分析的原理及其过程的理解,而对于词法错误的处理也在一定程度上提高了我的编程能力。

 实验代码如下:

 #include <stdio.h> #include <string.h> #include<stdlib.h>

 #define BEGIN 1 #define END 2 #define INTEGER 3 #define IF 4 #define THEN 5 #define ELSE 6 #define FUNCTION 7 #define READ 8 #define WRITE 9 #define SYMBOL 10

 //标识符 #define CONSTANT 11

 //常数 #define EQ 12

  //= #define NE 13

 //<> #define LE 14

  //<= #define LT 15

 //< #define BE 16

  //>= #define BT 17

  //> #define SUB 18

 //- #define MUL 19

 //* #define ASSIGN 20

 //:= #define LBRAC 21

 //( #define RBRAC 22

 //) #define SEM 23

 //;

 #define BUFLEN 50 #define TEMPLEN 2*BUFLEN

 int type=0; char val[TEMPLEN];

 FILE *infile;

  //.pas FILE *outfile;

 //.dyd FILE *errfile;

  //.err

 char buf[BUFLEN];

 //读入缓冲区 char temp[TEMPLEN]; char reserve[2];

  /******判别是否字母*****/ int isletter(char c) {

  if(((c>="a")&&(c<="z"))||((c>="A")&&(c<="Z")))

  return 1;

  else

  return 0; }

 /********判别是否数字********/ int isdigital(char c) {

  if(c>="0"&&c<="9")

  return 1;

  return 0; }

 /********匹配保留字******/ int match_reserve(char *p) {

  memset(val,0,TEMPLEN);

 if(!(strcmp(p,"begin")))

 {

 type=BEGIN;

  strcpy(val,"begin");

  to_outfile();

  return 1;

  }

  else if(!(strcmp(p,"end")))

 {

 type=END;

  strcpy(val,"end");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"integer")))

 {

 type=INTEGER;

  strcpy(val,"integer");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"if")))

 {

 type=IF;

 strcpy(val,"if");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"then")))

 {

 type=THEN;

  strcpy(val,"then");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"else")))

 {

 type=ELSE;

  strcpy(val,"else");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"function")))

 {

 type=FUNCTION;

  strcpy(val,"function");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"read")))

 {

 type=READ;

  strcpy(val,"read");

  to_outfile();

  return 1;

  }

 else if(!(strcmp(p,"write")))

 {

 type=WRITE;

  strcpy(val,"write");

  to_outfile();

  return 1;

  }

  else

  return 0; }

 /**********匹配标识符**********/

 void

 match_symbol(const char *p,int len) {

  //以字母开头,是标识符

  if(isletter(p[0]))

  {

  type=SYMBOL;

 strcpy(val,p);

  to_outfile();

  }

 //

 不是以字母开头的是常数

 else if(isdigital(p[0]))

 {

  type=CONSTANT;

  strcpy(val,p);

  to_outfile();

  int i;

  for (i=1;i<strlen(val);i++)

  {

  if(isletter(val[i]))

  fprintf(errfile,"标识符%s不正确\n",val);

  break;

  }

  }

  //

 不是以字母开头也不是以数字开头的报错

  else

 {

  strcpy(val,p);

  to_outfile();

  fprintf(errfile,"标识符%s不正确\n",val);

 } }

 /********匹配双运算符********/ void match_double_operator(char *p) {

 if(!(strcmp(p,":=")))

 {

 type=ASSIGN;

  strcpy(val,":=");

  to_outfile();

  }

 else if(!(strcmp(p,"<>")))

 {

 type=NE;

  strcpy(val,"<>");

  to_outfile();

  }

  else if(!(strcmp(p,"<=")))

 {

 type=LE;

  strcpy(val,"<=");

  to_outfile();

  }

 else if (!(strcmp(p,">=")))

 {

 type=BE;

  strcpy(val,">=");

  to_outfile();

  }

 else

 {

  strcpy(val,p);

  to_outfile();

  fprintf(errfile,"运算符%s不正确\n",val);

 } }

 /**********匹配单个运算符********/ void match_single_operator(char *p) {

 if(!(strcmp(p,"<")))

 {

 type=LT;

  strcpy(val,"<");

  to_outfile();

  }

  else if(!(strcmp(p,">")))

 {

 type=BT;

  strcpy(val,">");

  to_outfile();

  }

 else if(!(strcmp(p,"-")))

 {

 type=SUB;

  strcpy(val,"-");

  to_outfile();

  }

 else if(!(strcmp(p,"*")))

 {

  type=MUL;

  strcpy(val,"*");

  to_outfile();

  }

 else if(!(strcmp(p,"=")))

 {

 type=EQ;

  strcpy(val,"=");

  to_outfile();

  }

 else if(!(strcmp(p,"(")))

 {

 type=LBRAC;

  strcpy(val,"(");

  to_outfile();

  }

 else if(!(strcmp(p,")")))

 {

 type=RBRAC;

  strcpy(val,")");

  to_outfile();

  }

  else if(!(strcmp(p,";")))

 {

 type=SEM;

  strcpy(val,";");

  to_outfile();

  }

  else if (!(strcmp(p," ")))

  {

  //如果是空格空操作

  }

 else

 {

  strcpy(val,p);

  to_outfile();

  fprintf(errfile,"运算符%s不正确\n",val);

 } }

  void to_outfile() {

  fprintf(outfile,"%16s %02d\n",val,type); }

 int main(int argc,char *argv[]){

  int index=0;

 //指针指向缓存数组

  int length=0;

  //非运算符(标识符)数组长度

  memset(temp,0,TEMPLEN);

  if((infile=fopen("in.pas","r+"))==NULL)

 /*打开in.pas*/

  {

 printf("Source file cannot be opened\n");

 exit(1);

  }

 if(!(outfile=fopen("out.dyd","w+")))

 /*打开out.dyd*/

  {

 printf("Destination file cannot be opened\n");

 exit(1);

 }

  if(!(errfile=fopen("error.err","w+")))

 /*打开error.err*/

  {

 printf("Destination file cannot be opened\n");

 exit(1);

 }

  /***********读字符串并判断**********/

  while (!feof(infile)){

  memset(buf,0,BUFLEN);

  index = 0;

  fgets(buf,BUFLEN,infile);

  printf("%s",buf);

  if(buf[0]==0){

 break;

  }

  /*******遍历buf数组对读入的字符逐个判断*********/

  while((index<BUFLEN)&&(buf[index]!=0)){

  memset(reserve,0,2);

 /******若读入的是字母或数字*******/

 if((isletter(buf[index]) == 1)||(isdigital(buf[index]) == 1)){

  length++;

  reserve[0]=buf[index];

  strcat(temp,reserve);

  //注意这里tail[1]=0 保证temp是完整字符串

  index++;

  if(buf[index]==0){

  /****匹配保留字****/

 if(temp[0]!=0){

  int fm=match_reserve(temp);

  /**若不是保留字(fm==0),判断是标识符还是常量*/

  if(fm==0){

 match_symbol(temp,length);

  }

  memset(temp,0,TEMPLEN);

  memset(reserve,0,2);

  length=0;

 }

  }

 }

  /****读入的是运算符or界符***/

 else{

 /**首先判断temp中是否已出现一个单词*/

  if(temp[0]!=0){

 int fm=match_reserve(temp);

 //先判断是否为保留字

  if(fm==0){

 match_symbol(temp,length);

 }

  memset(temp,0,TEMPLEN);

 //将temp,length和tail清零

  length=0;

  }

  /**是否为双操作符 ":=" | "<=" | ">=" | "<>" */

  if(((buf[index]==":")&&(buf[index+1]=="="))||((buf[index]=="<")&&(buf[index+1]=="="))||((buf[index]==">")&&(buf[index+1]=="="))||((buf[index]=="<")&&(buf[index+1]==">"))){

 reserve[0]=buf[index];

 reserve[1]=buf[index+1];

 match_double_operator(reserve);

 index += 2;

  }

  /**如果是换行符写入EOLN 24*/

  else if (buf[index]=="\n"){

  fprintf(outfile,"

 EOLN 24\n");

  index += 1;

  }

  /**不是双操作符,判断是否为单操作符*/

  else{

 reserve[0]=buf[index];

 match_single_operator(reserve);

 index++;

  }

  memset(reserve,0,2);

 }

  }

  memset(buf,0,BUFLEN);

  //buffer清零

  }

  fprintf(outfile,"

  EOF 25");

 return 0;

 }

 电 电 子 科 技 大 学 学

 实 实

  验

  报

  告 实验二 一、 实验名称:

 递归下降词法分析器的设计与实现 二、 实验学时:4 三、 实验内容和目的:

 实验内容:

 根据给定的方法,编写相应的递归下降的语法分析程序,实现对词法分析后的单词序列的语法检查和程序结构的分析,生成相应的变量名表和过程名表,并将编译中语法检查出来的错误写入相应的文件。

 语法错分类:

 (1) 缺少符号错;

 (2) 符号匹配错

 (3) 符号无定义或重复定义。

 变量名表内容:

 变量名 vname: char(16) 所属过程 vproc:char(16) 分类 vkind: 0..1(0—变量、1—形参) 变量类型 vtype: types 变量层次 vlev: int

 变量在变量表中的位置 vadr: int(相对第一个变量而言) 过程名表内容:

 过程名 pname: char(16) 过程类型 ptype: types

 过程层次 plev: int

 第一个变量在变量表中的位置 fadr: int

 最后一个变量在变量表中的位置 ladr: int

 实验目的:

  通过设计并实现一个递归下降语法分析器,了解和掌握语法分析程序设计的原理及相应的程序设计方法,同时提高编程能力。

 四、 实验原理:

 1、语法分析是对源程序经过词法分析后转换成的单词流按方法规则进行判断,对能构成正确句子的单词流,给出相应的语法树;对不能构成正确句子的单词流判断其语法错误并做出相应处理。

 2、语法分析方法有自上而下和自下而上的分析方法。在不含左递归的文法 G 中,如果对每一个非终结符的所有候选式的第一个终结符都是两两不相交的(即无公共左因子),则可能构造出一个不带回溯的自上而下的分析程序,这个分析程序由一组递归过程组成,每个过程对应文法的一个非终结符。这样的分析程序称为递归下降分析程序。要使用递归下降分析法,我们必须先消除文法的左递归和提取公共左因子,消除左递归的方法如图:

 4、 本实验中程序语言的文法如下:

  <程序>→<分程序> <分程序>→begin <说明语句表>;<执行语句表> end <说明语句表>→<说明语句>│<说明语句表> ;<说明语句> <说明语句>→<变量说明>│<函数说明>

 <变量说明>→integer <变量> <变量>→<标识符> <标识符>→<字母>│<标识符><字母>│ <标识符><数字> <字母>→a│b│c│d│e│f│g│h│i│j│k│l│m│n│o│p│q│r│s│t│u│v│w│x│y│z

 <数字>→0│1│2│3│4│5│6│7│8│9 <函数说明>→integer function <标识符>(<参数>);<函数体> <参数>→<变量> <函数体>→begin <说明语句表>;<执行语句表> end <执行语句表>→<执行语句>│<执行语句表>;<执行语句> <执行语句>→<读语句>│<写语句>│<赋值语句>│<条件语句> <读语句>→read(<变量>) <写语句>→write(<变量>) <赋值语句>→<变量>:=<算术表达式> <算术表达式>→<算术表达式>-<项>│<项> <项>→<项>*<因子>│<因子> <因子>→<变量>│<常数>│<函数调用> <常数>→<无符号整数> <无符号整数>→<数字>│<无符号整数><数字> <条件语句>→if<条件表达式>then<执行语句>else <执行语句> <条件表达式>→<算术表达式><关系运算符><算术表达式> <关系运算符> →<│<=│>│>=│=│<>

 5、 本程序所设计的主要数据结构及方法如下:

 :

 方法:

 ① void addVar(char var_name[])

 添加变量到变量名表,若变量重复定义则报错; ② void addProc(char proc_name[]) 添加过程到过程名表; ③ int findVar(char var_name[])

 查找变量名表中变量是否已存在,主要用于查重; ④ int findProc(char proc_name[]) 查找过程名表中过程是否已存在; ⑤ void advance()

  从 out.dyd 中读取一行获取一个单词符号及其种别; ⑥ void error(int type)

 向 error.err 文件中写入对应的报错信息; ⑦ void S() 代表 <程序>→begin <说明语句表>;<执行语句表> end 中的<程序>; ⑧ void A()

  <说明语句表> ⑨ void A_STAR()

 <说明语句表>→<说明语句>│<说明语句表> ;<说明语句>消除左递归后出现的 A*,即<说明语句表*>; ⑩ int C()

  <说明语句>; ⑪ void H()

  <标识符>

 ⑫void E()

 <函数体>

 ⑬void B()

 <执行语句表> ⑭void Z()

 <执行语句> ⑮void J()

 <算术表达式> ⑯void X()

 <项> ⑰void Y()

 <因子> ⑱void K()

 <条件表达式> ⑲void P()

 <关系运算符> ⑳int main()

 主函数 还有 X_STAR()、B_STAR()与 J_STAR()都是对应的文法消除左递归以后新出现的非终极符 构 数据结构:

 struct variable var_table[10];

  //变量名表 struct procedure proc_table[10];

  //过程名表 struct variable{

 //变量结构体

  char vname[16];

  char vtype[10];

 int vadr;

  char vproc[16];

  int vlev; } ; struct procedure{

 //过程结构体

  char pname[16];

  char ptype[10];

  int plev,fadr,ladr; } ;

 五、 实验器材(设备、元器件)

 C 语言+windows7+CodeBlocks+gcc 六、 实验步骤:

 1 、 化简、提取公共左因子和消除左递归后的文法如下:

 <程序>→begin <说明语句表>;<执行语句表> end <说明语句表>→<说明语句><说明语句表*>

 //消除左递归 <说明语句表*>→;<说明语句><说明语句表*>|ε <说明语句>→integer<标识符或函数体>

 //提取公共左因子 <标识符或函数体>→<标识符>│function <标识符>(<标识符>);<函数体> <函数体>→begin <说明语句表>;<执行语句表> end <执行语句表>→<执行语句><执行语句表*>

  //消除左递归 <执行语句表*>→;<执行语句><执行语句表*>|ε <执行语句>→read(<标识符>)│write(<标识符>)│<标识符>:=<算术表达式>│if<条件表达式>then<执行语句>else <执行语句> <算术表达式>→<算术表达式>-<项>│<项> <项>→<因子><项*>

  //消除左递归 <项*>→*<因子><项*>|ε <因子>→<标识符>│<常数>│<函数调用> <常数>→<数字>│<无符号整数><数字> <条件表达式>→<算术表达式><关系运算符><算术表达式> <关系运算符> →<│<=│>│>=│=│<>

 【注】

 由于标识符可由词法分析阶段得到的二元式判断,所以在文法中将其推导省略

 2 、 用简单的英文字符替换中文后得文法如下:

 <S>→begin <A>;<B> end <A>→<C><A*>

  <A*>→;<C><A*>|ε <C>→integer <H> <H>→<I>│integer function <I>(<I>);<E> <I>→<L><I*>

  <I*>→<G><I*>|<G> <E>→begin <A>;<B> end <B>→<Z><B*>

 <B*>→;<Z><B*>|<Z> <Z>→read(<I>)│write(<I>)│<I>:=<J>│if<K>then<Z>else <Z> <J>→<X><J*>

  <J*>→ -<X><J*>|ε <X>→<Y><X*>

 <X*>→ε|*<Y><X*> <Y>→<I>│<O>│<G> <K>→<J><P><J> <P>→<│<=│>│>=│=│<> 3 、 程序主要流程:

 从 out.dyd 中读取待匹配的单词符号保存到 sym 中,用构造的递归下降分析器匹配该单

 词符号,若匹配成功,继续读取下一单词符号;若匹配失败,向错误文件 error.err 中写入相应的出错信息,继续读取下一单词符号,直到所有未匹配符号皆处理完毕。

 七、 实验数据及结果分析:

 1、 测试程序如图所示,所包含的语法错误有:错误的保留字 integr 和 beginnnnn,重复定义的标识符 k,不匹配的括号 read(m;,以及最后一行缺少了end 关键字;

  2、 错误信息文件 error.err 的内容如图:

 由上图可以看到测试程序中的 5 处错误都正确的识别出来,并且虽然源测试程序的第 3行和第 6 行的都是 integer k;但语法分析程序并没有报重复定义的错,说明本实验程序还可以识别不同层次的重复定义。

 本实验程序把 F 和 m 也当做未定义的变量,这里我个人认为按照惯例 F 和 m 还是应该定义一下,直接拿来使用不符合我们一般的编程习惯,但是 error.err 的 8、9、11、12 行对于已经报过错的变量 F 和 m 又报了一次未定义错误,感觉有一些啰嗦,可以改进一下本程序让它不要重复报错。

 八、 实验结论、心得体会和改进建议:

 1、 一开始本实验程序对于缺少分号的错误不能正确处理,这个问题一直困扰着 我,后来我发现这是由于文法<程序>→begin <说明语句表>;<执行语句表> end 中当说明语句表只有一条说明语句时,递归下降分析器并不能判定这条说明语句的接下来的一条语句到底是一条执行语句还是仍然是一条说明语句,所以在函数体 A_STAR 中需要增加一段程序判断一下下一条语句是不是执行语句,若是执行语句,由于当只有一个说明语句时,执行语句之前的那个分号已经被说明语句表匹配,所以这是需要回退一步(back),sym 重新取一次分号,让执行语句表之前的分号得以匹配;

 2、本实验中的过程表不是很完整,我只处理了过程名以及其对应的层次和类型,对于实验中要求的 fadr,ladr 并未做相应处理,这点值得改进;

 3、如果把第 2 行或第 7 行的 integer 改为 integr,将会使得程序由于无法判断这条语句到底是说明语句还是执行语句而无法正确执行,其实这个问题还是出在说明语句表和执行语句表之间的界限不清楚,我现在还没有想出一个很好的方法来解决这个问题;

 4、 实验一 一开始的时候我根本不知道语法分析应该报哪些错,对于词法分析应不应该报错也不了解,但是通过第 13 周的实验程序的检查和自己慢慢的调试,我逐渐加深了对于词法分析、语法分析的过程的理解,虽然这个程序的功能也不是很完善,但是自己动手编写递归下降分析器的这个过程确实使我对于编译的原理有了更深入的掌握;

  实验代码如下:

 #include <stdio.h> #include <stdlib.h> #include <string.h>

 #define MISSINGSEM

  1

 //缺少分号错误 #define MISSINGEND

  2

 //缺少end #define MISSINGBEGIN

 3

 //缺少begin #define MISSINGTYPE

  4

  //缺少类型定义 #define MISSINGRBRAC

 5

  //缺少右括号 #define MISSINGLBRAC

 6

  //缺少左括号 #define MISSINGPARA

 7

  //缺少参数 #define MISSINGFUCNAME

 8//缺少函数名称 #define MISSINGFUC

  9

 //缺少function关键字 #define MISSINGOP

  10

 //缺少操作符 #define MISSINGELSE

  11

 //缺少else #define MISSINGTHEN

  12

 //缺少then #define MISSINGVAR

 13

  //缺少变量名 #define UndefinedVar

  14

  //变量未定义 #define RepeatDefine

  15

 //变量重复定义

 FILE *infile; FILE *errfile; char *t; char sym[16]; int id; int lineNum = 1; int var_len= 0; int proc_len = 0; int level = 0;

 /**变量名表*/ struct variable {

  char vname[16];

 char vtype[10];

  //ints

  int vadr;

  //char vproc[16];

  int vlev; } ;

 /**过程名表*/ struct procedure {

  char pname[16];

  char ptype[10];

 // int plev,fadr,ladr; } ;

 struct variable var_table[10]; struct procedure proc_table[10];

 /**添加变量到变量名表*/ void addVar(char var_name[16]) {

  if (findVar(var_name))

 error(RepeatDefine);

  else

  {

  printf(" 添加到变量名表%s\n",var_name);

  strcpy(var_table[var_len].vname,var_name);

  strcpy(var_table[var_len].vtype,"integer");

  var_table[var_len].vlev = level;

  var_table[var_len].vadr = 4*var_len;

  var_len++;

  } }

 /**添加过程到过程名表*/ void addProc(char proc_name[16]) {

  printf(" 添加到过程名表%s\n",proc_name);

  strcpy(proc_table[proc_len].pname,proc_name);

  strcpy(proc_table[proc_len].ptype,"integer");

  proc_len++; }

 /**在变量名表中查找变量是否存在*/ int findVar(char var_name[16]) {

  printf("查找变量%s

  \n",var_name);

  int finded = 0,i = 0;

  for (i = 0;i < var_len+1;i++){

 if ((!strcmp(var_table[i].vname,var_name))&&(var_table[i].vlev==level))

  {

  finded = 1;

  printf("var_table[i].vname %s\n",var_table[i].vname);

  break;

  }

  }

  if (!finded)

 printf("没找到!\n");

  return finded; }

 /**在过程名表中查找过程是否存在*/ int findProc(char proc_name[16]) {

  int finded = 0,i = 0;

  for (i = 0;i < proc_len+1;i++){

  if (!strcmp(proc_table[i].pname,proc_name)){

 finded = 1;

 break;

  }

  }

  return finded; }

 /**if id == 25

 文件读取完毕!*/ void advance() {

  char line[21];

  if(!feof(infile))

  {

  fgets(line,21,infile);

  line [19] = "\0";

  //去掉换行符\n

  char *buf = line;

  t = strtok(buf," ");

 //使用strtok进行字符串分割

  buf = NULL;

  id = atoi(strtok(buf," "));

  strcpy(sym,t);

  printf("line%d: sym=%s,id=%d\n",lineNum,sym,id);

  if (id == 24){

  //如遇到EOLN,行号+1继续读取下一个字符串

  lineNum++;

  advance();

  }

  } }

  void back() {

  printf("back!!!!!!!!!!!!\n");

  fseek(infile,-60,1);

  lineNum --;

  advance(); }

 void error(int type) {

  switch(type) {

  case 1: fprintf(errfile,"LINE %02d:

  missing ";" here. \n",lineNum);break;

  case 2: fprintf(errfile,"LINE %02d:

  missing "end" here. \n",lineNum);break;

  case 3: fprintf(errfile,"LINE %02d:

  missing "begin" here. \n",lineNum);break;

  case 4: fprintf(errfile,"LINE %02d:

  缺少类型定义关键字,%s不是保留字\n",lineNum,sym);break;

  case 5: fprintf(errfile,"LINE %02d:

  missing ")" here. \n",lineNum);break;

  case 6: fprintf(errfile,"LINE %02d:

  missing "(" here. \n",lineNum);break;

  case 7: fprintf(errfile,"LINE %02d:

  缺少参数. \n",lineNum);break;

  case 8: fprintf(errfile,"LINE %02d:

  缺少函数名 \n",lineNum);break;

  case 9: fprintf(errfile,"LINE %02d:

  缺少function关键字. \n",lineNum);break;

  case 10: fprintf(errfile,"LINE %02d:

  缺少操作数. \n",lineNum);break;

  case 11: fprintf(errfile,"LINE %02d:

  missing "else" here. \n",lineNum);break;

  case 12: fprintf(errfile,"LINE %02d:

  missing "then" here. \n",lineNum);break;

  case 13: fprintf(errfile,"LINE %02d:

  缺少变量名. \n",lineNum);break;

  case 14: fprintf(errfile,"LINE %02d:

  变量%s未定义. \n",lineNum,sym);break;

  case 15:fprintf(errfile,"LINE %02d:

  变量%s重复定义. \n",lineNum,sym);break;

  default: fprintf(errfile,"LINE %02d:

  unknown error \n",lineNum);

  } }

 /*<程序>→begin <说明语句表>;<执行语句表> end*/ void S() {

  if (!strcmp(sym,"begin"))

 {

  advance();

  A();

  printf("函数体定义完end,进入执行语句表\n");

  if (!strcmp(sym,";"))

  {

  advance();

  B();

  if (!strcmp(sym,"end"))

  {

  advance();

  }

  else error(MISSINGEND);

 //缺少end

  }

  else

 error(MISSINGSEM);

  //缺少分号报错

  }

  else

  {

  error(MISSINGBEGIN);

 //缺少begin

  advance();

  A();

  printf("函数体定义完end,进入执行语句表\n");

  if (!strcmp(sym,";"))

  {

  advance();

  B();

  if (!strcmp(sym,"end"))

  {

  advance();

  }

  else error(MISSINGEND);

 //缺少end

  }

  else

 error(MISSINGSEM);

  //缺少分号报错

  }

  printf("*************Done!************\n"); }

 /*<说明语句表>→<说明语句>│<说明语句表> ;<说明语句>*/ /**需要注意当只有一个说明语句时,由于执行语句之前也有一个分号,所以分号已经被匹配!*/ void A() {

 printf("

 sym = %s\n",sym);

 printf("call A!\n");

 C();

 //说明语句

  A_STAR();

  //;说明语句 } void A_STAR() {

  int isC = 0;

  printf("

 sym = %s\n",sym);

  printf("call A_STAR!\n");

  if (!strcmp(sym,";"))

  {

  advance();

  /**注意这里需判断一下下一条是不是执行语句*/

  if (!strcmp(sym,"if")|!strcmp(sym,"read")|!strcmp(sym,"write")|(id == 10))

  {

  printf("下一条是执行语句!!!说明语句完\n");

  back();

 //如果下一条是执行语句,需回退一步,继续取分号

  return;

  }

 C();

  A_STAR();

  }

  else error(MISSINGSEM); }

 /*<说明语句>→integer <标识符>│integer function <标识符>(<标识符>);<函数体>*/ int C() {

  printf("

 sym = %s\n",sym);

  printf("call C!\n");

  if (!strcmp(sym,"integer"))

  {

  advance();

  H();

  return 1;

  }

  else

  {

  error(MISSINGTYPE);

  advance();

  H();

  return 0;

  } } void H() {

  printf("

 sym = %s\n",sym);

 printf("call H!\n");

  if (id == 10)

  //如果是标识符

  {

  addVar(sym);

 //加入变量表

 advance();

  }

  else if (!strcmp(sym,"function"))

  {

  advance();

  if (id == 10)

  {

  addProc(sym);

 //加入过程表

  advance();

  if (!strcmp(sym,"("))

  {

  advance();

  if (id == 10)

  {

  advance();

  if (!strcmp(sym,")"))

  {

  advance();

  if (!strcmp(sym,";"))

  {

  advance();

  E();

  }

  else error(MISSINGSEM);

 //缺少分号

  }

  else error(MISSINGRBRAC);

 //缺少右括号

  }

  else error(MISSINGPARA);

 //缺少参数

  }

  else error(MISSINGLBRAC);

 //缺少左括号

  }

  else

 error(MISSINGFUCNAME);

 //缺少函数名称

  }

  else error(MISSINGVAR);

 //缺少变量名 }

 /*<函数体>→begin <说明语句表>;<执行语句表>end*/ void E() {

 printf("

 sym = %s\n",sym);

  printf("call E!\n");

  if (!strcmp(sym,"begin"))

  {

  level++;

  advance();

  A();

  if (!strcmp(sym,";"))

  {

  advance();

  B();

  if (!strcmp(sym,"end"))

 //注意这里在执行语句表后面增加了一个分号

  {

  advance();

  }

  else error(MISSINGEND);

  }

  else error(MISSINGSEM);

  }

  else

  {

  level++;

  error(MISSINGBEGIN);

  advance();

  A();

  if (!strcmp(sym,";"))

  {

  advance();

  B();

  if (!strcmp(sym,"end"))

 //注意这里在执行语句表后面增加了一个分号

  {

  advance();

  }

  else error(MISSINGEND);

  }

  else error(MISSINGSEM);

  } }

 /*<执行语句表>→<执行语句>│<执行语句表>;<执行语句>*/ void B() {

  printf("

 sym = %s\n",sym);

  printf("call B!\n");

  Z();

  B_STAR(); }

 void B_STAR() {

  printf("

 sym = %s\n",sym);

  printf("call B_STAR!\n");

  if (!strcmp(sym,";"))

  {

  advance();

  Z();

  B_STAR();

  }

  else if (!strcmp(sym,"end")|!strcmp(sym,"EOF"));

  //最后一个执行语句无分号

  else error(MISSINGSEM); }

 /*<执行语句>→read(<标识符>)│write(<标识符>)│<标识符>:=<算术表达式>│if<条件表达式>then<执行语句>else <执行语句>*/ void Z() {

  printf("

 sym = %s\n",sym);

  printf("call Z!\n");

  if (!strcmp(sym,"read"))

  {

  advance();

  if (!strcmp(sym,"("))

  {

  advance();

  if (id == 10)

  {

  /*查变量表,如果不存在,则该变量未定义*/

  if (!findVar(sym))

 error(UndefinedVar);

  advance();

  if (!strcmp(sym,")")) advance();

  else

 error(MISSINGRBRAC);

  }

  else error(MISSINGPARA);

  }

  else error(MISSINGLBRAC);

  }

  else if (!strcmp(sym,"write"))

  {

  advance();

  if (!strcmp(sym,"("))

  {

  advance();

 if (id == 10)

  {

  int finded = findVar(sym);

  if (!finded)

 error(UndefinedVar);

  advance();

  if (!strcmp(sym,")")) advance();

  else

 error(MISSINGRBRAC);

  }

  else error(MISSINGPARA);

  }

  else error(MISSINGLBRAC);

  }

  else if (id == 10)

  {

  int finded = findVar(sym);

  if (!finded)

 error(UndefinedVar);

  advance();

  if (!strcmp(sym,":="))

  {

  advance();

  J();

  }

  else error(MISSINGOP);

  }

  else if(!strcmp(sym,"if"))

  {

  advance();

  K();

  if (!strcmp(sym,"then"))

  {

  advance();

  Z();

  if (!strcmp(sym,"else"))

  {

  advance();

  Z();

  }

  else error(MISSINGELSE);

  }

  else error(MISSINGTHEN);

  } }

 /*<算术表达式>→<算术表达式>-<项>│<项>*/ void J() {

  printf("call J!\n");

 X();

  J_STAR(); } void J_STAR() {

  printf("call J_STAR!\n");

  if (!strcmp(sym,"-"))

  {

  advance();

  X();

  J_STAR();

  } }

 /*<项>→<项>*<因子>│<因子>*/ void X() {

  printf("call X!\n");

  Y();

  X_STAR(); } void X_STAR() {

  printf("call X_STAR!\n");

  if (!strcmp(sym,"*"))

  {

  advance();

  Y();

  X_STAR();

  } }

 /*<因子>→<标识符>│<常数>│<函数调用>*/ void Y() {

  printf("call Y!\n");

  if(id == 10)

  //标识符

  {

  printf("

 Y() sym = %s\n",sym);

  if (!findVar(sym)&&!findProc(sym))

 error(UndefinedVar);

  advance();

  // 函数调用

 F(n)

  if (!strcmp(sym,"("))

  {

 advance();

  J();

  if (!strcmp(sym,")"))

 advance();

  else

 error(MISSINGRBRAC);

  }

  }

  else if (id ==11)

  // 常量

  {

  advance();

  } }

 /*<条件表达式>→<算术表达式><关系运算符><算术表达式>*/ void K() {

  printf("call K!\n");

  J();

  P();

  J(); }

 /*<关系运算符>→<│<=│>│>=│=│<>*/ void P() {

  printf("call P!\n");

  if (!strcmp(sym,"<")|!strcmp(sym,"<=")|!strcmp(sym,">")|!strcmp(sym,">=")|!strcmp(sym,"=")|!strcmp(sym,"<>"))

  {

  advance();

  }

  else error(MISSINGOP); }

 int main() {

  /*打开out.dyd*/

  if((infile=fopen("out.dyd","r+"))==NULL)

  {

 printf("Source file cannot be opened\n");

 exit(1);

  }

  /*打开error.err*/

  if((errfile=fopen("error.err","w+"))==NULL)

  {

 printf("Source file cannot be opened\n");

 exit(1);

 }

  t = (char *)malloc(20*sizeof(char));

  advance();

  S();

  fclose(infile);

  fclose(errfile);

  return 0; }

推荐访问:词法 分析 编译
上一篇:【精品】年级组长年终工作总结
下一篇:心得体会,学习雷锋心得体会300字

Copyright @ 2013 - 2018 优秀啊教育网 All Rights Reserved

优秀啊教育网 版权所有