diff --git a/libs/argparse/include/argparse.h b/libs/argparse/include/argparse.h index 2cb976e..e11f293 100644 --- a/libs/argparse/include/argparse.h +++ b/libs/argparse/include/argparse.h @@ -11,9 +11,13 @@ // 4. 支持配置文件解析 // 5. 支持国际化(i18n) +/// @brief 命令行参数约束 typedef struct scc_argparse_spec scc_argparse_spec_t; +/// @brief 命令行参数 eg. someting typedef struct scc_argparse_arg scc_argparse_arg_t; +/// @brief 命令行参数选项 eg. -a --long typedef struct scc_argparse_opt scc_argparse_opt_t; +/// @brief 命令集合 typedef struct scc_argparse_cmd scc_argparse_cmd_t; typedef SCC_VEC(scc_argparse_arg_t) scc_argparse_arg_vec_t; @@ -44,6 +48,7 @@ typedef enum scc_argparse_err { } scc_argparse_err_t; typedef SCC_VEC(const char *) scc_argparse_list_t; + // 约束规范结构体 struct scc_argparse_spec { scc_argparse_val_type_t value_type; // 值类型 @@ -111,6 +116,8 @@ typedef struct { cbool need_help; cbool need_version; cbool need_debug; + cbool need_error_add_help; + cbool need_error_add_usage; } scc_argparse_t; typedef SCC_VEC(scc_optparse_opt_t) scc_optparse_opt_vec_t; @@ -119,10 +126,10 @@ typedef struct { scc_argparse_cmd_t *current_cmd; // 当前正在解析的命令 scc_optparse_t optparse; // 底层解析器 scc_optparse_opt_vec_t opts; // 当前命令的选项列表 - scc_optparse_result_t result; - int positional_index; // 当前处理的位置参数索引 - cbool parsing_done; // 是否已完成解析 - scc_argparse_lang_t lang; + scc_optparse_result_t result; // 底层解析结果 + const void *err_ctx; // 错误上下文(期待的参数或者当前解析的参数) + int positional_index; // 当前处理的位置参数索引 + cbool parsing_done; // 是否已完成解析 } scc_argparse_context_t; void scc_argparse_init(scc_argparse_t *parser, const char *program_name, @@ -144,7 +151,7 @@ void scc_argparse_cmd_add_subcmd(scc_argparse_cmd_t *cmd, void scc_argparse_print_help(scc_argparse_t *parser, scc_argparse_cmd_t *cmd); void scc_argparse_print_error(scc_argparse_context_t *ctx, - scc_argparse_err_t err); + scc_argparse_t *parser, scc_argparse_err_t err); static inline void scc_argparse_spec_init(scc_argparse_spec_t *spec) { spec->value_type = SCC_ARGPARSE_VAL_TYPE_STRING; diff --git a/libs/argparse/include/optparse.h b/libs/argparse/include/optparse.h index 1327776..f3ce08d 100644 --- a/libs/argparse/include/optparse.h +++ b/libs/argparse/include/optparse.h @@ -1,6 +1,10 @@ #ifndef __SCC_OPTPARSER_H__ #define __SCC_OPTPARSER_H__ +#ifndef nullptr +#define nullptr ((void *)0) +#endif + typedef struct scc_optparse_opt { char prefix; char short_name; diff --git a/libs/argparse/src/argparse.c b/libs/argparse/src/argparse.c index 7200060..f4b2258 100644 --- a/libs/argparse/src/argparse.c +++ b/libs/argparse/src/argparse.c @@ -11,6 +11,8 @@ void scc_argparse_init(scc_argparse_t *parser, const char *program_name, parser->need_help = true; parser->need_version = true; parser->need_debug = false; + parser->need_error_add_help = false; + parser->need_error_add_usage = true; scc_argparse_cmd_init(&parser->root_cmd, parser->prog_name, parser->description); } @@ -37,9 +39,9 @@ static inline scc_argparse_cmd_t *is_subcommand(scc_argparse_cmd_t *cmd, return nullptr; } -static inline void parse_cmd(scc_optparse_t *optparse, - scc_optparse_opt_vec_t *opts, - scc_argparse_cmd_t *cmd) { +static inline void prepare_cmd(scc_optparse_t *optparse, + scc_optparse_opt_vec_t *opts, + scc_argparse_cmd_t *cmd) { scc_vec_free(*opts); scc_vec_init(*opts); scc_vec_foreach(cmd->opts, i) { @@ -85,6 +87,7 @@ static inline void parse_cmd(scc_optparse_t *optparse, scc_vec_push(*opts, (scc_optparse_opt_t)SCC_OPTPARSE_OPT_END()); scc_optparse_set(optparse, opts->data); } + static void push_help(scc_argparse_cmd_t *cmd) { if (cmd == nullptr) { return; @@ -108,15 +111,12 @@ static void init_context(scc_argparse_context_t *ctx, scc_argparse_t *parser, } scc_optparse_init(&ctx->optparse, argc, argv); scc_vec_init(ctx->opts); - parse_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd); + prepare_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd); ctx->positional_index = 0; ctx->parsing_done = false; - ctx->lang = parser->lang; } -static int handle_parse_error(scc_argparse_t *parser, - scc_argparse_context_t *ctx) { - (void)parser; // TODO +static int transite_error(scc_argparse_context_t *ctx) { scc_argparse_err_t error = SCC_ARGPARSE_ERR_NONE; switch (ctx->result.error) { case SCC_OPT_ERROR_NOT_FOUND_SHORT_ARG: @@ -133,27 +133,68 @@ static int handle_parse_error(scc_argparse_t *parser, error = SCC_ARGPARSE_ERR_UNKNOWN_ERR; break; } - scc_argparse_print_error(ctx, error); return error; } +static int check_choices(const scc_argparse_spec_t *spec, const char *value) { + if (!spec->choices.values || spec->choices.count == 0) { + return SCC_ARGPARSE_ERR_NONE; + } + + for (int i = 0; i < spec->choices.count; i += 1) { + if (scc_strcmp(value, spec->choices.values[i]) == 0) { + return SCC_ARGPARSE_ERR_NONE; + } + } + return SCC_ARGPARSE_ERR_INVALID_VALUE; +} + static int validate_and_cleanup(scc_argparse_context_t *ctx, scc_argparse_t *parser, int errcode) { - (void)parser; // TODO - if (errcode == SCC_ARGPARSE_ERR_NONE) { - // 检查必需参数是否都已提供 - scc_vec_foreach(ctx->current_cmd->args, i) { - scc_argparse_arg_t *arg = &scc_vec_at(ctx->current_cmd->args, i); - if (arg->spec.flag_required && + if (errcode != SCC_ARGPARSE_ERR_NONE) { + goto END; + } + // 检查必需的位置参数 + scc_vec_foreach(ctx->current_cmd->args, i) { + scc_argparse_arg_t *arg = &scc_vec_at(ctx->current_cmd->args, i); + if (arg->spec.flag_required) { + // 检查是否已存储(非空) + if (arg->spec.store.str_store == nullptr || *arg->spec.store.str_store == nullptr) { errcode = SCC_ARGPARSE_ERR_MISSING_ARG; - scc_argparse_print_error(ctx, errcode); - break; + ctx->err_ctx = arg->name; + goto END; + } + } + } + scc_vec_foreach(ctx->current_cmd->opts, i) { + scc_argparse_opt_t *opt = &scc_vec_at(ctx->current_cmd->opts, i); + if (opt->spec.flag_required) { + int provided = 0; + if (opt->spec.flag_store_as_count) { + provided = (opt->spec.store.int_store && + *opt->spec.store.int_store > 0); + } else if (opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_BOOL) { + provided = + (opt->spec.store.bool_store && *opt->spec.store.bool_store); + } else if (opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_LIST) { + provided = (opt->spec.store.vec_store && + scc_vec_size(*opt->spec.store.vec_store) > 0); + } else { + provided = (opt->spec.store.str_store && + *opt->spec.store.str_store != nullptr); + } + if (!provided) { + errcode = SCC_ARGPARSE_ERR_MISSING_ARG; + goto END; } } } - // 清理资源 +END: + if (errcode != SCC_ARGPARSE_ERR_NONE) { + scc_argparse_print_error(ctx, parser, errcode); + } scc_vec_free(ctx->opts); scc_optparse_drop(&ctx->optparse); return errcode; @@ -191,26 +232,6 @@ static int handle_option(scc_argparse_context_t *ctx, scc_argparse_t *parser) { *opt->spec.store.str_store = ctx->result.value; } - // // opt value == nullptr or value != nullptr - // scc_argparse_opt_t *org_opt = - // (scc_argparse_opt_t *)opt_res.opt->user_data; - // if (parser->need_help) { - // if (scc_strcmp(org_opt->long_name, "help") == 0) { - // scc_argparse_print_help(parser, current_cmd); - // break; - // } - // } - // if (org_opt->spec.store_as_count) { - // *org_opt->spec.store.int_store += 1; - // } - // if (org_opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_BOOL) { - // *org_opt->spec.store.bool_store = true; - // } - // if (opt_res.value) { - // org_opt->spec.raw_value = opt_res.value; - // // TODO - // *org_opt->spec.store.str_store = opt_res.value; - // } return SCC_ARGPARSE_ERR_NONE; } @@ -221,7 +242,7 @@ static int handle_positional_arg(scc_argparse_context_t *ctx, is_subcommand(ctx->current_cmd, ctx->result.value); if (subcmd != nullptr) { ctx->current_cmd = subcmd; - parse_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd); + prepare_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd); return SCC_ARGPARSE_ERR_NONE; } @@ -232,28 +253,9 @@ static int handle_positional_arg(scc_argparse_context_t *ctx, arg->spec.raw_value = ctx->result.value; ctx->positional_index++; } else { - scc_argparse_print_error(ctx, SCC_ARGPARSE_ERR_UNKNOWN_ARG); ctx->parsing_done = true; + return SCC_ARGPARSE_ERR_UNKNOWN_ARG; } - - // // position arg - // scc_argparse_cmd_t *cmd = is_subcommand(current_cmd, - // opt_res.value); - - // if (cmd != nullptr) { - // current_cmd = cmd; - // parse_cmd(&optparse, &opts, current_cmd); - // } else { - // // TODO argument - // scc_vec_foreach(current_cmd->args, i) { - // scc_argparse_arg_t *arg = &scc_vec_at(current_cmd->args, - // i); if (*arg->spec.store.str_store == 0) { - // *arg->spec.store.str_store = opt_res.value; - // arg->spec.raw_value = opt_res.value; - // break; - // } - // } - // } return SCC_ARGPARSE_ERR_NONE; } @@ -265,14 +267,15 @@ int scc_argparse_parse(scc_argparse_t *parser, int argc, const char **argv) { while (!ctx.parsing_done && scc_optparse_parse(&ctx.optparse, &ctx.result)) { if (parser->need_debug) { - scc_printf("[%c:%s:%d] %s\n", + scc_printf("debug:[%c:%s:%d] %s\n", ctx.result.opt ? ctx.result.opt->short_name : '-', ctx.result.opt ? ctx.result.opt->long_name : "--", - ctx.result.error, ctx.result.value); + ctx.result.error, + ctx.result.value ? ctx.result.value : ""); } if (ctx.result.error) { - errcode = handle_parse_error(parser, &ctx); + errcode = transite_error(&ctx); break; } diff --git a/libs/argparse/src/argparse_print.c b/libs/argparse/src/argparse_print.c index c121486..fc26fb7 100644 --- a/libs/argparse/src/argparse_print.c +++ b/libs/argparse/src/argparse_print.c @@ -12,6 +12,7 @@ enum { ARGPARSE_SHOW_CMD, ARGPARSE_SHOW_HELP_MSG, + ARGPRASE_USING_HELP_HINT, ARGPARSE_UNKNOWN_ARGUMENT, ARGPARSE_INVALID_VALUE_FOR_OPTION, ARGPARSE_OPTION_MISSING_VALUE, @@ -28,10 +29,12 @@ static const char *fmt_en[] = { [ARGPARSE_SHOW_CMD] = "Commands:\n", [ARGPARSE_SHOW_HELP_MSG] = "Show this help message and exit", - [ARGPARSE_UNKNOWN_ARGUMENT] = "Unknown argument '%s'", + [ARGPRASE_USING_HELP_HINT] = + "Using '-h' or '--help' to get more information\n", + [ARGPARSE_UNKNOWN_ARGUMENT] = "Unknown argument '%s'\n", [ARGPARSE_INVALID_VALUE_FOR_OPTION] = "Invalid value for option '%s'\n", [ARGPARSE_OPTION_MISSING_VALUE] = "Option '%s' missing value\n", - [ARGPARSE_DID_YOU_MEAN] = "; Did you mean: '%s'?\n", + [ARGPARSE_DID_YOU_MEAN] = "Did you mean: '%s'?\n", }; static const char *fmt_zh[] = { @@ -44,10 +47,11 @@ static const char *fmt_zh[] = { [ARGPARSE_SHOW_CMD] = "命令:\n", [ARGPARSE_SHOW_HELP_MSG] = "显示帮助信息并退出", - [ARGPARSE_UNKNOWN_ARGUMENT] = "未知的参数 '%s'", + [ARGPRASE_USING_HELP_HINT] = "使用 '-h' 或者 '--help' 获取更多信息\n", + [ARGPARSE_UNKNOWN_ARGUMENT] = "未知的参数 '%s'\n", [ARGPARSE_INVALID_VALUE_FOR_OPTION] = "无效的选项值 '%s'\n", [ARGPARSE_OPTION_MISSING_VALUE] = "选项 '%s' 缺少值\n", - [ARGPARSE_DID_YOU_MEAN] = "; 您是不是想要输入: '%s'?\n", + [ARGPARSE_DID_YOU_MEAN] = "您是不是想要输入: '%s'?\n", }; /** @@ -95,7 +99,7 @@ static int scc_levenshtein(const char *s1, const char *s2) { return dist; } -void scc_argparse_print_help(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) { +static void print_usage(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) { const char **lines = (parser->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en; scc_printf(lines[ARGPARSE_USAGE], @@ -109,6 +113,14 @@ void scc_argparse_print_help(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) { if (scc_vec_size(cmd->subcmds) > 0) scc_printf(lines[ARGPARSE_COMMAND]); scc_printf("\n\n"); +} + +void scc_argparse_print_help(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) { + const char **lines = + (parser->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en; + + print_usage(parser, cmd); + if (cmd->description) scc_printf("%s\n\n", cmd->description); @@ -197,28 +209,40 @@ const char *scc_argparse_find_similar_arg(scc_argparse_cmd_t *cmd, } void scc_argparse_print_error(scc_argparse_context_t *ctx, - scc_argparse_err_t err) { - const char **lines = (ctx->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en; - const char *optname = ctx->result.raw_arg; + scc_argparse_t *parser, scc_argparse_err_t err) { + const char **lines = + (parser->lang == SCC_ARGPARSE_LANG_ZH) ? fmt_zh : fmt_en; switch (err) { case SCC_ARGPARSE_ERR_INVALID_ARG: case SCC_ARGPARSE_ERR_INVALID_VALUE: - scc_printf(lines[ARGPARSE_INVALID_VALUE_FOR_OPTION], optname); + scc_printf(lines[ARGPARSE_INVALID_VALUE_FOR_OPTION], ctx->err_ctx); break; case SCC_ARGPARSE_ERR_MISSING_ARG: case SCC_ARGPARSE_ERR_MISSING_VALUE: - scc_printf(lines[ARGPARSE_OPTION_MISSING_VALUE], optname); + scc_printf(lines[ARGPARSE_OPTION_MISSING_VALUE], ctx->err_ctx); break; case SCC_ARGPARSE_ERR_UNKNOWN_ARG: case SCC_ARGPARSE_ERR_UNKNOWN_VALUE: - scc_printf(lines[ARGPARSE_UNKNOWN_ARGUMENT], optname); - const char *similar_arg = - scc_argparse_find_similar_arg(ctx->current_cmd, optname); + scc_printf(lines[ARGPARSE_UNKNOWN_ARGUMENT], ctx->result.raw_arg); + const char *similar_arg = scc_argparse_find_similar_arg( + ctx->current_cmd, ctx->result.raw_arg); if (similar_arg != 0) { scc_printf(lines[ARGPARSE_DID_YOU_MEAN], similar_arg); } break; + // FACK ERROR + case SCC_ARGPARSE_ERR_PNT_DEFAULT: + return; default: scc_printf("Unknown error: %d\n", err); + break; + } + if (parser->need_help) { + scc_printf(lines[ARGPRASE_USING_HELP_HINT]); + } + if (parser->need_error_add_help) { + scc_argparse_print_help(parser, ctx->current_cmd); + } else if (parser->need_error_add_usage) { + print_usage(parser, ctx->current_cmd); } } diff --git a/libs/argparse/examples/main.c b/libs/argparse/src/main.c similarity index 99% rename from libs/argparse/examples/main.c rename to libs/argparse/src/main.c index ea4571f..0312f10 100644 --- a/libs/argparse/examples/main.c +++ b/libs/argparse/src/main.c @@ -109,4 +109,4 @@ int main(int argc, const char **argv, const char **envp) { scc_argparse_drop(&argparse); return ret; -} \ No newline at end of file +} diff --git a/libs/argparse/src/optparse.c b/libs/argparse/src/optparse.c index 37d6a4d..0b6cbe0 100644 --- a/libs/argparse/src/optparse.c +++ b/libs/argparse/src/optparse.c @@ -216,6 +216,6 @@ RETURN: parser->current.count > res->opt->max_args) { res->error = SCC_OPT_ERROR_TOO_MANY_ARGS; } - // res->raw_arg = arg; + res->raw_arg = arg; return res->opt != 0 || res->value != 0 || res->error != SCC_OPT_ERROR_NONE; } diff --git a/libs/mcode/include/amd64/scc_amd64.h b/libs/mcode/include/amd64/scc_amd64.h index a43fa42..f43ccf5 100644 --- a/libs/mcode/include/amd64/scc_amd64.h +++ b/libs/mcode/include/amd64/scc_amd64.h @@ -2305,7 +2305,6 @@ SCC_MCODE_FUNC void scc_mcode_amd64_mov_r64_m64_sib(scc_mcode_t *mcode, int dst, scc_mcode_add_u8(mcode, 0x8B); int has_disp = (base != -1) ? 1 : 0; // 无基址时必须带 disp32 - int disp8 = 0; // 不自动选择,统一用 disp32 简化 int disp_size = 4; if (base != -1) { if (disp == 0) { diff --git a/libs/parser/src/scc_sema.c b/libs/parser/src/scc_sema.c index cdc03b6..214bd74 100644 --- a/libs/parser/src/scc_sema.c +++ b/libs/parser/src/scc_sema.c @@ -198,5 +198,7 @@ void scc_sema_init(scc_sema_callbacks_t *callbacks) { void scc_sema_drop(scc_sema_callbacks_t *callbacks) { // FIXME drop obj - scc_sema_symtab_drop(callbacks->context); + if (callbacks->context) { + scc_sema_symtab_drop(callbacks->context); + } } diff --git a/libs/parser/tests/parser_test.h b/libs/parser/tests/parser_test.h index 918ec44..a909c8d 100644 --- a/libs/parser/tests/parser_test.h +++ b/libs/parser/tests/parser_test.h @@ -52,28 +52,26 @@ typedef void (*scc_tree_dump_output_t)(void *userdata, const char *fmt, ...); char expect_buffer[BUFFER_SIZE]; char output_buffer[BUFFER_SIZE]; -static void dump2buffer(void *_buffer, const char *fmt, ...) { - char *buffer = _buffer; - va_list args; - va_start(args, fmt); - int res = scc_vsnprintf(buffer + strlen(buffer), - BUFFER_SIZE - strlen(buffer) - 1, fmt, args); - Assert(res > 0); - va_end(args); +static void dump2buffer(const char *str, usize len, void *user) { + char *buff = user; + buff[0] = '\n'; + buff[1] = '\0'; + memcpy(buff, str, len + 1); } static void _scc_check_ast(scc_ast_node_t *expect_node_ptr, const char *str, scc_parse_node_func parse_func, cbool need_sema) { scc_ast_node_t *output_node_ptr = process_input(str, parse_func, need_sema); - scc_tree_dump_ctx_t ctx; - expect_buffer[0] = '\n', expect_buffer[1] = '\0'; - scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer); + scc_tree_dump_t ctx; + scc_tree_dump_init(&ctx, true); scc_ast_dump_node(&ctx, expect_node_ptr); - scc_tree_dump_ctx_drop(&ctx); - output_buffer[0] = '\n', output_buffer[1] = '\0'; - scc_tree_dump_ctx_init(&ctx, true, dump2buffer, output_buffer); + scc_tree_dump_flush(&ctx, dump2buffer, expect_buffer); + scc_tree_dump_drop(&ctx); + + scc_tree_dump_init(&ctx, true); scc_ast_dump_node(&ctx, output_node_ptr); - scc_tree_dump_ctx_drop(&ctx); + scc_tree_dump_flush(&ctx, dump2buffer, output_buffer); + scc_tree_dump_drop(&ctx); } #define SCC_CHECK_AST_WITH_SEMA(expect_node_ptr, str, parse_func) \