编译原理:简单词法分析器的实现

要求

1、编写的分析程序能够正确识别输入的C语言源程序中的单词符号;
2、识别出的单词以<种别码,值>的形式保存;
3、对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提醒。
附代码中用到的单词的种别码如下:
编译原理:简单词法分析器的实现_第1张图片

原理

编译,就是将将高级语言翻译成汇编语言或机器语言的过程,第一步是使用语法分析器将字符流转变成记号流,将源程序根据构词规则分解为一系列的单词,单词分为这几类:
(1) 关键词:program、const、var、integer、decimal、string、procedure、begin、end 、if、then、else、while、do、call、read、write、not等
(2) 标识符:也就是变量名、数组名等,规则为以字母、下划线、数字构成的字符串(只能以字母或者下划线打头)
(3) 常数:包括整型、实型等
(4) 运算符:=、<、<=、>、>=、+、-、*、/等
(5) 界符:逗号、分号、括号等
通过判断,将代码分解成单词,再以格式输出即可(即<种别码,单词>)

流程图

编译原理:简单词法分析器的实现_第2张图片

代码

#include
#include 
using namespace std;
//定义 
int i,p,syn,row,j;//syn是单词种别码 
char ch; 
char *keyword[12]={"int","for","break","switch","case","do","if","else","return","while","void","default"};//关键字
int kwsyn[12]={1,2,3,4,5,6,7,8,9,10,11,12};//关键字的种别码 
char token[8],prog[80];//token存放单词,prog存放代码串 
void gettoken()
{
	for(i=0;i<8;i++) token[i]=NULL;//每一次判断时需要将token赋空 
	ch=prog[p++];
	//解决空格问题
	while(ch==' ')
    {
        ch=prog[p];
        p++;
    } 
	/*识别关键字或者变量名*/ 
	if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch == '_')) //变量名以字母或者下划线开头 
	{
		j=0;
		while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch == '_')) //变量名可由字母、下划线、数字组成
		{
			token[j++]=ch;
			ch=prog[p++]; 
		} 
		token[j++]='\0';
		p--;
		syn=13;//标识符种别码 
		for(i=0;i<12;i++)//12是keyword长度
		{
			if(strcmp(token,keyword[i])==0)
			{
				syn=kwsyn[i];//假如单词与关键字一致,则可判断为关键字 
				break; 
			}
		} 
	}
	/*识别实数*/
	else if(ch>='0'&&ch<='9') 
	{
		bool isDouble=false;//是否是小数
		int j=0;
		while(ch>='0'&&ch<='9')//实数开头必然为0=9 
		{
			token[j++]=ch;//将开头部分打入token 
			ch=prog[p++];
		}
		if(ch=='.')//遇到'.'可知是浮点数 
		{
			isDouble=true;
			token[j++]=ch;//将'.'打入token 
			ch=prog[p++];
			while(ch>='0'&&ch<='9')
			{
				token[j++]=ch;//将'.'后面的数字打入token 
			    ch=prog[p++];
			}
		} 
		if(isDouble) syn=14; //常量种别码 
        if(!isDouble) syn=14;//假如需要区分整数与浮点数,修改syn即可 
        p--; 
        /*
        token值溢出,问题,将数组转变成数值 
		if(token>32767)
            syn=-1;
        }*/
	} 
	/*其他字符*/
	else switch(ch)
	{
		case'+':
		    j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=30;//+=的种别码 
			}
			else if(ch=='+')
			{
				token[j++]=ch;
				//对+++……的识别
				ch=prog[p++];
				if(ch=='+')
				{
					token[j++]=ch;
				    syn=-1;//Error种别码 
				}
				else
				{
					syn=31;//++的种别码 
					p--;
				}
			}
			else
			{
				syn=15;//+的种别码
				p--;
			}
			break;
		case'-':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=32;//-=的种别码 
			}
			else if(ch=='-')
			{
				token[j++]=ch;
				//对---的识别
				ch=prog[p++];
				if(ch=='-')
				{
					token[j++]=ch;
				    syn=-1;//Error种别码 
				}
				else
				{
					syn=33;//---的种别码 
					p--;
				} 
			}
			else
			{
				syn=16;//-的种别码
				p--;
			}
			break;
		case'*':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=34;//*=的种别码 
			}
			else
			{
				syn=17;//*的种别码
				p--;
			}
			break;
		case'/':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=35;//  /=的种别码 
			}
			else
			{
				syn=18;//  /的种别码
				p--;
			}
			break;
		case'%':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=36;//%=的种别码 
			}
			else
			{
				syn=19;//%的种别码
				p--;
			}
			break;
		case'=':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=21;//==的种别码 
			}
			else
			{
				syn=20;//*的种别码
				p--;
			}
			break;
		case'<':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='>')
			{
				token[j++]=ch;
				syn=37;//<>的种别码 
			}
			else if(ch=='=')
			{
				token[j++]=ch;
				syn=38;//<=的种别码 
			}
			else
			{
				syn=22;//<的种别码
				p--;
			}
			break;
		case'>': 
		    j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=39;//>=的种别码 
			}
			else
			{
				syn=23;//>的种别码
				p--;
			}
			break;
		case'!':
			j=0;
			token[j++]=ch;
			ch=prog[p++];
			if(ch=='=')
			{
				token[j++]=ch;
				syn=24;//!=的种别码 
			}
			else
			{
				syn=-1;//deafult的种别码
				p--;
			}
			break;
		case';':syn=25;token[0]=ch;break;
		case'(':syn=26;token[0]=ch;break;
		case')':syn=27;token[0]=ch;break;
		case'{':syn=28;token[0]=ch;break;
		case'}':syn=29;token[0]=ch;break;
		case'#':syn=0;token[0]=ch;break;
		case'\n':syn=-2;break;
		default:syn=-1;break;	
	}
} 
 
int main()
{
	i=0;
	row=1;
	cout<<"Please input:"<<endl;
	//#为终止符,输入代码串 
	do
    {
        cin.get(ch);
        prog[p++]=ch;
    }while(ch!='#');
	p=0;
	do
	{
		gettoken();
		switch(syn)
		{
			case -1: cout<<"Error in row "<<row<<"!"<<endl; break;
            case -2: row=row+1;break;
            default: cout<<"<"<<syn<<","<<token<<">"<<endl;break;//种别码1-39的情况 
		}
	}while(syn!=0);
	
}

测试案例

输入以下的代码,可以看出关键字、标识符、运算符等是可以按照参考的种别码表一一对应的,且不在种别码内的+++、?被提示错误。

int s=10;
s+=1;
s-=1;
s++;
s+++;
b=a+c;
?}
int _ching_10;
#

编译原理:简单词法分析器的实现_第3张图片

写在后面

欢迎大家指出错误的地方

你可能感兴趣的:(编译原理,c++)