summaryrefslogtreecommitdiff
path: root/src/parser.h
diff options
context:
space:
mode:
authorDavid Moc <personal@cdatgoose.org>2026-03-08 15:02:30 +0100
committerDavid Moc <personal@cdatgoose.org>2026-03-08 15:02:30 +0100
commitad035ac5d942c6448a6a0464b995c2868a8378db (patch)
tree9c2c779d544a45b4234a6a3c311aa7b612ea975e /src/parser.h
parent0385817bb1301a778bb33f8405a435293b9f8905 (diff)
Gosh.\nFixed bugs in offsetting. Added syscalls. Cleaned up the previous commenting (used to pass the project thu claude to add comments but LLMs are dumb). Removed the LLM made test runner cuz fuck AI.HEADmaster
Diffstat (limited to 'src/parser.h')
-rw-r--r--src/parser.h472
1 files changed, 360 insertions, 112 deletions
diff --git a/src/parser.h b/src/parser.h
index 154e0ba..bd35323 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -1,5 +1,3 @@
-/* Parser: recursive-descent front end that builds an AST `_FN` list
- * from the token stream, handling expressions, statements, and functions. */
#ifndef INCLUDE_parser
#define INCLUDE_parser
@@ -10,13 +8,13 @@
#include <stdlib.h>
#include <string.h>
-/* Parser state */
+
typedef struct {
_LX *lx;
_T cur;
} _P;
-/* Error reporting with line/column info */
+
static void perror_expected(_LX *lx, const char *expected, const char *got) {
fprintf(stderr, "[PARSER] Error at line %d, column %d: expected %s, got %s\n",
lx->line, lx->col, expected, got);
@@ -37,7 +35,7 @@ static void pnext(_P *p) {
p->cur = lxnext(p->lx);
}
-/* Expect a particular token kind; on mismatch print helpful error and exit */
+
static void pexpect(_P *p, _TK tk) {
if (p->cur.kind != tk) {
const char *got = (p->cur.kind < TK__COUNT) ? _TN[p->cur.kind] : "<?>";
@@ -45,10 +43,35 @@ static void pexpect(_P *p, _TK tk) {
}
}
-static _STN *pstmt(_P *p); // forward
+
+static int is_type_token(_TK k) {
+ return k == TK_INT || k == TK_CHAR || k == TK_VOID ||
+ k == TK_FLOAT || k == TK_LONG || k == TK_SHORT;
+}
+
+
+static _TY pparse_type(_P *p) {
+ _TY ty;
+ switch (p->cur.kind) {
+ case TK_INT: ty = (_TY){.base=TY_INT, .ptr_level=0,.array_size=-1}; break;
+ case TK_CHAR: ty = (_TY){.base=TY_CHAR, .ptr_level=0,.array_size=-1}; break;
+ case TK_VOID: ty = (_TY){.base=TY_VOID, .ptr_level=0,.array_size=-1}; break;
+ case TK_FLOAT: ty = (_TY){.base=TY_FLOAT,.ptr_level=0,.array_size=-1}; break;
+ case TK_LONG: ty = (_TY){.base=TY_LONG, .ptr_level=0,.array_size=-1}; break;
+ case TK_SHORT: ty = (_TY){.base=TY_SHORT,.ptr_level=0,.array_size=-1}; break;
+ default:
+ perror_expected(p->lx, "type keyword", _TN[p->cur.kind]);
+ ty = (_TY){TY_INT,0,-1}; /* unreachable */
+ }
+ pnext(p);
+ while (p->cur.kind == TK_STAR) { ty.ptr_level++; pnext(p); }
+ return ty;
+}
+
+static _STN *pstmt(_P *p);
static _STN *pblock(_P *p) {
pexpect(p, TK_LBRACE);
- pnext(p); /* consume '{' */
+ pnext(p);
_STN *head = NULL;
_STN **cur = &head;
@@ -60,16 +83,17 @@ static _STN *pblock(_P *p) {
}
pexpect(p, TK_RBRACE);
- pnext(p); /* consume '}' */
+ pnext(p);
return st_block(head);
}
-static _EX *pexpr(_P *p); // forward
-static _EX *pterm(_P *p); // forward
-static _EX *punary(_P *p); // forward
-static _EX *pfact(_P *p); // fwd
+static _EX *pexpr(_P *p);
+static _EX *pterm(_P *p);
+static _EX *punary(_P *p);
+static _EX *pfact(_P *p);
+static _EX *pparse_charlit(_P *p);
+
-/* Precedence climbing layers */
static _EX *pmul(_P *p);
static _EX *padd(_P *p);
static _EX *pshift(_P *p);
@@ -92,19 +116,42 @@ static _STN *passign_or_expr_stmt(_P *p) {
_EX *rhs = pexpr(p);
return st_assign(lhs, rhs);
}
+
+ _TK compound_op = TK_INVALID;
+ if (p->cur.kind == TK_PLUS_EQ) compound_op = TK_PLUS;
+ else if (p->cur.kind == TK_MINUS_EQ) compound_op = TK_MINUS;
+ else if (p->cur.kind == TK_STAR_EQ) compound_op = TK_STAR;
+ else if (p->cur.kind == TK_SLASH_EQ) compound_op = TK_SLASH;
+ if (compound_op != TK_INVALID) {
+ if (!(lhs->kind == EX_VAR || lhs->kind == EX_DEREF || lhs->kind == EX_INDEX)) {
+ fprintf(stderr, "[PARSER] Error at line %d, column %d: invalid compound-assignment target\n", p->lx->line, p->lx->col);
+ exit(1);
+ }
+ pnext(p);
+ _EX *rhs = pexpr(p);
+ _EX *combined = ex_binop(lhs, compound_op, rhs);
+ return st_assign(lhs, combined);
+ }
return st_expr(lhs);
}
static _EX *ppostfix_from_expr(_P *p, _EX *e) {
- // Handle array indexing: expr[expr]
- while (p->cur.kind == TK_LBRACKET) {
- pnext(p); // consume '['
- _EX *index = pexpr(p);
- pexpect(p, TK_RBRACKET);
- pnext(p); // consume ']'
- e = ex_index(e, index);
- }
-
+ for (;;) {
+ if (p->cur.kind == TK_LBRACKET) {
+ pnext(p);
+ _EX *index = pexpr(p);
+ pexpect(p, TK_RBRACKET);
+ pnext(p);
+ e = ex_index(e, index);
+ } else if (p->cur.kind == TK_INC || p->cur.kind == TK_DEC) {
+ _TK op = p->cur.kind;
+ pnext(p);
+ _EX *one = ex_number(1);
+ e = ex_binop(e, op, one);
+ } else {
+ break;
+ }
+ }
return e;
}
@@ -113,7 +160,7 @@ static _EX *ppostfix(_P *p) {
return ppostfix_from_expr(p, e);
}
-/* ---- FACTOR ---- */
+
static _EX *pfact(_P *p) {
if (p->cur.kind == TK_NUMBER) {
_EX *n = ex_number(p->cur.val);
@@ -126,11 +173,11 @@ static _EX *pfact(_P *p) {
fprintf(stderr, "[PARSER] Error: strdup failed for identifier\n");
exit(1);
}
- pnext(p); /* consume identifier */
+ pnext(p);
if (p->cur.kind == TK_LPAREN) {
- /* function call */
- pnext(p); /* consume '(' */
+
+ pnext(p);
_EX **args = NULL;
int argc = 0;
@@ -145,7 +192,7 @@ static _EX *pfact(_P *p) {
args[argc++] = pexpr(p);
if (p->cur.kind == TK_COMMA) {
- pnext(p); /* skip comma */
+ pnext(p);
} else {
break;
}
@@ -153,7 +200,7 @@ static _EX *pfact(_P *p) {
}
pexpect(p, TK_RPAREN);
- pnext(p); /* consume ')' */
+ pnext(p);
return ex_call(name, args, argc);
}
@@ -162,11 +209,21 @@ static _EX *pfact(_P *p) {
return ppostfix_from_expr(p, var_expr);
} else if (p->cur.kind == TK_LPAREN) {
- pnext(p); /* consume '(' */
+ pnext(p);
+
+ if (p->cur.kind == TK_INT || p->cur.kind == TK_CHAR ||
+ p->cur.kind == TK_SHORT || p->cur.kind == TK_LONG ||
+ p->cur.kind == TK_VOID || p->cur.kind == TK_FLOAT) {
+ _TY to = pparse_type(p);
+ pexpect(p, TK_RPAREN);
+ pnext(p);
+ _EX *sub = punary(p);
+ return ppostfix_from_expr(p, ex_cast(to, sub));
+ }
_EX *n = pexpr(p);
pexpect(p, TK_RPAREN);
- pnext(p); /* consume ')' */
- return n;
+ pnext(p);
+ return ppostfix_from_expr(p, n);
} else if (p->cur.kind == TK_STRING) {
char *str = strdup(p->cur.lxem);
@@ -177,12 +234,14 @@ static _EX *pfact(_P *p) {
pnext(p);
return ex_string(str);
+ } else if (p->cur.kind == TK_CHARLIT) {
+ return pparse_charlit(p);
+
} else {
perror_unexpected(p->lx, "factor", _TN[p->cur.kind]);
}
}
-/* ---- TERM ---- */
static _EX *pmul(_P *p) {
_EX *n = punary(p);
while (p->cur.kind == TK_STAR || p->cur.kind == TK_SLASH || p->cur.kind == TK_PERCENT) {
@@ -276,7 +335,6 @@ static _EX *plogand(_P *p) {
while (p->cur.kind == TK_AND) {
pnext(p);
_EX *r = pbitor(p);
- // keep as a binary op node TK_AND; codegen will short-circuit
n = ex_binop(n, TK_AND, r);
}
return n;
@@ -292,60 +350,115 @@ static _EX *plogor(_P *p) {
return n;
}
-/* ---- EXPR ---- */
-static _EX *pexpr(_P *p) { return plogor(p); }
+static _EX *pexpr(_P *p) {
+ _EX *n = plogor(p);
+ if (p->cur.kind == TK_QUESTION) {
+ pnext(p); /* consume '?' */
+ _EX *then_e = pexpr(p);
+ if (p->cur.kind != TK_COLON) {
+ fprintf(stderr, "[PARSER] Error at line %d, column %d: expected ':' in ternary\n",
+ p->lx->line, p->lx->col);
+ exit(1);
+ }
+ pnext(p); /* consume ':' */
+ _EX *else_e = pexpr(p);
+ return ex_ternary(n, then_e, else_e);
+ }
+ return n;
+}
-/* ---- UNARY ---- */
static _EX *punary(_P *p) {
- if (p->cur.kind == TK_AMP) { // &expr
+ if (p->cur.kind == TK_AMP) {
pnext(p);
_EX *sub = punary(p);
NEW_EX(EX_ADDR);
e->addr.expr = sub;
return e;
}
- if (p->cur.kind == TK_STAR) { // *expr
+ if (p->cur.kind == TK_STAR) {
pnext(p);
_EX *sub = punary(p);
NEW_EX(EX_DEREF);
e->deref.expr = sub;
return e;
}
- if (p->cur.kind == TK_BANG) { // !expr -> (expr == 0)
+ if (p->cur.kind == TK_BANG) {
pnext(p);
_EX *sub = punary(p);
_EX *zero = ex_number(0);
return ex_binop(sub, TK_EQ, zero);
}
+ if (p->cur.kind == TK_MINUS) {
+ pnext(p);
+ _EX *sub = punary(p);
+ return ex_binop(ex_number(0), TK_MINUS, sub);
+ }
+ if (p->cur.kind == TK_INC || p->cur.kind == TK_DEC) {
+ _TK op = (p->cur.kind == TK_INC) ? TK_INC : TK_DEC;
+ pnext(p);
+ _EX *sub = punary(p);
+ return ex_binop(sub, op, ex_number(-1));
+ }
+ if (p->cur.kind == TK_SIZEOF) {
+ pnext(p); /* consume sizeof */
+ pexpect(p, TK_LPAREN); pnext(p);
+ int sz = 0;
+ if (p->cur.kind == TK_INT || p->cur.kind == TK_CHAR ||
+ p->cur.kind == TK_SHORT || p->cur.kind == TK_LONG ||
+ p->cur.kind == TK_VOID || p->cur.kind == TK_FLOAT) {
+ _TY ty = pparse_type(p);
+ if (ty.ptr_level > 0) sz = 8;
+ else {
+ switch (ty.base) {
+ case TY_CHAR: sz = 1; break;
+ case TY_SHORT: sz = 2; break;
+ case TY_INT: sz = 4; break;
+ case TY_LONG: sz = 8; break;
+ default: sz = 4; break;
+ }
+ }
+ if (ty.array_size > 0) sz *= ty.array_size;
+ } else {
+ /* sizeof(expr) — resolved at JIT time via __sizeof__ built-in */
+ _EX *inner = pexpr(p);
+ pexpect(p, TK_RPAREN); pnext(p);
+ _EX **args = (_EX **)malloc(sizeof(_EX *));
+ if (!args) { fprintf(stderr, "[PARSER] OOM in sizeof\n"); exit(1); }
+ args[0] = inner;
+ return ex_call(strdup("__sizeof__"), args, 1);
+ }
+ pexpect(p, TK_RPAREN); pnext(p);
+ return ex_number(sz);
+ }
return ppostfix(p);
}
-char parse_char_literal(_P *p) {
- /* assume current token is TK_SQUOTE */
- pnext(p); // consume opening '
- if (p->cur.kind != TK_IDENT) {
- perror_expected(p->lx, "character literal", _TN[p->cur.kind]);
- }
- char c = p->cur.lxem[0];
- pnext(p); // consume char
- pexpect(p, TK_SQUOTE);
- pnext(p); // consume closing '
- return c;
+static _EX *pparse_charlit(_P *p) {
+ int value = p->cur.val;
+ pnext(p);
+ _EX *e = (_EX *)calloc(1, sizeof(_EX));
+ if (!e) { fprintf(stderr, "[PARSER] Error: calloc failed in pparse_charlit\n"); exit(1); }
+ e->kind = EX_NUMBER;
+ e->value = value;
+ return e;
}
-_EX *ex_charlit(char c) {
- _EX *e = malloc(sizeof(_EX));
- if (!e) {
- fprintf(stderr, "[PARSER] Error: malloc failed in ex_charlit\n");
- exit(1);
- }
- e->kind = EX_NUMBER;
- e->value = c;
- return e;
+
+static char parse_char_literal(_P *p) {
+ char c = (char)p->cur.val;
+ pnext(p);
+ return c;
+}
+static _EX *ex_charlit(char c) {
+ _EX *e = (_EX *)calloc(1, sizeof(_EX));
+ if (!e) { fprintf(stderr, "[PARSER] Error: calloc failed in ex_charlit\n"); exit(1); }
+ e->kind = EX_NUMBER;
+ e->value = (unsigned char)c;
+ return e;
}
static _STN *pstmt(_P *p) {
switch (p->cur.kind) {
case TK_IF: {
- pnext(p); // consume if
+ pnext(p);
pexpect(p, TK_LPAREN); pnext(p);
_EX *cond = pexpr(p);
pexpect(p, TK_RPAREN); pnext(p);
@@ -362,6 +475,31 @@ static _STN *pstmt(_P *p) {
_STN *body = pstmt(p);
return st_while(cond, body);
}
+ case TK_DO: {
+ pnext(p); /* consume 'do' */
+ _STN *body = pstmt(p);
+ if (p->cur.kind != TK_WHILE) {
+ fprintf(stderr, "[PARSER] Error at line %d, column %d: expected 'while' after do body\n",
+ p->lx->line, p->lx->col);
+ exit(1);
+ }
+ pnext(p); /* consume 'while' */
+ pexpect(p, TK_LPAREN); pnext(p);
+ _EX *cond = pexpr(p);
+ pexpect(p, TK_RPAREN); pnext(p);
+ pexpect(p, TK_SEMI); pnext(p);
+ return st_dowhile(body, cond);
+ }
+ case TK_BREAK: {
+ pnext(p); /* consume 'break' */
+ pexpect(p, TK_SEMI); pnext(p);
+ return st_break();
+ }
+ case TK_CONTINUE: {
+ pnext(p); /* consume 'continue' */
+ pexpect(p, TK_SEMI); pnext(p);
+ return st_continue();
+ }
case TK_FOR: {
pnext(p);
pexpect(p, TK_LPAREN); pnext(p);
@@ -380,11 +518,13 @@ static _STN *pstmt(_P *p) {
_STN *body = pstmt(p);
return st_for(init, cond, step, body);
}
+ case TK_VOID:
+ case TK_FLOAT:
+ case TK_LONG:
+ case TK_SHORT:
case TK_INT:
case TK_CHAR: {
- _TY vtype = { .base = (p->cur.kind == TK_INT) ? TY_INT : TY_CHAR, .ptr_level = 0, .array_size = -1 };
- pnext(p); /* consume type */
- while (p->cur.kind == TK_STAR) { vtype.ptr_level++; pnext(p); }
+ _TY vtype = pparse_type(p);
if (p->cur.kind != TK_IDENT) {
perror_expected(p->lx, "variable name after type", _TN[p->cur.kind]);
@@ -396,27 +536,36 @@ static _STN *pstmt(_P *p) {
}
pnext(p);
- // Parse array size: [N] or []
if (p->cur.kind == TK_LBRACKET) {
- pnext(p); // consume '['
+ pnext(p);
if (p->cur.kind == TK_NUMBER) {
vtype.array_size = p->cur.val;
- pnext(p); // consume number
+ pnext(p);
} else {
vtype.array_size = 0; // unknown size []
}
pexpect(p, TK_RBRACKET);
- pnext(p); // consume ']'
+ pnext(p);
}
_EX *init = NULL;
if (p->cur.kind == TK_ASSIGN) {
pnext(p);
- if (vtype.ptr_level == 0 && vtype.base == TY_CHAR && p->cur.kind == TK_SQUOTE) {
- /* parse char literal */
- char c = parse_char_literal(p); // implement this to consume quotes and return char
- init = ex_charlit(c);
+ if (p->cur.kind == TK_LBRACE) {
+ pnext(p);
+ _EX **elems = NULL;
+ int nelems = 0;
+ while (p->cur.kind != TK_RBRACE && p->cur.kind != TK_EOF) {
+ elems = (_EX **)realloc(elems, sizeof(_EX *) * (nelems + 1));
+ if (!elems) { fprintf(stderr, "[PARSER] OOM in initializer list\n"); exit(1); }
+ elems[nelems++] = pexpr(p);
+ if (p->cur.kind == TK_COMMA) pnext(p);
+ }
+ pexpect(p, TK_RBRACE); pnext(p);
+ init = ex_call(strdup("__initlist__"), elems, nelems);
+ } else if (vtype.ptr_level == 0 && vtype.base == TY_CHAR && p->cur.kind == TK_CHARLIT) {
+ init = pparse_charlit(p);
} else {
init = pexpr(p);
}
@@ -435,16 +584,25 @@ static _STN *pstmt(_P *p) {
if (p->cur.kind == TK_ASSIGN) {
pnext(p);
_EX *rhs = pexpr(p);
- pexpect(p, TK_SEMI);
- pnext(p);
+ pexpect(p, TK_SEMI); pnext(p);
return st_assign(lhs_or_call, rhs);
}
- pexpect(p, TK_SEMI);
- pnext(p);
+ _TK cop = TK_INVALID;
+ if (p->cur.kind == TK_PLUS_EQ) cop = TK_PLUS;
+ else if (p->cur.kind == TK_MINUS_EQ) cop = TK_MINUS;
+ else if (p->cur.kind == TK_STAR_EQ) cop = TK_STAR;
+ else if (p->cur.kind == TK_SLASH_EQ) cop = TK_SLASH;
+ if (cop != TK_INVALID) {
+ pnext(p);
+ _EX *rhs = pexpr(p);
+ pexpect(p, TK_SEMI); pnext(p);
+ return st_assign(lhs_or_call, ex_binop(lhs_or_call, cop, rhs));
+ }
+ pexpect(p, TK_SEMI); pnext(p);
return st_expr(lhs_or_call);
}
case TK_RETURN: {
- pnext(p); /* consume 'return' */
+ pnext(p);
_EX *expr = pexpr(p);
pexpect(p, TK_SEMI);
pnext(p); /* consume ';' */
@@ -452,24 +610,35 @@ static _STN *pstmt(_P *p) {
return st_return(expr);
}
case TK_LBRACE: {
- /* block statement */
- return pblock(p); /* pblock will consume the braces */
+ return pblock(p);
}
default: {
- /* General expression or assignment starting with unary, paren, etc. */
_EX *lhs = pexpr(p);
if (p->cur.kind == TK_ASSIGN) {
- /* only allow assignment to var or *expr */
if (!(lhs->kind == EX_VAR || lhs->kind == EX_DEREF || lhs->kind == EX_INDEX)) {
fprintf(stderr, "[PARSER] Error at line %d, column %d: invalid assignment target - only variables, dereferenced expressions, and array indexing allowed\n", p->lx->line, p->lx->col);
exit(1);
}
pnext(p);
_EX *rhs = pexpr(p);
- pexpect(p, TK_SEMI);
- pnext(p);
+ pexpect(p, TK_SEMI); pnext(p);
return st_assign(lhs, rhs);
}
+ _TK dcop = TK_INVALID;
+ if (p->cur.kind == TK_PLUS_EQ) dcop = TK_PLUS;
+ else if (p->cur.kind == TK_MINUS_EQ) dcop = TK_MINUS;
+ else if (p->cur.kind == TK_STAR_EQ) dcop = TK_STAR;
+ else if (p->cur.kind == TK_SLASH_EQ) dcop = TK_SLASH;
+ if (dcop != TK_INVALID) {
+ if (!(lhs->kind == EX_VAR || lhs->kind == EX_DEREF || lhs->kind == EX_INDEX)) {
+ fprintf(stderr, "[PARSER] Error at line %d, column %d: invalid compound-assignment target\n", p->lx->line, p->lx->col);
+ exit(1);
+ }
+ pnext(p);
+ _EX *rhs = pexpr(p);
+ pexpect(p, TK_SEMI); pnext(p);
+ return st_assign(lhs, ex_binop(lhs, dcop, rhs));
+ }
pexpect(p, TK_SEMI);
pnext(p);
return st_expr(lhs);
@@ -478,11 +647,13 @@ static _STN *pstmt(_P *p) {
}
static _FN *pfunc(_P *p) {
- pexpect(p, TK_INT);
- pnext(p); /* consume 'int' */
+ if (!is_type_token(p->cur.kind)) {
+ perror_expected(p->lx, "return type for function", _TN[p->cur.kind]);
+ }
+ _TY ret_type = pparse_type(p);
if (p->cur.kind != TK_IDENT) {
- perror_expected(p->lx, "function name after 'int'", _TN[p->cur.kind]);
+ perror_expected(p->lx, "function name after return type", _TN[p->cur.kind]);
}
char *name = NULL;
if (p->cur.lxem)
@@ -491,54 +662,42 @@ static _FN *pfunc(_P *p) {
fprintf(stderr, "[PARSER] Error: strdup failed for function name\n");
exit(1);
}
- pnext(p); /* consume function name */
+ pnext(p);
- /* expect '(' then consume it */
pexpect(p, TK_LPAREN);
- pnext(p); /* consume '(' */
+ pnext(p);
- /* parse optional parameter list */
char **params = NULL;
_TY *params_types = NULL;
int pac = 0;
if (p->cur.kind != TK_RPAREN) {
- /* at least one parameter expected */
while (1) {
- /* first token should be a type, e.g. int */
- _TY vtype;
- if (p->cur.kind == TK_INT)
- vtype = (_TY){.base=TY_INT,.ptr_level=0,.array_size=-1};
- else if (p->cur.kind == TK_CHAR)
- vtype = (_TY){.base=TY_CHAR,.ptr_level=0,.array_size=-1};
- else {
+ if (!is_type_token(p->cur.kind)) {
perror_expected(p->lx, "type in parameter list", _TN[p->cur.kind]);
}
- pnext(p); /* consume type */
- while (p->cur.kind == TK_STAR) { vtype.ptr_level++; pnext(p); }
+ _TY vtype = pparse_type(p);
- /* next should be an identifier (variable name) */
if (p->cur.kind != TK_IDENT) {
perror_expected(p->lx, "identifier after type in parameter list", _TN[p->cur.kind]);
}
- // Parse array size for parameters after the identifier
char *param_name = strdup(p->cur.lxem);
if (!param_name) {
fprintf(stderr, "[PARSER] Error: strdup failed for parameter name\n");
exit(1);
}
- pnext(p); // consume identifier
+ pnext(p);
if (p->cur.kind == TK_LBRACKET) {
- pnext(p); // consume '['
+ pnext(p);
if (p->cur.kind == TK_NUMBER) {
vtype.array_size = p->cur.val;
- pnext(p); // consume number
+ pnext(p);
} else {
vtype.array_size = 0; // unknown size []
}
pexpect(p, TK_RBRACKET);
- pnext(p); // consume ']'
+ pnext(p);
}
char **new_params = (char **)realloc(params, sizeof(char *) * (pac + 1));
@@ -556,7 +715,7 @@ static _FN *pfunc(_P *p) {
pac++;
if (p->cur.kind == TK_COMMA) {
- pnext(p); /* consume comma and continue */
+ pnext(p);
continue;
} else {
break;
@@ -565,11 +724,11 @@ static _FN *pfunc(_P *p) {
}
pexpect(p, TK_RPAREN);
- pnext(p); /* consume ')' */
+ pnext(p);
- _STN *body = pblock(p); /* pblock consumes the block braces and returns */
+ _STN *body = pblock(p);
- return fn_new(name, params, params_types, pac, body);
+ return fn_new(name, params, params_types, pac, body, ret_type);
}
static _FN *parse_program(_LX *lx) {
@@ -579,9 +738,98 @@ static _FN *parse_program(_LX *lx) {
_FN **cur = &head;
while (pstate.cur.kind != TK_EOF) {
- _FN *f = pfunc(&pstate);
- *cur = f;
- cur = &f->n;
+ if (!is_type_token(pstate.cur.kind)) {
+ perror_unexpected(pstate.lx, "top-level declaration", _TN[pstate.cur.kind]);
+ }
+
+ /* Peek ahead: type ident ';'/'='/'[' → global var; type ident '(' → function */
+ _TY gtype = pparse_type(&pstate);
+
+ if (pstate.cur.kind != TK_IDENT) {
+ perror_expected(pstate.lx, "identifier after type", _TN[pstate.cur.kind]);
+ }
+ char *gname = strdup(pstate.cur.lxem);
+ if (!gname) { fprintf(stderr, "[PARSER] OOM\n"); exit(1); }
+ pnext(&pstate); /* consume ident */
+
+ if (pstate.cur.kind == TK_LBRACKET) {
+ pnext(&pstate);
+ if (pstate.cur.kind == TK_NUMBER) {
+ gtype.array_size = pstate.cur.val; pnext(&pstate);
+ } else {
+ gtype.array_size = 0;
+ }
+ pexpect(&pstate, TK_RBRACKET); pnext(&pstate);
+ }
+
+ if (pstate.cur.kind == TK_LPAREN) {
+ pnext(&pstate); /* consume '(' */
+
+ char **params = NULL;
+ _TY *param_types = NULL;
+ int pac = 0;
+
+ if (pstate.cur.kind != TK_RPAREN) {
+ do {
+ if (!is_type_token(pstate.cur.kind)) break;
+ _TY ptype = pparse_type(&pstate);
+ char *pname = NULL;
+ if (pstate.cur.kind == TK_IDENT) {
+ pname = strdup(pstate.cur.lxem);
+ if (!pname) { fprintf(stderr, "[PARSER] OOM\n"); exit(1); }
+ pnext(&pstate);
+ } else {
+ pname = strdup("_anon");
+ }
+ params = realloc(params, sizeof(char*) * (pac+1));
+ param_types = realloc(param_types, sizeof(_TY) * (pac+1));
+ if (!params || !param_types) { fprintf(stderr, "[PARSER] OOM\n"); exit(1); }
+ params[pac] = pname;
+ param_types[pac] = ptype;
+ pac++;
+ if (pstate.cur.kind == TK_COMMA) pnext(&pstate); else break;
+ } while (1);
+ }
+ pexpect(&pstate, TK_RPAREN); pnext(&pstate);
+
+ _STN *body = pblock(&pstate);
+
+ _FN *f = fn_new(gname, params, param_types, pac, body, gtype);
+ *cur = f;
+ cur = &f->n;
+ } else {
+ _EX *init = NULL;
+ if (pstate.cur.kind == TK_ASSIGN) {
+ pnext(&pstate);
+ if (pstate.cur.kind == TK_LBRACE) {
+ /* initializer list for global array */
+ pnext(&pstate);
+ _EX **elems = NULL; int nelems = 0;
+ while (pstate.cur.kind != TK_RBRACE && pstate.cur.kind != TK_EOF) {
+ elems = realloc(elems, sizeof(_EX*) * (nelems+1));
+ if (!elems) { fprintf(stderr, "[PARSER] OOM\n"); exit(1); }
+ elems[nelems++] = pexpr(&pstate);
+ if (pstate.cur.kind == TK_COMMA) pnext(&pstate);
+ }
+ pexpect(&pstate, TK_RBRACE); pnext(&pstate);
+ init = ex_call(strdup("__initlist__"), elems, nelems);
+ } else {
+ init = pexpr(&pstate);
+ }
+ }
+ pexpect(&pstate, TK_SEMI); pnext(&pstate);
+
+
+ char *gfunc_name = malloc(strlen(gname) + 12);
+ if (!gfunc_name) { fprintf(stderr, "[PARSER] OOM\n"); exit(1); }
+ sprintf(gfunc_name, "__global_%s__", gname);
+
+ _STN *gdecl = st_global(gname, gtype, init); /* gdecl takes ownership of gname */
+ _FN *gf = fn_new(gfunc_name, NULL, NULL, 0, gdecl,
+ (_TY){TY_VOID,0,-1});
+ *cur = gf;
+ cur = &gf->n;
+ }
}
if (pstate.cur.lxem) {