在C程序设计语言5-18题中,在dcl程序中,我们看到dcl()和dirdcl()函数相互调用,形成递归。原书成为recursive-descent,有相关资料翻译成递归下降。其实翻译成交叉递归更为合理。但这种实现方法比较难于理解的,gdb中函数跳来跳去,想了解程序实际流程很困难。这时,有个小技巧可以帮助我们理解代码时序。 void dcl(void) { static int dclcount = 0; printf(“this is the %d 次调用dcl start\n”,++dclcount); printf(“token is %s\n”,token); printf(“out is %s\n”,out); int ns; for (ns = 0;gettoken() == ‘*’? ns++; dirdcl(); while (ns–) strcat(out," pointer to"); printf(“this is the %d 次调用dcl terminate\n”,dclcount–); printf(“token is %s\n”,token); printf(“out is %s\n”,out); }
void dirdcl(void) { static int dirdclcount = 0; printf(“this is the %d 次调用dirdcl start\n”,++dirdclcount); printf(“token is %s\n”,token); printf(“out is %s\n”,out); int type; if (tokentype == ‘(’) { dcl(); if (tokentype != ‘)’) printf(“error:missing )\n”); } else if (tokentype == NAME ) strcpy(name,token); /数据类型前面已经取到了,这里取的是数据名称/ else printf(“error:expected name or (dcl)\n”); while ((type = gettoken()) == PARENS || type== BRACKETS) if (type == PARENS) strcat(out," function returning “); else { strcat(out, " array”); strcat(out, token); strcat(out," of"); } printf(“this is the %d 次调用dirdcl terminate\n”,dirdclcount–); printf(“token is %s\n”,token); printf(“out is %s\n”,out);
}
这里有3个关键点: 1.在函数内声明static型的计数变量,这样,在反复递归调用该函数时,该变量不会被重新初始化。这样我们就可以清楚了解该函数的调用顺序。 2.在函数开始和结尾分别打印该变量。注意两个++,–的位置。只有这样,才能确保这对打印的是同一个函数的计数。 开始:printf(“this is the %d 次调用dirdcl start\n”,++dirdclcount); 结尾:printf(“this is the %d 次调用dirdcl terminate\n”,dirdclcount–); 3.在打印计数变量后可以跟着打印你想了解的变量信息。结果如下:
int (*ptr)() this is the 1 次调用dcl start token is int out is this is the 1 次调用dirdcl start token is int out is this is the 2 次调用dcl start token is int out is this is the 2 次调用dirdcl start token is ptr out is this is the 2 次调用dirdcl terminate token is ptr out is this is the 2 次调用dcl terminate token is ptr out is pointer to this is the 1 次调用dirdcl terminate token is () out is pointer to function returning this is the 1 次调用dcl terminate token is () out is pointer to function returning ptr: pointer to function returning int
