《c专家编程》中的一个程序,可以将声明翻译为通俗语言,主要运用栈,挺难的,我自己是写不出的,照着书敲了一遍。
普通方法:
#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 now;
#define pop stack[top--]
#define push(s) stack[++top]=s
enum type_tag classify_string(void)
{
char *s = now.string;
if (!strcmp(s, "const"))
{
strcmp(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, "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;
}
void gettoken(void)//读取下一个标记到now
{
char *p = now.string;
while ((*p = getchar()) == ' ');//跳过空白字符
if (isalnum(*p))
{
while (isalnum(*++p = getchar()));
ungetc(*p,stdin);//将不符合的字符退回输入流
*p = '\0';
now.type = classify_string();
return;
}
if (*p == '*')
{
strcpy(now.string, "pointer to");
now.type = '*';
return;
}
now.string[1] = '\0';//单字符标记
now.type = *p;
return;
}
void read_to_first_identifer()
{
gettoken();
while (now.type != IDENTIFIER)//找到标识符
{
push(now);
gettoken();
}
printf("%s is ", now.string);
gettoken();
return;
}
void deal_with_arrays()
{
while (now.type == '[')
{
printf("array ");
gettoken();//数字或']'
if (isdigit(now.string[0]))
{
printf("0..%d ", atoi(now.string) - 1);
gettoken();//读取']'
}
gettoken();//读取']'之后的再一个标记
printf("of ");
}
}
void deal_with_function_args()
{
while (now.type != ')')
gettoken();
gettoken();
printf("function returing ");
}
void deal_with_pointers()
{
while (stack[top].type == '*')
printf("%s ", pop.string);
}
void deal_with_declacrator()//处理标识符后可能存在的数组/函数
{
switch (now.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_declacrator();
}
else
printf("%s ", pop.string);
}
}
int main()
{
read_to_first_identifer();
deal_with_declacrator();
printf("\n");
return 0;
}
有限自动机:
有限自动机表示是为研究有限内存的计算过程和某些语言类而抽象出的一种计算模型。有限状态自动机拥有有限数量的状态,每个状态可以迁移到零个或多个状态,输入字串决定执行哪个状态的迁移。有限状态自动机可以表示为一个有向图。
#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 now;
#define pop stack[top--]
#define push(s) stack[++top]=s
enum type_tag classify_string(void)
{
char *s = now.string;
if (!strcmp(s, "const"))
{
strcmp(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, "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;
}
void gettoken(void)//读取下一个标记到now
{
char *p = now.string;
while ((*p = getchar()) == ' ');//跳过空白字符
if (isalnum(*p))
{
while (isalnum(*++p = getchar()));
ungetc(*p, stdin);//将不符合的字符退回输入流
*p = '\0';
now.type = classify_string();
return;
}
if (*p == '*')
{
strcpy(now.string, "pointer to");
now.type = '*';
return;
}
now.string[1] = '\0';//单字符标记
now.type = *p;
return;
}
void initialize(), get_array(), get_params(), get_lparen(), get_ptr_part(), get_type();
void(*nextstate)(void) = initialize;//设立一个函数指针表示状态
int main()
{
while (nextstate != NULL)
(*nextstate)();
return 0;
}
void initialize()//取最左边的标识符
{
gettoken();
while (now.type != IDENTIFIER)
{
push(now);
gettoken();
}
printf("%s is ", now.string);
gettoken();
nextstate = get_array;
}
void get_array()//查看标识符的下一个符号,如果是方括号
{
nextstate = get_params;
while (now.type == '[')
{
printf("array ");
gettoken();//一个数字或']'
if (isdigit(now.string[0]))
{
printf("0..%d ", atoi(now.string) - 1);
gettoken();//读取']'
}
gettoken();
printf("of ");
nextstate = get_lparen;
}
}
void get_params()//如果是一个左括号表示
{
nextstate = get_lparen;
if (now.type == '(')
{
while (now.type != ')')//到右括号为止的内容表示返回...的函数
gettoken();
gettoken();
printf("function returning ");
}
}
void get_lparen()//如果左边的符号是一个左括号
{
nextstate = get_ptr_part;
if (top >= 0)
{
if (stack[top].type == '(')
{
pop;
gettoken();//在')'后读取
nextstate = get_array;
}
}
}
void get_ptr_part()//如果左边的符号是下述之一:const,volatile,*
{
nextstate = get_type;
if (stack[top].type == '*')
{
printf("pointer to ");
pop;
nextstate = get_lparen;
}
else if (stack[top].type == QUALIFIER)
{
printf("%s", pop.string);
nextstate = get_lparen;
}
}
void get_type()//剩下的符号形成声明的基本类型
{
nextstate = NULL;
while (top >= 0)
{
printf("%s ", pop.string);
}
printf("\n");
}