添加了 SCC_ARGPARSE_ERR_PNT_DEFAULT 错误类型用于默认操作处理, 实现了 scc_argparse_spec_setup_choices 函数支持枚举选择, 重构了错误处理流程使返回值更加一致。 修复了长选项名称匹配的逻辑错误。 feat(lexer): 添加换行符和注释符号的词法标记 新增 SCC_TOK_ENDLINE 和 SCC_TOK_SHARP 标记类型, 改进词法分析器对换行符和井号的识别处理。 feat(scc_core): 添加常用宏定义 添加 scc_min 和 scc_max 宏定义提供基础数值比较功能。 feat(main): 实现编译器主程序和命令行接口 创建主程序入口实现完整的编译流程, 集成预处理器、词法分析、语法分析和IR生成模块, 添加AST和IR输出功能支持调试查看中间表示。 chore(build): 配置项目构建依赖关系 创建 cbuild.toml 配置文件定义项目包信息和依赖库, 建立编译器各组件库之间的依赖关系管理。
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;
|
|
}
|