编译原理—词法分析器实验报告
一、实验目的:
1.设计、编制、调试一个词法分析子程序-识别单词,加深对词法分析原理的理解。
2.掌握在对程序设计语言的源程序扫描的过程中,将其分解后各类单词的语法分析方法。
二、实验要求:
1. 对给定的程序通过词法分析器弄够识别一个个单词符号,并以二元式(单词种别码,单词符号的属性值)显示。而本程序则是通过对给定路径的文件的分析后以单词符号和文字提示显示。
2. 本程序自行规定:
(1)关键字"begin","end","if","then","else","while","write","read",
"do", "call","const","char","until","procedure","repeat"
(2)运算符:"+","-","*","/","="
(3)界符:"{","}","[","]",";",",",".","(",")",":"
(4)其他标记 如字符串,表示以字母开头的标识符。
(5)空格、回车、换行符跳过。
在屏幕上显示如下:
( 1 , 无符号整数)
( begin , 关键字 )
( if , 关键字 )
( +, 运算符 )
( ; , 界符 )
( a , 普通标识符 )
三、使用环境:
Window vista 下的 Visual Studio 2008;
四、实验步骤
1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提高分析能力。
五、流程图
五、调试程序:
1.举例说明
文件位置:C:\TEST.txt
目标程序如下:
Int main()
{
i=10;
j=100;
n=1;
sum=0;
mult=1;
while (i>0) {n=n+1;i=i-1;}
if (j>=50) then sum=sum+j; else {mult=mult*(j+1);sum=sum+i;}
if (i<=10) then sum=sum-i; else mult=mult+i/2;
if (i==j) then sum=sum-j; else mult=mult-j/2;
if (n>1) then n=n-1; else n=n+1;
if (n<2) then n=n+2; else n=n-2;
}
2.运行结果:
六、程序源代码:
#include <iostream>
#include<string>
using namespace std;
#define MAX 22
char ch =' ';
string key[15]={"begin","end","if","then","else","while","write","read",
"do", "call","const","char","until","procedure","repeat"};
int Iskey(string c){ //关键字判断
int i;
for(i=0;i<MAX;i++) {
if(key[i].compare(c)==0) return 1;
}
return 0;
}
int IsLetter(char c) { //判断是否为字母
if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;
else return 0;
}
int IsDigit(char c){ //判断是否为数字
if(c>='0'&&c<='9') return 1;
else return 0;
}
void analyse(FILE *fpin){
string arr="";
while((ch=fgetc(fpin))!=EOF) {
arr="";
if(ch==' '||ch=='\t'||ch=='\n'){}
else if(IsLetter(ch)){
while(IsLetter(ch)||IsDigit(ch)) {
if((ch<='Z')&&(ch>='A')) ch=ch+32;
arr=arr+ch;
ch=fgetc(fpin);
}
fseek(fpin,-1L,SEEK_CUR);
if (Iskey(arr)){cout<<arr<<"\t$关键字"<<endl;}
else cout<<arr<<"\t$普通标识符"<<endl;
}
else if(IsDigit(ch)){
while(IsDigit(ch)||ch=='.'&&IsDigit(fgetc(fpin))){
arr=arr+ch;
ch=fgetc(fpin);
}
fseek(fpin,-1L,SEEK_CUR);
cout<<arr<<"\t$无符号实数"<<endl;
}
else switch(ch){
case'+':
case'-' :
case'*' :
case'=' :
case'/' :cout<<ch<<"\t$运算符"<<endl;break;
case'(' :
case')' :
case'[' :
case']' :
case';' :
case'.' :
case',' :
case'{' :
case'}' :cout<<ch<<"\t$界符"<<endl;break;
case':' :{ch=fgetc(fpin);
if(ch=='=') cout<<":="<<"\t$运算符"<<endl;
else {cout<<"="<<"\t$运算符"<<endl;;
fseek(fpin,-1L,SEEK_CUR);}
}break;
case'>' :{ch=fgetc(fpin);
if(ch=='=') cout<<">="<<"\t$运算符"<<endl;
if(ch=='>')cout<<">>"<<"\t$输入控制符"<<endl;
else {cout<<">"<<"\t$运算符"<<endl;
fseek(fpin,-1L,SEEK_CUR);}
}break;
case'<' :{ch=fgetc(fpin);
if(ch=='=')cout<<"<="<<"\t$运算符"<<endl;
else if(ch=='<')cout<<"<<"<<"\t$输出控制符"<<endl;
else if(ch=='>') cout<<"<>"<<"\t$运算符"<<endl;
else{cout<<"<"<<"\t$运算符"<<endl;
fseek(fpin,-1L,SEEK_CUR);}
}break;
default : cout<<ch<<"\t$无法识别字符"<<endl;
}
}
}
void main(){
char in_fn[30];
FILE * fpin;
cout<<"请输入源文件名(包括路径和后缀名):";
for(;;){
cin>>in_fn;
if((fpin=fopen(in_fn,"r"))!=NULL) break;
else cout<<"文件路径错误!请输入源文件名(包括路径和后缀名):";
}
cout<<"\n********************分析如下*********************"<<endl;
analyse(fpin);
fclose(fpin);
cout<<endl;
cout<<"按任意键结束"<<endl;
int a;
cin>>a;
}
六、实验心得:
通过此次实验,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理的理解;熟悉了构造词法分析程序的手工方式的相关原理,使用某种高级语言(例如C++语言)直接编写此法分析程序。另外,也让我重新熟悉了C++语言的相关内容,加深了对C++语言的用途的理解。在本次实验中,我纠正了一个一直以来的概念错误:main不是关键字,它定义为程序的入口,是主函数!在本实验中,虽然我把main初始化在关键字表
(字符指针类型数组)*Key[10]中,当与该数组中字符串进行比较时,若与main匹配成功,则返回2,若为其他关键字则返回1,以此来把main从关键字中区别出来。
在本实验中的关键字表只初始化了几个常用的关键字,还可继续扩充(只需扩大数组,向其中补充要添加的关键字)。
第二篇:C语言词法分析器.doc
/**测试文件(将"x:=5;if(x>=0)then x:=2*x+1/3;else x:=2/x; for if(x<3) then yy:=100;邯郸市**#%#" 保存为 "源程序.txt" 文件)*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>FILE *fp=NULL;//源程序文件 FILE *fp1 = fopen("词法分析结果.txt","w");//把词法分析结果写到文件"分析结果.txt"中char temp[20];char str;char *keyWord[6] = {"for","if","then","else","while","do"};//关键字 1—6char *Others[] = {"+","-","*","/", ":", ":=","<>","<=",">",">=","=", ";" , "(",")","#"};//运算符,分隔符13-16 17-18 20-28 0void ClearTemp(){for(int i=0;i<20;i++){temp[i]=NULL;}}void NumberProcess(char str){char ch;int i=1;temp[0] = str;while(!feof(fp)){ch = fgetc(fp);if(isdigit(ch)){temp[i++] = ch;}else{ printf("(%d,%s)\n",11,temp);fprintf(fp1,"(%d,%s)\n",11,temp);break;} }fseek(fp,-1,SEEK_CUR);ClearTemp();}void LetterProcess(char str){char ch;int i=1;temp[0] = str;while(!feof(fp)){ch = fgetc(fp);if(isalpha(ch)||isdigit(ch)){temp[i++] = ch;}else{int j=0;for(j=0;j<6;j++){if(strcmp(temp,keyWord[j]) == 0){printf("(%d,%s)\n",j+1,temp);//fputs(temp,fp1);fprintf(fp1,"(%d,%s)\n",j+1,temp);break;} }if(j==6){//printf("(%s,%d)\n",p,j+1);printf("(%d,%s)\n",10,temp);//fputs(temp,fp1);fprintf(fp1,"(%d,%s)\n",10,temp);}fseek(fp,-1,SEEK_CUR);break;}}ClearTemp();}void OtherProcess(char str){switch(str)//{"+","-","*","/", ":", ":=","<>","<=",">",">=","=", ";" , "(",")","#"};//运算符,分隔符13-16 17-18 20-28 0{case '+': {printf("(%d,%c)\n",13,str);fprintf(fp1,"(%d,%c)\n",13,str);break;}case '-': {printf("(%d,%c)\n",14,str);fprintf(fp1,"(%d,%c)\n",14,str);break;}case '*':{printf("(%d,%c)\n",15,str);fprintf(fp1,"(%d,%c)\n",15,str);break;}case '/': {printf("(%d,%c)\n",16,str);fprintf(fp1,"(%d,%c)\n",16,str);break;}case ':':{char tp;tp = fgetc(fp);if(tp == '='){printf("(%d,%c%c)\n",18,str,tp);fprintf(fp1,"(%d,%c%c)\n",18,str,tp);break;}else{printf("(%d,%c%c)\n",17,str,tp);fprintf(fp1,"(%d,%c%c)\n",17,str,tp);fseek(fp,-1,SEEK_CUR);break;}}case '<': //"<","<>","<=",">",">=","=", ";" , "(",")","#"};//运算符,分隔符20-28 0{char tp;tp = fgetc(fp);if(tp == '>'){printf("(%d,%c%c)\n",21,str,tp);fprintf(fp1,"(%d,%c%c)\n",21,str,tp);break;}else if(tp == '='){printf("(%d,%c%c)\n",22,str,tp);fprintf(fp1,"(%d,%c%c)\n",22,str,tp);break;
}else{printf("(%d,%c)\n",20,str);fprintf(fp1,"(%d,%c%c)\n",20,str,tp);fseek(fp,-1,SEEK_CUR);break;}}case '>': //">",">=","=", ";" , "(",")","#"};//运算符,分隔符23-28 0{char tp;tp = fgetc(fp);if(tp == '='){printf("(%d,%c%c)\n",24,str,tp);fprintf(fp1,"(%d,%c%c)\n",24,str,tp);break;}else{printf("(%d,%c)\n",23,str);fprintf(fp1,"(%d,%c)\n",23,str);fseek(fp,-1,SEEK_CUR);break;}}//,"=", ";" , "(",")","#"};//运算符,分隔符25-28 0case '=': {printf("(%d,%c)\n",25,str);fprintf(fp1,"(%d,%c)\n",25,str);break;}case ';': {printf("(%d,%c)\n",26,str);fprintf(fp1,"(%d,%c)\n",26,str);break;}case '(': {printf("(%d,%c)\n",27,str);fprintf(fp1,"(%d,%c)\n",27,str);break;}case ')': {printf("(%d,%c)\n",28,str);fprintf(fp1,"(%d,%c)\n",28,str);break;}case '#': {printf("(%d,%c)\n",0,str);fprintf(fp1,"(%d,%c)\n",0,str);break;}default : if(!feof(fp)){printf("无法识别的字符\n");fprintf(fp1,"无法识别的字符\n");}break;}}int main(){//printf("词法分析结果如下:\n\n");if ((fp = fopen("源程序.txt","r")) == NULL)//打开文件{printf("can not open the file!\n");exit(0);//打不开文件,退出 }/*if ((fp1 = fopen("词法分析结果.txt","w")) == NULL)//打开文件{printf("can not open the file!\n");exit(0);//打不开文件,退出 }*//*char str;while(!feof(fp)){str = fgetc(fp);printf("%c",str);}*///str = fgetc(fp);while (!feof(fp))//文件中还有结束{str = fgetc(fp);//从文件中取出一个字符if (isalpha(str))//是英文字符{LetterProcess(str);//字母处理}else if (isdigit(str))//是数字{NumberProcess(str);//数字处理}else if(str == '\t' || str == ' '|| str == '\n'){;}else{OtherProcess(str);//其他字符处理}}printf("\n词法分析结束.词法分析结果已写入文件.\n");fclose(fp);//关闭文件fclose(fp1);system("pause");return 0;}