- 添加了命令行参数约束相关数据结构定义 - 新增错误上下文字段用于更好的错误提示 - 实现了参数验证功能,包括必需参数检查和值选择验证 - 改进错误处理流程,支持添加帮助信息和使用说明 - 优化调试输出格式,增加更多错误场景的处理 fix(parser): 修复语义分析器资源释放问题 - 在scc_sema_drop函数中添加空指针检查,避免空指针释放导致崩溃 refactor(dump): 重构AST节点转储实现 - 将树形转储上下文重构为更简洁的数据结构 - 修改转储回调函数签名以支持更好的缓冲区管理 - 优化内存拷贝操作,提高转储性能 style(amd64): 移除未使用的变量声明 - 删除scc_mcode_amd64_mov_r64_m64_sib函数中未使用的disp8变量
222 lines
7.2 KiB
C
222 lines
7.2 KiB
C
#include <optparse.h>
|
|
|
|
void scc_optparse_init(scc_optparse_t *parser, int argc, const char **argv) {
|
|
parser->argc = argc;
|
|
parser->argv = argv;
|
|
parser->opts = 0;
|
|
scc_optparse_reset(parser);
|
|
}
|
|
|
|
void scc_optparse_drop(scc_optparse_t *parser) { (void)parser; }
|
|
|
|
void scc_optparse_set(scc_optparse_t *parser, const scc_optparse_opt_t *opts) {
|
|
parser->opts = opts;
|
|
scc_optparse_reset(parser);
|
|
}
|
|
|
|
void scc_optparse_reset(scc_optparse_t *parser) {
|
|
parser->handle_positional = 0;
|
|
parser->current.opt = 0;
|
|
parser->current.count = 0;
|
|
parser->current.arg_pos = 1;
|
|
parser->current.opt_pos = 0;
|
|
}
|
|
|
|
static inline const char *str_chr(const char *s, char c) {
|
|
while (*s && *s != c)
|
|
s++;
|
|
return *s ? s : 0;
|
|
}
|
|
|
|
const scc_optparse_opt_t *
|
|
scc_optparse_get_long_name(const scc_optparse_opt_t *opts, const char *name,
|
|
const char end) {
|
|
if (*name == '\0')
|
|
return 0;
|
|
for (const scc_optparse_opt_t *opt = opts; opt->prefix; ++opt) {
|
|
if (!opt->long_name) {
|
|
continue;
|
|
}
|
|
int i;
|
|
for (i = 0; opt->long_name[i]; ++i) {
|
|
if (name[i] != opt->long_name[i]) {
|
|
break;
|
|
}
|
|
}
|
|
if (opt->long_name[i] == '\0' && (name[i] == '\0' || name[i] == end))
|
|
return opt;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const scc_optparse_opt_t *
|
|
scc_optparse_get_short_name(const scc_optparse_opt_t *opts,
|
|
const char short_name) {
|
|
for (const scc_optparse_opt_t *opt = opts; opt->prefix; ++opt) {
|
|
if (opt->short_name == short_name) {
|
|
return opt;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void scc_optparse_parse_long_name(const scc_optparse_opt_t *opts,
|
|
scc_optparse_result_t *res,
|
|
const char *arg) {
|
|
// caller MUST use `--` start arg
|
|
const scc_optparse_opt_t *ret = 0;
|
|
const char *chr = str_chr(arg, '=');
|
|
if (chr) {
|
|
// --file=a.txt
|
|
ret = scc_optparse_get_long_name(opts, arg + 2, '=');
|
|
if (ret == 0) {
|
|
res->error = SCC_OPT_ERROR_NOT_FOUND_LONG_ARG;
|
|
} else {
|
|
res->opt = ret;
|
|
if (chr[1] == '\0') {
|
|
// TODO maybe can empty like -file=
|
|
res->error = SCC_OPT_ERROR_NOT_ENOUGH_ARGS;
|
|
}
|
|
res->value = chr + 1;
|
|
}
|
|
} else {
|
|
// --file a.txt
|
|
ret = scc_optparse_get_long_name(opts, arg + 2, '\0');
|
|
if (ret == 0) {
|
|
res->error = SCC_OPT_ERROR_NOT_FOUND_LONG_ARG;
|
|
} else {
|
|
res->opt = ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void scc_optparse_parse_short_name(const scc_optparse_opt_t *opts,
|
|
scc_optparse_result_t *res,
|
|
const char *arg,
|
|
int arg_start) {
|
|
// const char *chr =
|
|
// str_chr(arg + arg_start, '='); // TODO maybe short can have -I=/usr
|
|
const scc_optparse_opt_t *ret =
|
|
scc_optparse_get_short_name(opts, arg[arg_start]);
|
|
if (ret == 0) {
|
|
res->error = SCC_OPT_ERROR_NOT_FOUND_SHORT_ARG;
|
|
} else {
|
|
res->opt = ret;
|
|
}
|
|
}
|
|
|
|
static inline void scc_optparse_parse_position_arg(scc_optparse_t *parser,
|
|
const char *arg,
|
|
scc_optparse_result_t *res) {
|
|
parser->current.arg_pos++;
|
|
res->value = arg;
|
|
}
|
|
|
|
static inline int scc_optparse_check(scc_optparse_t *parser,
|
|
scc_optparse_result_t *res) {
|
|
if (!res->opt || res->error)
|
|
return 0;
|
|
if (res->value)
|
|
parser->current.count += 1;
|
|
if (parser->current.count < res->opt->max_args && res->opt->max_args > 0)
|
|
parser->current.opt = res->opt;
|
|
if (parser->current.count < res->opt->min_args && !res->value)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int scc_optparse_parse(scc_optparse_t *parser, scc_optparse_result_t *res) {
|
|
const scc_optparse_opt_t *opts = parser->opts;
|
|
const char *arg = 0;
|
|
res->opt = 0;
|
|
res->value = 0;
|
|
res->error = SCC_OPT_ERROR_NONE;
|
|
|
|
if (parser->current.opt_pos != 0) {
|
|
arg = parser->argv[parser->current.arg_pos];
|
|
goto CONTINUE_SHORT_OPTION;
|
|
}
|
|
|
|
while (parser->current.arg_pos < parser->argc) {
|
|
arg = parser->argv[parser->current.arg_pos];
|
|
|
|
if (arg[0] == '\0' || parser->handle_positional) {
|
|
scc_optparse_parse_position_arg(parser, arg, res);
|
|
goto RETURN;
|
|
}
|
|
|
|
for (const scc_optparse_opt_t *opt = opts; opt && opt->prefix; ++opt) {
|
|
if (arg[0] != opt->prefix) {
|
|
continue;
|
|
}
|
|
|
|
parser->current.opt = 0;
|
|
parser->current.count = 0;
|
|
if (arg[1] == opt->prefix) {
|
|
// long option like --
|
|
if (arg[2] == '\0') {
|
|
// the `--`
|
|
res->value = arg;
|
|
parser->handle_positional = 1;
|
|
parser->current.arg_pos++;
|
|
goto RETURN;
|
|
}
|
|
scc_optparse_parse_long_name(opts, res, arg);
|
|
parser->current.arg_pos += 1;
|
|
if (scc_optparse_check(parser, res)) {
|
|
goto NEXT;
|
|
}
|
|
goto RETURN;
|
|
} else {
|
|
// short option like -
|
|
if (arg[1] == '\0') {
|
|
// the `-`
|
|
res->value = arg;
|
|
parser->current.arg_pos++;
|
|
goto RETURN;
|
|
}
|
|
parser->current.opt_pos = 1;
|
|
CONTINUE_SHORT_OPTION:
|
|
scc_optparse_parse_short_name(opts, res, arg,
|
|
parser->current.opt_pos++);
|
|
int have_next = arg[parser->current.opt_pos];
|
|
|
|
parser->current.opt_pos =
|
|
have_next ? parser->current.opt_pos : 0;
|
|
parser->current.arg_pos += have_next ? 0 : 1;
|
|
if (scc_optparse_check(parser, res)) {
|
|
if (have_next) {
|
|
res->value = arg + parser->current.opt_pos;
|
|
parser->current.opt_pos = 0;
|
|
parser->current.arg_pos += 1;
|
|
goto RETURN;
|
|
}
|
|
goto NEXT;
|
|
}
|
|
goto RETURN;
|
|
}
|
|
}
|
|
// position arg
|
|
if (parser->current.opt &&
|
|
parser->current.count < parser->current.opt->max_args) {
|
|
res->opt = parser->current.opt;
|
|
res->value = arg;
|
|
parser->current.count++;
|
|
parser->current.arg_pos++;
|
|
goto RETURN;
|
|
} else {
|
|
scc_optparse_parse_position_arg(parser, arg, res);
|
|
goto RETURN;
|
|
}
|
|
NEXT:
|
|
continue;
|
|
}
|
|
RETURN:
|
|
if (res->opt && res->opt->max_args > 0 &&
|
|
parser->current.count > res->opt->max_args) {
|
|
res->error = SCC_OPT_ERROR_TOO_MANY_ARGS;
|
|
}
|
|
res->raw_arg = arg;
|
|
return res->opt != 0 || res->value != 0 || res->error != SCC_OPT_ERROR_NONE;
|
|
}
|