#ifndef INCLUDE_parser #define INCLUDE_parser #include "ast.h" #include "lexer.h" #include "token.h" #include #include #include typedef struct { _LX *lx; _T cur; } _P; 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); exit(1); } static void perror_unexpected(_LX *lx, const char *context, const char *got) { fprintf(stderr, "[PARSER] Error at line %d, column %d: unexpected %s in %s\n", lx->line, lx->col, got, context); exit(1); } static void pnext(_P *p) { if (p->cur.lxem) { free(p->cur.lxem); p->cur.lxem = NULL; } p->cur = lxnext(p->lx); } static void pexpect(_P *p, _TK tk) { if (p->cur.kind != tk) { const char *got = (p->cur.kind < TK__COUNT) ? _TN[p->cur.kind] : ""; perror_expected(p->lx, _TN[tk], got); } } 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); _STN *head = NULL; _STN **cur = &head; while (p->cur.kind != TK_RBRACE && p->cur.kind != TK_EOF) { _STN *stmt = pstmt(p); *cur = stmt; cur = &stmt->n; } pexpect(p, TK_RBRACE); pnext(p); return st_block(head); } 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); static _EX *pmul(_P *p); static _EX *padd(_P *p); static _EX *pshift(_P *p); static _EX *pbitand(_P *p); static _EX *pbitxor(_P *p); static _EX *pbitor(_P *p); static _EX *prel(_P *p); static _EX *peq(_P *p); static _EX *plogand(_P *p); static _EX *plogor(_P *p); static _STN *passign_or_expr_stmt(_P *p) { _EX *lhs = pexpr(p); if (p->cur.kind == TK_ASSIGN) { 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 in expression context\n", p->lx->line, p->lx->col); exit(1); } pnext(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) { 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; } static _EX *ppostfix(_P *p) { _EX *e = pfact(p); return ppostfix_from_expr(p, e); } static _EX *pfact(_P *p) { if (p->cur.kind == TK_NUMBER) { _EX *n = ex_number(p->cur.val); pnext(p); return n; } else if (p->cur.kind == TK_IDENT) { char *name = strdup(p->cur.lxem); if (!name) { fprintf(stderr, "[PARSER] Error: strdup failed for identifier\n"); exit(1); } pnext(p); if (p->cur.kind == TK_LPAREN) { pnext(p); _EX **args = NULL; int argc = 0; if (p->cur.kind != TK_RPAREN) { do { args = realloc(args, sizeof(_EX *) * (argc + 1)); if (!args) { fprintf(stderr, "[PARSER] Error at line %d, column %d: out of memory while parsing function arguments\n", p->lx->line, p->lx->col); exit(1); } args[argc++] = pexpr(p); if (p->cur.kind == TK_COMMA) { pnext(p); } else { break; } } while (1); } pexpect(p, TK_RPAREN); pnext(p); return ex_call(name, args, argc); } _EX *var_expr = ex_var(name); return ppostfix_from_expr(p, var_expr); } else if (p->cur.kind == TK_LPAREN) { 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); return ppostfix_from_expr(p, n); } else if (p->cur.kind == TK_STRING) { char *str = strdup(p->cur.lxem); if (!str) { fprintf(stderr, "[PARSER] Error: strdup failed for string literal\n"); exit(1); } 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]); } } 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) { _TK op = p->cur.kind; pnext(p); _EX *r = punary(p); n = ex_binop(n, op, r); } return n; } static _EX *padd(_P *p) { _EX *n = pmul(p); while (p->cur.kind == TK_PLUS || p->cur.kind == TK_MINUS) { _TK op = p->cur.kind; pnext(p); _EX *r = pmul(p); n = ex_binop(n, op, r); } return n; } static _EX *pshift(_P *p) { _EX *n = padd(p); while (p->cur.kind == TK_SHL || p->cur.kind == TK_SHR) { _TK op = p->cur.kind; pnext(p); _EX *r = padd(p); n = ex_binop(n, op, r); } return n; } static _EX *pbitand(_P *p) { _EX *n = peq(p); while (p->cur.kind == TK_AMP) { _TK op = p->cur.kind; pnext(p); _EX *r = peq(p); n = ex_binop(n, op, r); } return n; } static _EX *pbitxor(_P *p) { _EX *n = pbitand(p); while (p->cur.kind == TK_CARET) { _TK op = p->cur.kind; pnext(p); _EX *r = pbitand(p); n = ex_binop(n, op, r); } return n; } static _EX *pbitor(_P *p) { _EX *n = pbitxor(p); while (p->cur.kind == TK_BAR) { _TK op = p->cur.kind; pnext(p); _EX *r = pbitxor(p); n = ex_binop(n, op, r); } return n; } static _EX *prel(_P *p) { _EX *n = pshift(p); while (p->cur.kind == TK_LT || p->cur.kind == TK_LE || p->cur.kind == TK_GT || p->cur.kind == TK_GE) { _TK op = p->cur.kind; pnext(p); _EX *r = pshift(p); n = ex_binop(n, op, r); } return n; } static _EX *peq(_P *p) { _EX *n = prel(p); while (p->cur.kind == TK_EQ || p->cur.kind == TK_NE) { _TK op = p->cur.kind; pnext(p); _EX *r = prel(p); n = ex_binop(n, op, r); } return n; } static _EX *plogand(_P *p) { _EX *n = pbitor(p); while (p->cur.kind == TK_AND) { pnext(p); _EX *r = pbitor(p); n = ex_binop(n, TK_AND, r); } return n; } static _EX *plogor(_P *p) { _EX *n = plogand(p); while (p->cur.kind == TK_OR) { pnext(p); _EX *r = plogand(p); n = ex_binop(n, TK_OR, r); } return n; } 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; } static _EX *punary(_P *p) { 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) { pnext(p); _EX *sub = punary(p); NEW_EX(EX_DEREF); e->deref.expr = sub; return e; } 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); } 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; } 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); pexpect(p, TK_LPAREN); pnext(p); _EX *cond = pexpr(p); pexpect(p, TK_RPAREN); pnext(p); _STN *thenb = pstmt(p); _STN *elseb = NULL; if (p->cur.kind == TK_ELSE) { pnext(p); elseb = pstmt(p); } return st_if(cond, thenb, elseb); } case TK_WHILE: { pnext(p); pexpect(p, TK_LPAREN); pnext(p); _EX *cond = pexpr(p); pexpect(p, TK_RPAREN); pnext(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); _STN *init = NULL; _EX *cond = NULL; _STN *step = NULL; if (p->cur.kind != TK_SEMI) { init = pstmt(p); } else { pnext(p); } if (p->cur.kind != TK_SEMI) { cond = pexpr(p); } pexpect(p, TK_SEMI); pnext(p); if (p->cur.kind != TK_RPAREN) { step = passign_or_expr_stmt(p); } pexpect(p, TK_RPAREN); pnext(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 = pparse_type(p); if (p->cur.kind != TK_IDENT) { perror_expected(p->lx, "variable name after type", _TN[p->cur.kind]); } char *name = strdup(p->cur.lxem); if (!name) { fprintf(stderr, "[PARSER] Error: strdup failed for variable name\n"); exit(1); } pnext(p); if (p->cur.kind == TK_LBRACKET) { pnext(p); if (p->cur.kind == TK_NUMBER) { vtype.array_size = p->cur.val; pnext(p); } else { vtype.array_size = 0; // unknown size [] } pexpect(p, TK_RBRACKET); pnext(p); } _EX *init = NULL; if (p->cur.kind == TK_ASSIGN) { pnext(p); 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); } } pexpect(p, TK_SEMI); pnext(p); _STN *decl = st_var_decl(name, init); decl->var_decl.type = vtype; return decl; } case TK_IDENT: { _EX *lhs_or_call = pfact(p); /* starts from ident path */ if (p->cur.kind == TK_ASSIGN) { pnext(p); _EX *rhs = pexpr(p); pexpect(p, TK_SEMI); pnext(p); return st_assign(lhs_or_call, rhs); } _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); _EX *expr = pexpr(p); pexpect(p, TK_SEMI); pnext(p); /* consume ';' */ return st_return(expr); } case TK_LBRACE: { return pblock(p); } default: { _EX *lhs = pexpr(p); if (p->cur.kind == TK_ASSIGN) { 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); 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); } } } static _FN *pfunc(_P *p) { 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 return type", _TN[p->cur.kind]); } char *name = NULL; if (p->cur.lxem) name = strdup(p->cur.lxem); if (p->cur.lxem && !name) { fprintf(stderr, "[PARSER] Error: strdup failed for function name\n"); exit(1); } pnext(p); pexpect(p, TK_LPAREN); pnext(p); char **params = NULL; _TY *params_types = NULL; int pac = 0; if (p->cur.kind != TK_RPAREN) { while (1) { if (!is_type_token(p->cur.kind)) { perror_expected(p->lx, "type in parameter list", _TN[p->cur.kind]); } _TY vtype = pparse_type(p); if (p->cur.kind != TK_IDENT) { perror_expected(p->lx, "identifier after type in parameter list", _TN[p->cur.kind]); } char *param_name = strdup(p->cur.lxem); if (!param_name) { fprintf(stderr, "[PARSER] Error: strdup failed for parameter name\n"); exit(1); } pnext(p); if (p->cur.kind == TK_LBRACKET) { pnext(p); if (p->cur.kind == TK_NUMBER) { vtype.array_size = p->cur.val; pnext(p); } else { vtype.array_size = 0; // unknown size [] } pexpect(p, TK_RBRACKET); pnext(p); } char **new_params = (char **)realloc(params, sizeof(char *) * (pac + 1)); _TY *new_param_types = (_TY *)realloc(params_types, sizeof(_TY) * (pac + 1)); if (!new_params || !new_param_types) { fprintf(stderr, "[PARSER] Error at line %d, column %d: out of memory while parsing function parameters\n", p->lx->line, p->lx->col); free(new_params); free(new_param_types); exit(1); } params = new_params; params_types = new_param_types; params[pac] = param_name; params_types[pac] = vtype; pac++; if (p->cur.kind == TK_COMMA) { pnext(p); continue; } else { break; } } } pexpect(p, TK_RPAREN); pnext(p); _STN *body = pblock(p); return fn_new(name, params, params_types, pac, body, ret_type); } static _FN *parse_program(_LX *lx) { _P pstate = {.lx = lx, .cur = lxnext(lx)}; _FN *head = NULL; _FN **cur = &head; while (pstate.cur.kind != TK_EOF) { 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) { free(pstate.cur.lxem); pstate.cur.lxem = NULL; } return head; } #endif /* INCLUDE_parser */