Compare commits
2 Commits
eeb4c4fc3c
...
630e22b73b
| Author | SHA1 | Date | |
|---|---|---|---|
| 630e22b73b | |||
| 053c6abf51 |
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 : "<nullptr>");
|
||||
}
|
||||
|
||||
if (ctx.result.error) {
|
||||
errcode = handle_parse_error(parser, &ctx);
|
||||
errcode = transite_error(&ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,4 +109,4 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
|
||||
scc_argparse_drop(&argparse);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <scc_ast2ir.h>
|
||||
|
||||
static inline void parse_struct_union_layout(scc_ast_type_t *type) {}
|
||||
|
||||
static inline void parse_lexme2const_int(const char *lexme,
|
||||
scc_ir_const_int_t *value) {
|
||||
// FIXME
|
||||
@@ -430,7 +432,7 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
scc_ast2ir_expr(ctx, expr->subscript.index, false);
|
||||
// 3. 生成 getptr(GEP)
|
||||
scc_ir_value_ref_t elem_ptr =
|
||||
scc_ir_builder_get_ptr(&ctx->builder, base_ptr, index);
|
||||
scc_ir_builder_get_elem_ptr(&ctx->builder, base_ptr, index);
|
||||
// 4. 根据左值/右值返回
|
||||
if (is_lvalue) {
|
||||
return elem_ptr; // 作为左值:返回地址
|
||||
@@ -523,8 +525,8 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
ctx->builder.ctx.module, ir_type->data.pointer.base);
|
||||
if (target_type->tag == SCC_IR_TYPE_ARRAY) {
|
||||
// 生成 getptr 获取数组首地址
|
||||
return scc_ir_builder_get_ptr(&ctx->builder, in,
|
||||
SCC_IR_REF_nullptr);
|
||||
return scc_ir_builder_get_elem_ptr(&ctx->builder, in,
|
||||
SCC_IR_REF_nullptr);
|
||||
} else {
|
||||
// 标量类型:加载值
|
||||
return scc_ir_builder_load(&ctx->builder, in);
|
||||
|
||||
@@ -144,11 +144,12 @@ scc_ir_builder_const_string(scc_ir_builder_t *builder, const char *str,
|
||||
// scc_hashtable_insert(builder);
|
||||
|
||||
scc_ir_value_ref_t pointer_to_global_value = scc_ir_module_add_value(
|
||||
builder->ctx.module, &(scc_ir_value_t){
|
||||
.tag = SCC_IR_VALUE_TAG_GET_PTR,
|
||||
.data.get_ptr.src_addr = global_value_ref,
|
||||
.data.get_ptr.index = SCC_IR_VALUE_TAG_NULLPTR,
|
||||
});
|
||||
builder->ctx.module,
|
||||
&(scc_ir_value_t){
|
||||
.tag = SCC_IR_VALUE_TAG_GET_ELEM_PTR,
|
||||
.data.get_elem_ptr.src_addr = global_value_ref,
|
||||
.data.get_elem_ptr.index = SCC_IR_VALUE_TAG_NULLPTR,
|
||||
});
|
||||
scc_ir_builder_add_instr(builder, pointer_to_global_value);
|
||||
return pointer_to_global_value;
|
||||
}
|
||||
@@ -236,9 +237,9 @@ scc_ir_value_ref_t scc_ir_builder_store(scc_ir_builder_t *builder,
|
||||
* @param ptr 基础指针
|
||||
* @param index 索引值
|
||||
*/
|
||||
scc_ir_value_ref_t scc_ir_builder_get_ptr(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t ptr,
|
||||
scc_ir_value_ref_t index);
|
||||
scc_ir_value_ref_t scc_ir_builder_get_elem_ptr(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t ptr,
|
||||
scc_ir_value_ref_t index);
|
||||
|
||||
/**
|
||||
* @brief 创建二元运算指令
|
||||
|
||||
@@ -100,7 +100,6 @@ typedef enum scc_ir_value_tag {
|
||||
SCC_IR_VALUE_TAG_GLOBAL_ALLOC, ///< 全局分配
|
||||
SCC_IR_VALUE_TAG_LOAD, ///< 加载数据
|
||||
SCC_IR_VALUE_TAG_STORE, ///< 存储数据
|
||||
SCC_IR_VALUE_TAG_GET_PTR, ///< 获取指针
|
||||
SCC_IR_VALUE_TAG_GET_ELEM_PTR, ///< 获取元素指针
|
||||
SCC_IR_VALUE_TAG_OP, ///< 二元运算
|
||||
SCC_IR_VALUE_TAG_BRANCH, ///< 有条件分支
|
||||
@@ -258,10 +257,6 @@ struct scc_ir_value {
|
||||
scc_ir_value_ref_t target;
|
||||
scc_ir_value_ref_t value;
|
||||
} store;
|
||||
struct {
|
||||
scc_ir_value_ref_t src_addr;
|
||||
scc_ir_value_ref_t index;
|
||||
} get_ptr;
|
||||
struct {
|
||||
scc_ir_value_ref_t src_addr;
|
||||
scc_ir_value_ref_t index;
|
||||
|
||||
@@ -227,19 +227,33 @@ scc_ir_value_ref_t scc_ir_builder_store(scc_ir_builder_t *builder,
|
||||
return value_ref;
|
||||
}
|
||||
|
||||
scc_ir_value_ref_t scc_ir_builder_get_ptr(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t target,
|
||||
scc_ir_value_ref_t index) {
|
||||
scc_ir_value_ref_t scc_ir_builder_get_elem_ptr(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t target,
|
||||
scc_ir_value_ref_t index) {
|
||||
scc_ir_value_t get_ptr_node = {0};
|
||||
get_ptr_node.tag = SCC_IR_VALUE_TAG_GET_PTR;
|
||||
get_ptr_node.data.get_ptr.src_addr = target;
|
||||
get_ptr_node.data.get_ptr.index = index;
|
||||
get_ptr_node.tag = SCC_IR_VALUE_TAG_GET_ELEM_PTR;
|
||||
get_ptr_node.data.get_elem_ptr.src_addr = target;
|
||||
get_ptr_node.data.get_elem_ptr.index = index;
|
||||
|
||||
// 类型应与源地址相同(都是指针)
|
||||
scc_ir_value_t *src_node =
|
||||
scc_ir_module_get_value(GET_MODULE(builder), target);
|
||||
if (src_node) {
|
||||
get_ptr_node.type = src_node->type;
|
||||
scc_ir_type_t *type =
|
||||
scc_ir_module_get_type_by_value(GET_MODULE(builder), target);
|
||||
Assert(type != nullptr);
|
||||
if (type->tag == SCC_IR_TYPE_PTR) {
|
||||
scc_ir_type_t *base_type = scc_ir_module_get_type(
|
||||
GET_MODULE(builder), type->data.pointer.base);
|
||||
if (base_type->tag == SCC_IR_TYPE_ARRAY) {
|
||||
// FIXME GEP maybe multiple levels
|
||||
get_ptr_node.type = scc_ir_builder_type(
|
||||
builder, &(scc_ir_type_t){
|
||||
.tag = SCC_IR_TYPE_PTR,
|
||||
.data.pointer.base = base_type->data.array.base,
|
||||
});
|
||||
} else {
|
||||
get_ptr_node.type = scc_ir_builder_type(builder, type);
|
||||
}
|
||||
} else {
|
||||
get_ptr_node.type = scc_ir_builder_type(builder, type);
|
||||
}
|
||||
|
||||
scc_ir_value_ref_t value_ref =
|
||||
|
||||
@@ -20,7 +20,6 @@ static const char *get_node_type_str(scc_ir_value_tag_t tag) {
|
||||
[SCC_IR_VALUE_TAG_GLOBAL_ALLOC] = "GlobalAlloc",
|
||||
[SCC_IR_VALUE_TAG_LOAD] = "Load",
|
||||
[SCC_IR_VALUE_TAG_STORE] = "Store",
|
||||
[SCC_IR_VALUE_TAG_GET_PTR] = "GetPtr",
|
||||
[SCC_IR_VALUE_TAG_GET_ELEM_PTR] = "GetElemPtr",
|
||||
[SCC_IR_VALUE_TAG_OP] = "Op",
|
||||
[SCC_IR_VALUE_TAG_BRANCH] = "Branch",
|
||||
@@ -117,12 +116,12 @@ static void dump_store_node(scc_ir_dump_ctx_t *ctx,
|
||||
dump_child_node_ref(ctx, value->data.store.value, true);
|
||||
}
|
||||
|
||||
static void dump_get_ptr_node(scc_ir_dump_ctx_t *ctx,
|
||||
const scc_ir_value_t *value) {
|
||||
if (value->data.get_ptr.src_addr)
|
||||
dump_child_node_ref(ctx, value->data.get_ptr.src_addr, false);
|
||||
if (value->data.get_ptr.index)
|
||||
dump_child_node_ref(ctx, value->data.get_ptr.index, true);
|
||||
static void dump_get_elem_ptr_node(scc_ir_dump_ctx_t *ctx,
|
||||
const scc_ir_value_t *value) {
|
||||
if (value->data.get_elem_ptr.src_addr)
|
||||
dump_child_node_ref(ctx, value->data.get_elem_ptr.src_addr, false);
|
||||
if (value->data.get_elem_ptr.index)
|
||||
dump_child_node_ref(ctx, value->data.get_elem_ptr.index, true);
|
||||
}
|
||||
|
||||
static void dump_branch_node(scc_ir_dump_ctx_t *ctx,
|
||||
@@ -236,8 +235,8 @@ void scc_ir_dump_value(scc_ir_dump_ctx_t *ctx, scc_ir_value_ref_t value_ref) {
|
||||
case SCC_IR_VALUE_TAG_STORE:
|
||||
dump_store_node(ctx, value);
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_GET_PTR:
|
||||
dump_get_ptr_node(ctx, value);
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR:
|
||||
dump_get_elem_ptr_node(ctx, value);
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_OP:
|
||||
dump_op_node(ctx, value);
|
||||
@@ -556,13 +555,10 @@ void scc_ir_dump_value_linear(scc_ir_dump_ctx_t *ctx,
|
||||
format_ref_or_value(ctx, value->data.store.target);
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR:
|
||||
case SCC_IR_VALUE_TAG_GET_PTR:
|
||||
scc_tree_dump_append(
|
||||
ctx->dump_ctx,
|
||||
value->tag == SCC_IR_VALUE_TAG_GET_PTR ? "getptr " : "getelemptr ");
|
||||
format_ref_or_value(ctx, value->data.get_ptr.src_addr);
|
||||
scc_tree_dump_append(ctx->dump_ctx, "getelemptr ");
|
||||
format_ref_or_value(ctx, value->data.get_elem_ptr.src_addr);
|
||||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||||
format_ref_or_value(ctx, value->data.get_ptr.index);
|
||||
format_ref_or_value(ctx, value->data.get_elem_ptr.index);
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_OP:
|
||||
format_ref_or_value(ctx, value->data.op.lhs);
|
||||
|
||||
@@ -82,9 +82,9 @@ void scc_ir_value_init(scc_ir_value_t *in, const char *name,
|
||||
in->data.store.target = 0;
|
||||
in->data.store.value = 0;
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_GET_PTR:
|
||||
in->data.get_ptr.src_addr = 0;
|
||||
in->data.get_ptr.index = 0;
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR:
|
||||
in->data.get_elem_ptr.src_addr = 0;
|
||||
in->data.get_elem_ptr.index = 0;
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_OP:
|
||||
in->data.op.op = SCC_IR_OP_EMPTY;
|
||||
|
||||
@@ -287,14 +287,14 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
break;
|
||||
}
|
||||
///< 获取指针
|
||||
case SCC_IR_VALUE_TAG_GET_PTR: {
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR: {
|
||||
scc_reg_loc_t loc_res;
|
||||
parse_location(ctx, &loc_res, node_ref);
|
||||
|
||||
scc_ir_value_t *src_addr = scc_ir_module_get_value(
|
||||
GET_MODULE(ctx), value->data.get_ptr.src_addr);
|
||||
GET_MODULE(ctx), value->data.get_elem_ptr.src_addr);
|
||||
Assert(src_addr != nullptr);
|
||||
if (value->data.get_ptr.index == 0) {
|
||||
if (value->data.get_elem_ptr.index == 0) {
|
||||
if (src_addr->tag == SCC_IR_VALUE_TAG_GLOBAL_ALLOC) {
|
||||
// 全局变量:RIP相对寻址
|
||||
scc_mcode_amd64_lea_r64_rip_rel32(&ctx->sect_mcode,
|
||||
@@ -314,30 +314,35 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
} else if (src_addr->tag == SCC_IR_VALUE_TAG_ALLOC) {
|
||||
// 栈上变量:地址为 rbp - offset
|
||||
scc_reg_loc_t src_loc;
|
||||
parse_location(ctx, &src_loc, value->data.get_ptr.src_addr);
|
||||
parse_location(ctx, &src_loc,
|
||||
value->data.get_elem_ptr.src_addr);
|
||||
src_loc.kind = SCC_REG_KIND_STACK_ADDR;
|
||||
load_value_to_reg(ctx, &src_loc, SCC_AMD64_RAX);
|
||||
} else {
|
||||
// 其他情况(如链式
|
||||
// getptr):源地址值已经存储在某个位置,直接加载到 RAX
|
||||
// 其他情况(如链式getptr):源地址值已经存储在某个位置,直接加载到
|
||||
// RAX
|
||||
scc_reg_loc_t src_loc;
|
||||
parse_location(ctx, &src_loc, value->data.get_ptr.src_addr);
|
||||
parse_location(ctx, &src_loc,
|
||||
value->data.get_elem_ptr.src_addr);
|
||||
load_value_to_reg(ctx, &src_loc, SCC_AMD64_RAX);
|
||||
}
|
||||
|
||||
store_value_from_reg(ctx, &loc_res, SCC_AMD64_RAX);
|
||||
} else {
|
||||
// TODO
|
||||
scc_ir_value_t *index = scc_ir_module_get_value(
|
||||
GET_MODULE(ctx), value->data.get_ptr.index);
|
||||
Assert(index != nullptr &&
|
||||
index->tag == SCC_IR_VALUE_TAG_CONST_INT);
|
||||
}
|
||||
parse_value(ctx, value->data.get_elem_ptr.index, patches);
|
||||
|
||||
scc_reg_loc_t src_loc;
|
||||
scc_reg_loc_t idx_loc;
|
||||
parse_location(ctx, &src_loc, value->data.get_elem_ptr.src_addr);
|
||||
parse_location(ctx, &idx_loc, value->data.get_elem_ptr.index);
|
||||
src_loc.kind = SCC_REG_KIND_STACK_ADDR;
|
||||
load_value_to_reg(ctx, &src_loc, SCC_AMD64_RAX);
|
||||
load_value_to_reg(ctx, &idx_loc, SCC_AMD64_RDX);
|
||||
scc_mcode_amd64_lea_r64_m64_sib(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX, SCC_AMD64_RDX, 1, 0);
|
||||
}
|
||||
store_value_from_reg(ctx, &loc_res, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR: ///< 获取元素指针(used by array)
|
||||
TODO();
|
||||
///< 二元运算
|
||||
case SCC_IR_VALUE_TAG_OP: {
|
||||
scc_reg_loc_t loc_lhs;
|
||||
|
||||
@@ -49,7 +49,6 @@ void scc_reg_alloc_strategy_pure_stack(scc_reg_alloc_t *ctx,
|
||||
switch (node->tag) {
|
||||
case SCC_IR_VALUE_TAG_LOAD:
|
||||
case SCC_IR_VALUE_TAG_OP:
|
||||
case SCC_IR_VALUE_TAG_GET_PTR:
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR:
|
||||
case SCC_IR_VALUE_TAG_CALL: // 返回值
|
||||
loc.kind = SCC_REG_KIND_STACK;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -79,8 +79,33 @@ int scc_fprintf(scc_file_t file, const char *format, ...) {
|
||||
}
|
||||
|
||||
int scc_vfprintf(scc_file_t file, const char *format, va_list args) {
|
||||
char buf[4096] = {0};
|
||||
int size = vsnprintf_(buf, sizeof(buf), format, args);
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
|
||||
// 先计算所需长度
|
||||
int required_size = vsnprintf_(nullptr, 0, format, args_copy);
|
||||
va_end(args_copy);
|
||||
|
||||
if (required_size < 0)
|
||||
return -1;
|
||||
|
||||
char *buf = nullptr;
|
||||
int size = 0;
|
||||
|
||||
if (required_size < 4096) {
|
||||
// 小输出使用栈上缓冲区
|
||||
char stack_buf[4096];
|
||||
size = vsnprintf_(stack_buf, sizeof(stack_buf), format, args);
|
||||
buf = stack_buf;
|
||||
} else {
|
||||
// 大输出使用堆分配
|
||||
buf = scc_pal_malloc(required_size + 1);
|
||||
if (!buf)
|
||||
return -1;
|
||||
size = vsnprintf_(buf, required_size + 1, format, args);
|
||||
}
|
||||
|
||||
// 输出处理...
|
||||
if (file == scc_stdout) {
|
||||
scc_pal_write(buf, size);
|
||||
} else if (file == scc_stderr) {
|
||||
@@ -88,6 +113,12 @@ int scc_vfprintf(scc_file_t file, const char *format, va_list args) {
|
||||
} else {
|
||||
scc_pal_fwrite(file, buf, size);
|
||||
}
|
||||
|
||||
// 如果使用了堆分配,释放内存
|
||||
if (buf && required_size >= 4096) {
|
||||
scc_pal_free(buf);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user