summaryrefslogtreecommitdiff
path: root/src/parser.h
diff options
context:
space:
mode:
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) {