可调式性编码意味着把系统分成几个部分,先让程序总体结构运行。只有基本的程序能够运行之后你才能为那些复杂的细节完善、性能调优和算法优化进行编码。
   有时候,花点时间把编程问题分解成几个部分往往是解决它的最快办法。

   下面给出几个例子: 

 写散列表 

   自己以前也写过,记得调试时候好痛苦,那么大的散列,找起数据来一点都不方便。

   《C专家编程》中作者叙述他的同事这样写散列表:

   他首先让最简单的情况能够运行,就是散列函数总是返回一个0。散列函数如下:

/* hash_file: Placeholder for more sophisticated future
routine
*/
int hash_filename (char *s){
    return 0;
}
调用这个散列函数的代码如下:
/*
* find_file: Locate a previously created file descriptor or make a new one if necessary.
*/
file find_filename (
char *s)
{
  int hash_value = hash_filename(s);
  file f;
  for (f = file_hash_table[hash_value]; f != NIL;f=f->flink) {
    if (strcmp(f->fname, s) == SAME) {
      return f;
    }
  }
  /* file not found, so make a new one: */
  f
= allocate_file(s);
  f
->flink = file_hash_table[hash_value];
  file_hash_table[hash_value]
= f;
  return f;
}
它的效果就像是一个散列表还未使用。所有的元素都存储在第0个位置后面的链表中。这使得程序很容易调式。当他的主程序能够完美运行后,才开始着手优化措施。

 FSM实现cdecl

  cdecl是分析C语言的声明并把它们翻译成通俗语言。

   有限自动机(FSM)可以用作程序的控制结构。

  它的基本思路是用一张表保存所有可能的状态,并列出进入每个状态时可能执行的所有动作,其中最后一个动作就是计算(通常在当前状态和下一次输入字符的基础上,另外再经过一次表查询)下一个应该进入的状态。你从一个“初始状态”开始。在这一过程中,翻译表可能告诉你进入了一个错误的状态,表示一个预期之外的或错误的输入。你不停地在各种状态间转换,直到到达结束状态。

   在C语言中,有好几种方法可以用来表达FSM,但他们绝大多数都是基于函数指针数组。一个函数指针数组可以像下面这样声明:
 void (*state)[MAX_STATES]();

  不过这个例子,只需要一个函数函数指针就够了。在主循环里,程序将调用指针所指向的函数,并循环往复,直到结束函数被调用(到达FSM的终结状态)或遇到一个错误状态。

  1. 状态机图,详见《C专家编程》第3章

  2. 首先编写代码控制状态的转换。让每个动作程序简单打印一条信息,显示它已被调用。对他进行深入调试。

  3. 增加代码处理并分析输入的声明。

  完整代码:

View Code
/*
* FSM 实现 cdecl
*/

#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;
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") == 0) {
strcpy(s,
"read-only");
return QUALIFIER;
}
if (strcmp(s, "volatile") == 0)
return QUALIFIER;
if (strcmp(s, "void") == 0)
return TYPE;
if (strcmp(s, "char") == 0)
return TYPE;
if (strcmp(s, "signed") == 0)
return TYPE;
if (strcmp(s, "unsigned") == 0)
return TYPE;
if (strcmp(s, "short") == 0)
return TYPE;
if (strcmp(s, "int") == 0)
return TYPE;
if (strcmp(s, "long") == 0)
return TYPE;
if (strcmp(s, "float") == 0)
return TYPE;
if (strcmp(s, "double") == 0)
return TYPE;
if (strcmp(s, "struct") == 0)
return TYPE;
if (strcmp(s, "union") == 0)
return TYPE;
if (strcmp(s, "enum") == 0)
return TYPE;
return IDENTIFIER;
}

void gettoken(void) { /* 读取下一个标记到”this“ */
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_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() {
/* 在不同的状态间切换,直到指针值为NULL */
while (nextstate != NULL)
(
*nextstate)();
return 0;
}

void initialize() {
gettoken();
while (this.type != IDENTIFIER) {
push(
this);
gettoken();
}
printf(
"%s is ", this.string);
gettoken();
nextstate
= get_array;
}

void get_array() {
nextstate
= get_params;
while (this.type == '[') {
printf(
"array ");
gettoken();
/* a number or ']' */
if (isdigit(this.string[0])) {
printf(
"0..%d ", atoi(this.string) - 1);
gettoken();
/* read the ']' */
}
gettoken();
/* read next past the ']' */
printf(
"of ");
nextstate
= get_lparen;
}
}

void get_params() {
nextstate
= get_lparen;
if (this.type == '(') {
while (this.type != ')') {
gettoken();
}
gettoken();
printf(
"function returning ");
}
}

/* 左小括号 */
void get_lparen() {
nextstate
= get_ptr_part;
if (top >= 0) {
if (stack[top].type == '(') {
pop;
gettoken();
/* read past ')' */
nextstate
= get_array;
}
}
}

void get_ptr_part() {
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;
/* process tokens that we stacked while reading to
identifier
*/
while (top >= 0) {
printf(
"%s ", pop.string);
}
printf(
"\n");
}

 

posted on 2011-02-25 09:04  yongmou-  阅读(481)  评论(0编辑  收藏  举报