stage1 完成ast 定义sema

This commit is contained in:
zzy
2026-08-03 12:39:28 +08:00
parent a4ec5656d2
commit 74d7376039
19 changed files with 3857 additions and 137 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,9 @@
#include "../stage0/include/utils.h"
#include "spl_lexer.h"
#include "spl_tok.h"
#include <math.h>
typedef enum {
SPL_AST_CONTAINER_MEMBER,
SPL_AST_CONTAINER_ITEM,
SPL_AST_FN_DECL,
SPL_AST_FN_DEFINE,
SPL_AST_TYPE_DECL,
@@ -37,7 +36,11 @@ struct spl_ast_node {
spl_ast_node_kind_t kind;
spl_ast_loc_t loc;
union {
spl_ast_node_ref_vec_t container_member;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
spl_ast_node_ref_t self; /* self */
spl_ast_node_ref_vec_t members; /* container_decl 列表 */
} container_item;
struct {
const char *ident;
@@ -58,18 +61,8 @@ struct spl_ast_node {
} param_decl;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
const char *name;
enum {
SPL_AST_TYPE_STRUCT,
SPL_AST_TYPE_UNION,
SPL_AST_TYPE_ENUM,
SPL_AST_TYPE_TYPE_EXPR,
} kind;
union {
spl_ast_node_ref_t type_expr;
spl_ast_node_ref_t aggregate_list;
};
spl_ast_node_ref_t type_expr;
} type_decl;
struct {
spl_ast_node_ref_vec_t attr_list; /* attr_item */
@@ -103,6 +96,7 @@ struct spl_ast_node {
SPL_AST_CONTINUE_STATEMENT,
SPL_AST_DEFER_STATEMENT,
SPL_AST_VARDECL,
SPL_AST_CONSTDECL,
SPL_AST_TYPEDECL,
SPL_AST_EXPR_STATEMENT,
} kind;
@@ -131,8 +125,8 @@ struct spl_ast_node {
} for_statement;
struct {
spl_ast_node_ref_t expr;
spl_ast_node_ref_vec_t paced_exprs;
spl_ast_node_ref_vec_t statements;
spl_ast_node_ref_vec_t paced_exprs; /* packed_expr */
spl_ast_node_ref_vec_t match_block; /* block_item */
} match_statement;
struct {
spl_ast_node_ref_t expr;
@@ -145,6 +139,7 @@ struct spl_ast_node {
spl_ast_node_ref_vec_t block_or_statement; /* block_item/statement */
} defer_statement;
spl_ast_node_ref_t var_decl;
spl_ast_node_ref_t const_decl;
spl_ast_node_ref_t type_decl;
spl_ast_node_ref_t expr_statement;
};
@@ -280,10 +275,13 @@ struct spl_ast_node {
struct {
spl_ast_node_ref_vec_t type_prefixs; /* prefix_type */
spl_ast_node_ref_vec_t attr_list; /* attr_item */
enum {
SPL_AST_BASE_TYPE_FN,
SPL_AST_BASE_TYPE_PATH,
SPL_AST_TYPE_STRUCT,
SPL_AST_TYPE_UNION,
SPL_AST_TYPE_ENUM,
} kind;
const char *spl_base_type;
@@ -293,6 +291,7 @@ struct spl_ast_node {
spl_ast_node_ref_vec_t param_list; /* param_decl */
spl_ast_node_ref_t type_expr;
} fn_type;
spl_ast_node_ref_vec_t aggregate_list; /* container_decl */
};
} type_expr;
struct {

1
stage1/spl_ast2ir.c Normal file
View File

@@ -0,0 +1 @@
#include "spl_ast2ir.h"

4
stage1/spl_ast2ir.h Normal file
View File

@@ -0,0 +1,4 @@
#ifndef __SPL_AST2IR_H__
#define __SPL_AST2IR_H__
#endif /* __SPL_AST2IR_H__ */

26
stage1/spl_dumptree.c Normal file
View File

@@ -0,0 +1,26 @@
/* spl_dumptree.c 可配置的树形打印模块(只用基本 ASCII*/
#include "spl_dumptree.h"
#include <stdarg.h>
const spl_dumptree_style_t spl_dumptree_ascii_style = {
"| ",
"|-",
"`-",
" ",
};
void spl_dumptree_print(const spl_dumptree_style_t *st, const char *prefix, int is_last,
const char *fmt, ...) {
va_list ap;
printf("%s%s ", prefix, is_last ? st->last_branch : st->branch);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
}
void spl_dumptree_child_prefix(const spl_dumptree_style_t *st, const char *prefix, int is_last,
char *out, size_t cap) {
snprintf(out, cap, "%s%s", prefix, is_last ? st->space : st->vertical);
}

31
stage1/spl_dumptree.h Normal file
View File

@@ -0,0 +1,31 @@
/* spl_dumptree.h 可配置的树形打印模块(只用基本 ASCII*/
#ifndef __SPL_DUMPTREE_H__
#define __SPL_DUMPTREE_H__
#include <stddef.h>
#include <stdio.h>
/* 可配置的缩进字符串 */
typedef struct {
const char *vertical; /* "| " */
const char *branch; /* "|-" */
const char *last_branch; /* "`-" */
const char *space; /* " " */
} spl_dumptree_style_t;
/* 默认 ASCII 风格 */
extern const spl_dumptree_style_t spl_dumptree_ascii_style;
/* 打印一行节点标签prefix + 分支符 + label
* prefix 已累积的缩进骨架(不含分支符)
* is_last 本节点是否为同级最后一个子节点
* fmt printf 风格 label */
void spl_dumptree_print(const spl_dumptree_style_t *st, const char *prefix, int is_last,
const char *fmt, ...);
/* 生成子节点的缩进骨架parent_prefix + (parent_is_last ? space : vertical) */
void spl_dumptree_child_prefix(const spl_dumptree_style_t *st, const char *prefix, int is_last,
char *out, size_t cap);
#endif /* __SPL_DUMPTREE_H__ */

View File

@@ -69,20 +69,40 @@
X(control.trap, V0, SPL_IR_CONTROL_TRAP) \
X(dbg.breakpoint, V0, SPL_IR_DBG_BREAKPOINT) \
X(dbg.declare, V0, SPL_IR_DBG_DECLARE)
typedef enum {
#ifdef X
#undef X
#endif
#define X(a, b, c) c,
SPL_IR_FN_TABLE
#undef X
} spl_ir_kind_t;
/* clang-format on */
typedef struct {
enum {
} kind;
spl_ir_kind_t kind;
} spl_ir_node_t;
typedef VEC(spl_ir_node_t) spl_ir_node_vec_t;
typedef usize spl_ir_node_ref_t;
typedef VEC(spl_ir_node_ref_t) spl_ir_node_ref_vec_t;
typedef struct {
enum {
SPL_IR_ATTR_NONE,
SPL_IR_ATTR_LINK, /* 不实现 */
SPL_IR_ATTR_ABI, /* 只有 C ABI 支持 */
SPL_IR_ATTR_SYMBOL, /* 不实现 */
SPL_IR_ATTR_NAKED, /* 不实现 */
SPL_IR_ATTR_NOINLINE, /* 不实现 */
SPL_IR_ATTR_ALWAYSINLINE, /* 不实现 */
};
} spl_ir_attr_t;
typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t;
typedef struct {
const char *name;
spl_ir_attr_t attr;
spl_ir_node_vec_t nodes;
spl_ir_node_ref_vec_t labels;
} spl_ir_func_t;

1
stage1/spl_sema.c Normal file
View File

@@ -0,0 +1 @@
#include "spl_sema.h"

33
stage1/spl_sema.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef __SPL_SEMA_H__
#define __SPL_SEMA_H__
#include "spl_ast.h"
#include "spl_type.h"
typedef usize spl_scope_id_t; /* 0 is error */
typedef struct {
spl_scope_id_t parent;
MAP(const char *, spl_type_id_t) symbols;
} spl_scope_node_t;
typedef VEC(spl_scope_node_t) spl_scope_node_vec_t;
typedef struct {
spl_ast_t *ast;
spl_type_t type;
spl_scope_node_vec_t scopes;
spl_scope_id_t root_scope;
spl_scope_id_t current_scope;
int error_count;
} spl_sema_t;
void spl_sema_init(spl_sema_t *sema);
void spl_sema_drop(spl_sema_t *sema);
void spl_sema_run(spl_sema_t *sema);
spl_scope_id_t spl_sema_scope_alloc(spl_sema_t *sema);
bool spl_sema_scope_insert(spl_sema_t *sema, spl_scope_id_t id, const char *symbol_name,
spl_type_id_t symbol_val);
typedef VEC(const char *) spl_symbol_path_t;
spl_type_id_t spl_sema_scope_find(spl_sema_t *sema, spl_symbol_path_t path);
#endif /* __SPL_SEMA_H__ */

1
stage1/spl_type.c Normal file
View File

@@ -0,0 +1 @@
#include "spl_type.h"

116
stage1/spl_type.h Normal file
View File

@@ -0,0 +1,116 @@
#ifndef __SPL_TYPE_H__
#define __SPL_TYPE_H__
#include "../stage0/include/utils.h"
typedef usize spl_type_id_t; /* 0 is error */
typedef VEC(spl_type_id_t) spl_type_id_vec_t;
typedef struct {
enum {
SPL_TYPE_VOID,
SPL_TYPE_BOOL,
SPL_TYPE_INT,
SPL_TYPE_FLOAT,
SPL_TYPE_PTR,
SPL_TYPE_SLICE,
SPL_TYPE_ARRAY,
SPL_TYPE_STRUCT,
SPL_TYPE_UNION,
SPL_TYPE_ENUM,
SPL_TYPE_FN,
SPL_TYPE_ID,
} kind;
union {
struct {
usize bits;
int is_signed;
} int_type;
struct {
usize bits;
} float_type;
spl_type_id_t ptr_pointee;
spl_type_id_t slice_element;
struct {
spl_type_id_t element;
usize len;
} array_type;
spl_type_id_vec_t agg_field_types;
struct {
spl_type_id_vec_t variants;
spl_type_id_t tag_type;
} enum_type; // ADT
struct {
spl_type_id_vec_t params;
spl_type_id_t ret;
} fn_type;
spl_type_id_t type_id;
};
usize byte_size; /* 布局缓存 */
} spl_type_node_t;
typedef VEC(spl_type_node_t) spl_type_node_vec_t;
typedef struct {
const char *name;
spl_type_id_t type;
usize scope_id;
} spl_var_def_t;
typedef VEC(spl_var_def_t) spl_var_def_vec_t;
typedef struct {
enum {
SPL_DEF_NONE,
SPL_DEF_BUILTIN,
SPL_DEF_VAR,
SPL_DEF_FN_PARAMS,
SPL_DEF_AGG, // include enum variants
SPL_DEF_DISTINCT, // newtype
SPL_DEF_ALIAS, // sametypes
} kind;
union {
spl_var_def_t var_def;
spl_var_def_vec_t agg_def; // include enum variants
spl_var_def_vec_t fn_params_def;
spl_var_def_t type_def;
};
int source_loc;
enum {
SPL_FLAG_NONE,
} flag;
} spl_def_node_t;
typedef VEC(spl_def_node_t) spl_def_node_vec_t;
/*
SPL 设计是严格区分类型做到类型和名称无关即
type (类型名) = (匿名类型)
好处是递归使用可以直接操作类型名的映射的提前分配的匿名类型的id
*/
typedef struct {
spl_type_node_vec_t type_table;
spl_def_node_vec_t def_table; /* 使用type_id作为索引 */
} spl_type_t;
void spl_type_init(spl_type_t *type);
void spl_type_drop(spl_type_t *type);
void spl_type_def_dump(spl_type_t *type, spl_type_id_t id);
void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id);
// alloc 时两表平行 push, 保证索引同步
spl_type_id_t spl_type_alloc(spl_type_t *type);
spl_type_node_t *spl_type_node(spl_type_t *type, spl_type_id_t id);
spl_def_node_t *spl_type_def(spl_type_t *type, spl_type_id_t id);
spl_type_id_t spl_type_void(spl_type_t *type);
spl_type_id_t spl_type_bool(spl_type_t *type);
spl_type_id_t spl_type_int(spl_type_t *type, usize bits, int is_signed);
spl_type_id_t spl_type_float(spl_type_t *type, usize bits);
spl_type_id_t spl_type_ptr(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_slice(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_array(spl_type_t *type, spl_type_id_t val, usize len);
spl_type_id_t spl_type_tid(spl_type_t *type, spl_type_id_t val);
spl_type_id_t spl_type_agg(spl_type_t *type, spl_type_id_vec_t fields);
spl_type_id_t spl_type_enum(spl_type_t *type, spl_type_id_vec_t variants, spl_type_id_t tag);
spl_type_id_t spl_type_fn(spl_type_t *type, spl_type_id_vec_t params, spl_type_id_t ret);
#endif /* __SPL_TYPE_H__ */

View File

@@ -1,8 +1,19 @@
/* splc0.c — SPL compiler CLI */
/* splc0.c — SPL compiler CLI (stage 1, 引导用)
*
* splc0 --dump tokens|ast|all <file> dump 前端产物
* splc0 <in> <out> 编译 (阶段 B 实现)
*/
#define __SCC_LOG_IMPL_IMPORT_SRC__
#include "../stage0/include/utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "spl_ast.h"
#include "spl_lexer.h"
#include "spl_tok.h"
static char *read_file(const char *path, long *out_len) {
FILE *f = fopen(path, "rb");
if (!f) {
@@ -24,19 +35,68 @@ static char *read_file(const char *path, long *out_len) {
return buf;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: splc0 [--dump <flags>] <in> [out]\n");
static const char *const tok_type_names[] = {
#define X(name, enum_name, dummy) #enum_name,
KEYWORD_TABLE
#undef X
#define X(name, enum_name, dummy) #enum_name,
TOKEN_TABLE
#undef X
};
static void dump_tokens(const char *src, const char *fname) {
spl_tok_vec_t toks = spl_lex(src, fname);
printf("tokens got (%zu)\n", toks.size);
for (usize i = 0; i < toks.size; i++) {
const spl_tok_t *t = &toks.data[i];
printf("[%s] %.*s (%zu:%zu)\n", tok_type_names[t->type], (int)t->len, t->lexeme, t->line,
t->col);
}
vec_free(toks);
}
static void dump_ast(const char *src, const char *fname) {
spl_tok_vec_t toks = spl_lex(src, fname);
spl_ast_t ast;
spl_ast_init(&ast, &toks);
spl_ast_prase(&ast);
spl_ast_valid(&ast);
spl_ast_dump(&ast, ast.root);
spl_ast_drop(&ast);
}
static int cmd_dump(const char *flags, const char *path) {
long len;
char *src = read_file(path, &len);
if (!src)
return 1;
}
if (strcmp(argv[1], "--dump") == 0)
// return cmd_dump(argc - 2, argv + 2);
return 0;
if (strcmp(argv[1], "--help") == 0) {
printf("splc0 <in> <out> compile\n");
printf("splc0 --dump <f> <file> dump: tokens,cst,ast,ir,mcode,all\n");
return 0;
}
// return cmd_compile(argc - 1, argv + 1);
int do_tokens = strstr(flags, "tokens") != NULL || strcmp(flags, "all") == 0;
int do_ast = strstr(flags, "ast") != NULL || strcmp(flags, "all") == 0;
if (do_tokens)
dump_tokens(src, path);
if (do_ast)
dump_ast(src, path);
free(src);
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]\n");
return 1;
}
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, 阶段 B)\n");
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,all\n");
return 0;
}
if (strcmp(argv[1], "--dump") == 0) {
if (argc < 4) {
LOG_INFO("splc0: --dump need <flags> <file>\n");
return 1;
}
return cmd_dump(argv[2], argv[3]);
}
LOG_FATAL("splc0: compile todo\n");
return 1;
}

View File

@@ -1,4 +1,4 @@
/* spc_vm.c 鈥?VM launcher for stage 1 */
/* spc_vm.c launcher for stage 1 */
#include "../stage0/spl_mcode.h"
#include "../stage0/spl_syscall.h"
@@ -57,13 +57,12 @@ int main(int argc, const char **argv) {
return 1;
}
spl_vm_set_trace(&vm, trace);
if (debug_addr) spl_vm_set_debug(&vm, 1);
if (debug_addr)
spl_vm_set_debug(&vm, 1);
int ret = spl_vm_run_until(&vm, 0);
spl_vm_drop(&vm);
spl_prog_drop(&prog);
if (ret < 0)
return (int)vm.exit_code;
return (int)vm.exit_code;
}

View File

@@ -24,8 +24,8 @@ type Expr = enum {
fn eval(self: *Expr) i32 {
match self {
.Int[val] => ret val,
.Add[.left = left, .right = right] => ret eval(left) + eval(right),
.Int[val] => { ret val; },
.Add[sub] => { ret eval(sub.left) + eval(sub.right); }
}
ret 0;
}
@@ -39,7 +39,7 @@ fn main() i32 {
/* enum 方法 + match */
var expr_l := Expr { .Int = 3 };
var expr_r := Expr { .Int = 4 };
var expr := Expr { .Add = { .left = expr_l, .right = expr_r } };
var expr := Expr { .Add = .{ .left = expr_l, .right = expr_r } };
var result := expr.eval(&expr);
vm_printf("eval result: %d\n", result);
if result != 7 { ret 1; }

View File

@@ -118,7 +118,7 @@ fn test_shape_match() i32 {
.Circle[r] => {
if r != 10 { ret 1; }
},
.Rect[.x = w, .y = h] => {
.Rect[p] => {
ret 2;
}
}
@@ -127,9 +127,9 @@ fn test_shape_match() i32 {
s = Shape { .Rect = Point { .x = 3, .y = 4 } };
match s {
.Circle[r] => { ret 3; },
.Rect[.x = w, .y = h] => {
if w != 3 { ret 4; }
if h != 4 { ret 5; }
.Rect[p] => {
if p.x != 3 { ret 4; }
if p.y != 4 { ret 5; }
}
}

View File

@@ -8,7 +8,7 @@ fn test_string() i32 {
* String test: str is []u8
* ============================ */
var data: *u8 = "hello";
var s: []u8 = { .ptr = data, .len = 5 };
var s: []u8 = .{ .ptr = data, .len = 5 };
if s.len != 5 { ret 100; }
if s[0] != 104 { ret 101; } /* 'h' */
@@ -147,7 +147,7 @@ fn main() i32 {
var data: [5]i32;
data[0] = 10; data[1] = 20; data[2] = 30; data[3] = 40; data[4] = 50;
var p: *i32 = &data[2];
var from_ptr: []i32 = { .ptr = p, .len = 2 };
var from_ptr: []i32 = .{ .ptr = p, .len = 2 };
var from_ptr2: []i32;
from_ptr2.ptr = p;
from_ptr2.len = 2;

View File

@@ -78,7 +78,7 @@ fn test_slice_in_struct() i32 {
raw[0] = 65; raw[1] = 66; raw[2] = 67; raw[3] = 68;
/* Bug fix: { .ptr = ..., .len = ... } inside struct literal */
var b: Buffer = Buffer { .data = { .ptr = &raw[0], .len = 4 }, .len = 4 };
var b: Buffer = Buffer { .data = .{ .ptr = &raw[0], .len = 4 }, .len = 4 };
if b.len != 4 { ret 1; }
if b.data[0] != 65 { ret 2; }
@@ -90,7 +90,7 @@ fn test_slice_in_struct() i32 {
if raw[0] != 90 { ret 5; }
/* Initialize with shorter slice */
var b2: Buffer = Buffer { .data = { .ptr = &raw[2], .len = 2 }, .len = 2 };
var b2: Buffer = Buffer { .data = .{ .ptr = &raw[2], .len = 2 }, .len = 2 };
if b2.len != 2 { ret 6; }
if b2.data[0] != 67 { ret 7; }
@@ -211,7 +211,7 @@ fn test_complex_nesting() i32 {
var bundle: Bundle = Bundle {
.name = &str_data[0],
.buf = Buffer { .data = { .ptr = &str_data[1], .len = 3 }, .len = 3 },
.buf = Buffer { .data = .{ .ptr = &str_data[1], .len = 3 }, .len = 3 },
.row = MatrixRow { .items = [4]i32{1, 2, 3, 4} },
.pt = Point { .x = -5, .y = 15 }
};
@@ -259,7 +259,7 @@ fn test_enum_complex() i32 {
.Inactive => {
ret 2;
},
.Pending[.x = px, .y = py] => {
.Pending[p] => {
ret 3;
}
}
@@ -270,7 +270,7 @@ fn test_enum_complex() i32 {
match s2 {
.Active[val] => {},
.Inactive => { is_inactive = 1; },
.Pending[.x = px, .y = py] => {}
.Pending[p] => {}
}
if is_inactive != 1 { ret 4; }
@@ -279,9 +279,9 @@ fn test_enum_complex() i32 {
match s3 {
.Active[val] => { ret 5; },
.Inactive => { ret 6; },
.Pending[.x = px, .y = py] => {
if px != 7 { ret 7; }
if py != 8 { ret 8; }
.Pending[p] => {
if p.x != 7 { ret 7; }
if p.y != 8 { ret 8; }
}
}