编译原理----词法分析器实现(C)

时间:2022-03-02 16:47:15

关于编译原理和词法分析程序的介绍了要求我这里不再进行介绍。

如需了解编译原理和词法分析器的实现原理请参考我转载的一篇博客:点击打开链接

下面介绍一下我完成的词法分析器的实验要求

实验一:

目的:掌握对设计一种简单程序设计语言的完整词法分析器所必需具备的方法与技巧。

基本要求:

1)设计一个简单程序语言的单词标识及其相应种属编码,设计该语言单词的状态转换图并建立该语言的关键字表;

2)在程序中完成对该语言中标识符及整型数字的定义;

3)熟练掌握从外部文件扫描正文并读入正文符号继而组合单词的技巧,以及掌握正确识别和处理回车和换行等ASC控制码的方法,并能够对源程序进行原样列表显示;

4) 建立二元式文件,其中整型数字以二进制串形式表示;

一. 扫描器:

用C语言或PASCAL语言设计一个简单高级语言的词法分析器,该语言的所有单词种类以及被该扫描器所识别的源程序如下所示:

⑴ 单词种类(关键字30个,外加数字和标识符两类,共32类)

  1. PROGRAM          2.  VAR        3.  PROCEDURE

   4. BEGIN            5.  END        6.  IF

   7.  THEN             8.  ELSE       9.  REPEAT

10. UNTIL             11. READ        12.  WRITE

13. WRITELN          14.  FOR       15.  DO

16. 数字           17. 标识符      18.  +

19. —                 20.  *         21. /

22.  (                 23.  )         24. =

25.  ,            26.          27. < >

28.  <                 29.  >          30.  ;   

31. :=                32.  newline (凡遇到回车和换行符即Enter键时,就输出一个值为该串的二元式)

⑵ 其它符号的产生式定义:

字母→a|b|c|d|e|…|z|A|B|C|D|…|Z

数字→0|1|2|3|4|5|6|7|8|9


待识别源程序:

PROGRAM  mm;
VAR a,b;
PROCEDURE next(var b);
VAR c;
BEGIN
REPEAT
b:=b+1*(b-3)/4;c:=128;
REPEAT
IF c*c<>b THEN c:=bELSE c:=c+1;
UNTIL (b/c)*c=b;
UNTIL (c=b);
END;
BEGIN
READ (a);
WRITELN(a);IF a=1 THEN WRITE(a);
IF a<0 THEN BEGIN
b:=-1;WRITE(b);a:=-a;
END;
b:=2;
IF a<>0 THEN REPEAT
IF(a/b)*b=a THEN
REPEAT
BEGIN
WRITE(b);a:=-(a/b);
END;
UNTIL(a/b)*b<>a;
next(b);
UNTIL (b*b)>a ;
IF a<>1 THEN WRITE(a);
END。
设计吃法分析器首先要对要识别的字符进行分类:

我是将上述要求中:

1.所有的关键字每一个设为一类;种属编号是1-15.

2.+ 16,- 17,* 18,/ 19,(   20,)    21, =   22,     ,    23,。24,;25,:=   26,:27,>=  28,>   29,<>30,<=  31,<  32,数字    33,标示符    34.

3.其中我将关于换行的newline没有实现在程序上给予了忽略。

4.对与关键字“。”我在程序中改为了英文的点号。

下面为程序的实现代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream.h>
void writing(char ch);
void reading(char* prog);
char prog[800],token[80];
char ch;
int syn,p,m=0,n,row,sum=0;
//关键字存储
char *rwtab[15]={
"PROGRAM","VAR","PROCEDURE","BEGIN","END","IF",
"THEN","ELSE","REPEAT","UNTIL","READ","WRITE",
"WRITELN","FOR","DO"
};

