C语言:简单而不易懂的声明(二)

    今天编了个程序,把C语言的声明翻译成普通的语言,就能让大家明白C语言声明的含义。虽然这个程序有无数个版本,也被编写过无数次,通常这样的一个程序取名为“cdecl”。

    主要的数据结构是一个堆栈,虽然用的不熟,但是还是勉强能完成基本功能。我们从左往右读取,把各个标记依次压入堆栈,知道读到标识符为止。然后我们继续向右读取一个标记,也就是标识符右边的那个标记。接着,观察标识符左边的那个标记(需要从堆栈中弹出)。

    源程序代码如下:

#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 that;

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

enum 
type_tag classify_string(void){
/*
**推断标识符类型
*/
	char *s = that.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, "unsigned"))
		return TYPE;
	if(!strcmp(s, "short"))
		return TYPE;
	if(!strcmp(s, "int"))
		return TYPE;
	if(!strcmp(s, "long"))
		return TYPE;
	if(!strcmp(s, "double"))
		return TYPE;
	if(!strcmp(s, "float"))
		return TYPE;
	if(!strcmp(s, "struct"))
		return TYPE;
	if(!strcmp(s, "union"))
		return TYPE;
	if(!strcmp(s, "enum"))
		return TYPE;
	return IDENTIFIER;
}
void 
gettoken(void){
/*
**读取下一个标记到“that”
*/
	char *p = that.string;

	/*
	**略过空白字符
	*/
	while(' ' == (*p = getchar()));
	
	if(isalnum(*p)){
		/*
		**读入的标识符以A-Z,0-9开头。
		*/
		while(isalnum(*++p = getchar()));
		ungetc(*p, stdin);
		*p = '\0';
		that.type = classify_string();
		return;
	}

	if(NULL == *p){
		strcpy(that.string, "pointer to");
		that.type = '*';
		return;
	}
	that.string[1] = '\0';
	that.type = *p;
	return;
}

/*
**理解所有分析过程的代码段
*/
void 
read_to_first_identifier(){
	gettoken();
	while(IDENTIFIER != that.type){
		push(that);
		gettoken();
	}
	printf("%s is ", that.string);
	gettoken();
}
void
deal_with_arrays(){
	while( ']' == that.type ){
		printf("array ");
		gettoken();/*数字或‘]’*/
		if(isdigit(that.string[0])){
			printf("0..%d ", atoi(that.string) - 1);
			gettoken();/*读取‘]’*/
		}
		gettoken();/*读取‘]’之后的再一个标记*/
		printf("of ");
	}
}

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

void
deal_with_pointers(){
	while( '*' == stack[top].type){
		printf("%s ", pop.string );
	}
}

void
deal_with_declarator(){
	/*
	**处理标识符之后可能存在的数组或函数
	*/
	switch(that.type){
	case '[' :deal_with_arrays(); break;
	case '(' :deal_with_function_args();
	}

	deal_with_pointers();

	/*
	**处理在读入到标识符之前压入到堆栈中的符号
	*/
	while(top >= 0){
		if( '(' == stack[top].type ){
			pop;
			gettoken();
			deal_with_declarator();
		}
		else{
			printf( "%s ", pop.string );
		}
	}
}

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

你可能感兴趣的:(C语言,翻译,编译,cdecl,C语言声明)