#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define STRCMP(a, R, b) (strcmp(a, b) R 0)
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag{ Identifer, Qualifier, Type };
struct token
{
char type;
char string[MAXTOKENLEN];
};
struct token stack[MAXTOKENS];
struct token this;
int top = -1;
#define pop stack[top--]
#define push(s) stack[++top] = s
void Read_to_first_identifer(void);
enum type_tag Classify_str(void); /*推斷標識符的類型*/
void Gettoken(void);/*讀取下一個標記到this*/
void Deal_with_declarator(void);
void Deal_with_arrays(void);
void Deal_with_function_args(void);
void Deal_with_pointers(void);
void Deal_wirh_declarator(void);
int main(void)
{
char next = 0;
printf("輸入一個C語言聲明,cdecl程序會把聲明轉化成通俗文字:/n");
do{
/*將標記壓入堆棧,直至遇到標識符*/
Read_to_first_identifer();
Deal_with_declarator();
printf("/n是否進行下一個聲明的推斷(y//n)?");
}while('Y' == toupper( next = getchar() ));
return 0;
}
void Read_to_first_identifer(void)
{
Gettoken();
while(Identifer != this.type)
{
push(this);
Gettoken();
}
printf("%s is ", this.string);
Gettoken();
return;
}
void Gettoken(void)
{
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_str();
return;
}
if('*' == *p)
{
strcpy(this.string, "pointer to");
this.type = '*';
return;
}
this.string[1] = '/0';
this.type = *p;
return;
}
enum type_tag Classify_str(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, ==, "int")) return Type;
if(STRCMP(s, ==, "long")) return Type;
if(STRCMP(s, ==, "float")) return Type;
if(STRCMP(s, ==, "double")) return Type;
if(STRCMP(s, ==, "signed")) return Type;
if(STRCMP(s, ==, "unsigned")) return Type;
if(STRCMP(s, ==, "struct")) return Type;
if(STRCMP(s, ==, "union")) return Type;
if(STRCMP(s, ==, "enum")) return Type;
return Identifer;
}
void Deal_with_declarator(void)
{
/*處理標識符之後可能存在的函數或數組*/
switch(this.type)
{
case '[': Deal_with_arrays(); break;
case '(': Deal_with_function_args(); break;
default: break;
}
Deal_with_pointers();
/*處理在讀入標識符之前壓入堆棧的符號*/
while(-1 < top)
{
if('(' == stack[top].type)
{
pop;
Gettoken();
Deal_with_declarator();
}
else
printf("%s ", pop.string);
}
return;
}
void Deal_with_arrays(void)
{
while('[' == this.type)
{
printf("array ");
Gettoken();/*數字或']'*/
if(isdigit(this.string[0]))
{
printf("0..%d ", atoi(this.string)-1);
Gettoken();/*讀取']'*/
}
Gettoken();/*讀取']'之後的再一個標記*/
printf("of ");
}
return;
}
void Deal_with_function_args(void)
{
while(')' != this.type)
Gettoken();
Gettoken();
printf("function returning ");
return;
}
void Deal_with_pointers(void)
{
while('*' == stack[top].type)
printf("%s ", pop.string);
return;
}
farsight@farsight-ubuntu:~/chendan/link$ ./cdecl
輸入一個C語言聲明,cdecl程序會把聲明轉化成通俗文字:
int *p
p is pointer to int
是否進行下一個聲明的推斷(y/n)?y
char *const *(*next)()
next is pointer to function returning pointer to read-only pointer to char