feat(ast): 更新AST dump功能以使用新的树转储接口
- 将头文件中的tree_dump.h替换为scc_tree_dump.h - 修改函数签名将scc_tree_dump_ctx_t改为scc_tree_dump_t - 移除过时的宏定义和内联函数实现 - 使用新的scc_tree_dump_* API替代旧的PRINT_*宏 - 简化类型、表达式、语句和声明的转储逻辑 - 统一使用新的树转储接口进行节点和值的输出 feat(ast2ir): 实现逻辑运算符和一元运算符的IR转换 - 添加scc_ast2ir_logical_expr函数处理&&和||运算符 - 实现短路求值逻辑,包含分支控制流 - 添加对一元正号运算符的支持 - 实现取地址和间接寻址运算符 - 添加字符字面量解析支持转义序列 fix(ir): 修复字符串常量构建中的长度计算错误 - 修正数组长度计算从len+1改为len-1 - 调整字符串内容复制逻辑跳过引号边界 - 修正内存分配大小与实际数据长度匹配 refactor(ir): 更新IR转储模块使用统一的树转储接口 - 将IR转储上下文中的tree_dump_ctx_t替换为scc_tree_dump_t - 更新初始化函数签名以使用新的转储接口类型
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
#define __SCC_AST_DUMP_H__
|
||||
|
||||
#include "ast_def.h"
|
||||
#include <tree_dump.h>
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
/**
|
||||
* @brief 以指定格式 dump AST
|
||||
@@ -15,6 +15,6 @@
|
||||
* @param node AST 节点(可以是任意类型的节点)
|
||||
* @param ctx dump 上下文
|
||||
*/
|
||||
void scc_ast_dump_node(scc_tree_dump_ctx_t *ctx, const scc_ast_node_t *node);
|
||||
void scc_ast_dump_node(scc_tree_dump_t *ctx, const scc_ast_node_t *node);
|
||||
|
||||
#endif /* __SCC_AST_DUMP_H__ */
|
||||
|
||||
@@ -4,15 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <ast_dump.h>
|
||||
|
||||
#define PRINT_VALUE(ctx, fmt, value) \
|
||||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->value_color, fmt, value)
|
||||
|
||||
#define PRINT_NODE(ctx, name, value) \
|
||||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->node_color, "%s", name)
|
||||
|
||||
#define PRINT_QUOTED_VALUE(ctx, str) \
|
||||
SCC_TREE_DUMP_PRINT_AROUND(ctx, ctx->value_color, "'", "%s", str)
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
static const char *node_type_names[] = {
|
||||
[SCC_AST_UNKNOWN] = "Unknown",
|
||||
@@ -112,7 +104,6 @@ static const char *get_builtin_type_str(scc_ast_builtin_type_t type) {
|
||||
return builtin_type_names[type];
|
||||
}
|
||||
|
||||
// 获取操作符字符串
|
||||
static const char *get_op_str(scc_ast_expr_op_t op) {
|
||||
switch (op) {
|
||||
case SCC_AST_OP_ASSIGN:
|
||||
@@ -200,484 +191,374 @@ static const char *get_op_str(scc_ast_expr_op_t op) {
|
||||
}
|
||||
}
|
||||
|
||||
// 通用的开始节点打印函数
|
||||
static inline void start_node_dump(scc_ast_node_t *node,
|
||||
scc_tree_dump_ctx_t *ctx) {
|
||||
scc_tree_print_indent(ctx);
|
||||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->node_color, "%s",
|
||||
get_node_type_str(node->type));
|
||||
}
|
||||
|
||||
// 通用的结束节点打印函数
|
||||
static inline void end_node_dump(scc_tree_dump_ctx_t *ctx) {
|
||||
scc_tree_dump_printf(ctx, "\n");
|
||||
}
|
||||
|
||||
// 通用的递归转储辅助函数
|
||||
static inline void dump_child_node(scc_ast_node_t *child,
|
||||
scc_tree_dump_ctx_t *ctx, cbool is_last) {
|
||||
static inline void dump_child_node(scc_tree_dump_t *td, scc_ast_node_t *child,
|
||||
cbool is_last) {
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
scc_vec_push(ctx->stack, is_last);
|
||||
scc_ast_dump_node(ctx, child);
|
||||
(void)scc_vec_pop(ctx->stack);
|
||||
scc_tree_dump_push(td, is_last);
|
||||
scc_ast_dump_node(td, child);
|
||||
scc_tree_dump_pop(td);
|
||||
}
|
||||
|
||||
// 用于构建复合类型名称的宏
|
||||
#define BUILD_TYPE_NAME(ctx, prefix, name) \
|
||||
do { \
|
||||
if (ctx->use_color) { \
|
||||
scc_tree_dump_printf(ctx, "%s'%s%s%s'%s", ctx->value_color, \
|
||||
prefix, name, ctx->reset_color, \
|
||||
ctx->reset_color); \
|
||||
} else { \
|
||||
scc_tree_dump_printf(ctx, "'%s%s'", prefix, name); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void dump_quals(scc_ast_decl_specifier_t quals,
|
||||
scc_tree_dump_ctx_t *ctx) {
|
||||
if (quals.is_atomic) {
|
||||
PRINT_QUOTED_VALUE(ctx, "atomic");
|
||||
}
|
||||
if (quals.is_restrict) {
|
||||
PRINT_QUOTED_VALUE(ctx, "restrict");
|
||||
}
|
||||
if (quals.is_volatile) {
|
||||
PRINT_QUOTED_VALUE(ctx, "volatile");
|
||||
}
|
||||
if (quals.is_const) {
|
||||
PRINT_QUOTED_VALUE(ctx, "const");
|
||||
}
|
||||
if (quals.is_inline) {
|
||||
PRINT_QUOTED_VALUE(ctx, "inline");
|
||||
}
|
||||
if (quals.is_extern) {
|
||||
PRINT_QUOTED_VALUE(ctx, "extern");
|
||||
}
|
||||
scc_tree_dump_t *td) {
|
||||
if (quals.is_atomic)
|
||||
scc_tree_dump_value(td, " atomic");
|
||||
if (quals.is_restrict)
|
||||
scc_tree_dump_value(td, " restrict");
|
||||
if (quals.is_volatile)
|
||||
scc_tree_dump_value(td, " volatile");
|
||||
if (quals.is_const)
|
||||
scc_tree_dump_value(td, " const");
|
||||
if (quals.is_inline)
|
||||
scc_tree_dump_value(td, " inline");
|
||||
if (quals.is_extern)
|
||||
scc_tree_dump_value(td, " extern");
|
||||
}
|
||||
|
||||
// 递归转储类型
|
||||
static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_ctx_t *ctx) {
|
||||
static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_t *td) {
|
||||
if (!type)
|
||||
return;
|
||||
|
||||
start_node_dump(&type->base, ctx);
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "%s", get_node_type_str(type->base.type));
|
||||
dump_quals(type->quals, td);
|
||||
|
||||
dump_quals(type->quals, ctx);
|
||||
|
||||
// 根据类型输出特定信息
|
||||
switch (type->base.type) {
|
||||
case SCC_AST_TYPE_BUILTIN:
|
||||
PRINT_QUOTED_VALUE(ctx, get_builtin_type_str(type->builtin.type));
|
||||
scc_tree_dump_value(td, " '%s'",
|
||||
get_builtin_type_str(type->builtin.type));
|
||||
break;
|
||||
case SCC_AST_TYPE_POINTER:
|
||||
PRINT_QUOTED_VALUE(ctx, "pointer");
|
||||
scc_tree_dump_value(td, " pointer");
|
||||
break;
|
||||
case SCC_AST_TYPE_ARRAY:
|
||||
PRINT_QUOTED_VALUE(ctx, "array");
|
||||
scc_tree_dump_value(td, " array");
|
||||
break;
|
||||
case SCC_AST_TYPE_FUNCTION:
|
||||
PRINT_QUOTED_VALUE(ctx, "function");
|
||||
scc_tree_dump_value(td, " function");
|
||||
break;
|
||||
case SCC_AST_TYPE_STRUCT:
|
||||
if (type->record.name) {
|
||||
BUILD_TYPE_NAME(ctx, "struct ", type->record.name);
|
||||
} else {
|
||||
PRINT_QUOTED_VALUE(ctx, "<anonymous struct>");
|
||||
}
|
||||
if (type->record.name)
|
||||
scc_tree_dump_value(td, " 'struct %s'", type->record.name);
|
||||
else
|
||||
scc_tree_dump_value(td, " <anonymous struct>");
|
||||
break;
|
||||
case SCC_AST_TYPE_UNION:
|
||||
if (type->record.name) {
|
||||
BUILD_TYPE_NAME(ctx, "union ", type->record.name);
|
||||
} else {
|
||||
PRINT_QUOTED_VALUE(ctx, "<anonymous union>");
|
||||
}
|
||||
if (type->record.name)
|
||||
scc_tree_dump_value(td, " 'union %s'", type->record.name);
|
||||
else
|
||||
scc_tree_dump_value(td, " <anonymous union>");
|
||||
break;
|
||||
case SCC_AST_TYPE_ENUM:
|
||||
if (type->record.name) {
|
||||
BUILD_TYPE_NAME(ctx, "enum ", type->record.name);
|
||||
} else {
|
||||
PRINT_QUOTED_VALUE(ctx, "anonymous enum");
|
||||
}
|
||||
if (type->record.name)
|
||||
scc_tree_dump_value(td, " 'enum %s'", type->record.name);
|
||||
else
|
||||
scc_tree_dump_value(td, " anonymous enum");
|
||||
break;
|
||||
case SCC_AST_TYPE_TYPEDEF:
|
||||
PRINT_QUOTED_VALUE(ctx, type->typedef_type.name);
|
||||
scc_tree_dump_value(td, " '%s'", type->typedef_type.name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
end_node_dump(ctx);
|
||||
|
||||
// 递归转储子节点
|
||||
switch (type->base.type) {
|
||||
case SCC_AST_TYPE_POINTER:
|
||||
dump_child_node((scc_ast_node_t *)type->pointer.pointee, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)type->pointer.pointee, true);
|
||||
break;
|
||||
case SCC_AST_TYPE_ARRAY:
|
||||
dump_child_node((scc_ast_node_t *)type->array.element, ctx,
|
||||
dump_child_node(td, (scc_ast_node_t *)type->array.element,
|
||||
type->array.size == NULL);
|
||||
if (type->array.size) {
|
||||
dump_child_node((scc_ast_node_t *)type->array.size, ctx, true);
|
||||
}
|
||||
if (type->array.size)
|
||||
dump_child_node(td, (scc_ast_node_t *)type->array.size, true);
|
||||
break;
|
||||
case SCC_AST_TYPE_FUNCTION:
|
||||
scc_vec_push(ctx->stack, false);
|
||||
scc_tree_print_indent(ctx);
|
||||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->node_color, "%s\n", "ReturnType");
|
||||
dump_child_node((scc_ast_node_t *)type->function.return_type, ctx,
|
||||
true);
|
||||
(void)scc_vec_pop(ctx->stack);
|
||||
scc_tree_dump_push(td, false);
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "%s", "ReturnType");
|
||||
dump_child_node(td, (scc_ast_node_t *)type->function.return_type, true);
|
||||
scc_tree_dump_pop(td);
|
||||
|
||||
scc_vec_push(ctx->stack, true);
|
||||
scc_tree_dump_push(td, true);
|
||||
if (scc_vec_size(type->function.params) != 0) {
|
||||
scc_vec_foreach(type->function.params, i) {
|
||||
scc_ast_decl_t *param = scc_vec_at(type->function.params, i);
|
||||
if (param->name) {
|
||||
// FIXME param name
|
||||
}
|
||||
dump_type_impl(param->param.type, ctx);
|
||||
dump_type_impl(param->param.type, td);
|
||||
}
|
||||
} else {
|
||||
scc_tree_print_indent(ctx);
|
||||
PRINT_QUOTED_VALUE(ctx, "()");
|
||||
scc_tree_dump_printf(ctx, "\n");
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_value(td, "()");
|
||||
}
|
||||
(void)scc_vec_pop(ctx->stack);
|
||||
scc_tree_dump_pop(td);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归转储表达式
|
||||
static void dump_expr_impl(scc_ast_expr_t *expr, scc_tree_dump_ctx_t *ctx) {
|
||||
static void dump_expr_impl(scc_ast_expr_t *expr, scc_tree_dump_t *td) {
|
||||
if (!expr)
|
||||
return;
|
||||
|
||||
start_node_dump(&expr->base, ctx);
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "%s", get_node_type_str(expr->base.type));
|
||||
|
||||
// 根据表达式类型输出特定信息
|
||||
switch (expr->base.type) {
|
||||
case SCC_AST_EXPR_BINARY:
|
||||
PRINT_QUOTED_VALUE(ctx, get_op_str(expr->binary.op));
|
||||
scc_tree_dump_value(td, " '%s'", get_op_str(expr->binary.op));
|
||||
break;
|
||||
case SCC_AST_EXPR_UNARY:
|
||||
PRINT_QUOTED_VALUE(ctx, get_op_str(expr->unary.op));
|
||||
scc_tree_dump_value(td, " '%s'", get_op_str(expr->unary.op));
|
||||
break;
|
||||
case SCC_AST_EXPR_INT_LITERAL:
|
||||
case SCC_AST_EXPR_FLOAT_LITERAL:
|
||||
case SCC_AST_EXPR_CHAR_LITERAL:
|
||||
case SCC_AST_EXPR_STRING_LITERAL:
|
||||
PRINT_VALUE(ctx, " %s", expr->literal.lexme);
|
||||
scc_tree_dump_value(td, " %s", expr->literal.lexme);
|
||||
break;
|
||||
case SCC_AST_EXPR_IDENTIFIER:
|
||||
if (expr->identifier.name) {
|
||||
PRINT_QUOTED_VALUE(ctx, expr->identifier.name);
|
||||
}
|
||||
if (expr->identifier.name)
|
||||
scc_tree_dump_value(td, " '%s'", expr->identifier.name);
|
||||
break;
|
||||
case SCC_AST_EXPR_SIZE_OF:
|
||||
case SCC_AST_EXPR_ALIGN_OF:
|
||||
PRINT_QUOTED_VALUE(ctx, (expr->base.type == SCC_AST_EXPR_SIZE_OF)
|
||||
? "sizeof"
|
||||
: "alignof");
|
||||
scc_tree_dump_value(
|
||||
td, " '%s'",
|
||||
(expr->base.type == SCC_AST_EXPR_SIZE_OF) ? "sizeof" : "alignof");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
end_node_dump(ctx);
|
||||
|
||||
// 使用辅助函数处理子节点转储
|
||||
switch (expr->base.type) {
|
||||
case SCC_AST_EXPR_BINARY:
|
||||
dump_child_node((scc_ast_node_t *)expr->binary.lhs, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)expr->binary.rhs, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->binary.lhs, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->binary.rhs, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_UNARY:
|
||||
dump_child_node((scc_ast_node_t *)expr->unary.operand, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->unary.operand, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_COND:
|
||||
dump_child_node((scc_ast_node_t *)expr->cond.cond, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)expr->cond.then_expr, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)expr->cond.else_expr, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->cond.cond, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->cond.then_expr, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->cond.else_expr, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_CALL:
|
||||
dump_child_node((scc_ast_node_t *)expr->call.callee, ctx, false);
|
||||
// 转储参数
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->call.callee, false);
|
||||
for (size_t i = 0; i < expr->call.args.size; i++) {
|
||||
dump_child_node((scc_ast_node_t *)expr->call.args.data[i], ctx,
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->call.args.data[i],
|
||||
i == expr->call.args.size - 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_ARRAY_SUBSCRIPT:
|
||||
dump_child_node((scc_ast_node_t *)expr->subscript.array, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)expr->subscript.index, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->subscript.array, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->subscript.index, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_MEMBER:
|
||||
case SCC_AST_EXPR_PTR_MEMBER:
|
||||
dump_child_node((scc_ast_node_t *)expr->member.base, ctx, false);
|
||||
scc_vec_push(ctx->stack, true);
|
||||
scc_tree_print_indent(ctx);
|
||||
SCC_TREE_DUMP_PRINT_PURE(
|
||||
ctx, ctx->node_color, "%s %s\n",
|
||||
expr->base.type == SCC_AST_EXPR_MEMBER ? "Member" : "PtrMember",
|
||||
expr->member.name);
|
||||
(void)scc_vec_pop(ctx->stack);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->member.base, false);
|
||||
scc_tree_dump_push(td, true);
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(
|
||||
td, "%s",
|
||||
expr->base.type == SCC_AST_EXPR_MEMBER ? "Member" : "PtrMember");
|
||||
scc_tree_dump_value(td, " %s", expr->member.name);
|
||||
scc_tree_dump_pop(td);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_CAST:
|
||||
dump_child_node((scc_ast_node_t *)expr->cast.type, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)expr->cast.expr, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->cast.type, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->cast.expr, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_SIZE_OF:
|
||||
case SCC_AST_EXPR_ALIGN_OF:
|
||||
if (expr->attr_of.expr) {
|
||||
dump_child_node((scc_ast_node_t *)expr->attr_of.expr, ctx, true);
|
||||
} else if (expr->attr_of.type) {
|
||||
dump_child_node((scc_ast_node_t *)expr->attr_of.type, ctx, true);
|
||||
}
|
||||
if (expr->attr_of.expr)
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->attr_of.expr, true);
|
||||
else if (expr->attr_of.type)
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->attr_of.type, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_LVALUE:
|
||||
dump_child_node((scc_ast_node_t *)expr->lvalue.type, ctx, true);
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->lvalue.type, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_COMPOUND:;
|
||||
dump_child_node((scc_ast_node_t *)expr->compound.base, ctx, false);
|
||||
if (scc_vec_size(expr->compound.lhs_exprs) !=
|
||||
scc_vec_size(expr->compound.rhs_exprs)) {
|
||||
LOG_ERROR("compound expr lhs and rhs size not equal");
|
||||
break;
|
||||
}
|
||||
case SCC_AST_EXPR_COMPOUND:
|
||||
dump_child_node(td, (scc_ast_node_t *)expr->compound.base, false);
|
||||
{
|
||||
usize size = scc_vec_size(expr->compound.lhs_exprs);
|
||||
for (usize i = 0; i < size; i++) {
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(expr->compound.lhs_exprs, i), ctx,
|
||||
td,
|
||||
(scc_ast_node_t *)scc_vec_at(expr->compound.lhs_exprs, i),
|
||||
false);
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(expr->compound.rhs_exprs, i), ctx,
|
||||
td,
|
||||
(scc_ast_node_t *)scc_vec_at(expr->compound.rhs_exprs, i),
|
||||
i + 1 == size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_BUILTIN:
|
||||
// PRINT_QUOTED_VALUE(ctx, scc_ast_builtin_type_name(expr->builtin));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归转储语句
|
||||
static void dump_stmt_impl(scc_ast_stmt_t *stmt, scc_tree_dump_ctx_t *ctx) {
|
||||
static void dump_stmt_impl(scc_ast_stmt_t *stmt, scc_tree_dump_t *td) {
|
||||
if (!stmt)
|
||||
return;
|
||||
|
||||
start_node_dump(&stmt->base, ctx);
|
||||
// 根据语句类型输出特定信息
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "%s", get_node_type_str(stmt->base.type));
|
||||
|
||||
switch (stmt->base.type) {
|
||||
case SCC_AST_STMT_IF:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->if_stmt.cond, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)stmt->if_stmt.then_stmt, ctx,
|
||||
!stmt->if_stmt.opt_else_stmt);
|
||||
if (stmt->if_stmt.opt_else_stmt) {
|
||||
dump_child_node((scc_ast_node_t *)stmt->if_stmt.opt_else_stmt, ctx,
|
||||
true);
|
||||
}
|
||||
return;
|
||||
case SCC_AST_STMT_WHILE:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->while_stmt.cond, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)stmt->while_stmt.body, ctx, true);
|
||||
return;
|
||||
case SCC_AST_STMT_DO_WHILE:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->while_stmt.body, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)stmt->while_stmt.cond, ctx, true);
|
||||
return;
|
||||
case SCC_AST_STMT_SWITCH:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->switch_stmt.cond, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)stmt->switch_stmt.body, ctx, true);
|
||||
return;
|
||||
case SCC_AST_STMT_FOR:
|
||||
end_node_dump(ctx);
|
||||
if (stmt->for_stmt.init) {
|
||||
dump_child_node((scc_ast_node_t *)stmt->for_stmt.init, ctx, false);
|
||||
}
|
||||
if (stmt->for_stmt.cond) {
|
||||
dump_child_node((scc_ast_node_t *)stmt->for_stmt.cond, ctx, false);
|
||||
}
|
||||
if (stmt->for_stmt.incr) {
|
||||
dump_child_node((scc_ast_node_t *)stmt->for_stmt.incr, ctx, false);
|
||||
}
|
||||
dump_child_node((scc_ast_node_t *)stmt->for_stmt.body, ctx, true);
|
||||
return;
|
||||
case SCC_AST_STMT_RETURN:
|
||||
if (stmt->return_stmt.expr) {
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->return_stmt.expr, ctx,
|
||||
true);
|
||||
} else {
|
||||
end_node_dump(ctx);
|
||||
if (!stmt->return_stmt.expr) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->return_stmt.expr, true);
|
||||
return;
|
||||
case SCC_AST_STMT_GOTO:
|
||||
if (stmt->goto_stmt.label) {
|
||||
PRINT_VALUE(ctx, " Label: %s", stmt->goto_stmt.label);
|
||||
}
|
||||
end_node_dump(ctx);
|
||||
break;
|
||||
if (stmt->goto_stmt.label)
|
||||
scc_tree_dump_value(td, " Label: %s", stmt->goto_stmt.label);
|
||||
return;
|
||||
case SCC_AST_STMT_LABEL:
|
||||
if (stmt->label_stmt.label) {
|
||||
PRINT_VALUE(ctx, " %s", stmt->label_stmt.label);
|
||||
}
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->label_stmt.stmt, ctx, true);
|
||||
break;
|
||||
case SCC_AST_STMT_COMPOUND:
|
||||
end_node_dump(ctx);
|
||||
scc_vec_foreach(stmt->compound.block_items, i) {
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(stmt->compound.block_items, i),
|
||||
ctx, i + 1 == stmt->compound.block_items.size);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_STMT_EXPR:
|
||||
end_node_dump(ctx);
|
||||
if (stmt->expr.expr) {
|
||||
dump_child_node((scc_ast_node_t *)stmt->expr.expr, ctx, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_STMT_CASE:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->case_stmt.expr, ctx, false);
|
||||
dump_child_node((scc_ast_node_t *)stmt->case_stmt.stmt, ctx, true);
|
||||
break;
|
||||
|
||||
if (stmt->label_stmt.label)
|
||||
scc_tree_dump_value(td, " %s", stmt->label_stmt.label);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->label_stmt.stmt, true);
|
||||
return;
|
||||
case SCC_AST_STMT_BREAK:
|
||||
case SCC_AST_STMT_CONTINUE:
|
||||
end_node_dump(ctx);
|
||||
break;
|
||||
|
||||
return;
|
||||
case SCC_AST_STMT_DEFAULT:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->default_stmt.stmt, ctx, true);
|
||||
break;
|
||||
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->default_stmt.stmt, true);
|
||||
return;
|
||||
case SCC_AST_STMT_COMPOUND:
|
||||
scc_vec_foreach(stmt->compound.block_items, i) {
|
||||
dump_child_node(
|
||||
td, (scc_ast_node_t *)scc_vec_at(stmt->compound.block_items, i),
|
||||
i + 1 == stmt->compound.block_items.size);
|
||||
}
|
||||
return;
|
||||
case SCC_AST_STMT_EXPR:
|
||||
if (stmt->expr.expr)
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->expr.expr, true);
|
||||
return;
|
||||
case SCC_AST_STMT_IF:
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->if_stmt.cond, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->if_stmt.then_stmt,
|
||||
!stmt->if_stmt.opt_else_stmt);
|
||||
if (stmt->if_stmt.opt_else_stmt)
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->if_stmt.opt_else_stmt,
|
||||
true);
|
||||
return;
|
||||
case SCC_AST_STMT_WHILE:
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.cond, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.body, true);
|
||||
return;
|
||||
case SCC_AST_STMT_DO_WHILE:
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.body, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.cond, true);
|
||||
return;
|
||||
case SCC_AST_STMT_SWITCH:
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->switch_stmt.cond, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->switch_stmt.body, true);
|
||||
return;
|
||||
case SCC_AST_STMT_FOR:
|
||||
if (stmt->for_stmt.init)
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.init, false);
|
||||
if (stmt->for_stmt.cond)
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.cond, false);
|
||||
if (stmt->for_stmt.incr)
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.incr, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.body, true);
|
||||
return;
|
||||
case SCC_AST_STMT_CASE:
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->case_stmt.expr, false);
|
||||
dump_child_node(td, (scc_ast_node_t *)stmt->case_stmt.stmt, true);
|
||||
return;
|
||||
default:
|
||||
LOG_WARN("unknown node type %d", stmt->base.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归转储声明
|
||||
static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_ctx_t *ctx) {
|
||||
static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_t *td) {
|
||||
if (!decl)
|
||||
return;
|
||||
|
||||
start_node_dump(&decl->base, ctx);
|
||||
if (decl->name) {
|
||||
PRINT_QUOTED_VALUE(ctx, decl->name);
|
||||
}
|
||||
end_node_dump(ctx);
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "%s", get_node_type_str(decl->base.type));
|
||||
if (decl->name)
|
||||
scc_tree_dump_value(td, " '%s'", decl->name);
|
||||
|
||||
// 递归转储子节点
|
||||
switch (decl->base.type) {
|
||||
case SCC_AST_DECL_LIST:
|
||||
scc_vec_foreach(decl->list.vars, i) {
|
||||
dump_child_node((scc_ast_node_t *)scc_vec_at(decl->list.vars, i),
|
||||
ctx, i + 1 == scc_vec_size(decl->list.vars));
|
||||
dump_child_node(td,
|
||||
(scc_ast_node_t *)scc_vec_at(decl->list.vars, i),
|
||||
i + 1 == scc_vec_size(decl->list.vars));
|
||||
}
|
||||
break;
|
||||
case SCC_AST_DECL_VAR:
|
||||
if (decl->var.type) {
|
||||
dump_child_node((scc_ast_node_t *)decl->var.type, ctx,
|
||||
dump_child_node(td, (scc_ast_node_t *)decl->var.type,
|
||||
decl->var.init == NULL);
|
||||
if (decl->var.init) {
|
||||
dump_child_node((scc_ast_node_t *)decl->var.init, ctx, true);
|
||||
}
|
||||
if (decl->var.init)
|
||||
dump_child_node(td, (scc_ast_node_t *)decl->var.init, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_DECL_FUNC:
|
||||
if (decl->func.type) {
|
||||
dump_child_node((scc_ast_node_t *)decl->func.type, ctx,
|
||||
decl->func.body == null);
|
||||
if (decl->func.body) {
|
||||
dump_child_node((scc_ast_node_t *)decl->func.body, ctx, true);
|
||||
}
|
||||
dump_child_node(td, (scc_ast_node_t *)decl->func.type,
|
||||
decl->func.body == NULL);
|
||||
if (decl->func.body)
|
||||
dump_child_node(td, (scc_ast_node_t *)decl->func.body, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_DECL_PARAM:
|
||||
if (decl->param.type) {
|
||||
dump_child_node((scc_ast_node_t *)decl->param.type, ctx, true);
|
||||
}
|
||||
if (decl->param.type)
|
||||
dump_child_node(td, (scc_ast_node_t *)decl->param.type, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_DECL_STRUCT:
|
||||
case SCC_AST_DECL_UNION:
|
||||
case SCC_AST_DECL_ENUM:
|
||||
scc_vec_foreach(decl->record.fields, i) {
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(decl->record.fields, i), ctx,
|
||||
td, (scc_ast_node_t *)scc_vec_at(decl->record.fields, i),
|
||||
i + 1 == scc_vec_size(decl->record.fields));
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_DECL_TYPEDEF:
|
||||
if (decl->typedef_decl.type) {
|
||||
dump_child_node((scc_ast_node_t *)decl->typedef_decl.type, ctx,
|
||||
if (decl->typedef_decl.type)
|
||||
dump_child_node(td, (scc_ast_node_t *)decl->typedef_decl.type,
|
||||
true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归转储翻译单元
|
||||
static void dump_unit_impl(scc_ast_translation_unit_t *unit,
|
||||
scc_tree_dump_ctx_t *ctx) {
|
||||
scc_tree_dump_t *td) {
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
start_node_dump(&unit->base, ctx);
|
||||
end_node_dump(ctx);
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "%s", get_node_type_str(unit->base.type));
|
||||
scc_vec_foreach(unit->declarations, i) {
|
||||
dump_child_node((scc_ast_node_t *)scc_vec_at(unit->declarations, i),
|
||||
ctx, i + 1 == scc_vec_size(unit->declarations));
|
||||
dump_child_node(td, (scc_ast_node_t *)scc_vec_at(unit->declarations, i),
|
||||
i + 1 == scc_vec_size(unit->declarations));
|
||||
}
|
||||
}
|
||||
|
||||
void scc_ast_dump_node(scc_tree_dump_ctx_t *ctx, const scc_ast_node_t *node) {
|
||||
void scc_ast_dump_node(scc_tree_dump_t *td, const scc_ast_node_t *node) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (SCC_AST_IS_A(scc_ast_expr_t, node)) {
|
||||
dump_expr_impl(SCC_AST_CAST_TO(scc_ast_expr_t, node), ctx);
|
||||
} else if (SCC_AST_IS_A(scc_ast_stmt_t, node)) {
|
||||
dump_stmt_impl(SCC_AST_CAST_TO(scc_ast_stmt_t, node), ctx);
|
||||
} else if (SCC_AST_IS_A(scc_ast_decl_t, node)) {
|
||||
dump_decl_impl(SCC_AST_CAST_TO(scc_ast_decl_t, node), ctx);
|
||||
} else if (SCC_AST_IS_A(scc_ast_type_t, node)) {
|
||||
dump_type_impl(SCC_AST_CAST_TO(scc_ast_type_t, node), ctx);
|
||||
} else if (SCC_AST_IS_A(scc_ast_translation_unit_t, node)) {
|
||||
dump_unit_impl(SCC_AST_CAST_TO(scc_ast_translation_unit_t, node), ctx);
|
||||
}
|
||||
if (SCC_AST_IS_A(scc_ast_expr_t, node))
|
||||
dump_expr_impl(SCC_AST_CAST_TO(scc_ast_expr_t, node), td);
|
||||
else if (SCC_AST_IS_A(scc_ast_stmt_t, node))
|
||||
dump_stmt_impl(SCC_AST_CAST_TO(scc_ast_stmt_t, node), td);
|
||||
else if (SCC_AST_IS_A(scc_ast_decl_t, node))
|
||||
dump_decl_impl(SCC_AST_CAST_TO(scc_ast_decl_t, node), td);
|
||||
else if (SCC_AST_IS_A(scc_ast_type_t, node))
|
||||
dump_type_impl(SCC_AST_CAST_TO(scc_ast_type_t, node), td);
|
||||
else if (SCC_AST_IS_A(scc_ast_translation_unit_t, node))
|
||||
dump_unit_impl(SCC_AST_CAST_TO(scc_ast_translation_unit_t, node), td);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,92 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
return scc_ir_builder_type(&ctx->builder, &ir_type);
|
||||
}
|
||||
|
||||
scc_ir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
||||
scc_ast_expr_t *expr,
|
||||
scc_ir_value_ref_t lhs,
|
||||
scc_ir_value_ref_t rhs) {
|
||||
scc_ir_bblock_ref_t start_block =
|
||||
scc_ir_builder_current_bblock(&ctx->builder);
|
||||
|
||||
scc_ir_bblock_ref_t right_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "logic_right");
|
||||
scc_ir_bblock_ref_t end_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "logic_end");
|
||||
|
||||
// 为结果创建临时存储空间
|
||||
scc_ir_type_ref_t int32_type = scc_ir_builder_type_i32(&ctx->builder);
|
||||
scc_ir_value_ref_t result_var =
|
||||
scc_ir_builder_alloca(&ctx->builder, int32_type, "logic_result");
|
||||
|
||||
// 计算左操作数
|
||||
scc_ir_value_ref_t left_val = scc_ast2ir_expr(ctx, expr->binary.lhs, false);
|
||||
scc_ir_value_ref_t zero_val = scc_ir_builder_const_int(
|
||||
&ctx->builder, int32_type, (scc_ir_const_int_t){.int32 = 0});
|
||||
scc_ir_value_ref_t one_val = scc_ir_builder_const_int(
|
||||
&ctx->builder, int32_type, (scc_ir_const_int_t){.int32 = 1});
|
||||
|
||||
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND) {
|
||||
// a && b
|
||||
scc_ir_bblock_ref_t false_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "and_false");
|
||||
|
||||
// 如果左操作数为0,结果为0(短路)
|
||||
scc_ir_value_ref_t is_left_zero = scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_EQ, left_val, zero_val);
|
||||
scc_ir_builder_branch(&ctx->builder, is_left_zero, false_block,
|
||||
right_block);
|
||||
|
||||
// false_block: 左边为0,结果为0
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, false_block);
|
||||
scc_ir_builder_store(&ctx->builder, result_var, zero_val);
|
||||
scc_ir_builder_jump(&ctx->builder, end_block);
|
||||
|
||||
// right_block: 左边非0,计算右边
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, right_block);
|
||||
scc_ir_value_ref_t right_val =
|
||||
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
||||
scc_ir_value_ref_t is_right_zero = scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_EQ, right_val, zero_val);
|
||||
scc_ir_value_ref_t result =
|
||||
scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_XOR, is_right_zero,
|
||||
one_val); // !right == 0 ? 1 : 0
|
||||
scc_ir_builder_store(&ctx->builder, result_var, result);
|
||||
scc_ir_builder_jump(&ctx->builder, end_block);
|
||||
|
||||
} else { // SCC_AST_OP_LOGICAL_OR
|
||||
// a || b
|
||||
scc_ir_bblock_ref_t true_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "or_true");
|
||||
|
||||
// 如果左操作数非0,结果为1(短路)
|
||||
scc_ir_value_ref_t is_left_nonzero = scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_NEQ, left_val, zero_val);
|
||||
scc_ir_builder_branch(&ctx->builder, is_left_nonzero, true_block,
|
||||
right_block);
|
||||
|
||||
// true_block: 左边非0,结果为1
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, true_block);
|
||||
scc_ir_builder_store(&ctx->builder, result_var, one_val);
|
||||
scc_ir_builder_jump(&ctx->builder, end_block);
|
||||
|
||||
// right_block: 左边为0,计算右边
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, right_block);
|
||||
scc_ir_value_ref_t right_val =
|
||||
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
||||
scc_ir_value_ref_t is_right_zero = scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_EQ, right_val, zero_val);
|
||||
scc_ir_value_ref_t result =
|
||||
scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_XOR, is_right_zero,
|
||||
one_val); // !right == 0 ? 1 : 0
|
||||
scc_ir_builder_store(&ctx->builder, result_var, result);
|
||||
scc_ir_builder_jump(&ctx->builder, end_block);
|
||||
}
|
||||
|
||||
// 设置结束块为当前块,并返回结果
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, end_block);
|
||||
return scc_ir_builder_load(&ctx->builder, result_var);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
@@ -218,7 +304,7 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
/* 逻辑操作符 */
|
||||
case SCC_AST_OP_LOGICAL_OR: // ||
|
||||
case SCC_AST_OP_LOGICAL_AND: // &&
|
||||
TODO();
|
||||
return scc_ast2ir_logical_expr(ctx, expr, lhs, rhs);
|
||||
/* clang-format on */
|
||||
default:
|
||||
LOG_FATAL("Unsupported binary operator: %d", expr->binary.op);
|
||||
@@ -243,6 +329,9 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
// SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
|
||||
// SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
|
||||
switch (expr->unary.op) {
|
||||
case SCC_AST_OP_UNARY_PLUS:
|
||||
/* just pass */
|
||||
return operand;
|
||||
case SCC_AST_OP_UNARY_MINUS: {
|
||||
// 负号
|
||||
// 实现为0 - operand
|
||||
@@ -254,6 +343,28 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_SUB, zero_ref,
|
||||
operand);
|
||||
}
|
||||
case SCC_AST_OP_ADDRESS_OF:
|
||||
// 取地址
|
||||
operand =
|
||||
scc_ir_builder_get_ptr(&ctx->builder, operand, SCC_IR_REF_NULL);
|
||||
Assert(operand != SCC_IR_REF_NULL);
|
||||
return operand;
|
||||
case SCC_AST_OP_INDIRECTION:
|
||||
// 从地址取值
|
||||
// FIXME
|
||||
scc_ir_value_t *value =
|
||||
scc_ir_module_get_value(ctx->builder.ctx.module, operand);
|
||||
Assert(value != null);
|
||||
scc_ir_type_t *type =
|
||||
scc_ir_module_get_type(ctx->builder.ctx.module, value->type);
|
||||
Assert(type != null);
|
||||
if (type->tag != SCC_IR_TYPE_PTR) {
|
||||
LOG_FATAL("Invalid type: %d", type->tag);
|
||||
}
|
||||
|
||||
operand = scc_ir_builder_load(&ctx->builder, operand);
|
||||
Assert(operand != SCC_IR_REF_NULL);
|
||||
return operand;
|
||||
case SCC_AST_OP_BITWISE_NOT:
|
||||
// 按位取反
|
||||
return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_NOT, operand,
|
||||
@@ -327,9 +438,37 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
return scc_ir_builder_const_int(&ctx->builder, type_ref, value);
|
||||
}
|
||||
|
||||
// SCC_AST_EXPR_INT_LITERAL, // 整数字面量
|
||||
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
|
||||
// SCC_AST_EXPR_CHAR_LITERAL, // 字符字面量
|
||||
case SCC_AST_EXPR_CHAR_LITERAL: {
|
||||
// FIXME just 'a' '\n'
|
||||
scc_ir_type_ref_t type_ref = scc_ir_builder_type_i32(&ctx->builder);
|
||||
const char *lexme = expr->literal.lexme;
|
||||
Assert(lexme[0] == '\'');
|
||||
u8 int_lit = 0;
|
||||
if (lexme[1] == '\\') {
|
||||
switch (lexme[2]) {
|
||||
case 'a':
|
||||
int_lit = '\a';
|
||||
break;
|
||||
case 'b':
|
||||
int_lit = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
int_lit = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
int_lit = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
int_lit = '\r';
|
||||
}
|
||||
} else {
|
||||
int_lit = lexme[1];
|
||||
}
|
||||
scc_ir_const_int_t value;
|
||||
value.int32 = int_lit;
|
||||
return scc_ir_builder_const_int(&ctx->builder, type_ref, value);
|
||||
}
|
||||
case SCC_AST_EXPR_STRING_LITERAL: {
|
||||
// FIXME
|
||||
scc_ir_builder_const_string(&ctx->builder, expr->literal.lexme,
|
||||
|
||||
@@ -86,7 +86,7 @@ scc_ir_builder_const_string(scc_ir_builder_t *builder, const char *str,
|
||||
scc_ir_type_t array_type = {
|
||||
.tag = SCC_IR_TYPE_ARRAY,
|
||||
.data.array.base = u8_type,
|
||||
.data.array.len = len + 1, // 包含 null 结尾
|
||||
.data.array.len = len - 1, // 包含 null 结尾
|
||||
};
|
||||
scc_ir_type_ref_t array_type_ref =
|
||||
scc_ir_ctx_get_type(&builder->ctx, &array_type);
|
||||
@@ -103,14 +103,15 @@ scc_ir_builder_const_string(scc_ir_builder_t *builder, const char *str,
|
||||
.type = array_type_ref,
|
||||
.data.const_array.base_type = u8_type,
|
||||
};
|
||||
char *buff = scc_malloc(len + 1);
|
||||
char *buff = scc_malloc(len - 1);
|
||||
Assert(buff);
|
||||
for (usize i = 0; i < len; i++) {
|
||||
buff[i] = str[i];
|
||||
// FIXME content to real string
|
||||
for (usize i = 1; i < len - 1; i++) {
|
||||
buff[i - 1] = str[i];
|
||||
}
|
||||
buff[len] = '\0';
|
||||
buff[len - 2] = '\0';
|
||||
scc_vec_unsafe_from_buffer(const_array_value.data.const_array.elements,
|
||||
buff, len + 1);
|
||||
buff, len - 1);
|
||||
scc_ir_value_ref_t const_array_ref =
|
||||
scc_ir_module_add_value(builder->ctx.module, &const_array_value);
|
||||
Assert(const_array_ref != SCC_IR_REF_NULL);
|
||||
@@ -182,6 +183,7 @@ scc_ir_bblock_ref_t scc_ir_builder_begin_bblock(scc_ir_builder_t *builder,
|
||||
*/
|
||||
void scc_ir_builder_end_bblock(scc_ir_builder_t *builder);
|
||||
|
||||
scc_ir_func_ref_t scc_ir_builder_current_bblock(scc_ir_builder_t *builder);
|
||||
/**
|
||||
* @brief 设置当前基本块
|
||||
*/
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
#define __SCC_IR_DUMP_H__
|
||||
|
||||
#include "ir_prog.h"
|
||||
#include <tree_dump.h>
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
typedef struct {
|
||||
scc_ir_cprog_t *cprog;
|
||||
scc_tree_dump_ctx_t *dump_ctx;
|
||||
scc_tree_dump_t *dump_ctx;
|
||||
} scc_ir_dump_ctx_t;
|
||||
|
||||
void scc_ir_dump_ctx_init(scc_ir_dump_ctx_t *ctx,
|
||||
scc_tree_dump_ctx_t *tree_dump,
|
||||
void scc_ir_dump_ctx_init(scc_ir_dump_ctx_t *ctx, scc_tree_dump_t *tree_dump,
|
||||
scc_ir_cprog_t *cprog);
|
||||
void scc_ir_dump_value(scc_ir_dump_ctx_t *ctx, scc_ir_value_ref_t node_ref);
|
||||
void scc_ir_dump_type(scc_ir_dump_ctx_t *ctx, scc_ir_type_ref_t type_ref);
|
||||
|
||||
@@ -39,4 +39,11 @@ scc_ir_bblock_t *scc_ir_module_get_bblock(scc_ir_module_t *ctx,
|
||||
scc_ir_func_t *scc_ir_module_get_func(scc_ir_module_t *ctx,
|
||||
scc_ir_func_ref_t ref);
|
||||
|
||||
static inline scc_ir_type_t *
|
||||
scc_ir_module_get_type_by_value(scc_ir_module_t *ctx, scc_ir_value_ref_t ref) {
|
||||
scc_ir_value_t *value = scc_ir_module_get_value(ctx, ref);
|
||||
Assert(value != null);
|
||||
return scc_ir_module_get_type(ctx, value->type);
|
||||
}
|
||||
|
||||
#endif /* __SCC_IR_MODULE_H__ */
|
||||
|
||||
@@ -129,6 +129,10 @@ void scc_ir_builder_set_current_bblock(scc_ir_builder_t *builder,
|
||||
builder->current_bblock = bblock;
|
||||
}
|
||||
|
||||
scc_ir_func_ref_t scc_ir_builder_current_bblock(scc_ir_builder_t *builder) {
|
||||
return builder->current_bblock;
|
||||
}
|
||||
|
||||
void scc_ir_builder_add_instr(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t instr) {
|
||||
scc_ir_bblock_t *current_bblock =
|
||||
@@ -205,6 +209,7 @@ scc_ir_value_ref_t scc_ir_builder_load(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t scc_ir_builder_store(scc_ir_builder_t *builder,
|
||||
scc_ir_value_ref_t target,
|
||||
scc_ir_value_ref_t value) {
|
||||
Assert(target != SCC_IR_REF_NULL && value != SCC_IR_REF_NULL);
|
||||
scc_ir_value_t store_node = {0};
|
||||
store_node.tag = SCC_IR_VALUE_TAG_STORE;
|
||||
store_node.data.store.target = target;
|
||||
|
||||
@@ -112,7 +112,7 @@ static int cmp_type(const void *_key1, const void *_key2) {
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
Panic("Unknown key type %d", key1->tag);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ typedef enum {
|
||||
SCC_REG_KIND_GPR, ///< 通用寄存器(整数)
|
||||
SCC_REG_KIND_FPR, ///< 浮点数寄存器
|
||||
SCC_REG_KIND_STACK, ///< 栈
|
||||
SCC_REG_KIND_STACK_ADDR, ///< 栈地址(如 alloc 节点)
|
||||
SCC_REG_KIND_IMM, ///< 整数立即数
|
||||
SCC_REG_KIND_IMM_FP, ///< 浮点数常量
|
||||
} scc_reg_kind_t;
|
||||
|
||||
@@ -5,6 +5,24 @@
|
||||
|
||||
#define GET_MODULE(ctx) (&(ctx->cprog->module))
|
||||
|
||||
static int scc_type_width(scc_ir_type_t *type) {
|
||||
/* clang-format off */
|
||||
switch (type->tag) {
|
||||
case SCC_IR_TYPE_i8: case SCC_IR_TYPE_u8: return 1;
|
||||
case SCC_IR_TYPE_i16: case SCC_IR_TYPE_u16: return 2;
|
||||
case SCC_IR_TYPE_i32: case SCC_IR_TYPE_u32: return 4;
|
||||
case SCC_IR_TYPE_i64: case SCC_IR_TYPE_u64: return 8;
|
||||
case SCC_IR_TYPE_PTR: return 8;
|
||||
default: return 8; // 默认64位
|
||||
}
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
static bool scc_type_is_signed(scc_ir_type_t *type) {
|
||||
return (type->tag == SCC_IR_TYPE_i8 || type->tag == SCC_IR_TYPE_i16 ||
|
||||
type->tag == SCC_IR_TYPE_i32 || type->tag == SCC_IR_TYPE_i64);
|
||||
}
|
||||
|
||||
static void parse_location(scc_ir2mcode_ctx_t *ctx, scc_reg_loc_t *loc,
|
||||
scc_ir_value_ref_t node_ref) {
|
||||
Assert(ctx != null && loc != null);
|
||||
@@ -40,11 +58,12 @@ static void parse_location(scc_ir2mcode_ctx_t *ctx, scc_reg_loc_t *loc,
|
||||
scc_reg_loc_t arg_loc;
|
||||
// arg_loc.kind = SCC_REG_KIND_FUNC_ARG;
|
||||
// arg_loc.idx = node->data.arg_ref.idx;
|
||||
arg_loc.kind = SCC_REG_KIND_STACK;
|
||||
arg_loc.kind = SCC_REG_KIND_STACK_ADDR;
|
||||
arg_loc.idx = 8 * node->data.arg_ref.idx;
|
||||
*loc = arg_loc;
|
||||
return;
|
||||
}
|
||||
case SCC_IR_VALUE_TAG_ALLOC:
|
||||
default:
|
||||
idx = (usize)scc_hashtable_get(ctx->noderef2regloc,
|
||||
(void *)(usize)node_ref);
|
||||
@@ -72,6 +91,12 @@ static void load_value_to_reg(scc_mcode_t *mcode, scc_reg_loc_t *loc, int reg) {
|
||||
case SCC_REG_KIND_IMM:
|
||||
scc_mcode_amd64_mov_r64_imm64(mcode, reg, loc->idx); // 或 imm32
|
||||
break;
|
||||
case SCC_REG_KIND_STACK_ADDR:
|
||||
// 将栈地址加载到寄存器(取地址)
|
||||
// FIXME -8 for rdp
|
||||
scc_mcode_amd64_lea_r64_m64_disp32(mcode, reg, SCC_AMD64_RBP,
|
||||
-loc->idx - 8);
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("unsupported location");
|
||||
}
|
||||
@@ -93,6 +118,12 @@ static void store_value_from_reg(scc_mcode_t *mcode, scc_reg_loc_t *loc,
|
||||
case SCC_REG_KIND_IMM:
|
||||
LOG_FATAL("cannot store to immediate");
|
||||
break;
|
||||
case SCC_REG_KIND_STACK_ADDR:
|
||||
// 将寄存器的值存储到栈地址
|
||||
// FIXME -8 for rdp
|
||||
scc_mcode_amd64_mov_m64_disp32_r64(mcode, SCC_AMD64_RBP, -loc->idx - 8,
|
||||
reg);
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("unsupported location");
|
||||
break;
|
||||
@@ -123,8 +154,9 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
///< ABI
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_BLOCK_ARG_REF: ///< 基本块参数引用
|
||||
break;
|
||||
case SCC_IR_VALUE_TAG_ALLOC: ///< 分配内存(stack)
|
||||
case SCC_IR_VALUE_TAG_GLOBAL_ALLOC: ///< 全局分配(bss)
|
||||
case SCC_IR_VALUE_TAG_GLOBAL_ALLOC: ///< 全局分配(bss
|
||||
break;
|
||||
///< 加载数据
|
||||
case SCC_IR_VALUE_TAG_LOAD: {
|
||||
@@ -133,18 +165,79 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
scc_reg_loc_t to;
|
||||
parse_location(ctx, &from, node->data.load.target);
|
||||
parse_location(ctx, &to, node_ref);
|
||||
load_value_to_reg(&ctx->sect_mcode, &from, SCC_AMD64_RAX);
|
||||
|
||||
load_value_to_reg(&ctx->sect_mcode, &from, SCC_AMD64_RCX);
|
||||
// 获取基类型宽度
|
||||
scc_ir_type_t *ptr_type = scc_ir_module_get_type_by_value(
|
||||
GET_MODULE(ctx), node->data.load.target);
|
||||
scc_ir_type_t *base_type = scc_ir_module_get_type(
|
||||
GET_MODULE(ctx), ptr_type->data.pointer.base);
|
||||
int width = scc_type_width(base_type);
|
||||
bool is_signed = scc_type_is_signed(base_type);
|
||||
|
||||
// 间接加载到 RAX
|
||||
if (width == 1) {
|
||||
if (is_signed)
|
||||
scc_mcode_amd64_movsx_r64_m8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
else
|
||||
scc_mcode_amd64_movzx_r64_m8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
} else if (width == 2) {
|
||||
if (is_signed)
|
||||
scc_mcode_amd64_movsx_r64_m16(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
else
|
||||
scc_mcode_amd64_movzx_r64_m16(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
} else if (width == 4) {
|
||||
if (is_signed)
|
||||
scc_mcode_amd64_movsx_r64_m32(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
else
|
||||
scc_mcode_amd64_mov_r32_m32(
|
||||
&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX); // 32位加载自动清零高位
|
||||
} else { // 8
|
||||
scc_mcode_amd64_mov_r64_m64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
}
|
||||
// 存储结果
|
||||
store_value_from_reg(&ctx->sect_mcode, &to, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
///< 存储数据
|
||||
case SCC_IR_VALUE_TAG_STORE: {
|
||||
scc_reg_loc_t from;
|
||||
scc_reg_loc_t to;
|
||||
parse_location(ctx, &from, node->data.store.value);
|
||||
parse_location(ctx, &to, node->data.store.target);
|
||||
load_value_to_reg(&ctx->sect_mcode, &from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &to, SCC_AMD64_RAX);
|
||||
scc_reg_loc_t val_loc, addr_loc;
|
||||
parse_location(ctx, &val_loc, node->data.store.value);
|
||||
parse_location(ctx, &addr_loc, node->data.store.target);
|
||||
|
||||
// 将值加载到 RAX
|
||||
load_value_to_reg(&ctx->sect_mcode, &val_loc, SCC_AMD64_RAX);
|
||||
// 将目标地址加载到 RCX
|
||||
load_value_to_reg(&ctx->sect_mcode, &addr_loc, SCC_AMD64_RCX);
|
||||
|
||||
// 获取目标指针的基类型宽度
|
||||
scc_ir_type_t *ptr_type = scc_ir_module_get_type_by_value(
|
||||
GET_MODULE(ctx), node->data.store.target);
|
||||
scc_ir_type_t *base_type = scc_ir_module_get_type(
|
||||
GET_MODULE(ctx), ptr_type->data.pointer.base);
|
||||
int width = scc_type_width(base_type);
|
||||
|
||||
// 根据宽度生成存储指令
|
||||
if (width == 1) {
|
||||
scc_mcode_amd64_mov_m8_r8(&ctx->sect_mcode, SCC_AMD64_RCX,
|
||||
SCC_AMD64_RAX);
|
||||
} else if (width == 2) {
|
||||
scc_mcode_amd64_mov_m16_r16(&ctx->sect_mcode, SCC_AMD64_RCX,
|
||||
SCC_AMD64_RAX);
|
||||
} else if (width == 4) {
|
||||
scc_mcode_amd64_mov_m32_r32(&ctx->sect_mcode, SCC_AMD64_RCX,
|
||||
SCC_AMD64_RAX);
|
||||
} else { // width == 8
|
||||
scc_mcode_amd64_mov_m64_r64(&ctx->sect_mcode, SCC_AMD64_RCX,
|
||||
SCC_AMD64_RAX);
|
||||
}
|
||||
break;
|
||||
}
|
||||
///< 获取指针
|
||||
@@ -189,6 +282,9 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
// 将右操作数加载到 RCX
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc_rhs, SCC_AMD64_RCX);
|
||||
switch (node->data.op.op) {
|
||||
case SCC_IR_OP_EMPTY:
|
||||
Panic("unsupported empty op");
|
||||
break;
|
||||
case SCC_IR_OP_ADD:
|
||||
scc_mcode_amd64_add_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
@@ -200,16 +296,30 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
case SCC_IR_OP_MUL:
|
||||
scc_mcode_amd64_mul_r64(&ctx->sect_mcode, SCC_AMD64_RCX);
|
||||
break;
|
||||
// [SCC_IR_OP_EMPTY] = "empty", [SCC_IR_OP_NEQ] = "!=",
|
||||
// [SCC_IR_OP_EQ] = "==", [SCC_IR_OP_GT] = ">",
|
||||
// [SCC_IR_OP_LT] = "<", [SCC_IR_OP_GE] = ">=",
|
||||
// [SCC_IR_OP_LE] = "<=", [SCC_IR_OP_ADD] = "+",
|
||||
// [SCC_IR_OP_SUB] = "-", [SCC_IR_OP_MUL] = "*",
|
||||
// [SCC_IR_OP_DIV] = "/", [SCC_IR_OP_MOD] = "%",
|
||||
// [SCC_IR_OP_AND] = "&", [SCC_IR_OP_OR] = "|",
|
||||
// [SCC_IR_OP_XOR] = "^", [SCC_IR_OP_NOT] = "~",
|
||||
// [SCC_IR_OP_SHL] = "<<", [SCC_IR_OP_SHR] = ">>",
|
||||
// [SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right
|
||||
case SCC_IR_OP_DIV:
|
||||
case SCC_IR_OP_MOD:
|
||||
TODO();
|
||||
break;
|
||||
case SCC_IR_OP_AND:
|
||||
scc_mcode_amd64_and_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_OR:
|
||||
scc_mcode_amd64_or_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_XOR:
|
||||
scc_mcode_amd64_xor_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_NOT:
|
||||
scc_mcode_amd64_not_r64(&ctx->sect_mcode, SCC_AMD64_RAX);
|
||||
break;
|
||||
case SCC_IR_OP_SHL:
|
||||
case SCC_IR_OP_SHR:
|
||||
case SCC_IR_OP_SAR:
|
||||
TODO();
|
||||
break;
|
||||
case SCC_IR_OP_NEQ:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
@@ -329,7 +439,12 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME hack func value
|
||||
if (scc_vec_size(func->bblocks)) {
|
||||
scc_mcode_amd64_call_rel32(&ctx->sect_mcode, 0);
|
||||
} else {
|
||||
scc_mcode_amd64_call_mem_rip_rel32(&ctx->sect_mcode, 0);
|
||||
}
|
||||
usize sym_idx = sccf_builder_get_symbol_idx(ctx->builder, func->name);
|
||||
Assert(sym_idx != 0);
|
||||
sccf_builder_add_reloc(
|
||||
|
||||
@@ -49,8 +49,7 @@ scc_hashtable_t *scc_reg_alloc_with_stack(scc_reg_alloc_t *ctx,
|
||||
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_ALLOC: {
|
||||
case SCC_IR_VALUE_TAG_GET_ELEM_PTR: {
|
||||
loc.kind = SCC_REG_KIND_STACK;
|
||||
loc.idx = ctx->alloc_stack_size;
|
||||
|
||||
@@ -61,6 +60,20 @@ scc_hashtable_t *scc_reg_alloc_with_stack(scc_reg_alloc_t *ctx,
|
||||
(void *)scc_vec_size(ctx->reg_loc_vec));
|
||||
break;
|
||||
}
|
||||
case SCC_IR_VALUE_TAG_ALLOC: {
|
||||
// 为 alloc 分配栈偏移,但不作为普通值存储
|
||||
loc.kind =
|
||||
SCC_REG_KIND_STACK_ADDR; // 实际不需要存储到 reg_loc_vec
|
||||
loc.idx = ctx->alloc_stack_size;
|
||||
ctx->alloc_stack_size += 8; // 根据类型大小调整
|
||||
|
||||
// 记录偏移
|
||||
scc_vec_push(ctx->reg_loc_vec, loc);
|
||||
scc_hashtable_set(&ctx->node_ref2reg_loc,
|
||||
(void *)(usize)node_ref,
|
||||
(void *)scc_vec_size(ctx->reg_loc_vec));
|
||||
break;
|
||||
}
|
||||
case SCC_IR_VALUE_TAG_CALL: {
|
||||
// 处理返回值
|
||||
scc_ir_type_t *func_type =
|
||||
|
||||
@@ -185,7 +185,7 @@ typedef enum scc_tok_subtype {
|
||||
*/
|
||||
struct scc_lexer_token {
|
||||
scc_tok_type_t type;
|
||||
scc_cstring_t lexeme;
|
||||
scc_str_t lexeme;
|
||||
scc_pos_t loc;
|
||||
};
|
||||
|
||||
@@ -199,7 +199,7 @@ static inline void scc_lexer_tok_drop(scc_lexer_tok_t *tok) {
|
||||
tok->loc.line = 0;
|
||||
tok->loc.name = null;
|
||||
tok->loc.offset = 0;
|
||||
scc_cstring_free(&tok->lexeme);
|
||||
scc_str_drop(&tok->lexeme);
|
||||
}
|
||||
|
||||
static inline cbool scc_lexer_tok_match(const scc_lexer_tok_t *tok,
|
||||
@@ -211,7 +211,7 @@ static inline cbool scc_lexer_tok_match(const scc_lexer_tok_t *tok,
|
||||
static inline scc_lexer_tok_t scc_lexer_tok_copy(const scc_lexer_tok_t *src) {
|
||||
Assert(src != null);
|
||||
scc_lexer_tok_t dst = *src;
|
||||
dst.lexeme = scc_cstring_copy(&src->lexeme);
|
||||
dst.lexeme = scc_str_copy(&src->lexeme);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
static inline void scc_lexer_gen_number_true(scc_lexer_tok_t *tok) {
|
||||
Assert(tok != null && tok->type == SCC_TOK_UNKNOWN);
|
||||
tok->type = SCC_TOK_INT_LITERAL;
|
||||
tok->lexeme = scc_cstring_from_cstr("1");
|
||||
tok->lexeme = scc_str_from_cstr("1");
|
||||
}
|
||||
|
||||
static inline void scc_lexer_gen_number_false(scc_lexer_tok_t *tok) {
|
||||
Assert(tok != null && tok->type == SCC_TOK_UNKNOWN);
|
||||
tok->type = SCC_TOK_INT_LITERAL;
|
||||
tok->lexeme = scc_cstring_from_cstr("0");
|
||||
tok->lexeme = scc_str_from_cstr("0");
|
||||
}
|
||||
|
||||
static inline cbool scc_lexer_peek_non_blank(scc_lexer_tok_ring_t *stream,
|
||||
|
||||
@@ -74,13 +74,13 @@ static inline cbool peek_char(scc_lexer_t *lexer, scc_sstream_char_t *out) {
|
||||
}
|
||||
|
||||
/* 从环形缓冲区消费一个字符,并将它追加到lexeme中 */
|
||||
static inline cbool next_char(scc_lexer_t *lexer, scc_cstring_t *lexeme,
|
||||
static inline cbool next_char(scc_lexer_t *lexer, scc_str_t *lexeme,
|
||||
scc_sstream_char_t *out) {
|
||||
cbool ok;
|
||||
scc_ring_next(*lexer->stream_ref, *out, ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
scc_cstring_append_ch(lexeme, out->character);
|
||||
scc_str_append_ch(lexeme, out->character);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ static inline cbool next_char(scc_lexer_t *lexer, scc_cstring_t *lexeme,
|
||||
|
||||
void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
|
||||
scc_sstream_char_t cur = {0};
|
||||
scc_cstring_t lex = scc_cstring_create(); // 临时lexeme
|
||||
scc_str_t lex = scc_str_empty(); // 临时lexeme
|
||||
|
||||
// 尝试预览第一个字符
|
||||
if (!peek_char(lexer, &cur)) {
|
||||
@@ -165,7 +165,7 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
|
||||
scc_ring_consume(*lexer->stream_ref);
|
||||
}
|
||||
// 检查是否为关键字
|
||||
int idx = keyword_cmp(scc_cstring_as_cstr(&lex), scc_cstring_len(&lex));
|
||||
int idx = keyword_cmp(scc_str_as_cstr(&lex), scc_str_len(&lex));
|
||||
if (idx != -1) {
|
||||
token->type = keywords[idx].tok_type;
|
||||
}
|
||||
@@ -478,8 +478,8 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
|
||||
token->loc = start_loc;
|
||||
token->lexeme = lex; // 转移所有权
|
||||
LEX_DEBUG("get token `%s` (%s) at %s:%d:%d", scc_get_tok_name(token->type),
|
||||
scc_cstring_as_cstr(&token->lexeme), token->loc.name,
|
||||
token->loc.line, token->loc.col);
|
||||
scc_str_as_cstr(&token->lexeme), token->loc.name, token->loc.line,
|
||||
token->loc.col);
|
||||
}
|
||||
|
||||
// scc_lexer_get_token maybe got invalid (with parser)
|
||||
|
||||
@@ -58,10 +58,9 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
LOG_INFO("get token [%-8s] `%s` at %s:%d:%d",
|
||||
scc_get_tok_name(token.type),
|
||||
scc_cstring_as_cstr(&token.lexeme), token.loc.name,
|
||||
token.loc.line, token.loc.col);
|
||||
scc_cstring_free(&token.lexeme);
|
||||
scc_get_tok_name(token.type), scc_str_as_cstr(&token.lexeme),
|
||||
token.loc.name, token.loc.line, token.loc.col);
|
||||
scc_str_drop(&token.lexeme);
|
||||
}
|
||||
scc_sstream_drop_ring(ref);
|
||||
scc_sstream_drop(&stream);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <utest/acutest.h>
|
||||
|
||||
// 辅助函数:释放 token 的 lexeme
|
||||
static void free_token(scc_lexer_tok_t *tok) { scc_cstring_free(&tok->lexeme); }
|
||||
static void free_token(scc_lexer_tok_t *tok) { scc_str_drop(&tok->lexeme); }
|
||||
|
||||
// 单 token 测试宏(检查类型)
|
||||
#define TEST_TOKEN(input, expected_type) \
|
||||
@@ -18,12 +18,11 @@ static void free_token(scc_lexer_tok_t *tok) { scc_cstring_free(&tok->lexeme); }
|
||||
scc_lexer_get_token(&lexer, &token); \
|
||||
\
|
||||
TEST_CHECK(token.type == expected_type && \
|
||||
scc_strcmp(input, scc_cstring_as_cstr(&token.lexeme)) == \
|
||||
0); \
|
||||
scc_strcmp(input, scc_str_as_cstr(&token.lexeme)) == 0); \
|
||||
TEST_MSG("Input: '%s'", input); \
|
||||
TEST_MSG("Expected: %s `%s`", scc_get_tok_name(expected_type), input); \
|
||||
TEST_MSG("Got: %s `%s`", scc_get_tok_name(token.type), \
|
||||
scc_cstring_as_cstr(&token.lexeme)); \
|
||||
scc_str_as_cstr(&token.lexeme)); \
|
||||
\
|
||||
free_token(&token); \
|
||||
scc_sstream_drop_ring(ref); \
|
||||
|
||||
@@ -204,8 +204,8 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
lhs = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(lhs != null);
|
||||
scc_ast_expr_member_init(
|
||||
lhs, ptr, scc_cstring_as_cstr(&tok.lexeme), tok.loc);
|
||||
scc_ast_expr_member_init(lhs, ptr, scc_str_as_cstr(&tok.lexeme),
|
||||
tok.loc);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) {
|
||||
ptr = lhs;
|
||||
continue;
|
||||
|
||||
@@ -728,7 +728,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
const char *name = scc_cstring_as_cstr(&ident_tok.lexeme);
|
||||
const char *name = scc_str_as_cstr(&ident_tok.lexeme);
|
||||
|
||||
scc_ast_expr_t *member = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(member != null);
|
||||
@@ -786,7 +786,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_identifier_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
scc_ast_expr_identifier_init(expr, scc_str_as_cstr(&tok.lexeme),
|
||||
tok.loc);
|
||||
break;
|
||||
}
|
||||
@@ -795,8 +795,8 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_int_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false, tok.loc);
|
||||
scc_ast_expr_literal_int_init(expr, scc_str_as_cstr(&tok.lexeme), false,
|
||||
tok.loc);
|
||||
break;
|
||||
}
|
||||
case SCC_TOK_FLOAT_LITERAL: {
|
||||
@@ -804,7 +804,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_float_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
scc_ast_expr_literal_float_init(expr, scc_str_as_cstr(&tok.lexeme),
|
||||
false, tok.loc);
|
||||
break;
|
||||
}
|
||||
@@ -813,12 +813,12 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_char_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
scc_ast_expr_literal_char_init(expr, scc_str_as_cstr(&tok.lexeme),
|
||||
false, tok.loc);
|
||||
break;
|
||||
}
|
||||
case SCC_TOK_STRING_LITERAL: {
|
||||
scc_cstring_t string = scc_cstring_create();
|
||||
scc_str_t string = scc_str_empty();
|
||||
scc_lexer_tok_t tok;
|
||||
while (1) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
@@ -829,16 +829,16 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
break;
|
||||
}
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
scc_cstring_t tmp = scc_cstring_move(&tok.lexeme);
|
||||
scc_str_t tmp = scc_str_move(&tok.lexeme);
|
||||
scc_lexer_tok_drop(&tok);
|
||||
scc_cstring_append(&string, &tmp);
|
||||
scc_str_append(&string, &tmp);
|
||||
}
|
||||
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
// FIXME loc
|
||||
scc_ast_expr_literal_string_init(expr, scc_cstring_as_cstr(&string),
|
||||
true, tok.loc);
|
||||
scc_ast_expr_literal_string_init(expr, scc_str_as_cstr(&string), true,
|
||||
tok.loc);
|
||||
break;
|
||||
}
|
||||
case SCC_TOK_L_PAREN:
|
||||
|
||||
@@ -92,8 +92,7 @@ static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser,
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
Assert(stmt != null);
|
||||
scc_ast_stmt_label_init(stmt, scc_cstring_as_cstr(&tok.lexeme), statement,
|
||||
pos);
|
||||
scc_ast_stmt_label_init(stmt, scc_str_as_cstr(&tok.lexeme), statement, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@@ -312,7 +311,7 @@ static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser,
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_GOTO)) {
|
||||
scc_lexer_tok_t tok = {0};
|
||||
if (scc_parser_next_consume(parser, &tok)) {
|
||||
scc_ast_stmt_goto_init(stmt, scc_cstring_as_cstr(&tok.lexeme), pos);
|
||||
scc_ast_stmt_goto_init(stmt, scc_str_as_cstr(&tok.lexeme), pos);
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected label after goto.");
|
||||
|
||||
@@ -229,8 +229,8 @@ cbool scc_parse_is_decl_specifier_start(scc_parser_t *parser) {
|
||||
return true;
|
||||
// typedef 名称(标识符也可能是类型说明符)
|
||||
case SCC_TOK_IDENT:
|
||||
return scc_parse_got_type(
|
||||
parser, scc_cstring_as_cstr(&tok_ptr->lexeme)) != null;
|
||||
return scc_parse_got_type(parser, scc_str_as_cstr(&tok_ptr->lexeme)) !=
|
||||
null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -260,8 +260,8 @@ cbool scc_parse_is_type_specifier_start(scc_parser_t *parser) {
|
||||
// typedef 名称
|
||||
case SCC_TOK_IDENT:
|
||||
// 需要检查标识符是否在符号表中定义为 typedef
|
||||
return scc_parse_got_type(
|
||||
parser, scc_cstring_as_cstr(&tok_ptr->lexeme)) != null;
|
||||
return scc_parse_got_type(parser, scc_str_as_cstr(&tok_ptr->lexeme)) !=
|
||||
null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -585,7 +585,7 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
|
||||
if (tok_ptr->type == SCC_TOK_IDENT) {
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
name = scc_cstring_as_cstr(&tok.lexeme);
|
||||
name = scc_str_as_cstr(&tok.lexeme);
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
}
|
||||
|
||||
@@ -683,7 +683,7 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
if (tok_ptr->type == SCC_TOK_IDENT) {
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
name = scc_cstring_as_cstr(&tok.lexeme);
|
||||
name = scc_str_as_cstr(&tok.lexeme);
|
||||
}
|
||||
|
||||
if (tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE) {
|
||||
@@ -711,8 +711,8 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
scc_ast_decl_t *enum_item_decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(enum_item_decl != null);
|
||||
scc_ast_decl_val_init(enum_item_decl, type,
|
||||
scc_cstring_as_cstr(&tok.lexeme),
|
||||
enum_item_init, tok.loc);
|
||||
scc_str_as_cstr(&tok.lexeme), enum_item_init,
|
||||
tok.loc);
|
||||
scc_vec_push(member, enum_item_decl);
|
||||
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
@@ -777,11 +777,11 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) {
|
||||
goto done;
|
||||
case SCC_TOK_IDENT:
|
||||
info.user_type =
|
||||
scc_parse_got_type(parser, scc_cstring_as_cstr(&tok_ptr->lexeme));
|
||||
scc_parse_got_type(parser, scc_str_as_cstr(&tok_ptr->lexeme));
|
||||
if (info.user_type == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected type specifier %s",
|
||||
scc_cstring_as_cstr(&tok_ptr->lexeme));
|
||||
scc_str_as_cstr(&tok_ptr->lexeme));
|
||||
}
|
||||
scc_parser_next_consume(parser, null);
|
||||
Assert(info.user_type != null);
|
||||
@@ -1217,7 +1217,7 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
|
||||
// FIXME memory leak
|
||||
const char *name = decl_name_tok.type == SCC_TOK_IDENT
|
||||
? scc_cstring_as_cstr(&decl_name_tok.lexeme)
|
||||
? scc_str_as_cstr(&decl_name_tok.lexeme)
|
||||
: null;
|
||||
|
||||
if (decl_type->base.type == SCC_AST_TYPE_FUNCTION) {
|
||||
|
||||
@@ -77,31 +77,31 @@ static void decl_callback(void *context, scc_ast_node_type_t node_type,
|
||||
if (node_type == SCC_AST_DECL_STRUCT) {
|
||||
scc_ast_type_struct_init(type, decl->name, decl, decl->base.loc);
|
||||
// FIXME memory leak
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$S_");
|
||||
scc_str_t name = scc_str_from_cstr("$S_");
|
||||
|
||||
if (decl->name == null) {
|
||||
decl->name = "<anonymous struct>";
|
||||
}
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
scc_str_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_str_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (node_type == SCC_AST_DECL_UNION) {
|
||||
scc_ast_type_union_init(type, decl->name, decl, decl->base.loc);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$U_");
|
||||
scc_str_t name = scc_str_from_cstr("$U_");
|
||||
if (decl->name == null) {
|
||||
decl->name = "<anonymous union>";
|
||||
}
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
scc_str_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_str_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (node_type == SCC_AST_DECL_ENUM) {
|
||||
scc_ast_type_enum_init(type, decl->name, decl, decl->base.loc);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$E_");
|
||||
scc_str_t name = scc_str_from_cstr("$E_");
|
||||
if (decl->name == null) {
|
||||
decl->name = "<anonymous enum>";
|
||||
}
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
scc_str_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_str_as_cstr(&name),
|
||||
&type->base);
|
||||
|
||||
scc_vec_foreach(decl->record.fields, i) {
|
||||
|
||||
@@ -19,7 +19,7 @@ typedef enum {
|
||||
typedef SCC_VEC(scc_lexer_tok_vec_t) scc_pproc_macro_extened_params_t;
|
||||
// 宏定义结构
|
||||
typedef struct scc_macro {
|
||||
scc_cstring_t name; // 宏名称
|
||||
scc_str_t name; // 宏名称
|
||||
scc_pproc_macro_type_t type; // 宏类型
|
||||
scc_lexer_tok_vec_t replaces; // 替换列表
|
||||
scc_lexer_tok_vec_t params; // 参数列表(仅函数宏)
|
||||
@@ -35,7 +35,7 @@ typedef struct scc_macro_table {
|
||||
* @param type 宏类型
|
||||
* @return 创建的宏对象指针,失败返回NULL
|
||||
*/
|
||||
scc_pproc_macro_t *scc_pproc_macro_new(const scc_cstring_t *name,
|
||||
scc_pproc_macro_t *scc_pproc_macro_new(const scc_str_t *name,
|
||||
scc_pproc_macro_type_t type);
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ void scc_pproc_macro_drop(scc_pproc_macro_t *macro);
|
||||
* @return 成功返回true,失败返回false
|
||||
*/
|
||||
cbool scc_pproc_add_object_macro(scc_pproc_macro_table_t *pp,
|
||||
const scc_cstring_t *name,
|
||||
const scc_str_t *name,
|
||||
const scc_lexer_tok_vec_t *replacement);
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ cbool scc_pproc_add_object_macro(scc_pproc_macro_table_t *pp,
|
||||
* @return 成功返回true,失败返回false
|
||||
*/
|
||||
cbool scc_pproc_add_function_macro(scc_pproc_macro_table_t *pp,
|
||||
const scc_cstring_t *name,
|
||||
const scc_str_t *name,
|
||||
const scc_lexer_tok_vec_t *params,
|
||||
const scc_lexer_tok_vec_t *replacement);
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ scc_pproc_macro_t *scc_pproc_macro_table_set(scc_pproc_macro_table_t *pp,
|
||||
* @return 找到的宏对象指针,未找到返回NULL
|
||||
*/
|
||||
scc_pproc_macro_t *scc_pproc_macro_table_get(scc_pproc_macro_table_t *pp,
|
||||
const scc_cstring_t *name);
|
||||
const scc_str_t *name);
|
||||
|
||||
/**
|
||||
* @brief 从预处理器中删除宏
|
||||
@@ -93,7 +93,7 @@ scc_pproc_macro_t *scc_pproc_macro_table_get(scc_pproc_macro_table_t *pp,
|
||||
* @return 成功删除返回true,未找到返回false
|
||||
*/
|
||||
cbool scc_pproc_macro_table_remove(scc_pproc_macro_table_t *pp,
|
||||
const scc_cstring_t *name);
|
||||
const scc_str_t *name);
|
||||
|
||||
void scc_pproc_marco_table_init(scc_pproc_macro_table_t *macros);
|
||||
void scc_pproc_macro_table_drop(scc_pproc_macro_table_t *macros);
|
||||
|
||||
@@ -29,7 +29,7 @@ typedef struct {
|
||||
typedef SCC_VEC(scc_pproc_file_t *) scc_pproc_file_stack_t;
|
||||
|
||||
typedef SCC_VEC(scc_lexer_tok_ring_t *) scc_pproc_ring_vec_t;
|
||||
typedef SCC_VEC(scc_cstring_t) scc_pproc_cstr_vec_t;
|
||||
typedef SCC_VEC(scc_str_t) scc_pproc_cstr_vec_t;
|
||||
|
||||
typedef struct scc_pproc {
|
||||
scc_lexer_tok_ring_t *org_ring;
|
||||
@@ -61,13 +61,13 @@ scc_lexer_tok_ring_t *scc_pproc_to_ring(scc_pproc_t *pp, int ring_size,
|
||||
void scc_pproc_drop(scc_pproc_t *pp);
|
||||
|
||||
static inline void scc_pproc_add_include_path(scc_pproc_t *pp,
|
||||
const scc_cstring_t *path) {
|
||||
scc_vec_push(pp->include_paths, scc_cstring_copy(path));
|
||||
const scc_str_t *path) {
|
||||
scc_vec_push(pp->include_paths, scc_str_copy(path));
|
||||
}
|
||||
|
||||
static inline void scc_pproc_add_include_path_cstr(scc_pproc_t *pp,
|
||||
const char *path) {
|
||||
scc_vec_push(pp->include_paths, scc_cstring_from_cstr(path));
|
||||
scc_vec_push(pp->include_paths, scc_str_from_cstr(path));
|
||||
}
|
||||
|
||||
void scc_pproc_handle_directive(scc_pproc_t *pp);
|
||||
|
||||
@@ -133,8 +133,8 @@ void scc_pproc_parse_function_macro(scc_pproc_t *pp,
|
||||
if (idx++ % 2 != 0) {
|
||||
LOG_FATAL("ERROR");
|
||||
}
|
||||
scc_cstring_t va_args = scc_cstring_from_cstr("__VA_ARGS__");
|
||||
scc_cstring_free(&arg->lexeme);
|
||||
scc_str_t va_args = scc_str_from_cstr("__VA_ARGS__");
|
||||
scc_str_drop(&arg->lexeme);
|
||||
arg->lexeme = va_args;
|
||||
scc_vec_push(macro->params, *arg);
|
||||
} else if (scc_get_tok_subtype(arg->type) ==
|
||||
@@ -249,12 +249,12 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
SCC_ERROR(tok.loc, "invalid preprocessing directive");
|
||||
goto ERROR;
|
||||
}
|
||||
int ret = keyword_cmp(scc_cstring_as_cstr(&tok.lexeme),
|
||||
scc_cstring_len(&tok.lexeme));
|
||||
int ret =
|
||||
keyword_cmp(scc_str_as_cstr(&tok.lexeme), scc_str_len(&tok.lexeme));
|
||||
if (ret == -1) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
SCC_ERROR(tok.loc, "expected preprocessor directive name, got '%s'",
|
||||
scc_cstring_as_cstr(&tok.lexeme));
|
||||
scc_str_as_cstr(&tok.lexeme));
|
||||
goto ERROR;
|
||||
}
|
||||
scc_tok_type_t type = keywords[ret].tok_type;
|
||||
@@ -362,7 +362,7 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
return; \
|
||||
} \
|
||||
if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_LITERAL) { \
|
||||
func_name(tok.loc, "%s", scc_cstring_as_cstr(&tok.lexeme)); \
|
||||
func_name(tok.loc, "%s", scc_str_as_cstr(&tok.lexeme)); \
|
||||
} \
|
||||
scc_lexer_tok_drop(&tok); \
|
||||
} \
|
||||
@@ -382,6 +382,6 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
break;
|
||||
}
|
||||
ERROR:
|
||||
LOG_WARN("Unhandled directive: %s", scc_cstring_as_cstr(&tok.lexeme));
|
||||
LOG_WARN("Unhandled directive: %s", scc_str_as_cstr(&tok.lexeme));
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ static inline scc_lexer_tok_t scc_pproc_tok_copy(scc_pproc_expand_t *ctx,
|
||||
static scc_lexer_tok_t stringify_argument(scc_pproc_expand_t *ctx,
|
||||
scc_lexer_tok_vec_t *arg_tokens) {
|
||||
// WRITE BY AI
|
||||
scc_cstring_t str = scc_cstring_create();
|
||||
scc_cstring_append_ch(&str, '\"'); // 左引号
|
||||
scc_str_t str = scc_str_empty();
|
||||
scc_str_append_ch(&str, '\"'); // 左引号
|
||||
|
||||
int need_space = 0; // 是否需要插入空格
|
||||
scc_lexer_tok_t *tok = null;
|
||||
@@ -32,7 +32,7 @@ static scc_lexer_tok_t stringify_argument(scc_pproc_expand_t *ctx,
|
||||
|
||||
// 需要空格且当前不是第一个有效token,插入一个空格
|
||||
if (need_space && i > 0) {
|
||||
scc_cstring_append_ch(&str, ' ');
|
||||
scc_str_append_ch(&str, ' ');
|
||||
}
|
||||
|
||||
// 对字符串/字符常量内的 " 和 \ 进行转义
|
||||
@@ -41,10 +41,10 @@ static scc_lexer_tok_t stringify_argument(scc_pproc_expand_t *ctx,
|
||||
// 注意:lex包含两端的引号,需要跳过首尾,转义内部字符
|
||||
// 简化:暂不处理内部转义,直接追加
|
||||
}
|
||||
scc_cstring_append(&str, &tok->lexeme);
|
||||
scc_str_append(&str, &tok->lexeme);
|
||||
need_space = 0;
|
||||
}
|
||||
scc_cstring_append_ch(&str, '\"'); // 右引号
|
||||
scc_str_append_ch(&str, '\"'); // 右引号
|
||||
|
||||
scc_lexer_tok_t result;
|
||||
result.type = SCC_TOK_STRING_LITERAL;
|
||||
@@ -60,19 +60,19 @@ static scc_lexer_tok_t stringify_argument(scc_pproc_expand_t *ctx,
|
||||
static scc_lexer_tok_t concatenate_tokens(scc_pproc_expand_t *ctx,
|
||||
const scc_lexer_tok_t *left,
|
||||
const scc_lexer_tok_t *right) {
|
||||
scc_cstring_t new_lex = scc_cstring_from_cstr("");
|
||||
scc_str_t new_lex = scc_str_from_cstr("");
|
||||
if (left != null) {
|
||||
scc_cstring_append(&new_lex, &left->lexeme);
|
||||
scc_str_append(&new_lex, &left->lexeme);
|
||||
}
|
||||
if (right != null) {
|
||||
scc_cstring_append(&new_lex, &right->lexeme);
|
||||
scc_str_append(&new_lex, &right->lexeme);
|
||||
}
|
||||
|
||||
scc_lexer_t lexer;
|
||||
scc_sstream_t sstream;
|
||||
// new_lex 所有权转移
|
||||
scc_sstream_init_by_buffer(&sstream, scc_cstring_as_cstr(&new_lex),
|
||||
scc_cstring_len(&new_lex), true, 8);
|
||||
scc_sstream_init_by_buffer(&sstream, scc_str_as_cstr(&new_lex),
|
||||
scc_str_len(&new_lex), true, 8);
|
||||
scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream));
|
||||
scc_lexer_tok_ring_t *ring = scc_lexer_to_ring(&lexer, 8, true);
|
||||
|
||||
@@ -269,7 +269,7 @@ expand_arguments(scc_pproc_macro_extened_params_t *expanded_params,
|
||||
scc_vec_init(expanded_param);
|
||||
scc_vec_foreach(splite_param, j) {
|
||||
scc_lexer_tok_t tok = scc_vec_at(splite_param, j);
|
||||
tok.lexeme = scc_cstring_copy(&tok.lexeme);
|
||||
tok.lexeme = scc_str_copy(&tok.lexeme);
|
||||
scc_vec_push(expanded_param, tok);
|
||||
}
|
||||
scc_lexer_tok_ring_t ring = scc_lexer_array_to_ring(&expanded_param);
|
||||
@@ -353,7 +353,7 @@ RETURN:
|
||||
static int find_params(const scc_lexer_tok_t *tok,
|
||||
const scc_pproc_macro_t *macro) {
|
||||
scc_vec_foreach(macro->params, j) {
|
||||
if (scc_cstring_cmp(&(tok->lexeme),
|
||||
if (scc_str_equal(&(tok->lexeme),
|
||||
&(scc_vec_at(macro->params, j).lexeme)) == 0) {
|
||||
return j;
|
||||
}
|
||||
@@ -437,8 +437,8 @@ static inline void expand_function_macro(scc_pproc_expand_t *ctx,
|
||||
scc_lexer_tok_t tok =
|
||||
scc_pproc_tok_copy(ctx, &scc_vec_at(macro->replaces, i));
|
||||
if (tok.type == SCC_TOK_BLANK) {
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
tok.lexeme = scc_cstring_from_cstr(" ");
|
||||
scc_str_drop(&tok.lexeme);
|
||||
tok.lexeme = scc_str_from_cstr(" ");
|
||||
scc_vec_push(tok_buffer, tok);
|
||||
continue;
|
||||
}
|
||||
@@ -449,8 +449,8 @@ static inline void expand_function_macro(scc_pproc_expand_t *ctx,
|
||||
int right_idx = got_right_non_blank(i, ¯o->replaces);
|
||||
if (right_idx >= (int)macro->replaces.size) {
|
||||
LOG_WARN("generate empty stringify");
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
tok.lexeme = scc_cstring_from_cstr("");
|
||||
scc_str_drop(&tok.lexeme);
|
||||
tok.lexeme = scc_str_from_cstr("");
|
||||
scc_vec_push(tok_buffer, tok);
|
||||
break;
|
||||
}
|
||||
@@ -491,7 +491,7 @@ static inline void expand_function_macro(scc_pproc_expand_t *ctx,
|
||||
scc_vec_size(right_vec) ? &scc_vec_at(right_vec, 0) : null;
|
||||
|
||||
// GNU ## extention
|
||||
if (scc_strcmp(scc_cstring_as_cstr(&(right_tok->lexeme)),
|
||||
if (scc_strcmp(scc_str_as_cstr(&(right_tok->lexeme)),
|
||||
"__VA_ARGS__") == 0) {
|
||||
if (scc_vec_size(right_vec) == 0) {
|
||||
concact(ctx, &tok_buffer, right, true);
|
||||
@@ -550,8 +550,8 @@ static inline void expand_object_macro(scc_pproc_expand_t *ctx,
|
||||
scc_pproc_tok_copy(ctx, &scc_vec_at(macro->replaces, i));
|
||||
if (tok.type == SCC_TOK_BLANK) {
|
||||
// FIXME using function to warpper it
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
tok.lexeme = scc_cstring_from_cstr(" ");
|
||||
scc_str_drop(&tok.lexeme);
|
||||
tok.lexeme = scc_str_from_cstr(" ");
|
||||
} else if (tok.type == SCC_TOK_SHARP_SHARP) {
|
||||
// ## contact
|
||||
scc_lexer_tok_drop(&tok);
|
||||
@@ -635,7 +635,7 @@ void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) {
|
||||
}
|
||||
|
||||
if (expand_ctx->need_parse_defined &&
|
||||
scc_strcmp(scc_cstring_as_cstr(&tok.lexeme), "defined") == 0) {
|
||||
scc_strcmp(scc_str_as_cstr(&tok.lexeme), "defined") == 0) {
|
||||
scc_pos_t pos = tok.loc;
|
||||
scc_lexer_tok_drop(&tok);
|
||||
if (parse_defined(expand_ctx, &pos)) {
|
||||
@@ -679,19 +679,19 @@ void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) {
|
||||
}
|
||||
// FIXME 这可能不符合c语义
|
||||
case SCC_PP_MACRO_BUILTIN__FILE__:
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
scc_cstring_append_ch(&tok.lexeme, '"');
|
||||
scc_cstring_append_cstr(&tok.lexeme, tok.loc.name,
|
||||
scc_str_drop(&tok.lexeme);
|
||||
scc_str_append_ch(&tok.lexeme, '"');
|
||||
scc_str_append_cstr(&tok.lexeme, tok.loc.name,
|
||||
scc_strlen(tok.loc.name));
|
||||
scc_cstring_append_ch(&tok.lexeme, '"');
|
||||
scc_str_append_ch(&tok.lexeme, '"');
|
||||
tok.type = SCC_TOK_STRING_LITERAL;
|
||||
scc_vec_push(expand_ctx->output, tok);
|
||||
break;
|
||||
case SCC_PP_MACRO_BUILTIN__LINE__:
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
scc_str_drop(&tok.lexeme);
|
||||
char *buff = scc_malloc(32);
|
||||
scc_snprintf(buff, 32, "%zu", tok.loc.line);
|
||||
tok.lexeme = scc_cstring_from_cstr(buff);
|
||||
tok.lexeme = scc_str_from_cstr(buff);
|
||||
scc_free(buff);
|
||||
tok.type = SCC_TOK_INT_LITERAL;
|
||||
scc_vec_push(expand_ctx->output, tok);
|
||||
|
||||
@@ -148,8 +148,8 @@ static int parse_constant_condition(scc_pproc_t *pp,
|
||||
|
||||
if (tok.type == SCC_TOK_INT_LITERAL) {
|
||||
// got int
|
||||
const char *intstr = scc_cstring_as_cstr(&tok.lexeme);
|
||||
for (int i = scc_cstring_len(&tok.lexeme) - 1; i >= 0; i--) {
|
||||
const char *intstr = scc_str_as_cstr(&tok.lexeme);
|
||||
for (int i = scc_str_len(&tok.lexeme) - 1; i >= 0; i--) {
|
||||
res = res * 10 + intstr[i] - '0';
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include <scc_core_ring.h>
|
||||
#include <scc_pproc.h>
|
||||
|
||||
static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t *fname,
|
||||
scc_pos_t *pos, int is_system) {
|
||||
scc_cstring_t fpath = scc_cstring_create();
|
||||
static int switch_file_stack(scc_pproc_t *pp, scc_str_t *fname, scc_pos_t *pos,
|
||||
int is_system) {
|
||||
scc_str_t fpath = scc_str_empty();
|
||||
int ret = 0;
|
||||
|
||||
const char *org_fname = pos->name;
|
||||
@@ -12,10 +12,10 @@ static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t *fname,
|
||||
if (!is_system) {
|
||||
const char parent[] = "/../";
|
||||
// FIXME maybe it can eazy
|
||||
scc_cstring_append_cstr(&fpath, org_fname, scc_strlen(org_fname));
|
||||
scc_cstring_append_cstr(&fpath, parent, scc_strlen(parent));
|
||||
scc_cstring_append(&fpath, fname);
|
||||
ret = scc_fexists(scc_cstring_as_cstr(&fpath));
|
||||
scc_str_append_cstr(&fpath, org_fname, scc_strlen(org_fname));
|
||||
scc_str_append_cstr(&fpath, parent, scc_strlen(parent));
|
||||
scc_str_append(&fpath, fname);
|
||||
ret = scc_fexists(scc_str_as_cstr(&fpath));
|
||||
if (ret == true) {
|
||||
goto FOPEN;
|
||||
}
|
||||
@@ -23,17 +23,17 @@ static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t *fname,
|
||||
|
||||
/* system default path and -I includes path */
|
||||
scc_vec_foreach(pp->include_paths, i) {
|
||||
scc_cstring_free(&fpath);
|
||||
scc_cstring_t *syspath = &scc_vec_at(pp->include_paths, i);
|
||||
scc_cstring_append(&fpath, syspath);
|
||||
scc_cstring_append_ch(&fpath, '/');
|
||||
scc_cstring_append(&fpath, fname);
|
||||
ret = scc_fexists(scc_cstring_as_cstr(&fpath));
|
||||
scc_str_drop(&fpath);
|
||||
scc_str_t *syspath = &scc_vec_at(pp->include_paths, i);
|
||||
scc_str_append(&fpath, syspath);
|
||||
scc_str_append_ch(&fpath, '/');
|
||||
scc_str_append(&fpath, fname);
|
||||
ret = scc_fexists(scc_str_as_cstr(&fpath));
|
||||
if (ret == true) {
|
||||
goto FOPEN;
|
||||
}
|
||||
}
|
||||
SCC_ERROR(*pos, "include file '%s' not found", scc_cstring_as_cstr(fname));
|
||||
SCC_ERROR(*pos, "include file '%s' not found", scc_str_as_cstr(fname));
|
||||
return -1;
|
||||
FOPEN:
|
||||
if ((int)scc_vec_size(pp->file_stack) >= pp->config.max_include_depth) {
|
||||
@@ -44,7 +44,7 @@ FOPEN:
|
||||
|
||||
scc_pproc_file_t *file = scc_malloc(sizeof(scc_pproc_file_t));
|
||||
Assert(file != null);
|
||||
if (scc_sstream_init(&(file->sstream), scc_cstring_as_cstr(&fpath), 1024)) {
|
||||
if (scc_sstream_init(&(file->sstream), scc_str_as_cstr(&fpath), 1024)) {
|
||||
return -1;
|
||||
}
|
||||
scc_lexer_init(&(file->lexer), scc_sstream_to_ring(&(file->sstream)));
|
||||
@@ -62,21 +62,21 @@ void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok,
|
||||
scc_pos_t pos = include_tok->loc;
|
||||
scc_lexer_tok_drop(include_tok);
|
||||
|
||||
scc_cstring_t line = scc_cstring_create();
|
||||
scc_str_t line = scc_str_empty();
|
||||
while (1) {
|
||||
scc_ring_next_consume(*tok_ring, tok, ok);
|
||||
if (!ok)
|
||||
break;
|
||||
if (scc_get_tok_subtype(tok.type) != SCC_TOK_SUBTYPE_EMPTYSPACE &&
|
||||
scc_get_tok_subtype(tok.type) != SCC_TOK_SUBTYPE_COMMENT) {
|
||||
scc_cstring_append(&line, &tok.lexeme);
|
||||
scc_str_append(&line, &tok.lexeme);
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
scc_ring_free(*tok_ring);
|
||||
|
||||
const char *includename = scc_cstring_as_cstr(&line);
|
||||
int len = scc_cstring_len(&line);
|
||||
const char *includename = scc_str_as_cstr(&line);
|
||||
int len = scc_str_len(&line);
|
||||
if (len < 2) {
|
||||
goto ERROR;
|
||||
} else if (len == 2) {
|
||||
@@ -94,19 +94,19 @@ void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok,
|
||||
goto ERROR;
|
||||
}
|
||||
}
|
||||
scc_cstring_t fname = scc_cstring_create();
|
||||
scc_str_t fname = scc_str_empty();
|
||||
for (int i = 1; i < len - 1; i++) {
|
||||
scc_cstring_append_ch(&fname, includename[i]);
|
||||
scc_str_append_ch(&fname, includename[i]);
|
||||
}
|
||||
scc_cstring_free(&line);
|
||||
scc_str_drop(&line);
|
||||
int is_system = includename[0] == '<';
|
||||
if (switch_file_stack(pp, &fname, &pos, is_system)) {
|
||||
// LOG_ERROR()
|
||||
}
|
||||
scc_cstring_free(&fname);
|
||||
scc_str_drop(&fname);
|
||||
return;
|
||||
ERROR:
|
||||
SCC_ERROR(pos,
|
||||
"invalid include filename, expected \"FILENAME\" or <FILENAME>");
|
||||
scc_cstring_free(&line);
|
||||
scc_str_drop(&line);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <pproc_macro.h>
|
||||
|
||||
// 创建宏对象
|
||||
scc_pproc_macro_t *scc_pproc_macro_new(const scc_cstring_t *name,
|
||||
scc_pproc_macro_t *scc_pproc_macro_new(const scc_str_t *name,
|
||||
scc_pproc_macro_type_t type) {
|
||||
scc_pproc_macro_t *macro = scc_malloc(sizeof(scc_pproc_macro_t));
|
||||
if (!macro) {
|
||||
@@ -9,7 +9,7 @@ scc_pproc_macro_t *scc_pproc_macro_new(const scc_cstring_t *name,
|
||||
return null;
|
||||
}
|
||||
|
||||
macro->name = scc_cstring_copy(name);
|
||||
macro->name = scc_str_copy(name);
|
||||
macro->type = type;
|
||||
scc_vec_init(macro->params);
|
||||
scc_vec_init(macro->replaces);
|
||||
@@ -34,14 +34,14 @@ void scc_pproc_macro_drop(scc_pproc_macro_t *macro) {
|
||||
}
|
||||
scc_vec_free(macro->replaces);
|
||||
|
||||
scc_cstring_free(¯o->name);
|
||||
scc_str_drop(¯o->name);
|
||||
|
||||
scc_free(macro);
|
||||
}
|
||||
|
||||
// 添加对象宏
|
||||
cbool scc_pproc_add_object_macro(scc_pproc_macro_table_t *macros,
|
||||
const scc_cstring_t *name,
|
||||
const scc_str_t *name,
|
||||
const scc_lexer_tok_vec_t *replacement) {
|
||||
if (!macros || !name || !replacement)
|
||||
return false;
|
||||
@@ -56,7 +56,7 @@ cbool scc_pproc_add_object_macro(scc_pproc_macro_table_t *macros,
|
||||
scc_pproc_macro_t *existing =
|
||||
scc_hashtable_get(¯os->table, ¯o->name);
|
||||
if (existing) {
|
||||
LOG_WARN("Redefining macro: %s", scc_cstring_as_cstr(¯o->name));
|
||||
LOG_WARN("Redefining macro: %s", scc_str_as_cstr(¯o->name));
|
||||
scc_pproc_macro_drop(existing);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ cbool scc_pproc_add_object_macro(scc_pproc_macro_table_t *macros,
|
||||
|
||||
// 添加函数宏
|
||||
cbool scc_pproc_add_function_macro(scc_pproc_macro_table_t *macros,
|
||||
const scc_cstring_t *name,
|
||||
const scc_str_t *name,
|
||||
const scc_lexer_tok_vec_t *params,
|
||||
const scc_lexer_tok_vec_t *replacement) {
|
||||
if (!macros || !name || !params || !replacement)
|
||||
@@ -84,7 +84,7 @@ cbool scc_pproc_add_function_macro(scc_pproc_macro_table_t *macros,
|
||||
scc_pproc_macro_t *existing =
|
||||
scc_hashtable_get(¯os->table, ¯o->name);
|
||||
if (existing) {
|
||||
LOG_WARN("Redefining macro: %s", scc_cstring_as_cstr(¯o->name));
|
||||
LOG_WARN("Redefining macro: %s", scc_str_as_cstr(¯o->name));
|
||||
scc_pproc_macro_drop(existing);
|
||||
}
|
||||
|
||||
@@ -96,10 +96,10 @@ cbool scc_pproc_add_function_macro(scc_pproc_macro_table_t *macros,
|
||||
|
||||
scc_pproc_macro_t *scc_pproc_macro_table_set(scc_pproc_macro_table_t *pp,
|
||||
scc_pproc_macro_t *macro) {
|
||||
Assert(pp != null && macro != null && scc_cstring_len(¯o->name) != 0);
|
||||
Assert(pp != null && macro != null && scc_str_len(¯o->name) != 0);
|
||||
scc_pproc_macro_t *old = scc_hashtable_set(&pp->table, ¯o->name, macro);
|
||||
if (old && old != macro) {
|
||||
LOG_WARN("same macro name `%s`", scc_cstring_as_cstr(¯o->name));
|
||||
LOG_WARN("same macro name `%s`", scc_str_as_cstr(¯o->name));
|
||||
scc_pproc_macro_drop(old);
|
||||
}
|
||||
return macro;
|
||||
@@ -107,13 +107,13 @@ scc_pproc_macro_t *scc_pproc_macro_table_set(scc_pproc_macro_table_t *pp,
|
||||
|
||||
// 查找宏定义
|
||||
scc_pproc_macro_t *scc_pproc_macro_table_get(scc_pproc_macro_table_t *pp,
|
||||
const scc_cstring_t *name) {
|
||||
const scc_str_t *name) {
|
||||
return scc_hashtable_get(&pp->table, name);
|
||||
}
|
||||
|
||||
// 从预处理器中删除宏
|
||||
cbool scc_pproc_macro_table_remove(scc_pproc_macro_table_t *pp,
|
||||
const scc_cstring_t *name) {
|
||||
const scc_str_t *name) {
|
||||
if (!pp || !name)
|
||||
return false;
|
||||
|
||||
@@ -127,18 +127,18 @@ cbool scc_pproc_macro_table_remove(scc_pproc_macro_table_t *pp,
|
||||
}
|
||||
|
||||
static u32 hash_func(const void *key) {
|
||||
const scc_cstring_t *string = (const scc_cstring_t *)key;
|
||||
return scc_strhash32(scc_cstring_as_cstr(string));
|
||||
const scc_str_t *string = (const scc_str_t *)key;
|
||||
return scc_strhash32(scc_str_as_cstr(string));
|
||||
}
|
||||
|
||||
static int hash_cmp(const void *key1, const void *key2) {
|
||||
const scc_cstring_t *str1 = (const scc_cstring_t *)key1;
|
||||
const scc_cstring_t *str2 = (const scc_cstring_t *)key2;
|
||||
const scc_str_t *str1 = (const scc_str_t *)key1;
|
||||
const scc_str_t *str2 = (const scc_str_t *)key2;
|
||||
|
||||
if (str1->size != str2->size) {
|
||||
return str1->size - str2->size;
|
||||
}
|
||||
return scc_strcmp(scc_cstring_as_cstr(str1), scc_cstring_as_cstr(str2));
|
||||
return scc_strcmp(scc_str_as_cstr(str1), scc_str_as_cstr(str2));
|
||||
}
|
||||
|
||||
void scc_pproc_marco_table_init(scc_pproc_macro_table_t *macros) {
|
||||
|
||||
@@ -110,8 +110,7 @@ void scc_pproc_add_builtin_macros(scc_pproc_macro_table_t *macro_table) {
|
||||
{"__LINE__", SCC_PP_MACRO_BUILTIN__LINE__},
|
||||
};
|
||||
for (usize i = 0; i < SCC_ARRLEN(builin_table); i += 1) {
|
||||
scc_cstring_t builtin_name =
|
||||
scc_cstring_from_cstr(builin_table[i].name);
|
||||
scc_str_t builtin_name = scc_str_from_cstr(builin_table[i].name);
|
||||
scc_pproc_macro_t *builtin =
|
||||
scc_pproc_macro_new(&builtin_name, builin_table[i].type);
|
||||
scc_pproc_macro_table_set(macro_table, builtin);
|
||||
@@ -146,7 +145,7 @@ CONTINUE:
|
||||
}
|
||||
|
||||
if (ret && scc_get_tok_subtype(tok->type) == SCC_TOK_SUBTYPE_INVALID) {
|
||||
PanicFmt("Invalid token: %s", scc_cstring_as_cstr(&tok->lexeme));
|
||||
PanicFmt("Invalid token: %s", scc_str_as_cstr(&tok->lexeme));
|
||||
}
|
||||
if (ret && !pp->ring_need_comment &&
|
||||
scc_get_tok_subtype(tok->type) == SCC_TOK_SUBTYPE_COMMENT) {
|
||||
@@ -180,7 +179,7 @@ void scc_pproc_drop(scc_pproc_t *pp) {
|
||||
scc_ring_free(pp->expanded_ring);
|
||||
|
||||
scc_vec_foreach(pp->include_paths, i) {
|
||||
scc_cstring_free(&scc_vec_at(pp->include_paths, i));
|
||||
scc_str_drop(&scc_vec_at(pp->include_paths, i));
|
||||
}
|
||||
scc_vec_free(pp->include_paths);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <utest/acutest.h>
|
||||
|
||||
static cbool process_input(const char *input, scc_cstring_t *output) {
|
||||
static cbool process_input(const char *input, scc_str_t *output) {
|
||||
int ret = 0;
|
||||
scc_sstream_t mem_stream;
|
||||
ret = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
|
||||
@@ -17,14 +17,14 @@ static cbool process_input(const char *input, scc_cstring_t *output) {
|
||||
scc_pproc_init(&pp, scc_lexer_to_ring(&lexer, 8, true));
|
||||
|
||||
scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pp, 8, true, true);
|
||||
*output = scc_cstring_from_cstr("");
|
||||
*output = scc_str_from_cstr("");
|
||||
scc_lexer_tok_t tok;
|
||||
while (1) {
|
||||
scc_ring_next_consume(*tok_ring, tok, ret);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
scc_cstring_append(output, &tok.lexeme);
|
||||
scc_str_append(output, &tok.lexeme);
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
|
||||
@@ -37,24 +37,24 @@ static cbool process_input(const char *input, scc_cstring_t *output) {
|
||||
|
||||
#define CHECK_PP_OUTPUT_EXACT(input, expect) \
|
||||
do { \
|
||||
scc_cstring_t output; \
|
||||
scc_str_t output; \
|
||||
process_input(input, &output); \
|
||||
assert(output.data != NULL); \
|
||||
TEST_CHECK(strcmp(output.data, expect) == 0); \
|
||||
TEST_MSG("Expected: %s", expect); \
|
||||
TEST_MSG("Produced: %s", output.data); \
|
||||
scc_cstring_free(&output); \
|
||||
scc_str_drop(&output); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_PP_OUTPUT_CONTAIN(input, expect) \
|
||||
do { \
|
||||
scc_cstring_t output; \
|
||||
scc_str_t output; \
|
||||
process_input(input, &output); \
|
||||
assert(output.data != NULL); \
|
||||
TEST_CHECK(strstr(output.data, expect) != NULL); \
|
||||
TEST_MSG("Expected: %s", expect); \
|
||||
TEST_MSG("Produced: %s", output.data); \
|
||||
scc_cstring_free(&output); \
|
||||
scc_str_drop(&output); \
|
||||
} while (0)
|
||||
|
||||
static void test_define_simple_no_macro(void) {
|
||||
|
||||
@@ -16,11 +16,11 @@ static void load_from_def(pe_idata_lib_ctx_t *ctx, const char *file_path,
|
||||
name @number
|
||||
...
|
||||
*/
|
||||
scc_cstring_t fpath = scc_cstring_from_cstr(file_path);
|
||||
scc_cstring_append_ch(&fpath, '/');
|
||||
scc_cstring_append_cstr(&fpath, dll_name, scc_strlen(dll_name));
|
||||
scc_cstring_append_cstr(&fpath, ".def", 4);
|
||||
const char *fname = scc_cstring_as_cstr(&fpath);
|
||||
scc_str_t fpath = scc_str_from_cstr(file_path);
|
||||
scc_str_append_ch(&fpath, '/');
|
||||
scc_str_append_cstr(&fpath, dll_name, scc_strlen(dll_name));
|
||||
scc_str_append_cstr(&fpath, ".def", 4);
|
||||
const char *fname = scc_str_as_cstr(&fpath);
|
||||
scc_file_t fp = scc_fopen(fname, SCC_FILE_READ);
|
||||
if (fp == null) {
|
||||
LOG_ERROR("load_from_def file read error: %s", fname);
|
||||
|
||||
99
libs/tree_dump/include/scc_tree_dump.h
Normal file
99
libs/tree_dump/include/scc_tree_dump.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef SCC_TREE_DUMP_H
|
||||
#define SCC_TREE_DUMP_H
|
||||
|
||||
#include "scc_core_str.h"
|
||||
#include "scc_core_vec.h"
|
||||
|
||||
typedef struct scc_tree_dump {
|
||||
scc_str_t buf; // 字符串缓冲区
|
||||
SCC_VEC(cbool) stack; // 缩进栈:每个元素表示该层是否为最后一个子节点
|
||||
cbool use_color; // 是否启用颜色
|
||||
cbool line_start; // 当前是否在行首(需要输出缩进)
|
||||
|
||||
// 可配置的缩进字符串
|
||||
const char *vertical; // "| "
|
||||
const char *branch; // "|-"
|
||||
const char *last_branch; // "`-"
|
||||
const char *space; // " "
|
||||
|
||||
// 颜色字符串(当 use_color 为 false 时为空字符串)
|
||||
const char *node_color; // 节点名称颜色
|
||||
const char *value_color; // 值颜色
|
||||
const char *branch_color; // 分支符号颜色
|
||||
const char *reset_color; // 重置颜色
|
||||
} scc_tree_dump_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化树形输出器
|
||||
* @param td 输出器指针
|
||||
* @param use_color 是否使用 ANSI 颜色
|
||||
*/
|
||||
void scc_tree_dump_init(scc_tree_dump_t *td, cbool use_color);
|
||||
|
||||
/**
|
||||
* @brief 释放输出器占用的资源
|
||||
*/
|
||||
void scc_tree_dump_drop(scc_tree_dump_t *td);
|
||||
|
||||
/**
|
||||
* @brief 清空当前缓冲区,但保留已分配内存
|
||||
*/
|
||||
void scc_tree_dump_clear(scc_tree_dump_t *td);
|
||||
|
||||
/**
|
||||
* @brief 获取当前构建的字符串(以 '\0' 结尾)
|
||||
* @return 内部缓冲区指针,不可 free
|
||||
*/
|
||||
const char *scc_tree_dump_cstr(scc_tree_dump_t *td);
|
||||
|
||||
/**
|
||||
* @brief 将缓冲区内容通过回调输出,并清空缓冲区
|
||||
* @param output 输出回调函数,接收字符串指针、长度、用户数据
|
||||
* @param user 用户数据
|
||||
*/
|
||||
void scc_tree_dump_flush(scc_tree_dump_t *td,
|
||||
void (*output)(const char *str, usize len, void *user),
|
||||
void *user);
|
||||
|
||||
/**
|
||||
* @brief 开始一个新行(自动输出缩进)
|
||||
* @note 通常不需要手动调用,因为 append 系列函数会自动处理
|
||||
*/
|
||||
void scc_tree_dump_begin_line(scc_tree_dump_t *td);
|
||||
|
||||
/**
|
||||
* @brief 追加普通字符串(自动处理行首缩进)
|
||||
*/
|
||||
void scc_tree_dump_append(scc_tree_dump_t *td, const char *s);
|
||||
|
||||
/**
|
||||
* @brief 格式化追加(printf 风格)
|
||||
*/
|
||||
void scc_tree_dump_append_fmt(scc_tree_dump_t *td, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief 追加带节点颜色的文本
|
||||
*/
|
||||
#define scc_tree_dump_node(td, fmt, ...) \
|
||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->node_color, \
|
||||
##__VA_ARGS__, (td)->reset_color)
|
||||
|
||||
/**
|
||||
* @brief 追加带值颜色的格式化文本
|
||||
*/
|
||||
#define scc_tree_dump_value(td, fmt, ...) \
|
||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->value_color, \
|
||||
##__VA_ARGS__, (td)->reset_color)
|
||||
|
||||
/**
|
||||
* @brief 推入新层级
|
||||
* @param is_last 该层级是否是父节点的最后一个子节点
|
||||
*/
|
||||
void scc_tree_dump_push(scc_tree_dump_t *td, cbool is_last);
|
||||
|
||||
/**
|
||||
* @brief 弹出当前层级
|
||||
*/
|
||||
void scc_tree_dump_pop(scc_tree_dump_t *td);
|
||||
|
||||
#endif // SCC_TREE_DUMP_H
|
||||
@@ -1,119 +0,0 @@
|
||||
#ifndef __SCC_TREE_DUMP_H__
|
||||
#define __SCC_TREE_DUMP_H__
|
||||
|
||||
#include <scc_core.h>
|
||||
|
||||
#define SCC_TREE_DUMP_VERTICAL "| "
|
||||
#define SCC_TREE_DUMP_BRANCH "|-"
|
||||
#define SCC_TREE_DUMP_LAST_BRANCH "`-"
|
||||
#define SCC_TREE_DUMP_SPACE " "
|
||||
|
||||
#define SCC_TREE_DUMP_NODE_COLOR ANSI_FG_BLUE
|
||||
#define SCC_TREE_DUMP_VALUE_COLOR ANSI_FG_GREEN
|
||||
#define SCC_TREE_DUMP_BRANCH_COLOR ANSI_FG_YELLOW
|
||||
#define SCC_TREE_DUMP_RESET_COLOR ANSI_NONE
|
||||
|
||||
// #define ANSI_FMT
|
||||
|
||||
typedef SCC_VEC(cbool) scc_ast_dump_stack_t;
|
||||
|
||||
typedef void (*scc_tree_dump_output_t)(void *userdata, const char *fmt, ...);
|
||||
|
||||
typedef struct {
|
||||
scc_ast_dump_stack_t stack; ///< 每层是否为最后子节点
|
||||
cbool use_color; ///< 是否使用颜色输出
|
||||
|
||||
const char *vertical;
|
||||
const char *branch;
|
||||
const char *last_branch;
|
||||
const char *space;
|
||||
|
||||
const char *node_color; ///< 节点类型颜色
|
||||
const char *value_color; ///< 值颜色
|
||||
const char *branch_color; ///< 分支符号颜色
|
||||
const char *reset_color; ///< 重置颜色
|
||||
|
||||
scc_tree_dump_output_t output_func;
|
||||
void *output_userdata;
|
||||
} scc_tree_dump_ctx_t;
|
||||
|
||||
static inline void scc_tree_dump_ctx_init(scc_tree_dump_ctx_t *ctx,
|
||||
cbool use_color,
|
||||
scc_tree_dump_output_t output_func,
|
||||
void *output_userdata) {
|
||||
ctx->use_color = use_color;
|
||||
scc_vec_init(ctx->stack);
|
||||
|
||||
ctx->vertical = SCC_TREE_DUMP_VERTICAL;
|
||||
ctx->branch = SCC_TREE_DUMP_BRANCH;
|
||||
ctx->last_branch = SCC_TREE_DUMP_LAST_BRANCH;
|
||||
ctx->space = SCC_TREE_DUMP_SPACE;
|
||||
|
||||
ctx->node_color = use_color ? SCC_TREE_DUMP_NODE_COLOR : "";
|
||||
ctx->value_color = use_color ? SCC_TREE_DUMP_VALUE_COLOR : "";
|
||||
ctx->branch_color = use_color ? SCC_TREE_DUMP_BRANCH_COLOR : "";
|
||||
ctx->reset_color = use_color ? SCC_TREE_DUMP_RESET_COLOR : "";
|
||||
|
||||
ctx->output_func = output_func;
|
||||
ctx->output_userdata = output_userdata;
|
||||
}
|
||||
|
||||
#define scc_tree_dump_printf(ctx, fmt, ...) \
|
||||
(ctx)->output_func((ctx)->output_userdata, fmt, ##__VA_ARGS__)
|
||||
|
||||
static inline void scc_tree_dump_ctx_drop(scc_tree_dump_ctx_t *ctx) {
|
||||
scc_vec_free(ctx->stack);
|
||||
}
|
||||
|
||||
// 打印缩进
|
||||
static inline void scc_tree_print_indent(scc_tree_dump_ctx_t *ctx) {
|
||||
scc_vec_foreach(ctx->stack, i) {
|
||||
cbool last_child = scc_vec_at(ctx->stack, i);
|
||||
const char *data = null;
|
||||
if (i + 1 == scc_vec_size(ctx->stack)) {
|
||||
// 最后一层打印分支符号
|
||||
data = last_child ? ctx->last_branch : ctx->branch;
|
||||
} else {
|
||||
data = last_child ? ctx->space : ctx->vertical;
|
||||
}
|
||||
Assert(data != null);
|
||||
if (ctx->use_color) {
|
||||
ctx->output_func(ctx->output_userdata, "%s%s%s", ctx->branch_color,
|
||||
data, ctx->reset_color);
|
||||
} else {
|
||||
ctx->output_func(ctx->output_userdata, "%s", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SCC_TREE_DUMP_PRINT_COLORED(ctx, color, before_str, fmt, after_str, \
|
||||
...) \
|
||||
(ctx)->output_func((ctx)->output_userdata, \
|
||||
before_str "%s" fmt "%s" after_str, \
|
||||
(ctx)->use_color ? color : "", ##__VA_ARGS__, \
|
||||
(ctx)->use_color ? ANSI_NONE : "");
|
||||
|
||||
#define SCC_TREE_DUMP_PRINT_AROUND(ctx, color, around_str, fmt, ...) \
|
||||
SCC_TREE_DUMP_PRINT_COLORED(ctx, color, around_str, fmt, around_str, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define SCC_TREE_DUMP_PRINT_PURE(ctx, color, fmt, ...) \
|
||||
SCC_TREE_DUMP_PRINT_COLORED(ctx, color, "", fmt, "", ##__VA_ARGS__)
|
||||
|
||||
// 推入新的层级到栈中
|
||||
static inline void scc_tree_dump_push_level(scc_tree_dump_ctx_t *ctx,
|
||||
cbool is_last_child) {
|
||||
scc_vec_push(ctx->stack, is_last_child);
|
||||
}
|
||||
|
||||
// 弹出当前层级
|
||||
static inline void scc_tree_dump_pop_level(scc_tree_dump_ctx_t *ctx) {
|
||||
(void)scc_vec_pop(ctx->stack);
|
||||
}
|
||||
|
||||
// 获取当前层级深度
|
||||
static inline usize scc_tree_dump_depth(scc_tree_dump_ctx_t *ctx) {
|
||||
return scc_vec_size(ctx->stack);
|
||||
}
|
||||
|
||||
#endif /* __SCC_TREE_DUMP_H__ */
|
||||
126
libs/tree_dump/src/scc_tree_dump.c
Normal file
126
libs/tree_dump/src/scc_tree_dump.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
#define DEFAULT_VERTICAL "| "
|
||||
#define DEFAULT_BRANCH "|-"
|
||||
#define DEFAULT_LAST_BRANCH "`-"
|
||||
#define DEFAULT_SPACE " "
|
||||
#define NODE_COLOR "\033[34m"
|
||||
#define VALUE_COLOR "\033[32m"
|
||||
#define BRANCH_COLOR "\033[33m"
|
||||
#define RESET_COLOR "\033[0m"
|
||||
|
||||
void scc_tree_dump_init(scc_tree_dump_t *td, cbool use_color) {
|
||||
scc_str_init(&td->buf);
|
||||
scc_vec_init(td->stack);
|
||||
td->use_color = use_color;
|
||||
td->line_start = true;
|
||||
|
||||
td->vertical = DEFAULT_VERTICAL;
|
||||
td->branch = DEFAULT_BRANCH;
|
||||
td->last_branch = DEFAULT_LAST_BRANCH;
|
||||
td->space = DEFAULT_SPACE;
|
||||
|
||||
td->node_color = use_color ? NODE_COLOR : "";
|
||||
td->value_color = use_color ? VALUE_COLOR : "";
|
||||
td->branch_color = use_color ? BRANCH_COLOR : "";
|
||||
td->reset_color = use_color ? RESET_COLOR : "";
|
||||
}
|
||||
|
||||
void scc_tree_dump_drop(scc_tree_dump_t *td) {
|
||||
scc_str_drop(&td->buf);
|
||||
scc_vec_free(td->stack);
|
||||
}
|
||||
|
||||
void scc_tree_dump_clear(scc_tree_dump_t *td) {
|
||||
scc_str_clear(&td->buf);
|
||||
td->line_start = true;
|
||||
}
|
||||
|
||||
const char *scc_tree_dump_cstr(scc_tree_dump_t *td) {
|
||||
return scc_str_as_cstr(&td->buf);
|
||||
}
|
||||
|
||||
void scc_tree_dump_flush(scc_tree_dump_t *td,
|
||||
void (*output)(const char *str, usize len, void *user),
|
||||
void *user) {
|
||||
if (td->buf.size > 1 && output) {
|
||||
output(td->buf.data, td->buf.size - 1, user);
|
||||
}
|
||||
scc_tree_dump_clear(td);
|
||||
}
|
||||
|
||||
void scc_tree_dump_begin_line(scc_tree_dump_t *td) {
|
||||
if (!td->line_start) {
|
||||
// 如果不在行首,先换行(表示上一行结束)
|
||||
if (td->buf.size > 1) {
|
||||
scc_str_append_ch(&td->buf, '\n');
|
||||
}
|
||||
}
|
||||
// 输出缩进
|
||||
usize depth = scc_vec_size(td->stack);
|
||||
for (usize i = 0; i < depth; i++) {
|
||||
cbool last = scc_vec_at(td->stack, i);
|
||||
const char *prefix;
|
||||
if (i + 1 == depth) {
|
||||
prefix = last ? td->last_branch : td->branch;
|
||||
} else {
|
||||
prefix = last ? td->space : td->vertical;
|
||||
}
|
||||
if (td->use_color) {
|
||||
scc_str_append_fmt(&td->buf, "%s%s%s", td->branch_color, prefix,
|
||||
td->reset_color);
|
||||
} else {
|
||||
scc_str_append_cstr(&td->buf, prefix, scc_strlen(prefix));
|
||||
}
|
||||
}
|
||||
td->line_start = false;
|
||||
}
|
||||
|
||||
void scc_tree_dump_append(scc_tree_dump_t *td, const char *s) {
|
||||
if (td->line_start) {
|
||||
scc_tree_dump_begin_line(td);
|
||||
}
|
||||
scc_str_append_cstr(&td->buf, s, scc_strlen(s));
|
||||
}
|
||||
|
||||
void scc_tree_dump_append_fmt(scc_tree_dump_t *td, const char *fmt, ...) {
|
||||
if (td->line_start) {
|
||||
scc_tree_dump_begin_line(td);
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// 计算所需长度
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
usize len = scc_vsnprintf(null, 0, fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
if (len == 0) {
|
||||
va_end(args);
|
||||
return;
|
||||
}
|
||||
// 确保缓冲区容量足够
|
||||
if (td->buf.size + len + 1 > td->buf.cap) {
|
||||
usize new_cap = td->buf.cap;
|
||||
while (new_cap < td->buf.size + len + 1) {
|
||||
new_cap = new_cap ? new_cap * 2 : 16;
|
||||
}
|
||||
char *new_data = (char *)scc_realloc(td->buf.data, new_cap);
|
||||
Assert(new_data != null);
|
||||
td->buf.data = new_data;
|
||||
td->buf.cap = new_cap;
|
||||
}
|
||||
scc_vsnprintf(td->buf.data + td->buf.size - (td->buf.size == 0 ? 0 : 1),
|
||||
len + 1, fmt, args);
|
||||
va_end(args);
|
||||
if (td->buf.size == 0) {
|
||||
td->buf.size = 1;
|
||||
}
|
||||
td->buf.size += len;
|
||||
td->buf.data[td->buf.size - 1] = '\0';
|
||||
}
|
||||
|
||||
void scc_tree_dump_push(scc_tree_dump_t *td, cbool is_last) {
|
||||
scc_vec_push(td->stack, is_last);
|
||||
}
|
||||
|
||||
void scc_tree_dump_pop(scc_tree_dump_t *td) { (void)scc_vec_pop(td->stack); }
|
||||
@@ -10,22 +10,22 @@
|
||||
* @brief 动态字符串结构体
|
||||
* @attention 创建的字符串对象需要使用 scc_cstring_free 释放
|
||||
*/
|
||||
typedef struct scc_cstring {
|
||||
typedef struct scc_str {
|
||||
usize size; /**< 字符串当前大小(包括结尾的'\0')*/
|
||||
usize cap; /**< 分配的容量 */
|
||||
char *data; /**< 实际存储数据的指针 */
|
||||
} scc_cstring_t;
|
||||
} scc_str_t;
|
||||
|
||||
/**
|
||||
* @brief 创建一个新的空动态字符串对象
|
||||
*
|
||||
* @return cstring_t 初始化后的对象
|
||||
*/
|
||||
static inline scc_cstring_t scc_cstring_create(void) {
|
||||
return (scc_cstring_t){.data = null, .size = 0, .cap = 0};
|
||||
static inline scc_str_t scc_str_empty(void) {
|
||||
return (scc_str_t){.data = null, .size = 0, .cap = 0};
|
||||
}
|
||||
|
||||
static inline void scc_cstring_init(scc_cstring_t *string) {
|
||||
static inline void scc_str_init(scc_str_t *string) {
|
||||
Assert(string != null);
|
||||
string->data = null;
|
||||
string->size = 0;
|
||||
@@ -38,9 +38,9 @@ static inline void scc_cstring_init(scc_cstring_t *string) {
|
||||
* @param s 输入的 C 风格字符串
|
||||
* @return cstring_t 新建对象,包含输入字符串的副本
|
||||
*/
|
||||
static inline scc_cstring_t scc_cstring_from_cstr(const char *s) {
|
||||
static inline scc_str_t scc_str_from_cstr(const char *s) {
|
||||
if (s == null) {
|
||||
return scc_cstring_create();
|
||||
return scc_str_empty();
|
||||
}
|
||||
|
||||
usize len = 0;
|
||||
@@ -53,11 +53,11 @@ static inline scc_cstring_t scc_cstring_from_cstr(const char *s) {
|
||||
scc_memcpy(data, s, len);
|
||||
data[len] = '\0';
|
||||
|
||||
return (scc_cstring_t){.size = len + 1, .cap = len + 1, .data = data};
|
||||
return (scc_str_t){.size = len + 1, .cap = len + 1, .data = data};
|
||||
}
|
||||
|
||||
static inline scc_cstring_t scc_cstring_copy(const scc_cstring_t *s) {
|
||||
return scc_cstring_from_cstr(s->data);
|
||||
static inline scc_str_t scc_str_copy(const scc_str_t *s) {
|
||||
return scc_str_from_cstr(s->data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ static inline scc_cstring_t scc_cstring_copy(const scc_cstring_t *s) {
|
||||
*
|
||||
* @param str 要被释放的字符串指针
|
||||
*/
|
||||
static inline void scc_cstring_free(scc_cstring_t *str) {
|
||||
static inline void scc_str_drop(scc_str_t *str) {
|
||||
if (str == null) {
|
||||
return;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ static inline void scc_cstring_free(scc_cstring_t *str) {
|
||||
* @param data 要追加的 C 字符串指针
|
||||
* @param len 要追加的 C 字符串长度
|
||||
*/
|
||||
static inline void scc_cstring_append_cstr(scc_cstring_t *str, const char *data,
|
||||
static inline void scc_str_append_cstr(scc_str_t *str, const char *data,
|
||||
usize len) {
|
||||
if (str == null || data == null || len == 0) {
|
||||
return;
|
||||
@@ -127,19 +127,48 @@ static inline void scc_cstring_append_cstr(scc_cstring_t *str, const char *data,
|
||||
* @param str 目标动态字符串指针
|
||||
* @param other 要追加的动态字符串指针
|
||||
*/
|
||||
static inline void scc_cstring_append(scc_cstring_t *str,
|
||||
const scc_cstring_t *other) {
|
||||
scc_cstring_append_cstr(str, other->data, other->size - 1);
|
||||
static inline void scc_str_append(scc_str_t *str, const scc_str_t *other) {
|
||||
scc_str_append_cstr(str, other->data, other->size - 1);
|
||||
}
|
||||
|
||||
#ifndef __SCC_PURE_LIB__
|
||||
#include "scc_core_impl.h"
|
||||
static inline void scc_str_append_fmt(scc_str_t *str, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
usize needed = scc_vsnprintf(null, 0, fmt, args);
|
||||
va_end(args);
|
||||
if (needed == 0)
|
||||
return;
|
||||
|
||||
// 确保容量足够(需要额外空间给 '\0')
|
||||
if (str->size + needed + 1 > str->cap) {
|
||||
usize new_cap = str->cap;
|
||||
while (new_cap < str->size + needed + 1) {
|
||||
new_cap = new_cap ? new_cap * 2 : (needed + 16);
|
||||
}
|
||||
char *new_data = (char *)scc_realloc(str->data, new_cap);
|
||||
Assert(new_data != NULL);
|
||||
str->data = new_data;
|
||||
str->cap = new_cap;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
scc_vsnprintf(str->data + str->size - 1, needed + 1, fmt, args);
|
||||
va_end(args);
|
||||
str->size += needed;
|
||||
// 确保结尾 '\0'(scc_vsnprintf 已添加)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 向动态字符串末尾追加一个字符
|
||||
*
|
||||
* @param str 目标动态字符串指针
|
||||
* @param ch 要追加的字符
|
||||
*/
|
||||
static inline void scc_cstring_append_ch(scc_cstring_t *str, char ch) {
|
||||
scc_cstring_append_cstr(str, &ch, 1);
|
||||
static inline void scc_str_append_ch(scc_str_t *str, char ch) {
|
||||
scc_str_append_cstr(str, &ch, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +177,7 @@ static inline void scc_cstring_append_ch(scc_cstring_t *str, char ch) {
|
||||
* @param str 动态字符串指针
|
||||
* @return usize 字符串实际长度
|
||||
*/
|
||||
static inline usize scc_cstring_len(const scc_cstring_t *str) {
|
||||
static inline usize scc_str_len(const scc_str_t *str) {
|
||||
if (str == null) {
|
||||
return 0;
|
||||
}
|
||||
@@ -164,7 +193,7 @@ static inline usize scc_cstring_len(const scc_cstring_t *str) {
|
||||
* @param str 动态字符串指针
|
||||
* @return cbool
|
||||
*/
|
||||
static inline cbool scc_cstring_is_empty(const scc_cstring_t *str) {
|
||||
static inline cbool scc_str_is_empty(const scc_str_t *str) {
|
||||
return str == null || str->size == 0;
|
||||
}
|
||||
|
||||
@@ -173,7 +202,7 @@ static inline cbool scc_cstring_is_empty(const scc_cstring_t *str) {
|
||||
*
|
||||
* @param str 动态字符串指针
|
||||
*/
|
||||
static inline void scc_cstring_clear(scc_cstring_t *str) {
|
||||
static inline void scc_str_clear(scc_str_t *str) {
|
||||
if (str) {
|
||||
str->size = 1;
|
||||
if (str->data) {
|
||||
@@ -188,19 +217,18 @@ static inline void scc_cstring_clear(scc_cstring_t *str) {
|
||||
* @param str 动态字符串指针
|
||||
* @return char* 返回指向内部缓冲区的 C 风格字符串指针
|
||||
*/
|
||||
static inline char *scc_cstring_as_cstr(const scc_cstring_t *str) {
|
||||
static inline char *scc_str_as_cstr(const scc_str_t *str) {
|
||||
if (str == null || str->data == null) {
|
||||
return null;
|
||||
}
|
||||
return str->data;
|
||||
}
|
||||
|
||||
static inline int scc_cstring_cmp(const scc_cstring_t *str1,
|
||||
const scc_cstring_t *str2) {
|
||||
return scc_strcmp(scc_cstring_as_cstr(str1), scc_cstring_as_cstr(str2));
|
||||
static inline int scc_str_equal(const scc_str_t *str1, const scc_str_t *str2) {
|
||||
return scc_strcmp(scc_str_as_cstr(str1), scc_str_as_cstr(str2));
|
||||
}
|
||||
|
||||
static inline char *scc_cstring_move_cstr(scc_cstring_t *str) {
|
||||
static inline char *scc_str_move_cstr(scc_str_t *str) {
|
||||
if (str == null || str->data == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -211,8 +239,8 @@ static inline char *scc_cstring_move_cstr(scc_cstring_t *str) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline scc_cstring_t scc_cstring_move(scc_cstring_t *str) {
|
||||
return scc_cstring_from_cstr(scc_cstring_move_cstr(str));
|
||||
static inline scc_str_t scc_str_move(scc_str_t *str) {
|
||||
return scc_str_from_cstr(scc_str_move_cstr(str));
|
||||
}
|
||||
|
||||
#endif /* __SCC_CORE_STR_H__ */
|
||||
|
||||
49
src/main.c
49
src/main.c
@@ -24,7 +24,7 @@ static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
|
||||
} else if (verbose >= 1) {
|
||||
scc_printf(
|
||||
"token [%-8s] `%s` at %s:%d:%d\n", scc_get_tok_name(tok.type),
|
||||
tok.type != SCC_TOK_ENDLINE ? scc_cstring_as_cstr(&tok.lexeme)
|
||||
tok.type != SCC_TOK_ENDLINE ? scc_str_as_cstr(&tok.lexeme)
|
||||
: "\\n",
|
||||
tok.loc.name, tok.loc.line, tok.loc.col);
|
||||
}
|
||||
@@ -42,11 +42,11 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) {
|
||||
break;
|
||||
}
|
||||
if (fp == scc_stdout) {
|
||||
scc_printf("%s", scc_cstring_as_cstr(&tok.lexeme));
|
||||
scc_printf("%s", scc_str_as_cstr(&tok.lexeme));
|
||||
} else {
|
||||
usize ret = scc_fwrite(fp, scc_cstring_as_cstr(&tok.lexeme),
|
||||
scc_cstring_len(&tok.lexeme));
|
||||
if (ret != scc_cstring_len(&tok.lexeme)) {
|
||||
usize ret = scc_fwrite(fp, scc_str_as_cstr(&tok.lexeme),
|
||||
scc_str_len(&tok.lexeme));
|
||||
if (ret != scc_str_len(&tok.lexeme)) {
|
||||
LOG_FATAL("Failed to write to file");
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,10 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) {
|
||||
scc_fclose(fp);
|
||||
}
|
||||
|
||||
static void tree_dump_output(const char *str, usize len, void *user) {
|
||||
scc_fprintf(user, "%.*s", (int)len, str);
|
||||
}
|
||||
|
||||
void init_platform(void);
|
||||
|
||||
int main(int argc, const char **argv, const char **envp) {
|
||||
@@ -139,7 +143,7 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
scc_lexer_tok_vec_t pproc_tok_vec;
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
scc_lexer_tok_t tok = {
|
||||
.lexeme = scc_cstring_from_cstr("1"),
|
||||
.lexeme = scc_str_from_cstr("1"),
|
||||
.type = SCC_TOK_INT_LITERAL,
|
||||
.loc.name = "<internal>",
|
||||
.loc.line = 0,
|
||||
@@ -147,10 +151,10 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
.loc.offset = 0,
|
||||
};
|
||||
scc_vec_push(pproc_tok_vec, tok);
|
||||
scc_cstring_t pproc_predefined_macros[] = {
|
||||
scc_cstring_from_cstr("__SCC__"),
|
||||
scc_cstring_from_cstr("_WIN64"),
|
||||
scc_cstring_from_cstr("__x86_64__"),
|
||||
scc_str_t pproc_predefined_macros[] = {
|
||||
scc_str_from_cstr("__SCC__"),
|
||||
scc_str_from_cstr("_WIN64"),
|
||||
scc_str_from_cstr("__x86_64__"),
|
||||
};
|
||||
for (usize i = 0; i < SCC_ARRLEN(pproc_predefined_macros); i += 1) {
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
@@ -193,16 +197,16 @@ sstream_drop:
|
||||
}
|
||||
|
||||
if (config.emit_ast) {
|
||||
scc_tree_dump_ctx_t tree_dump;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == null) {
|
||||
scc_tree_dump_ctx_init(&tree_dump, true, (void *)scc_fprintf,
|
||||
(void *)scc_stdout);
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_ctx_init(&tree_dump, false, (void *)scc_fprintf,
|
||||
(void *)fp);
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit);
|
||||
scc_tree_dump_ctx_drop(&tree_dump);
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output,
|
||||
fp == null ? scc_stdout : fp);
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -216,18 +220,19 @@ sstream_drop:
|
||||
|
||||
if (config.emit_ir) {
|
||||
scc_ir_dump_ctx_t ir_dump_ctx;
|
||||
scc_tree_dump_ctx_t tree_dump;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == null) {
|
||||
scc_tree_dump_ctx_init(&tree_dump, true, (void *)scc_fprintf,
|
||||
(void *)scc_stdout);
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_ctx_init(&tree_dump, false, (void *)scc_fprintf,
|
||||
(void *)fp);
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump, &cprog);
|
||||
// scc_ir_dump_cprog(&ir_dump_ctx);
|
||||
scc_ir_dump_cprog_linear(&ir_dump_ctx);
|
||||
scc_tree_dump_ctx_drop(&tree_dump);
|
||||
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output,
|
||||
fp == null ? scc_stdout : fp);
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "scc_stdio.h"
|
||||
|
||||
int main(void) {
|
||||
puts("hello world");
|
||||
const char *str = "hello world";
|
||||
puts(str);
|
||||
return 0;
|
||||
}
|
||||
9
tests/simple/12_logic.c
Normal file
9
tests/simple/12_logic.c
Normal file
@@ -0,0 +1,9 @@
|
||||
int check(int i) { return i >= 0 && i < 10; }
|
||||
|
||||
int main() {
|
||||
int num = 0;
|
||||
for (int i = 0; check(i); i += 1) {
|
||||
num = num + 1;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
8
tests/simple/13_array.c
Normal file
8
tests/simple/13_array.c
Normal file
@@ -0,0 +1,8 @@
|
||||
int main(void) {
|
||||
char buff[] = "hello buffer";
|
||||
int res = 0;
|
||||
for (char *ptr = buff; *ptr != 0; ptr += 1) {
|
||||
res += *ptr;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
[return_val_cases]
|
||||
# windows: echo $LASTEXITCODE
|
||||
"./01_return.c" = 65536
|
||||
"./02_decl_expr.c" = 1
|
||||
"./03_decl_init.c" = 11
|
||||
@@ -10,4 +11,6 @@
|
||||
"./09_for.c" = 10
|
||||
"./10_main.c" = 3
|
||||
"./11_recursive.c" = 120
|
||||
"./12_logic.c" = 10
|
||||
"./13_array.c" = 1198
|
||||
[stdout_val_cases]
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
#define __SCC_STDIO_H__
|
||||
|
||||
extern int puts(const char *str);
|
||||
extern char *gets(char *buff);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user