⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scanner.cpp

📁 为简单的函数绘图语言编写一个解释器语法制导部分 语法制导注意:必须严格按照下面步骤调试程序
💻 CPP
字号:
#include "scanner.h"

#define TOKEN_LEN 100

static FILE *InFile;                //输入的文件
unsigned int LineNo;                //记录记号所在位置(行数)
static char TokenBuffer[TOKEN_LEN]; //记号缓冲区


//初始化词法分析器
int InitScanner(const char *Filename)
{
	LineNo=1;                                 
	InFile=fopen(Filename,"r");     //打开文件
	if(InFile!=NULL)return 1;       //打开文件成功
	else return 0;                  //打开文件失败
}

//关闭词法分析器
void CloseScanner(void)
{
	if(InFile!=NULL)fclose(InFile);//关闭所打开的文件
}

//从文件中获取一个字符
static char GetChar(void)
{
	int Char=getc(InFile);   //获取字符
	return toupper(Char);    //保持大小写一致
}

//把预读的字符回退到输入源程序中
static void BackChar(char Char)
{
	if(Char!=EOF)ungetc(Char,InFile);//当不是文件结束符时回退字符
}


//将字符加入记号缓冲区
static void AddCharTokenString(char Char)
{
	int TokenLength=strlen(TokenBuffer); //获取当前字符缓冲区的长度
	if(TokenLength+1>=sizeof(TokenBuffer))return;//判断长度是否超出缓冲区范围
	TokenBuffer[TokenLength]=Char;   //将当前字符加入字符缓冲区
	TokenBuffer[TokenLength+1]='\0'; //将下一位置为结束符
}

//清空记号缓冲区
static void EmptyTokenString()
{
	memset(TokenBuffer,0,TOKEN_LEN);
}

//判断所给字符是否在符号表中
static Token JudgeKeyToken(const char*IDString)
{
	int loop;   //定义循环变量
	for(loop=0;loop<sizeof(TokenTab)/sizeof(TokenTab[0]);loop++)
	//判断所给字符是否在符号表中
	{
		//符号表存在该符号
		if(strcmp(TokenTab[loop].lexeme,IDString)==0)
			return TokenTab[loop];
	}
	//不存在该符号,进行出错处理
	Token errortoken;
	memset(&errortoken,0,sizeof(Token));
	errortoken.type=ERRTOKEN;
	return errortoken;
}

//获取一个记号
extern Token GetToken(void)
{
	Token token;
	int Char;
	
	memset(&token,0,sizeof(Token));
	EmptyTokenString();
	token.lexeme=TokenBuffer;
	
	for(;;)//过滤源程序中的空格、TAB、回车等,遇到文件结束符返回空记号
	{
		Char=GetChar();//获取一个字符
		if(Char==EOF)//判断是否是文件结束符
		{
			token.type=NONTOKEN;
			return token;
		}
		if(Char=='\n')LineNo++;//当是回车符时,行数加一
		if(!isspace(Char))break;//不是空格,则跳出循环,进行字符判断
	}
	AddCharTokenString(Char);//将当前记号加入记号缓冲区
	if(isalpha(Char))//判断记号是否是保留字或参数名
	{
		for(;;)//将整个记号存入记号缓冲区
		{
			Char=GetChar();
			if(isalnum(Char))AddCharTokenString(Char);
			else break;
		}
		BackChar(Char);
		token=JudgeKeyToken(TokenBuffer);//判断记号类别
		token.lexeme=TokenBuffer;//获得记号
		return token;
	}
	else if(isdigit(Char))//判断记号是否是数字
	{
		for(;;)//获得整个整数并存入记号缓冲区
		{
			Char=GetChar();
			if(isdigit(Char))AddCharTokenString(Char);
			else break;
		}
		if(Char=='.')//若存在小数,则将小数部分也存入记号缓冲区
		{
			AddCharTokenString(Char);
			for(;;)
			{ 
				Char=GetChar();
				if(isdigit(Char))AddCharTokenString(Char);
				else break;
			}
		}
		BackChar(Char);
		token.type=CONST_ID;
		token.value=atof(TokenBuffer);//获得数字的值
		return token;
	}
	else  //不是字符和数字,则一定是运算符或分割符
	{
		switch(Char)
		{ case';':token.type=SEMICO;break;
		  case'(':token.type=L_BRACKET;break;
	   	  case')':token.type=R_BRACKET;break;
		  case',':token.type=COMMA;break;
		  case'+':token.type=PLUS;break;
		  case'-':
			  Char=GetChar();
			  if(Char=='-')//若是双减号,表示注释符
			  {
				  while(Char!='\n'&&Char!=EOF)Char=GetChar();
				  BackChar(Char);
				  return GetToken();
			  }
			  else//若是单减号,就表示减法
			  {
				  BackChar(Char);
				  token.type=MINUS;
				  break;
			  }
		  case'/':
			  Char=GetChar();
			  if(Char=='/')//若是双除号,表示注释符
			  {
				  while(Char!='\n'&&Char!=EOF)Char=GetChar();
				  BackChar(Char);
				  return GetToken();
			  }
			  else//若是单除号,表示是除法
			  {
				  BackChar(Char);
				  token.type=DIV;
				  break;
			  }
		  case'*':
			  Char=GetChar();
			  if(Char=='*')//若是双乘号,表示乘方运算
			  {
				  token.type=POWER;
				  break;
			  }
			  else//若是单乘号,表示乘法
			  {
				  BackChar(Char);
				  token.type=MUL;
				  break;
			  }
		  default:token.type=ERRTOKEN;break;
		}
	}
	return token;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -