c语言声明处理程序——cdecl

程序来源于《c专家编程》上作者提供的源码,在原有的基础上增加了一些注释以方便理解。

总体思路:

  1. 读至第一个标识符,将读取过程遇到的所有标记(包括"const"、"int"等关键字,指针符"*"和单字符标记"["、"("等,不包括空格、标识符)进行分类和说明,然后压入堆栈中
  2. 按照书上的声明处理顺序即操作(如下图)对标识符的左右标记进行处理,向左通过访问堆栈,向右通过输入流

 源码及注释如下:

#include<stdio.h> 
#include<string.h>
#define MAXTOKENLEN 64 
#define MAXTOKENS 100
#define pop stack[top--]
#define push(s) stack[++top] = s
#define STRCMP(a, R, b) (strcmp(a, b) R 0)
 
/*标识符,限定符,类型*/ 
enum type_tag { IDENTIFIER, QUALIFIER, TYPE };

//标识符的数据结构
struct token {
	char type;	//标识符的类型 
	char string[MAXTOKENLEN];  //string用来保存标记输出的信息 
};

struct token stack[MAXTOKENS];	//保存第一个标识之前的所有标记
struct token this; 	//保存刚读入的标记
int top = -1;	//栈顶指针

/*实用程序---------------*/
/* 判断当前标记的类型 */
enum type_tag classify_string()
{
	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, ==, "int")) return TYPE;
	if(STRCMP(s, ==, "short")) return TYPE;
	if(STRCMP(s, ==, "long")) return TYPE;
	if(STRCMP(s, ==, "signed")) return TYPE;
	if(STRCMP(s, ==, "unsigned")) 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;
}

/*取下一个标记*/
void gettoken()
{
	char *p = this.string;
	
	/*略过空白字符*/
	while((*p = getchar()) == ' ');
	
	/*读入的标识符以字母,0-9开头,下划线开头*/
	if(isalnum(*p) || (*p == '_')) {
		while(isalnum(*++p = getchar()) || (*p == '_'));
		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 = this.string[0];
}

/*读至第一个标识符*/
void read_to_first_identifier()
{
	gettoken();
	while(this.type != IDENTIFIER) {
		push(this);
		gettoken();
	}
	printf("%s is ", this.string);
	gettoken();
}

/*解析程序--------------*/
/*处理函数参数,直到读取')'*/
void deal_with_function_args()
{
	while(this.type != ')') {
		gettoken();
	}
	printf("function returning ");
	gettoken();		//读取')'的下一个标记  
}

/*处理(多重)数组,直到读取']'*/
void deal_with_arrays()
{
	while(this.type == '['){
		printf("array ");
		gettoken();		//数字或']'
		if(isdigit(this.string[0])){
			printf("0..%d ", atoi(this.string)-1);	//将字符串转换为数值
			gettoken();
		}
		gettoken();		//读取']'的下一个标记 
		printf("of ");
	}
}

/*处理(多重)指针,非必要,参考 134~135行*/
void deal_with_pointers()
{
	while(stack[top].type == '*'){
		printf("%s ", pop.string);
	}
}

/*处理声明器,左右交替*/
void deal_with_declarator()
{
	/*向右读取
	  处理标识符之后可能存在的数组/函数*/ 
	switch(this.type){
		case '[': deal_with_arrays(); break;
		case '(': deal_with_function_args();
	}
	
	/*向左读取
	  处理读入到标识符之前压入到堆栈中的指针
	  该语句并不是必要的,因为包含在下面的else中,没有该函数,else也能正确处理指针并输出信息
	  maybe是为了严格按照思路来编程,遵循正确的思维模式*/ 
	deal_with_pointers();
	
	/*处理读入到标识符之前压入到堆栈中的符号*/ 
	while(top >= 0){
		if(stack[top].type == '('){
			pop;			
			gettoken();		//因为处理数组和函数时会读取右括号的下一个标记,可能是')' 
							//这里相当于跳过了')' ,读取')'之后的符号,
			deal_with_declarator();		
		}else {
			printf("%s ", pop.string);
		}
	}
}

/*主程序----------*/
int main()
{ 
	read_to_first_identifier();
	deal_with_declarator();
	printf("\b.\n");
	return 0;
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值