void scaner()
{
/*
共分为三大块,分别是标示符、数字、符号,对应下面的 if else if 和 else


*/
for(n=0;n<8;n++) token[n]=NULL;
//过滤空格
ch=prog[p++];
while(ch==' ')
{
ch=prog[p];
p++;
}

if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')) //可能是标示符或者变量名
{
m=0; //整形变量int
while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
{
token[m++]=ch;
ch=prog[p++];
}
//识别出一个标示符
token[m++]='\0';
//回退一位
p--;
syn=34;//单纯的标示符
for(n=0;n<15;n++) //将识别出来的字符和已定义的标示符作比较,
if(strcmp(token,rwtab[n])==0)
{ //字符串类别
syn=n+1;
break;
}
}
else if((ch>='0'&&ch<='9')) //数字
{
{
sum=0;
while((ch>='0'&&ch<='9'))
{
sum=sum*10+ch-'0';
//读取下一个字符
ch=prog[p++];
}
}
//回退一下
p--;
syn=33;//33标示数值类型
//限制数组的大小范围
if(sum>999999999)
syn=-1;
}
else switch(ch) //其他字符
{
case'<':
m=0;
token[m++]=ch;
//读取下一个字符
ch=prog[p++];
if(ch=='>')
{
syn=30;
token[m++]=ch;
}
else if(ch=='=')
{
syn=31;
token[m++]=ch;
}
else
{
syn=32;
p--;
}
break;
case'>':
m=0;
token[m++]=ch;
//读取下一个字符
ch=prog[p++];
if(ch=='=')
{
syn=28;
token[m++]=ch;
}
else
{
syn=29;
p--;
}
break;
case':':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='=')
{
syn=26;
token[m++]=ch;
}
else
{
syn=27;
p--;
}
break;

case'+':syn=16;token[0]=ch;break;
case'-':syn=17;token[0]=ch;break;
case'*':syn=18;token[0]=ch;break;
case'/':syn=19;token[0]=ch;break;

case'(':syn=20;token[0]=ch;break;
case')':syn=21;token[0]=ch;break;
case'=':syn=22;token[0]=ch;break;
case',':syn=23;token[0]=ch;break;
case'.':syn=24;token[0]=ch;break;
case';':syn=25;token[0]=ch;break;


case'#':syn=0;token[0]=ch;break;
case'\n':syn=-2;break;
default: syn=-1;break;
}
}

int main()
{
p=0;
row=1;
cout<<"Please input string:"<<endl;
//读取原程序逐个字符读取当读到“#”时停止读取
//do
//{
// cin.get(ch);
// prog[p++]=ch;
// }
// while(ch!='#');
reading(prog);
p=0;
do
{
scaner();
switch(syn)
{
case 33: cout<<"("<<syn<<","<<sum<<")"<<endl; break; //输出的是数值
case -1: cout<<"Error in row "<<row<<"!"<<endl; break;//输出的是错误信息
case -2: row=row++;break;
default: cout<<"("<<syn<<","<<token<<")"<<endl;break;//输出的是标示符
}
}
while (syn!=0);//结束符号时停止执行
return 0;
}


void writing(char ch){
FILE * out;
if((out=fopen("D:/b.txt","w"))==NULL)
{
printf("写入文件打开失败!!!!");
exit(0);
}
fputc(ch,out);

}

void reading(char * prog)
{
FILE * in;
printf("请输入文件路径:\n");
char path[100],ch;
scanf("%s",&path);
printf("%s\n",path);
if((in = fopen(path,"r"))==NULL){
printf("文件无法打开!!!");
exit(0);
}
int i=0;
while(!feof(in)){
ch = fgetc(in);
putchar(ch);
prog[i]=ch;
i++;
}
prog[--i]='#';
fclose(in);
}
程序的远行结果:

编译原理----词法分析器实现(C)
以上是程序的执行结果;但是程序在分析样例程序时出现了一个错误我还没有解决。希望哪位大神指出。

本程序是在我上边连接博客的一个扩展。

注:

如果需要将十进制转化为二进制可以采取下列方法进行转换:

int binary(int number){
bool a[1000];
int i=0;
while(1) {
a[i]=number%2;
number=number/2;
if(number==0)break;
i++;
} for(int j=i; j>=0; j--)
printf("%d",a[j]);
return 0;

}