From 8c90d54782acc44b1673549d91025d27f11ee1e8 Mon Sep 17 00:00:00 2001 From: samsonium Date: Thu, 29 Oct 2026 00:08:44 +0300 Subject: [PATCH] ref: split parser into separate files --- CMakeLists.txt | 24 + include/compiler/internals/parser.h | 45 + src/compiler/fzl_parser.c | 1309 +-------------------------- src/compiler/parser/pa_and.c | 33 + src/compiler/parser/pa_assignment.c | 42 + src/compiler/parser/pa_block.c | 52 ++ src/compiler/parser/pa_break.c | 17 + src/compiler/parser/pa_class.c | 148 +++ src/compiler/parser/pa_cond.c | 59 ++ src/compiler/parser/pa_expression.c | 8 + src/compiler/parser/pa_factor.c | 41 + src/compiler/parser/pa_for.c | 121 +++ src/compiler/parser/pa_function.c | 101 +++ src/compiler/parser/pa_if.c | 61 ++ src/compiler/parser/pa_loop.c | 20 + src/compiler/parser/pa_new.c | 27 + src/compiler/parser/pa_or.c | 33 + src/compiler/parser/pa_postfix.c | 98 ++ src/compiler/parser/pa_power.c | 41 + src/compiler/parser/pa_primary.c | 164 ++++ src/compiler/parser/pa_program.c | 42 + src/compiler/parser/pa_return.c | 26 + src/compiler/parser/pa_statement.c | 48 + src/compiler/parser/pa_term.c | 40 + src/compiler/parser/pa_unary.c | 24 + src/compiler/parser/pa_while.c | 52 ++ src/compiler/parser/utility.c | 75 ++ 27 files changed, 1444 insertions(+), 1307 deletions(-) create mode 100644 include/compiler/internals/parser.h create mode 100644 src/compiler/parser/pa_and.c create mode 100644 src/compiler/parser/pa_assignment.c create mode 100644 src/compiler/parser/pa_block.c create mode 100644 src/compiler/parser/pa_break.c create mode 100644 src/compiler/parser/pa_class.c create mode 100644 src/compiler/parser/pa_cond.c create mode 100644 src/compiler/parser/pa_expression.c create mode 100644 src/compiler/parser/pa_factor.c create mode 100644 src/compiler/parser/pa_for.c create mode 100644 src/compiler/parser/pa_function.c create mode 100644 src/compiler/parser/pa_if.c create mode 100644 src/compiler/parser/pa_loop.c create mode 100644 src/compiler/parser/pa_new.c create mode 100644 src/compiler/parser/pa_or.c create mode 100644 src/compiler/parser/pa_postfix.c create mode 100644 src/compiler/parser/pa_power.c create mode 100644 src/compiler/parser/pa_primary.c create mode 100644 src/compiler/parser/pa_program.c create mode 100644 src/compiler/parser/pa_return.c create mode 100644 src/compiler/parser/pa_statement.c create mode 100644 src/compiler/parser/pa_term.c create mode 100644 src/compiler/parser/pa_unary.c create mode 100644 src/compiler/parser/pa_while.c create mode 100644 src/compiler/parser/utility.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 95dae20..673be5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,30 @@ add_executable(fzc src/compiler/analyzer/an_strfmt.c src/compiler/analyzer/an_unarycond.c src/compiler/analyzer/an_unarymath.c + src/compiler/parser/pa_and.c + src/compiler/parser/pa_assignment.c + src/compiler/parser/pa_block.c + src/compiler/parser/pa_break.c + src/compiler/parser/pa_class.c + src/compiler/parser/pa_cond.c + src/compiler/parser/pa_expression.c + src/compiler/parser/pa_factor.c + src/compiler/parser/pa_for.c + src/compiler/parser/pa_function.c + src/compiler/parser/pa_if.c + src/compiler/parser/pa_loop.c + src/compiler/parser/pa_new.c + src/compiler/parser/pa_or.c + src/compiler/parser/pa_postfix.c + src/compiler/parser/pa_power.c + src/compiler/parser/pa_primary.c + src/compiler/parser/pa_program.c + src/compiler/parser/pa_return.c + src/compiler/parser/pa_statement.c + src/compiler/parser/pa_term.c + src/compiler/parser/pa_unary.c + src/compiler/parser/pa_while.c + src/compiler/parser/utility.c src/compiler/reader/rd_fmtstr.c src/compiler/reader/rd_name.c src/compiler/reader/rd_number.c diff --git a/include/compiler/internals/parser.h b/include/compiler/internals/parser.h new file mode 100644 index 0000000..58ea577 --- /dev/null +++ b/include/compiler/internals/parser.h @@ -0,0 +1,45 @@ +#ifndef INTERNALS_PARSER_H +#define INTERNALS_PARSER_H + +#include "compiler/fzl_parser.h" +#include "compiler/fzl_token.h" + +extern char plast_err[256]; +extern fzl_token_t *last_known_tok; + +extern fzl_token_t null_tok; +extern fzl_token_t this_tok; + +fzl_token_t *peek(fzl_parser_t *parser); +fzl_token_t *consume(fzl_parser_t *parser); +bool is(fzl_parser_t *parser, fzl_toktype_t type); +fzl_nodetype_t math_op_to_type(fzl_toktype_t type); +fzl_nodetype_t unary_op_to_type(fzl_toktype_t type); + +fzl_node_t *pa_primary(fzl_parser_t *parser); +fzl_node_t *pa_postfix(fzl_parser_t *parser); +fzl_node_t *pa_unary(fzl_parser_t *parser); +fzl_node_t *pa_power(fzl_parser_t *parser); +fzl_node_t *pa_factor(fzl_parser_t *parser); +fzl_node_t *pa_term(fzl_parser_t *parser); +fzl_node_t *pa_cond(fzl_parser_t *parser); +fzl_node_t *pa_and(fzl_parser_t *parser); +fzl_node_t *pa_or(fzl_parser_t *parser); +fzl_node_t *pa_new(fzl_parser_t *parser); +fzl_node_t *pa_assignment(fzl_parser_t *parser); +fzl_node_t *pa_expression(fzl_parser_t *parser); + +fzl_node_t *pa_class(fzl_parser_t *parser); +fzl_node_t *pa_function(fzl_parser_t *parser); +fzl_node_t *pa_return(fzl_parser_t *parser); +fzl_node_t *pa_if(fzl_parser_t *parser); +fzl_node_t *pa_block(fzl_parser_t *parser); +fzl_node_t *pa_for(fzl_parser_t *parser); +fzl_node_t *pa_while(fzl_parser_t *parser); +fzl_node_t *pa_loop(fzl_parser_t *parser); +fzl_node_t *pa_break(fzl_parser_t *parser); + +fzl_node_t *pa_statement(fzl_parser_t *parser); +fzl_node_t *pa_program(fzl_parser_t *parser); + +#endif // INTERNALS_PARSER_H diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 559bf55..cb6e54b 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -44,8 +45,6 @@ fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) return parser; } -// --- Parse zone --- - // Make a new node fzl_node_t *fzl_mknode(fzl_nodetype_t type, fzl_token_t *token) { @@ -62,1316 +61,12 @@ fzl_node_t *fzl_mknode(fzl_nodetype_t type, fzl_token_t *token) return node; } -// Get token at cursor -static fzl_token_t *peek(fzl_parser_t *parser) -{ - if (!parser || !parser->cursor) - return NULL; - - last_known_tok = parser->cursor->token; - return parser->cursor->token; -} - -// Consume token at cursor and move to the next -static fzl_token_t *consume(fzl_parser_t *parser) -{ - if (!parser || !parser->cursor || !parser->cursor->token) - return NULL; - - fzl_token_t *tok = parser->cursor->token; - parser->cursor = parser->cursor->next; - return tok; -} - -// Check if current token have the same type as specified -static bool is(fzl_parser_t *parser, fzl_toktype_t type) -{ - if (!parser) - return false; - - fzl_token_t *tok = peek(parser); - if (!tok) - return false; - - return tok->type == type; -} - -// Convert arithmetic operator token type to node type -static fzl_nodetype_t math_op_to_type(fzl_toktype_t type) -{ - switch (type) - { - case FZL_TOKTYPE_PLUS: - return FZL_NODETYPE_ADD; - case FZL_TOKTYPE_MINUS: - return FZL_NODETYPE_SUB; - case FZL_TOKTYPE_STAR: - return FZL_NODETYPE_MUL; - case FZL_TOKTYPE_SLASH: - return FZL_NODETYPE_DIV; - case FZL_TOKTYPE_CARET: - return FZL_NODETYPE_POW; - case FZL_TOKTYPE_PERCENT: - return FZL_NODETYPE_MOD; - - default: - return 0; - } -} - -static fzl_nodetype_t unary_op_to_type(fzl_toktype_t type) -{ - switch (type) - { - case FZL_TOKTYPE_PLUS: - return FZL_NODETYPE_UNARY_PLUS; - case FZL_TOKTYPE_MINUS: - return FZL_NODETYPE_UNARY_MINUS; - case FZL_TOKTYPE_NOT: - return FZL_NODETYPE_NOT; - - default: - return 0; - } -} - -fzl_node_t *parse_expression(fzl_parser_t *parser); - -// Parse primary -fzl_node_t *parse_primary(fzl_parser_t *parser) -{ - if (!parser || !peek(parser)) - return NULL; - - if (is(parser, FZL_TOKTYPE_STR_LITERAL) || - is(parser, FZL_TOKTYPE_NUM_LITERAL) || - is(parser, FZL_TOKTYPE_BOOL_LITERAL) || - is(parser, FZL_TOKTYPE_NULL_LITERAL)) - { - fzl_token_t *tok = consume(parser); - return fzl_mknode(FZL_NODETYPE_LITERAL, tok); - } - else if (is(parser, FZL_TOKTYPE_STR_FORMAT_START)) - { - consume(parser); - - size_t remainder = 2; - size_t count = 0; - fzl_node_t **entries = malloc(remainder * sizeof(fzl_node_t *)); - if (!entries) - { - snprintf(plast_err, sizeof(plast_err), "out of memory"); - return NULL; - } - - while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_STR_FORMAT_END) - { - if (is(parser, FZL_TOKTYPE_STR_FORMAT_END)) - break; - - if (remainder <= count) - { - remainder *= 2; - fzl_node_t **newentries = - realloc(entries, remainder * sizeof(fzl_node_t *)); - if (!newentries) - { - snprintf(plast_err, sizeof(plast_err), "out of memory"); - for (size_t i = 0; i < count; i++) - fzl_freeast(entries[i]); - - free(entries); - return NULL; - } - - entries = newentries; - } - - fzl_node_t *expr = parse_expression(parser); - if (expr == NULL) - { - for (size_t i = 0; i < count; i++) - fzl_freeast(entries[i]); - - free(entries); - return NULL; - } - - entries[count++] = expr; - } - - fzl_token_t *end = consume(parser); - if (end->type != FZL_TOKTYPE_STR_FORMAT_END) - { - snprintf(plast_err, sizeof(plast_err), - "'%s':%zu:%zu => unterminated format string", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - - for (size_t i = 0; i < count; i++) - fzl_freeast(entries[i]); - - free(entries); - } - - if (count < 1) - { - snprintf(plast_err, sizeof(plast_err), - "'%s':%zu:%zu => do you really need empty format string?", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - - for (size_t i = 0; i < count; i++) - fzl_freeast(entries[i]); - - free(entries); - return NULL; - } - - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FMT_STRING, entries[0]->token); - if (!node) - { - snprintf(plast_err, sizeof(plast_err), "out of memory"); - for (size_t i = 0; i < count; i++) - fzl_freeast(entries[i]); - - free(entries); - return NULL; - } - - node->list.entries = entries; - node->list.entry_count = count; - - return node; - } - else if (is(parser, FZL_TOKTYPE_LPAREN)) - { - consume(parser); - fzl_node_t *node = parse_expression(parser); - if (!is(parser, FZL_TOKTYPE_RPAREN)) - { - snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - fzl_freeast(node); - return NULL; - } - consume(parser); - return node; - } - else if (is(parser, FZL_TOKTYPE_NAME)) - { - fzl_token_t *name = consume(parser); - if (!is(parser, FZL_TOKTYPE_NAME)) - return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); - - fzl_token_t *realname = consume(parser); // :D - fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, name); - decl->var.type = name; - decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, realname); - return decl; - } - else if (is(parser, FZL_TOKTYPE_TYPE)) - { - fzl_token_t *type = consume(parser); - fzl_token_t *name = consume(parser); - if (!name || name->type != FZL_TOKTYPE_NAME) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected name after type at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - - fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, type); - decl->var.type = type; - decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); - return decl; - } - - if (!plast_err[0]) - snprintf(plast_err, sizeof(plast_err), - "'%s': expected expression at %ld:%ld", last_known_tok->filename, - last_known_tok->ln, last_known_tok->cn); - return NULL; -} - -// Parse postfix expressions (parens, index access, dots) -fzl_node_t *parse_postfix(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_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 = parse_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; -} - -// Parse unary operations -fzl_node_t *parse_unary(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS) && - !is(parser, FZL_TOKTYPE_NOT)) - return parse_postfix(parser); - - fzl_token_t *op = consume(parser); - fzl_node_t *operand = parse_unary(parser); - - if (!operand) - return NULL; - - fzl_node_t *result = fzl_mknode(unary_op_to_type(op->type), op); - result->unary_op.operand = operand; - - return result; -} - -fzl_node_t *parse_power(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_unary(parser); - fzl_node_t *right = NULL; - - if (!left) - return NULL; - - if (is(parser, FZL_TOKTYPE_CARET)) - { - fzl_token_t *caret = consume(parser); - - right = parse_unary(parser); - if (!right) - { - fzl_freeast(left); - if (!plast_err[0]) - snprintf(plast_err, sizeof(plast_err), - "'%s': expected expression 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_POW, caret); - node->binary_op.left = left; - node->binary_op.right = right; - - left = node; - } - - return left; -} - -// Parse FACTOR: multiplication and division -fzl_node_t *parse_factor(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_power(parser); - fzl_node_t *right = NULL; - - if (!left) - return NULL; - - while (is(parser, FZL_TOKTYPE_STAR) || is(parser, FZL_TOKTYPE_SLASH) || - is(parser, FZL_TOKTYPE_PERCENT)) - { - fzl_token_t *op = consume(parser); - - right = parse_factor(parser); - if (!right) - { - fzl_freeast(left); - if (!plast_err[0]) - snprintf(plast_err, sizeof(plast_err), - "'%s': expected expression at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - - fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); - node->binary_op.left = left; - node->binary_op.right = right; - left = node; - } - - return left; -} - -// Parse TERM: addition and subtraction -fzl_node_t *parse_term(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_factor(parser); - fzl_node_t *right = NULL; - - if (!left) - return NULL; - - while (is(parser, FZL_TOKTYPE_PLUS) || is(parser, FZL_TOKTYPE_MINUS)) - { - fzl_token_t *op = consume(parser); - - right = parse_factor(parser); - if (!right) - { - fzl_freeast(left); - if (!plast_err[0]) - snprintf(plast_err, sizeof(plast_err), - "'%s': expected expression at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - - fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); - node->binary_op.left = left; - node->binary_op.right = right; - left = node; - } - - return left; -} - -// Parse conditional operations -fzl_node_t *parse_cond(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_term(parser); - fzl_node_t *right = NULL; - - if (!left) - return NULL; - - while (is(parser, FZL_TOKTYPE_EQEQ) || is(parser, FZL_TOKTYPE_NEQ) || - is(parser, FZL_TOKTYPE_LANGLE) || is(parser, FZL_TOKTYPE_LEQ) || - is(parser, FZL_TOKTYPE_RANGLE) || is(parser, FZL_TOKTYPE_REQ)) - { - fzl_token_t *op = consume(parser); - right = parse_term(parser); - if (!right) - { - fzl_freeast(left); - return NULL; - } - - fzl_node_t *result; - switch (op->type) - { - case FZL_TOKTYPE_EQEQ: - result = fzl_mknode(FZL_NODETYPE_EQUAL, op); - break; - case FZL_TOKTYPE_NEQ: - result = fzl_mknode(FZL_NODETYPE_NEQUAL, op); - break; - case FZL_TOKTYPE_LANGLE: - result = fzl_mknode(FZL_NODETYPE_LESS, op); - break; - case FZL_TOKTYPE_LEQ: - result = fzl_mknode(FZL_NODETYPE_LESS_EQUAL, op); - break; - case FZL_TOKTYPE_RANGLE: - result = fzl_mknode(FZL_NODETYPE_GREATER, op); - break; - case FZL_TOKTYPE_REQ: - result = fzl_mknode(FZL_NODETYPE_GREATER_EQUAL, op); - break; - default: - return NULL; - } - - result->binary_op.left = left; - result->binary_op.right = right; - left = result; - } - - return left; -} - -// Parse conditional && -fzl_node_t *parse_and(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_cond(parser); - fzl_node_t *right = NULL; - - if (!left) - return NULL; - - while (is(parser, FZL_TOKTYPE_DAMPERSAND)) - { - fzl_token_t * or = consume(parser); - right = parse_cond(parser); - if (!right) - { - fzl_freeast(left); - return NULL; - } - - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_AND, or); - node->binary_op.left = left; - node->binary_op.right = right; - left = node; - } - - return left; -} - -// Parse conditional || -fzl_node_t *parse_or(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_node_t *left = parse_and(parser); - fzl_node_t *right = NULL; - - if (!left) - return NULL; - - while (is(parser, FZL_TOKTYPE_DVBAR)) - { - fzl_token_t * or = consume(parser); - right = parse_and(parser); - if (!right) - { - fzl_freeast(left); - return NULL; - } - - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_OR, or); - node->binary_op.left = left; - node->binary_op.right = right; - left = node; - } - - return left; -} - -// Object construct parsing -fzl_node_t *parse_new(fzl_parser_t *parser) -{ - if (!is(parser, FZL_TOKTYPE_NEW)) - return parse_or(parser); - - fzl_token_t *new = consume(parser); - fzl_node_t *objname = parse_or(parser); - if (!objname || (objname->type != FZL_NODETYPE_IDENTIFIER && - objname->type != FZL_NODETYPE_FIELD)) - { - fzl_freeast(objname); - snprintf(plast_err, sizeof(plast_err), - "'%s': expected class name after 'new' keyword 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_CONSTRUCT, new); - node->construct.name = objname; - - return node; -} - -// Assignments parsing -fzl_node_t *parse_assignment(fzl_parser_t *parser) -{ - fzl_node_t *left = parse_new(parser); - if (!left) - return NULL; - - if (is(parser, FZL_TOKTYPE_EQ)) - { - fzl_token_t *asn = consume(parser); - if (!left || (left->type != FZL_NODETYPE_IDENTIFIER && - left->type != FZL_NODETYPE_DECLARATION && - left->type != FZL_NODETYPE_FIELD)) - { - fzl_freeast(left); - snprintf(plast_err, sizeof(plast_err), - "'%s': cannot assign to '%s' at %ld:%ld", - last_known_tok->filename, (char *)left->token->value, - last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_node_t *right = parse_assignment(parser); - if (!right) - { - fzl_freeast(left); - return NULL; - } - - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_ASSIGN, asn); - node->binary_op.left = left; - node->binary_op.right = right; - - left = node; - } - - return left; -} - -// Expression parsing -fzl_node_t *parse_expression(fzl_parser_t *parser) -{ - return parse_assignment(parser); -} - -fzl_node_t *parse_statement(fzl_parser_t *parser); - -// Parse class definition -fzl_node_t *parse_class(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_token_t *class = consume(parser); - fzl_token_t *name = consume(parser); - if (!name || name->type != FZL_TOKTYPE_NAME) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected class name at %ld:%ld", last_known_tok->filename, - last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_token_t *lbrace = consume(parser); - if (!lbrace || lbrace->type != FZL_TOKTYPE_LBRACE) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected '{' after class name at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - size_t fremainder = 2; - size_t fcount = 0; - fzl_node_t **fields = malloc(fremainder * sizeof(fzl_node_t *)); - if (!fields) - { - snprintf(plast_err, sizeof(plast_err), - "failed to allocate space for class fields"); - return NULL; - } - - size_t mremainder = 2; - size_t mcount = 0; - fzl_node_t **methods = malloc(mremainder * sizeof(fzl_node_t *)); - if (!methods) - { - snprintf(plast_err, sizeof(plast_err), - "failed to allocate space for class fields"); - free(fields); - return NULL; - } - - while (!is(parser, FZL_TOKTYPE_RBRACE)) - { - fzl_node_t *node = parse_statement(parser); - if (!node) - return NULL; - - if (node->type == FZL_NODETYPE_DECLARATION) - { - if (fremainder <= fcount) - { - fremainder *= 2; - fields = realloc(fields, fremainder * sizeof(fzl_node_t *)); - if (!fields) - { - snprintf(plast_err, sizeof(plast_err), - "failed to resize fields array"); - fzl_freeast(node); - free(methods); - return NULL; - } - } - - fields[fcount++] = node; - } - else if (node->type == FZL_NODETYPE_FUNCTION) - { - if (mremainder <= mcount) - { - mremainder *= 2; - methods = realloc(methods, mremainder * sizeof(fzl_node_t *)); - if (!methods) - { - snprintf(plast_err, sizeof(plast_err), - "failed to resize methods array"); - fzl_freeast(node); - free(fields); - return NULL; - } - } - - fzl_node_t **new_args = realloc(node->fn.args, (++node->fn.args_count) * - sizeof(fzl_node_t *)); - if (!new_args) - { - snprintf(plast_err, sizeof(plast_err), - "failed to reallocate method args list"); - free(fields); - fzl_freeast(node); - return NULL; - } - - if (node->fn.args_count > 1) - memmove(&new_args[1], new_args, - (node->fn.args_count - 1) * sizeof(fzl_node_t *)); - - fzl_node_t *this_id = fzl_mknode(FZL_NODETYPE_IDENTIFIER, &this_tok); - fzl_node_t *this_dec = fzl_mknode(FZL_NODETYPE_DECLARATION, name); - this_dec->var.type = name; - this_dec->var.identifier = this_id; - - new_args[0] = this_dec; - node->fn.args = new_args; - methods[mcount++] = node; - } - else - { - fzl_freeast(node); - snprintf(plast_err, sizeof(plast_err), - "'%s': unknown type of class member at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - free(fields); - free(methods); - return NULL; - } - } - fzl_token_t *rbra = consume(parser); - if (rbra->type != FZL_TOKTYPE_RBRACE) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected '}' after class definition at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - free(fields); - free(methods); - return NULL; - } - - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CLASS, class); - node->class.name = name; - node->class.fields = fields; - node->class.fields_count = fcount; - node->class.methods = methods; - node->class.methods_count = mcount; - - return node; -} - -// Functions parsing -fzl_node_t *parse_function(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_token_t *fn = consume(parser); - if (!fn || fn->type != FZL_TOKTYPE_FUNCTION) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected keyword 'fn' at %ld:%ld", last_known_tok->filename, - last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_token_t *name = consume(parser); - if (!name || name->type != FZL_TOKTYPE_NAME) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected function name at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_token_t *lpar = consume(parser); - if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN) - { - snprintf(plast_err, sizeof(plast_err), "'%s': expected '(' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - size_t remainder = 1; - size_t count = 0; - fzl_node_t **args = malloc(remainder * sizeof(fzl_node_t *)); - - while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN)) - { - fzl_node_t *arg = parse_expression(parser); - if (!arg) - return NULL; - - if (remainder <= count) - { - remainder *= 2; - args = realloc(args, remainder * sizeof(fzl_node_t *)); - } - - args[count++] = arg; - - if (is(parser, FZL_TOKTYPE_COMMA)) - consume(parser); - } - - fzl_token_t *rpar = consume(parser); - if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN) - { - free(args); - 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_token_t *type = NULL; - if (is(parser, FZL_TOKTYPE_TYPE) || is(parser, FZL_TOKTYPE_NAME)) - type = consume(parser); - - if (!type) - type = &null_tok; - - if (!is(parser, FZL_TOKTYPE_LBRACE)) - { - free(args); - snprintf(plast_err, sizeof(plast_err), - "'%s': expected '{' after function declaration at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_node_t *body = parse_statement(parser); - if (!body) - { - free(args); - return NULL; - } - - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FUNCTION, name); - node->fn.args = args; - node->fn.args_count = count; - node->fn.body = body; - node->fn.name = name; - node->fn.type = type; - - return node; -} - -// Return parsing -fzl_node_t *parse_return(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_token_t *ret = consume(parser); - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_RETURN, ret); - - if (!is(parser, FZL_TOKTYPE_SEMICOLON)) - { - fzl_node_t *retval = parse_expression(parser); - if (!retval) - { - fzl_freeast(node); - return NULL; - } - - node->ret.value = retval; - } - - return node; -} - -fzl_node_t *parse_if(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_token_t *if_tok = consume(parser); - fzl_token_t *lparen = consume(parser); - if (lparen->type != FZL_TOKTYPE_LPAREN) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected '(' before condition at %ld:%ld", lparen->filename, - lparen->ln, lparen->cn); - return NULL; - } - - fzl_node_t *condition = parse_expression(parser); - if (!condition) - return NULL; - - fzl_token_t *rparen = consume(parser); - if (rparen->type != FZL_TOKTYPE_RPAREN) - { - fzl_freeast(condition); - snprintf(plast_err, sizeof(plast_err), - "'%s': expected ')' after condition at %ld:%ld", rparen->filename, - rparen->ln, rparen->cn); - return NULL; - } - - fzl_node_t *else_block = NULL; - fzl_node_t *true_block = parse_statement(parser); - if (!true_block) - { - fzl_freeast(condition); - return NULL; - } - - if (is(parser, FZL_TOKTYPE_ELSE)) - { - consume(parser); // else - else_block = parse_statement(parser); - if (!else_block) - { - fzl_freeast(condition); - fzl_freeast(true_block); - return NULL; - } - } - - fzl_node_t *stmt_node = fzl_mknode(FZL_NODETYPE_CONDITIONAL, if_tok); - stmt_node->cond.condition = condition; - stmt_node->cond.true_block = true_block; - stmt_node->cond.else_block = else_block; - - return stmt_node; -} - -// Block statement parsing -fzl_node_t *parse_block(fzl_parser_t *parser) -{ - if (!parser) - return NULL; - - fzl_token_t *block_tok = consume(parser); - - size_t remainder = 2; - size_t count = 0; - fzl_node_t **stmts = malloc(remainder * sizeof(fzl_node_t *)); - - while (peek(parser) && !is(parser, FZL_TOKTYPE_RBRACE)) - { - fzl_node_t *node = parse_statement(parser); - if (!node) - { - free(stmts); - return NULL; - } - - if (remainder <= count) - { - remainder *= 2; - stmts = realloc(stmts, remainder * sizeof(fzl_node_t *)); - } - - stmts[count++] = node; - } - fzl_token_t *rbrace = consume(parser); - if (!rbrace || rbrace->type != FZL_TOKTYPE_RBRACE) - { - for (size_t i = 0; i < count; i++) - fzl_freeast(stmts[i]); - free(stmts); - - snprintf(plast_err, sizeof(plast_err), - "'%s': missing '}' after block 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_BLOCK, block_tok); - node->list.entries = stmts; - node->list.entry_count = count; - return node; -} - -// For-loop parsing -fzl_node_t *parse_for(fzl_parser_t *parser) -{ - fzl_token_t *tok = consume(parser); - fzl_token_t *lpar = consume(parser); - if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected '(' after for keyword at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_node_t *start = NULL; - if (!is(parser, FZL_TOKTYPE_SEMICOLON)) - { - start = parse_expression(parser); - if (!start) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': expected loop init or ';' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - - fzl_token_t *sc = consume(parser); - if (!sc || sc->type != FZL_TOKTYPE_SEMICOLON) - { - fzl_freeast(start); - snprintf(plast_err, sizeof(plast_err), - "'%s': missing ';' after init section at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - } - else - consume(parser); - - fzl_node_t *condition = NULL; - if (!is(parser, FZL_TOKTYPE_SEMICOLON)) - { - condition = parse_expression(parser); - if (!condition) - { - fzl_freeast(start); - snprintf(plast_err, sizeof(plast_err), - "'%s': expected loop condition or ';' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - - fzl_token_t *sc = consume(parser); - if (!sc || sc->type != FZL_TOKTYPE_SEMICOLON) - { - fzl_freeast(start); - fzl_freeast(condition); - snprintf(plast_err, sizeof(plast_err), - "'%s': missing ';' after condition at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - } - else - consume(parser); - - fzl_node_t *step = NULL; - if (!is(parser, FZL_TOKTYPE_RPAREN)) - { - step = parse_expression(parser); - if (!step) - { - fzl_freeast(start); - fzl_freeast(condition); - snprintf(plast_err, sizeof(plast_err), - "'%s': expected loop step end or ')' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, - last_known_tok->cn); - return NULL; - } - } - - fzl_token_t *rpar = consume(parser); - if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN) - { - fzl_freeast(start); - fzl_freeast(condition); - fzl_freeast(step); - snprintf(plast_err, sizeof(plast_err), - "'%s': missing ')' after loop setup at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_node_t *body = parse_statement(parser); - if (!body) - { - fzl_freeast(start); - fzl_freeast(condition); - fzl_freeast(step); - snprintf(plast_err, sizeof(plast_err), - "'%s': missing body of for loop 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_LOOP, tok); - node->loop.init = start; - node->loop.cond = condition; - node->loop.step = step; - node->loop.body = body; - - return node; -} - -// While-loop parsing -fzl_node_t *parse_while(fzl_parser_t *parser) -{ - fzl_token_t *tok = consume(parser); - fzl_token_t *lpar = consume(parser); - if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': missing '(' after while keyword at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_node_t *condition = parse_expression(parser); - if (!condition) - { - snprintf(plast_err, sizeof(plast_err), - "'%s': missing condition for 'while' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_token_t *rpar = consume(parser); - if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN) - { - fzl_freeast(condition); - snprintf(plast_err, sizeof(plast_err), - "'%s': missing ')' after while loop condition at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - - fzl_node_t *body = parse_statement(parser); - if (!body) - { - fzl_freeast(condition); - snprintf(plast_err, sizeof(plast_err), - "'%s': missing while loop body 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_LOOP, tok); - node->loop.cond = condition; - node->loop.body = body; - - return node; -} - -// `while` and `for` loops -fzl_node_t *parse_loop(fzl_parser_t *parser) -{ - if (!peek(parser)) - return NULL; - - if (is(parser, FZL_TOKTYPE_FOR)) - return parse_for(parser); - else if (is(parser, FZL_TOKTYPE_WHILE)) - return parse_while(parser); - - snprintf(plast_err, sizeof(plast_err), - "'%s': unknown type of loop at %ld:%ld", last_known_tok->filename, - last_known_tok->ln, last_known_tok->cn); - return NULL; -} - -// `break` keyword parsing -fzl_node_t *parse_break(fzl_parser_t *parser) -{ - fzl_token_t *tok = consume(parser); - if (!tok) - { - snprintf(plast_err, sizeof(plast_err), "'%s': EOF", - last_known_tok->filename); - return NULL; - } - - return fzl_mknode(FZL_NODETYPE_BREAK, tok); -} - -// Statement parsing -fzl_node_t *parse_statement(fzl_parser_t *parser) -{ - if (!peek(parser)) - return NULL; - - fzl_node_t *res = NULL; - - if (is(parser, FZL_TOKTYPE_CLASS)) - return parse_class(parser); - else if (is(parser, FZL_TOKTYPE_FUNCTION)) - return parse_function(parser); - else if (is(parser, FZL_TOKTYPE_RETURN)) - res = parse_return(parser); - else if (is(parser, FZL_TOKTYPE_IF)) - return parse_if(parser); - else if (is(parser, FZL_TOKTYPE_LBRACE)) - return parse_block(parser); - else if (is(parser, FZL_TOKTYPE_FOR) || is(parser, FZL_TOKTYPE_WHILE)) - return parse_loop(parser); - else if (is(parser, FZL_TOKTYPE_BREAK)) - res = parse_break(parser); - - if (!res) - res = parse_expression(parser); - - if (!res) - { - fzl_freeast(res); - return NULL; - } - - if (!is(parser, FZL_TOKTYPE_SEMICOLON)) - { - fzl_freeast(res); - snprintf(plast_err, sizeof(plast_err), "'%s': missing ';' at %ld:%ld", - last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); - return NULL; - } - while (is(parser, FZL_TOKTYPE_SEMICOLON)) - consume(parser); - - return res; -} - -// Internal parsing entry point -fzl_node_t *parse_program(fzl_parser_t *parser) -{ - if (!peek(parser)) - return NULL; - - fzl_node_t *first = NULL; - fzl_node_t *last = NULL; - fzl_node_t *node = NULL; - while (peek(parser) != NULL) - { - node = parse_statement(parser); - if (!node) - { - fzl_freeast(first); - return NULL; - } - - if (!last) - { - first = node; - last = node; - } - else - { - last->next = node; - last = node; - } - } - - if (!first) - { - snprintf(plast_err, sizeof(plast_err), "nothing to parse >:("); - return NULL; - } - - return first; -} - // Parse tokens and build AST int fzl_parse(fzl_parser_t *parser) { last_known_tok = NULL; - fzl_node_t *ast = parse_program(parser); + fzl_node_t *ast = pa_program(parser); if (!ast) return -1; diff --git a/src/compiler/parser/pa_and.c b/src/compiler/parser/pa_and.c new file mode 100644 index 0000000..cc99bb4 --- /dev/null +++ b/src/compiler/parser/pa_and.c @@ -0,0 +1,33 @@ +#include +#include + +// Parse conditional && +fzl_node_t *pa_and(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_node_t *left = pa_cond(parser); + fzl_node_t *right = NULL; + + if (!left) + return NULL; + + while (is(parser, FZL_TOKTYPE_DAMPERSAND)) + { + fzl_token_t * or = consume(parser); + right = pa_cond(parser); + if (!right) + { + fzl_freeast(left); + return NULL; + } + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_AND, or); + node->binary_op.left = left; + node->binary_op.right = right; + left = node; + } + + return left; +} diff --git a/src/compiler/parser/pa_assignment.c b/src/compiler/parser/pa_assignment.c new file mode 100644 index 0000000..198d548 --- /dev/null +++ b/src/compiler/parser/pa_assignment.c @@ -0,0 +1,42 @@ +#include +#include +#include + +// Assignments parsing +fzl_node_t *pa_assignment(fzl_parser_t *parser) +{ + fzl_node_t *left = pa_new(parser); + if (!left) + return NULL; + + if (is(parser, FZL_TOKTYPE_EQ)) + { + fzl_token_t *asn = consume(parser); + if (!left || (left->type != FZL_NODETYPE_IDENTIFIER && + left->type != FZL_NODETYPE_DECLARATION && + left->type != FZL_NODETYPE_FIELD)) + { + fzl_freeast(left); + snprintf(plast_err, sizeof(plast_err), + "'%s': cannot assign to '%s' at %ld:%ld", + last_known_tok->filename, (char *)left->token->value, + last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_node_t *right = pa_assignment(parser); + if (!right) + { + fzl_freeast(left); + return NULL; + } + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_ASSIGN, asn); + node->binary_op.left = left; + node->binary_op.right = right; + + left = node; + } + + return left; +} diff --git a/src/compiler/parser/pa_block.c b/src/compiler/parser/pa_block.c new file mode 100644 index 0000000..afd3f30 --- /dev/null +++ b/src/compiler/parser/pa_block.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +// Block statement parsing +fzl_node_t *pa_block(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_token_t *block_tok = consume(parser); + + size_t remainder = 2; + size_t count = 0; + fzl_node_t **stmts = malloc(remainder * sizeof(fzl_node_t *)); + + while (peek(parser) && !is(parser, FZL_TOKTYPE_RBRACE)) + { + fzl_node_t *node = pa_statement(parser); + if (!node) + { + free(stmts); + return NULL; + } + + if (remainder <= count) + { + remainder *= 2; + stmts = realloc(stmts, remainder * sizeof(fzl_node_t *)); + } + + stmts[count++] = node; + } + fzl_token_t *rbrace = consume(parser); + if (!rbrace || rbrace->type != FZL_TOKTYPE_RBRACE) + { + for (size_t i = 0; i < count; i++) + fzl_freeast(stmts[i]); + free(stmts); + + snprintf(plast_err, sizeof(plast_err), + "'%s': missing '}' after block 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_BLOCK, block_tok); + node->list.entries = stmts; + node->list.entry_count = count; + return node; +} diff --git a/src/compiler/parser/pa_break.c b/src/compiler/parser/pa_break.c new file mode 100644 index 0000000..ebb4d47 --- /dev/null +++ b/src/compiler/parser/pa_break.c @@ -0,0 +1,17 @@ +#include +#include +#include + +// `break` keyword parsing +fzl_node_t *pa_break(fzl_parser_t *parser) +{ + fzl_token_t *tok = consume(parser); + if (!tok) + { + snprintf(plast_err, sizeof(plast_err), "'%s': EOF", + last_known_tok->filename); + return NULL; + } + + return fzl_mknode(FZL_NODETYPE_BREAK, tok); +} diff --git a/src/compiler/parser/pa_class.c b/src/compiler/parser/pa_class.c new file mode 100644 index 0000000..db87791 --- /dev/null +++ b/src/compiler/parser/pa_class.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include + +// Parse class definition +fzl_node_t *pa_class(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_token_t *class = consume(parser); + fzl_token_t *name = consume(parser); + if (!name || name->type != FZL_TOKTYPE_NAME) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected class name at %ld:%ld", last_known_tok->filename, + last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_token_t *lbrace = consume(parser); + if (!lbrace || lbrace->type != FZL_TOKTYPE_LBRACE) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected '{' after class name at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + size_t fremainder = 2; + size_t fcount = 0; + fzl_node_t **fields = malloc(fremainder * sizeof(fzl_node_t *)); + if (!fields) + { + snprintf(plast_err, sizeof(plast_err), + "failed to allocate space for class fields"); + return NULL; + } + + size_t mremainder = 2; + size_t mcount = 0; + fzl_node_t **methods = malloc(mremainder * sizeof(fzl_node_t *)); + if (!methods) + { + snprintf(plast_err, sizeof(plast_err), + "failed to allocate space for class fields"); + free(fields); + return NULL; + } + + while (!is(parser, FZL_TOKTYPE_RBRACE)) + { + fzl_node_t *node = pa_statement(parser); + if (!node) + return NULL; + + if (node->type == FZL_NODETYPE_DECLARATION) + { + if (fremainder <= fcount) + { + fremainder *= 2; + fields = realloc(fields, fremainder * sizeof(fzl_node_t *)); + if (!fields) + { + snprintf(plast_err, sizeof(plast_err), + "failed to resize fields array"); + fzl_freeast(node); + free(methods); + return NULL; + } + } + + fields[fcount++] = node; + } + else if (node->type == FZL_NODETYPE_FUNCTION) + { + if (mremainder <= mcount) + { + mremainder *= 2; + methods = realloc(methods, mremainder * sizeof(fzl_node_t *)); + if (!methods) + { + snprintf(plast_err, sizeof(plast_err), + "failed to resize methods array"); + fzl_freeast(node); + free(fields); + return NULL; + } + } + + fzl_node_t **new_args = realloc(node->fn.args, (++node->fn.args_count) * + sizeof(fzl_node_t *)); + if (!new_args) + { + snprintf(plast_err, sizeof(plast_err), + "failed to reallocate method args list"); + free(fields); + fzl_freeast(node); + return NULL; + } + + if (node->fn.args_count > 1) + memmove(&new_args[1], new_args, + (node->fn.args_count - 1) * sizeof(fzl_node_t *)); + + fzl_node_t *this_id = fzl_mknode(FZL_NODETYPE_IDENTIFIER, &this_tok); + fzl_node_t *this_dec = fzl_mknode(FZL_NODETYPE_DECLARATION, name); + this_dec->var.type = name; + this_dec->var.identifier = this_id; + + new_args[0] = this_dec; + node->fn.args = new_args; + methods[mcount++] = node; + } + else + { + fzl_freeast(node); + snprintf(plast_err, sizeof(plast_err), + "'%s': unknown type of class member at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + free(fields); + free(methods); + return NULL; + } + } + fzl_token_t *rbra = consume(parser); + if (rbra->type != FZL_TOKTYPE_RBRACE) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected '}' after class definition at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + free(fields); + free(methods); + return NULL; + } + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CLASS, class); + node->class.name = name; + node->class.fields = fields; + node->class.fields_count = fcount; + node->class.methods = methods; + node->class.methods_count = mcount; + + return node; +} diff --git a/src/compiler/parser/pa_cond.c b/src/compiler/parser/pa_cond.c new file mode 100644 index 0000000..ef7b03f --- /dev/null +++ b/src/compiler/parser/pa_cond.c @@ -0,0 +1,59 @@ +#include +#include + +// Parse conditional operations +fzl_node_t *pa_cond(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_node_t *left = pa_term(parser); + fzl_node_t *right = NULL; + + if (!left) + return NULL; + + while (is(parser, FZL_TOKTYPE_EQEQ) || is(parser, FZL_TOKTYPE_NEQ) || + is(parser, FZL_TOKTYPE_LANGLE) || is(parser, FZL_TOKTYPE_LEQ) || + is(parser, FZL_TOKTYPE_RANGLE) || is(parser, FZL_TOKTYPE_REQ)) + { + fzl_token_t *op = consume(parser); + right = pa_term(parser); + if (!right) + { + fzl_freeast(left); + return NULL; + } + + fzl_node_t *result; + switch (op->type) + { + case FZL_TOKTYPE_EQEQ: + result = fzl_mknode(FZL_NODETYPE_EQUAL, op); + break; + case FZL_TOKTYPE_NEQ: + result = fzl_mknode(FZL_NODETYPE_NEQUAL, op); + break; + case FZL_TOKTYPE_LANGLE: + result = fzl_mknode(FZL_NODETYPE_LESS, op); + break; + case FZL_TOKTYPE_LEQ: + result = fzl_mknode(FZL_NODETYPE_LESS_EQUAL, op); + break; + case FZL_TOKTYPE_RANGLE: + result = fzl_mknode(FZL_NODETYPE_GREATER, op); + break; + case FZL_TOKTYPE_REQ: + result = fzl_mknode(FZL_NODETYPE_GREATER_EQUAL, op); + break; + default: + return NULL; + } + + result->binary_op.left = left; + result->binary_op.right = right; + left = result; + } + + return left; +} diff --git a/src/compiler/parser/pa_expression.c b/src/compiler/parser/pa_expression.c new file mode 100644 index 0000000..7f7f0bc --- /dev/null +++ b/src/compiler/parser/pa_expression.c @@ -0,0 +1,8 @@ +#include +#include + +// Expression parsing +fzl_node_t *pa_expression(fzl_parser_t *parser) +{ + return pa_assignment(parser); +} diff --git a/src/compiler/parser/pa_factor.c b/src/compiler/parser/pa_factor.c new file mode 100644 index 0000000..cbc0a92 --- /dev/null +++ b/src/compiler/parser/pa_factor.c @@ -0,0 +1,41 @@ +#include +#include +#include + +// Parse FACTOR: multiplication and division +fzl_node_t *pa_factor(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_node_t *left = pa_power(parser); + fzl_node_t *right = NULL; + + if (!left) + return NULL; + + while (is(parser, FZL_TOKTYPE_STAR) || is(parser, FZL_TOKTYPE_SLASH) || + is(parser, FZL_TOKTYPE_PERCENT)) + { + fzl_token_t *op = consume(parser); + + right = pa_factor(parser); + if (!right) + { + fzl_freeast(left); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': expected expression at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + + fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); + node->binary_op.left = left; + node->binary_op.right = right; + left = node; + } + + return left; +} diff --git a/src/compiler/parser/pa_for.c b/src/compiler/parser/pa_for.c new file mode 100644 index 0000000..1326971 --- /dev/null +++ b/src/compiler/parser/pa_for.c @@ -0,0 +1,121 @@ +#include +#include +#include + +// For-loop parsing +fzl_node_t *pa_for(fzl_parser_t *parser) +{ + fzl_token_t *tok = consume(parser); + fzl_token_t *lpar = consume(parser); + if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected '(' after for keyword at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_node_t *start = NULL; + if (!is(parser, FZL_TOKTYPE_SEMICOLON)) + { + start = pa_expression(parser); + if (!start) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected loop init or ';' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + + fzl_token_t *sc = consume(parser); + if (!sc || sc->type != FZL_TOKTYPE_SEMICOLON) + { + fzl_freeast(start); + snprintf(plast_err, sizeof(plast_err), + "'%s': missing ';' after init section at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + } + else + consume(parser); + + fzl_node_t *condition = NULL; + if (!is(parser, FZL_TOKTYPE_SEMICOLON)) + { + condition = pa_expression(parser); + if (!condition) + { + fzl_freeast(start); + snprintf(plast_err, sizeof(plast_err), + "'%s': expected loop condition or ';' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + + fzl_token_t *sc = consume(parser); + if (!sc || sc->type != FZL_TOKTYPE_SEMICOLON) + { + fzl_freeast(start); + fzl_freeast(condition); + snprintf(plast_err, sizeof(plast_err), + "'%s': missing ';' after condition at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + } + else + consume(parser); + + fzl_node_t *step = NULL; + if (!is(parser, FZL_TOKTYPE_RPAREN)) + { + step = pa_expression(parser); + if (!step) + { + fzl_freeast(start); + fzl_freeast(condition); + snprintf(plast_err, sizeof(plast_err), + "'%s': expected loop step end or ')' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + } + + fzl_token_t *rpar = consume(parser); + if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN) + { + fzl_freeast(start); + fzl_freeast(condition); + fzl_freeast(step); + snprintf(plast_err, sizeof(plast_err), + "'%s': missing ')' after loop setup at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_node_t *body = pa_statement(parser); + if (!body) + { + fzl_freeast(start); + fzl_freeast(condition); + fzl_freeast(step); + snprintf(plast_err, sizeof(plast_err), + "'%s': missing body of for loop 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_LOOP, tok); + node->loop.init = start; + node->loop.cond = condition; + node->loop.step = step; + node->loop.body = body; + + return node; +} diff --git a/src/compiler/parser/pa_function.c b/src/compiler/parser/pa_function.c new file mode 100644 index 0000000..e113e1d --- /dev/null +++ b/src/compiler/parser/pa_function.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +// Functions parsing +fzl_node_t *pa_function(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_token_t *fn = consume(parser); + if (!fn || fn->type != FZL_TOKTYPE_FUNCTION) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected keyword 'fn' at %ld:%ld", last_known_tok->filename, + last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_token_t *name = consume(parser); + if (!name || name->type != FZL_TOKTYPE_NAME) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected function name at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_token_t *lpar = consume(parser); + if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN) + { + snprintf(plast_err, sizeof(plast_err), "'%s': expected '(' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + size_t remainder = 1; + size_t count = 0; + fzl_node_t **args = malloc(remainder * sizeof(fzl_node_t *)); + + while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN)) + { + fzl_node_t *arg = pa_expression(parser); + if (!arg) + return NULL; + + if (remainder <= count) + { + remainder *= 2; + args = realloc(args, remainder * sizeof(fzl_node_t *)); + } + + args[count++] = arg; + + if (is(parser, FZL_TOKTYPE_COMMA)) + consume(parser); + } + + fzl_token_t *rpar = consume(parser); + if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN) + { + free(args); + 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_token_t *type = NULL; + if (is(parser, FZL_TOKTYPE_TYPE) || is(parser, FZL_TOKTYPE_NAME)) + type = consume(parser); + + if (!type) + type = &null_tok; + + if (!is(parser, FZL_TOKTYPE_LBRACE)) + { + free(args); + snprintf(plast_err, sizeof(plast_err), + "'%s': expected '{' after function declaration at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_node_t *body = pa_statement(parser); + if (!body) + { + free(args); + return NULL; + } + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FUNCTION, name); + node->fn.args = args; + node->fn.args_count = count; + node->fn.body = body; + node->fn.name = name; + node->fn.type = type; + + return node; +} diff --git a/src/compiler/parser/pa_if.c b/src/compiler/parser/pa_if.c new file mode 100644 index 0000000..febba53 --- /dev/null +++ b/src/compiler/parser/pa_if.c @@ -0,0 +1,61 @@ +#include +#include +#include + +// Parse if statement +fzl_node_t *pa_if(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_token_t *if_tok = consume(parser); + fzl_token_t *lparen = consume(parser); + if (lparen->type != FZL_TOKTYPE_LPAREN) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected '(' before condition at %ld:%ld", lparen->filename, + lparen->ln, lparen->cn); + return NULL; + } + + fzl_node_t *condition = pa_expression(parser); + if (!condition) + return NULL; + + fzl_token_t *rparen = consume(parser); + if (rparen->type != FZL_TOKTYPE_RPAREN) + { + fzl_freeast(condition); + snprintf(plast_err, sizeof(plast_err), + "'%s': expected ')' after condition at %ld:%ld", rparen->filename, + rparen->ln, rparen->cn); + return NULL; + } + + fzl_node_t *else_block = NULL; + fzl_node_t *true_block = pa_statement(parser); + if (!true_block) + { + fzl_freeast(condition); + return NULL; + } + + if (is(parser, FZL_TOKTYPE_ELSE)) + { + consume(parser); // else + else_block = pa_statement(parser); + if (!else_block) + { + fzl_freeast(condition); + fzl_freeast(true_block); + return NULL; + } + } + + fzl_node_t *stmt_node = fzl_mknode(FZL_NODETYPE_CONDITIONAL, if_tok); + stmt_node->cond.condition = condition; + stmt_node->cond.true_block = true_block; + stmt_node->cond.else_block = else_block; + + return stmt_node; +} diff --git a/src/compiler/parser/pa_loop.c b/src/compiler/parser/pa_loop.c new file mode 100644 index 0000000..0d9698a --- /dev/null +++ b/src/compiler/parser/pa_loop.c @@ -0,0 +1,20 @@ +#include +#include +#include + +// `while` and `for` loops +fzl_node_t *pa_loop(fzl_parser_t *parser) +{ + if (!peek(parser)) + return NULL; + + if (is(parser, FZL_TOKTYPE_FOR)) + return pa_for(parser); + else if (is(parser, FZL_TOKTYPE_WHILE)) + return pa_while(parser); + + snprintf(plast_err, sizeof(plast_err), + "'%s': unknown type of loop at %ld:%ld", last_known_tok->filename, + last_known_tok->ln, last_known_tok->cn); + return NULL; +} diff --git a/src/compiler/parser/pa_new.c b/src/compiler/parser/pa_new.c new file mode 100644 index 0000000..8aa3f3f --- /dev/null +++ b/src/compiler/parser/pa_new.c @@ -0,0 +1,27 @@ +#include +#include +#include + +// Object construct parsing +fzl_node_t *pa_new(fzl_parser_t *parser) +{ + if (!is(parser, FZL_TOKTYPE_NEW)) + return pa_or(parser); + + fzl_token_t *new = consume(parser); + fzl_node_t *objname = pa_or(parser); + if (!objname || (objname->type != FZL_NODETYPE_IDENTIFIER && + objname->type != FZL_NODETYPE_FIELD)) + { + fzl_freeast(objname); + snprintf(plast_err, sizeof(plast_err), + "'%s': expected class name after 'new' keyword 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_CONSTRUCT, new); + node->construct.name = objname; + + return node; +} diff --git a/src/compiler/parser/pa_or.c b/src/compiler/parser/pa_or.c new file mode 100644 index 0000000..fcdc08f --- /dev/null +++ b/src/compiler/parser/pa_or.c @@ -0,0 +1,33 @@ +#include +#include + +// Parse OR (||) +fzl_node_t *pa_or(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_node_t *left = pa_and(parser); + fzl_node_t *right = NULL; + + if (!left) + return NULL; + + while (is(parser, FZL_TOKTYPE_DVBAR)) + { + fzl_token_t * or = consume(parser); + right = pa_and(parser); + if (!right) + { + fzl_freeast(left); + return NULL; + } + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_OR, or); + node->binary_op.left = left; + node->binary_op.right = right; + left = node; + } + + return left; +} diff --git a/src/compiler/parser/pa_postfix.c b/src/compiler/parser/pa_postfix.c new file mode 100644 index 0000000..3edd7aa --- /dev/null +++ b/src/compiler/parser/pa_postfix.c @@ -0,0 +1,98 @@ +#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; +} diff --git a/src/compiler/parser/pa_power.c b/src/compiler/parser/pa_power.c new file mode 100644 index 0000000..4e1d278 --- /dev/null +++ b/src/compiler/parser/pa_power.c @@ -0,0 +1,41 @@ +#include +#include +#include + +// Parse power expression +fzl_node_t *pa_power(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_node_t *left = pa_unary(parser); + fzl_node_t *right = NULL; + + if (!left) + return NULL; + + if (is(parser, FZL_TOKTYPE_CARET)) + { + fzl_token_t *caret = consume(parser); + + right = pa_unary(parser); + if (!right) + { + fzl_freeast(left); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': expected expression 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_POW, caret); + node->binary_op.left = left; + node->binary_op.right = right; + + left = node; + } + + return left; +} diff --git a/src/compiler/parser/pa_primary.c b/src/compiler/parser/pa_primary.c new file mode 100644 index 0000000..d6c068c --- /dev/null +++ b/src/compiler/parser/pa_primary.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include + +// Parse primary +fzl_node_t *pa_primary(fzl_parser_t *parser) +{ + if (!parser || !peek(parser)) + return NULL; + + if (is(parser, FZL_TOKTYPE_STR_LITERAL) || + is(parser, FZL_TOKTYPE_NUM_LITERAL) || + is(parser, FZL_TOKTYPE_BOOL_LITERAL) || + is(parser, FZL_TOKTYPE_NULL_LITERAL)) + { + fzl_token_t *tok = consume(parser); + return fzl_mknode(FZL_NODETYPE_LITERAL, tok); + } + else if (is(parser, FZL_TOKTYPE_STR_FORMAT_START)) + { + consume(parser); + + size_t remainder = 2; + size_t count = 0; + fzl_node_t **entries = malloc(remainder * sizeof(fzl_node_t *)); + if (!entries) + { + snprintf(plast_err, sizeof(plast_err), "out of memory"); + return NULL; + } + + while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_STR_FORMAT_END) + { + if (is(parser, FZL_TOKTYPE_STR_FORMAT_END)) + break; + + if (remainder <= count) + { + remainder *= 2; + fzl_node_t **newentries = + realloc(entries, remainder * sizeof(fzl_node_t *)); + if (!newentries) + { + snprintf(plast_err, sizeof(plast_err), "out of memory"); + for (size_t i = 0; i < count; i++) + fzl_freeast(entries[i]); + + free(entries); + return NULL; + } + + entries = newentries; + } + + fzl_node_t *expr = pa_expression(parser); + if (expr == NULL) + { + for (size_t i = 0; i < count; i++) + fzl_freeast(entries[i]); + + free(entries); + return NULL; + } + + entries[count++] = expr; + } + + fzl_token_t *end = consume(parser); + if (end->type != FZL_TOKTYPE_STR_FORMAT_END) + { + snprintf(plast_err, sizeof(plast_err), + "'%s':%zu:%zu => unterminated format string", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + + for (size_t i = 0; i < count; i++) + fzl_freeast(entries[i]); + + free(entries); + } + + if (count < 1) + { + snprintf(plast_err, sizeof(plast_err), + "'%s':%zu:%zu => do you really need empty format string?", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + + for (size_t i = 0; i < count; i++) + fzl_freeast(entries[i]); + + free(entries); + return NULL; + } + + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FMT_STRING, entries[0]->token); + if (!node) + { + snprintf(plast_err, sizeof(plast_err), "out of memory"); + for (size_t i = 0; i < count; i++) + fzl_freeast(entries[i]); + + free(entries); + return NULL; + } + + node->list.entries = entries; + node->list.entry_count = count; + + return node; + } + else if (is(parser, FZL_TOKTYPE_LPAREN)) + { + consume(parser); + fzl_node_t *node = pa_expression(parser); + if (!is(parser, FZL_TOKTYPE_RPAREN)) + { + snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + fzl_freeast(node); + return NULL; + } + consume(parser); + return node; + } + else if (is(parser, FZL_TOKTYPE_NAME)) + { + fzl_token_t *name = consume(parser); + if (!is(parser, FZL_TOKTYPE_NAME)) + return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); + + fzl_token_t *realname = consume(parser); // :D + fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, name); + decl->var.type = name; + decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, realname); + return decl; + } + else if (is(parser, FZL_TOKTYPE_TYPE)) + { + fzl_token_t *type = consume(parser); + fzl_token_t *name = consume(parser); + if (!name || name->type != FZL_TOKTYPE_NAME) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected name after type at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + + fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, type); + decl->var.type = type; + decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); + return decl; + } + + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': expected expression at %ld:%ld", last_known_tok->filename, + last_known_tok->ln, last_known_tok->cn); + return NULL; +} diff --git a/src/compiler/parser/pa_program.c b/src/compiler/parser/pa_program.c new file mode 100644 index 0000000..c555bea --- /dev/null +++ b/src/compiler/parser/pa_program.c @@ -0,0 +1,42 @@ +#include +#include +#include + +// Internal parsing entry point +fzl_node_t *pa_program(fzl_parser_t *parser) +{ + if (!peek(parser)) + return NULL; + + fzl_node_t *first = NULL; + fzl_node_t *last = NULL; + fzl_node_t *node = NULL; + while (peek(parser) != NULL) + { + node = pa_statement(parser); + if (!node) + { + fzl_freeast(first); + return NULL; + } + + if (!last) + { + first = node; + last = node; + } + else + { + last->next = node; + last = node; + } + } + + if (!first) + { + snprintf(plast_err, sizeof(plast_err), "nothing to parse >:("); + return NULL; + } + + return first; +} diff --git a/src/compiler/parser/pa_return.c b/src/compiler/parser/pa_return.c new file mode 100644 index 0000000..b36001f --- /dev/null +++ b/src/compiler/parser/pa_return.c @@ -0,0 +1,26 @@ +#include +#include + +// Return parsing +fzl_node_t *pa_return(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_token_t *ret = consume(parser); + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_RETURN, ret); + + if (!is(parser, FZL_TOKTYPE_SEMICOLON)) + { + fzl_node_t *retval = pa_expression(parser); + if (!retval) + { + fzl_freeast(node); + return NULL; + } + + node->ret.value = retval; + } + + return node; +} diff --git a/src/compiler/parser/pa_statement.c b/src/compiler/parser/pa_statement.c new file mode 100644 index 0000000..e9915a6 --- /dev/null +++ b/src/compiler/parser/pa_statement.c @@ -0,0 +1,48 @@ +#include +#include +#include + +// Statement parsing +fzl_node_t *pa_statement(fzl_parser_t *parser) +{ + if (!peek(parser)) + return NULL; + + fzl_node_t *res = NULL; + + if (is(parser, FZL_TOKTYPE_CLASS)) + return pa_class(parser); + else if (is(parser, FZL_TOKTYPE_FUNCTION)) + return pa_function(parser); + else if (is(parser, FZL_TOKTYPE_RETURN)) + res = pa_return(parser); + else if (is(parser, FZL_TOKTYPE_IF)) + return pa_if(parser); + else if (is(parser, FZL_TOKTYPE_LBRACE)) + return pa_block(parser); + else if (is(parser, FZL_TOKTYPE_FOR) || is(parser, FZL_TOKTYPE_WHILE)) + return pa_loop(parser); + else if (is(parser, FZL_TOKTYPE_BREAK)) + res = pa_break(parser); + + if (!res) + res = pa_expression(parser); + + if (!res) + { + fzl_freeast(res); + return NULL; + } + + if (!is(parser, FZL_TOKTYPE_SEMICOLON)) + { + fzl_freeast(res); + snprintf(plast_err, sizeof(plast_err), "'%s': missing ';' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + while (is(parser, FZL_TOKTYPE_SEMICOLON)) + consume(parser); + + return res; +} diff --git a/src/compiler/parser/pa_term.c b/src/compiler/parser/pa_term.c new file mode 100644 index 0000000..64fe300 --- /dev/null +++ b/src/compiler/parser/pa_term.c @@ -0,0 +1,40 @@ +#include +#include +#include + +// Parse TERM: addition and subtraction +fzl_node_t *pa_term(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + fzl_node_t *left = pa_factor(parser); + fzl_node_t *right = NULL; + + if (!left) + return NULL; + + while (is(parser, FZL_TOKTYPE_PLUS) || is(parser, FZL_TOKTYPE_MINUS)) + { + fzl_token_t *op = consume(parser); + + right = pa_factor(parser); + if (!right) + { + fzl_freeast(left); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': expected expression at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, + last_known_tok->cn); + return NULL; + } + + fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op); + node->binary_op.left = left; + node->binary_op.right = right; + left = node; + } + + return left; +} diff --git a/src/compiler/parser/pa_unary.c b/src/compiler/parser/pa_unary.c new file mode 100644 index 0000000..6b5e1a0 --- /dev/null +++ b/src/compiler/parser/pa_unary.c @@ -0,0 +1,24 @@ +#include +#include + +// Parse unary operations +fzl_node_t *pa_unary(fzl_parser_t *parser) +{ + if (!parser) + return NULL; + + if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS) && + !is(parser, FZL_TOKTYPE_NOT)) + return pa_postfix(parser); + + fzl_token_t *op = consume(parser); + fzl_node_t *operand = pa_unary(parser); + + if (!operand) + return NULL; + + fzl_node_t *result = fzl_mknode(unary_op_to_type(op->type), op); + result->unary_op.operand = operand; + + return result; +} diff --git a/src/compiler/parser/pa_while.c b/src/compiler/parser/pa_while.c new file mode 100644 index 0000000..c3ac956 --- /dev/null +++ b/src/compiler/parser/pa_while.c @@ -0,0 +1,52 @@ +#include +#include +#include + +// While-loop parsing +fzl_node_t *pa_while(fzl_parser_t *parser) +{ + fzl_token_t *tok = consume(parser); + fzl_token_t *lpar = consume(parser); + if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': missing '(' after while keyword at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_node_t *condition = pa_expression(parser); + if (!condition) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': missing condition for 'while' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_token_t *rpar = consume(parser); + if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN) + { + fzl_freeast(condition); + snprintf(plast_err, sizeof(plast_err), + "'%s': missing ')' after while loop condition at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + + fzl_node_t *body = pa_statement(parser); + if (!body) + { + fzl_freeast(condition); + snprintf(plast_err, sizeof(plast_err), + "'%s': missing while loop body 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_LOOP, tok); + node->loop.cond = condition; + node->loop.body = body; + + return node; +} diff --git a/src/compiler/parser/utility.c b/src/compiler/parser/utility.c new file mode 100644 index 0000000..d9e7653 --- /dev/null +++ b/src/compiler/parser/utility.c @@ -0,0 +1,75 @@ +#include +#include + +// Get token at cursor +fzl_token_t *peek(fzl_parser_t *parser) +{ + if (!parser || !parser->cursor) + return NULL; + + last_known_tok = parser->cursor->token; + return parser->cursor->token; +} + +// Consume token at cursor and move to the next +fzl_token_t *consume(fzl_parser_t *parser) +{ + if (!parser || !parser->cursor || !parser->cursor->token) + return NULL; + + fzl_token_t *tok = parser->cursor->token; + parser->cursor = parser->cursor->next; + return tok; +} + +// Check if current token have the same type as specified +bool is(fzl_parser_t *parser, fzl_toktype_t type) +{ + if (!parser) + return false; + + fzl_token_t *tok = peek(parser); + if (!tok) + return false; + + return tok->type == type; +} + +// Convert arithmetic operator token type to node type +fzl_nodetype_t math_op_to_type(fzl_toktype_t type) +{ + switch (type) + { + case FZL_TOKTYPE_PLUS: + return FZL_NODETYPE_ADD; + case FZL_TOKTYPE_MINUS: + return FZL_NODETYPE_SUB; + case FZL_TOKTYPE_STAR: + return FZL_NODETYPE_MUL; + case FZL_TOKTYPE_SLASH: + return FZL_NODETYPE_DIV; + case FZL_TOKTYPE_CARET: + return FZL_NODETYPE_POW; + case FZL_TOKTYPE_PERCENT: + return FZL_NODETYPE_MOD; + + default: + return 0; + } +} + +fzl_nodetype_t unary_op_to_type(fzl_toktype_t type) +{ + switch (type) + { + case FZL_TOKTYPE_PLUS: + return FZL_NODETYPE_UNARY_PLUS; + case FZL_TOKTYPE_MINUS: + return FZL_NODETYPE_UNARY_MINUS; + case FZL_TOKTYPE_NOT: + return FZL_NODETYPE_NOT; + + default: + return 0; + } +}