69,371
社区成员
发帖
与我相关
我的任务
分享
// 用//是本人的注释
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag { IDENTIFIER, QUALIFIER, TYPE };
struct token{
char type;
char string[MAXTOKENLEN];
};
int top = -1;
//int t_num = 0; //本人的修改,可先不管
/*在第一个标识符(identifier)前保存所有的标识(token)*/
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,"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)
{/*读入下一个标记,保存在“this”中*/
char *p = this.string;
/*略过所有的空白字符*/
while ((*p = getchar()) == ' ');
if(isalnum(*p)){
/*在标识符中读入A-Z,1-9字符*/
while (isalnum(*++p = getchar()));
ungetc(*p,stdin);
*p = '\0';
this.type = classify_string();
return;
}
this.string[1] = '\0';
this.type = *p;
return;
}
void initialize(), get_array(), get_params(), get_lparen(), get_ptr_part(), get_type();//各种状态
void (*nextstate)(void) = initialize;
int main()
/*用有限状态机实现的cdecl*/
{
/*在不同的状态间转换,直到指针为NULL*/
while(1){
while(nextstate != NULL) (*nextstate)();
nextstate = initialize;
fflush(stdin);
}
return 0;
}
void initialize()
{
gettoken();
while (this.type != IDENTIFIER){
push(this);
gettoken();
}
printf("%s is ", this.string);
gettoken();
nextstate = get_array;
}
void get_array() //状态1,也就是分析环里的步骤2
{
nextstate = get_params;
while (this.type == '['){
printf("array ");
gettoken();/*一个数字或']'*/
if(isdigit(this.string[0])){
printf("0..%d ",atoi(this.string)-1);
gettoken();/*读取']'*/
}
gettoken();/*在']'之后读取*/
printf("of ");
nextstate = get_lparen;
}
}
//状态2,也就是分析环里的步骤3。bug就在这个函数里,大家可以先看下
//这个程序是不对函数里的参数进行分析的
void get_params()
{
nextstate = get_lparen;
if(this.type == '('){
while(this.type != ')'){
gettoken();
}
gettoken();
printf("function returning ");
}
}
/*
void get_params() //这是我的修改,为了不影响代码的可读性,bug我在后面再分析了
{
nextstate = get_lparen;
if(this.type == '('){
t_num++;
while (t_num != 0){
gettoken();
if(this.type == '(') t_num++;
else if(this.type == ')') t_num--;
}
gettoken();
printf("function returning ");
}
}
*/
void get_lparen() //状态3,也就是分析环里的步骤4
{
nextstate = get_ptr_part;
if(top >= 0){
if(stack[top].type == '('){
pop;
gettoken();/*在'('之后读取*/
nextstate = get_array;
}
}
}
void get_ptr_part() //状态4,也就是分析环里的步骤5
{
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");
}
/*******************************************************************************************
对bug的分析:
while(this.type != ')'){
gettoken();
出现问题的就是上面这一个循环语句,它这里只判断了是不是找到了右括号,但作者可能没想到这个
右括号可以不是匹配函数左括号的右括号,举个例子:int foo(int(*p)[10]),大家看这个就知道了这
个循环语句会在把数组指针括起来的右括号就终止了,但实际上它应该找到的是最右边那个函数的右
括号,就这bug产生了,后面的声明部分可能会被抛弃或错用。由此想到那个环对步骤3“如何阅读”的
描述:“到右括号为止的内容”也应该说成是和前面左括号匹配的右括号才对。
大家可以测试一下这个声明,信号函数:void (*signal(int sig, void(*func)))(int);
或者我随便写的一个: int (*foo(int(*p)(void)))[10];
至于我修改就是加了一个计数的变量,这样就可以准确找到对应的右括号了,当然可能会有更好
的方法,哈哈。
我写这个也不是贬低这本书,我知道我也没这个能力,这个只是我的一个发现,发上来和大家分
享一下而已。还有不得不说的就是《c专家编程》的确是一本好书,c语言进阶必备啊。。。哈哈!
*********************************************************************************************/