文章目录
一、实验目的
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。
二、实验题目
如源程序为C语言。输入如下一段:
main()
{
int a=-5,b=4,j;
if(a>=b)
j=a-b;
else j=b-a;
}
运行结果输出如下:
(”main”,1,1)
(”(”,5)
(”)”,5)
(”{”,5)
(”int”,1,2)
(”a”,2)
(”=”,4)
(”-5”,3)
(”,”,5)
(”b”,2)
(”=”,4)
(”4”,3)
(”,”,5)
(”j”,2)
(”;”,5)
(”if”,1,3)
(”(”,5)
(”a”,2)
(”>=”,4)
(”b”,2)
(”)”,5)
(”j”,2)
(”=”,4)
(”a”,2)
(”-”,4)
(”b”,2)
(”;”,5)
(”else”,1,4)
(”j”,2)
(”=”,4)
(”b”,2)
(”-”,4)
(”a”,2)
(”;”,5)
(”}”,5)
三、实验理论依据
(一)识别各种单词符号
1、程序语言的单词符号一般分为五种:
(1)关键字(保留字/ 基本字)if 、while 、int…
(2)标识符:常量名、变量名…
(3)常数:34 、56.78 、…
(4)运算符:+ 、- 、* 、/ 、〈 、|| 、&&….
界限符:, ; ( ) { } /*
2、识别单词:掌握单词的构成规则很重要
(1)标识符的识别:字母| 下划线+( 字母/ 数字/ 下划线)
(2)关键字的识别:与标识符相同,最后查表
(3)常数的识别
(4)界符和算符的识别
3、大多数程序设计语言的单词符号都可以用转换图来识别,如下图所示
4、词法分析器输出的单词符号常常表示为二元式:(单词种别,单词符号的属性值)
(1)单词种别通常用整数编码,如1 代表关键字,2 代表标识符等
(2)关键字可视其全体为一种,也可以一字一种。采用一字一种得分法实际处理起来较为方便。
(3)标识符一般统归为一种
(4)常数按类型(整数、实数等)分种
(5)运算符可采用一符一种的方法。
(6)界符一般一符一种的分法。
(二)超前搜索方法
1、词法分析时,常常会用到超前搜索方法。
如当前待分析字符串为“a>+” ,当前字符为“>” ,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?
显然,只有知道下一个字符是什么才能下结论。于是分析器读入下一个字符’+’ ,这时可知应将’>’ 解释为大于运算符。但此时,超前读了一个字符’+’ ,所以要回退一个字符,词法分析器才能正常运行。又比如:‘+’ 分析为正号还是加法符号
(三)预处理
预处理工作包括对空白符、跳格符、回车符和换行符等编辑性字符的处理,及删除注解等。由一个预处理子程序来完成。
四、词法分析器的设计
1、设计方法
(1)写出该语言的词法规则。
(2)把词法规则转换为相应的状态转换图。
(3)把各转换图的初态连在一起,构成识别该语言的自动机
(4)设计扫描器
2、把扫描器作为语法分析的一个过程,当语法分析需要一个单词时,就调用扫描器。 扫描器从初态出发,当识别一个单词后便进入终态,送出二元式
五、完整程序
下面为成功运行的完整程序:
#include<stdio.h>
#include<cctype>
#include<string.h>
#include<string>
#include<stdlib.h>
FILE *fp;
char cbuffer;
char *key[32] = { "auto","double","int","struct","break","else","long","switch","case",
"enum","register","typedef","char","extern","return","union","const","float","short",
"unsigned","continue","for","signed","void","default","goto","sizeof","volatile","do",
"while","static","if" };
int atype, id = 4;//id为类型标记
//每个函数都会用到的公共变量
int main()
{
char alphaprocess(char buffer);
char digitprocess(char buffer);
char otherprocess(char buffer);
int search(char searchchar[], int wordtype);
int myisdigit(char ch);
if ((fp = fopen("C:/Users/admin/Desktop/test.txt", "r")) == NULL)
//if (fopen_s(&fp,"C:/Users/admin/Desktop/test.txt", "r") == NULL)
printf("error");
else
{
cbuffer = fgetc(fp);//从磁盘文件中读取一个字符
while (cbuffer != EOF)//只要没到文件末尾就继续
{
if (cbuffer == ' ' || cbuffer == '\n')
cbuffer = fgetc(fp);
else
if(isalpha(cbuffer) || cbuffer == '_' )
//加入以下划线开头的标识符的判断
cbuffer = alphaprocess(cbuffer);//字符处理函数
else
if (isdigit(cbuffer))
cbuffer = digitprocess(cbuffer);//数字处理程序
else cbuffer = otherprocess(cbuffer);//其他处理程序
}
}
}
int search(char searchchar[], int wordtype)
{
int i = 0;
int p;
switch (wordtype)
{
case 1:for (i = 0; i <= 31; i++)
{
if (strcmp(key[i], searchchar) == 0)
{
p = i + 1; break;//是保留字则p为非零且不重复的整数
}
else p = 0;//不是保留字返回p=0
}
return(p);
}
}
int myisdigit(char ch)
{
if (ch >= 48 && ch <= 57)
return 1;
else
return 0;
}
char alphaprocess(char buffer)
{
int atype;//保留字在数组中的位置
int i = -1;
char alphatp[20];//数组用来装读取的字符或保留字
char* key2[] = { "printf","scanf" };
while ((isalpha(buffer)) || (isdigit(buffer)) || buffer == '_')
{
alphatp[++i] = buffer;
buffer = fgetc(fp);//需填空
}//读一个完整的单词,由字母、数字和下划线组成
alphatp[i+1] = '\0';
atype = search(alphatp, 1);//search函数判断类型
if (atype != 0)
{
printf("%s,(1,%d)\n", alphatp, atype - 1); id = 1;//保留字
}
else
{
if (alphatp[0] == '*')
printf("(%s,2,指针变量)\n", alphatp);
else
printf("(%s,2)\n", alphatp); id = 2;//标识符
}
return buffer;//
}
char digitprocess(char buffer)//加入小数、科学计数法的判断,注意小数点的个数
{
int i = -1;
char digittp[20];
char another[20];
while ((myisdigit(buffer)))
{
digittp[++i] = buffer;
buffer = fgetc(fp);
}
if (buffer == 'e' || buffer == 'E')//e前面为整数的科学计数法
{
buffer = fgetc(fp);
digittp[++i] = 'e';
while (buffer == '+' || buffer == '-' || myisdigit(buffer))
{
digittp[++i] = buffer;
buffer = fgetc(fp);
}
digittp[i + 1] = '\0';
id = 3;
printf("(%s, 3)\n", digittp);
return buffer;
}
if (buffer == '.')//小数
{
digittp[++i] = '.';
buffer = fgetc(fp);
while ((myisdigit(buffer)))
{
digittp[++i] = buffer;
buffer = fgetc(fp);
}
if (buffer == 'e' || buffer == 'E')//e前面为小数的科学计数法
{
digittp[++i] = 'e';
buffer = fgetc(fp);
while (buffer == '+' || buffer == '-' || myisdigit(buffer))
{
digittp[++i] = buffer;
buffer = fgetc(fp);
}
digittp[i + 1] = '\0';
id = 3;
printf("(%s, 3)\n", digittp);
return buffer;
}
digittp[i + 1] = '\0';
while (buffer == '.')//如果存在多个小数点
{
int j = 0;
another[j] = '0';
another[++j] = '.';
buffer = fgetc(fp);
while (myisdigit(buffer))
{
another[++j] = buffer;
buffer = fgetc(fp);
}
another[j + 1] = '\0';
printf("(%s ,3)\n", another);
}
}
else digittp[i + 1] = '\0';//小数判断部分结束
printf("(%s ,3)\n", digittp);
id = 3;
return(buffer);
}
char otherprocess(char buffer)
{
char ch[30];
int w = 0;
ch[0] = buffer;
ch[1] = '\0';
if (ch[0] == '#')//头文件
{
buffer = fgetc(fp);
while (isalpha(buffer) && buffer != '<' && buffer != '"')
{
ch[++w] = buffer;
buffer = fgetc(fp);
}
if (strcmp(ch, "#include"))
{
ch[++w] = buffer;
buffer = fgetc(fp);
while (buffer != '>' && buffer != '"')
{
ch[++w] = buffer;
buffer = fgetc(fp);
}
ch[++w] = buffer;
ch[w + 1] = '\0';
id = 6;
printf("(%s,6,头文件语句)\n", ch);
buffer = fgetc(fp);
return buffer;
}
}
if (ch[0] == ',' || ch[0] == ';' || ch[0] == '{' || ch[0] == '}' || ch[0] == '(' || ch[0] == ')')
{
printf("(%s ,5)\n", ch);//分隔符为第5类
buffer = fgetc(fp);
id = 4;//为什么是4,看131行
return(buffer);
}
if (ch[0] == '*' || ch[0] == '/')//扩充乘等与除等
{
buffer = fgetc(fp);
if (buffer == '=')//扩充部分
{
ch[1] = buffer;
ch[2] = '\0';
printf("(%s,4)\n", ch);
}
else
{
printf("(%s ,4)\n", ch);
id = 4;
return(buffer);
}//扩充部分结束
buffer = fgetc(fp);
id = 4;
return(buffer);
}
if (ch[0] == '=' || ch[0] == '!' || ch[0] == '<' || ch[0] == '>')//两个符号一起输出
{
buffer = fgetc(fp);
if (buffer == '=')
{
ch[1] = buffer;
ch[2] = '\0';
printf("(%s ,4)\n", ch);
}
else
{
printf("(%s ,4)\n", ch);
id = 4;
return(buffer);
}
buffer = fgetc(fp);
id = 4;
return(buffer);
}
if (ch[0] == '+' || ch[0] == '-')//扩充,+=,-=,++,--
{
if (id == 4) //在当前符号以前是运算符,则此时为正负号
{
int i = 1;
buffer = fgetc(fp);
ch[1] = buffer;
while (myisdigit(buffer = fgetc(fp)))//修改成可以读任意位数字
{
ch[++i] = buffer;
}
ch[i + 1] = '\0';//修改结束
printf("(%s ,3)\n", ch);
id = 3;
buffer = fgetc(fp);
return(buffer);
}
else
{
buffer = fgetc(fp);
if (buffer == '=' || buffer == '+' || buffer == '-')//+=、-=、++、--扩充部分
{
ch[1] = buffer;
ch[2] = '\0';
printf("(%s,4)\n", ch);
}
else
{
printf("(%s ,4)\n", ch);
id = 4;
return(buffer);
}//扩充结束
printf("(%s ,4)\n", ch);
buffer = fgetc(fp);
id = 4;
return(buffer);
}
}
}
六、运行结果截图
(1)输入测试程序如下所示:
(2)测试程序结果如下所示: