Создание слоя абстракции вокруг этого может сделать вещи более сложными и, таким образом, подверженными ошибкам.Я бы не стал этого делать, если количество команд, которые вы должны обрабатывать, невелико, их необходимо поддерживать, и это одна из основных задач вашего приложения.
С предварительными условиями для сохранения типаБезопасный и сохраняющий разбор отдельно от алгоритмов, вы можете создать нечто похожее на следующий C-подобный псевдокод:
typedef enum
{
INT,
STR
} type_t; // for marking which type that is supported by the command
typedef struct
{
type_t type;
const char* text; // what kind of text that is expected in case of strings
} arg_t;
typedef struct
{
const char* name; // the name of the command
arg_t* args; // list of allowed arguments
size_t args_n; // size of that list
void (*callback)(void); // placeholder for callback functions of different types
} command_t;
Затем вы можете создавать функции обработчика обратного вызова, которые не заботятся о разборе, а только об ихвыделенная задача:
void cmd_branch (const char* str);
void cmd_kill (int n);
Массив команд может выглядеть примерно так:
const command_t commands[] =
{
{ // BRANCH [FAST][SLOW]
.name="BRANCH",
.args=(entry_t[]){ {STR,"FAST"}, {STR,"SLOW"} },
.args_n=2,
.callback= (void(*)(void)) cmd_branch,
},
{ // KILL [7][9]
.name="KILL",
.args=(entry_t[]){ {INT, NULL} },
.args_n=1,
.callback= (void(*)(void)) cmd_kill,
}
};
Функция синтаксического анализа будет выполнять:
- Найти какую командукоторый был получен при поиске в указанном выше списке (bsearch, если большой список).
- Проверьте, какой тип аргументов поддерживает полученная команда
- Соответствующий анализ аргументов
- Вызовите соответствующую функцию с помощьюаргументы соответствующего типа
Так как в этом примере просто использовался какой-то указатель на фиктивную функцию типа (void(*)(void))
, вам придетсят к правильному типу.Может быть сделано, например, C11 _Generic:
call(commands[i], int_val);
, который расширяется до:
#define call(command, arg) _Generic((arg), \
int: (void(*)(int)) command.callback, \
const char*: (void(*)(const char*)) command.callback )(arg)