一、 实验题目:
词法分析程序
二、 实验内容:
1、主程序设计考虑:
主程序的说明部分为各种表格和变量安排空间(关键字和特殊符号表)。
id 和 ci 数组分别存放标识符和常数;还有一些为造表填表设置的变量。
主程序的工作部分建议设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个
单词;调用词法分析过程;输出每个单词的内部码。
2)词法分析过程考虑
该过程取名为 lexical,它根据输入单词的第一个有效字符(有时还需读第二个字符),判断单词类,
产生类号。对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有该元素,
则记录其在表中的位置,如未出现过,将标识符按顺序填入数组 id 中,将常数存入数组中 ci 中,并记
录其在表中的位置。
三、 程序源代码:
#include
#include
#include
#include
#define LEN sizeof(struct Node)
#define NULL 0
struct Node
{
char data;
struct Node *next;
};
void Output1(struct Node*);
void Scaner(); /*词法分析*/
void Scaner1();
void GetBC();
void GetChar();
void Concat();
int IsLetter(char ch);
int IsDegit(char ch);
int Reserve();
void Retract();
void Back(char *a,char *b);
struct Node *head,*p;
第 页
共 页
char ch; /*全局变量*/
char
*key[]={"int","char","float","void","const","if","else","do","while","scanf","printf","retu
rn","main"}; /*关键字表*/
char Token[20]; /*字符数组,存放构成单词的符号串*/
char *id[256];
int ci [256];
int i=0;
int j=0;
int opt;
void main()
{
head=(struct Node *)malloc(LEN); /*分配头节点存储空间*/
if(!head)
{
printf("error");
exit(1);
}
head->next=NULL;
head->data=' ';
p=head;
printf("如果想结束输入就在新的一行的开始输入’$’!\n 输入结束后屏幕上会输入你刚输入的代
码\n");
printf("请输入你的代码:\n");
while(1)
{
int i=0;
char temp[256];/*每行长度不超过 256 个字符*/
gets(temp); /*输入源程序,以行为单位*/
if(temp[0]=='$') break;/*当输入的第一个字符为$时表示输入源代码结束*/
p->next=(struct Node *)malloc(LEN);
if(!(head->next))
{
printf("error");
exit(1);
}
// p=head;
p=head->next;
while(temp[i]!='\0' && i<256)
{
/*将输入的代码以行为单位存入缓冲区*/
p->data=temp[i];
p->next=(struct Node *)malloc(LEN);
if(!(p->next))
第 页
共 页
{
printf("error");
exit(1);
}
p=p->next;
i++;
}
p->data='\n';
p->next=NULL;
/*尾结点*/
/*扫描缓冲区,输出结果*/
}
printf("你刚才输入的是代码为:\n");
Output1(head);
p=head->next;
printf("经该词法分析器程序处理后输出结果为:\n");
printf("注:第一个无素 1,2,3,4,5 分别表关键字、表标识符、表常数、表运算符、表界符\n");
printf("
// printf("有两种输出格式,可通输入 0 或 1 进行选择");
//opt=(int)getchar();
while(p->next!=NULL)
{
第二无素为该单词在各自表中的指针或内部码值\n");
Scaner();
}
system("pause");
//return 0;
}
void Output1(struct Node *head)
{
/*扫描缓冲区函数*/
if(!(head)) {printf("error");exit(1);}
p=head->next;
while(p->next!=NULL)
{
printf("%c",p->data);
p=p->next;
}
printf("\n");
}
void GetBC() /*若 ch 中是空白字符,则不停调用 getch()直到读入的不是空白字符为止*/
{
while (ch==' ')
GetChar();
}
void GetChar()
/*从缓冲区读入一字符*/
第 页
共 页
{
}
ch=p->data;
p=p->next;
void Concat()
{
/*将 ch 中的字符连接到 token 的后面*/
unsigned int i;
i=strlen(Token);
if(ch!=' ')
{
Token[i]=ch;
Token[i+1]='\0';
}
}
int IsLetter(char ch)
{
return isalpha((int)ch);
}
int IsDigit(char ch)
{
/*判断 ch 中的是否是数字*/
return isdigit((int)ch);
}
int Reserve() /*判断 token 中的字符串是否是关键字或是标识符*/
{
int k;
for(k=0;k<13;k++)
{
if(strcmp(key[k],Token)==0)
return (k+1);
}
return 0;
}
void Retract() /*指针回退一个字符*/
{
struct Node *Q;
Q=head->next;
while(Q->next!=p)
Q=Q->next;
p=Q;
}
void Back(char *a,char *b)
{
第 页
共 页
printf("(%s,%s)\n",a,b);
}
void Scaner()
{
int c;
Token[0]=NULL;
GetChar();
GetBC();
if(IsLetter(ch))
{
while(IsLetter(ch)||IsDigit(ch))
{
Concat();
GetChar();
}
Retract();
c=Reserve();
if(c!=0)
{
printf("<1,%d>\n",c);
}
else
{
printf("<2,%d>\n",i);
id[i]=Token;
i++;
}
}
else if(IsDigit(ch)){
while(IsDigit(ch))
{
Concat();
GetChar();
}
Retract();
printf("<3,%d>\n",j);
ci[j]=atoi(Token);
j++;
}
else
switch(ch)
{
case'+': GetChar();
if(ch=='+')
第 页
共 页
{
}
printf("<4,39>\n");
Retract();
printf("<4,15>\n");
break;
case'-': GetChar();
if(ch=='-')
case'&':GetChar();
case'|':GetChar();
{
printf("<4,40>\n");}
Retract();
printf("<4,16>\n");
break;
if(ch=='&')
{
printf("<4,27>\n");
}
printf("error\n");
Retract();
if(ch=='|')
{
printf("<4,28>\n");
}
Retract();
break;
case'*':
case'/':
case'%':
printf("<4,17>\n");
break;
printf("<4,18>\n");
break;
printf("<4,19>\n");
break;
case'<': GetChar();
if(ch=='=')
{
printf("<4,26>\n");
}
Retract();
printf("<4,23>\n");
break;
case'>': GetChar();
第 页
共 页
if(ch=='=')
{
printf("<4,25>\n");
}
Retract();
printf("<4,22>\n");
break;
case';':printf("<5,35>\n");break;
case',': printf("<5,36>\n");break;
case'"': printf("<5,37>\n");break;
case'{': printf("<5,33>\n");break;
case'}':printf("<5,34>\n");break;
case'(':printf("<5,31>\n");break;
case')':printf("<5,32>\n");break;
case'=':GetChar();
if(ch=='=')
{
printf("<4,21>\n");}
Retract();
printf("<5,20>\n");
case'!':GetChar();
break;
if(ch=='=')
{
printf("<5,24>\n");}
Retract();
printf("<5,29>\n");
break;
case'\n': break;
default: printf("error\n");break;
}
}
四、 测试结果:
第 页
共 页
五、小结(包括收获、心得体会、存在的问题及解决问题的方法、建议等)
注:内容一律使用宋体五号字,单倍行间距
1、 通过这次实验我对词法分析器有了进一步的了解,把理论知识应用于实验中。
2、 在编写程序过程中也遇到了很多困难,不过最终通过自己细心检查得到了解决,为以后编程积累了些
小知识;
3、 程序实现功能很有限,但时间有限,只完成上述功能,以后会继续改进的。
4、 希望老师以后多一些实践机会,把理论知识应用到实际程序中,会更容易理解。
第 页
共 页