编译原理实验一【词法分析程序设计】
基本要求:①掌握程序语言的词法结构。②掌握状态转换图的使用。③掌握设计词法分析程序的一般方法。④学会熟练调式程序。重点及难点:掌握用状态转换图描述程序词法结构的一般方法,并在此基础上完成简版C语言子集词法分析程序的设计和调试运行。一、 C语言子集的单词符号表示一个非常重要的事实是:大多数程序语言的单词符号都可以用状态转换图予以识别。作为本次实验,我们来构造一个C语言子集的简单词法分析器。下表列出了
基本要求:
①掌握程序语言的词法结构。
②掌握状态转换图的使用。
③掌握设计词法分析程序的一般方法。
④学会熟练调式程序。
重点及难点:掌握用状态转换图描述程序词法结构的一般方法,并在此基础上完成简版C语言子集词法分析程序的设计和调试运行。
一、 C语言子集的单词符号表示
一个非常重要的事实是:大多数程序语言的单词符号都可以用状态转换图予以识别。作为本次实验,我们来构造一个C语言子集的简单词法分析器。下表列出了这个C语言子集的所有单词符号以及它们的种别编码和内码值。由于直接使用整数编码不利于记忆,故该程序中用一些特殊符号来表示种别编码。
C语言子集的单词符号及内码值
二、 C语言子集对应的状态转换图
在设计的状态转换图中,首先对输入串做预处理,即剔除多余的空白符(在实际的词法分析中,预处理还包括剔除注释和制表换行符等编辑性字符的工作),使词法分析工作既简单又清晰。其次,将保留字作为一类特殊的标识符来处理,也即对保留字不专设对应的状态转换图,当转换图识别出一个标识符时就去查对上表的前五项,确定它是否为一个保留字。当然,也可以专设一个保留字表来进行处理。
在状态2时,所识别出的标识符应先与表的前五项逐一比较,若匹配,则该标识符是一个保留字,否则就是标识符。如果是标识符,应先查符号表,看表中是否有此标识符。若表中无此标识符,则将它登录到符号表中,然后返回其在符号表中的入口指针(地址)作为该标识符的内码值;若表中有此标识符,则给出重名错误信息。在状态4时,应将识别的常数转换成二进制常数并将其登录到常数表,然后返回其在常数表中的入口指针作为该常数的内码值。
三、状态转换图的实现
状态转换图非常容易用程序实现,最简单的办法是让每个状态对应一小段程序。对于上述状转换图,我们首先引进一组变量和过程如下:
(1)character:字符变量,存放最新读入的源程序字符。
(2)token:字符数组,存放构成单词符号的字符串。
(3)getbe( ):若character中的字符为空白,则调用getchar( ),直至character为非空白符为止。
(4)concatenation( ):将token中的字符串与character中的字符连接并作为token中新的字符串。
(5) letter( )和digit( ):判断character中的字符是否为字母和数字的布尔函数,是则返回true,否则返回false。
(6) reserve( ):按token数组中的字符串查表中的前五项(即判别其是否为保留字),若是保留字则返回它的编码,否则返回0值。
(7) retract( ):扫描指针回退一个字符,同时将character置为空白。
(8) buildlist( ):将标识符登录到符号表或将常数登录到常数表。
(9)error( ):出现非法字符,显示出错信息。
四.源代码
#include <stdio.h>
#include <string.h>
int i,j,k;
char s;
char a[20],token[20];
int letter()
{
if ((s>=97)&&(s<=122))
return 1;
else
return 0;
}
int Digit()
{
if ((s>=48)&&(s<=57))
return 1;
else
return 0;
}
void get()
{
s=a[i];
i=i+1;
}
void retract()
{
i=i-1;
}
int lookup()
{
if (strcmp(token,"while")==0)
return 1;
else if (strcmp(token,"if")==0)
return 2;
else if (strcmp(token,"else")==0)
return 3;
else if (strcmp(token,"switch")==0)
return 4;
else if (strcmp(token,"case")==0)
return 5;
else
return 0;
}
void main()
{
printf("Please input you source program,end('#'):\n");
i=0;
do
{
i=i+1;
scanf("%c",&a[i]);
}
while(a[i]!='#');
i=1;
memset(token,0,sizeof(char)*10);
j=0;
get();
while(s!='#')
{
if(s==' '||s==10||s==13)
get();
else
{
switch(s)
{
case'a':
case'b':
case'c':
case'd':
case'e':
case'f':
case'g':
case'h':
case'i':
case'j':
case'k':
case'l':
case'm':
case'o':
case'p':
case'q':
case'r':
case's':
case't':
case'u':
case'v':
case'w':
case'x':
case'y':
case'z':
while(Digit()||letter())
{
token[j]=s;
j=j+1;
get();
}
retract();
if(k==0)
printf("(6,%s)\n",token);
else
printf("(%d,null)\n",k);
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
while(Digit())
{
token[j]=s;
j=j+1;
get();
}
retract();
printf("(%d,%s)\n",7,token);
break;
case'+':printf("(+,null)\n");
break;
case'-':printf("(-,null)\n");
break;
case'*':printf("(*,null)\n");
break;
case'<':
get();
if (s=='=')
printf("(relop,LE)\n");
else
{
retract();
printf("(relop,LT)\n");
}
break;
case'=':
get();
if(s=='=')
printf("(relop,EQ)\n");
else
{
retract();
printf("(=,null)\n");
}
break;
case';':printf("(;,null)\n");
break;
default:printf("(%c,error)\n,s");
break;
}
memset(token,0,sizeof(char)*10);
j=0;
get();
}
}
}
更多推荐


所有评论(0)