#include<stdio.h>     //包含库所用的某些宏和变量
#include<stdlib.h>    //包含库
#include<string.h>    //包含字符串处理库
#define _KEY_WORD_END "waiting for your expanding"     //定义关键字结束标志
typedef struct  
{
	int typenum;  
    char * word;
}WORD;
char input[255];      //输入换缓冲区
char token[255]="";   //单词缓冲区
int p_input;          //输入换缓冲区指针
int p_token;          //单词缓冲区指针
char ch;              //当前所读的字符
char *rwtab[]={"begin","if","then","while","do","end",_KEY_WORD_END};        //C语言关键字
WORD * scaner();    //词法扫描函数,获得关键字


main()
{  
	int over=1;  
    WORD *oneword;  
	oneword=(WORD *)malloc(sizeof(WORD));  
    printf("Input your code(end with #):");   //读入源程序字符串到缓冲区,以#结束,允许多行输入    
    scanf("%[^#]s",input);                         
    p_input=0;        
	printf("The code is:\n%s\n\n",input);  	
	while(over<1000&&over!=-1)    
	{            
		oneword=scaner();          
		printf("(%d,%s)\n",oneword->typenum,oneword->word);         
		over=oneword->typenum;  
    }
}

//需要用到的自编函数参考实现

//从输入缓冲区读取一个字符到ch中

char m_getch()
{      
	ch=input[p_input];         
	p_input=p_input+1;      
	return (ch);
}

//去掉空白字符

void getbc()
{  
      
	while(ch==' '||ch==10)     
	{       
		ch=input[p_input];   
		p_input=p_input+1;  
	}
}

//拼接单词

void concat()
{  
       
	token[p_token]=ch;      
	p_token=p_token+1;    
	token[p_token]='\0';
}

//判断是否字母

int letter()
{  
	if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')
		return 1;  
	else
		return 0;
}

//判断是否数字

int digit()
{        
	if(ch>='0'&&ch<='9')   
		return 1;  
	else  
		return 0;
}

//检索关键字表格

int reserve()
{  
	int i=0;  
	while(strcmp(rwtab[i],_KEY_WORD_END)) //数组中的单词跟输入的单词比较
	{
		if(!strcmp(rwtab[i],token))
		{
			return i+1;
		}
		i=i+1;
	}
	return 10;
}

//回退一个字符

void retract()
{  
	p_input=p_input-1;
}


WORD *scaner()//扫描单词
{  
	WORD *myword;  
	myword=(WORD *)malloc(sizeof(WORD));  
    myword->typenum=10;
    myword->word=""; 
    p_token=0;  
    m_getch();  
	getbc();    
    if(letter())     
    {       
		while(letter()||digit())      
		{         
			concat();       
			m_getch();    
		}                  
		retract();                 
        myword->typenum=reserve();              
		myword->word=token;         
		return(myword);        
	}            
	else if(digit())         
	{  
		while(digit())  
		{ 
			concat();  
			m_getch();  
		}  
		retract();  
		myword->typenum=11; 
        myword->word=token;  
		return(myword);
	}  
	else  
	{  
		switch(ch)   
		{   
		case'+':
			myword->typenum=13;
			myword->word="+";
			return(myword);
			break;
		case'-':
			myword->typenum=14;
			myword->word="-";
			return(myword);
			break;
		case'*':
			myword->typenum=15;
			myword->word="*";
			return(myword);
			break;
		case'/':
			myword->typenum=16;
			myword->word="/";
			return(myword);
			break;
		case':':
			m_getch(); 
			if(ch=='=')    
			{     
				myword->typenum=18;
				myword->word=":=";  
				return(myword);  
			}   
			retract();   
			myword->typenum=17; 
			myword->word=":";  
			return(myword); 
			break;   
		case'<':
			m_getch(); 
			if(ch=='=')    
			{     
				myword->typenum=21;
				myword->word="<=";  
				return(myword);  
			}   
			else if(ch=='>')
			{
				myword->typenum=22;
				myword->word="<>";
				return(myword);
			}
			retract();   
			myword->typenum=20; 
			myword->word="<";  
			return(myword); 
			break;   
		case'>':
			m_getch(); 
			if(ch=='=')    
			{     
				myword->typenum=24;
				myword->word=">=";  
				return(myword);  
			}   
			retract();   
			myword->typenum=23; 
			myword->word=">";  
			return(myword); 
			break;   
		case'=':   
			myword->typenum=25; 
			myword->word="=";  
			return(myword);    
			break;  
		case';':   
			myword->typenum=26;  
			myword->word=";";    
			return(myword);   
			break;   
		case '(':   
			myword->typenum=27;   
			myword->word="(";   
			return(myword);  
			break;
		case ')':    
			myword->typenum=28;  
			myword->word=")";   
			return(myword);   
			break;  
		case '#':
			myword->typenum=0;  
			myword->word="OVER";   
			return(myword);   
			break;   
		case '\0':   
			myword->typenum=1000; 
			myword->word="#";  
			return(myword);   
			break;
		default:   
			myword->typenum=-1; 
			myword->word="ERROR";
			return(myword);
		}
	}  
}