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

📄 scan.cpp

📁 上课时老师用过的SNL编译器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// scan.cpp: implementation of the Cscan class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "face.h"
#include "scan.h"
#include "global.h"
#include "MainFrm.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Cscan::Cscan()
{
	//在构造函数中初始化变量值:

	lineno = 0;
    linepos = 0;
    bufsize = 0;
	Tokennum=0;
	EOF_flag = FALSE;

    Error = false;

}

Cscan::~Cscan()
{

}

/****************************************************/
/* 文件	zscanner.cpp								*/
/* 说明 TINY编译器的词法扫描器实现					*/
/* 主题 编译器结构:原理和实例						*/
/****************************************************/

/*******************************************************************/
/* 函数名 getNextChar											   */
/* 功  能 取得下一非空字符函数									   */	
/* 说  明 该函数从输入缓冲区lineBuf中取得下一个非空字符		       */
/*        如果lineBuf中的字串已经读完,则从源代码文件中读入一新行   */
/*******************************************************************/
int Cscan::getNextChar(void)
{ 
   /* 当前代码输入行缓冲器lineBuf已经耗尽 */
   if (!(linepos < bufsize))				

   {
	/* 源代码行号lineno加1 */
    lineno++;
    
    /* 从源文件source中读入BUFLEN-2(254)个字符到行缓冲区lineBuf中      *
	 * fgets在的lineBuf末尾保留换行符.并在末尾加了一个NULL字符表示结束 */
	if (fgets(lineBuf,BUFLEN-1,source))	
    
	{ 	 
	  /* 如果源文件追踪标志EchoSource为TRUE                               *
	   * 将源程序行号lineno及行内容lineBuf在词法扫描时写入列表文件listing */
	  if (EchoSource) fprintf(listing,"%4d: %s",lineno,lineBuf);
	  
	  /* 取得当前输入源代码行的实际长度,送给变量bufsize */
	  bufsize = strlen(lineBuf);

	  /* 输入行缓冲区lineBuf中当前字符位置linepos指向lineBuf开始位置 */
	  linepos = 0;

	  /* 取得输入行缓冲区lineBuf中下一字符 */
      return lineBuf[linepos++];

    }
    else
	{ 
	  /* 未能成功读入新的代码行,fget函数返回值为NULL *
	   * 已经到源代码文件末尾,设置EOF_flag标志为TRUE */
	  EOF_flag = TRUE;					

   	  /* 函数返回EOF */
	  return EOF;
    }
  }

  /* 行输入缓冲区lineBuf中字符还未读完,直接取其中下一字符,函数返回所取字符 */
  else return lineBuf[linepos++];
}

/********************************************************/
/* 函数名 ungetNextChar									*/		
/* 功  能 字符回退函数									*/
/* 说  明 该过程在行输入缓冲区lineBuf中回退一个字符		*/
/*        用于超前读字符后不匹配时候的回退				*/
/********************************************************/
 void Cscan::ungetNextChar(void)
{
  /* 如果EOF_flag标志为FALSE,不是处于源文件末尾  *
   * 输入行缓冲区lineBuf中当前字符位置linepos减1 */
  if (!EOF_flag) 
	   linepos-- ;
}

/*****************************************************************/
/* 函数名 ChainToFile   										 */	
/* 功  能 将链表中的Token结点依次存入文件中                      */							    
/* 说  明  参数p是指针变量,指向Token链表的表头                  */
/*****************************************************************/
void Cscan::ChainToFile (ChainNodeType *Chainhead)
{ 
  int num=1;
  FILE *fp;
  ChainNodeType  *currentP=Chainhead;
/*创建一个新的文件"Tokenlist",以存储Token序列*/
  fp=fopen("c:\\Tokenlist","wb+");
  if (fp==NULL)
         {  printf("cannot create file Tokenlist!\n");
              exit(0);
	     }  
  
  fp=fopen("c:\\Tokenlist","ab");   /*按追加方式打开文件*/
    if (fp==NULL)
         {  printf("cannot open file Tokenlist!\n");
              exit(0);
	     }  
 /*从表头到表尾,依次将所有的Token写入文件*/ 
	do 
	{  fwrite(currentP,TOKENLEN,1,fp);
       currentP=currentP->nextToken;
       num++;
    }
    while (currentP!=NULL);

  fclose(fp);  /*关闭文件*/
}


