河工大编译原理

河北工业大学编译原理实验
c++/c
词法分析


```cpp
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
#include <math.h>
#include<ctype.h>
#define BEGIN 1
#define END 2
#define	IF 3
#define THEN 4
#define ELSE 5
#define FOR 6
# define ID 7	//标识符
# define LT 8	//小于
# define LE 9   //小于等于
# define EQ 10	//等于
# define NE 11	//不等于
# define GT 12	//大于
# define GE 13	//大于等于
# define IS 14	//赋值
# define PL 15	//加
# define MI 16	//减
# define MU 17  //乘
# define DI 18  // 除
char TOKEN[20];//依次存放一个单词英文中的各个字符
char to[20];  //存放下一个要分析的单词
int lookup (char*);//以TOKEN中的字符串查保留字表
void out(int, char*);//输出函数
void report_error ();//报告出错
void scanner_example (FILE *);//遍历文件查询
int HandleOtherWord (void);//处理出错
#define chushi 0
#define DIGIT 1
#define POINT 2
#define OTHER 3
#define POWER 4
#define PLUS 5
#define MINUS 6
#define UCON 7 //无符号数常量的类号是7
#define ClassOther 200
#define EndState -1

int w,n,p,e,d,j;
int ICON;
int row=1;
int Class;//用来表示单词的等级
float FCON;
static int CurrentState;//用来表示当前状态,初始状态值为0
int GetChar (int c);
int EXCUTE (int,int);
int LEX (void);

//建立保留字表
#define MAX_KEY_NUMBER 20 //关键字的数量
#define KEY_WORD_END "waiting for your expanding"  //关键字结束标记
char *KeyWordTable[MAX_KEY_NUMBER]={"begin","end","if","then","else","for",KEY_WORD_END};//保留字表

//查保留字表,判断是否为关键字
int lookup(char* token)
{
	int n=0;
	while(strcmp(KeyWordTable[n],KEY_WORD_END))//strcmp 比较两串是否相同,若相同返回0  保留字与关键字结束标记不一样,接着执行
	{
		if(!strcmp(KeyWordTable[n],token))//比较token所指向的关键字和保留字表中哪个关键字相符
		{
			return n+1;  //返回类别码的值
			break;
		}
		n++;
	}
	return 0;//单词不是关键字,而是标识符
}

int HandleOtherWord (void)
 {
	return ClassOther; 
 }

//报错函数
int HandleError (void)
{
	FILE *fpt;
	fpt = fopen("输出1.txt","a");//打开文本文档进行写入
	fprintf(fpt,"识别失败!\n"); 
	return 0;
}
//主函数,打开并读文件
void main(void)
{
    FILE *fp;
	if((fp=fopen("编译1.txt","r"))==NULL)//打开文件,打不开则报错
	{
		printf("\nfile open error!!\n");
		exit(1);
	}		
	do{
		scanner_example(fp);//查询文件, 直到文件结束 
	}while(fgetc(fp)!=EOF);
	
	fclose(fp);//关闭文件

}

void scanner_example (FILE *fp)
{
	char ch;
	int i, c;
	ch=fgetc(fp);     //fgetc函数 在文件中读取一个字符,赋值给ch

	while(ch!=EOF)          //文件不结束时一直执行
	{
		//判断是否为关键字或者标识符
		if (isalpha (ch))   //判断字符ch是否为英文字母,若为英文字母,返回非0(小写字母为2,大写字母为1)。若不是字母,返回0。
		{
			TOKEN[0]=ch; //将字符存到token中
			to[0]=ch;
			ch=fgetc(fp); //再往下读一个字符
			//if(ch=='\n') row++;
			i=1;
			while (isalnum (ch))//检查所传的字符是否是字母和数字,如果ch是一个数字或一个字母,则该函数返回非零值,否则返回 0
			{//当ch不是数字或者字母时结束while循环
				TOKEN[i]=ch; //存入字符
				to[i]=ch;
				i++;
				ch=fgetc(fp);//再往下读一个字符
			//	if(ch=='\n') row++;
			}
			TOKEN[i]= '\0';//结束token
			to[i]='\0';
			fseek(fp,-1,1);  // retract fseek函数 每调用一次,就把扫描指示器回退一个字符位置(即退回多读的那个字符)
			                //fp为文件指针,-1:为偏移量,正数表示正向偏移,负数表示负向偏移;1:设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
	                 //SEEK_SET: 文件开头SEEK_CUR: 当前位置 SEEK_END: 文件结尾其中SEEK_SET, SEEK_CUR和SEEK_END依次为0,1和2.
	                 //指针退回到离文件当前位置1字节处
			
			//保留字
			c=lookup(TOKEN);//检查TOKEN中的字符串是否为保留字,若有则将相应的关键字的类别码赋给c,否则c=0
			if (c==0)
			{//输出为标识符
			FILE *fpt;
			fpt = fopen("输出1.txt","a");//打开文本文档进行写入
			fprintf(fpt,"(ID,'%s')\n",TOKEN);
			fclose(fpt);
			}
			else 
				out (c," ");    //说明为关键字
	 	    if(ch==EOF)//文件读完,跳出循环
			{
				break;
			}
		}
		//判断是否为“无符号数”
		else if (isdigit(ch)||ch=='.') //当第一个字符为数字时 当ch为数字0-9时,返回非零值,否则返回零
		{//第一个为数字或者点
			to[0]=ch;
			int CurrentState=0;
			char y=GetChar(ch);//每调用一次,就把扫描指示器当前所指示的源程序字符送入字符变量ch,
			                   //然后把扫描指示器前推一个字符位置。
			CurrentState=EXCUTE(CurrentState,y);//状态
			//循环判断过程
			i=1;
			while (CurrentState!=EndState)//当前状态不是结束状态时,到结束时为止
			{
				ch=fgetc(fp); //再读入一个字符
				to[i]=ch;
				i++;
				y=GetChar(ch);
				CurrentState=EXCUTE(CurrentState,y);
			}

	    	if(j==0)
			{
				
            	FILE *fpt;
	            fpt = fopen("输出1.txt","a");//打开文本文档进行写入
				fprintf(fpt,"(INT,%d)\n",ICON);//无符号数整形常数
				fclose(fpt);
				TOKEN[8]= '\0';///
				to[i]='\0';
				fseek(fp,-1,1);
			}
			else if(j==3)
			{
				
				FILE *fpt;
				fpt = fopen("输出1.txt","a");//打开文本文档进行写入
				fprintf(fpt,"包含多个小数点,识别失败!!\n");//无符号数 实型常数
				fclose(fpt);
				TOKEN[8]= '\0';
				to[i]='\0';
				fseek(fp,1,1);//识别错误之后还可以继续识别
			
			}
			else if(j==4)  
			{	
				to[i]='\0';
			}
			else
			{
				
               	FILE *fpt;
            	fpt = fopen("输出1.txt","a");//打开文本文档进行写入
			    fprintf(fpt,"(REAL,%g)\n",FCON);//无符号数 实型常数
				fclose(fpt);
				TOKEN[8]='\0';//结束token
				to[i]='\0';
				fseek(fp,-1,1);//返回一个字符
			} 
			if(ch==EOF)//结束
			{
				break;
			}
		}

		//判断第一个字符是否为运算符
		else         
			switch(ch)
		{
			to[0]=ch;
			i=1;
          case'<':
			  ch=fgetc(fp);    //再读入一个字符           
			  if(ch=='=')
			  {
				  to[i]=ch;
				  i++;
				  out(LE," ");    // <=
				  to[i]='\0';
			  }
			  else if(ch=='>') 
			  {
				  to[i]=ch;
				  i++;
				  out(NE," ");       // <>
				  to[i]='\0';
			  }
			 else
			  {      
				 //to[i]=ch;
				  out (LT," "); // <
				 // i++;
				   to[i]='\0';
				  if(ch==EOF) //如果结束了,则跳出循环
				  {
					  break;
				  }
				  else 
					  fseek (fp,-1,1);	//返回上一个字符			  
			  }
			  break;
		  case '=':
			        out(EQ, " ");      // =  
					 to[i]='\0';
					
			         break;
		  case ':': 
			        ch=fgetc(fp);            
					if(ch=='=')
					{
					to[i]=ch;
					i++;
				    out(IS," ");// :=
					to[i]='\0';
					}
			       else if(ch==EOF)
				   {
				       break;
				   }
			       else
				   { 
				        if(ch==EOF)//结束
						{
							break;
						}
						else {
							fseek (fp,-1,1);//返回一个字符
				            //report_error();//报告出错位置
						}
				   }
			        break;
		  case'>':
			  ch=fgetc(fp);                 
			  if(ch=='=')
			  {
				  to[i]=ch;
				  i++;
				  out(GE," ");    //>=   
				  to[i]='\0';
			  }
			  
			  else
			  {
				   to[i]=ch;
				  i++;
				  out(GT," "); //>
                   to[i]='\0';
				   if(ch==EOF)
				   {break;}
				  else fseek (fp,-1,1);//返回一个字符
			  }
			  break;
		  case'+':
			       to[i]=ch;
				    i++;
                   to[i]='\0';
			  out(PL," ");break;       
		  case'-':
			  to[i]=ch;
			  i++;
              to[i]='\0';
			  out(MI," ");break;            
		  case'*':
			  to[i]=ch;
			  i++;
              to[i]='\0';
			  out(MU," ");break;           
		  case'/':
			  to[i]=ch;
			  i++;
              to[i]='\0';
			  out(DI," ");break;  
		  case' ':
			  break;  
		 case'\n':
				 row++;
			    break;

		  default: report_error(); //报告出错位置
			  break;
		}
		ch=fgetc(fp);
	}
	return;
}

/*输出函数*/
void out(int c,char*v)  
{
    FILE *fpt;
	fpt = fopen("输出1.txt","a");//打开文本文档进行写入
	char* cl="";//定义一个字符
	switch(c)
	{
		case BEGIN:
			cl = "BEGIN"; break;
	    case END:
			cl = "END"; break;
	    case IF:
			cl = "IF"; break;
	    case THEN:
			cl = "THEN"; break;
  	    case ELSE:
			cl = "ELSE"; break;
	    case ID:
			cl = "ID"; break;
	    case LE:
			cl = "LE"; break;
	    case LT:
			cl = "LT"; break;
	    case EQ: 
			cl = "EQ"; break;
	    case NE: 
			cl = "NE"; break;
	    case GT: 
			cl = "GT"; break;
	    case GE:
			cl = "GE"; break;
	    case IS: 
			cl = "IS"; break;
	    case PL:
			cl = "PL"; break;
  	    case MI: 
			cl = "MI"; break;
	    case MU: 
			cl = "MU"; break;
	    case DI: 
			cl = "DI"; break;
		case FOR:
			cl = "FOR"; break;
	}

	fprintf(fpt,"(%s,%s)\n",cl,v);
	fclose(fpt);
}

void report_error()
{
	printf("error");

}

//每调用一次,就把扫描指示器当前所指示的源程序字符送入字符变量ch,然后把扫描指示器前推一个字符位置。
int GetChar (int c)
{
	if(isdigit(c))//若参数ch为阿拉伯数字0~9,则返回非0值,否则返回0 
	{//数字
		d=c-'0';
		return DIGIT;
	}
	if (c=='.') 
		return POINT;//返回点
	if (c=='E'||c=='e')
		return POWER;//返回给定数字的乘幂
   if (c=='+') 
	   return PLUS;
   if (c=='-') 
	   return MINUS;
   return OTHER;
}

//识别无符号数
int EXCUTE (int state, int symbol)//状态和DIGIT这种标志
{
	j=0;
	switch (state)
	{
	case 0:
		switch (symbol)
		{
		case DIGIT: n=0;p=0;e=1;w=d;CurrentState=1;Class=UCON;break;
        case POINT: w=0;n=0;p=0;e=1;CurrentState=3;Class=UCON;break;
        default: HandleOtherWord();Class=ClassOther;
		     	CurrentState=EndState;
		}break;
		
	case 1:
		switch (symbol)
		{
		case DIGIT: w=w*10+d;CurrentState=1;break;         //CurrentState=1
        case POINT: CurrentState=2;break;
        case POWER: CurrentState=4;break;
        default: ICON=w;CurrentState=EndState;j=0;//整型常数
        }break;
    case 2:
		switch (symbol)
        {
        case DIGIT: n++;w=w*10+d;CurrentState=2;break;
        case POWER: CurrentState=4;break;
        case POINT: CurrentState=EndState;j=3;break;
        default: FCON=float(w*pow(10,e*p-n));CurrentState=EndState;j=1;//实型常数
        }break;
    case 3:
		switch (symbol)
        {
        case DIGIT: n++;w=w*10+d;CurrentState=2;break;
        default: HandleError();CurrentState=EndState;j=4;
        }break;
    case 4:
		switch (symbol)
        {
        case DIGIT: p=p*10+d;CurrentState=6;break;
        case MINUS:e=-1; CurrentState=5;break;
        case PLUS: CurrentState=5;break;
        default: HandleError();CurrentState=EndState;
        }break;
    case 5:
		switch (symbol)
        {
        case DIGIT: p=p*10+d;CurrentState=6;break;
        default: HandleError();CurrentState=EndState;
        }break;
    case 6:
		switch (symbol)
        {
		case DIGIT:p=p*10+d;CurrentState=6;break;
        default: FCON=w*pow(10,e*p-n);CurrentState=EndState;j=1;
        }break;

	}
	return CurrentState;
}



  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值