【编译原理】类C语言词法分析器的设计

1.实验要求

输入为一个以类C语言编写的源程序

输出为一组二元组序列构成的文本文件,一行为一个二元组,二元组中间以逗号隔开

实验报告上要求附上DFA  

2.语言说明:

保留字:unsigned、break、return、void、case、float、char、for、while、continue、if、default、do、int、switch、double、long、else

运算符:+,-,*,/,>,>=,<,<=,==,!=,&&,||,!

界限符:{ }( ); ,

常量:十进制无符号数

标识符:以字母或下划线开始,后面跟上字母或数字

3.   实验原理

词法分析是编译的第一阶段。词法分析器的主要任务是读入源程序的输入字符,将它们组成词素,生成并输出一个词法单元序列,这个词法单元序列被输出到语法分析器进行语法分析。另外,由于词法分析器在编译器中负责读取源程序,因此除了识别词素之外,它还会完成一些其他任务,比如过滤掉源程序中的注释和空白,将编译器生成的错误消息与源程序的位置关联起来等。词法分析器的作用如下: 

读入源程序的输入字符,将它们组成词素,生成并输出一个词法单元序列; 

过滤掉源程序中的注释和空白; 

将编译器生成的错误消息与源程序的位置关联起来; 

4.DFA设计:【编译原理】类C语言词法分析器的设计_第1张图片

5.实验代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef pair mp;
const string key_word[]={"unsigned","break","return","void","case","float","char","for","while","continue","if","default","do","int","switch","double","long","else"};//保留字
const string operators[]={"+","-","*","/",">",">=","<","<=","==","!=","&&","||","!"};//运算符
const char jiefu[]={',',';','(',')','{','}'};//界符
map flag_table;//标识符表等
mapnum_table;//常量表
mapstr_table;//字符串表
maphead_table;//头文件表
mapchar_table;//字符表
mapfenjiefu_table;//分界符表
int keymark[40],operatormark[40];
int isjiefu(char ch)
{
	for(int i=0;i<5;i++)
		if(ch==jiefu[i])
			return 1;
	return 0;
}
//判断是不是关键字
int iskey(string ch)
{
	int i;
	for(i=0;i<17;i++)
		if(key_word[i]==ch)
			return i;
	return -1;
}
int isope(string ch)
{
	int i;
	for(i=0;i<12;i++)
		if(operators[i]==ch)
			return i;
	return -1;
}
int ischar(char ch)
{
	if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')
		return 1;
	return -1;
}
int isnumber(char ch)
{
	if(ch>='0'&&ch<='9')
		return 1;
	return -1;
}
//获得关键字或者标识符
void get_keyflag(char* ptr,FILE* f)
{
	string token;
	token+=*ptr;
	while(1)
	{
		*(++ptr)=fgetc(f);
		if(ischar(*ptr)==-1&&isnumber(*ptr)==-1&&*ptr!='_')
		break;
		token+=*ptr;
	}
	ungetc(*ptr,f);
	//*ptr='\0';
	int h=iskey(token);
	if(h>=0)//是关键字
	{
		if(!keymark[h])
			keymark[h]=1;
		cout<::iterator it;
			it=flag_table.find(token);
			tmp=it->second;
		}
		cout<::iterator it;
		it=num_table.find(token);
		tmp=it->second;
	}
	cout<"<::iterator it;
		it=str_table.find(token);
		mp tmp;
		if(it==str_table.end())//新的字符串
		{

			tmp=make_pair(3,str_table.size()+1);
			str_table[token]=tmp;
		}
		else
		{tmp=it->second;}
		cout<=0)
	{
		operatormark[p]=1;
		cout<=0)
	{
		operatormark[index]=1;
		cout<127)
			cout<<"输入的不是ascii码"<"<"<'||*ptr=='"')
			   break;
		   tmp+=*ptr;
	   }
	   mp p;
	   if(head_table.find(tmp)==head_table.end())
	   {
		   p=make_pair(4,head_table.size()+1);
		   head_table[tmp]=p;
	   }
	   else
	   {
		   map::iterator it;
		   it=head_table.find(tmp);
		   p=it->second;
	   }
	   cout<"<"<'||*ptr=='<')
	{
		double_operator(ptr,f);}
	else if(isjiefu(*ptr)==1)
	{
		mp tmp;
		map::iterator it;
		if(fenjiefu_table.find(*ptr)==fenjiefu_table.end())
		{
			tmp=make_pair(6,fenjiefu_table.size()+1);
			fenjiefu_table[*ptr]=tmp;}
		else
		{
			it=fenjiefu_table.find(*ptr);
			tmp=it->second;}
		 cout<<*ptr<<" , "<<"界符"<

输入的类C词法

char word[10];
        char pro[100][100] = { "PROGRAM", 

"BEGIN", "END", "VAR", "INTEGER", "WHILE", "IF", "THEN", 

"ELSE", "DO", "PROCEDURE" ,


"char","int","if","else","var" 

,"return","break","do","while","for","double","float","short"};

        int n = 0;
        word[n++] = a[i++];
        while ((a[i] >= 'A'&&a[i] <= 'Z') || (a

[i] >= '0' && a[i] <= '9')||(a[i]>='a'&&a[i]<='z'))
        {
            word[n++] = a[i++];
        }
        word[n] = '\0';
        i--;

程序运行输出结果:

【编译原理】类C语言词法分析器的设计_第2张图片【编译原理】类C语言词法分析器的设计_第3张图片

6.分析讨论:

(1)遇见问题:二目运算符无法识别 ,导致拆分识别为两个单目运算符;第二个问题就是如果识别的词法带有注释,会报错。

(2)解决方法: 修改识别运算符代码部分加入双目运算符的识别

(3)后续改进思路:一个不方便的地方就是没能实现通过输入文件名读取文件的数据,每次读入新的文件仍需要修改代码。

你可能感兴趣的