/****************************************************************/
/* 函数名 printToken											*/	
/* 功  能 输出单词函数											*/
/* 说  明 该函数将单词及其词元写入列表文件listing				*/
/*        参数token指定了输出单词,参数tokenString指定了其词元	*/
/****************************************************************/
 void Cscan::printToken( TokenType token )

{
  /* 对函数参数token给定单词进行分类处理 */
  switch (token.Lex)

  { 
	/* 单词token为保留字,将保留字词元以指定格式写入列表文件listing */
    case  PROGRAM:   
    case  PROCEDURE:  
    case  TYPE:     
    case  VAR:      
    case  IF:        
    case  THEN:      
    case  ELSE:     
    case  FI:        
	case  WHILE:    
    case  DO:        
    case  ENDWH:    
    case  BEGIN:     
    case END:        
    case READ:       
    case WRITE:      
    case ARRAY:      
    case OF:         
    case RECORD:     
    case RETURN:    
    /*后来添加的*/
	case INTEGER:  
	case CHAR1:       
      fprintf(listing,
         "reserved word: %s\n",token.Sem);
      break;

 /*特殊符号 */
   
	/* 单词token为特殊符号:ASSIGN (赋值),将":="写入文件listing */
    case ASSIGN: fprintf(listing,":=\n"); break;
    
	/* 单词token为特殊符号:LT (小于),将"<"写入文件listing */
	case LT: fprintf(listing,"<\n"); break;
  
	/* 单词token为特殊符号:EQ (等于),将"="写入文件listing */
	case EQ: fprintf(listing,"=\n"); break;
    
	/* 单词token为特殊符号:PLUS (加号),将"+"写入文件listing */
	case PLUS: fprintf(listing,"+\n"); break;
 
	/* 单词token为特殊符号;MINUS (减号),将"-"写入文件listing */
	case MINUS: fprintf(listing,"-\n"); break;

	/* 单词token为特殊符号:TIMES (乘号),将"*"写入文件listing */
    case TIMES: fprintf(listing,"*\n"); break;

	/* 单词token为特殊符号:OVER (除号),将"/"写入文件listing */
    case OVER: fprintf(listing,"/\n"); break;

	/* 单词token为特殊符号:LPAREN (左括号),将"("写入文件listing */
	case LPAREN: fprintf(listing,"(\n"); break;

	/* 单词token为特殊符号:RPAREN (右括号),将")"写入文件listing */
    case RPAREN: fprintf(listing,")\n"); break;

	/* 单词token为特殊符号:LMIDPAREN (左中括号),将"["写入文件listing */
    case LMIDPAREN: fprintf(listing,"[\n"); break;    
	
	/* 单词token为特殊符号:RMIDPAREN (右中括号),将"]"写入文件listing */
    case RMIDPAREN: fprintf(listing,"]\n"); break; 

	/* 单词token为特殊符号:SEMI (分号),将";"写入文件listing */
	case SEMI: fprintf(listing,";\n"); break;

	/* 单词token为特殊符号:COLON (冒号),将":"写入文件listing */
    case COLON: fprintf(listing,":\n"); break;	

	/* 单词token为特殊符号:COMMA (逗号),将","写入文件listing */
    case COMMA: fprintf(listing,",\n"); break;	
		
	/* 单词token为特殊符号:DOT (程序结束符),将"."写入文件listing */
    case DOT: fprintf(listing,".\n"); break;	
	
    /* 单词token为特殊符号:UNDERANGE (下标界限),将".."写入文件listing */
	case UNDERANGE: fprintf(listing,";\n"); break;

	/* 单词token为簿记单词符号:ENDFILE (文件结尾),将EOF写入文件listing */
    case ENDFILE1: fprintf(listing,"EOF\n"); break;
    
	/* 单词token为多字符单词符号:INTC (数字),将数值写入文件listing */
	case INTC:
      fprintf(listing,
          "INTC, val= %s\n",token.Sem);
      break;

	/* 单词token为多字符单词符号:CHARC (字符),将字符写入文件listing */
	case CHARC:
      fprintf(listing,
          "CHARC, letter= %s\n",token.Sem);
      break;
	  
	/* 单词token为多字符单词符号:ID (标识符),将标识符名写入文件listing */
	case ID:
      fprintf(listing,
          "ID, name= %s\n",token.Sem);
      break;

	/* 单词token为簿记单词符号:ERROR (错误),将错误信息写入文件listing */
    case ERROR1:
      fprintf(listing, "ERROR: %s\n",token.Sem);
      break;

	/* 单词token为其他未知单词,未知信息写入文件listing,此种情况不应发生 */
    default: 
      fprintf(listing,"Unknown token: %d\n",token.Lex);
  }
}

