词法分析器
一、实验目的:
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。
二、实验要求
如源程序为C语言。输入如下一段:
main()
{
int a,b;
a = 10;
b = a + 20;
}#
要求输出如右图。
要求:
1、将单词分为五种
识别关键字:main、if、int、for、while、do、return、break、continue;单词种别码为1。
标识符;单词种别码为2。
常数为无符号整形数;单词种别码为3。
运算符包括:+、-、*、/、=、>、<、>=、<=、!= ;
单词种别码为4。
分隔符包括:,、;、{、}、(、); 单词种别码为5。
2、使用一符一种的分法
关键字、运算符和分界符可以每一个均为一种
标识符和常数仍然一类一种
三、实验内容
1、功能描述
改程序是一个实现词法分析的功能,能识别5种单词,其他单词报错。
2、程序结构描述
int IsKey(char *Word)关键字匹配函数,查询是否为关键字,若是,返回值为1,否则为0。
int IsAlpha(char c) 查看是否为字母,若是,返回值为1,否则为0。
int IsNum(char c) 查看是否为数字,若是,返回值为1,否则为0。
void scanner(FILE *fp) 扫描函数,扫描程序中的字符串并调用上述三种函数检查是否是字母、数字,是否是关键字,并输出。
fseek(fp,-1,1) 回退一个字符。
fgetc(fp) 从数据流中区下一个字符。
fopen 文件打开函数,返回指向文件第一个字符的指针
四、实验结果
测试内容为
main()
{
int a,b;
a = 10;
b = a + 20;
}#
结果
测试代码为
void main()
{
int a,b;
if(a = 10;)
b += 20;
c=%;
}#
结果为
测试代码
main()
{
int a,b;
if(a <= "10")
b += 20;
c=%@;
return 0;
}#
结果
五、实验过程记录
1、因为用到回退函数fseek(),而以前没有用过这个函数,所以开始时很苦恼,不知道如何回退一个字符,后来问了同学,才明白原来有这么一个函数,顿时豁然开朗。
2、本次试验中word[20]保存字符串时,不能正确保存,总是出错,原因是while(IsNum(ch)||IsAlpha(ch)){
Word[i]=ch;
i++;
ch=fgetc(fp);
}中,i++与Word[i]=ch;次序不对,后来多次思索,发现问题。
六、实验总结
本次实验花了将近一个下午才完成。在纸上设计的时间大约40分钟,剩下的时间是录入和调试。本次实验使我认识到,一段时间搁置,不编程序,水平会下降,好多有关c语言的知识会忘掉,所以以后我会经常写写程序。另外,通过本次实验,我又进一步加深对词法分析原理的理解。总的来说,获益匪浅!
附录
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<iostream.h>
Char*Key[9]={"void","main","int","if","then","else","return","break","continue"};
char ch; // 存储识别出的单词流
int IsAlpha(char c) { //判断是否为字母
if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;
else return 0;
}
int IsNum(char c){ //判断是否为数字
if(c>='0'&&c<='9') return 1;
else return 0;
}
int IsKey(char *Word){ //识别关键字函数
int m,i;
for(i=0;i<8;i++){
if((m=strcmp(Word,Key[i]))==0)
return 1;
}
return 0;
}
void scanner(FILE *fp){ //扫描函数
char Word[20]={'\0'};
char ch;
int i,c;
ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符
if(IsAlpha(ch)){ //判断该字符是否是字母
Word[0]=ch;
ch=fgetc(fp);
i=1;
while(IsNum(ch)||IsAlpha(ch)){ //判断该字符是否是字母或数字
Word[i]=ch;
i++;
ch=fgetc(fp);
}
Word[i]='\0'; //'\0' 代表字符结束(空格)
fseek(fp,-1,1); //回退一个字符
c=IsKey(Word); //判断是否是关键字
if(c==0) cout<<"(2,"<<Word<<')'<<endl;//不是关键字
else cout<<"(1,"<<Word<<')'<<endl; //输出关键字
}
else //开始判断的字符不是字母
if(IsNum(ch)){ //判断是否是数字
Word[0]=ch;
ch=fgetc(fp);
i=1;
while(IsNum(ch)){
Word[i]=ch;
i++;
ch=fgetc(fp);
}
Word[i]='\0';
fseek(fp,-1,1); //回退
cout<<"(3,"<<Word<<')'<<endl;
}
else //开始判断的字符不是字母也不是数字
{
Word[0]=ch;
switch(ch){
case'[':
case']':
case'(':
case')':
case'{':
case'}':
case',':
case'"':
case';':cout<<"(5,"<<Word<<')'<<endl; break;
case'+':ch=fgetc(fp);
if(ch=='='||ch=='+'){
Word[1]=ch;
cout<<"(4,"<<Word<<')'<<endl;//运算符"+="或判断结果为"++"
}
else {
fseek(fp,-1,1);
cout<<"(4,"<<Word<<')'<<endl;//判断结果为"+"
}
break;
case'-':ch=fgetc(fp);
if(ch=='='||ch=='-'){
Word[1]=ch;
cout<<"(4,"<<Word<<')'<<endl; }
else {
fseek(fp,-1,1);
cout<<"(4,"<<Word<<')'<<endl; //判断结果为"-"
}
break;
case'*':
case'/':
case'!':
case'=':ch=fgetc(fp);
if(ch=='='){
Word[1]=ch;
cout<<"(4,"<<Word<<')'<<endl;
}
else {
fseek(fp,-1,1);
cout<<"(4,"<<Word<<')'<<endl;
}
break;
case'<':ch=fgetc(fp);
if(ch=='='||ch=='<'){
Word[1]=ch;
cout<<"(4,"<<Word<<')'<<endl;
}
else {
fseek(fp,-1,1);
cout<<"4\t"<<Word<<endl; //判断结果为"<"
}
break;
case'>':ch=fgetc(fp);
if(ch=='='||ch=='>')
{
Word[1]=ch;cout<<"(4,"<<Word<<')'<<endl;
}
else {
fseek(fp,-1,1);
cout<<"(4,"<<Word<<')'<<endl;
}
break;
default:
cout<<"(无法识别字符,"<<Word<<')'<<endl; break;
}
}
}
void main()
{
FILE *fp;
fp=fopen("c:\\1.txt","r");
if(fp==NULL) //读取文件内容,并返回文件指针,该指针指向文件的第一个字符
{cout<<"读入文件错误!"<<endl;
exit(0);
}
cout<<"******************* 词法分析结果如下 *******************\n";
while(ch!='#'){
ch=fgetc(fp);
if(ch=='#') break; //文件以#结尾,作为扫描结束条件
else if(ch==' '||ch=='\t'||ch=='\n'){} //忽略空格,空白,和换行
else{
fseek(fp,-1,1); //回退一个字节开始识别单词流
scanner(fp);
}
}
}
第二篇:词法分析实验报告1
一.目的与要求:通过编写并上机调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将其分解后各类单词的词法分析方法。
二.实验内容:
输入:据教学要求和学生具体情况,从具有代表性的高级程序设计语言中,选取一个适当大小的子集,例如可以选取一类典型单词,也可以尽可能使各种类型的单词都能兼顾到。
输出:单词串的输出形式,所输出的每一单词均按形如(CLASS,VALUE)的二元式编码。对于变量和常数,CLASS字段为相应的类别码,VALUE字段则是该标识符、常数在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。对于关键字和分隔符,采用一词一类的编码形式。由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,VALUE字段则为“空”。不过,为便于查看由词法分析程序所输出的单词串,要求在CLASS字段上直接放置单词符号串本身。
三.处理过程:在扫描源程序字符串时,一旦识别出关键字、分隔符、标识符、无符号常数中之一,即以单词形式(各类单词均采用相同的结构,即二元式编码形式)输出。每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直至整个源程序全部扫描完毕,并形成相应的单词串形式的源程序。具体方法如下:
(一)单词的分类:构造上述语言中的各类单词符号及其分类码表如下:
(二)状态转移矩阵
(三)词法分析过程
四、词法分析程序的功能
输入:所给文法的原程序字符串。
输出:二元数组。
如:main() { int x,y; x=9; x>=y; return; }#
输出结果为:
(1, main)
error!
error!
(17, {)
(2, int)
(6,x)
(14,,)
(6,y)
(15,;)
(6,x)
(13,>=)
(6,return)
(15,;)
(18,})
五.源程序
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
char *table[7]={" ","main","int","if","then","else","return"},TOKEN[20],ch; //定义关键字
int lookup(char *TOKEN){ //关键字匹配函数
int m,i;
for(i=1;i<6;i++){
if((m=strcmp(TOKEN,table[i]))==0)
return(i);
}
return(0);
}
void out(int c,char *TOKEN){ //输出函数
printf("(%d,%s)\n",c,TOKEN);
}
void scanner(FILE *fp){ //扫描函数
char TOKEN[20]={'\0'};
char ch;
int i,c;
ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符
if(isalpha(ch)){ //判断该字符是否是字母
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(isalnum(ch)){ //判断该字符是否是字母或数字
TOKEN[i]=ch;
i++;
ch=fgetc(fp);
}
TOKEN[i]='\0';
fseek(fp,-1,1); //回退一个字符
c=lookup(TOKEN);
if(c==0)
out(6,TOKEN); //输出标识符
else out(c,TOKEN); //输出关键字
}
else
if(isdigit(ch)){ //判断是否是数字
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(isdigit(ch)){
TOKEN[i]=ch;
i++;
ch=fgetc(fp);
}
TOKEN[i]='\0';
fseek(fp,-1,1);
out(7,TOKEN);
}
else
{
TOKEN[0]=ch;
switch(ch){
case'{':out(17,TOKEN);
break;
case'}':out(18,TOKEN);
break;
case',':out(14,TOKEN);
break;
case';':out(15,TOKEN);
break;
case'<':ch=fgetc(fp);
TOKEN[1]=ch;
if(ch=='='){
out(9,TOKEN);
}
else if(ch=='>'){
out(11,TOKEN);
}
else {
fseek(fp,-1,1);
out(8,TOKEN);
}
break;
case'=':out(10,TOKEN);
break;
case'>':ch=fgetc(fp);
TOKEN[1]=ch;
if(ch=='=') out(13,TOKEN);
else {
fseek(fp,-1,1);
out(12,TOKEN);
}
break;
default:printf("error!\n");
break;
}
}
}
main()
{
FILE *fp;
if((fp=fopen("E:\\222.txt","r"))==NULL){ //读取文件内容,并返回文件指针,该指针指向文件的第一个字符
fprintf(stderr,"error opening.\n");
exit(1);
}
do{
ch=fgetc(fp);
if(ch=='#') //文件以#结尾,作为扫描结束条件
break;
if(ch==' ') //如果是空格,自动跳到下个字符
scanner(fp);
else{
fseek(fp,-1,1); //如果不是空格,则回退一个字符并扫描
scanner(fp);
}
}while(ch!='#');
return(0);
}
六.函数说明
1. int lookup(char *TOKEN) 关键字匹配函数,查询所述程序中的关键字
2. void out(int c,char *TOKEN) 输出函数
3. void scanner(FILE *fp) 扫描函数,扫描程序中的字符串并调用lookup函数检查是否是关键字,再调用out函数输出二元组
4.fseek(fp,-1,1) 回退一个字符
5.isalpha(ch) 字母判断函数,若ch指的是字母,返回非0,否则返回0
6.isalnum(h) 字母或数字判断函数,若ch指的是字母或数字,返回非0,否则返回0
7.isdigit(ch) 数字判断函数,若ch指的是数字,返回非0,否则返回0
8.fgetc(fp) 从数据流中区下一个字符
9.fopen 文件打开函数,返回指向文件第一个字符的指针
七.实验结果及截图