cdecl代码解释

/*
 * =====================================================================================
 *
 *       Filename:  cdecl.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2012年02月28日 21时54分11秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  MaZheng (blog.csdn.net/mazheng1989), [email protected]
 *        Company:  Dalian University Of Technology
 *
 * =====================================================================================
 */

 //		int *((*p)(int))(int)
 //		int(*(*func)[5])(int *p)
 //		int (*(*func)[5][6])[7][8]
 //		int (*(*(*func)(int *))[5])(int *)
 //		int (*(*func[7][8][9])(int *))[5]
 //		int (*(*f)())[10]
 //		int *(*(*fp)(int))[10]
 //		int *(*(*arr[5])())()
 //		int (*(*a)[])()

#include	<stdio.h>
#include	<string.h>
#include	<ctype.h>
#include	<stdlib.h>
#define	 MAXTOKENS 100			/*  */
#define	MAXTOKENLEN 64			/*  */

//分别是标示符,类型限定符,类型说明符
enum type_tag{ IDENTIFIER,QUALIFIER,TYPE};

struct token{
	char type;
	char string[MAXTOKENLEN];
};

int top =-1;
struct token stack[MAXTOKENS];
struct token this;

#define	pop stack[top--]			
#define	push(s) stack[++top]=s		

enum type_tag classify_string(void )/*推断标识符的类型*/
{
	char *s=this.string;
	if(!strcmp(s,"const"))
	{
		strcpy(s,"read-only");
		return QUALIFIER;
	}
	if(!strcmp(s,"volatile")) return QUALIFIER;
	if(!strcmp(s,"void")) return TYPE;
	if(!strcmp(s,"char")) return TYPE;
	if(!strcmp(s,"signed")) return TYPE;
	if(!strcmp(s,"unsigned")) return TYPE;
	if(!strcmp(s,"short")) return TYPE;
	if(!strcmp(s,"int")) return TYPE;
	if(!strcmp(s,"long")) return TYPE;
	if(!strcmp(s,"float")) return TYPE;
	if(!strcmp(s,"double")) return TYPE;
	if(!strcmp(s,"struct")) return TYPE;
	if(!strcmp(s,"union")) return TYPE;
	if(!strcmp(s,"enum")) return TYPE;
	return IDENTIFIER;
}

/*
读取标记,包括括号,方括号,指针标示符,变量名。如果是数字或者字符则保存到全局变量this(string设置为获得的字符或者数字,类型保存到type),并获得类型。
如果是指针显示符则把指针显示符保存为type,string设置为"pointer to"
否则则是把string[0]设置为这个未知的符号(通常是括号或者方括号),然后string[1]设置为'\0',type也设置为这个未知的符号
*/

void gettoken(void)/*读取下一个标记到 this*/
{
	char *p=this.string;
	/*略过空白字符*/
	while((*p=getchar())==' ')
		;

	if(isalnum(*p))
	{
		/*读入的标识符以A—Z,0-9开头*/
		while(isalnum(*++p=getchar()))
			;
		ungetc(*p,stdin);
		*p='\0';
		this.type=classify_string();
		return;
	}
	if(*p=='*')
	{
		strcpy(this.string,"pointer to");
		this.type='*';
		return ;
	}
	this.string[1]='\0';
	this.type=*p;
	return ;
}

/*
首先获取第一个标示符并设置type,如果的返回值type不是IDENTIFIER(也就是唯一的变量名),则保存这个符号的信息并继续读取,直到读取到变量名。
读取到变量名之后输出这个变量名并再次读取变量名后面的那个符号,预防是左方括号或者左括号(即处理变量名是函数或者数组)
*/
void read_to_first_identifier()
{
	gettoken();
	while(this.type!=IDENTIFIER)
	{
		push(this);
		gettoken();
	}
	printf("%s is ",this.string);
	gettoken();
}

void deal_with_arrays()
{
	//之所以使用while,是为了多维数组的情况,下面在读取了维数大小和后面紧接的']'符号之后还会继续在while循环中读取']'后面紧接的符号,如果是多维数组,那么这个
	//while循环会继续,直到这个多维数组解析完毕,那么gettoken函数所读取到的符号就会被丢弃(其实是没有使用,视为丢弃,通常是一个右括号)
	while(this.type=='[')
	{
		printf("array ");
		gettoken();/*数字或']'*/
		if(isdigit(this.string[0]))
		{
			int temp;
			sscanf(this.string,"%d",&temp);
			printf("0..%d ",temp-1);
			gettoken();/*读取']'*/
		}
		gettoken();/*读取']'之后的再一个标记*/
		printf("of ");
	}
}

void deal_with_function_args()
{
	while(this.type!=')')
	{
		gettoken();
	}
	gettoken();
	printf("function returning ");
}

void deal_with_pointers()
{
	//之所以是while语句,因为可能是指针的指针的……
	while(stack[top].type=='*')
	{
		printf("%s ",pop.string);
	}
}

void deal_with_declarator()
{
	//第一次进入这个函数的时候这个switch语句作用是接着read_to_first_identifier最后一个gettoken函数,处理如果是函数或者数组的情况
	//后面这个switch语句的作用是处理变量名之后所读取到的符号
	switch(this.type)
	{
		//读取数组维数(一维或者多维),然后读取最后一个']'符号后面的符号,一般是')',这个')'不会被使用,相当于被丢弃
		case '[':
			deal_with_arrays();
				 break;
		//对于函数那么会一直读取字符,直到遇到了右括号为止,其中的参数都会被忽略,并继续调用gettoken函数读取下一个符号(也就是')'后面的那个符号,')'同样被丢弃了),
		//然后输出"function returning "
		case '(':
				 deal_with_function_args();
				 break;
	}
	
	//处理栈里面的下一个字符是指针显示符的情况,如果是指针显示符‘*’,那么就输出相应的string语句
	deal_with_pointers();
	
	/*处理从读入到标识符之前所压入到栈的符号*/
	while(top>=0)
	{
		//因为stack中存储的只可能是类型说明符,左括号,指针显示符
		//变量名的前面不可能出现数组,指针显示符再前面的deal_with_pointers函数中已经处理好了
		//而类型说明符只会是最后一个处理的元素,所以这里只处理函数的情况
		if(stack[top].type=='(')
		{
			pop;
			gettoken();/*读取下一个符号*/
			deal_with_declarator();
		}
		else
		{
			//进入这个else分支,一般是处理栈里面最后一个符号,也就是第一个读取到栈里面的符号,一般是类型说明符
			printf("%s ",pop.string);
		}
	}
}

int main()
{
	/*将标记呀入堆栈中,直到遇见标识符*/
	read_to_first_identifier();
	deal_with_declarator();
	printf("\n");
	return 0;
}


你可能感兴趣的:(cdecl)