implemented arrays, pointers and struct init

This commit is contained in:
Lorenzo Torres 2025-12-03 20:39:23 +01:00
parent b504739d59
commit 6d73af4fbb
5 changed files with 194 additions and 75 deletions

14
lc.c
View file

@ -69,7 +69,8 @@ void print_ast(ast_node *node, int depth) {
printf("Identifier: %.*s\n", (int)node->expr.string.len, node->expr.string.start); printf("Identifier: %.*s\n", (int)node->expr.string.len, node->expr.string.start);
break; break;
case NODE_CAST: case NODE_CAST:
printf("Cast: %.*s\n", (int)node->expr.cast.type_len, node->expr.cast.type); printf("Cast:\n");
print_ast(node->expr.cast.type, depth);
print_ast(node->expr.cast.value, depth + 1); print_ast(node->expr.cast.value, depth + 1);
break; break;
case NODE_ACCESS: case NODE_ACCESS:
@ -134,6 +135,14 @@ void print_ast(ast_node *node, int depth) {
current = current->expr.unit_node.next; current = current->expr.unit_node.next;
} }
break; break;
case NODE_STRUCT_INIT:
printf("Struct init:\n");
current = node->expr.struct_init.members;
while (current && current->type == NODE_UNIT) {
print_ast(current->expr.unit_node.expr, depth + 1);
current = current->expr.unit_node.next;
}
break;
case NODE_STRUCT: case NODE_STRUCT:
printf("Struct: %.*s\n", (int)node->expr.structure.name_len, node->expr.structure.name); printf("Struct: %.*s\n", (int)node->expr.structure.name_len, node->expr.structure.name);
member *m = node->expr.structure.members; member *m = node->expr.structure.members;
@ -164,7 +173,8 @@ void print_ast(ast_node *node, int depth) {
print_ast(node->expr.whle.body, depth + 1); print_ast(node->expr.whle.body, depth + 1);
break; break;
case NODE_VAR_DECL: case NODE_VAR_DECL:
printf("VarDecl: %.*s: %.*s\n", (int)node->expr.var_decl.name_len, node->expr.var_decl.name, (int)node->expr.var_decl.type_len, node->expr.var_decl.type); printf("VarDecl: ");
print_ast(node->expr.var_decl.type, 0);
print_ast(node->expr.var_decl.value, depth + 1); print_ast(node->expr.var_decl.value, depth + 1);
break; break;
case NODE_FUNCTION: case NODE_FUNCTION:

View file

@ -16,11 +16,11 @@ typedef enum {
TOKEN_AND, // & TOKEN_AND, // &
TOKEN_HAT, // ^ TOKEN_HAT, // ^
TOKEN_PIPE, // | TOKEN_PIPE, // |
TOKEN_EQ, // =
TOKEN_ARROW, // -> TOKEN_ARROW, // ->
TOKEN_LSHIFT, // << TOKEN_LSHIFT, // <<
TOKEN_RSHIFT, // >> TOKEN_RSHIFT, // >>
TOKEN_DOUBLE_EQ, // == TOKEN_DOUBLE_EQ, // ==
TOKEN_EQ, // =
TOKEN_LESS_THAN, // < TOKEN_LESS_THAN, // <
TOKEN_GREATER_THAN, // > TOKEN_GREATER_THAN, // >
TOKEN_LESS_EQ, // <= TOKEN_LESS_EQ, // <=

217
parser.c
View file

@ -8,6 +8,7 @@ bool has_errors = false;
ast_node *parse_expression(parser *p); ast_node *parse_expression(parser *p);
static ast_node *parse_statement(parser *p); static ast_node *parse_statement(parser *p);
static ast_node *parse_type(parser *p);
/* Consume a token in the list. */ /* Consume a token in the list. */
static void advance(parser *p) static void advance(parser *p)
@ -329,8 +330,7 @@ ast_node *parse_unary(parser *p)
advance(p); advance(p);
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_CAST; node->type = NODE_CAST;
node->expr.cast.type = peek(p)->lexeme; node->expr.cast.type = parse_type(p);
node->expr.cast.type_len = peek(p)->lexeme_len;
advance(p); advance(p);
advance(p); advance(p);
node->expr.cast.value = parse_expression(p); node->expr.cast.value = parse_expression(p);
@ -448,11 +448,86 @@ ast_node *parse_expression(parser *p)
return node; return node;
} }
if (match(p, TOKEN_LCURLY)) {
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_STRUCT_INIT;
if (match(p, TOKEN_RCURLY))
{
node->expr.struct_init.members = NULL;
return node;
}
snapshot arena_start = arena_snapshot(p->allocator);
node->expr.struct_init.members = arena_alloc(p->allocator, sizeof(ast_node));
node->expr.struct_init.members->type = NODE_UNIT;
node->expr.struct_init.members->expr.unit_node.expr = parse_expression(p);
ast_node *tail = node->expr.struct_init.members;
node->expr.struct_init.members_len = 1;
/* In this case, there is only one parameter */
if (match(p, TOKEN_RCURLY))
{
return node;
}
if (match(p, TOKEN_COMMA))
{
ast_node *expr = parse_expression(p);
if (expr)
{
while (!match(p, TOKEN_RCURLY))
{
if (!match(p, TOKEN_COMMA))
{
error(p, "expected `}`.");
arena_reset_to_snapshot(p->allocator, arena_start);
return NULL;
}
tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node));
tail->expr.unit_node.next->expr.unit_node.expr = expr;
tail = tail->expr.unit_node.next;
tail->type = NODE_UNIT;
expr = parse_expression(p);
if (!expr)
{
error(p, "expected `}`.");
arena_reset_to_snapshot(p->allocator, arena_start);
return NULL;
}
node->expr.struct_init.members_len += 1;
}
tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node));
tail->expr.unit_node.next->expr.unit_node.expr = expr;
tail = tail->expr.unit_node.next;
tail->type = NODE_UNIT;
}
else
{
error(p, "expected member initialization.");
arena_reset_to_snapshot(p->allocator, arena_start);
return NULL;
}
}
else
{
error(p, "expected `}`.");
arena_reset_to_snapshot(p->allocator, arena_start);
return NULL;
}
return node;
}
if (p->tokens && ((p->tokens->type >= TOKEN_DOUBLE_EQ && p->tokens->type <= TOKEN_NOT_EQ) || (p->tokens->type >= TOKEN_LSHIFT_EQ && p->tokens->type <= TOKEN_DOUBLE_AND))) if (p->tokens && ((p->tokens->type >= TOKEN_DOUBLE_EQ && p->tokens->type <= TOKEN_NOT_EQ) || (p->tokens->type >= TOKEN_LSHIFT_EQ && p->tokens->type <= TOKEN_DOUBLE_AND)))
{ {
binary_op op; binary_op op;
switch (p->tokens->type) switch (p->tokens->type)
{ {
case TOKEN_EQ:
op = OP_ASSIGN;
break;
case TOKEN_DOUBLE_EQ: case TOKEN_DOUBLE_EQ:
op = OP_EQ; op = OP_EQ;
break; break;
@ -492,6 +567,10 @@ ast_node *parse_expression(parser *p)
node->expr.binary.left = left; node->expr.binary.left = left;
node->expr.binary.operator = op; node->expr.binary.operator = op;
node->expr.binary.right = parse_expression(p); node->expr.binary.right = parse_expression(p);
if (!node->expr.binary.right) {
error(p, "expected expression.");
return NULL;
}
return node; return node;
} }
@ -688,7 +767,7 @@ static ast_node *parse_if(parser *p)
} }
static ast_node *parse_struct(parser *p); static ast_node *parse_struct(parser *p);
static member *parse_member(parser *p) static ast_node *parse_type(parser *p)
{ {
ast_node *type = NULL; ast_node *type = NULL;
@ -699,18 +778,52 @@ static member *parse_member(parser *p)
type = parse_struct(p); type = parse_struct(p);
type->type = NODE_UNION; type->type = NODE_UNION;
} }
if (!type) { if (match(p, TOKEN_LSQUARE)) {
type = parse_factor(p); /* Array/slice type */
if (!type) { type = arena_alloc(p->allocator, sizeof(ast_node));
error(p, "expected struct definition or identifier."); type->type = NODE_PTR_TYPE;
if (match(p, TOKEN_STAR)) {
type->expr.ptr_type.flags |= PTR_ARRAY;
} else {
type->expr.ptr_type.flags |= PTR_SLICE;
}
type->expr.ptr_type.type = parse_type(p);
if (!type->expr.ptr_type.type) {
error(p, "expected type.");
return NULL; return NULL;
} }
if (type->type != NODE_IDENTIFIER) { if (!match(p, TOKEN_RSQUARE)) {
error(p, "expected struct definition or identifier."); error(p, "expected `]`.");
return NULL;
}
}
if (match(p, TOKEN_STAR)) {
type = arena_alloc(p->allocator, sizeof(ast_node));
type->type = NODE_PTR_TYPE;
type->expr.ptr_type.flags |= PTR_RAW;
type->expr.ptr_type.type = parse_type(p);
if (!type->expr.ptr_type.type) {
error(p, "expected type.");
return NULL; return NULL;
} }
} }
if (!type) {
type = parse_factor(p);
if (!type) {
return NULL;
}
if (type->type != NODE_IDENTIFIER) {
return NULL;
}
}
return type;
}
static member *parse_member(parser *p)
{
ast_node *type = parse_type(p);
if (!match_peek(p, TOKEN_IDENTIFIER)) { if (!match_peek(p, TOKEN_IDENTIFIER)) {
error(p, "expected identifier."); error(p, "expected identifier.");
@ -873,9 +986,7 @@ static ast_node *parse_function(parser *p)
{ {
ast_node *fn = arena_alloc(p->allocator, sizeof(ast_node)); ast_node *fn = arena_alloc(p->allocator, sizeof(ast_node));
fn->type = NODE_FUNCTION; fn->type = NODE_FUNCTION;
fn->expr.function.type = peek(p)->lexeme; fn->expr.function.type = parse_type(p);
fn->expr.function.type_len = peek(p)->lexeme_len;
advance(p);
fn->expr.function.name = peek(p)->lexeme; fn->expr.function.name = peek(p)->lexeme;
fn->expr.function.name_len = peek(p)->lexeme_len; fn->expr.function.name_len = peek(p)->lexeme_len;
advance(p); advance(p);
@ -883,7 +994,7 @@ static ast_node *parse_function(parser *p)
advance(p); advance(p);
if (match(p, TOKEN_RPAREN)) { if (match(p, TOKEN_RPAREN)) {
fn->expr.function.body = parse_compound(p); fn->expr.function.body = parse_compound(p);;
fn->expr.function.parameters = NULL; fn->expr.function.parameters = NULL;
fn->expr.function.parameters_len = 0; fn->expr.function.parameters_len = 0;
return fn; return fn;
@ -925,6 +1036,39 @@ static ast_node *parse_function(parser *p)
static ast_node *parse_statement(parser *p) static ast_node *parse_statement(parser *p)
{ {
token *current = p->tokens;
ast_node *type = parse_type(p);
if (type && match_peek(p, TOKEN_IDENTIFIER)) {
if (p->tokens->next && p->tokens->next->type == TOKEN_LPAREN) {
/* Function definition. */
p->tokens = current;
return parse_function(p);
}
p->tokens = current;
/* Variable declaration. */
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_VAR_DECL;
node->expr.var_decl.type = parse_type(p);
node->expr.var_decl.name = p->tokens->lexeme;
node->expr.var_decl.name_len = p->tokens->lexeme_len;
advance(p);
if (match(p, TOKEN_EQ)) {
node->expr.var_decl.value = parse_expression(p);
} else {
node->expr.var_decl.value = NULL;
}
if (!match(p, TOKEN_SEMICOLON))
{
error(p, "expected `;` after statement.");
return NULL;
}
return node;
} else {
p->tokens = current;
}
if (match(p, TOKEN_BREAK)) if (match(p, TOKEN_BREAK))
{ {
if (!match(p, TOKEN_SEMICOLON)) if (!match(p, TOKEN_SEMICOLON))
@ -1027,53 +1171,6 @@ static ast_node *parse_statement(parser *p)
else if (match(p, TOKEN_IF)) { else if (match(p, TOKEN_IF)) {
return parse_if(p); return parse_if(p);
} }
else if (match_peek(p, TOKEN_IDENTIFIER) && p->tokens->next && p->tokens->next->type == TOKEN_EQ)
{
/* Variable assignment. */
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_BINARY;
node->expr.binary.left = parse_factor(p);
advance(p);
node->expr.binary.right = parse_expression(p);
node->expr.binary.operator = OP_ASSIGN;
if (!match(p, TOKEN_SEMICOLON))
{
error(p, "expected `;` after statement.");
return NULL;
}
return node;
}
else if (match_peek(p, TOKEN_IDENTIFIER) && p->tokens->next && p->tokens->next->type == TOKEN_IDENTIFIER)
{
if (p->tokens->next->next && p->tokens->next->next->type == TOKEN_LPAREN) {
/* Function definition. */
return parse_function(p);
}
/* Variable declaration. */
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
node->type = NODE_VAR_DECL;
node->expr.var_decl.type = p->tokens->lexeme;
node->expr.var_decl.type_len = p->tokens->lexeme_len;
advance(p);
node->expr.var_decl.name = p->tokens->lexeme;
node->expr.var_decl.name_len = p->tokens->lexeme_len;
advance(p);
if (match(p, TOKEN_EQ)) {
node->expr.var_decl.value = parse_expression(p);
} else {
node->expr.var_decl.value = NULL;
}
if (!match(p, TOKEN_SEMICOLON))
{
error(p, "expected `;` after statement.");
return NULL;
}
return node;
}
else if (match(p, TOKEN_STRUCT)) else if (match(p, TOKEN_STRUCT))
{ {
return parse_struct(p); return parse_struct(p);

View file

@ -99,14 +99,24 @@ typedef enum {
NODE_UNION, NODE_UNION,
NODE_VAR_DECL, NODE_VAR_DECL,
NODE_FUNCTION, NODE_FUNCTION,
NODE_TERNARY, NODE_PTR_TYPE,
NODE_SWITCH, NODE_TERNARY, /* TODO */
NODE_SWITCH, /* TODO */
NODE_STRUCT_INIT,
NODE_UNIT, NODE_UNIT,
} node_type; } node_type;
#define PTR_SLICE 0x0
#define PTR_RAW 0x1
#define PTR_ARRAY 0x2
typedef struct _ast_node { typedef struct _ast_node {
node_type type; node_type type;
union { union {
struct {
struct _ast_node *type;
u8 flags;
} ptr_type;
struct { struct {
char *name; char *name;
usize name_len; usize name_len;
@ -134,8 +144,7 @@ typedef struct _ast_node {
} ternary; } ternary;
struct { struct {
struct _ast_node *value; struct _ast_node *value;
char *type; struct _ast_node *type;
usize type_len;
} cast; } cast;
struct { struct {
struct _ast_node *expr; struct _ast_node *expr;
@ -183,8 +192,7 @@ typedef struct _ast_node {
struct _ast_node *value; struct _ast_node *value;
char *name; char *name;
usize name_len; usize name_len;
char *type; struct _ast_node *type;
usize type_len;
} var_decl; } var_decl;
struct { struct {
member *members; member *members;
@ -196,8 +204,7 @@ typedef struct _ast_node {
usize parameters_len; usize parameters_len;
char *name; char *name;
usize name_len; usize name_len;
char *type; struct _ast_node *type;
usize type_len;
struct _ast_node *body; struct _ast_node *body;
} function; } function;
struct { struct {
@ -205,6 +212,10 @@ typedef struct _ast_node {
char *name; char *name;
usize name_len; usize name_len;
} enm; // enum } enm; // enum
struct {
struct _ast_node *members;
usize members_len;
} struct_init;
} expr; } expr;
} ast_node; } ast_node;

5
test.l
View file

@ -1,4 +1,5 @@
u32 a(u32 a) u32 a()
{ {
u32 x = 3; Person v = {x = 3, y = 4, z = 5};
return z[0];
} }