diff options
Diffstat (limited to 'src/parser.h')
| -rw-r--r-- | src/parser.h | 472 |
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) { |
