编译原理实验词法分析实验报告

  编译技术实验报告

 实验题目:

 词 词 法分析

 学 学

 院:

 信息学院

 专 专

 业:

 计算机科学与技术

 学 学

 号:

  姓 姓

 名:

 一、 实验目的

 (1) 理解词法分析的功能;

 (2) 理解词法分析的实现方法;

  二 、 实验内容

 PL0 的文法 如下

 „< >‟为非终结符。

 „::=‟ 该符号的左部由右部定义,可读作“定义为”。

 „|‟ 表示„或‟,为左部可由多个右部定义。

 „{ }‟ 表示花括号内的语法成分可以重复。在不加上下界时可重复0到任意次数,有上下界时可重复次数的限制。

 „[ ]‟ 表示方括号内的成分为任选项。

 „( )‟ 表示圆括号内的成分优先。

 上述符号为“元符号”, 文法用上述符号作为文法符号时需要用引号„‟括起。

  〈程序〉∷=〈分程序〉.

 〈分程序〉∷= [〈变量说明部分〉][〈过程说明部分〉]〈语句〉

 〈变量说明部分〉∷=VAR〈标识符〉{,〈标识符〉}:INTEGER;

 〈无符号整数〉∷=〈数字〉{〈数字〉}

 〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉}

 〈过程说明部分〉∷=〈过程首部〉〈分程序〉{;〈过程说明部分〉};

 〈过程首部〉∷=PROCEDURE〈标识符〉;

 〈语句〉∷=〈赋值语句〉|〈条件语句〉|〈过程调用语句〉|〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉

 〈赋值语句〉∷=〈标识符〉∶=〈表达式〉

 〈复合语句〉∷=BEGIN〈语句〉{;〈语句〉}END

 〈条件〉∷=〈表达式〉〈关系运算符〉〈表达式〉

 〈表达式〉∷=〈项〉{〈加法运算符〉〈项〉}

 〈项〉∷=〈因子〉{〈乘法运算符〉〈因子〉}

 〈因子〉∷=〈标识符〉|〈无符号整数〉|"("〈表达式〉")"

 〈加法运算符〉∷=+|-

 〈乘法运算符〉∷=*

 〈关系运算符〉∷=<>|=|<|<=|>|>=

 〈条件语句〉∷=IF〈条件〉THEN〈语句〉

 〈字母〉∷=a|b|…|X|Y|Z

 〈数字〉∷=0|1|2|…|8|9

  现 实现 PL0 的 的 词法分析

 三 、 实验 分析与设计

 PL0 词法分析程序是一个独立的过程,其功能是为语法语义分析提供单词,把输入的字符串形式的源程序分割成一个个单词符号传递给语

 法语义分析。

 其主要方法步骤为从源程序扫描下一个字符,忽略空格、换行、TAB和注释并识别单词,再将不同类别的单词归类输出。

  四 、实验 的 实现

 #include <stdio.h>

 #include<stdlib.h>

 #include<string.h>

 #include<ctype.h>

 #include<stdbool.h>

  #definenorw 11

 //norw-1个关键字

 #defineal 20

 //最长的关键字的长度

 #define ID norw

 #define INT norw+1

 #define COMMA norw+2

 #define ENDF norw+3

 #define COLON norw+4

 #define SEMIC norw+5

 #define ADD norw+6

 #define MINUS norw+7

 #define MULTI norw+8

 #define EVALU norw+9

 #define LE norw+10

 #define NE norw+11

 #define LT norw+12

 #define EQ norw+13

 #define GE norw+14

 #define GT norw+15

 #define FLOAT norw+16

  char TOKEN[20];

 //字符数组用来依次存放单词词文的各个字符

 extern int lookup(char *);

  //以TOKEN字符串查保留字表

 extern void report_error(char);

 //报告程序中的词法错误

 bool isalpha(char);

 //判断接收字符是否为字母

 bool isalnum(char);

 //判断接收字符是否为字母或者数字

 bool isdigit(char);

 //判断接收字符是否为数字

 bool isannotation(char);

 //判断接收字符是否为注释

 extern char letter(char c); //用来将大写字母转化成小写字母

 FILE* fin;

 FILE* fout;

  void scanner()

 {//词法分析的主体程序,对输入的文本文件进行词法分析

  char ch;

  int i,c;

  int error=0;

  //记录文件中词法错误的个数

  ch=fgetc(fin);

 //从输入文件中读取一个字符

 while(ch!=EOF)

  {//当从输入文件接收的字符不是文件结束符时,执行循环

 if(isalpha(ch))

 {//如果从输入文件接收的第一个字符是字母

 ch=letter(ch);

  TOKEN[0]=ch;

  ch=fgetc(fin);i=1;

  while(isalnum(ch))

  {

 ch=letter(ch);

 TOKEN[i]=ch;i++;

 ch=fgetc(fin);

  }

  TOKEN[i]="\0";

  c=lookup(TOKEN);

  //查保留字表

  if(c==0) {fprintf(fout,"(%d,%s)\n", ID,TOKEN);} //输出标识符

  else fprintf(fout,"(%d,%s)\n", c,TOKEN);

 //输出接收单词为保留字

 }

 if(isdigit(ch))

  //如果从输入文件接收的第一个字符是数字

 {

 int cdot=0;

  //统计小数点个数

  TOKEN[0]=ch;

  ch=fgetc(fin);i=1;

  while(isdigit(ch)||ch==".")

  {//从第二个接收字符开始,当是数字或者是小数点时,执行循环

 if(ch==".")

 cdot++;

 TOKEN[i]=ch;i++;

 ch=fgetc(fin);//重复接收字符,直到接收到非数字

 if(cdot>=2)

 {

 error++;

 TOKEN[i]="\0";

 printf("%s is error\n", TOKEN);

 break;

 }

  }

  if(isalpha(ch)) //如果第二个字符是字母

  {

 while(isalpha(ch)) //接收完所有的字母,跳出循环

 {

  TOKEN[i]=ch;i++;

  ch=fgetc(fin);

 }

 TOKEN[i]="\0";

 error++;

 printf("%s is error\n", TOKEN);

  }

 else if(cdot==0)

 //当接收的字符为整型单词时

  {

 fseek(fin,-1,1);

  TOKEN[i]="\0";

 int a,temp=0,c;

 for(c=0;c<i;c++)

 {

 a=TOKEN[c] - "0";

 if(c!=0)

 {

 temp=temp*10;

 temp=temp+a;

 }

 else

 {

 temp=a;

 }

 }

 fprintf(fout,"(%d,%d)\n", INT, temp);

 //输出接收单词为整数

  }

  else if(cdot==1)

 {

 fseek(fin,-1,1);

  TOKEN[i]="\0";

 int a,part1=0,jc,b=0;

  //b用来确定小数点所在的位置

 float c=0.1,part2=0.0;

 while(TOKEN[b]!=".")

 {

 b=b+1;

 }

 for(jc=0;jc<b;jc++)

 {

 a=TOKEN[jc] - "0";

 if(jc!=0)

 {

 part1=part1*10;

 part1=part1+a;

 }

 else

 {

 part1=a;

 }

 }

 for(jc=b+1;jc<i;jc++)

 {

 a=TOKEN[jc]-"0";

 part2=a*c+part2;

 c=c*0.1;

 }

 fprintf(fout,"(%d,%f)\n", FLOAT, part1+part2);

 //输出接收单词为小数

 }else if(cdot==2)

 {

 fseek(fin,-1,1);

 }

  }

  else

 //如果从输入文件接收的第一个字符既不是字母又不是数字

 switch(ch)

 {//将所接收到的符号字符进行分类,采取一符一类

  case":":ch=fgetc(fin);

 if(ch=="=") fprintf(fout,"(%d,:=)\n", EVALU);

  //输出接收符号为赋值号

  else

 {ch=fgetc(fin);

  fseek(fin,-1,1);

 //文件接收字符回推一个字符

  fprintf(fout,"(%d,":")\n", COLON);

  //输出冒号

 }

 break;

  case",":fprintf(fout,"(%d,",")\n", COMMA); break;

  //输出逗号

  case".":fprintf(fout,"(%d,".")\n", ENDF);break;

 //输出句号

  case";":fprintf(fout,"(%d,".")\n", SEMIC);break;

  //输出分号

  case"+":fprintf(fout,"(%d,"+")\n", ADD);break;

 //输出加号

  case"-":fprintf(fout,"(%d,"-")\n", MINUS);break;

  //输出减号

  case"*":fprintf(fout,"(%d,"*")\n", MULTI);break;

  //输出乘号

  case"<":ch=fgetc(fin);

 if(ch=="=")fprintf(fout,"(%d,"<=")\n", LE);

  //输出小于或等于号

 else if(ch==">")fprintf(fout,"(%d,"<>")\n", NE);

 //输出不等于号

 else

 {

 fseek(fin,-1,1);

 fprintf(fout,"(%d,"<")\n", LT);;

  //输出小于号

 }

  break;

  case"=":fprintf(fout,"(%d,"=")\n", EQ);break;

 //输出等于号

  case">":ch=fgetc(fin);

 if(ch=="=")fprintf(fout,"(%d,">=")\n", GE);

  //输出大于或等于号

  else

  {

  fseek(fin,-1,1);

  fprintf(fout,"(%d,">")\n", GT);

  //输出大于号

  }

 break;

  case" ":break;

  case"\n":break;

  case"\t":break;

  case"/":ch=fgetc(fin);//检查是否为单行注释

  if(ch=="/"){

  while(ch!="\n"){

  ch=fgetc(fin);

  }

  }

 else {

 fseek(fin,-1,1);

 printf("/ is error\n");

 error++;

 }

 break;

  case"{":

 while(1){

  ch=fgetc(fin);

  if(ch=="}") break;

  if(ch==EOF)

 {

 fseek(fin,-1,1);

 printf("{

 is error\n");

 error++;

 break;

  }

  }

  break;

  default:printf("%c is error\n", ch);

  //接收非上述字符程序报告词法错误

  error++;break;

 }

 ch=fgetc(fin);

 //继续从文件中读取下一个单词,直到文件结束

  }//while循环结束

 printf("共发现%d 个词法错误!",error);

  return;

 }

  int lookup(char *token)

 {

  int j;

 char word[norw][al];

  strcpy(&(word[1][0]), "begin" );

  strcpy(&(word[2][0]), "end");

  strcpy(&(word[3][0]), "var");

  strcpy(&(word[4][0]), "integer");

  strcpy(&(word[5][0]), "while");

  strcpy(&(word[6][0]), "do");

  strcpy(&(word[7][0]), "if");

  strcpy(&(word[8][0]), "then");

  strcpy(&(word[9][0]), "procedure");

  strcpy(&(word[10][0]), "else");

 for(j=1;j<=norw-1;j++)if(strcmp(token,word[j])==0) return j;

  //以TOKEN字符串查保留字表,若查到返回保留字类别码

  return 0;

 //TOKEN不是保留字,返回0

 }

  bool isalpha(char c)

 { //判断接收字符是否为字母

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

  else return 0;

  }

 bool isalnum(char c)

 {//判断接收字符是否为字母或者数字

 if((c>="a"&&c<="z")||(c>="A"&&c<="Z")||(c>="0"&&c<="9"))return 1;

  else return 0;

 }

  bool isdigit(char c)

 {//判断接收字符是否为数字

 if(c>="0"&&c<="9")return 1;

  else return 0;

 }

  char letter(char c) //将大写字母转换成小写字母,即不区分大小写

 {

 if(c>="A"&&c<="Z")

 {

 c=c+32;

 }

 return c;

 }

  int main()

 {

 char filename[20];

 printf("请输入文件名:");

 scanf("%s",filename);

 if((fin=fopen(filename,"r"))==NULL) //打开要读取的文本文件

 {

  printf("不能打开文件.\n");

  exit(0);

 }

  printf("请输入保存分析结果的文件名:");

 scanf("%s",filename);

  if((fout=fopen(filename,"w"))==NULL)

  {

 printf("不能打开文件.\n");

 exit(0);

  }

  scanner();

 //调用词法分析程序

 //getchar();getchar();

  fclose(fin);

 fclose(fout);

 return 0;

 }

  五 、 运行的结果