1.设计思路
前段时间研究了一下红黑树,趁着今天有时间,就使用红黑树实现了一下命令解析器。
命令解析器的原则是根据输入的命令,调用相关命令的功能。命令的名字作为红黑树的键值,而相关命令的功能实现则设计为键值。因此红黑树的实现作为了命令解析器的数据结构组织手段。
增加和减少命令时,尽量不需要跨文件的修改(如果只有几个命令,可能可以接受,但是后期维护也是相当大的工作量)。
命令的相关功能调用,为了达到相关文件以及模块的去耦合作用,使用函数指针进行实现。
底层的框架实现命令的注册以及注销,相关命令的功能调用等。而使用这些调用接口的则将会在具体的功能文件中进行,这样达到了增删等动作不需要改动底层的框架,而只需要在自己的功能文件中进行即可。
2.具体实现
红黑树的实现可参照之前的实现。
2.1底层框架(cmd)
底层框架只需要给功能函数提供注册,注销,命令功能函数的调用,以及添加到红黑树时的比较规则函数即可。
2.1.1 注册函数
注册函数就是调用了红黑树的put函数,将命令存放到红黑树中。
void register_cmd(struct entry ** cmds_node, char *name, handler cmd_operate)
{
put(cmds_node, (void *)name, (void *) cmd_operate);
}2.1.2注销函数
注销函数就是调用了红黑树的delete函数,将命令从红黑树中删除。
void unregister_cmd(struct entry ** cmds_node, char *name)
{
struct entry * p = NULL;
p = get(*cmds_node, (void *)name);
if(NULL != p)
delete_entry(cmds_node, p);
else
printf("unregister cmd (the cmd is not in the cmds node!\n");
}2.1.3 调用命令的功能函数
通过键获取节点的值,直接调用该功能函数即可。
void match_cmd(struct entry * cmds_node, char * name)
{
struct entry * x;
x = get(cmds_node, (void *)name);
if(NULL != x) {
handler cmd_operate = (handler)x->data;
cmd_operate((void *)name);
} else {
printf("match cmd(the cmd is not in the cmds node!\n");
}
}
2.1.4 比较函数
因为输入的命令都是字符串,因此红黑树中的比较函数需要实现为字符串的比较。
int string_cmp(void * str1, void * str2)
{
assert(NULL != str1 && NULL != str2);
return strncmp((char*)str1, (char*)str2, strlen(str1) >= strlen(str2) ? strlen(str1):strlen(str2));
}3.应用实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "cmd.h"
static void cmd_1(void * data)
{
printf("this is the the cmd %s!\n", (char *)data);
}
static void cmd_2(void * data)
{
printf("this is the the cmd %s!\n", (char *)data);
}
static void cmd_3(void * data)
{
printf("this is the the cmd %s!\n", (char *)data);
}
static void cmd_4(void * data)
{
printf("this is the the cmd %s!\n", (char *)data);
}
static void cmd_5(void * data)
{
printf("this is the the cmd %s!\n", (char *)data);
}
int main(void)
{
struct entry * tree = NULL;//定义指针的时候需要赋初值,不然可能造成错误
char str_cmd[30] = {0};
register_cmd(&tree, (void *)"cmd_1", (handler)cmd_1);
tree->cmp = string_cmp;
register_cmd(&tree, (void *)"cmd_2", (handler)cmd_2);
register_cmd(&tree, (void *)"cmd_3", (handler)cmd_3);
register_cmd(&tree, (void *)"cmd_4", (handler)cmd_4);
register_cmd(&tree, (void *)"cmd_5", (handler)cmd_5);
while(1) {
scanf("%s", str_cmd);
if(!strncmp(str_cmd, "done", strlen("done"))){
printf("this is done\n");
break;
}
match_cmd(tree, str_cmd);
}
return 0;
} 在实际的应用中,功能的文件肯定不止一个,因此最开始的红黑树肯定需要作为所以文件的共有变量。
本文介绍了如何使用红黑树设计命令解析器,通过将命令名作为红黑树键值,实现命令的注册、注销及功能调用。通过函数指针实现模块去耦合,降低后期维护成本。详细讲解了底层框架的注册、注销、功能调用函数以及比较函数的实现,并给出了应用实例。

被折叠的 条评论
为什么被折叠?