/*****************************************************************/
/* 函数名 printTokenlist										 */	
/* 功  能 将文件"Tokenlist"中保存的Token序列写入列表文件listing中*/							    
/*        一般,listing指向标准输出。                            */
/* 说  明                                                        */
/*****************************************************************/
void Cscan::printTokenlist()
{  int num;
   TokenType currentToken;
    
   //输出信息部分:
	if (Error)
          fprintf(listing,">>词法分析有错,以ERROR打头的为错误的Token:\n");
	else  fprintf(listing,">>词法分析无错:Token序列如下:\n");
   
	//fprintf(listing, " \n>>scanner result :\n");
 /*按只读方式打开文件*/
   FILE *fp=fopen("c:\\Tokenlist","rb");
   if (fp==NULL)   
   {   fprintf(listing,"cannot create file Tokenlist!\n");
       exit(0);
   }  
/*从文件中依次读Token,并输出到listing指向的列表文件中去*/
 for (num=1;num<=Tokennum;num++)
   {/*从文件中读一个Token存入变量currentToken中*/  
	   fread(&currentToken,TOKENLEN,1,fp);
	   fprintf(listing,"\t%d:  ",currentToken.lineshow);
       printToken(currentToken);
    /*文件指针移到下一个Token的位置*/
       fseek(fp,num*TOKENLEN,0);
   }
 
 fclose(fp);  /*关闭文件*/


}

/**************************************************************/
/* 函数名 reservedLookup								      */
/* 功  能 保留字查找函数									  */
/* 说  明 使用线性查找,查看一个标识符是否是保留字			  */
/*		  标识符如果在保留字表中则返回相应单词,否则返回单词ID */
/**************************************************************/
LexType  Cscan::reservedLookup (char * s)

{ 
  int i;
 
  /* 在保留字表中查找,MAXRESERVED已经定义为8,为保留字数 */
  for (i=0;i<MAXRESERVED;i++)				

	/* 线性查保留字表,察看函数参数s指定标识符是否在表中 *
	 * 当两字符串匹配的时候,函数strcmp返回值为0(FALSE)	*/ 
    if (!strcmp(s,reservedWords[i].str))	

		/* 字符串s与保留字表中某一表项匹配,函数返回对应保留字单词 */
		return( reservedWords[i].tok);			

  /* 字符串s未在保留字表中找到,函数返回标识符单词ID */
  return ID;								
}

/****************************************
 ********* 词法扫描器基本函数  **********
 ****************************************/

/************************************************************/
/* 函数名 getTokenlist										*/
/* 功  能 取得单词函数										*/
/* 说  明 函数从源文件字符串序列中获取下一个单词符号		*/
/*        使用确定性有限自动机DFA,采用直接转向法    		*/
/*        超前读字符,对保留字采用查表方式识别    			*/
/*        产生词法错误时候,仅仅略过产生错误的字符,不加改正  */
/************************************************************/
 void  Cscan::getTokenList(CString  pgm)

{ 
/***************************************/
	//在构造函数中初始化变量值:
	lineno = 0;
    linepos = 0;
    bufsize = 0;
	Tokennum=0;
	EOF_flag = FALSE;

    Error = false;
/**************************************/

   	source =fopen(pgm ,"r");

   if (source==NULL)
   { 
      AfxGetApp()->m_pMainWnd->MessageBox("未找到源文件");
	  Error = true;

⌨️ 快捷键说明

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