#include #include #include #include // Parse postfix expressions (parens, index access, dots) fzl_node_t *pa_postfix(fzl_parser_t *parser) { if (!parser) return NULL; fzl_node_t *left = pa_primary(parser); if (!left) return NULL; if (is(parser, FZL_TOKTYPE_LPAREN) || is(parser, FZL_TOKTYPE_DOT)) { while (is(parser, FZL_TOKTYPE_LPAREN) || is(parser, FZL_TOKTYPE_DOT)) { fzl_token_t *post = consume(parser); if (post->type == FZL_TOKTYPE_LPAREN) { size_t args_capacity = 2; size_t args_count = 0; fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *)); while (!is(parser, FZL_TOKTYPE_RPAREN)) { fzl_node_t *arg = pa_expression(parser); if (!arg) { for (size_t i = 0; i < args_count; i++) fzl_freeast(args[i]); free(args); fzl_freeast(left); return NULL; } if (args_capacity <= args_count) { args_capacity *= 2; args = realloc(args, args_capacity * sizeof(fzl_node_t *)); } args[args_count] = arg; args_count++; if (is(parser, FZL_TOKTYPE_COMMA)) consume(parser); } fzl_token_t *rparen = consume(parser); if (!rparen || rparen->type != FZL_TOKTYPE_RPAREN) { for (size_t i = 0; i < args_count; i++) fzl_freeast(args[i]); free(args); fzl_freeast(left); snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' after argument list at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); return NULL; } fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, left->token); node->call.callee = left; node->call.args = args; node->call.args_count = args_count; left = node; } else if (post->type == FZL_TOKTYPE_DOT) { if (!is(parser, FZL_TOKTYPE_NAME)) { fzl_freeast(left); snprintf(plast_err, sizeof(plast_err), "'%s': expected name after '.' at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); return NULL; } fzl_token_t *name = consume(parser); fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FIELD, name); node->memb.parent = left; node->memb.field = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); left = node; } } } return left; }