feat: 结构体 struct — 最后一项 P0 功能

- lexer: TOK_STRUCT, TOK_DOT 关键字和运算符
- ast: AST_STRUCT_DECL/STRUCT_INIT/FIELD_ACCESS 3 种新节点
- parser: struct 声明 + .field 访问 + Name{field:val} 初始化
- sema: struct 类型符号表,字段类型解析,初始化字段检查
- codegen: LLVMStructType + extractvalue/insertvalue 字段操作
- 新增集成测试: 12_struct.l, 13_struct_nested.l
- 基于 Codex 分析报告 P0 #4

所有 P0 功能已全部完成。
This commit is contained in:
2026-06-05 12:21:22 +08:00
parent 620cec4d57
commit b390d390f3
17 changed files with 1521 additions and 47 deletions
+148 -11
View File
@@ -33,6 +33,9 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena*
node->type.kind = TYPE_ERROR;
} else {
node->type.kind = sym->type;
if (sym->type == TYPE_STRUCT && sym->struct_type_name) {
node->type.struct_name = sym->struct_type_name;
}
}
break;
}
@@ -156,6 +159,99 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena*
break;
}
case AST_FIELD_ACCESS: {
analyze_expr(node->as.field_access.object, scope, errors, a);
AstNode* obj = node->as.field_access.object;
if (obj->type.kind == TYPE_ERROR) {
node->type.kind = TYPE_ERROR;
break;
}
if (obj->type.kind != TYPE_STRUCT) {
error_add(errors, "<sema>", node->line, node->col,
"类型 '%s' 不是结构体,不能访问字段 '%s'",
type_name(obj->type.kind), node->as.field_access.field);
node->type.kind = TYPE_ERROR;
break;
}
// 查找结构体定义
const char* struct_name = obj->type.struct_name;
if (!struct_name) {
error_add(errors, "<sema>", node->line, node->col,
"无法确定结构体类型");
node->type.kind = TYPE_ERROR;
break;
}
Symbol* struct_sym = scope_lookup_struct(scope, struct_name);
if (!struct_sym) {
error_add(errors, "<sema>", node->line, node->col,
"未定义的结构体 '%s'", struct_name);
node->type.kind = TYPE_ERROR;
break;
}
int fi = scope_struct_field_index(struct_sym, node->as.field_access.field);
if (fi < 0) {
error_add(errors, "<sema>", node->line, node->col,
"结构体 '%s' 没有字段 '%s'", struct_name, node->as.field_access.field);
node->type.kind = TYPE_ERROR;
break;
}
node->type.kind = struct_sym->struct_field_types[fi];
node->as.field_access.field_index = fi;
// 如果字段也是结构体类型,传播类型名
if (node->type.kind == TYPE_STRUCT &&
struct_sym->struct_field_struct_names &&
struct_sym->struct_field_struct_names[fi]) {
node->type.struct_name = struct_sym->struct_field_struct_names[fi];
}
break;
}
case AST_STRUCT_INIT: {
Symbol* struct_sym = scope_lookup_struct(scope, node->as.struct_init.type_name);
if (!struct_sym) {
error_add(errors, "<sema>", node->line, node->col,
"未定义的结构体类型 '%s'", node->as.struct_init.type_name);
node->type.kind = TYPE_ERROR;
break;
}
if (node->as.struct_init.field_count != struct_sym->struct_field_count) {
error_add(errors, "<sema>", node->line, node->col,
"结构体 '%s' 有 %zu 个字段,但提供了 %zu 个",
node->as.struct_init.type_name,
struct_sym->struct_field_count,
node->as.struct_init.field_count);
node->type.kind = TYPE_ERROR;
break;
}
// 检查每个字段名和类型匹配
for (size_t i = 0; i < node->as.struct_init.field_count; i++) {
const char* fname = node->as.struct_init.field_names[i];
AstNode* fval = node->as.struct_init.field_values[i];
analyze_expr(fval, scope, errors, a);
int fi = scope_struct_field_index(struct_sym, fname);
if (fi < 0) {
error_add(errors, "<sema>", node->line, node->col,
"结构体 '%s' 没有字段 '%s'",
node->as.struct_init.type_name, fname);
node->type.kind = TYPE_ERROR;
continue;
}
TypeKind expected = struct_sym->struct_field_types[fi];
TypeKind actual = fval->type.kind;
if (actual != TYPE_ERROR && actual != expected) {
error_add(errors, "<sema>", node->line, node->col,
"字段 '%s' 类型不匹配: 期望 '%s',得到 '%s'",
fname, type_name(expected), type_name(actual));
}
}
if (node->type.kind != TYPE_ERROR) {
node->type.kind = TYPE_STRUCT;
node->type.struct_name = node->as.struct_init.type_name;
}
break;
}
default: break;
}
}
@@ -165,7 +261,25 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
switch (node->kind) {
case AST_PROGRAM:
// 第一遍:收集所有函数签名
// 第一遍:收集所有结构体定义
for (size_t i = 0; i < node->as.program.struct_count; i++) {
AstNode* sd = node->as.program.structs[i];
const char** fnames = (const char**)arena_alloc_impl(a,
sd->as.struct_decl.field_count * sizeof(const char*));
TypeKind* ftypes = (TypeKind*)arena_alloc_impl(a,
sd->as.struct_decl.field_count * sizeof(TypeKind));
const char** fstruct_names = (const char**)arena_alloc_impl(a,
sd->as.struct_decl.field_count * sizeof(const char*));
for (size_t j = 0; j < sd->as.struct_decl.field_count; j++) {
fnames[j] = sd->as.struct_decl.fields[j]->as.parameter.name;
ftypes[j] = sd->as.struct_decl.fields[j]->as.parameter.type;
fstruct_names[j] = sd->as.struct_decl.fields[j]->as.parameter.struct_type_name;
}
scope_insert_struct(scope, a, sd->as.struct_decl.name,
fnames, ftypes, fstruct_names,
sd->as.struct_decl.field_count);
}
// 第二遍:收集所有函数签名
for (size_t i = 0; i < node->as.program.fn_count; i++) {
AstNode* fn = node->as.program.functions[i];
TypeKind* pts = (TypeKind*)arena_alloc_impl(a, fn->as.function.param_count * sizeof(TypeKind));
@@ -176,7 +290,7 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
fn->as.function.return_type, pts,
fn->as.function.param_count);
}
// 第遍:分析每个函数体
// 第遍:分析每个函数体
for (size_t i = 0; i < node->as.program.fn_count; i++) {
analyze_node(node->as.program.functions[i], scope, errors, a);
}
@@ -203,14 +317,29 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
analyze_expr(node->as.let_stmt.init, scope, errors, a);
TypeKind inferred = node->as.let_stmt.init->type.kind;
TypeKind var_type;
const char* var_struct_name = NULL;
if (node->as.let_stmt.has_type_annot) {
// 使用显式类型标注
var_type = node->as.let_stmt.annot_type;
const char* annot_struct = node->as.let_stmt.struct_type_name;
if (annot_struct) {
// struct 类型标注
Symbol* st_sym = scope_lookup_struct(scope, annot_struct);
if (!st_sym) {
error_add(errors, "<sema>", node->line, node->col,
"未定义的结构体类型 '%s'", annot_struct);
break;
}
var_type = TYPE_STRUCT;
var_struct_name = annot_struct;
} else {
var_type = node->as.let_stmt.annot_type;
}
if (inferred != TYPE_ERROR && inferred != var_type) {
error_add(errors, "<sema>", node->line, node->col,
"变量 '%s' 类型标注为 '%s',但初始化表达式类型为 '%s'",
node->as.let_stmt.name, type_name(var_type), type_name(inferred));
node->as.let_stmt.name,
annot_struct ? annot_struct : type_name(var_type),
type_name(inferred));
}
} else {
// 类型推断
@@ -220,15 +349,23 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
break;
}
var_type = inferred;
if (inferred == TYPE_STRUCT) {
var_struct_name = node->as.let_stmt.init->type.struct_name;
}
}
node->type.kind = var_type;
node->type.struct_name = var_struct_name;
Symbol* sym = scope_insert(scope, a, node->as.let_stmt.name, SYM_VARIABLE, var_type);
if (!sym) {
error_add(errors, "<sema>", node->line, node->col,
"变量 '%s' 重复定义", node->as.let_stmt.name);
} else {
sym->is_mut = node->as.let_stmt.is_mut;
if (var_struct_name) {
sym->type = TYPE_STRUCT;
sym->struct_type_name = var_struct_name;
}
}
break;
}
@@ -304,17 +441,17 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
}
void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) {
Scope* global = scope_new(arena, NULL);
Scope* global_scope = scope_new(arena, NULL);
// 注册内置函数
TypeKind params_i64[] = {TYPE_I64};
scope_insert_function(global, arena, "print_i64", TYPE_VOID, params_i64, 1);
scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, params_i64, 1);
TypeKind params_f64[] = {TYPE_F64};
scope_insert_function(global, arena, "print_f64", TYPE_VOID, params_f64, 1);
scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, params_f64, 1);
TypeKind params_bool[] = {TYPE_BOOL};
scope_insert_function(global, arena, "print_bool", TYPE_VOID, params_bool, 1);
scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, params_bool, 1);
TypeKind params_str[] = {TYPE_STR};
scope_insert_function(global, arena, "print_str", TYPE_VOID, params_str, 1);
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, params_str, 1);
analyze_node(ast, global, errors, arena);
analyze_node(ast, global_scope, errors, arena);
}
+49
View File
@@ -29,6 +29,10 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
sym->name = name; sym->kind = kind; sym->type = type;
sym->is_mut = false; sym->return_type = TYPE_VOID;
sym->param_types = NULL; sym->param_count = 0;
sym->struct_field_names = NULL;
sym->struct_field_types = NULL;
sym->struct_field_count = 0;
sym->struct_type_name = NULL;
sym->next = scope->head;
scope->head = sym;
return sym;
@@ -44,7 +48,52 @@ Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name,
Symbol* sym = (Symbol*)arena_alloc_impl(alloc, sizeof(Symbol));
sym->name = name; sym->kind = SYM_FUNCTION; sym->type = TYPE_VOID;
sym->return_type = ret; sym->param_types = pt; sym->param_count = pc;
sym->struct_field_names = NULL;
sym->struct_field_types = NULL;
sym->struct_field_count = 0;
sym->struct_type_name = NULL;
sym->next = scope->head;
scope->head = sym;
return sym;
}
Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name,
const char** fnames, TypeKind* ftypes,
const char** fstruct_names, size_t fc) {
if (scope->head) {
for (Symbol* sym = scope->head; sym; sym = sym->next) {
if (strcmp(sym->name, name) == 0) return NULL;
}
}
Symbol* sym = (Symbol*)arena_alloc_impl(alloc, sizeof(Symbol));
sym->name = name; sym->kind = SYM_STRUCT; sym->type = TYPE_STRUCT;
sym->is_mut = false; sym->return_type = TYPE_VOID;
sym->param_types = NULL; sym->param_count = 0;
sym->struct_field_names = fnames;
sym->struct_field_types = ftypes;
sym->struct_field_struct_names = fstruct_names;
sym->struct_field_count = fc;
sym->struct_type_name = NULL;
sym->next = scope->head;
scope->head = sym;
return sym;
}
Symbol* scope_lookup_struct(const Scope* scope, const char* name) {
for (const Scope* s = scope; s; s = s->parent) {
for (Symbol* sym = s->head; sym; sym = sym->next) {
if (sym->kind == SYM_STRUCT && strcmp(sym->name, name) == 0)
return sym;
}
}
return NULL;
}
int scope_struct_field_index(const Symbol* sym, const char* field_name) {
if (sym->kind != SYM_STRUCT) return -1;
for (size_t i = 0; i < sym->struct_field_count; i++) {
if (strcmp(sym->struct_field_names[i], field_name) == 0)
return (int)i;
}
return -1;
}
+19 -1
View File
@@ -4,7 +4,7 @@
#include "l_lang.h"
#include "ast.h"
typedef enum { SYM_VARIABLE, SYM_PARAMETER, SYM_FUNCTION } SymbolKind;
typedef enum { SYM_VARIABLE, SYM_PARAMETER, SYM_FUNCTION, SYM_STRUCT } SymbolKind;
typedef struct Symbol {
const char* name;
@@ -15,6 +15,13 @@ typedef struct Symbol {
TypeKind return_type;
TypeKind* param_types;
size_t param_count;
// 结构体特有(SYM_STRUCT
const char** struct_field_names;
TypeKind* struct_field_types;
const char** struct_field_struct_names; // 字段为 struct 类型时的具体类型名
size_t struct_field_count;
// 变量引用结构体类型时,记录具体类型名
const char* struct_type_name;
// 链表(同一作用域内的下一个符号)
struct Symbol* next;
} Symbol;
@@ -38,4 +45,15 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name,
TypeKind ret, TypeKind* pt, size_t pc);
// 插入结构体符号
Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name,
const char** fnames, TypeKind* ftypes,
const char** fstruct_names, size_t fc);
// 查找结构体符号(在所有作用域中)
Symbol* scope_lookup_struct(const Scope* scope, const char* name);
// 在结构体符号中查找字段索引(返回 -1 表示未找到)
int scope_struct_field_index(const Symbol* sym, const char* field_name);
#endif