实验一 词法分析
一、实验目的:
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)
二、实验预习提示
1、 词法分析器的功能和输出格式
词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。本实验中,采用的是一类符号一种别码的方式。
2、 单词的BNF表示
->
->||
|ε
->
-> |ε
-> +
-> -
-> >
-> >=
3、“超前搜索”方法
词法分析时,常常会用到超前搜索方法。如当前待分析字符串为“a>+”,当前字符为’>’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?显然,只有知道下一个字符是什么才能下结论。于是分析器读入下一个字符’+’,这时可知应将’>’解释为大于运算符。但此时,超前读了一个字符’+’,所以要回退一个字符,词法分析器才能正常运行。在分析标识符,无符号整数等时也有类似情况。
4、模块结构
三、实验过程
1、将单词分为五种
识别关键字:main、if、int、for、while、do、return、break、continue;单词种别码为1。
标识符;单词种别码为2。
常数为无符号整形数;单词种别码为3。
运算符包括:+、-、*、/、=、>、=、
分隔符包括:,、;、{、}、(、); 单词种别码为5。
2、程序思路
这在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
(1)定义部分:定义常量、变量、数据结构。
(2)初始化:从文件将源程序全部输入到字符缓冲区中。
(3)取单词前:去掉多余空白。
(4)取单词:读出单词的每一个字符,组成单词,分析类型。
(5)取单词后:去掉多余空白。
(6)显示结果。
3、数据输入及运行结果
输入数据为:
main()
{
int a,b;
a >= 10;
b = a + 20;
}#
运行结果为:
四、程序源码
#include
#include
#include
#include
char *table[7]={" ","main","int","if","then","else","return"},TOKEN[20],ch; //定义关键字 char *table2[10]={"+","-","*","/","=",">","=","
char * table3[6]={",",";","{","}","(",")"};//定义分隔符
int lookup(char *TOKEN){ //关键字匹配函数
int i;
for(i=0;i
if((strcmp(TOKEN,table[i])) == 0)
return 1;
}
/*
for(i=0;i
if((strcmp(TOKEN,table2[i])) ==0)
return 4;
}
for(i=0;i
if((strcmp(TOKEN,table3[i])) ==0)
return 5;
}*/
return 2;
}
void out(int c,char *TOKEN){ //输出函数
printf("(%d,%s)\n",c,TOKEN);
}
int zimu(char ch){ //字母判断函数
if((ch >= 'A' && ch
|| (ch >= 'a' && ch
return ch;
else
return 0;
}
int shuzi(char ch){ //数字判断函数
if(ch >= '0' && ch
return ch;
else
return 0;
}
int fenge(char ch){//分隔符判断函数
for(int i=0;i
if((strcmp(TOKEN,table3[i])) ==0)
return 5;
}
return 0;
}
void scanner(FILE *fp){ //扫描函数
char TOKEN[20]={'\0'};
char ch;
int i,c;
ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符
if(ch == ' ')
return;
if(zimu(ch)){ //判断该字符是否是字母
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(shuzi(ch)|| zimu(ch)){ //判断该字符是否是字母或数字
TOKEN[i] = ch;
i++;
ch = fgetc(fp);
}
fseek(fp,-1,1);
TOKEN[i] = '\0';
c = lookup(TOKEN);
out(c,TOKEN);
return;
}else if(shuzi(ch)){//判断数字
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(shuzi(ch)){ //判断该字符是否是字母或数字
TOKEN[i] = ch;
i++;
ch = fgetc(fp);
}
fseek(fp,-1,1);
TOKEN[i] = '\0';
out(3,TOKEN);
return;
}else {//判断分割符运算符
TOKEN[0]=ch;
int i;
for(i=0;i
if((strcmp(TOKEN,table3[i])) == 0){
out(5,TOKEN);
return;
}
}
for(i=0;i
if((strcmp(TOKEN,table2[i])) == 0){
if(i>=5){//双运算符
ch=fgetc(fp);
if(!(shuzi(ch) || zimu(ch) || ch == ' ')){
TOKEN[1]=ch;
}else
fseek(fp,-1,1);
}
out(4,TOKEN);
return;
}
}
}
}
int main()
{
FILE *fp;
if((fp=fopen("a.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);
} //如果不是空格,则回退一个字符并扫描
实验一 词法分析
一、实验目的:
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)
二、实验预习提示
1、 词法分析器的功能和输出格式
词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。本实验中,采用的是一类符号一种别码的方式。
2、 单词的BNF表示
->
->||
|ε
->
-> |ε
-> +
-> -
-> >
-> >=
3、“超前搜索”方法
词法分析时,常常会用到超前搜索方法。如当前待分析字符串为“a>+”,当前字符为’>’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?显然,只有知道下一个字符是什么才能下结论。于是分析器读入下一个字符’+’,这时可知应将’>’解释为大于运算符。但此时,超前读了一个字符’+’,所以要回退一个字符,词法分析器才能正常运行。在分析标识符,无符号整数等时也有类似情况。
4、模块结构
三、实验过程
1、将单词分为五种
识别关键字:main、if、int、for、while、do、return、break、continue;单词种别码为1。
标识符;单词种别码为2。
常数为无符号整形数;单词种别码为3。
运算符包括:+、-、*、/、=、>、=、
分隔符包括:,、;、{、}、(、); 单词种别码为5。
2、程序思路
这在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
(1)定义部分:定义常量、变量、数据结构。
(2)初始化:从文件将源程序全部输入到字符缓冲区中。
(3)取单词前:去掉多余空白。
(4)取单词:读出单词的每一个字符,组成单词,分析类型。
(5)取单词后:去掉多余空白。
(6)显示结果。
3、数据输入及运行结果
输入数据为:
main()
{
int a,b;
a >= 10;
b = a + 20;
}#
运行结果为:
四、程序源码
#include
#include
#include
#include
char *table[7]={" ","main","int","if","then","else","return"},TOKEN[20],ch; //定义关键字 char *table2[10]={"+","-","*","/","=",">","=","
char * table3[6]={",",";","{","}","(",")"};//定义分隔符
int lookup(char *TOKEN){ //关键字匹配函数
int i;
for(i=0;i
if((strcmp(TOKEN,table[i])) == 0)
return 1;
}
/*
for(i=0;i
if((strcmp(TOKEN,table2[i])) ==0)
return 4;
}
for(i=0;i
if((strcmp(TOKEN,table3[i])) ==0)
return 5;
}*/
return 2;
}
void out(int c,char *TOKEN){ //输出函数
printf("(%d,%s)\n",c,TOKEN);
}
int zimu(char ch){ //字母判断函数
if((ch >= 'A' && ch
|| (ch >= 'a' && ch
return ch;
else
return 0;
}
int shuzi(char ch){ //数字判断函数
if(ch >= '0' && ch
return ch;
else
return 0;
}
int fenge(char ch){//分隔符判断函数
for(int i=0;i
if((strcmp(TOKEN,table3[i])) ==0)
return 5;
}
return 0;
}
void scanner(FILE *fp){ //扫描函数
char TOKEN[20]={'\0'};
char ch;
int i,c;
ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符
if(ch == ' ')
return;
if(zimu(ch)){ //判断该字符是否是字母
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(shuzi(ch)|| zimu(ch)){ //判断该字符是否是字母或数字
TOKEN[i] = ch;
i++;
ch = fgetc(fp);
}
fseek(fp,-1,1);
TOKEN[i] = '\0';
c = lookup(TOKEN);
out(c,TOKEN);
return;
}else if(shuzi(ch)){//判断数字
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(shuzi(ch)){ //判断该字符是否是字母或数字
TOKEN[i] = ch;
i++;
ch = fgetc(fp);
}
fseek(fp,-1,1);
TOKEN[i] = '\0';
out(3,TOKEN);
return;
}else {//判断分割符运算符
TOKEN[0]=ch;
int i;
for(i=0;i
if((strcmp(TOKEN,table3[i])) == 0){
out(5,TOKEN);
return;
}
}
for(i=0;i
if((strcmp(TOKEN,table2[i])) == 0){
if(i>=5){//双运算符
ch=fgetc(fp);
if(!(shuzi(ch) || zimu(ch) || ch == ' ')){
TOKEN[1]=ch;
}else
fseek(fp,-1,1);
}
out(4,TOKEN);
return;
}
}
}
}
int main()
{
FILE *fp;
if((fp=fopen("a.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);
} //如果不是空格,则回退一个字符并扫描