要求
1、编写的分析程序能够正确识别输入的C语言源程序中的单词符号;
2、识别出的单词以<种别码,值>的形式保存;
3、对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提醒。
附代码中用到的单词的种别码如下:
原理
编译,就是将将高级语言翻译成汇编语言或机器语言的过程,第一步是使用语法分析器将字符流转变成记号流,将源程序根据构词规则分解为一系列的单词,单词分为这几类:
(1) 关键词:program、const、var、integer、decimal、string、procedure、begin、end 、if、then、else、while、do、call、read、write、not等
(2) 标识符:也就是变量名、数组名等,规则为以字母、下划线、数字构成的字符串(只能以字母或者下划线打头)
(3) 常数:包括整型、实型等
(4) 运算符:=、<、<=、>、>=、+、-、*、/等
(5) 界符:逗号、分号、括号等
通过判断,将代码分解成单词,再以<syn,token>格式输出即可(即<种别码,单词>)
流程图
代码
#include<iostream>
#include<cstring>
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;
#
写在后面
欢迎大家指出错误的地方😁