Compare commits
2 Commits
cabd1710ed
...
5f915ba8d3
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f915ba8d3 | |||
| 2e5e98868d |
@@ -15,6 +15,8 @@ ir 中间代码标识
|
||||
|
||||
opt 优化器
|
||||
|
||||
asm 汇编器
|
||||
|
||||
mcode 机器码
|
||||
|
||||
sccf 统一输出格式
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef __SCC_AST_BUILTIN_H__
|
||||
#define __SCC_AST_BUILTIN_H__
|
||||
|
||||
#include "ast_def.h"
|
||||
|
||||
extern scc_ast_type_t scc_ast_builtin_type_va_list;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_void;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_bool;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_char;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_short;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_long;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_long_long;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_int;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_float;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_double;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_long_double;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_complex_float;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_complex_double;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_complex_long_double;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_unsigned_char;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_unsigned_short;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_unsigned_int;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_unsigned_long;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_unsigned_long_long;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_signed_char;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_signed_short;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_signed_int;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_signed_long;
|
||||
extern scc_ast_type_t scc_ast_builtin_type_signed_long_long;
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@
|
||||
typedef enum {
|
||||
SCC_AST_UNKNOWN,
|
||||
// 声明
|
||||
scc_ast_decl_t_BEGIN, // 声明开始
|
||||
scc_ast_decl_t_BEGIN, // 声明开始 sema 函数作用域开始
|
||||
SCC_AST_DECL_LIST, // 声明列表
|
||||
SCC_AST_DECL_VAR, // 变量声明
|
||||
SCC_AST_DECL_FUNC, // 函数声明
|
||||
@@ -19,10 +19,10 @@ typedef enum {
|
||||
SCC_AST_DECL_UNION, // 联合声明
|
||||
SCC_AST_DECL_ENUM, // 枚举声明
|
||||
SCC_AST_DECL_TYPEDEF, // typedef 声明
|
||||
scc_ast_decl_t_END, // 声明结束
|
||||
scc_ast_decl_t_END, // 声明结束 sema 函数作用域结束
|
||||
|
||||
// 语句
|
||||
scc_ast_stmt_t_BEGIN, // 语句开始
|
||||
scc_ast_stmt_t_BEGIN, // 语句开始 sema 作用域开始
|
||||
SCC_AST_STMT_COMPOUND, // 复合语句 { ... }
|
||||
SCC_AST_STMT_EXPR, // 表达式语句
|
||||
SCC_AST_STMT_IF, // if 语句
|
||||
@@ -37,7 +37,7 @@ typedef enum {
|
||||
SCC_AST_STMT_RETURN, // return 语句
|
||||
SCC_AST_STMT_GOTO, // goto 语句
|
||||
SCC_AST_STMT_LABEL, // 标签语句
|
||||
scc_ast_stmt_t_END, // 结束语句
|
||||
scc_ast_stmt_t_END, // 结束语句 sema 作用域结束
|
||||
|
||||
// 表达式
|
||||
scc_ast_expr_t_BEGIN, // 表达式开始
|
||||
@@ -180,7 +180,7 @@ struct scc_ast_type {
|
||||
} array;
|
||||
struct {
|
||||
scc_ast_type_t *return_type;
|
||||
scc_ast_decl_vec_t param_types; // va_list <=> ...
|
||||
scc_ast_decl_vec_t params; // va_list <=> ...
|
||||
} function;
|
||||
struct {
|
||||
const char *name;
|
||||
@@ -294,7 +294,6 @@ struct scc_ast_expr {
|
||||
struct {
|
||||
const char *name;
|
||||
scc_ast_expr_t *callee;
|
||||
scc_ast_expr_t *_target;
|
||||
scc_ast_expr_vec_t args;
|
||||
} call;
|
||||
// 数组下标
|
||||
@@ -306,7 +305,7 @@ struct scc_ast_expr {
|
||||
struct {
|
||||
scc_ast_expr_t *base;
|
||||
const char *name;
|
||||
usize _target_idx;
|
||||
usize _target_idx; ///< fill by sema
|
||||
} member;
|
||||
// cast 类型转换
|
||||
struct {
|
||||
@@ -332,7 +331,7 @@ struct scc_ast_expr {
|
||||
// 标识符
|
||||
struct {
|
||||
const char *name;
|
||||
scc_ast_decl_t *_target;
|
||||
scc_ast_decl_t *_target; ///< fill by sema
|
||||
} identifier;
|
||||
struct {
|
||||
scc_ast_type_t *type;
|
||||
@@ -393,6 +392,7 @@ struct scc_ast_stmt {
|
||||
} default_stmt;
|
||||
// break/continue
|
||||
struct {
|
||||
scc_ast_stmt_t *_target; // fill by sema
|
||||
} jump;
|
||||
// return 语句
|
||||
struct {
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#ifndef __SCC_AST_H__
|
||||
#define __SCC_AST_H__
|
||||
|
||||
#include "ast_builtin.h"
|
||||
#include "ast_def.h"
|
||||
#include "ast_dump.h"
|
||||
|
||||
// decls can be null but maybe warning
|
||||
static inline void
|
||||
scc_ast_translation_unit_init(scc_ast_translation_unit_t *translation_unit,
|
||||
scc_ast_decl_vec_t *decls) {
|
||||
scc_ast_decl_vec_t *decls, scc_pos_t loc) {
|
||||
Assert(translation_unit != null);
|
||||
translation_unit->base.type = SCC_AST_TRANSLATION_UNIT;
|
||||
translation_unit->base.loc = scc_pos_create();
|
||||
translation_unit->base.loc = loc;
|
||||
if (decls == null) {
|
||||
scc_vec_init(translation_unit->declarations);
|
||||
} else {
|
||||
@@ -21,9 +20,10 @@ scc_ast_translation_unit_init(scc_ast_translation_unit_t *translation_unit,
|
||||
}
|
||||
|
||||
static inline void scc_ast_decl_list_init(scc_ast_decl_t *decl,
|
||||
scc_ast_decl_vec_t *list_move) {
|
||||
scc_ast_decl_vec_t *list_move,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null && list_move != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_LIST;
|
||||
decl->name = null;
|
||||
decl->list.vars = *list_move;
|
||||
@@ -34,9 +34,10 @@ static inline void scc_ast_decl_list_init(scc_ast_decl_t *decl,
|
||||
static inline void scc_ast_decl_unsafe_val_init(scc_ast_decl_t *decl,
|
||||
scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_expr_t *var_init) {
|
||||
scc_ast_expr_t *var_init,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null && type != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_VAR;
|
||||
decl->name = name;
|
||||
decl->var.type = type;
|
||||
@@ -46,9 +47,10 @@ static inline void scc_ast_decl_unsafe_val_init(scc_ast_decl_t *decl,
|
||||
// var_init can be null
|
||||
static inline void scc_ast_decl_val_init(scc_ast_decl_t *decl,
|
||||
scc_ast_type_t *type, const char *name,
|
||||
scc_ast_expr_t *var_init) {
|
||||
scc_ast_expr_t *var_init,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null && name != null && type != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_VAR;
|
||||
decl->name = name;
|
||||
decl->var.type = type;
|
||||
@@ -59,9 +61,9 @@ static inline void scc_ast_decl_val_init(scc_ast_decl_t *decl,
|
||||
static inline void scc_ast_decl_func_init(scc_ast_decl_t *decl,
|
||||
scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body, scc_pos_t loc) {
|
||||
Assert(decl != null && name != null && type != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_FUNC;
|
||||
decl->name = name;
|
||||
decl->func.type = type;
|
||||
@@ -72,9 +74,9 @@ static inline void scc_ast_decl_func_init(scc_ast_decl_t *decl,
|
||||
// name can be null
|
||||
static inline void scc_ast_decl_param_init(scc_ast_decl_t *decl,
|
||||
scc_ast_type_t *type,
|
||||
const char *name) {
|
||||
const char *name, scc_pos_t loc) {
|
||||
Assert(decl != null && type != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_PARAM;
|
||||
decl->name = name;
|
||||
decl->param.type = type;
|
||||
@@ -83,9 +85,10 @@ static inline void scc_ast_decl_param_init(scc_ast_decl_t *decl,
|
||||
// name and fields can be null
|
||||
static inline void scc_ast_decl_struct_init(scc_ast_decl_t *decl,
|
||||
const char *name,
|
||||
scc_ast_decl_vec_t *fields_move) {
|
||||
scc_ast_decl_vec_t *fields_move,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_STRUCT;
|
||||
decl->name = name;
|
||||
if (fields_move == null) {
|
||||
@@ -99,9 +102,10 @@ static inline void scc_ast_decl_struct_init(scc_ast_decl_t *decl,
|
||||
// name and fields can be null
|
||||
static inline void scc_ast_decl_union_init(scc_ast_decl_t *decl,
|
||||
const char *name,
|
||||
scc_ast_decl_vec_t *fields_move) {
|
||||
scc_ast_decl_vec_t *fields_move,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_UNION;
|
||||
decl->name = name;
|
||||
if (fields_move == null) {
|
||||
@@ -115,9 +119,10 @@ static inline void scc_ast_decl_union_init(scc_ast_decl_t *decl,
|
||||
// name and fields can be null
|
||||
static inline void scc_ast_decl_enum_init(scc_ast_decl_t *decl,
|
||||
const char *name,
|
||||
scc_ast_expr_vec_t *fields_move) {
|
||||
scc_ast_expr_vec_t *fields_move,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_ENUM;
|
||||
decl->name = name;
|
||||
if (fields_move == null) {
|
||||
@@ -130,20 +135,20 @@ static inline void scc_ast_decl_enum_init(scc_ast_decl_t *decl,
|
||||
|
||||
static inline void scc_ast_decl_typedef_init(scc_ast_decl_t *decl,
|
||||
const char *name,
|
||||
scc_ast_type_t *type) {
|
||||
scc_ast_type_t *type,
|
||||
scc_pos_t loc) {
|
||||
Assert(decl != null && name != null && type != null);
|
||||
decl->base.loc = scc_pos_create();
|
||||
decl->base.loc = loc;
|
||||
decl->base.type = SCC_AST_DECL_TYPEDEF;
|
||||
decl->name = name;
|
||||
decl->typedef_decl.type = type;
|
||||
}
|
||||
|
||||
// items can be null
|
||||
static inline void
|
||||
scc_ast_stmt_compound_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_block_item_vec_t *items_move) {
|
||||
static inline void scc_ast_stmt_compound_init(
|
||||
scc_ast_stmt_t *stmt, scc_ast_block_item_vec_t *items_move, scc_pos_t loc) {
|
||||
Assert(stmt != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_COMPOUND;
|
||||
if (items_move == null) {
|
||||
scc_vec_init(stmt->compound.block_items);
|
||||
@@ -155,9 +160,9 @@ scc_ast_stmt_compound_init(scc_ast_stmt_t *stmt,
|
||||
|
||||
// expr can be null
|
||||
static inline void scc_ast_stmt_expr_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *expr) {
|
||||
scc_ast_expr_t *expr, scc_pos_t loc) {
|
||||
Assert(stmt != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_EXPR;
|
||||
stmt->expr.expr = expr;
|
||||
}
|
||||
@@ -166,9 +171,10 @@ static inline void scc_ast_stmt_expr_init(scc_ast_stmt_t *stmt,
|
||||
static inline void scc_ast_stmt_if_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_stmt_t *then,
|
||||
scc_ast_stmt_t *opt_else) {
|
||||
scc_ast_stmt_t *opt_else,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null && cond != null && then != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_IF;
|
||||
stmt->if_stmt.cond = cond;
|
||||
stmt->if_stmt.then_stmt = then;
|
||||
@@ -177,9 +183,10 @@ static inline void scc_ast_stmt_if_init(scc_ast_stmt_t *stmt,
|
||||
|
||||
static inline void scc_ast_stmt_while_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null && cond != null && body != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_WHILE;
|
||||
stmt->while_stmt.cond = cond;
|
||||
stmt->while_stmt.body = body;
|
||||
@@ -187,9 +194,10 @@ static inline void scc_ast_stmt_while_init(scc_ast_stmt_t *stmt,
|
||||
|
||||
static inline void scc_ast_stmt_do_while_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null && cond != null && body != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_DO_WHILE;
|
||||
stmt->while_stmt.cond = cond;
|
||||
stmt->while_stmt.body = body;
|
||||
@@ -200,9 +208,9 @@ static inline void scc_ast_stmt_for_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_type_t *init,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_expr_t *incr,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body, scc_pos_t loc) {
|
||||
Assert(stmt != null && body != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_FOR;
|
||||
stmt->for_stmt.init = init;
|
||||
stmt->for_stmt.cond = cond;
|
||||
@@ -212,9 +220,10 @@ static inline void scc_ast_stmt_for_init(scc_ast_stmt_t *stmt,
|
||||
|
||||
static inline void scc_ast_stmt_switch_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null && cond != null && body != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_SWITCH;
|
||||
stmt->switch_stmt.cond = cond;
|
||||
stmt->switch_stmt.body = body;
|
||||
@@ -222,47 +231,53 @@ static inline void scc_ast_stmt_switch_init(scc_ast_stmt_t *stmt,
|
||||
|
||||
static inline void scc_ast_stmt_case_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body, scc_pos_t loc) {
|
||||
Assert(stmt != null && cond != null && body != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_CASE;
|
||||
stmt->case_stmt.expr = cond;
|
||||
stmt->case_stmt.stmt = body;
|
||||
}
|
||||
|
||||
static inline void scc_ast_stmt_default_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null && body != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_DEFAULT;
|
||||
stmt->default_stmt.stmt = body;
|
||||
}
|
||||
|
||||
static inline void scc_ast_stmt_break_init(scc_ast_stmt_t *stmt) {
|
||||
static inline void scc_ast_stmt_break_init(scc_ast_stmt_t *stmt,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_BREAK;
|
||||
stmt->jump._target = null;
|
||||
}
|
||||
|
||||
static inline void scc_ast_stmt_continue_init(scc_ast_stmt_t *stmt) {
|
||||
static inline void scc_ast_stmt_continue_init(scc_ast_stmt_t *stmt,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_CONTINUE;
|
||||
stmt->jump._target = null;
|
||||
}
|
||||
|
||||
// expr can be null
|
||||
static inline void scc_ast_stmt_return_init(scc_ast_stmt_t *stmt,
|
||||
scc_ast_expr_t *expr) {
|
||||
scc_ast_expr_t *expr,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_RETURN;
|
||||
stmt->return_stmt.expr = expr;
|
||||
}
|
||||
|
||||
static inline void scc_ast_stmt_goto_init(scc_ast_stmt_t *stmt,
|
||||
const char *label) {
|
||||
const char *label, scc_pos_t loc) {
|
||||
Assert(stmt != null && label != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_GOTO;
|
||||
stmt->goto_stmt.label = label;
|
||||
stmt->goto_stmt._target = null;
|
||||
@@ -270,9 +285,10 @@ static inline void scc_ast_stmt_goto_init(scc_ast_stmt_t *stmt,
|
||||
|
||||
static inline void scc_ast_stmt_label_init(scc_ast_stmt_t *stmt,
|
||||
const char *label,
|
||||
scc_ast_stmt_t *body) {
|
||||
scc_ast_stmt_t *body,
|
||||
scc_pos_t loc) {
|
||||
Assert(stmt != null);
|
||||
stmt->base.loc = scc_pos_create();
|
||||
stmt->base.loc = loc;
|
||||
stmt->base.type = SCC_AST_STMT_LABEL;
|
||||
stmt->label_stmt.label = label;
|
||||
stmt->label_stmt.stmt = body;
|
||||
@@ -281,9 +297,10 @@ static inline void scc_ast_stmt_label_init(scc_ast_stmt_t *stmt,
|
||||
static inline void scc_ast_expr_binary_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_op_t op,
|
||||
scc_ast_expr_t *lhs,
|
||||
scc_ast_expr_t *rhs) {
|
||||
scc_ast_expr_t *rhs,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && lhs != null && rhs != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_BINARY;
|
||||
expr->binary.op = op;
|
||||
expr->binary.lhs = lhs;
|
||||
@@ -292,9 +309,10 @@ static inline void scc_ast_expr_binary_init(scc_ast_expr_t *expr,
|
||||
|
||||
static inline void scc_ast_expr_unary_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_op_t op,
|
||||
scc_ast_expr_t *operand) {
|
||||
scc_ast_expr_t *operand,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && operand != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_UNARY;
|
||||
expr->unary.op = op;
|
||||
expr->unary.operand = operand;
|
||||
@@ -303,10 +321,11 @@ static inline void scc_ast_expr_unary_init(scc_ast_expr_t *expr,
|
||||
static inline void scc_ast_expr_cond_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_expr_t *then_expr,
|
||||
scc_ast_expr_t *else_expr) {
|
||||
scc_ast_expr_t *else_expr,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && cond != null && then_expr != null &&
|
||||
else_expr != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_COND;
|
||||
expr->cond.cond = cond;
|
||||
expr->cond.then_expr = then_expr;
|
||||
@@ -316,12 +335,12 @@ static inline void scc_ast_expr_cond_init(scc_ast_expr_t *expr,
|
||||
// args can be null
|
||||
static inline void scc_ast_expr_call_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *callee,
|
||||
scc_ast_expr_vec_t *args) {
|
||||
scc_ast_expr_vec_t *args,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && callee != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_CALL;
|
||||
expr->call.callee = callee;
|
||||
expr->call._target = null;
|
||||
if (args == null) {
|
||||
scc_vec_init(expr->call.args);
|
||||
} else {
|
||||
@@ -332,9 +351,10 @@ static inline void scc_ast_expr_call_init(scc_ast_expr_t *expr,
|
||||
// SCC_AST_EXPR_ARRAY_SUBSCRIPT, // 数组下标
|
||||
static inline void scc_ast_expr_array_subscript_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *array,
|
||||
scc_ast_expr_t *index) {
|
||||
scc_ast_expr_t *index,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && array != null && index != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_ARRAY_SUBSCRIPT;
|
||||
expr->subscript.array = array;
|
||||
expr->subscript.index = index;
|
||||
@@ -343,9 +363,10 @@ static inline void scc_ast_expr_array_subscript_init(scc_ast_expr_t *expr,
|
||||
static inline void _scc_ast_expr_member_init(scc_ast_expr_t *expr,
|
||||
scc_ast_node_type_t type,
|
||||
scc_ast_expr_t *object,
|
||||
const char *member) {
|
||||
const char *member,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && object != null && member != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = type;
|
||||
expr->member.base = object;
|
||||
expr->member.name = member;
|
||||
@@ -354,21 +375,24 @@ static inline void _scc_ast_expr_member_init(scc_ast_expr_t *expr,
|
||||
|
||||
static inline void scc_ast_expr_member_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *object,
|
||||
const char *member) {
|
||||
_scc_ast_expr_member_init(expr, SCC_AST_EXPR_MEMBER, object, member);
|
||||
const char *member, scc_pos_t loc) {
|
||||
_scc_ast_expr_member_init(expr, SCC_AST_EXPR_MEMBER, object, member, loc);
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_ptr_member_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *object,
|
||||
const char *member) {
|
||||
_scc_ast_expr_member_init(expr, SCC_AST_EXPR_PTR_MEMBER, object, member);
|
||||
const char *member,
|
||||
scc_pos_t loc) {
|
||||
_scc_ast_expr_member_init(expr, SCC_AST_EXPR_PTR_MEMBER, object, member,
|
||||
loc);
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_cast_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type,
|
||||
scc_ast_expr_t *operand) {
|
||||
scc_ast_expr_t *operand,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && type != null && operand != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_CAST;
|
||||
expr->cast.type = type;
|
||||
expr->cast.expr = operand;
|
||||
@@ -377,9 +401,10 @@ static inline void scc_ast_expr_cast_init(scc_ast_expr_t *expr,
|
||||
// type and target_expr can be null but it only one of them can be null
|
||||
static inline void scc_ast_expr_sizeof_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type,
|
||||
scc_ast_expr_t *target_expr) {
|
||||
scc_ast_expr_t *target_expr,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_SIZE_OF;
|
||||
expr->attr_of.type = type;
|
||||
expr->attr_of.expr = target_expr;
|
||||
@@ -388,10 +413,12 @@ static inline void scc_ast_expr_sizeof_init(scc_ast_expr_t *expr,
|
||||
// type and target_expr can be null but it only one of them can be null
|
||||
static inline void scc_ast_expr_alignof_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type,
|
||||
scc_ast_expr_t *target_expr) {
|
||||
scc_ast_expr_t *target_expr,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.type = SCC_AST_EXPR_SIZE_OF;
|
||||
expr->base.loc = loc;
|
||||
expr->base.type =
|
||||
SCC_AST_EXPR_SIZE_OF; // 注意:这里使用了 SIZE_OF,可能需要改为 ALIGN_OF
|
||||
expr->attr_of.type = type;
|
||||
expr->attr_of.expr = target_expr;
|
||||
}
|
||||
@@ -400,9 +427,10 @@ static inline void scc_ast_expr_alignof_init(scc_ast_expr_t *expr,
|
||||
static inline void scc_ast_expr_compound_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *base,
|
||||
scc_ast_expr_vec_t *lhs_exprs,
|
||||
scc_ast_expr_vec_t *rhs_exprs) {
|
||||
scc_ast_expr_vec_t *rhs_exprs,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && base != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_COMPOUND;
|
||||
expr->compound.base = base;
|
||||
|
||||
@@ -423,67 +451,77 @@ static inline void scc_ast_expr_compound_init(scc_ast_expr_t *expr,
|
||||
|
||||
static inline void scc_ast_expr_literal_init(scc_ast_expr_t *expr,
|
||||
scc_ast_node_type_t type,
|
||||
const char *value, cbool owned) {
|
||||
const char *value, cbool owned,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && value != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = type;
|
||||
expr->literal.lexme = value;
|
||||
expr->literal.owned = owned;
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_literal_int_init(scc_ast_expr_t *expr,
|
||||
const char *value,
|
||||
cbool owned) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_INT_LITERAL, value, owned);
|
||||
const char *value, cbool owned,
|
||||
scc_pos_t loc) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_INT_LITERAL, value, owned,
|
||||
loc);
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_literal_float_init(scc_ast_expr_t *expr,
|
||||
const char *value,
|
||||
cbool owned) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_FLOAT_LITERAL, value, owned);
|
||||
cbool owned, scc_pos_t loc) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_FLOAT_LITERAL, value, owned,
|
||||
loc);
|
||||
}
|
||||
static inline void scc_ast_expr_literal_char_init(scc_ast_expr_t *expr,
|
||||
const char *value,
|
||||
cbool owned) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_CHAR_LITERAL, value, owned);
|
||||
cbool owned, scc_pos_t loc) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_CHAR_LITERAL, value, owned,
|
||||
loc);
|
||||
}
|
||||
static inline void scc_ast_expr_literal_string_init(scc_ast_expr_t *expr,
|
||||
const char *value,
|
||||
cbool owned) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_STRING_LITERAL, value, owned);
|
||||
cbool owned,
|
||||
scc_pos_t loc) {
|
||||
scc_ast_expr_literal_init(expr, SCC_AST_EXPR_STRING_LITERAL, value, owned,
|
||||
loc);
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_identifier_init(scc_ast_expr_t *expr,
|
||||
const char *name) {
|
||||
const char *name,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && name != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_IDENTIFIER;
|
||||
expr->identifier.name = name;
|
||||
expr->identifier._target = null;
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_lvalue_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type) {
|
||||
scc_ast_type_t *type,
|
||||
scc_pos_t loc) {
|
||||
Assert(expr != null && type != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.loc = loc;
|
||||
expr->base.type = SCC_AST_EXPR_LVALUE;
|
||||
expr->lvalue.type = type;
|
||||
}
|
||||
|
||||
// have defined builtin type
|
||||
static inline void _scc_ast_type_builtin_init(scc_ast_type_t *type,
|
||||
scc_ast_builtin_type_t builtin) {
|
||||
static inline void scc_ast_type_builtin_init(scc_ast_type_t *type,
|
||||
scc_ast_builtin_type_t builtin,
|
||||
scc_pos_t loc) {
|
||||
Assert(type != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = SCC_AST_TYPE_BUILTIN;
|
||||
type->builtin.type = builtin;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
}
|
||||
|
||||
static inline void scc_ast_type_pointer_init(scc_ast_type_t *type,
|
||||
scc_ast_type_t *pointee) {
|
||||
scc_ast_type_t *pointee,
|
||||
scc_pos_t loc) {
|
||||
Assert(type != null && pointee != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = SCC_AST_TYPE_POINTER;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->pointer.pointee = pointee;
|
||||
@@ -492,9 +530,10 @@ static inline void scc_ast_type_pointer_init(scc_ast_type_t *type,
|
||||
// size can be null
|
||||
static inline void scc_ast_type_array_init(scc_ast_type_t *type,
|
||||
scc_ast_type_t *element,
|
||||
scc_ast_expr_t *size) {
|
||||
scc_ast_expr_t *size,
|
||||
scc_pos_t loc) {
|
||||
Assert(type != null && element != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = SCC_AST_TYPE_ARRAY;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->array.element = element;
|
||||
@@ -504,16 +543,17 @@ static inline void scc_ast_type_array_init(scc_ast_type_t *type,
|
||||
// return_type and params can be null
|
||||
static inline void scc_ast_type_function_init(scc_ast_type_t *type,
|
||||
scc_ast_type_t *return_type,
|
||||
scc_ast_decl_vec_t *params) {
|
||||
scc_ast_decl_vec_t *params,
|
||||
scc_pos_t loc) {
|
||||
Assert(type != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = SCC_AST_TYPE_FUNCTION;
|
||||
type->function.return_type = return_type;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
if (params == null) {
|
||||
scc_vec_init(type->function.param_types);
|
||||
scc_vec_init(type->function.params);
|
||||
} else {
|
||||
type->function.param_types = *params;
|
||||
type->function.params = *params;
|
||||
scc_vec_init(*params);
|
||||
}
|
||||
}
|
||||
@@ -521,9 +561,10 @@ static inline void scc_ast_type_function_init(scc_ast_type_t *type,
|
||||
static inline void _scc_ast_type_record_init(scc_ast_type_t *type,
|
||||
scc_ast_node_type_t type_kind,
|
||||
const char *name,
|
||||
scc_ast_decl_t *decl) {
|
||||
scc_ast_decl_t *decl,
|
||||
scc_pos_t loc) {
|
||||
Assert(type != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = type_kind;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->record.name = name;
|
||||
@@ -533,23 +574,25 @@ static inline void _scc_ast_type_record_init(scc_ast_type_t *type,
|
||||
// name and decl can be null
|
||||
static inline void scc_ast_type_struct_init(scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_decl_t *decl) {
|
||||
_scc_ast_type_record_init(type, SCC_AST_TYPE_STRUCT, name, decl);
|
||||
scc_ast_decl_t *decl,
|
||||
scc_pos_t loc) {
|
||||
_scc_ast_type_record_init(type, SCC_AST_TYPE_STRUCT, name, decl, loc);
|
||||
}
|
||||
|
||||
// name and decl can be null
|
||||
static inline void scc_ast_type_union_init(scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_decl_t *decl) {
|
||||
_scc_ast_type_record_init(type, SCC_AST_TYPE_UNION, name, decl);
|
||||
scc_ast_decl_t *decl,
|
||||
scc_pos_t loc) {
|
||||
_scc_ast_type_record_init(type, SCC_AST_TYPE_UNION, name, decl, loc);
|
||||
}
|
||||
|
||||
// name and decl can be null
|
||||
static inline void scc_ast_type_enum_init(scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_decl_t *decl) {
|
||||
scc_ast_decl_t *decl, scc_pos_t loc) {
|
||||
Assert(type != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = SCC_AST_TYPE_ENUM;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->enumeration.name = name;
|
||||
@@ -558,9 +601,10 @@ static inline void scc_ast_type_enum_init(scc_ast_type_t *type,
|
||||
|
||||
static inline void scc_ast_type_typedef_init(scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_decl_t *target) {
|
||||
scc_ast_decl_t *target,
|
||||
scc_pos_t loc) {
|
||||
Assert(type != null && target != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.loc = loc;
|
||||
type->base.type = SCC_AST_TYPE_TYPEDEF;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->typedef_type.name = name;
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
#include <ast_builtin.h>
|
||||
|
||||
#define SCC_AST_BUILTIN_TYPE_HEADER \
|
||||
.base.type = SCC_AST_TYPE_BUILTIN, .base.loc.col = 0, .base.loc.line = 0, \
|
||||
.base.loc.name = "__scc_ast_builtin_type", .base.loc.offset = 0
|
||||
|
||||
// va_list
|
||||
scc_ast_type_t scc_ast_builtin_type_va_list = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_VA_LIST,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_void = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_VOID,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_bool = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_BOOL,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_char = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_CHAR,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_short = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_SHORT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_int = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_INT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_long = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_LONG,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_long_long = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_LONG_LONG,
|
||||
};
|
||||
|
||||
// unsigned 类型
|
||||
scc_ast_type_t scc_ast_builtin_type_unsigned_char = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_unsigned_short = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_unsigned_int = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_INT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_unsigned_long = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_unsigned_long_long = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
|
||||
};
|
||||
|
||||
// signed 类型(实际上与默认相同,但为了完整性)
|
||||
scc_ast_type_t scc_ast_builtin_type_signed_char = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_CHAR,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_signed_short = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_SHORT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_signed_int = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_INT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_signed_long = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_signed_long_long = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_float = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_FLOAT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_double = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_DOUBLE,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_long_double = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_LONG_DOUBLE,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_complex_float = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_complex_double = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE,
|
||||
};
|
||||
|
||||
scc_ast_type_t scc_ast_builtin_type_complex_long_double = {
|
||||
SCC_AST_BUILTIN_TYPE_HEADER,
|
||||
.builtin.type = SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE,
|
||||
};
|
||||
@@ -347,10 +347,9 @@ static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_ctx_t *ctx) {
|
||||
(void)scc_vec_pop(ctx->stack);
|
||||
|
||||
scc_vec_push(ctx->stack, true);
|
||||
if (scc_vec_size(type->function.param_types) != 0) {
|
||||
scc_vec_foreach(type->function.param_types, i) {
|
||||
scc_ast_decl_t *param =
|
||||
scc_vec_at(type->function.param_types, i);
|
||||
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
|
||||
}
|
||||
|
||||
@@ -5,8 +5,22 @@
|
||||
#include <scc_ast.h>
|
||||
#include <scc_ir.h>
|
||||
|
||||
void scc_ast2ir_translation_unit(scc_ir_builder_t *builder,
|
||||
scc_ast_translation_unit_t *tu,
|
||||
const scc_type_abi_t *abi);
|
||||
typedef struct {
|
||||
scc_ir_builder_t builder;
|
||||
scc_hashtable_t node2ir; ///< decl to ir_ref
|
||||
scc_hashtable_t symtab; ///< symbol to ir_ref
|
||||
scc_strpool_t strpool; ///< string pool
|
||||
const scc_type_abi_t *abi;
|
||||
} scc_ast2ir_ctx_t;
|
||||
|
||||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *abi);
|
||||
|
||||
void scc_ast2ir_translation_unit(scc_ast2ir_ctx_t *ctx,
|
||||
scc_ast_translation_unit_t *tu);
|
||||
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl);
|
||||
scc_ir_node_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr);
|
||||
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, scc_ast_stmt_t *stmt);
|
||||
scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
scc_ast_type_t *ast_type);
|
||||
|
||||
#endif /* __SCC_AST2IR_H__ */
|
||||
|
||||
@@ -1,561 +0,0 @@
|
||||
#include <ir_builtin.h>
|
||||
#include <scc_ast2ir.h>
|
||||
|
||||
static scc_ir_node_ref_t ast_expr_to_ir(scc_ir_builder_t *ctx,
|
||||
scc_ast_expr_t *expr);
|
||||
static void ast_stmt_to_ir(scc_ir_builder_t *ctx, scc_ast_stmt_t *stmt);
|
||||
static void ast_decl_to_ir(scc_ir_builder_t *ctx, scc_ast_decl_t *decl);
|
||||
static scc_ir_type_ref_t ast_type_to_ir_type(scc_ir_builder_t *ctx,
|
||||
scc_ast_type_t *ast_type);
|
||||
|
||||
// 转换AST类型为IR类型
|
||||
static scc_ir_type_ref_t ast_type_to_ir_type(scc_ir_builder_t *ctx,
|
||||
scc_ast_type_t *ast_type) {
|
||||
if (ctx == null || ast_type == null) {
|
||||
LOG_ERROR("args is null");
|
||||
return 0;
|
||||
}
|
||||
scc_ir_type_t ir_type;
|
||||
|
||||
switch (ast_type->base.type) {
|
||||
case SCC_AST_TYPE_BUILTIN: {
|
||||
// 映射内置类型
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_I32);
|
||||
// TODO: 根据具体内置类型设置
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_TYPE_POINTER: {
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_PTR);
|
||||
|
||||
// 创建指向类型并添加到程序类型列表
|
||||
scc_ir_type_ref_t pointee_type =
|
||||
ast_type_to_ir_type(ctx, ast_type->pointer.pointee);
|
||||
|
||||
// 注意:我们需要找到一种合适的方式来存储类型信息
|
||||
// 目前的IR设计中类型信息应该直接存储在类型结构中
|
||||
ir_type.data.pointer.base = pointee_type;
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_TYPE_ARRAY: {
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_ARRAY);
|
||||
|
||||
// 创建元素类型并添加到程序类型列表
|
||||
scc_ir_type_ref_t element_type =
|
||||
ast_type_to_ir_type(ctx, ast_type->array.element);
|
||||
|
||||
// 将类型添加到程序的类型容器中
|
||||
ir_type.data.array.base = element_type;
|
||||
// TODO: 处理数组大小表达式
|
||||
ir_type.data.array.len = 0; // 暂时设为0
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_TYPE_FUNCTION: {
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_FUNC);
|
||||
|
||||
// 处理返回类型
|
||||
scc_ir_type_ref_t ret_type =
|
||||
ast_type_to_ir_type(ctx, ast_type->function.return_type);
|
||||
|
||||
// 将返回类型添加到程序的类型容器中
|
||||
ir_type.data.function.ret_type = ret_type;
|
||||
|
||||
// 转换参数类型
|
||||
scc_ir_type_ref_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_foreach(ast_type->function.param_types, i) {
|
||||
scc_ast_decl_t *decl_param =
|
||||
scc_vec_at(ast_type->function.param_types, i);
|
||||
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
|
||||
scc_ir_type_ref_t tmp_type =
|
||||
ast_type_to_ir_type(ctx, decl_param->param.type);
|
||||
scc_vec_push(params, tmp_type);
|
||||
}
|
||||
ir_type.data.function.params = params;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported AST type: %d", ast_type->base.type);
|
||||
return 0;
|
||||
}
|
||||
return scc_ir_ctx_new_type(&ctx->ctx, &ir_type);
|
||||
}
|
||||
|
||||
// 转换AST表达式为IR节点
|
||||
static scc_ir_node_ref_t ast_expr_to_ir(scc_ir_builder_t *ctx,
|
||||
scc_ast_expr_t *expr) {
|
||||
if (ctx == null || expr == null) {
|
||||
LOG_ERROR("args is null");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (expr->base.type) {
|
||||
case SCC_AST_EXPR_IDENTIFIER: {
|
||||
// TODO maybe error or need symtab
|
||||
scc_ir_node_t in;
|
||||
scc_ir_node_init(&in, expr->identifier.name, SCC_IR_NODE_LOAD);
|
||||
return scc_ir_ctx_new_node(&ctx->ctx, &in);
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_INT_LITERAL: {
|
||||
// TODO parse i32 value
|
||||
return scc_ir_ctx_get_i32_const(&ctx->ctx, 0);
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_BINARY: {
|
||||
// 转换左右操作数
|
||||
scc_ir_node_ref_t lhs, rhs;
|
||||
lhs = ast_expr_to_ir(ctx, expr->binary.lhs);
|
||||
rhs = ast_expr_to_ir(ctx, expr->binary.rhs);
|
||||
|
||||
// 映射操作符
|
||||
scc_ir_op_type_t op;
|
||||
switch (expr->binary.op) {
|
||||
/* clang-format off */
|
||||
case SCC_AST_OP_ADD: op = SCC_IR_OP_ADD; break;
|
||||
case SCC_AST_OP_SUB: op = SCC_IR_OP_SUB; break;
|
||||
case SCC_AST_OP_MUL: op = SCC_IR_OP_MUL; break;
|
||||
case SCC_AST_OP_DIV: op = SCC_IR_OP_DIV; break;
|
||||
case SCC_AST_OP_MOD: op = SCC_IR_OP_MOD; break;
|
||||
case SCC_AST_OP_LOGICAL_AND: op = SCC_IR_OP_AND; break;
|
||||
case SCC_AST_OP_LOGICAL_OR: op = SCC_IR_OP_OR; break;
|
||||
case SCC_AST_OP_BITWISE_XOR: op = SCC_IR_OP_XOR; break;
|
||||
case SCC_AST_OP_LEFT_SHIFT: op = SCC_IR_OP_SHL; break;
|
||||
case SCC_AST_OP_RIGHT_SHIFT: op = SCC_IR_OP_SHR; break;
|
||||
case SCC_AST_OP_EQUAL: op = SCC_IR_OP_EQ; break;
|
||||
case SCC_AST_OP_NOT_EQUAL: op = SCC_IR_OP_NEQ; break;
|
||||
case SCC_AST_OP_LESS: op = SCC_IR_OP_LT; break;
|
||||
case SCC_AST_OP_LESS_EQUAL: op = SCC_IR_OP_LE; break;
|
||||
case SCC_AST_OP_GREATER: op = SCC_IR_OP_GT; break;
|
||||
case SCC_AST_OP_GREATER_EQUAL: op = SCC_IR_OP_GE; break;
|
||||
case SCC_AST_OP_ASSIGN: {
|
||||
// 赋值表达式:存储右值到左值位置
|
||||
return scc_ir_builder_store(ctx, lhs, rhs);
|
||||
|
||||
}
|
||||
case SCC_AST_OP_ASSIGN_ADD:
|
||||
TODO();
|
||||
/* clang-format on */
|
||||
default:
|
||||
LOG_WARN("Unsupported binary operator: %d", expr->binary.op);
|
||||
op = SCC_IR_OP_ADD; // 默认
|
||||
}
|
||||
|
||||
// 创建操作节点
|
||||
return scc_ir_builder_binop(ctx, op, lhs, rhs);
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_UNARY: {
|
||||
// 转换操作数
|
||||
scc_ir_node_ref_t operand = ast_expr_to_ir(ctx, expr->unary.operand);
|
||||
|
||||
// 映射一元操作符
|
||||
switch (expr->unary.op) {
|
||||
case SCC_AST_OP_SUB:
|
||||
// 负号
|
||||
// 实现为0 - operand
|
||||
return scc_ir_builder_binop(ctx, SCC_IR_OP_SUB,
|
||||
scc_ir_ctx_get_builtin_zero(&ctx->ctx),
|
||||
operand);
|
||||
case SCC_AST_OP_BITWISE_NOT:
|
||||
// 按位取反
|
||||
return scc_ir_builder_binop(ctx, SCC_IR_OP_NOT, operand, 0);
|
||||
case SCC_AST_OP_LOGICAL_NOT:
|
||||
// 逻辑非
|
||||
// 实现为与0比较
|
||||
return scc_ir_builder_binop(ctx, SCC_IR_OP_EQ,
|
||||
scc_ir_ctx_get_builtin_zero(&ctx->ctx),
|
||||
operand);
|
||||
default:
|
||||
LOG_WARN("Unsupported unary operator: %d", expr->unary.op);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_COND: {
|
||||
TODO();
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_CALL: {
|
||||
// 转换参数
|
||||
scc_ir_node_ref_vec_t args;
|
||||
scc_vec_init(args);
|
||||
|
||||
// 检查参数是否为空
|
||||
if (expr->call.args.data != null) {
|
||||
scc_vec_foreach(expr->call.args, i) {
|
||||
scc_ast_expr_t *arg_expr = scc_vec_at(expr->call.args, i);
|
||||
scc_ir_node_ref_t arg_node;
|
||||
arg_node = ast_expr_to_ir(ctx, arg_expr);
|
||||
scc_vec_push(args, arg_node);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建调用节点(需要查找函数定义)
|
||||
// TODO: 需要符号表查找函数
|
||||
scc_ir_node_ref_t func =
|
||||
scc_ir_builder_call(ctx, 0, args.data, args.size);
|
||||
scc_vec_free(args);
|
||||
return func;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_WARN("Unsupported expression type: %d", expr->base.type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 转换AST语句为IR
|
||||
static void ast_stmt_to_ir(scc_ir_builder_t *ctx, scc_ast_stmt_t *stmt) {
|
||||
if (stmt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (stmt->base.type) {
|
||||
case SCC_AST_STMT_COMPOUND: {
|
||||
// 进入新的作用域
|
||||
scc_vec_foreach(stmt->compound.block_items, i) {
|
||||
scc_ast_node_t *child_stmt =
|
||||
scc_vec_at(stmt->compound.block_items, i);
|
||||
if (SCC_AST_IS_A(scc_ast_stmt_t, child_stmt)) {
|
||||
ast_stmt_to_ir(ctx,
|
||||
SCC_AST_CAST_TO(scc_ast_stmt_t, child_stmt));
|
||||
} else if (SCC_AST_IS_A(scc_ast_decl_t, child_stmt)) {
|
||||
ast_decl_to_ir(ctx,
|
||||
SCC_AST_CAST_TO(scc_ast_decl_t, child_stmt));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_STMT_EXPR: {
|
||||
ast_expr_to_ir(ctx, stmt->expr.expr);
|
||||
break;
|
||||
}
|
||||
|
||||
// case SCC_AST_STMT_IF: {
|
||||
// // 创建基本块 - 统一使用栈上分配
|
||||
// scc_ir_bblock_t true_block;
|
||||
// scc_ir_bblock_init(&true_block, "if_true");
|
||||
|
||||
// scc_ir_bblock_t false_block;
|
||||
// scc_ir_bblock_init(&false_block, "if_false");
|
||||
|
||||
// scc_ir_bblock_t merge_block;
|
||||
// scc_ir_bblock_init(&merge_block, "if_merge");
|
||||
|
||||
// // 转换条件
|
||||
// scc_ir_node_ref_t cond_node = ast_expr_to_ir(ctx,
|
||||
// stmt->if_stmt.cond);
|
||||
|
||||
// // 创建分支指令
|
||||
// scc_ir_builder_branch();
|
||||
// scc_ir_node_t br_node;
|
||||
// init_branch_node(&br_node, cond, &true_block, &false_block);
|
||||
// emit_instruction(ctx, &br_node);
|
||||
|
||||
// // 保存当前块
|
||||
// ast2ir_ctx_t saved = ctx->current_ctx;
|
||||
|
||||
// // 生成true分支
|
||||
// emit_basicblock(ctx, &true_block);
|
||||
// ast_stmt_to_ir(ctx, stmt->if_stmt.then_stmt);
|
||||
|
||||
// // 跳转到合并块
|
||||
// scc_ir_node_t jump_node;
|
||||
// init_jump_node(&jump_node, &merge_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 生成false分支(如果有)
|
||||
// emit_basicblock(ctx, &false_block);
|
||||
// if (stmt->if_stmt.opt_else_stmt) {
|
||||
// ast_stmt_to_ir(ctx, stmt->if_stmt.opt_else_stmt);
|
||||
// }
|
||||
|
||||
// // 跳转到合并块
|
||||
// init_jump_node(&jump_node, &merge_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 恢复上下文并设置当前块为合并块
|
||||
// ctx->current_ctx = saved;
|
||||
// emit_basicblock(ctx, &merge_block);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case SCC_AST_STMT_WHILE: {
|
||||
// // 创建基本块 - 统一使用栈上分配
|
||||
// scc_ir_bblock_t cond_block;
|
||||
// scc_ir_bblock_init(&cond_block, "while_cond");
|
||||
|
||||
// scc_ir_bblock_t body_block;
|
||||
// scc_ir_bblock_init(&body_block, "while_body");
|
||||
|
||||
// scc_ir_bblock_t exit_block;
|
||||
// scc_ir_bblock_init(&exit_block, "while_exit");
|
||||
|
||||
// // 跳转到条件块
|
||||
// scc_ir_node_t jump_node;
|
||||
// init_jump_node(&jump_node, &cond_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 保存当前块
|
||||
// ast2ir_ctx_t saved = ctx->current_ctx;
|
||||
|
||||
// // 生成条件块
|
||||
// emit_basicblock(ctx, &cond_block);
|
||||
// scc_ir_node_t cond_node;
|
||||
// ast_expr_to_ir(ctx, stmt->while_stmt.cond, &cond_node);
|
||||
|
||||
// // 将条件节点添加到程序节点列表
|
||||
// scc_vec_push(ctx->program->global_vals, cond_node);
|
||||
// scc_ir_node_t *cond =
|
||||
// &scc_vec_at(ctx->program->global_vals,
|
||||
// scc_vec_size(ctx->program->global_vals) - 1);
|
||||
|
||||
// // 创建分支
|
||||
// scc_ir_node_t br_node;
|
||||
// init_branch_node(&br_node, cond, &body_block, &exit_block);
|
||||
// emit_instruction(ctx, &br_node);
|
||||
|
||||
// // 生成循环体
|
||||
// emit_basicblock(ctx, &body_block);
|
||||
// ast_stmt_to_ir(ctx, stmt->while_stmt.body);
|
||||
|
||||
// // 跳转回条件块
|
||||
// init_jump_node(&jump_node, &cond_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 恢复上下文并设置当前块为退出块
|
||||
// ctx->current_ctx = saved;
|
||||
// emit_basicblock(ctx, &exit_block);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case SCC_AST_STMT_DO_WHILE: {
|
||||
// // 创建基本块 - 统一使用栈上分配
|
||||
// scc_ir_bblock_t cond_block;
|
||||
// scc_ir_bblock_init(&cond_block, "do_while_cond");
|
||||
|
||||
// scc_ir_bblock_t body_block;
|
||||
// scc_ir_bblock_init(&body_block, "do_while_body");
|
||||
|
||||
// scc_ir_bblock_t exit_block;
|
||||
// scc_ir_bblock_init(&exit_block, "do_while_exit");
|
||||
|
||||
// // 跳转到循环体块
|
||||
// scc_ir_node_t jump_node;
|
||||
// init_jump_node(&jump_node, &body_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 保存当前块
|
||||
// ast2ir_ctx_t saved = ctx->current_ctx;
|
||||
|
||||
// // 生成循环体
|
||||
// emit_basicblock(ctx, &body_block);
|
||||
// ast_stmt_to_ir(ctx, stmt->do_while_stmt.body);
|
||||
|
||||
// // 跳转到条件块
|
||||
// init_jump_node(&jump_node, &cond_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 生成条件块
|
||||
// emit_basicblock(ctx, &cond_block);
|
||||
// scc_ir_node_t cond_node;
|
||||
// ast_expr_to_ir(ctx, stmt->do_while_stmt.cond, &cond_node);
|
||||
|
||||
// // 将条件节点添加到程序节点列表
|
||||
// scc_vec_push(ctx->program->global_vals, cond_node);
|
||||
// scc_ir_node_t *cond =
|
||||
// &scc_vec_at(ctx->program->global_vals,
|
||||
// scc_vec_size(ctx->program->global_vals) - 1);
|
||||
|
||||
// // 创建分支
|
||||
// scc_ir_node_t br_node;
|
||||
// init_branch_node(&br_node, cond, &body_block, &exit_block);
|
||||
// emit_instruction(ctx, &br_node);
|
||||
|
||||
// // 恢复上下文并设置当前块为退出块
|
||||
// ctx->current_ctx = saved;
|
||||
// emit_basicblock(ctx, &exit_block);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case SCC_AST_STMT_FOR: {
|
||||
// // 初始化部分
|
||||
// if (SCC_AST_IS_A(scc_ast_expr_t, stmt->for_stmt.init)) {
|
||||
// scc_ir_node_t dummy_node;
|
||||
// ast_expr_to_ir(ctx,
|
||||
// SCC_AST_CAST_TO(scc_ast_expr_t,
|
||||
// stmt->for_stmt.init), &dummy_node);
|
||||
// } else if (SCC_AST_IS_A(scc_ast_decl_t, stmt->for_stmt.init)) {
|
||||
// ast_decl_to_ir(
|
||||
// ctx, SCC_AST_CAST_TO(scc_ast_decl_t,
|
||||
// stmt->for_stmt.init));
|
||||
// } else {
|
||||
// UNREACHABLE();
|
||||
// }
|
||||
|
||||
// // 创建基本块 - 统一使用栈上分配
|
||||
// scc_ir_bblock_t cond_block;
|
||||
// scc_ir_bblock_init(&cond_block, "for_cond");
|
||||
|
||||
// scc_ir_bblock_t body_block;
|
||||
// scc_ir_bblock_init(&body_block, "for_body");
|
||||
|
||||
// scc_ir_bblock_t exit_block;
|
||||
// scc_ir_bblock_init(&exit_block, "for_exit");
|
||||
|
||||
// // 跳转到条件块
|
||||
// scc_ir_node_t jump_node;
|
||||
// init_jump_node(&jump_node, &cond_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 保存当前块
|
||||
// ast2ir_ctx_t saved = ctx->current_ctx;
|
||||
|
||||
// // 生成条件块
|
||||
// emit_basicblock(ctx, &cond_block);
|
||||
|
||||
// scc_ir_node_t *cond = null;
|
||||
// if (stmt->for_stmt.cond) {
|
||||
// scc_ir_node_t cond_node;
|
||||
// ast_expr_to_ir(ctx, stmt->for_stmt.cond, &cond_node);
|
||||
|
||||
// // 将条件节点添加到程序节点列表
|
||||
// scc_vec_push(ctx->program->global_vals, cond_node);
|
||||
// cond = &scc_vec_at(ctx->program->global_vals,
|
||||
// scc_vec_size(ctx->program->global_vals) -
|
||||
// 1);
|
||||
// } else {
|
||||
// // 无条件循环,条件为真
|
||||
// scc_ir_node_t true_node;
|
||||
// init_const_int_node(&true_node, 1, null);
|
||||
|
||||
// // 将true节点添加到程序节点列表
|
||||
// scc_vec_push(ctx->program->global_vals, true_node);
|
||||
// cond = &scc_vec_at(ctx->program->global_vals,
|
||||
// scc_vec_size(ctx->program->global_vals) -
|
||||
// 1);
|
||||
// }
|
||||
|
||||
// // 创建分支
|
||||
// scc_ir_node_t br_node;
|
||||
// init_branch_node(&br_node, cond, &body_block, &exit_block);
|
||||
// emit_instruction(ctx, &br_node);
|
||||
|
||||
// // 生成循环体
|
||||
// emit_basicblock(ctx, &body_block);
|
||||
// ast_stmt_to_ir(ctx, stmt->for_stmt.body);
|
||||
|
||||
// // 执行迭代表达式(如果存在)
|
||||
// if (stmt->for_stmt.incr) {
|
||||
// scc_ir_node_t dummy_node;
|
||||
// ast_expr_to_ir(ctx, stmt->for_stmt.incr, &dummy_node);
|
||||
// }
|
||||
|
||||
// // 跳转回条件块
|
||||
// init_jump_node(&jump_node, &cond_block);
|
||||
// emit_instruction(ctx, &jump_node);
|
||||
|
||||
// // 恢复上下文并设置当前块为退出块
|
||||
// ctx->current_ctx = saved;
|
||||
// emit_basicblock(ctx, &exit_block);
|
||||
// break;
|
||||
// }
|
||||
|
||||
case SCC_AST_STMT_RETURN: {
|
||||
if (stmt->return_stmt.expr) {
|
||||
scc_ir_node_ref_t ret_val_node =
|
||||
ast_expr_to_ir(ctx, stmt->return_stmt.expr);
|
||||
|
||||
scc_ir_builder_ret(ctx, ret_val_node);
|
||||
} else {
|
||||
scc_ir_builder_ret_void(ctx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_WARN("Unsupported statement type: %d", stmt->base.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 转换AST声明为IR
|
||||
static void ast_decl_to_ir(scc_ir_builder_t *ctx, scc_ast_decl_t *decl) {
|
||||
if (ctx == null || decl == null) {
|
||||
LOG_ERROR("Invalid argument");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (decl->base.type) {
|
||||
case SCC_AST_DECL_VAR: {
|
||||
// 转换类型
|
||||
scc_ir_type_ref_t ir_type = ast_type_to_ir_type(ctx, decl->var.type);
|
||||
|
||||
// 创建分配节点
|
||||
scc_ir_node_ref_t alloc_val_node =
|
||||
scc_ir_builder_alloca(ctx, ir_type, decl->name);
|
||||
|
||||
// 如果有初始化表达式
|
||||
if (!decl->var.init) {
|
||||
break;
|
||||
}
|
||||
scc_ir_node_ref_t init_val_node = ast_expr_to_ir(ctx, decl->var.init);
|
||||
|
||||
// 将初始化值节点添加到程序节点列表
|
||||
// scc_vec_push(ctx->program->global_vals, init_val_node);
|
||||
// scc_ir_node_t *init_val =
|
||||
// &scc_vec_at(ctx->program->global_vals,
|
||||
// scc_vec_size(ctx->program->global_vals) - 1);
|
||||
|
||||
scc_ir_builder_store(ctx, alloc_val_node, init_val_node);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_DECL_FUNC: {
|
||||
// TODO params name
|
||||
scc_ir_type_ref_t func_type = ast_type_to_ir_type(ctx, decl->func.type);
|
||||
scc_ir_builder_begin_func(ctx, decl->name, func_type, null);
|
||||
// 处理函数体(如果有)
|
||||
if (decl->func.body) {
|
||||
scc_ir_builder_begin_bblock(ctx, "entry");
|
||||
ast_stmt_to_ir(ctx, decl->func.body);
|
||||
scc_ir_builder_end_bblock(ctx);
|
||||
}
|
||||
scc_ir_builder_end_func(ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_WARN("Unsupported declaration type: %d", decl->base.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将AST的翻译单元转换为IR
|
||||
* @warning 需要初始化builder且保证tu合法
|
||||
*
|
||||
* @param builder
|
||||
* @param tu
|
||||
*/
|
||||
void scc_ast2ir_translation_unit(scc_ir_builder_t *builder,
|
||||
scc_ast_translation_unit_t *tu,
|
||||
const scc_type_abi_t *abi) {
|
||||
if (tu == null || builder == null) {
|
||||
LOG_ERROR("Invalid argument");
|
||||
return;
|
||||
}
|
||||
|
||||
scc_vec_foreach(tu->declarations, i) {
|
||||
scc_ast_decl_t *decl = scc_vec_at(tu->declarations, i);
|
||||
ast_decl_to_ir(builder, decl);
|
||||
}
|
||||
}
|
||||
530
libs/ast2ir/src/scc_ast2ir.c
Normal file
530
libs/ast2ir/src/scc_ast2ir.c
Normal file
@@ -0,0 +1,530 @@
|
||||
#include <ir_builtin.h>
|
||||
#include <scc_ast2ir.h>
|
||||
|
||||
scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
scc_ast_type_t *ast_type) {
|
||||
if (ctx == null || ast_type == null) {
|
||||
LOG_ERROR("args is null");
|
||||
return 0;
|
||||
}
|
||||
scc_ir_type_t ir_type;
|
||||
|
||||
switch (ast_type->base.type) {
|
||||
case SCC_AST_TYPE_BUILTIN: {
|
||||
// 映射内置类型
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_I32);
|
||||
// TODO: 根据具体内置类型设置
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_TYPE_POINTER: {
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_PTR);
|
||||
|
||||
// 创建指向类型并添加到程序类型列表
|
||||
scc_ir_type_ref_t pointee_type =
|
||||
scc_ast2ir_type(ctx, ast_type->pointer.pointee);
|
||||
|
||||
// 注意:我们需要找到一种合适的方式来存储类型信息
|
||||
// 目前的IR设计中类型信息应该直接存储在类型结构中
|
||||
ir_type.data.pointer.base = pointee_type;
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_TYPE_ARRAY: {
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_ARRAY);
|
||||
|
||||
// 创建元素类型并添加到程序类型列表
|
||||
scc_ir_type_ref_t element_type =
|
||||
scc_ast2ir_type(ctx, ast_type->array.element);
|
||||
|
||||
// 将类型添加到程序的类型容器中
|
||||
ir_type.data.array.base = element_type;
|
||||
// TODO: 处理数组大小表达式
|
||||
ir_type.data.array.len = 0; // 暂时设为0
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_TYPE_FUNCTION: {
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_FUNC);
|
||||
|
||||
// 处理返回类型
|
||||
scc_ir_type_ref_t ret_type =
|
||||
scc_ast2ir_type(ctx, ast_type->function.return_type);
|
||||
|
||||
// 将返回类型添加到程序的类型容器中
|
||||
ir_type.data.function.ret_type = ret_type;
|
||||
|
||||
// 转换参数类型
|
||||
scc_ir_type_ref_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_foreach(ast_type->function.params, i) {
|
||||
scc_ast_decl_t *decl_param =
|
||||
scc_vec_at(ast_type->function.params, i);
|
||||
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
|
||||
scc_ir_type_ref_t tmp_type =
|
||||
scc_ast2ir_type(ctx, decl_param->param.type);
|
||||
scc_vec_push(params, tmp_type);
|
||||
}
|
||||
ir_type.data.function.params = params;
|
||||
break;
|
||||
}
|
||||
|
||||
// SCC_AST_TYPE_BUILTIN, // 内置类型
|
||||
// SCC_AST_TYPE_POINTER, // 指针类型
|
||||
// SCC_AST_TYPE_ARRAY, // 数组类型
|
||||
// SCC_AST_TYPE_FUNCTION, // 函数类型
|
||||
// SCC_AST_TYPE_STRUCT, // 结构体类型
|
||||
// SCC_AST_TYPE_UNION, // 联合类型
|
||||
// SCC_AST_TYPE_ENUM, // 枚举类型
|
||||
// SCC_AST_TYPE_TYPEDEF, // typedef 类型
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported AST type: %d", ast_type->base.type);
|
||||
return 0;
|
||||
}
|
||||
return scc_ir_ctx_new_type(&ctx->builder.ctx, &ir_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ctx
|
||||
* @param expr
|
||||
* @return scc_ir_node_ref_t
|
||||
*/
|
||||
scc_ir_node_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr) {
|
||||
if (ctx == null || expr == null) {
|
||||
LOG_ERROR("args is null");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (expr->base.type) {
|
||||
case SCC_AST_EXPR_BINARY: {
|
||||
scc_ir_node_ref_t lhs, rhs;
|
||||
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs);
|
||||
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs);
|
||||
|
||||
// 映射操作符
|
||||
scc_ir_op_type_t op;
|
||||
switch (expr->binary.op) {
|
||||
/* clang-format off */
|
||||
case SCC_AST_OP_ADD: op = SCC_IR_OP_ADD; break;
|
||||
case SCC_AST_OP_SUB: op = SCC_IR_OP_SUB; break;
|
||||
case SCC_AST_OP_MUL: op = SCC_IR_OP_MUL; break;
|
||||
case SCC_AST_OP_DIV: op = SCC_IR_OP_DIV; break;
|
||||
case SCC_AST_OP_MOD: op = SCC_IR_OP_MOD; break;
|
||||
case SCC_AST_OP_LOGICAL_AND: op = SCC_IR_OP_AND; break;
|
||||
case SCC_AST_OP_LOGICAL_OR: op = SCC_IR_OP_OR; break;
|
||||
case SCC_AST_OP_BITWISE_XOR: op = SCC_IR_OP_XOR; break;
|
||||
case SCC_AST_OP_LEFT_SHIFT: op = SCC_IR_OP_SHL; break;
|
||||
case SCC_AST_OP_RIGHT_SHIFT: op = SCC_IR_OP_SHR; break;
|
||||
case SCC_AST_OP_EQUAL: op = SCC_IR_OP_EQ; break;
|
||||
case SCC_AST_OP_NOT_EQUAL: op = SCC_IR_OP_NEQ; break;
|
||||
case SCC_AST_OP_LESS: op = SCC_IR_OP_LT; break;
|
||||
case SCC_AST_OP_LESS_EQUAL: op = SCC_IR_OP_LE; break;
|
||||
case SCC_AST_OP_GREATER: op = SCC_IR_OP_GT; break;
|
||||
case SCC_AST_OP_GREATER_EQUAL: op = SCC_IR_OP_GE; break;
|
||||
// SCC_AST_OP_ASSIGN, // =
|
||||
// SCC_AST_OP_ASSIGN_ADD, // +=
|
||||
// SCC_AST_OP_ASSIGN_SUB, // -=
|
||||
// SCC_AST_OP_ASSIGN_MUL, // *=
|
||||
// SCC_AST_OP_ASSIGN_DIV, // /=
|
||||
// SCC_AST_OP_ASSIGN_MOD, // %=
|
||||
// SCC_AST_OP_ASSIGN_AND, // &=
|
||||
// SCC_AST_OP_ASSIGN_XOR, // ^=
|
||||
// SCC_AST_OP_ASSIGN_OR, // |=
|
||||
// SCC_AST_OP_ASSIGN_LSHIFT, // <<=
|
||||
// SCC_AST_OP_ASSIGN_RSHIFT, // >>=
|
||||
case SCC_AST_OP_ASSIGN: {
|
||||
return scc_ir_builder_store(&ctx->builder, lhs, rhs);
|
||||
}
|
||||
case SCC_AST_OP_ASSIGN_ADD:
|
||||
TODO();
|
||||
// /* 赋值操作符 */
|
||||
// /* 条件操作符 */
|
||||
// SCC_AST_OP_CONDITIONAL, // ?:
|
||||
// /* 逗号操作符 */
|
||||
// SCC_AST_OP_COMMA, // ,
|
||||
// /* 逻辑操作符 */
|
||||
// SCC_AST_OP_LOGICAL_OR, // ||
|
||||
// SCC_AST_OP_LOGICAL_AND, // &&
|
||||
// /* 位操作符 */
|
||||
// SCC_AST_OP_BITWISE_OR, // |
|
||||
// SCC_AST_OP_BITWISE_XOR, // ^
|
||||
// SCC_AST_OP_BITWISE_AND, // &
|
||||
// /* 相等性操作符 */
|
||||
// SCC_AST_OP_EQUAL, // ==
|
||||
// SCC_AST_OP_NOT_EQUAL, // !=
|
||||
// /* 关系操作符 */
|
||||
// SCC_AST_OP_LESS, // <
|
||||
// SCC_AST_OP_GREATER, // >
|
||||
// SCC_AST_OP_LESS_EQUAL, // <=
|
||||
// SCC_AST_OP_GREATER_EQUAL, // >=
|
||||
// /* 移位操作符 */
|
||||
// SCC_AST_OP_LEFT_SHIFT, // <<
|
||||
// SCC_AST_OP_RIGHT_SHIFT, // >>
|
||||
// /* 算术操作符 */
|
||||
// SCC_AST_OP_ADD, // +
|
||||
// SCC_AST_OP_SUB, // -
|
||||
// SCC_AST_OP_MUL, // *
|
||||
// SCC_AST_OP_DIV, // /
|
||||
// SCC_AST_OP_MOD, // %
|
||||
// /* 一元操作符 */
|
||||
// SCC_AST_OP_UNARY_PLUS, // + (一元)
|
||||
// SCC_AST_OP_UNARY_MINUS, // - (一元)
|
||||
// SCC_AST_OP_ADDRESS_OF, // &
|
||||
// SCC_AST_OP_INDIRECTION, // *
|
||||
// SCC_AST_OP_BITWISE_NOT, // ~
|
||||
// SCC_AST_OP_LOGICAL_NOT, // !
|
||||
// SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀)
|
||||
// SCC_AST_OP_PREFIX_DECREMENT, // -- (前缀)
|
||||
// SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
|
||||
// SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
|
||||
// /* 成员访问 */
|
||||
// SCC_AST_OP_MEMBER_ACCESS, // .
|
||||
// SCC_AST_OP_PTR_MEMBER_ACCESS, // ->
|
||||
/* clang-format on */
|
||||
default:
|
||||
LOG_FATAL("Unsupported binary operator: %d", expr->binary.op);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 创建操作节点
|
||||
return scc_ir_builder_binop(&ctx->builder, op, lhs, rhs);
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_UNARY: {
|
||||
scc_ir_node_ref_t operand = scc_ast2ir_expr(ctx, expr->unary.operand);
|
||||
|
||||
// 映射一元操作符
|
||||
switch (expr->unary.op) {
|
||||
case SCC_AST_OP_SUB:
|
||||
// 负号
|
||||
// 实现为0 - operand
|
||||
return scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_SUB,
|
||||
scc_ir_ctx_get_builtin_zero(&ctx->builder.ctx), operand);
|
||||
case SCC_AST_OP_BITWISE_NOT:
|
||||
// 按位取反
|
||||
return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_NOT, operand,
|
||||
0);
|
||||
case SCC_AST_OP_LOGICAL_NOT:
|
||||
// 逻辑非
|
||||
// 实现为与0比较
|
||||
return scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_EQ,
|
||||
scc_ir_ctx_get_builtin_zero(&ctx->builder.ctx), operand);
|
||||
default:
|
||||
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_COND: {
|
||||
TODO();
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_EXPR_CALL: {
|
||||
// 转换参数
|
||||
scc_ir_node_ref_vec_t args;
|
||||
scc_vec_init(args);
|
||||
|
||||
// 检查参数是否为空
|
||||
if (expr->call.args.data != null) {
|
||||
scc_vec_foreach(expr->call.args, i) {
|
||||
scc_ast_expr_t *arg_expr = scc_vec_at(expr->call.args, i);
|
||||
scc_ir_node_ref_t arg_node;
|
||||
arg_node = scc_ast2ir_expr(ctx, arg_expr);
|
||||
scc_vec_push(args, arg_node);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建调用节点(需要查找函数定义)
|
||||
// TODO: 需要符号表查找函数
|
||||
scc_ir_node_ref_t func =
|
||||
scc_ir_builder_call(&ctx->builder, 0, args.data, args.size);
|
||||
scc_vec_free(args);
|
||||
return func;
|
||||
}
|
||||
|
||||
// SCC_AST_EXPR_ARRAY_SUBSCRIPT, // 数组下标
|
||||
// SCC_AST_EXPR_MEMBER, // 成员访问 .
|
||||
// SCC_AST_EXPR_PTR_MEMBER, // 指针成员访问 ->
|
||||
// SCC_AST_EXPR_CAST, // 类型转换
|
||||
// SCC_AST_EXPR_SIZE_OF, // sizeof
|
||||
// SCC_AST_EXPR_ALIGN_OF, // _Alignof
|
||||
// SCC_AST_EXPR_COMPOUND, // 复合字面量
|
||||
// SCC_AST_EXPR_LVALUE, // 右值
|
||||
// SCC_AST_EXPR_BUILTIN, // 内置表达式
|
||||
|
||||
case SCC_AST_EXPR_INT_LITERAL: {
|
||||
// FIXME maybe using some array to int;
|
||||
usize int_lit = 0;
|
||||
for (usize i = 0; i < scc_strlen(expr->literal.lexme); i++) {
|
||||
int_lit = int_lit * 10 + (expr->literal.lexme[i] - '0');
|
||||
}
|
||||
return scc_ir_ctx_get_i32_const(&ctx->builder.ctx, int_lit);
|
||||
}
|
||||
|
||||
// SCC_AST_EXPR_INT_LITERAL, // 整数字面量
|
||||
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
|
||||
// SCC_AST_EXPR_CHAR_LITERAL, // 字符字面量
|
||||
// SCC_AST_EXPR_STRING_LITERAL, // 字符串字面量
|
||||
|
||||
case SCC_AST_EXPR_IDENTIFIER: {
|
||||
// FIXME hack hashtable
|
||||
scc_ir_node_ref_t in = (scc_ir_node_ref_t)(usize)scc_hashtable_get(
|
||||
&ctx->node2ir, expr->identifier._target);
|
||||
return scc_ir_builder_load(&ctx->builder, in);
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported expression type: %d", expr->base.type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ctx
|
||||
* @param stmt
|
||||
*/
|
||||
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, scc_ast_stmt_t *stmt) {
|
||||
if (stmt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (stmt->base.type) {
|
||||
case SCC_AST_STMT_COMPOUND: {
|
||||
scc_vec_foreach(stmt->compound.block_items, i) {
|
||||
scc_ast_node_t *child_stmt =
|
||||
scc_vec_at(stmt->compound.block_items, i);
|
||||
if (SCC_AST_IS_A(scc_ast_stmt_t, child_stmt)) {
|
||||
scc_ast2ir_stmt(ctx,
|
||||
SCC_AST_CAST_TO(scc_ast_stmt_t, child_stmt));
|
||||
} else if (SCC_AST_IS_A(scc_ast_decl_t, child_stmt)) {
|
||||
scc_ast2ir_decl(ctx,
|
||||
SCC_AST_CAST_TO(scc_ast_decl_t, child_stmt));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_STMT_EXPR: {
|
||||
scc_ast2ir_expr(ctx, stmt->expr.expr);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_STMT_IF: {
|
||||
/*
|
||||
branch cond
|
||||
/ \
|
||||
true_block false_block
|
||||
\ /
|
||||
merge_block
|
||||
*/
|
||||
scc_ir_bblock_ref_t true_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "if_true");
|
||||
|
||||
scc_ir_bblock_ref_t false_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "if_false");
|
||||
|
||||
scc_ir_bblock_ref_t merge_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "if_merge");
|
||||
|
||||
scc_ir_node_ref_t cond_node = scc_ast2ir_expr(ctx, stmt->if_stmt.cond);
|
||||
scc_ir_builder_branch(&ctx->builder, cond_node, true_block,
|
||||
false_block);
|
||||
|
||||
// 生成true分支
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, true_block);
|
||||
scc_ast2ir_stmt(ctx, stmt->if_stmt.then_stmt);
|
||||
scc_ir_builder_jump(&ctx->builder, merge_block);
|
||||
|
||||
// 生成false分支
|
||||
if (stmt->if_stmt.opt_else_stmt) {
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, true_block);
|
||||
scc_ast2ir_stmt(ctx, stmt->if_stmt.opt_else_stmt);
|
||||
scc_ir_builder_jump(&ctx->builder, merge_block);
|
||||
}
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, merge_block);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_STMT_WHILE: {
|
||||
scc_ir_bblock_ref_t cond_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "while_cond");
|
||||
scc_ir_bblock_ref_t body_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "while_body");
|
||||
scc_ir_bblock_ref_t exit_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "while_exit");
|
||||
|
||||
scc_ir_builder_jump(&ctx->builder, cond_block);
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||||
scc_ir_node_ref_t cond_node =
|
||||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond);
|
||||
scc_ir_builder_branch(&ctx->builder, cond_node, body_block, exit_block);
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||||
scc_ir_builder_jump(&ctx->builder, cond_block);
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_STMT_DO_WHILE: {
|
||||
scc_ir_bblock_ref_t cond_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "do_while_cond");
|
||||
scc_ir_bblock_ref_t body_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "do_while_body");
|
||||
scc_ir_bblock_ref_t exit_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "do_while_exit");
|
||||
|
||||
scc_ir_builder_jump(&ctx->builder, body_block);
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||||
scc_ir_builder_jump(&ctx->builder, cond_block);
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||||
scc_ir_node_ref_t cond_node =
|
||||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond);
|
||||
scc_ir_builder_branch(&ctx->builder, cond_node, body_block, exit_block);
|
||||
|
||||
scc_ir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_STMT_FOR: {
|
||||
TODO();
|
||||
scc_ir_bblock_ref_t cond_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "for_while_cond");
|
||||
scc_ir_bblock_ref_t body_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "for_while_body");
|
||||
scc_ir_bblock_ref_t exit_block =
|
||||
scc_ir_builder_bblock(&ctx->builder, "for_while_exit");
|
||||
break;
|
||||
}
|
||||
|
||||
// SCC_AST_STMT_SWITCH, // switch 语句
|
||||
// SCC_AST_STMT_CASE, // case 语句
|
||||
// SCC_AST_STMT_DEFAULT, // default 语句
|
||||
// SCC_AST_STMT_BREAK, // break 语句
|
||||
// SCC_AST_STMT_CONTINUE, // continue 语句
|
||||
case SCC_AST_STMT_RETURN: {
|
||||
if (stmt->return_stmt.expr) {
|
||||
scc_ir_node_ref_t ret_val_node =
|
||||
scc_ast2ir_expr(ctx, stmt->return_stmt.expr);
|
||||
scc_ir_builder_ret(&ctx->builder, ret_val_node);
|
||||
} else {
|
||||
scc_ir_builder_ret_void(&ctx->builder);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// SCC_AST_STMT_GOTO, // goto 语句
|
||||
// SCC_AST_STMT_LABEL, // 标签语句
|
||||
default:
|
||||
LOG_FATAL("Unsupported statement type: %d", stmt->base.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ctx
|
||||
* @param decl
|
||||
*/
|
||||
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl) {
|
||||
if (ctx == null || decl == null) {
|
||||
LOG_ERROR("Invalid argument");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (decl->base.type) {
|
||||
case SCC_AST_DECL_VAR: {
|
||||
// 转换类型
|
||||
scc_ir_type_ref_t ir_type = scc_ast2ir_type(ctx, decl->var.type);
|
||||
|
||||
// 创建分配节点
|
||||
scc_ir_node_ref_t alloc_val_node =
|
||||
scc_ir_builder_alloca(&ctx->builder, ir_type, decl->name);
|
||||
|
||||
// 如果有初始化表达式
|
||||
if (!decl->var.init) {
|
||||
break;
|
||||
}
|
||||
scc_ir_node_ref_t init_val_node = scc_ast2ir_expr(ctx, decl->var.init);
|
||||
scc_ir_builder_store(&ctx->builder, alloc_val_node, init_val_node);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_DECL_FUNC: {
|
||||
// TODO params name
|
||||
scc_ir_type_ref_t func_type = scc_ast2ir_type(ctx, decl->func.type);
|
||||
if (decl->func.body == null) {
|
||||
// function decl
|
||||
break;
|
||||
}
|
||||
scc_ir_builder_begin_func(&ctx->builder, decl->name, func_type, null);
|
||||
scc_ir_builder_begin_bblock(&ctx->builder, "entry");
|
||||
scc_ast2ir_stmt(ctx, decl->func.body);
|
||||
scc_ir_builder_end_bblock(&ctx->builder);
|
||||
scc_ir_builder_end_func(&ctx->builder);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_AST_DECL_LIST: {
|
||||
scc_vec_foreach(decl->list.vars, i) {
|
||||
scc_ast_decl_t *sub_decl = scc_vec_at(decl->list.vars, i);
|
||||
scc_ast2ir_decl(ctx, sub_decl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCC_AST_DECL_PARAM: {
|
||||
break;
|
||||
}
|
||||
case SCC_AST_DECL_STRUCT:
|
||||
break;
|
||||
case SCC_AST_DECL_UNION:
|
||||
break;
|
||||
|
||||
case SCC_AST_DECL_ENUM:
|
||||
case SCC_AST_DECL_TYPEDEF:
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported declaration type: %d", decl->base.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_ast2ir_translation_unit(scc_ast2ir_ctx_t *ctx,
|
||||
scc_ast_translation_unit_t *tu) {
|
||||
Assert(ctx != null && tu != null);
|
||||
|
||||
scc_vec_foreach(tu->declarations, i) {
|
||||
scc_ast_decl_t *decl = scc_vec_at(tu->declarations, i);
|
||||
scc_ast2ir_decl(ctx, decl);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 scc_hash_node(const void *key) { return (u32)(usize)key; }
|
||||
static int scc_cmp_node(const void *key1, const void *key2) {
|
||||
return key1 == key2;
|
||||
}
|
||||
|
||||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *abi) {
|
||||
Assert(ctx != null);
|
||||
ctx->abi = abi;
|
||||
scc_ir_builder_init(&ctx->builder);
|
||||
|
||||
scc_hashtable_init(&ctx->node2ir, scc_hash_node, scc_cmp_node);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <scc_ast2ir.h>
|
||||
#include <utest/acutest.h>
|
||||
|
||||
void test_type(void) {}
|
||||
|
||||
void test_expr(void) {}
|
||||
|
||||
void test_stmt(void) {}
|
||||
|
||||
void test_decl(void) {}
|
||||
|
||||
TEST_LIST = {
|
||||
|
||||
};
|
||||
|
||||
@@ -56,6 +56,15 @@ void scc_ir_builder_end_func(scc_ir_builder_t *builder);
|
||||
*/
|
||||
scc_ir_func_ref_t scc_ir_builder_current_func(scc_ir_builder_t *builder);
|
||||
|
||||
/**
|
||||
* @brief 创建一个新的基本块,并自动添加到当前函数中,但不改变当前块。
|
||||
* @param builder IR构建器
|
||||
* @param label 基本块标签(可为 NULL,自动生成)
|
||||
* @return 新基本块的引用
|
||||
*/
|
||||
scc_ir_bblock_ref_t scc_ir_builder_bblock(scc_ir_builder_t *builder,
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
* @brief 开始构建新的基本块
|
||||
* @param label 基本块标签(可为NULL,自动生成)
|
||||
|
||||
@@ -52,8 +52,8 @@ typedef enum scc_ir_type_tag {
|
||||
|
||||
struct scc_ir_type {
|
||||
scc_ir_type_tag_t tag;
|
||||
// int size; // 字节大小
|
||||
// int align; // 对齐要求
|
||||
int size; // 字节大小
|
||||
int align; // 对齐要求
|
||||
union {
|
||||
struct {
|
||||
scc_ir_type_ref_t base;
|
||||
@@ -85,6 +85,8 @@ struct scc_ir_func {
|
||||
typedef enum scc_ir_node_tag {
|
||||
SCC_IR_NODE_NULL,
|
||||
SCC_IR_NODE_CONST_INT,
|
||||
SCC_IR_NODE_CONST_UINT,
|
||||
SCC_IR_NODE_CONST_FLOAT,
|
||||
SCC_IR_NODE_CONV, ///< 类型转换
|
||||
SCC_IR_NODE_FUNC_ARG_REF, ///< 函数参数引用
|
||||
SCC_IR_NODE_BLOCK_ARG_REF, ///< 基本块参数引用
|
||||
|
||||
@@ -80,8 +80,8 @@ scc_ir_func_ref_t scc_ir_builder_current_func(scc_ir_builder_t *builder) {
|
||||
return builder->current_func;
|
||||
}
|
||||
|
||||
scc_ir_bblock_ref_t scc_ir_builder_begin_bblock(scc_ir_builder_t *builder,
|
||||
const char *label) {
|
||||
scc_ir_bblock_ref_t scc_ir_builder_bblock(scc_ir_builder_t *builder,
|
||||
const char *label) {
|
||||
scc_ir_bblock_t bblock = {0};
|
||||
|
||||
if (label) {
|
||||
@@ -100,16 +100,22 @@ scc_ir_bblock_ref_t scc_ir_builder_begin_bblock(scc_ir_builder_t *builder,
|
||||
|
||||
scc_ir_bblock_ref_t bblock_ref =
|
||||
scc_ir_ctx_new_bblock(&builder->ctx, &bblock);
|
||||
builder->current_bblock = bblock_ref;
|
||||
return bblock_ref;
|
||||
}
|
||||
|
||||
scc_ir_bblock_ref_t scc_ir_builder_begin_bblock(scc_ir_builder_t *builder,
|
||||
const char *label) {
|
||||
|
||||
builder->current_bblock = scc_ir_builder_bblock(builder, label);
|
||||
|
||||
// 将基本块添加到当前函数
|
||||
scc_ir_func_t *current_func =
|
||||
scc_ir_ctx_get_func(&builder->ctx, builder->current_func);
|
||||
if (current_func) {
|
||||
scc_vec_push(current_func->bblocks, bblock_ref);
|
||||
scc_vec_push(current_func->bblocks, builder->current_bblock);
|
||||
}
|
||||
|
||||
return bblock_ref;
|
||||
return builder->current_bblock;
|
||||
}
|
||||
|
||||
void scc_ir_builder_end_bblock(scc_ir_builder_t *builder) {
|
||||
@@ -152,13 +158,13 @@ scc_ir_node_ref_t scc_ir_builder_alloca(scc_ir_builder_t *builder,
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_builder_load(scc_ir_builder_t *builder,
|
||||
scc_ir_node_ref_t ptr) {
|
||||
scc_ir_node_ref_t target) {
|
||||
scc_ir_node_t load_node = {0};
|
||||
load_node.tag = SCC_IR_NODE_LOAD;
|
||||
load_node.data.load.target = ptr;
|
||||
load_node.data.load.target = target;
|
||||
|
||||
// 设置类型为指针指向的类型
|
||||
scc_ir_node_t *ptr_node = scc_ir_ctx_get_node(&builder->ctx, ptr);
|
||||
scc_ir_node_t *ptr_node = scc_ir_ctx_get_node(&builder->ctx, target);
|
||||
if (ptr_node) {
|
||||
scc_ir_type_t *ptr_type =
|
||||
scc_ir_ctx_get_type(&builder->ctx, ptr_node->type);
|
||||
@@ -176,11 +182,11 @@ scc_ir_node_ref_t scc_ir_builder_load(scc_ir_builder_t *builder,
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_builder_store(scc_ir_builder_t *builder,
|
||||
scc_ir_node_ref_t ptr,
|
||||
scc_ir_node_ref_t target,
|
||||
scc_ir_node_ref_t value) {
|
||||
scc_ir_node_t store_node = {0};
|
||||
store_node.tag = SCC_IR_NODE_STORE;
|
||||
store_node.data.store.target = ptr;
|
||||
store_node.data.store.target = target;
|
||||
store_node.data.store.value = value;
|
||||
|
||||
scc_ir_node_ref_t node_ref =
|
||||
@@ -193,15 +199,15 @@ scc_ir_node_ref_t scc_ir_builder_store(scc_ir_builder_t *builder,
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_builder_get_ptr(scc_ir_builder_t *builder,
|
||||
scc_ir_node_ref_t ptr,
|
||||
scc_ir_node_ref_t target,
|
||||
scc_ir_node_ref_t index) {
|
||||
scc_ir_node_t get_ptr_node = {0};
|
||||
get_ptr_node.tag = SCC_IR_NODE_GET_PTR;
|
||||
get_ptr_node.data.get_ptr.src_addr = ptr;
|
||||
get_ptr_node.data.get_ptr.src_addr = target;
|
||||
get_ptr_node.data.get_ptr.index = index;
|
||||
|
||||
// 类型应与源地址相同(都是指针)
|
||||
scc_ir_node_t *src_node = scc_ir_ctx_get_node(&builder->ctx, ptr);
|
||||
scc_ir_node_t *src_node = scc_ir_ctx_get_node(&builder->ctx, target);
|
||||
if (src_node) {
|
||||
get_ptr_node.type = src_node->type;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ static const char *get_node_type_str(scc_ir_node_tag_t tag) {
|
||||
[SCC_IR_NODE_RET] = "Return",
|
||||
};
|
||||
|
||||
if (tag >= 0 && tag < sizeof(node_types) / sizeof(node_types[0]) &&
|
||||
if (tag >= 0 && (usize)tag < sizeof(node_types) / sizeof(node_types[0]) &&
|
||||
node_types[tag] != NULL) {
|
||||
return node_types[tag];
|
||||
}
|
||||
@@ -39,11 +39,12 @@ static const char *get_op_str(scc_ir_op_type_t op) {
|
||||
[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_SHL] = "<<", [SCC_IR_OP_SHR] = ">>",
|
||||
[SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right
|
||||
};
|
||||
|
||||
if (op >= 0 && op < sizeof(ops) / sizeof(ops[0]) && ops[op] != NULL) {
|
||||
if (op >= 0 && (usize)op < sizeof(ops) / sizeof(ops[0]) &&
|
||||
ops[op] != NULL) {
|
||||
return ops[op];
|
||||
}
|
||||
return "<unknown_op>";
|
||||
@@ -64,7 +65,7 @@ static const char *get_type_tag_str(scc_ir_type_tag_t tag) {
|
||||
[SCC_IR_TYPE_STRUCT] = "struct", [SCC_IR_TYPE_VECTOR] = "vector",
|
||||
};
|
||||
|
||||
if (tag >= 0 && tag < sizeof(type_tags) / sizeof(type_tags[0]) &&
|
||||
if (tag >= 0 && (usize)tag < sizeof(type_tags) / sizeof(type_tags[0]) &&
|
||||
type_tags[tag] != NULL) {
|
||||
return type_tags[tag];
|
||||
}
|
||||
|
||||
@@ -87,6 +87,20 @@ static inline void scc_parse_decl_sema(scc_parser_t *parser,
|
||||
decl);
|
||||
}
|
||||
|
||||
static inline void scc_parse_expr_sema(scc_parser_t *parser,
|
||||
scc_ast_expr_t *expr) {
|
||||
parser->sema_callbacks.on_expr(parser->sema_callbacks.context,
|
||||
expr ? expr->base.type : SCC_AST_UNKNOWN,
|
||||
expr);
|
||||
}
|
||||
|
||||
static inline void scc_parse_stmt_sema(scc_parser_t *parser,
|
||||
scc_ast_stmt_t *stmt) {
|
||||
parser->sema_callbacks.on_stmt(parser->sema_callbacks.context,
|
||||
stmt ? stmt->base.type : SCC_AST_UNKNOWN,
|
||||
stmt);
|
||||
}
|
||||
|
||||
static inline void scc_parse_type_sema(scc_parser_t *parser,
|
||||
scc_ast_type_t *type) {
|
||||
parser->sema_callbacks.on_type(parser->sema_callbacks.context,
|
||||
|
||||
@@ -182,7 +182,9 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
init = scc_parse_assignment_expression(parser);
|
||||
return init;
|
||||
}
|
||||
scc_parser_next_consume(parser, null);
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
scc_pos_t pos = tok.loc;
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
init = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(init != null);
|
||||
@@ -202,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));
|
||||
scc_ast_expr_member_init(
|
||||
lhs, ptr, scc_cstring_as_cstr(&tok.lexeme), tok.loc);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) {
|
||||
ptr = lhs;
|
||||
continue;
|
||||
@@ -230,7 +232,7 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
}
|
||||
lhs = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(lhs != null);
|
||||
scc_ast_expr_array_subscript_init(lhs, ptr, idx);
|
||||
scc_ast_expr_array_subscript_init(lhs, ptr, idx, tok_ptr->loc);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) {
|
||||
ptr = lhs;
|
||||
continue;
|
||||
@@ -253,7 +255,7 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
scc_vec_push(rhs_exprs, expr);
|
||||
}
|
||||
}
|
||||
scc_ast_expr_compound_init(init, base, &lhs_exprs, &rhs_exprs);
|
||||
scc_ast_expr_compound_init(init, base, &lhs_exprs, &rhs_exprs, pos);
|
||||
return init;
|
||||
}
|
||||
|
||||
@@ -283,10 +285,14 @@ CONTINUE:
|
||||
scc_parser_next_consume(parser, null);
|
||||
// TODO maybe memory leak
|
||||
scc_ast_expr_t *lvalue = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
scc_ast_expr_lvalue_init(lvalue, decl->var.type);
|
||||
scc_ast_expr_lvalue_init(lvalue, decl->var.type, decl->base.loc);
|
||||
decl->var.init = scc_parse_initializer(parser, lvalue);
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACE) {
|
||||
parser->sema_callbacks.on_decl(parser->sema_callbacks.context,
|
||||
scc_ast_decl_t_BEGIN, null);
|
||||
scc_ast_stmt_t *body = scc_parse_statement(parser);
|
||||
parser->sema_callbacks.on_decl(parser->sema_callbacks.context,
|
||||
scc_ast_decl_t_END, null);
|
||||
Assert(decl->base.type == SCC_AST_DECL_FUNC);
|
||||
decl->func.body = body;
|
||||
Assert(decl->func.type != null);
|
||||
@@ -305,10 +311,12 @@ CONTINUE:
|
||||
if (decl_list) {
|
||||
scc_vec_foreach(decl_list_vec, i) {
|
||||
decl = scc_vec_at(decl_list_vec, i);
|
||||
scc_ast_decl_typedef_init(decl, decl->name, decl->var.type);
|
||||
scc_ast_decl_typedef_init(decl, decl->name, decl->var.type,
|
||||
decl->base.loc);
|
||||
}
|
||||
} else {
|
||||
scc_ast_decl_typedef_init(decl, decl->name, decl->var.type);
|
||||
scc_ast_decl_typedef_init(decl, decl->name, decl->var.type,
|
||||
decl->base.loc);
|
||||
}
|
||||
}
|
||||
if (decl_list != null) {
|
||||
@@ -316,7 +324,9 @@ CONTINUE:
|
||||
decl = scc_vec_at(decl_list_vec, i);
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
}
|
||||
scc_ast_decl_list_init(decl_list, &decl_list_vec);
|
||||
// FIXME
|
||||
scc_ast_decl_list_init(decl_list, &decl_list_vec,
|
||||
scc_vec_at(decl_list_vec, 0)->base.loc);
|
||||
decl = decl_list;
|
||||
} else {
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
|
||||
@@ -374,7 +374,8 @@ static scc_ast_expr_t *parse_expression_with_precedence(scc_parser_t *parser,
|
||||
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_binary_init(expr, op, left, right);
|
||||
// FIXME pos
|
||||
scc_ast_expr_binary_init(expr, op, left, right, left->base.loc);
|
||||
left = expr;
|
||||
}
|
||||
return left;
|
||||
@@ -391,6 +392,7 @@ scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
return left;
|
||||
scc_pos_t pos = tok_ptr->loc;
|
||||
|
||||
int prec = get_token_precedence(tok_ptr->type);
|
||||
if (prec == PREC_ASSIGNMENT && is_binary_operator(tok_ptr->type)) {
|
||||
@@ -411,7 +413,7 @@ scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser) {
|
||||
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_binary_init(expr, op, left, right);
|
||||
scc_ast_expr_binary_init(expr, op, left, right, pos);
|
||||
left = expr;
|
||||
}
|
||||
return left;
|
||||
@@ -426,6 +428,7 @@ static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) {
|
||||
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr && tok_ptr->type == SCC_TOK_COND) {
|
||||
scc_pos_t pos = tok_ptr->loc;
|
||||
// 消耗 '?'
|
||||
scc_lexer_tok_t q_tok;
|
||||
if (!scc_parser_next_consume(parser, &q_tok))
|
||||
@@ -456,7 +459,7 @@ static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) {
|
||||
|
||||
scc_ast_expr_t *cond = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(cond != null);
|
||||
scc_ast_expr_cond_init(cond, cond_expr, then_expr, else_expr);
|
||||
scc_ast_expr_cond_init(cond, cond_expr, then_expr, else_expr, pos);
|
||||
cond_expr = cond;
|
||||
}
|
||||
return cond_expr;
|
||||
@@ -480,13 +483,15 @@ static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) {
|
||||
if (!operand) {
|
||||
// FIXME postfix-expression
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
scc_ast_expr_lvalue_init(expr, type);
|
||||
// FIXME pos
|
||||
scc_ast_expr_lvalue_init(expr, type, type->base.loc);
|
||||
operand = scc_parse_initializer(parser, expr);
|
||||
return operand;
|
||||
}
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_cast_init(expr, type, operand);
|
||||
// FIXME pos
|
||||
scc_ast_expr_cast_init(expr, type, operand, type->base.loc);
|
||||
return expr;
|
||||
} else {
|
||||
// 不是类型转换,回退
|
||||
@@ -538,6 +543,7 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_op_t op = map_token_to_unary_op(tok.type, true);
|
||||
scc_pos_t pos = tok.loc;
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
// 一元运算符右结合,递归调用 parse_unary_expression
|
||||
@@ -556,7 +562,7 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_unary_init(expr, op, operand);
|
||||
scc_ast_expr_unary_init(expr, op, operand, pos);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_SIZEOF:
|
||||
@@ -573,6 +579,7 @@ static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) {
|
||||
tok_ptr.type != SCC_TOK_SIZEOF) {
|
||||
return null;
|
||||
}
|
||||
scc_pos_t pos = tok_ptr.loc;
|
||||
scc_lexer_tok_drop(&tok_ptr);
|
||||
|
||||
const scc_lexer_tok_t *next = scc_parser_peek(parser);
|
||||
@@ -599,14 +606,14 @@ static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
Assert(type_name != null);
|
||||
scc_ast_expr_sizeof_init(expr, type_name, null);
|
||||
scc_ast_expr_sizeof_init(expr, type_name, null, pos);
|
||||
return expr;
|
||||
}
|
||||
next:
|
||||
// 尝试解析 sizeof unary-expression
|
||||
scc_ast_expr_t *operand = parse_unary_expression(parser);
|
||||
if (operand != null) {
|
||||
scc_ast_expr_sizeof_init(expr, null, operand);
|
||||
scc_ast_expr_sizeof_init(expr, null, operand, pos);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@@ -618,11 +625,14 @@ next:
|
||||
static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *left = parse_primary_expression(parser);
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
scc_pos_t pos = scc_pos_create();
|
||||
if (!left) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (!(tok_ptr && tok_ptr->type == SCC_TOK_L_PAREN)) {
|
||||
return null;
|
||||
}
|
||||
pos = tok_ptr->loc;
|
||||
|
||||
scc_parser_store(parser);
|
||||
scc_parser_next(parser);
|
||||
scc_ast_type_t *type = scc_parse_type_name(parser);
|
||||
@@ -635,7 +645,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected ')'");
|
||||
}
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
scc_ast_expr_lvalue_init(expr, type);
|
||||
scc_ast_expr_lvalue_init(expr, type, pos);
|
||||
left = scc_parse_initializer(parser, expr);
|
||||
return left;
|
||||
}
|
||||
@@ -650,6 +660,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
{
|
||||
if (!scc_parser_next_consume(parser, null))
|
||||
return left;
|
||||
pos = left->base.loc;
|
||||
|
||||
scc_ast_expr_t *index = scc_parse_expression(parser);
|
||||
if (!index) {
|
||||
@@ -664,7 +675,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
}
|
||||
scc_ast_expr_t *subscript = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(subscript != null);
|
||||
scc_ast_expr_array_subscript_init(subscript, left, index);
|
||||
scc_ast_expr_array_subscript_init(subscript, left, index, pos);
|
||||
left = subscript;
|
||||
break;
|
||||
}
|
||||
@@ -672,6 +683,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
{
|
||||
if (!scc_parser_next_consume(parser, null))
|
||||
return left;
|
||||
pos = left->base.loc;
|
||||
scc_ast_expr_vec_t args;
|
||||
scc_vec_init(args);
|
||||
|
||||
@@ -700,7 +712,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
}
|
||||
scc_ast_expr_t *call = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(call != null);
|
||||
scc_ast_expr_call_init(call, left, &args);
|
||||
scc_ast_expr_call_init(call, left, &args, pos);
|
||||
left = call;
|
||||
break;
|
||||
}
|
||||
@@ -723,9 +735,9 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *member = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(member != null);
|
||||
if (op_tok.type == SCC_TOK_DOT) {
|
||||
scc_ast_expr_member_init(member, left, name);
|
||||
scc_ast_expr_member_init(member, left, name, ident_tok.loc);
|
||||
} else {
|
||||
scc_ast_expr_ptr_member_init(member, left, name);
|
||||
scc_ast_expr_ptr_member_init(member, left, name, ident_tok.loc);
|
||||
}
|
||||
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
@@ -739,10 +751,10 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
if (!scc_parser_next_consume(parser, &op_tok))
|
||||
return left;
|
||||
scc_ast_expr_op_t op = map_token_to_unary_op(op_tok.type, false);
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_unary_init(expr, op, left);
|
||||
scc_ast_expr_unary_init(expr, op, left, op_tok.loc);
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
left = expr;
|
||||
break;
|
||||
}
|
||||
@@ -776,7 +788,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_identifier_init(expr, scc_cstring_as_cstr(&tok.lexeme));
|
||||
scc_ast_expr_identifier_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
tok.loc);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_INT_LITERAL: {
|
||||
@@ -785,7 +798,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
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);
|
||||
false, tok.loc);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_FLOAT_LITERAL: {
|
||||
@@ -794,7 +807,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_float_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false);
|
||||
false, tok.loc);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_CHAR_LITERAL: {
|
||||
@@ -803,7 +816,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_char_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false);
|
||||
false, tok.loc);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_STRING_LITERAL: {
|
||||
@@ -825,8 +838,9 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
|
||||
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);
|
||||
true, tok.loc);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_L_PAREN:
|
||||
@@ -847,7 +861,15 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) {
|
||||
if (!left)
|
||||
return null;
|
||||
|
||||
while (scc_parser_consume_if(parser, SCC_TOK_COMMA)) {
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
while (1) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null || tok_ptr->type != SCC_TOK_COMMA) {
|
||||
break;
|
||||
}
|
||||
scc_pos_t pos = tok_ptr->loc;
|
||||
scc_parser_next_consume(parser, null);
|
||||
|
||||
scc_ast_expr_t *right = scc_parse_assignment_expression(parser);
|
||||
if (!right) {
|
||||
parser_sync(parser);
|
||||
@@ -855,7 +877,7 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) {
|
||||
}
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_binary_init(expr, SCC_AST_OP_COMMA, left, right);
|
||||
scc_ast_expr_binary_init(expr, SCC_AST_OP_COMMA, left, right, pos);
|
||||
left = expr;
|
||||
}
|
||||
return left;
|
||||
|
||||
@@ -73,7 +73,8 @@ static inline scc_ast_expr_t *ast_parse_paren_expression(scc_parser_t *parser) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
scc_lexer_tok_t tok = {0};
|
||||
if (!scc_parser_next_consume(parser, &tok)) {
|
||||
return null;
|
||||
@@ -91,11 +92,13 @@ 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);
|
||||
scc_ast_stmt_label_init(stmt, scc_cstring_as_cstr(&tok.lexeme), statement,
|
||||
pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_CASE)) {
|
||||
return null;
|
||||
}
|
||||
@@ -120,11 +123,12 @@ static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_case_init(stmt, expr, statement);
|
||||
scc_ast_stmt_case_init(stmt, expr, statement, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_DEFAULT)) {
|
||||
return null;
|
||||
}
|
||||
@@ -141,17 +145,20 @@ static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_default_init(stmt, statement);
|
||||
scc_ast_stmt_default_init(stmt, statement, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_L_BRACE)) {
|
||||
return null;
|
||||
}
|
||||
scc_ast_block_item_vec_t block_items;
|
||||
scc_vec_init(block_items);
|
||||
|
||||
parser->sema_callbacks.on_stmt(parser->sema_callbacks.context,
|
||||
scc_ast_stmt_t_BEGIN, null);
|
||||
while (!scc_parser_consume_if(parser, SCC_TOK_R_BRACE)) {
|
||||
/// TODO
|
||||
// scc_parse_is_decl();
|
||||
@@ -168,13 +175,15 @@ static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser) {
|
||||
}
|
||||
scc_vec_push(block_items, ret);
|
||||
}
|
||||
parser->sema_callbacks.on_stmt(parser->sema_callbacks.context,
|
||||
scc_ast_stmt_t_END, null);
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_compound_init(stmt, &block_items);
|
||||
scc_ast_stmt_compound_init(stmt, &block_items, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser, scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_IF)) {
|
||||
return null;
|
||||
}
|
||||
@@ -190,11 +199,12 @@ static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_if_init(stmt, expression, statement, opt_else);
|
||||
scc_ast_stmt_if_init(stmt, expression, statement, opt_else, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SWITCH)) {
|
||||
return null;
|
||||
}
|
||||
@@ -203,11 +213,12 @@ static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser) {
|
||||
scc_ast_stmt_t *statement = scc_parse_statement(parser);
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_switch_init(stmt, expression, statement);
|
||||
scc_ast_stmt_switch_init(stmt, expression, statement, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_WHILE)) {
|
||||
return null;
|
||||
}
|
||||
@@ -216,11 +227,12 @@ static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser) {
|
||||
scc_ast_stmt_t *statement = scc_parse_statement(parser);
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_while_init(stmt, expression, statement);
|
||||
scc_ast_stmt_while_init(stmt, expression, statement, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_DO)) {
|
||||
return null;
|
||||
}
|
||||
@@ -237,11 +249,12 @@ static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *expression = ast_parse_paren_expression(parser);
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_do_while_init(stmt, expression, statement);
|
||||
scc_ast_stmt_do_while_init(stmt, expression, statement, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_FOR)) {
|
||||
return null;
|
||||
}
|
||||
@@ -288,27 +301,28 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
||||
body = scc_parse_statement(parser);
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_for_init(stmt, init, cond, incr, body);
|
||||
scc_ast_stmt_for_init(stmt, init, cond, incr, body, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
|
||||
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));
|
||||
scc_ast_stmt_goto_init(stmt, scc_cstring_as_cstr(&tok.lexeme), pos);
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected label after goto.");
|
||||
}
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_CONTINUE)) {
|
||||
scc_ast_stmt_continue_init(stmt);
|
||||
scc_ast_stmt_continue_init(stmt, pos);
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_BREAK)) {
|
||||
scc_ast_stmt_break_init(stmt);
|
||||
scc_ast_stmt_break_init(stmt, pos);
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_RETURN)) {
|
||||
scc_ast_stmt_return_init(stmt, scc_parse_expression(parser));
|
||||
scc_ast_stmt_return_init(stmt, scc_parse_expression(parser), pos);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@@ -320,11 +334,12 @@ static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser) {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser) {
|
||||
static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser,
|
||||
scc_pos_t pos) {
|
||||
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_expr_init(stmt, null);
|
||||
scc_ast_stmt_expr_init(stmt, null, pos);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@@ -334,7 +349,7 @@ static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||
scc_ast_stmt_expr_init(stmt, expr);
|
||||
scc_ast_stmt_expr_init(stmt, expr, pos);
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
@@ -350,6 +365,7 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
if (!tok_ref) {
|
||||
return null;
|
||||
}
|
||||
scc_pos_t pos = tok_ref->loc;
|
||||
switch (tok_ref->type) {
|
||||
/*
|
||||
(6.8.1)
|
||||
@@ -366,14 +382,14 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
break;
|
||||
}
|
||||
scc_parser_reset(parser);
|
||||
stmt = parse_label_statement(parser);
|
||||
stmt = parse_label_statement(parser, pos);
|
||||
goto RETURN;
|
||||
case SCC_TOK_CASE: {
|
||||
stmt = parse_case_statement(parser);
|
||||
stmt = parse_case_statement(parser, pos);
|
||||
goto RETURN;
|
||||
}
|
||||
case SCC_TOK_DEFAULT:
|
||||
stmt = parse_default_statement(parser);
|
||||
stmt = parse_default_statement(parser, pos);
|
||||
goto RETURN;
|
||||
/*
|
||||
(6.8.2)
|
||||
@@ -389,7 +405,7 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
statement
|
||||
*/
|
||||
case SCC_TOK_L_BRACE:
|
||||
stmt = parse_compound_statement(parser);
|
||||
stmt = parse_compound_statement(parser, pos);
|
||||
goto RETURN;
|
||||
/*
|
||||
(6.8.4)
|
||||
@@ -399,10 +415,10 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
switch ( expression ) statement
|
||||
*/
|
||||
case SCC_TOK_IF:
|
||||
stmt = parse_if_statement(parser);
|
||||
stmt = parse_if_statement(parser, pos);
|
||||
goto RETURN;
|
||||
case SCC_TOK_SWITCH:
|
||||
stmt = parse_switch_statement(parser);
|
||||
stmt = parse_switch_statement(parser, pos);
|
||||
goto RETURN;
|
||||
/*
|
||||
(6.8.5)
|
||||
@@ -415,13 +431,13 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
statement
|
||||
*/
|
||||
case SCC_TOK_WHILE:
|
||||
stmt = parse_while_statement(parser);
|
||||
stmt = parse_while_statement(parser, pos);
|
||||
goto RETURN;
|
||||
case SCC_TOK_DO:
|
||||
stmt = parse_do_while_statement(parser);
|
||||
stmt = parse_do_while_statement(parser, pos);
|
||||
goto RETURN;
|
||||
case SCC_TOK_FOR:
|
||||
stmt = parse_for_statement(parser);
|
||||
stmt = parse_for_statement(parser, pos);
|
||||
goto RETURN;
|
||||
/*
|
||||
(6.8.6)
|
||||
@@ -435,7 +451,7 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
case SCC_TOK_CONTINUE:
|
||||
case SCC_TOK_BREAK:
|
||||
case SCC_TOK_RETURN:
|
||||
stmt = parse_jump_statement(parser);
|
||||
stmt = parse_jump_statement(parser, pos);
|
||||
goto RETURN;
|
||||
default:
|
||||
break;
|
||||
@@ -445,12 +461,9 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||
expression-statement:
|
||||
expression(opt) ;
|
||||
*/
|
||||
stmt = parse_expression_statement(parser);
|
||||
stmt = parse_expression_statement(parser, pos);
|
||||
RETURN:
|
||||
scc_parser_reset(parser);
|
||||
if (stmt) {
|
||||
parser->sema_callbacks.on_stmt(parser->sema_callbacks.context,
|
||||
stmt->base.type, stmt);
|
||||
}
|
||||
scc_parse_stmt_sema(parser, stmt);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@@ -467,7 +467,8 @@ static cbool check_type_combinations(scc_parser_t *parser,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static scc_ast_type_t *build_type_from_info(type_spec_info_t *info) {
|
||||
static scc_ast_type_t *build_type_from_info(type_spec_info_t *info,
|
||||
scc_pos_t pos) {
|
||||
// 如果有用户定义类型,直接返回(注意可能需要复制或共享)
|
||||
if (info->user_type) {
|
||||
return info->user_type; // 假设 parse_struct_union_enum 已分配好节点
|
||||
@@ -528,7 +529,7 @@ static scc_ast_type_t *build_type_from_info(type_spec_info_t *info) {
|
||||
}
|
||||
|
||||
scc_ast_type_t *type = ast_type_alloc();
|
||||
_scc_ast_type_builtin_init(type, builtin);
|
||||
scc_ast_type_builtin_init(type, builtin, pos);
|
||||
// 注意:限定符(const, volatile)不应在此处处理,应由上层函数负责
|
||||
return type;
|
||||
}
|
||||
@@ -564,9 +565,12 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
declarator(opt) : constant-expression
|
||||
*/
|
||||
// FIXME check struct/union
|
||||
scc_parser_next_consume(parser, null);
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
scc_lexer_tok_t tok;
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
scc_pos_t pos = tok.loc;
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
const char *name = null;
|
||||
scc_ast_decl_t *decl = null;
|
||||
scc_ast_decl_vec_t member;
|
||||
@@ -614,9 +618,9 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
if (type_kind == SCC_AST_TYPE_STRUCT) {
|
||||
scc_ast_decl_struct_init(decl, name, &member);
|
||||
scc_ast_decl_struct_init(decl, name, &member, pos);
|
||||
} else {
|
||||
scc_ast_decl_union_init(decl, name, &member);
|
||||
scc_ast_decl_union_init(decl, name, &member, pos);
|
||||
}
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
} else {
|
||||
@@ -629,7 +633,7 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
}
|
||||
|
||||
scc_ast_type_t *type = ast_type_alloc();
|
||||
_scc_ast_type_record_init(type, type_kind, name, decl);
|
||||
_scc_ast_type_record_init(type, type_kind, name, decl, pos);
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -649,12 +653,16 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
enumeration-constant
|
||||
enumeration-constant = constant-expression
|
||||
*/
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ENUM)) {
|
||||
scc_lexer_tok_t tok;
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
scc_pos_t pos = tok.loc;
|
||||
if (tok.type != SCC_TOK_ENUM) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected 'enum'");
|
||||
return null;
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
scc_lexer_tok_t tok;
|
||||
const char *name = null;
|
||||
scc_ast_decl_t *decl = null;
|
||||
scc_ast_expr_vec_t member;
|
||||
@@ -697,7 +705,7 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
}
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
scc_ast_decl_enum_init(decl, name, &member);
|
||||
scc_ast_decl_enum_init(decl, name, &member, pos);
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
} else {
|
||||
if (name == null) {
|
||||
@@ -709,7 +717,7 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_type_t *type = ast_type_alloc();
|
||||
scc_ast_type_enum_init(type, name, decl);
|
||||
scc_ast_type_enum_init(type, name, decl, pos);
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -719,6 +727,10 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) {
|
||||
return null;
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
return null;
|
||||
}
|
||||
scc_pos_t pos = tok_ptr->loc;
|
||||
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_STRUCT:
|
||||
@@ -840,7 +852,7 @@ done:
|
||||
if (!check_type_combinations(parser, &info)) {
|
||||
return null;
|
||||
}
|
||||
return build_type_from_info(&info);
|
||||
return build_type_from_info(&info, pos);
|
||||
duplicate_error:
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Duplicate type specifier");
|
||||
return null;
|
||||
@@ -858,6 +870,7 @@ static scc_ast_type_t *parse_pointer(scc_parser_t *parser,
|
||||
if (tok_ptr == null || tok_ptr->type != SCC_TOK_MUL) {
|
||||
return pointee;
|
||||
}
|
||||
scc_pos_t pos = tok_ptr->loc;
|
||||
scc_parser_next_consume(parser, null);
|
||||
|
||||
scc_ast_type_t *pointer = ast_type_alloc();
|
||||
@@ -866,7 +879,7 @@ static scc_ast_type_t *parse_pointer(scc_parser_t *parser,
|
||||
*delay_pointee_ptr = pointer;
|
||||
pointee = pointer;
|
||||
}
|
||||
scc_ast_type_pointer_init(pointer, pointee);
|
||||
scc_ast_type_pointer_init(pointer, pointee, pos);
|
||||
pointer->quals = parse_type_qualifier_list(parser, pointer->quals);
|
||||
|
||||
return parse_pointer(parser, pointer, delay_pointee_ptr);
|
||||
@@ -887,6 +900,7 @@ static void parse_parameter_type_list(scc_parser_t *parser,
|
||||
*/
|
||||
scc_ast_decl_t *param = null;
|
||||
scc_ast_decl_t *decl = null;
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
while (1) {
|
||||
// FIXME
|
||||
scc_ast_type_t *type = scc_parse_declaration_specifiers(parser);
|
||||
@@ -904,14 +918,24 @@ static void parse_parameter_type_list(scc_parser_t *parser,
|
||||
param->base.type = SCC_AST_DECL_PARAM;
|
||||
|
||||
scc_vec_push(*params, param);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_COMMA)) {
|
||||
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type != SCC_TOK_COMMA) {
|
||||
break;
|
||||
}
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_ELLIPSIS)) {
|
||||
|
||||
scc_parser_next_consume(parser, null);
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type == SCC_TOK_ELLIPSIS) {
|
||||
param = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(param != null);
|
||||
// FIXME
|
||||
scc_ast_decl_param_init(param, &scc_ast_builtin_type_va_list, null);
|
||||
type = scc_malloc(sizeof(scc_ast_type_t));
|
||||
Assert(type != null);
|
||||
scc_ast_type_builtin_init(type, SCC_AST_BUILTIN_TYPE_VA_LIST,
|
||||
tok_ptr->loc);
|
||||
scc_ast_decl_param_init(param, type, null, tok_ptr->loc);
|
||||
scc_parser_next_consume(parser, null);
|
||||
scc_vec_push(*params, param);
|
||||
break;
|
||||
}
|
||||
@@ -1041,7 +1065,8 @@ parse_direct_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_decl_vec_t params;
|
||||
parse_function_parameters(parser, ¶ms);
|
||||
ret = ast_type_alloc();
|
||||
scc_ast_type_function_init(ret, base, ¶ms);
|
||||
// FIXME
|
||||
scc_ast_type_function_init(ret, base, ¶ms, base->base.loc);
|
||||
return parse_direct_declarator(parser, ret, delay_pointee_ptr,
|
||||
tok_ident);
|
||||
} else {
|
||||
@@ -1063,7 +1088,8 @@ parse_direct_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t *ret = ast_type_alloc();
|
||||
base =
|
||||
parse_direct_declarator(parser, base, delay_pointee_ptr, tok_ident);
|
||||
scc_ast_type_array_init(ret, base, size);
|
||||
// FIXME
|
||||
scc_ast_type_array_init(ret, base, size, base->base.loc);
|
||||
return ret;
|
||||
} else {
|
||||
return base;
|
||||
@@ -1112,7 +1138,8 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_decl_vec_t params;
|
||||
parse_function_parameters(parser, ¶ms);
|
||||
ret = ast_type_alloc();
|
||||
scc_ast_type_function_init(ret, base, ¶ms);
|
||||
// FIXME
|
||||
scc_ast_type_function_init(ret, base, ¶ms, base->base.loc);
|
||||
return parse_direct_abstract_declarator(parser, ret,
|
||||
delay_pointee_ptr);
|
||||
} else {
|
||||
@@ -1133,7 +1160,8 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t *ret = ast_type_alloc();
|
||||
base =
|
||||
parse_direct_abstract_declarator(parser, base, delay_pointee_ptr);
|
||||
scc_ast_type_array_init(ret, base, size);
|
||||
// FIXME
|
||||
scc_ast_type_array_init(ret, base, size, base->base.loc);
|
||||
return ret;
|
||||
} else {
|
||||
return base;
|
||||
@@ -1157,7 +1185,7 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
: null;
|
||||
|
||||
if (decl_type->base.type == SCC_AST_TYPE_FUNCTION) {
|
||||
scc_ast_decl_func_init(decl, decl_type, name, null);
|
||||
scc_ast_decl_func_init(decl, decl_type, name, null, decl_name_tok.loc);
|
||||
// TODO using sema to change it
|
||||
if (type->quals.is_inline) {
|
||||
decl_type->quals.is_inline = true;
|
||||
@@ -1165,7 +1193,8 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
type->quals.is_inline = false;
|
||||
}
|
||||
} else {
|
||||
scc_ast_decl_unsafe_val_init(decl, decl_type, name, null);
|
||||
scc_ast_decl_unsafe_val_init(decl, decl_type, name, null,
|
||||
decl_name_tok.loc);
|
||||
}
|
||||
|
||||
if (decl_name_tok.type != SCC_TOK_IDENT) {
|
||||
@@ -1175,10 +1204,11 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
if (decl_type->base.type == SCC_AST_TYPE_STRUCT) {
|
||||
scc_ast_decl_struct_init(decl, decl_type->record.name,
|
||||
null);
|
||||
scc_ast_decl_struct_init(decl, decl_type->record.name, null,
|
||||
decl_type->base.loc);
|
||||
} else {
|
||||
scc_ast_decl_union_init(decl, decl_type->record.name, null);
|
||||
scc_ast_decl_union_init(decl, decl_type->record.name, null,
|
||||
decl_type->base.loc);
|
||||
}
|
||||
} else {
|
||||
decl = decl_type->record.decl;
|
||||
@@ -1188,14 +1218,16 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
if (decl_type->enumeration.decl == null) {
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
scc_ast_decl_enum_init(decl, type->enumeration.name, null);
|
||||
scc_ast_decl_enum_init(decl, type->enumeration.name, null,
|
||||
decl_type->base.loc);
|
||||
} else {
|
||||
decl = type->enumeration.decl;
|
||||
scc_free(decl_type); // FIXME
|
||||
}
|
||||
} else {
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
scc_ast_decl_unsafe_val_init(decl, type, null, null);
|
||||
scc_ast_decl_unsafe_val_init(decl, type, null, null,
|
||||
decl_type->base.loc);
|
||||
}
|
||||
}
|
||||
return decl;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <scc_pos_log.h>
|
||||
#include <scc_sema.h>
|
||||
#include <sema_symtab.h>
|
||||
|
||||
@@ -10,12 +11,55 @@ static void type_callback(void *context, scc_ast_node_type_t node_type,
|
||||
return;
|
||||
}
|
||||
|
||||
static void decl_callback(void *context, scc_ast_node_type_t node_type,
|
||||
static void expr_callback(void *context, scc_ast_node_type_t node_type,
|
||||
void *node) {
|
||||
scc_sema_symtab_t *sema_symtab = context;
|
||||
|
||||
if (node_type == SCC_AST_UNKNOWN || node == null) {
|
||||
return;
|
||||
}
|
||||
scc_ast_expr_t *decl = SCC_AST_CAST_TO(scc_ast_expr_t, node);
|
||||
if (node_type == SCC_AST_EXPR_IDENTIFIER) {
|
||||
scc_ast_node_t *node =
|
||||
scc_sema_symtab_lookup_symbol(sema_symtab, decl->identifier.name);
|
||||
if (node == null) {
|
||||
SCC_ERROR(decl->base.loc, "Identifier '%s' not found",
|
||||
decl->identifier.name);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void stmt_callback(void *context, scc_ast_node_type_t node_type,
|
||||
void *node) {
|
||||
scc_sema_symtab_t *sema_symtab = context;
|
||||
|
||||
if (node_type == scc_ast_stmt_t_BEGIN) {
|
||||
scc_sema_symtab_enter_scope(sema_symtab);
|
||||
return;
|
||||
} else if (node_type == scc_ast_stmt_t_END) {
|
||||
scc_sema_symtab_leave_scope(sema_symtab);
|
||||
return;
|
||||
}
|
||||
if (node_type == SCC_AST_UNKNOWN || node == null) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void decl_callback(void *context, scc_ast_node_type_t node_type,
|
||||
void *node) {
|
||||
scc_sema_symtab_t *sema_symtab = context;
|
||||
if (node_type == scc_ast_decl_t_BEGIN) {
|
||||
scc_sema_symtab_enter_scope(sema_symtab);
|
||||
return;
|
||||
} else if (node_type == scc_ast_decl_t_END) {
|
||||
scc_sema_symtab_leave_scope(sema_symtab);
|
||||
return;
|
||||
}
|
||||
if (node_type == SCC_AST_UNKNOWN || node == null) {
|
||||
return;
|
||||
}
|
||||
scc_ast_decl_t *decl = SCC_AST_CAST_TO(scc_ast_decl_t, node);
|
||||
|
||||
scc_ast_type_t *type = scc_malloc(sizeof(scc_ast_type_t));
|
||||
@@ -24,25 +68,25 @@ static void decl_callback(void *context, scc_ast_node_type_t node_type,
|
||||
return;
|
||||
}
|
||||
if (decl->base.type == SCC_AST_DECL_STRUCT) {
|
||||
scc_ast_type_struct_init(type, decl->name, decl);
|
||||
scc_ast_type_struct_init(type, decl->name, decl, decl->base.loc);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$S_");
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (decl->base.type == SCC_AST_DECL_UNION) {
|
||||
scc_ast_type_union_init(type, decl->name, decl);
|
||||
scc_ast_type_union_init(type, decl->name, decl, decl->base.loc);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$U_");
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (decl->base.type == SCC_AST_DECL_ENUM) {
|
||||
scc_ast_type_enum_init(type, decl->name, decl);
|
||||
scc_ast_type_enum_init(type, decl->name, decl, decl->base.loc);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$E_");
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (decl->base.type == SCC_AST_DECL_TYPEDEF) {
|
||||
scc_ast_type_typedef_init(type, decl->name, decl);
|
||||
scc_ast_type_typedef_init(type, decl->name, decl, decl->base.loc);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, decl->name, &type->base);
|
||||
}
|
||||
return;
|
||||
@@ -67,18 +111,19 @@ void scc_sema_init(scc_sema_callbacks_t *callbacks) {
|
||||
}
|
||||
callbacks->context = sema_symtab;
|
||||
callbacks->on_decl = decl_callback;
|
||||
callbacks->on_expr = null;
|
||||
callbacks->on_stmt = null;
|
||||
callbacks->on_expr = expr_callback;
|
||||
callbacks->on_stmt = stmt_callback;
|
||||
callbacks->on_type = type_callback;
|
||||
callbacks->got_type = got_type_callback;
|
||||
|
||||
scc_sema_symtab_init(sema_symtab);
|
||||
|
||||
// FIXME memory leak
|
||||
scc_ast_type_t *type = scc_malloc(sizeof(scc_ast_type_t));
|
||||
scc_ast_type_builtin_init(type, SCC_AST_BUILTIN_TYPE_VA_LIST,
|
||||
scc_pos_create());
|
||||
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_list",
|
||||
&scc_ast_builtin_type_va_list.base);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_size_t",
|
||||
&scc_ast_builtin_type_long_long.base);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_ptrdiff_t",
|
||||
&scc_ast_builtin_type_long_long.base);
|
||||
&type->base);
|
||||
}
|
||||
|
||||
void scc_sema_drop(scc_sema_callbacks_t *callbacks) {}
|
||||
|
||||
0
libs/parser/tests/gen_ast.h
Normal file
0
libs/parser/tests/gen_ast.h
Normal file
95
libs/parser/tests/parser_test.h
Normal file
95
libs/parser/tests/parser_test.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <scc_lexer.h>
|
||||
#include <scc_parser.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <utest/acutest.h>
|
||||
|
||||
typedef scc_ast_node_t *(*scc_parse_node_func)(scc_parser_t *parser);
|
||||
|
||||
static scc_ast_node_t *process_input(const char *input,
|
||||
scc_parse_node_func parse_func,
|
||||
cbool need_sema) {
|
||||
int res = 0;
|
||||
scc_sstream_t mem_stream;
|
||||
res = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
|
||||
16);
|
||||
Assert(res == 0);
|
||||
|
||||
scc_lexer_t lexer;
|
||||
scc_lexer_init(&lexer, scc_sstream_to_ring(&mem_stream));
|
||||
|
||||
scc_lexer_tok_ring_t *tok_ring = scc_lexer_to_ring(&lexer, 64, false);
|
||||
|
||||
scc_parser_t parser;
|
||||
if (need_sema) {
|
||||
scc_sema_callbacks_t sema_callbacks;
|
||||
scc_sema_init(&sema_callbacks);
|
||||
scc_parser_init(&parser, tok_ring, &sema_callbacks);
|
||||
} else {
|
||||
scc_parser_init(&parser, tok_ring, null);
|
||||
}
|
||||
|
||||
scc_ast_node_t *ret = parse_func(&parser);
|
||||
|
||||
cbool not_eof = false;
|
||||
scc_ring_not_eof(*parser.ring, not_eof);
|
||||
if (not_eof == true) {
|
||||
// FIXME MAYBE free
|
||||
LOG_ERROR("Didn't consume all tokens");
|
||||
return null;
|
||||
}
|
||||
|
||||
scc_lexer_drop_ring(parser.ring);
|
||||
scc_parser_drop(&parser);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&mem_stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef void (*scc_tree_dump_output_t)(void *userdata, const char *fmt, ...);
|
||||
|
||||
#define BUFFER_SIZE (4096)
|
||||
char expect_buffer[BUFFER_SIZE];
|
||||
char output_buffer[BUFFER_SIZE];
|
||||
|
||||
static void dump2buffer(void *_buffer, const char *fmt, ...) {
|
||||
char *buffer = _buffer;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int res = scc_vsnprintf(buffer + strlen(buffer),
|
||||
BUFFER_SIZE - strlen(buffer) - 1, fmt, args);
|
||||
Assert(res > 0);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void _scc_check_ast(scc_ast_node_t *expect_node_ptr, const char *str,
|
||||
scc_parse_node_func parse_func, cbool need_sema) {
|
||||
scc_ast_node_t *output_node_ptr = process_input(str, parse_func, need_sema);
|
||||
scc_tree_dump_ctx_t ctx;
|
||||
expect_buffer[0] = '\n', expect_buffer[1] = '\0';
|
||||
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer);
|
||||
scc_ast_dump_node(&ctx, expect_node_ptr);
|
||||
scc_tree_dump_ctx_drop(&ctx);
|
||||
output_buffer[0] = '\n', output_buffer[1] = '\0';
|
||||
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, output_buffer);
|
||||
scc_ast_dump_node(&ctx, output_node_ptr);
|
||||
scc_tree_dump_ctx_drop(&ctx);
|
||||
}
|
||||
|
||||
#define SCC_CHECK_AST_WITH_SEMA(expect_node_ptr, str, parse_func) \
|
||||
do { \
|
||||
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func, \
|
||||
true); \
|
||||
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
|
||||
TEST_MSG("Expected: %s", expect_buffer); \
|
||||
TEST_MSG("Produced: %s", output_buffer); \
|
||||
} while (0);
|
||||
|
||||
#define SCC_CHECK_AST(expect_node_ptr, str, parse_func) \
|
||||
do { \
|
||||
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func, \
|
||||
false); \
|
||||
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
|
||||
TEST_MSG("Expected: %s", expect_buffer); \
|
||||
TEST_MSG("Produced: %s", output_buffer); \
|
||||
} while (0);
|
||||
395
libs/parser/tests/test_parse_expr.c
Normal file
395
libs/parser/tests/test_parse_expr.c
Normal file
@@ -0,0 +1,395 @@
|
||||
void init_func(void);
|
||||
#define TEST_INIT init_func()
|
||||
|
||||
#include "parser_test.h"
|
||||
|
||||
static scc_ast_type_t int_type;
|
||||
void init_func(void) {
|
||||
scc_ast_type_builtin_init(&int_type, SCC_AST_BUILTIN_TYPE_INT,
|
||||
scc_pos_create());
|
||||
}
|
||||
|
||||
#define LOC scc_pos_create()
|
||||
|
||||
static void test_primary_expr(void) {
|
||||
TEST_CASE("identifier");
|
||||
{
|
||||
scc_ast_expr_t ident;
|
||||
scc_ast_expr_identifier_init(&ident, "x", LOC);
|
||||
SCC_CHECK_AST(&ident.base, "x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("integer literal");
|
||||
{
|
||||
scc_ast_expr_t int_lit;
|
||||
scc_ast_expr_literal_int_init(&int_lit, "42", false, LOC);
|
||||
SCC_CHECK_AST(&int_lit.base, "42", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("string literal");
|
||||
{
|
||||
scc_ast_expr_t str_lit;
|
||||
scc_ast_expr_literal_string_init(&str_lit, "\"hello\"", false, LOC);
|
||||
SCC_CHECK_AST(&str_lit.base, "\"hello\"", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("parenthesized expression");
|
||||
{
|
||||
scc_ast_expr_t ident;
|
||||
scc_ast_expr_identifier_init(&ident, "y", LOC);
|
||||
// 解析器应直接返回内部表达式,因此期望结果与 "y" 相同
|
||||
SCC_CHECK_AST(&ident.base, "(y)", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_postfix_expr(void) {
|
||||
TEST_CASE("array subscript");
|
||||
{
|
||||
scc_ast_expr_t a, index, subscript;
|
||||
scc_ast_expr_identifier_init(&a, "a", LOC);
|
||||
scc_ast_expr_literal_int_init(&index, "10", false, LOC);
|
||||
scc_ast_expr_array_subscript_init(&subscript, &a, &index, LOC);
|
||||
SCC_CHECK_AST(&subscript.base, "a[10]", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("function call (no arguments)");
|
||||
{
|
||||
scc_ast_expr_t callee, call;
|
||||
scc_ast_expr_identifier_init(&callee, "f", LOC);
|
||||
scc_ast_expr_vec_t args;
|
||||
scc_vec_init(args);
|
||||
scc_ast_expr_call_init(&call, &callee, &args, LOC);
|
||||
SCC_CHECK_AST(&call.base, "f()", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("function call (with arguments)");
|
||||
{
|
||||
scc_ast_expr_t callee, arg1, arg2, call;
|
||||
scc_ast_expr_identifier_init(&callee, "f", LOC);
|
||||
scc_ast_expr_literal_int_init(&arg1, "1", false, LOC);
|
||||
scc_ast_expr_identifier_init(&arg2, "x", LOC);
|
||||
|
||||
scc_ast_expr_vec_t args;
|
||||
scc_vec_init(args);
|
||||
scc_vec_push(args, &arg1);
|
||||
scc_vec_push(args, &arg2);
|
||||
|
||||
scc_ast_expr_call_init(&call, &callee, &args, LOC);
|
||||
SCC_CHECK_AST(&call.base, "f(1, x)", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("member access (.)");
|
||||
{
|
||||
scc_ast_expr_t obj, member;
|
||||
scc_ast_expr_identifier_init(&obj, "s", LOC);
|
||||
scc_ast_expr_member_init(&member, &obj, "field", LOC);
|
||||
SCC_CHECK_AST(&member.base, "s.field", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("pointer member access (->)");
|
||||
{
|
||||
scc_ast_expr_t ptr, member;
|
||||
scc_ast_expr_identifier_init(&ptr, "p", LOC);
|
||||
scc_ast_expr_ptr_member_init(&member, &ptr, "field", LOC);
|
||||
SCC_CHECK_AST(&member.base, "p->field", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("postfix increment/decrement");
|
||||
{
|
||||
scc_ast_expr_t x, post_inc, post_dec;
|
||||
scc_ast_expr_identifier_init(&x, "x", LOC);
|
||||
scc_ast_expr_unary_init(&post_inc, SCC_AST_OP_POSTFIX_INCREMENT, &x,
|
||||
LOC);
|
||||
scc_ast_expr_unary_init(&post_dec, SCC_AST_OP_POSTFIX_DECREMENT, &x,
|
||||
LOC);
|
||||
SCC_CHECK_AST(&post_inc.base, "x++", scc_parse_expression);
|
||||
SCC_CHECK_AST(&post_dec.base, "x--", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_unary_expr(void) {
|
||||
scc_ast_expr_t x;
|
||||
scc_ast_expr_identifier_init(&x, "x", LOC);
|
||||
|
||||
TEST_CASE("prefix increment");
|
||||
{
|
||||
scc_ast_expr_t pre_inc;
|
||||
scc_ast_expr_unary_init(&pre_inc, SCC_AST_OP_PREFIX_INCREMENT, &x, LOC);
|
||||
SCC_CHECK_AST(&pre_inc.base, "++x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("prefix decrement");
|
||||
{
|
||||
scc_ast_expr_t pre_dec;
|
||||
scc_ast_expr_unary_init(&pre_dec, SCC_AST_OP_PREFIX_DECREMENT, &x, LOC);
|
||||
SCC_CHECK_AST(&pre_dec.base, "--x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("address-of");
|
||||
{
|
||||
scc_ast_expr_t addr;
|
||||
scc_ast_expr_unary_init(&addr, SCC_AST_OP_ADDRESS_OF, &x, LOC);
|
||||
SCC_CHECK_AST(&addr.base, "&x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("indirection (dereference)");
|
||||
{
|
||||
scc_ast_expr_t deref;
|
||||
scc_ast_expr_unary_init(&deref, SCC_AST_OP_INDIRECTION, &x, LOC);
|
||||
SCC_CHECK_AST(&deref.base, "*x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("unary plus");
|
||||
{
|
||||
scc_ast_expr_t plus;
|
||||
scc_ast_expr_unary_init(&plus, SCC_AST_OP_UNARY_PLUS, &x, LOC);
|
||||
SCC_CHECK_AST(&plus.base, "+x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("unary minus");
|
||||
{
|
||||
scc_ast_expr_t minus;
|
||||
scc_ast_expr_unary_init(&minus, SCC_AST_OP_UNARY_MINUS, &x, LOC);
|
||||
SCC_CHECK_AST(&minus.base, "-x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("bitwise NOT");
|
||||
{
|
||||
scc_ast_expr_t bit_not;
|
||||
scc_ast_expr_unary_init(&bit_not, SCC_AST_OP_BITWISE_NOT, &x, LOC);
|
||||
SCC_CHECK_AST(&bit_not.base, "~x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("logical NOT");
|
||||
{
|
||||
scc_ast_expr_t log_not;
|
||||
scc_ast_expr_unary_init(&log_not, SCC_AST_OP_LOGICAL_NOT, &x, LOC);
|
||||
SCC_CHECK_AST(&log_not.base, "!x", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("sizeof expression");
|
||||
{
|
||||
scc_ast_expr_t sizeof_expr;
|
||||
scc_ast_expr_sizeof_init(&sizeof_expr, NULL, &x, LOC);
|
||||
SCC_CHECK_AST(&sizeof_expr.base, "sizeof(x)", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("sizeof type");
|
||||
{
|
||||
scc_ast_expr_t sizeof_type;
|
||||
scc_ast_expr_sizeof_init(&sizeof_type, &int_type, NULL, LOC);
|
||||
SCC_CHECK_AST(&sizeof_type.base, "sizeof(int)", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_cast_expr(void) {
|
||||
TEST_CASE("cast");
|
||||
{
|
||||
scc_ast_expr_t x, cast;
|
||||
scc_ast_expr_identifier_init(&x, "x", LOC);
|
||||
scc_ast_expr_cast_init(&cast, &int_type, &x, LOC);
|
||||
SCC_CHECK_AST(&cast.base, "(int)x", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_binary_expr(void) {
|
||||
scc_ast_expr_t a, b, c, d;
|
||||
scc_ast_expr_identifier_init(&a, "a", LOC);
|
||||
scc_ast_expr_identifier_init(&b, "b", LOC);
|
||||
scc_ast_expr_identifier_init(&c, "c", LOC);
|
||||
scc_ast_expr_identifier_init(&d, "d", LOC);
|
||||
|
||||
TEST_CASE("multiplication and addition (priority)");
|
||||
{
|
||||
// a * b + c
|
||||
scc_ast_expr_t mul, add;
|
||||
scc_ast_expr_binary_init(&mul, SCC_AST_OP_MUL, &a, &b, LOC);
|
||||
scc_ast_expr_binary_init(&add, SCC_AST_OP_ADD, &mul, &c, LOC);
|
||||
SCC_CHECK_AST(&add.base, "a * b + c", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("subtraction (left associativity)");
|
||||
{
|
||||
// a - b - c => (a - b) - c
|
||||
scc_ast_expr_t sub1, sub2;
|
||||
scc_ast_expr_binary_init(&sub1, SCC_AST_OP_SUB, &a, &b, LOC);
|
||||
scc_ast_expr_binary_init(&sub2, SCC_AST_OP_SUB, &sub1, &c, LOC);
|
||||
SCC_CHECK_AST(&sub2.base, "a - b - c", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("shift");
|
||||
{
|
||||
// a << b
|
||||
scc_ast_expr_t shift;
|
||||
scc_ast_expr_binary_init(&shift, SCC_AST_OP_LEFT_SHIFT, &a, &b, LOC);
|
||||
SCC_CHECK_AST(&shift.base, "a << b", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("relational");
|
||||
{
|
||||
// a < b
|
||||
scc_ast_expr_t lt;
|
||||
scc_ast_expr_binary_init(<, SCC_AST_OP_LESS, &a, &b, LOC);
|
||||
SCC_CHECK_AST(<.base, "a < b", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("equality");
|
||||
{
|
||||
// a == b
|
||||
scc_ast_expr_t eq;
|
||||
scc_ast_expr_binary_init(&eq, SCC_AST_OP_EQUAL, &a, &b, LOC);
|
||||
SCC_CHECK_AST(&eq.base, "a == b", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("bitwise operators (priority)");
|
||||
{
|
||||
// a & b ^ c | d => ((a & b) ^ c) | d
|
||||
scc_ast_expr_t bitand, bitxor, bitor;
|
||||
scc_ast_expr_binary_init(&bitand, SCC_AST_OP_BITWISE_AND, &a, &b, LOC);
|
||||
scc_ast_expr_binary_init(&bitxor, SCC_AST_OP_BITWISE_XOR, &bitand, &c,
|
||||
LOC);
|
||||
scc_ast_expr_binary_init(&bitor, SCC_AST_OP_BITWISE_OR, &bitxor, &d,
|
||||
LOC);
|
||||
SCC_CHECK_AST(&bitor.base, "a & b ^ c | d", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("logical operators (priority)");
|
||||
{
|
||||
// a && b || c => (a && b) || c
|
||||
scc_ast_expr_t logand, logor;
|
||||
scc_ast_expr_binary_init(&logand, SCC_AST_OP_LOGICAL_AND, &a, &b, LOC);
|
||||
scc_ast_expr_binary_init(&logor, SCC_AST_OP_LOGICAL_OR, &logand, &c,
|
||||
LOC);
|
||||
SCC_CHECK_AST(&logor.base, "a && b || c", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_conditional_expr(void) {
|
||||
scc_ast_expr_t a, b, c;
|
||||
scc_ast_expr_identifier_init(&a, "a", LOC);
|
||||
scc_ast_expr_identifier_init(&b, "b", LOC);
|
||||
scc_ast_expr_identifier_init(&c, "c", LOC);
|
||||
|
||||
TEST_CASE("simple conditional");
|
||||
{
|
||||
scc_ast_expr_t cond;
|
||||
scc_ast_expr_cond_init(&cond, &a, &b, &c, LOC);
|
||||
SCC_CHECK_AST(&cond.base, "a ? b : c", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("nested conditional (right associative)");
|
||||
{
|
||||
// a ? b : c ? d : e => a ? b : (c ? d : e)
|
||||
scc_ast_expr_t d, e, inner, outer;
|
||||
scc_ast_expr_identifier_init(&d, "d", LOC);
|
||||
scc_ast_expr_identifier_init(&e, "e", LOC);
|
||||
scc_ast_expr_cond_init(&inner, &c, &d, &e, LOC);
|
||||
scc_ast_expr_cond_init(&outer, &a, &b, &inner, LOC);
|
||||
SCC_CHECK_AST(&outer.base, "a ? b : c ? d : e", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_assignment_expr(void) {
|
||||
scc_ast_expr_t a, b, c;
|
||||
scc_ast_expr_identifier_init(&a, "a", LOC);
|
||||
scc_ast_expr_identifier_init(&b, "b", LOC);
|
||||
scc_ast_expr_identifier_init(&c, "c", LOC);
|
||||
scc_ast_expr_t lit42;
|
||||
scc_ast_expr_literal_int_init(&lit42, "42", false, LOC);
|
||||
|
||||
TEST_CASE("simple assignment");
|
||||
{
|
||||
// a = 42
|
||||
scc_ast_expr_t assign;
|
||||
scc_ast_expr_binary_init(&assign, SCC_AST_OP_ASSIGN, &a, &lit42, LOC);
|
||||
SCC_CHECK_AST(&assign.base, "a = 42", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("chained assignment (right associative)");
|
||||
{
|
||||
// a = b = c
|
||||
scc_ast_expr_t inner, outer;
|
||||
scc_ast_expr_binary_init(&inner, SCC_AST_OP_ASSIGN, &b, &c, LOC);
|
||||
scc_ast_expr_binary_init(&outer, SCC_AST_OP_ASSIGN, &a, &inner, LOC);
|
||||
SCC_CHECK_AST(&outer.base, "a = b = c", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("compound assignment");
|
||||
{
|
||||
// a += b
|
||||
scc_ast_expr_t add_assign;
|
||||
scc_ast_expr_binary_init(&add_assign, SCC_AST_OP_ASSIGN_ADD, &a, &b,
|
||||
LOC);
|
||||
SCC_CHECK_AST(&add_assign.base, "a += b", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("assignment with expression");
|
||||
{
|
||||
// a = a - b + 42
|
||||
scc_ast_expr_t sub, add, assign;
|
||||
scc_ast_expr_binary_init(&sub, SCC_AST_OP_SUB, &a, &b, LOC);
|
||||
scc_ast_expr_binary_init(&add, SCC_AST_OP_ADD, &sub, &lit42, LOC);
|
||||
scc_ast_expr_binary_init(&assign, SCC_AST_OP_ASSIGN, &a, &add, LOC);
|
||||
SCC_CHECK_AST(&assign.base, "a = a - b + 42", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_comma_expr(void) {
|
||||
TEST_CASE("comma operator");
|
||||
{
|
||||
scc_ast_expr_t a, b, comma;
|
||||
scc_ast_expr_identifier_init(&a, "a", LOC);
|
||||
scc_ast_expr_identifier_init(&b, "b", LOC);
|
||||
scc_ast_expr_binary_init(&comma, SCC_AST_OP_COMMA, &a, &b, LOC);
|
||||
SCC_CHECK_AST(&comma.base, "a, b", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_complex_expr(void) {
|
||||
TEST_CASE("mixed operators with precedence");
|
||||
{
|
||||
scc_ast_expr_t a, b, c, d;
|
||||
scc_ast_expr_identifier_init(&a, "a", LOC);
|
||||
scc_ast_expr_identifier_init(&b, "b", LOC);
|
||||
scc_ast_expr_identifier_init(&c, "c", LOC);
|
||||
scc_ast_expr_identifier_init(&d, "d", LOC);
|
||||
|
||||
// a + b * c - d
|
||||
scc_ast_expr_t mul, add, sub;
|
||||
scc_ast_expr_binary_init(&mul, SCC_AST_OP_MUL, &b, &c, LOC);
|
||||
scc_ast_expr_binary_init(&add, SCC_AST_OP_ADD, &a, &mul, LOC);
|
||||
scc_ast_expr_binary_init(&sub, SCC_AST_OP_SUB, &add, &d, LOC);
|
||||
SCC_CHECK_AST(&sub.base, "a + b * c - d", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_CASE("postfix and unary combination");
|
||||
{
|
||||
scc_ast_expr_t p, post_inc, deref;
|
||||
scc_ast_expr_identifier_init(&p, "p", LOC);
|
||||
scc_ast_expr_unary_init(&post_inc, SCC_AST_OP_POSTFIX_INCREMENT, &p,
|
||||
LOC);
|
||||
scc_ast_expr_unary_init(&deref, SCC_AST_OP_INDIRECTION, &post_inc, LOC);
|
||||
SCC_CHECK_AST(&deref.base, "*p++", scc_parse_expression);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_detail_expr(void) {
|
||||
TEST_CASE("multi string literal connection");
|
||||
scc_ast_expr_t str;
|
||||
scc_ast_expr_literal_string_init(&str, "\"ab\"", false, scc_pos_create());
|
||||
SCC_CHECK_AST(&str.base, "\"a\" \"b\"", scc_parse_expression);
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"test_primary_expr", test_primary_expr},
|
||||
{"test_postfix_expr", test_postfix_expr},
|
||||
{"test_unary_expr", test_unary_expr},
|
||||
{"test_cast_expr", test_cast_expr},
|
||||
{"test_binary_expr", test_binary_expr},
|
||||
{"test_conditional_expr", test_conditional_expr},
|
||||
{"test_assignment_expr", test_assignment_expr},
|
||||
{"test_comma_expr", test_comma_expr},
|
||||
{"test_complex_expr", test_complex_expr},
|
||||
{"test_detail_expr", test_detail_expr},
|
||||
{NULL, NULL},
|
||||
};
|
||||
583
libs/parser/tests/test_parse_type.c
Normal file
583
libs/parser/tests/test_parse_type.c
Normal file
@@ -0,0 +1,583 @@
|
||||
void init_func(void);
|
||||
#define TEST_INIT init_func()
|
||||
|
||||
#include "parser_test.h"
|
||||
|
||||
static scc_ast_type_t int_type;
|
||||
static scc_ast_type_t char_type;
|
||||
static scc_ast_type_t void_type;
|
||||
static scc_ast_type_t pointer_int_type;
|
||||
static scc_ast_type_t pointer_char_type;
|
||||
static scc_ast_type_t pointer_void_type;
|
||||
static scc_ast_type_t pointer_pointer_int_type;
|
||||
|
||||
void init_func(void) {
|
||||
scc_ast_type_builtin_init(&int_type, SCC_AST_BUILTIN_TYPE_INT,
|
||||
scc_pos_create());
|
||||
scc_ast_type_builtin_init(&char_type, SCC_AST_BUILTIN_TYPE_CHAR,
|
||||
scc_pos_create());
|
||||
scc_ast_type_builtin_init(&void_type, SCC_AST_BUILTIN_TYPE_VOID,
|
||||
scc_pos_create());
|
||||
scc_ast_type_pointer_init(&pointer_int_type, &int_type, scc_pos_create());
|
||||
scc_ast_type_pointer_init(&pointer_char_type, &char_type, scc_pos_create());
|
||||
scc_ast_type_pointer_init(&pointer_void_type, &void_type, scc_pos_create());
|
||||
scc_ast_type_pointer_init(&pointer_pointer_int_type, &pointer_int_type,
|
||||
scc_pos_create());
|
||||
}
|
||||
|
||||
static void test_builtin_type(void) {
|
||||
#define CHECK_BUILTIN_TYPE(type, str) \
|
||||
do { \
|
||||
scc_ast_type_t builtin_type; \
|
||||
scc_ast_type_builtin_init(&builtin_type, type, scc_pos_create()); \
|
||||
SCC_CHECK_AST(&builtin_type.base, str, scc_parse_type_name); \
|
||||
} while (0)
|
||||
|
||||
// CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_VA_LIST, "...");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_VOID, "void");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_BOOL, "bool");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_CHAR, "char");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SHORT, "short");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_INT, "int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG, "long");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG, "long int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG_LONG, "long long");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG_LONG, "long long int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR, "unsigned char");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT, "unsigned short");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_INT, "unsigned int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG, "unsigned long");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG, "unsigned long int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
|
||||
"unsigned long long");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
|
||||
"unsigned long long int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_CHAR, "signed char");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_SHORT, "signed short");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_INT, "signed int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG, "signed long");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG, "signed long int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
|
||||
"signed long long");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
|
||||
"signed long long int");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_FLOAT, "float");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_DOUBLE, "double");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG_DOUBLE, "long double");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT, "complex float");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE, "complex double");
|
||||
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE,
|
||||
"complex long double");
|
||||
#undef CHECK_BUILTIN_TYPE
|
||||
}
|
||||
|
||||
static void test_pointer_type(void) {
|
||||
TEST_CASE("simple pointer");
|
||||
// int *
|
||||
SCC_CHECK_AST(&pointer_int_type.base, "int *", scc_parse_type_name);
|
||||
// int **
|
||||
SCC_CHECK_AST(&pointer_pointer_int_type.base, "int **",
|
||||
scc_parse_type_name);
|
||||
// int *** (需要临时构建)
|
||||
{
|
||||
scc_ast_type_t ptr_ptr_ptr_int;
|
||||
scc_ast_type_pointer_init(&ptr_ptr_ptr_int, &pointer_pointer_int_type,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&ptr_ptr_ptr_int.base, "int ***", scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_array_type(void) {
|
||||
scc_ast_expr_t size_5, size_3;
|
||||
|
||||
TEST_CASE("fixed size array");
|
||||
{
|
||||
// int [5]
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
scc_ast_type_t array_5_int;
|
||||
scc_ast_type_array_init(&array_5_int, &int_type, &size_5,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&array_5_int.base, "int [5]", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("incomplete array");
|
||||
{
|
||||
// int []
|
||||
scc_ast_type_t array_unknown_int;
|
||||
scc_ast_type_array_init(&array_unknown_int, &int_type, NULL,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&array_unknown_int.base, "int []", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("multidimensional array");
|
||||
{
|
||||
// int [5][3]
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
scc_ast_expr_literal_int_init(&size_3, "3", false, scc_pos_create());
|
||||
|
||||
scc_ast_type_t inner_array;
|
||||
scc_ast_type_array_init(&inner_array, &int_type, &size_3,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_type_t outer_array;
|
||||
scc_ast_type_array_init(&outer_array, &inner_array, &size_5,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&outer_array.base, "int [5][3]", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("pointer to array");
|
||||
{
|
||||
// int (*)[5]
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
|
||||
scc_ast_type_t array_5_int;
|
||||
scc_ast_type_array_init(&array_5_int, &int_type, &size_5,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_type_t ptr_to_array;
|
||||
scc_ast_type_pointer_init(&ptr_to_array, &array_5_int,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&ptr_to_array.base, "int (*)[5]", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("array of pointers");
|
||||
{
|
||||
// int *[5]
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
|
||||
scc_ast_type_t array_of_ptr;
|
||||
scc_ast_type_array_init(&array_of_ptr, &pointer_int_type, &size_5,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&array_of_ptr.base, "int *[5]", scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_function_type(void) {
|
||||
TEST_CASE("function with no parameters (old-style)");
|
||||
{
|
||||
// int ()
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, NULL,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&func_type.base, "int ()", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("function with void parameter");
|
||||
{
|
||||
// int (void)
|
||||
scc_ast_decl_t void_param;
|
||||
scc_ast_decl_param_init(&void_param, &void_type, NULL,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, &void_param);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, ¶ms,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&func_type.base, "int (void)", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("function with parameters");
|
||||
{
|
||||
// int (int, float)
|
||||
scc_ast_type_t float_type;
|
||||
scc_ast_type_builtin_init(&float_type, SCC_AST_BUILTIN_TYPE_FLOAT,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_t param_int, param_float;
|
||||
scc_ast_decl_param_init(¶m_int, &int_type, NULL, scc_pos_create());
|
||||
scc_ast_decl_param_init(¶m_float, &float_type, NULL,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, ¶m_int);
|
||||
scc_vec_push(params, ¶m_float);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, ¶ms,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&func_type.base, "int (int, float)", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("function with variadic parameters");
|
||||
{
|
||||
// int (int, ...)
|
||||
scc_ast_type_t va_list_type;
|
||||
scc_ast_type_builtin_init(&va_list_type, SCC_AST_BUILTIN_TYPE_VA_LIST,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_t param_int, param_var;
|
||||
scc_ast_decl_param_init(¶m_int, &int_type, NULL, scc_pos_create());
|
||||
scc_ast_decl_param_init(¶m_var, &va_list_type, "...",
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, ¶m_int);
|
||||
scc_vec_push(params, ¶m_var);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, ¶ms,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&func_type.base, "int (int, ...)", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("function returning pointer");
|
||||
{
|
||||
// int *()
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &pointer_int_type, NULL,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&func_type.base, "int *()", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("pointer to function");
|
||||
{
|
||||
// int (*)(void)
|
||||
scc_ast_decl_t void_param;
|
||||
scc_ast_decl_param_init(&void_param, &void_type, NULL,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, &void_param);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, ¶ms,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_type_t ptr_to_func;
|
||||
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
|
||||
SCC_CHECK_AST(&ptr_to_func.base, "int (*)(void)", scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_struct_union_type(void) {
|
||||
TEST_CASE("struct tag (incomplete)");
|
||||
{
|
||||
// struct S
|
||||
scc_ast_type_t struct_type;
|
||||
scc_ast_type_struct_init(&struct_type, "S", NULL, scc_pos_create());
|
||||
SCC_CHECK_AST(&struct_type.base, "struct S", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("union tag (incomplete)");
|
||||
{
|
||||
// union U
|
||||
scc_ast_type_t union_type;
|
||||
scc_ast_type_union_init(&union_type, "U", NULL, scc_pos_create());
|
||||
SCC_CHECK_AST(&union_type.base, "union U", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("anonymous struct definition");
|
||||
{
|
||||
// struct { int x; }
|
||||
scc_ast_decl_t field_x;
|
||||
scc_ast_decl_val_init(&field_x, &int_type, "x", NULL, scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t fields;
|
||||
scc_vec_init(fields);
|
||||
scc_vec_push(fields, &field_x);
|
||||
|
||||
scc_ast_decl_t struct_decl;
|
||||
scc_ast_decl_struct_init(&struct_decl, NULL, &fields, scc_pos_create());
|
||||
|
||||
scc_ast_type_t struct_type;
|
||||
scc_ast_type_struct_init(&struct_type, NULL, &struct_decl,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&struct_type.base, "struct { int x; }",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("named struct definition");
|
||||
{
|
||||
// struct S { int x; }
|
||||
scc_ast_decl_t field_x;
|
||||
scc_ast_decl_val_init(&field_x, &int_type, "x", NULL, scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t fields;
|
||||
scc_vec_init(fields);
|
||||
scc_vec_push(fields, &field_x);
|
||||
|
||||
scc_ast_decl_t struct_decl;
|
||||
scc_ast_decl_struct_init(&struct_decl, "S", &fields, scc_pos_create());
|
||||
|
||||
scc_ast_type_t struct_type;
|
||||
scc_ast_type_struct_init(&struct_type, "S", &struct_decl,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&struct_type.base, "struct S { int x; }",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("union definition");
|
||||
{
|
||||
// union { int a; float b; }
|
||||
scc_ast_type_t float_type;
|
||||
scc_ast_type_builtin_init(&float_type, SCC_AST_BUILTIN_TYPE_FLOAT,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_t field_a, field_b;
|
||||
scc_ast_decl_val_init(&field_a, &int_type, "a", NULL, scc_pos_create());
|
||||
scc_ast_decl_val_init(&field_b, &float_type, "b", NULL,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_decl_vec_t fields;
|
||||
scc_vec_init(fields);
|
||||
scc_vec_push(fields, &field_a);
|
||||
scc_vec_push(fields, &field_b);
|
||||
|
||||
scc_ast_decl_t union_decl;
|
||||
scc_ast_decl_union_init(&union_decl, NULL, &fields, scc_pos_create());
|
||||
|
||||
scc_ast_type_t union_type;
|
||||
scc_ast_type_union_init(&union_type, NULL, &union_decl,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&union_type.base, "union { int a; float b; }",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_enum_type(void) {
|
||||
TEST_CASE("enum tag (incomplete)");
|
||||
{
|
||||
// enum E
|
||||
scc_ast_type_t enum_type;
|
||||
scc_ast_type_enum_init(&enum_type, "E", NULL, scc_pos_create());
|
||||
SCC_CHECK_AST(&enum_type.base, "enum E", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("anonymous enum definition");
|
||||
{
|
||||
// enum { RED, GREEN, BLUE }
|
||||
scc_ast_expr_t red, green, blue;
|
||||
scc_ast_expr_identifier_init(&red, "RED", scc_pos_create());
|
||||
scc_ast_expr_identifier_init(&green, "GREEN", scc_pos_create());
|
||||
scc_ast_expr_identifier_init(&blue, "BLUE", scc_pos_create());
|
||||
|
||||
scc_ast_expr_vec_t enumerators;
|
||||
scc_vec_init(enumerators);
|
||||
scc_vec_push(enumerators, &red);
|
||||
scc_vec_push(enumerators, &green);
|
||||
scc_vec_push(enumerators, &blue);
|
||||
|
||||
scc_ast_decl_t enum_decl;
|
||||
scc_ast_decl_enum_init(&enum_decl, NULL, &enumerators,
|
||||
scc_pos_create());
|
||||
|
||||
scc_ast_type_t enum_type;
|
||||
scc_ast_type_enum_init(&enum_type, NULL, &enum_decl, scc_pos_create());
|
||||
SCC_CHECK_AST(&enum_type.base, "enum { RED, GREEN, BLUE }",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("named enum definition");
|
||||
{
|
||||
// enum E { RED, GREEN, BLUE }
|
||||
scc_ast_expr_t red, green, blue;
|
||||
scc_ast_expr_identifier_init(&red, "RED", scc_pos_create());
|
||||
scc_ast_expr_identifier_init(&green, "GREEN", scc_pos_create());
|
||||
scc_ast_expr_identifier_init(&blue, "BLUE", scc_pos_create());
|
||||
|
||||
scc_ast_expr_vec_t enumerators;
|
||||
scc_vec_init(enumerators);
|
||||
scc_vec_push(enumerators, &red);
|
||||
scc_vec_push(enumerators, &green);
|
||||
scc_vec_push(enumerators, &blue);
|
||||
|
||||
scc_ast_decl_t enum_decl;
|
||||
scc_ast_decl_enum_init(&enum_decl, "E", &enumerators, scc_pos_create());
|
||||
|
||||
scc_ast_type_t enum_type;
|
||||
scc_ast_type_enum_init(&enum_type, "E", &enum_decl, scc_pos_create());
|
||||
SCC_CHECK_AST(&enum_type.base, "enum E { RED, GREEN, BLUE }",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_specifier_type(void) {
|
||||
TEST_CASE("const/volatile on builtin types");
|
||||
{
|
||||
// const int
|
||||
scc_ast_type_t const_int = int_type;
|
||||
const_int.quals.is_const = true;
|
||||
SCC_CHECK_AST(&const_int.base, "const int", scc_parse_type_name);
|
||||
|
||||
// volatile int
|
||||
scc_ast_type_t volatile_int = int_type;
|
||||
volatile_int.quals.is_volatile = true;
|
||||
SCC_CHECK_AST(&volatile_int.base, "volatile int", scc_parse_type_name);
|
||||
|
||||
// const volatile int
|
||||
scc_ast_type_t const_volatile_int = int_type;
|
||||
const_volatile_int.quals.is_const = true;
|
||||
const_volatile_int.quals.is_volatile = true;
|
||||
SCC_CHECK_AST(&const_volatile_int.base, "const volatile int",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("const/volatile on pointers");
|
||||
{
|
||||
// int * const (const pointer to int)
|
||||
scc_ast_type_t const_ptr_to_int = pointer_int_type;
|
||||
const_ptr_to_int.quals.is_const = true;
|
||||
SCC_CHECK_AST(&const_ptr_to_int.base, "int * const",
|
||||
scc_parse_type_name);
|
||||
|
||||
// const int * (pointer to const int)
|
||||
scc_ast_type_t const_int = int_type;
|
||||
const_int.quals.is_const = true;
|
||||
scc_ast_type_t ptr_to_const_int;
|
||||
scc_ast_type_pointer_init(&ptr_to_const_int, &const_int,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&ptr_to_const_int.base, "const int *",
|
||||
scc_parse_type_name);
|
||||
|
||||
// const int * const (const pointer to const int)
|
||||
scc_ast_type_t const_ptr_to_const_int;
|
||||
scc_ast_type_pointer_init(&const_ptr_to_const_int, &const_int,
|
||||
scc_pos_create());
|
||||
const_ptr_to_const_int.quals.is_const = true;
|
||||
SCC_CHECK_AST(&const_ptr_to_const_int.base, "const int * const",
|
||||
scc_parse_type_name);
|
||||
|
||||
// volatile int * restrict (restrict pointer to volatile int)
|
||||
scc_ast_type_t volatile_int = int_type;
|
||||
volatile_int.quals.is_volatile = true;
|
||||
scc_ast_type_t restrict_ptr_to_volatile_int;
|
||||
scc_ast_type_pointer_init(&restrict_ptr_to_volatile_int, &volatile_int,
|
||||
scc_pos_create());
|
||||
restrict_ptr_to_volatile_int.quals.is_restrict = true;
|
||||
SCC_CHECK_AST(&restrict_ptr_to_volatile_int.base,
|
||||
"volatile int * restrict", scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("const on array element type");
|
||||
{
|
||||
// const int [5]
|
||||
scc_ast_expr_t size_5;
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
|
||||
scc_ast_type_t const_int = int_type;
|
||||
const_int.quals.is_const = true;
|
||||
|
||||
scc_ast_type_t const_array;
|
||||
scc_ast_type_array_init(&const_array, &const_int, &size_5,
|
||||
scc_pos_create());
|
||||
SCC_CHECK_AST(&const_array.base, "const int [5]", scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_hard_type(void) {
|
||||
TEST_CASE("pointer to array of pointers to function");
|
||||
// int (*(*)[5])(void)
|
||||
{
|
||||
// 1) 函数类型 int (void)
|
||||
scc_ast_decl_t void_param;
|
||||
scc_ast_decl_param_init(&void_param, &void_type, NULL,
|
||||
scc_pos_create());
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, &void_param);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, ¶ms,
|
||||
scc_pos_create());
|
||||
|
||||
// 2) 指向函数的指针
|
||||
scc_ast_type_t ptr_to_func;
|
||||
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
|
||||
|
||||
// 3) 数组,元素为上述指针,大小5
|
||||
scc_ast_expr_t size_5;
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
|
||||
scc_ast_type_t array_of_ptr;
|
||||
scc_ast_type_array_init(&array_of_ptr, &ptr_to_func, &size_5,
|
||||
scc_pos_create());
|
||||
|
||||
// 4) 指向数组的指针
|
||||
scc_ast_type_t ptr_to_array;
|
||||
scc_ast_type_pointer_init(&ptr_to_array, &array_of_ptr,
|
||||
scc_pos_create());
|
||||
|
||||
SCC_CHECK_AST(&ptr_to_array.base, "int (*(*)[5])(void)",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("pointer to function returning pointer to array");
|
||||
// int (*(*)(void))[5]
|
||||
{
|
||||
// 1) 数组类型 int [5]
|
||||
scc_ast_expr_t size_5;
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
|
||||
|
||||
scc_ast_type_t array_type;
|
||||
scc_ast_type_array_init(&array_type, &int_type, &size_5,
|
||||
scc_pos_create());
|
||||
|
||||
// 2) 指向数组的指针
|
||||
scc_ast_type_t ptr_to_array;
|
||||
scc_ast_type_pointer_init(&ptr_to_array, &array_type, scc_pos_create());
|
||||
|
||||
// 3) 函数类型,返回上述指针,无参数
|
||||
scc_ast_decl_t void_param;
|
||||
scc_ast_decl_param_init(&void_param, &void_type, NULL,
|
||||
scc_pos_create());
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, &void_param);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &ptr_to_array, ¶ms,
|
||||
scc_pos_create());
|
||||
|
||||
// 4) 指向函数的指针
|
||||
scc_ast_type_t ptr_to_func;
|
||||
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
|
||||
|
||||
SCC_CHECK_AST(&ptr_to_func.base, "int (*(*)(void))[5]",
|
||||
scc_parse_type_name);
|
||||
}
|
||||
|
||||
TEST_CASE("function returning pointer to function");
|
||||
// int (*())(void)
|
||||
{
|
||||
// 1) 函数类型 int (void)
|
||||
scc_ast_decl_t void_param;
|
||||
scc_ast_decl_param_init(&void_param, &void_type, NULL,
|
||||
scc_pos_create());
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, &void_param);
|
||||
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &int_type, ¶ms,
|
||||
scc_pos_create());
|
||||
|
||||
// 2) 指向该函数的指针
|
||||
scc_ast_type_t ptr_to_func;
|
||||
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
|
||||
|
||||
// 3) 外部函数类型,返回上述指针,无参数
|
||||
scc_ast_type_t outer_func;
|
||||
scc_ast_type_function_init(&outer_func, &ptr_to_func, NULL,
|
||||
scc_pos_create());
|
||||
|
||||
SCC_CHECK_AST(&outer_func.base, "int (*())(void)", scc_parse_type_name);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"test_builtin_type", test_builtin_type},
|
||||
{"test_pointer_type", test_pointer_type},
|
||||
{"test_array_type", test_array_type},
|
||||
{"test_function_type", test_function_type},
|
||||
{"test_struct_union_type", test_struct_union_type},
|
||||
{"test_enum_type", test_enum_type},
|
||||
{"test_specifier_type", test_specifier_type},
|
||||
{"test_hard_type", test_hard_type},
|
||||
{NULL, NULL},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
5
libs/parser/tests/test_sema_unit.c
Normal file
5
libs/parser/tests/test_sema_unit.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <utest/acutest.h>
|
||||
|
||||
TEST_LIST = {
|
||||
{NULL, NULL},
|
||||
};
|
||||
@@ -69,6 +69,66 @@ scc_pe_section_range scc_pe_reserve_section_header(scc_pe_builder_t *builder,
|
||||
u32 virtual_size,
|
||||
u32 data_size);
|
||||
|
||||
static inline scc_pe_section_range
|
||||
scc_pe_reserve_text_section_header(scc_pe_builder_t *builder, u32 data_size) {
|
||||
return scc_pe_reserve_section_header(
|
||||
builder, (BYTE *)".text\0\0",
|
||||
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
|
||||
data_size, data_size);
|
||||
}
|
||||
|
||||
static inline scc_pe_section_range
|
||||
scc_pe_reserve_data_section_header(scc_pe_builder_t *builder, u32 data_size) {
|
||||
return scc_pe_reserve_section_header(builder, (BYTE *)".data\0\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
data_size, data_size);
|
||||
}
|
||||
|
||||
static inline scc_pe_section_range
|
||||
scc_pe_reserve_rdata_section_header(scc_pe_builder_t *builder, u32 data_size) {
|
||||
return scc_pe_reserve_section_header(builder, (BYTE *)".rdata\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA |
|
||||
IMAGE_SCN_MEM_READ,
|
||||
data_size, data_size);
|
||||
}
|
||||
|
||||
static inline scc_pe_section_range
|
||||
scc_pe_reserve_bss_section_header(scc_pe_builder_t *builder, u32 data_size) {
|
||||
return scc_pe_reserve_section_header(builder, (BYTE *)".bss\0\0\0",
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA |
|
||||
IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
data_size, 0);
|
||||
}
|
||||
|
||||
static inline scc_pe_section_range
|
||||
scc_pe_reserve_idata_section_header(scc_pe_builder_t *builder, u32 data_size) {
|
||||
scc_pe_section_range range = scc_pe_reserve_section_header(
|
||||
builder, (BYTE *)".idata\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
data_size, data_size);
|
||||
scc_vec_at(builder->image_data_directory_vec,
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT) = (IMAGE_DATA_DIRECTORY){
|
||||
.VirtualAddress = range.virual_address, .Size = range.virual_size};
|
||||
return range;
|
||||
}
|
||||
|
||||
static inline scc_pe_section_range
|
||||
scc_pe_reserve_reloc_section_header(scc_pe_builder_t *builder, u32 data_size) {
|
||||
scc_pe_section_range range = scc_pe_reserve_section_header(
|
||||
builder, (BYTE *)".reloc\0\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_DISCARDABLE,
|
||||
data_size, data_size);
|
||||
scc_vec_at(builder->image_data_directory_vec,
|
||||
IMAGE_DIRECTORY_ENTRY_BASERELOC) = (IMAGE_DATA_DIRECTORY){
|
||||
.VirtualAddress = range.virual_address, .Size = range.virual_size};
|
||||
return range;
|
||||
}
|
||||
|
||||
void scc_pe_write_header(scc_pe_builder_t *builder, scc_pe_config_t *config);
|
||||
|
||||
void scc_pe_write_section(scc_pe_builder_t *builder,
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*
|
||||
* @bug 可以有更好的方式解决这个问题
|
||||
*/
|
||||
#ifdef DUMMYUNIONNAME
|
||||
#undef DUMMYUNIONNAME
|
||||
#endif
|
||||
#define DUMMYUNIONNAME DUMMYUNIONNAME
|
||||
|
||||
// 基本类型定义
|
||||
|
||||
@@ -10,33 +10,21 @@ typedef struct {
|
||||
scc_pe_buffer_t data; ///< 具体数据
|
||||
scc_hashtable_t str_map; ///< 符号名称映射到data的idx
|
||||
u32 section_offset; ///< 在idata中的偏移
|
||||
} scc_winpe_hnt_builder_t;
|
||||
|
||||
typedef struct {
|
||||
u32 offset; ///< 相对代码段的偏移地址
|
||||
i32 addend; ///< 可选的偏移量的附加值 可选默认为0
|
||||
u8 size; ///< 引用的地址的大小
|
||||
const char *library_name; ///< 库名称 eg. "Kernel32.dll"
|
||||
const char *symbol_name; ///< 导入dll的符号名称 eg. "CreateFileW"
|
||||
u16 ordinal; ///< 符号的序号 eg. 可选
|
||||
} scc_winpe_extern_t;
|
||||
typedef SCC_VEC(scc_winpe_extern_t) scc_winpe_extern_vec_t;
|
||||
} scc_pe_hnt_builder_t;
|
||||
|
||||
typedef SCC_VEC(const char *) scc_winpe_name_vec_t;
|
||||
typedef struct {
|
||||
const char *name;
|
||||
scc_winpe_name_vec_t symbol_names;
|
||||
} scc_winpe_idata_lib_t;
|
||||
typedef SCC_VEC(scc_winpe_idata_lib_t) scc_winpe_idata_lib_vec_t;
|
||||
typedef SCC_VEC(scc_winpe_idata_lib_t) scc_pe_idata_lib_vec_t;
|
||||
typedef struct {
|
||||
scc_pe_buffer_t buffer; ///< 导入表数据
|
||||
scc_winpe_extern_vec_t externs;
|
||||
scc_hashtable_t externs_set;
|
||||
|
||||
scc_winpe_hnt_builder_t hnt_builder;
|
||||
scc_pe_hnt_builder_t hnt_builder;
|
||||
scc_hashtable_t iat_map; ///< 符号名称映射到idata的虚拟镜像地址
|
||||
scc_winpe_idata_lib_vec_t idata_libs;
|
||||
} scc_winpe_idata_builder_t;
|
||||
scc_pe_idata_lib_vec_t idata_libs;
|
||||
} scc_pe_idata_builder_t;
|
||||
|
||||
/**
|
||||
* @brief PE格式导入表构建器初始化
|
||||
@@ -45,8 +33,8 @@ typedef struct {
|
||||
* @param builder
|
||||
* @param idata_libs
|
||||
*/
|
||||
void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
|
||||
scc_winpe_idata_lib_vec_t *idata_libs);
|
||||
void scc_pe_idata_builder_init(scc_pe_idata_builder_t *builder,
|
||||
scc_pe_idata_lib_vec_t *idata_libs);
|
||||
|
||||
/**
|
||||
* @brief 获取导入表占据的大小
|
||||
@@ -55,7 +43,7 @@ void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
|
||||
* @param builder
|
||||
* @return u32
|
||||
*/
|
||||
u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder);
|
||||
u32 scc_pe_reserve_idata(scc_pe_idata_builder_t *builder);
|
||||
|
||||
/**
|
||||
* @brief 构造导入表
|
||||
@@ -64,13 +52,12 @@ u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder);
|
||||
* @param builder
|
||||
* @param idata_range
|
||||
*/
|
||||
scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder,
|
||||
scc_pe_buffer_t scc_pe_construct_idata(scc_pe_idata_builder_t *builder,
|
||||
scc_pe_section_range *idata_range);
|
||||
|
||||
// RVA Relative Virtual Address
|
||||
static inline u64
|
||||
scc_pe_idata_get_symbol_rva(scc_winpe_idata_builder_t *builder,
|
||||
const char *symbol_name) {
|
||||
static inline u64 scc_pe_idata_get_symbol_rva(scc_pe_idata_builder_t *builder,
|
||||
const char *symbol_name) {
|
||||
return (u64)scc_hashtable_get(&builder->iat_map, symbol_name);
|
||||
}
|
||||
|
||||
|
||||
45
libs/target/pe/include/scc_pe_reloc.h
Normal file
45
libs/target/pe/include/scc_pe_reloc.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef __SCC_PE_RELOC_H__
|
||||
#define __SCC_PE_RELOC_H__
|
||||
|
||||
#include "scc_pe_def.h"
|
||||
|
||||
typedef struct {
|
||||
u32 offset; ///< 相对代码段的偏移地址
|
||||
i32 addend; ///< 可选的偏移量的附加值 可选默认为0
|
||||
u8 size; ///< 引用的地址的大小
|
||||
const char *library_name; ///< 库名称 eg. "Kernel32.dll"
|
||||
const char *symbol_name; ///< 导入dll的符号名称 eg. "CreateFileW"
|
||||
u16 ordinal; ///< 符号的序号 eg. 可选
|
||||
} scc_pe_extern_t;
|
||||
typedef SCC_VEC(scc_pe_extern_t) scc_pe_extern_vec_t;
|
||||
|
||||
typedef struct {
|
||||
scc_pe_extern_vec_t externs;
|
||||
scc_hashtable_t externs_set;
|
||||
|
||||
} scc_pe_reloc_builder_t;
|
||||
|
||||
void scc_pe_reloc_builder_init(scc_pe_reloc_builder_t *builder);
|
||||
|
||||
// void scc_pe_reloc_add_item(scc_pe_reloc_builder_t *builder, );
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @warning
|
||||
*
|
||||
* @param builder
|
||||
* @return u32
|
||||
*/
|
||||
u32 scc_pe_reserve_reloc(scc_pe_reloc_builder_t *builder);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @warning
|
||||
*
|
||||
* @param builder
|
||||
* @param reloc_range
|
||||
*/
|
||||
scc_pe_buffer_t scc_pe_construct_reloc(scc_pe_reloc_builder_t *builder,
|
||||
scc_pe_section_range *reloc_range);
|
||||
|
||||
#endif /* __SCC_PE_RELOC_H__ */
|
||||
@@ -13,9 +13,9 @@ image_import_descriptor_init(u32 import_lookup_table_rva, u32 name_rva,
|
||||
return iid;
|
||||
};
|
||||
|
||||
static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
|
||||
static void scc_winpe_hnt_builder_push(scc_pe_hnt_builder_t *builder,
|
||||
const char *name, u16 hint);
|
||||
static void scc_winpe_hnt_builder_init(scc_winpe_hnt_builder_t *builder) {
|
||||
static void scc_winpe_hnt_builder_init(scc_pe_hnt_builder_t *builder) {
|
||||
scc_vec_init(builder->data);
|
||||
builder->section_offset = 0;
|
||||
scc_hashtable_init(&builder->str_map,
|
||||
@@ -23,7 +23,7 @@ static void scc_winpe_hnt_builder_init(scc_winpe_hnt_builder_t *builder) {
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
}
|
||||
|
||||
static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
|
||||
static void scc_winpe_hnt_builder_push(scc_pe_hnt_builder_t *builder,
|
||||
const char *name, u16 hint) {
|
||||
///< 可选哈希表去重
|
||||
if (scc_hashtable_get(&builder->str_map, name)) {
|
||||
@@ -49,13 +49,13 @@ static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
|
||||
Assert(scc_vec_size(builder->data) % 2 == 0);
|
||||
}
|
||||
|
||||
static u64 scc_winpe_hnt_get_offset(scc_winpe_hnt_builder_t *builder,
|
||||
static u64 scc_winpe_hnt_get_offset(scc_pe_hnt_builder_t *builder,
|
||||
const char *name) {
|
||||
return (u64)scc_hashtable_get(&builder->str_map, name);
|
||||
}
|
||||
|
||||
void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
|
||||
scc_winpe_idata_lib_vec_t *idata_libs) {
|
||||
void scc_pe_idata_builder_init(scc_pe_idata_builder_t *builder,
|
||||
scc_pe_idata_lib_vec_t *idata_libs) {
|
||||
scc_vec_init(builder->buffer);
|
||||
builder->idata_libs = *idata_libs;
|
||||
|
||||
@@ -66,7 +66,7 @@ void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
}
|
||||
|
||||
u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder) {
|
||||
u32 scc_pe_reserve_idata(scc_pe_idata_builder_t *builder) {
|
||||
u32 idata_size = (scc_vec_size(builder->idata_libs) + 1) *
|
||||
sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
|
||||
@@ -89,7 +89,7 @@ u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder) {
|
||||
return idata_size;
|
||||
}
|
||||
|
||||
scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder,
|
||||
scc_pe_buffer_t scc_pe_construct_idata(scc_pe_idata_builder_t *builder,
|
||||
scc_pe_section_range *idata_range) {
|
||||
u32 idata_rva = idata_range->virual_address;
|
||||
u32 hnt_offset = builder->hnt_builder.section_offset;
|
||||
|
||||
0
libs/target/pe/src/scc_pe_reloc.c
Normal file
0
libs/target/pe/src/scc_pe_reloc.c
Normal file
@@ -24,19 +24,14 @@ int main() {
|
||||
scc_pe_builder_t builder = {0};
|
||||
scc_pe_builder_init(&builder, true, 4096, 512);
|
||||
scc_pe_reserve_header(&builder, 3);
|
||||
scc_pe_section_range code_range = scc_pe_reserve_section_header(
|
||||
&builder, (BYTE *)".text\0\0",
|
||||
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE,
|
||||
sizeof(code), sizeof(code));
|
||||
scc_pe_section_range code_range =
|
||||
scc_pe_reserve_text_section_header(&builder, sizeof(code));
|
||||
|
||||
scc_pe_section_range data_range = scc_pe_reserve_section_header(
|
||||
&builder, (BYTE *)".data\0\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
sizeof(data), sizeof(data));
|
||||
scc_pe_section_range data_range =
|
||||
scc_pe_reserve_data_section_header(&builder, sizeof(data));
|
||||
|
||||
scc_winpe_idata_builder_t idata_builder;
|
||||
scc_winpe_idata_lib_vec_t idata_libs;
|
||||
scc_pe_idata_builder_t idata_builder;
|
||||
scc_pe_idata_lib_vec_t idata_libs;
|
||||
scc_vec_init(idata_libs);
|
||||
scc_winpe_idata_lib_t ucrtbase;
|
||||
ucrtbase.name = "ucrtbase.dll";
|
||||
@@ -45,14 +40,8 @@ int main() {
|
||||
scc_vec_push(idata_libs, ucrtbase);
|
||||
scc_pe_idata_builder_init(&idata_builder, &idata_libs);
|
||||
u32 idata_size = scc_pe_reserve_idata(&idata_builder);
|
||||
scc_pe_section_range idata_range = scc_pe_reserve_section_header(
|
||||
&builder, (BYTE *)".idata\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
idata_size, idata_size);
|
||||
scc_vec_at(builder.image_data_directory_vec, IMAGE_DIRECTORY_ENTRY_IMPORT) =
|
||||
(IMAGE_DATA_DIRECTORY){.VirtualAddress = idata_range.virual_address,
|
||||
.Size = idata_range.virual_size};
|
||||
scc_pe_section_range idata_range =
|
||||
scc_pe_reserve_idata_section_header(&builder, idata_size);
|
||||
scc_pe_buffer_t idata_buffer =
|
||||
scc_pe_construct_idata(&idata_builder, &idata_range);
|
||||
|
||||
@@ -97,5 +86,5 @@ int main() {
|
||||
scc_pe_write_section(&builder, &idata_range,
|
||||
scc_vec_unsafe_get_data(idata_buffer),
|
||||
scc_vec_size(idata_buffer));
|
||||
scc_pe_dump_to_file(&builder, "hello_world.exe");
|
||||
scc_pe_dump_to_file(&builder, __FILE__ "/../pe_write_idata.exe");
|
||||
}
|
||||
2
libs/target/pe/tests/test_pe_write_reloc.c
Normal file
2
libs/target/pe/tests/test_pe_write_reloc.c
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
int main(void) { return 0; }
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void test_example() {
|
||||
printf("Test passed!\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_example();
|
||||
return 0;
|
||||
}
|
||||
142
src/config.h
Normal file
142
src/config.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef __SCC_CONFIG_H__
|
||||
#define __SCC_CONFIG_H__
|
||||
|
||||
#include <argparse.h>
|
||||
|
||||
typedef struct {
|
||||
const char *input_file;
|
||||
const char *output_file;
|
||||
int verbose;
|
||||
scc_argparse_list_t include_paths;
|
||||
scc_argparse_list_t define_macros;
|
||||
cbool emit_lex;
|
||||
cbool emit_pp;
|
||||
cbool emit_ast;
|
||||
cbool emit_ir;
|
||||
} scc_config_t;
|
||||
|
||||
static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
scc_argparse_lang_t lang) {
|
||||
enum {
|
||||
SCC_HINT_PROG_NAME,
|
||||
SCC_HINT_DESCRIPTION,
|
||||
SCC_HINT_OUTPUT_FILE,
|
||||
SCC_HINT_INPUT_FILE,
|
||||
SCC_HINT_INCLUDE_PATH,
|
||||
SCC_HINT_DEFINED_MACRO,
|
||||
SCC_HINT_VERBOSE,
|
||||
|
||||
SCC_HINT_EMIT_LEX,
|
||||
SCC_HINT_EMIT_PP,
|
||||
SCC_HINT_EMIT_AST,
|
||||
SCC_HINT_EMIT_IR,
|
||||
};
|
||||
static const char *scc_hints_en[] = {
|
||||
[SCC_HINT_PROG_NAME] = "scc",
|
||||
[SCC_HINT_DESCRIPTION] = "A simple C compiler",
|
||||
[SCC_HINT_OUTPUT_FILE] =
|
||||
"Output file (`-` means standard output stream file)",
|
||||
[SCC_HINT_INPUT_FILE] = "Input source file",
|
||||
[SCC_HINT_INCLUDE_PATH] = "Add directory to the include search paths",
|
||||
[SCC_HINT_DEFINED_MACRO] = "Define a macro",
|
||||
[SCC_HINT_VERBOSE] = "Increase verbosity (can be used multiple times)",
|
||||
[SCC_HINT_EMIT_LEX] = "Generate lexer sources tokens and exit",
|
||||
[SCC_HINT_EMIT_PP] = "Generate preprocessed tokens and exit",
|
||||
[SCC_HINT_EMIT_AST] = "Generate AST and exit",
|
||||
[SCC_HINT_EMIT_IR] = "Generate IR and exit",
|
||||
};
|
||||
static const char *scc_hints_zh[] = {
|
||||
[SCC_HINT_PROG_NAME] = "scc",
|
||||
[SCC_HINT_DESCRIPTION] = "一个简单的C编译器",
|
||||
[SCC_HINT_OUTPUT_FILE] = "输出文件(`-`表示标准输出流文件)",
|
||||
[SCC_HINT_INPUT_FILE] = "输入源文件",
|
||||
[SCC_HINT_INCLUDE_PATH] = "添加系统头文件到搜索路径",
|
||||
[SCC_HINT_DEFINED_MACRO] = "定义宏",
|
||||
[SCC_HINT_VERBOSE] = "增加详细输出(可多次使用)",
|
||||
[SCC_HINT_EMIT_LEX] = "生成`源代码的词法单元`并退出",
|
||||
[SCC_HINT_EMIT_PP] = "生成`预处理后的词法单元`并退出",
|
||||
[SCC_HINT_EMIT_AST] = "生成`抽象语法树`并退出",
|
||||
[SCC_HINT_EMIT_IR] = "生成`中间代码`并退出",
|
||||
};
|
||||
|
||||
const char **scc_hints;
|
||||
switch (lang) {
|
||||
case SCC_ARGPARSE_LANG_EN:
|
||||
scc_hints = scc_hints_en;
|
||||
break;
|
||||
case SCC_ARGPARSE_LANG_ZH:
|
||||
scc_hints = scc_hints_zh;
|
||||
break;
|
||||
default:
|
||||
scc_hints = scc_hints_en;
|
||||
break;
|
||||
}
|
||||
|
||||
scc_argparse_init(argparse, scc_hints[SCC_HINT_PROG_NAME],
|
||||
scc_hints[SCC_HINT_DESCRIPTION]);
|
||||
argparse->lang = lang;
|
||||
scc_argparse_cmd_t *root = scc_argparse_get_root(argparse);
|
||||
|
||||
// -o, --output
|
||||
scc_argparse_opt_t opt_output;
|
||||
scc_argparse_opt_init(&opt_output, 'o', "output",
|
||||
scc_hints[SCC_HINT_OUTPUT_FILE]);
|
||||
scc_argparse_spec_setup_string(&opt_output.spec, &(config->output_file));
|
||||
scc_argparse_cmd_add_opt(root, &opt_output);
|
||||
|
||||
// input file (必需)
|
||||
scc_argparse_arg_t arg_input;
|
||||
scc_argparse_arg_init(&arg_input, "input", scc_hints[SCC_HINT_INPUT_FILE]);
|
||||
scc_argparse_spec_setup_string(&arg_input.spec, &(config->input_file));
|
||||
scc_argparse_spec_set_required(&arg_input.spec, true);
|
||||
scc_argparse_cmd_add_arg(root, &arg_input);
|
||||
|
||||
// -I, --include (添加额外的系统头文件搜索路径)
|
||||
scc_argparse_opt_t opt_include;
|
||||
scc_argparse_opt_init(&opt_include, 'I', "include",
|
||||
scc_hints[SCC_HINT_INCLUDE_PATH]);
|
||||
scc_argparse_spec_setup_list(&opt_include.spec, &(config->include_paths));
|
||||
scc_argparse_cmd_add_opt(root, &opt_include);
|
||||
|
||||
// -D, --define (定义宏)
|
||||
scc_argparse_opt_t opt_define;
|
||||
scc_argparse_opt_init(&opt_define, 'D', "define",
|
||||
scc_hints[SCC_HINT_DEFINED_MACRO]);
|
||||
scc_argparse_spec_setup_list(&opt_define.spec, &(config->define_macros));
|
||||
scc_argparse_cmd_add_opt(root, &opt_define);
|
||||
|
||||
// -v, --verbose (计数)
|
||||
scc_argparse_opt_t opt_verbose;
|
||||
scc_argparse_opt_init(&opt_verbose, 'V', "verbose",
|
||||
scc_hints[SCC_HINT_VERBOSE]);
|
||||
scc_argparse_spec_setup_count(&opt_verbose.spec, &(config->verbose));
|
||||
scc_argparse_cmd_add_opt(root, &opt_verbose);
|
||||
|
||||
// --emit-lex
|
||||
scc_argparse_opt_t opt_lex;
|
||||
scc_argparse_opt_init(&opt_lex, 0, "emit-lex",
|
||||
scc_hints[SCC_HINT_EMIT_LEX]);
|
||||
scc_argparse_spec_setup_bool(&opt_lex.spec, &(config->emit_lex));
|
||||
scc_argparse_cmd_add_opt(root, &opt_lex);
|
||||
|
||||
// --emit-pp
|
||||
scc_argparse_opt_t opt_pp;
|
||||
scc_argparse_opt_init(&opt_pp, 0, "emit-pp", scc_hints[SCC_HINT_EMIT_PP]);
|
||||
scc_argparse_spec_setup_bool(&opt_pp.spec, &(config->emit_pp));
|
||||
scc_argparse_cmd_add_opt(root, &opt_pp);
|
||||
|
||||
// -T, --emit-ast
|
||||
scc_argparse_opt_t opt_ast;
|
||||
scc_argparse_opt_init(&opt_ast, 'T', "emit-ast",
|
||||
scc_hints[SCC_HINT_EMIT_AST]);
|
||||
scc_argparse_spec_setup_bool(&opt_ast.spec, &(config->emit_ast));
|
||||
scc_argparse_cmd_add_opt(root, &opt_ast);
|
||||
|
||||
// -R, --emit-ir
|
||||
scc_argparse_opt_t opt_ir;
|
||||
scc_argparse_opt_init(&opt_ir, 'R', "emit-ir", scc_hints[SCC_HINT_EMIT_IR]);
|
||||
scc_argparse_spec_setup_bool(&opt_ir.spec, &(config->emit_ir));
|
||||
scc_argparse_cmd_add_opt(root, &opt_ir);
|
||||
}
|
||||
|
||||
#endif /* __SCC_CONFIG_H___ */
|
||||
137
src/main.c
137
src/main.c
@@ -7,130 +7,7 @@
|
||||
#include <scc_ast2ir.h>
|
||||
#include <scc_parser.h>
|
||||
|
||||
typedef struct {
|
||||
const char *input_file;
|
||||
const char *output_file;
|
||||
int verbose;
|
||||
scc_argparse_list_t include_paths;
|
||||
cbool emit_lex;
|
||||
cbool emit_pp;
|
||||
cbool emit_ast;
|
||||
cbool emit_ir;
|
||||
} scc_config_t;
|
||||
|
||||
static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
scc_argparse_lang_t lang) {
|
||||
enum {
|
||||
SCC_HINT_PROG_NAME,
|
||||
SCC_HINT_DESCRIPTION,
|
||||
SCC_HINT_OUTPUT_FILE,
|
||||
SCC_HINT_INPUT_FILE,
|
||||
SCC_HINT_INCLUDE_PATH,
|
||||
SCC_HINT_VERBOSE,
|
||||
|
||||
SCC_HINT_EMIT_LEX,
|
||||
SCC_HINT_EMIT_PP,
|
||||
SCC_HINT_EMIT_AST,
|
||||
SCC_HINT_EMIT_IR,
|
||||
};
|
||||
static const char *scc_hints_en[] = {
|
||||
[SCC_HINT_PROG_NAME] = "scc",
|
||||
[SCC_HINT_DESCRIPTION] = "A simple C compiler",
|
||||
[SCC_HINT_OUTPUT_FILE] =
|
||||
"Output file (`-` means standard output stream file)",
|
||||
[SCC_HINT_INPUT_FILE] = "Input source file",
|
||||
[SCC_HINT_INCLUDE_PATH] = "Add directory to the include search paths",
|
||||
[SCC_HINT_VERBOSE] = "Increase verbosity (can be used multiple times)",
|
||||
[SCC_HINT_EMIT_LEX] = "Generate lexer sources tokens and exit",
|
||||
[SCC_HINT_EMIT_PP] = "Generate preprocessed tokens and exit",
|
||||
[SCC_HINT_EMIT_AST] = "Generate AST and exit",
|
||||
[SCC_HINT_EMIT_IR] = "Generate IR and exit",
|
||||
};
|
||||
static const char *scc_hints_zh[] = {
|
||||
[SCC_HINT_PROG_NAME] = "scc",
|
||||
[SCC_HINT_DESCRIPTION] = "一个简单的C编译器",
|
||||
[SCC_HINT_OUTPUT_FILE] = "输出文件(`-`表示标准输出流文件)",
|
||||
[SCC_HINT_INPUT_FILE] = "输入源文件",
|
||||
[SCC_HINT_INCLUDE_PATH] = "添加系统头文件到搜索路径",
|
||||
[SCC_HINT_VERBOSE] = "增加详细输出(可多次使用)",
|
||||
[SCC_HINT_EMIT_LEX] = "生成`源代码的词法单元`并退出",
|
||||
[SCC_HINT_EMIT_PP] = "生成`预处理后的词法单元`并退出",
|
||||
[SCC_HINT_EMIT_AST] = "生成`抽象语法树`并退出",
|
||||
[SCC_HINT_EMIT_IR] = "生成`中间代码`并退出",
|
||||
};
|
||||
|
||||
const char **scc_hints;
|
||||
switch (lang) {
|
||||
case SCC_ARGPARSE_LANG_EN:
|
||||
scc_hints = scc_hints_en;
|
||||
break;
|
||||
case SCC_ARGPARSE_LANG_ZH:
|
||||
scc_hints = scc_hints_zh;
|
||||
break;
|
||||
default:
|
||||
scc_hints = scc_hints_en;
|
||||
break;
|
||||
}
|
||||
|
||||
scc_argparse_init(argparse, scc_hints[SCC_HINT_PROG_NAME],
|
||||
scc_hints[SCC_HINT_DESCRIPTION]);
|
||||
argparse->lang = lang;
|
||||
scc_argparse_cmd_t *root = scc_argparse_get_root(argparse);
|
||||
|
||||
// -o, --output
|
||||
scc_argparse_opt_t opt_output;
|
||||
scc_argparse_opt_init(&opt_output, 'o', "output",
|
||||
scc_hints[SCC_HINT_OUTPUT_FILE]);
|
||||
scc_argparse_spec_setup_string(&opt_output.spec, &(config->output_file));
|
||||
scc_argparse_cmd_add_opt(root, &opt_output);
|
||||
|
||||
// input file (必需)
|
||||
scc_argparse_arg_t arg_input;
|
||||
scc_argparse_arg_init(&arg_input, "input", scc_hints[SCC_HINT_INPUT_FILE]);
|
||||
scc_argparse_spec_setup_string(&arg_input.spec, &(config->input_file));
|
||||
scc_argparse_spec_set_required(&arg_input.spec, true);
|
||||
scc_argparse_cmd_add_arg(root, &arg_input);
|
||||
|
||||
// -I, --include (添加额外的系统头文件搜索路径)
|
||||
scc_argparse_opt_t opt_include;
|
||||
scc_argparse_opt_init(&opt_include, 'I', "include",
|
||||
scc_hints[SCC_HINT_INCLUDE_PATH]);
|
||||
scc_argparse_spec_setup_list(&opt_include.spec, &(config->include_paths));
|
||||
scc_argparse_cmd_add_opt(root, &opt_include);
|
||||
|
||||
// -v, --verbose (计数)
|
||||
scc_argparse_opt_t opt_verbose;
|
||||
scc_argparse_opt_init(&opt_verbose, 'V', "verbose",
|
||||
scc_hints[SCC_HINT_VERBOSE]);
|
||||
scc_argparse_spec_setup_count(&opt_verbose.spec, &(config->verbose));
|
||||
scc_argparse_cmd_add_opt(root, &opt_verbose);
|
||||
|
||||
// --emit-lex
|
||||
scc_argparse_opt_t opt_lex;
|
||||
scc_argparse_opt_init(&opt_lex, 0, "emit-lex",
|
||||
scc_hints[SCC_HINT_EMIT_LEX]);
|
||||
scc_argparse_spec_setup_bool(&opt_lex.spec, &(config->emit_lex));
|
||||
scc_argparse_cmd_add_opt(root, &opt_lex);
|
||||
|
||||
// --emit-pp
|
||||
scc_argparse_opt_t opt_pp;
|
||||
scc_argparse_opt_init(&opt_pp, 0, "emit-pp", scc_hints[SCC_HINT_EMIT_PP]);
|
||||
scc_argparse_spec_setup_bool(&opt_pp.spec, &(config->emit_pp));
|
||||
scc_argparse_cmd_add_opt(root, &opt_pp);
|
||||
|
||||
// -T, --emit-ast
|
||||
scc_argparse_opt_t opt_ast;
|
||||
scc_argparse_opt_init(&opt_ast, 'T', "emit-ast",
|
||||
scc_hints[SCC_HINT_EMIT_AST]);
|
||||
scc_argparse_spec_setup_bool(&opt_ast.spec, &(config->emit_ast));
|
||||
scc_argparse_cmd_add_opt(root, &opt_ast);
|
||||
|
||||
// -R, --emit-ir
|
||||
scc_argparse_opt_t opt_ir;
|
||||
scc_argparse_opt_init(&opt_ir, 'R', "emit-ir", scc_hints[SCC_HINT_EMIT_IR]);
|
||||
scc_argparse_spec_setup_bool(&opt_ir.spec, &(config->emit_ir));
|
||||
scc_argparse_cmd_add_opt(root, &opt_ir);
|
||||
}
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -332,11 +209,10 @@ sstream_drop:
|
||||
return 0;
|
||||
}
|
||||
|
||||
scc_ir_builder_t ir_builder;
|
||||
scc_ir_builder_init(&ir_builder);
|
||||
scc_ast2ir_ctx_t ast2ir_ctx;
|
||||
#include <abi/win_x64_type_abi.h>
|
||||
scc_ast2ir_translation_unit(&ir_builder, translation_unit,
|
||||
scc_win_x64_type_abi);
|
||||
scc_ast2ir_ctx_init(&ast2ir_ctx, scc_win_x64_type_abi);
|
||||
scc_ast2ir_translation_unit(&ast2ir_ctx, translation_unit);
|
||||
|
||||
if (config.emit_ir) {
|
||||
scc_ir_dump_ctx_t ir_dump_ctx;
|
||||
@@ -348,8 +224,9 @@ sstream_drop:
|
||||
scc_tree_dump_ctx_init(&tree_dump, false, (void *)scc_fprintf,
|
||||
(void *)fp);
|
||||
}
|
||||
scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump, &ir_builder.cprog,
|
||||
&ir_builder.ctx);
|
||||
scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump,
|
||||
&ast2ir_ctx.builder.cprog,
|
||||
&ast2ir_ctx.builder.ctx);
|
||||
// scc_ir_dump_cprog(&ir_dump_ctx);
|
||||
scc_ir_dump_cprog_linear(&ir_dump_ctx);
|
||||
scc_tree_dump_ctx_drop(&tree_dump);
|
||||
|
||||
Reference in New Issue
Block a user