diff --git a/include/common/fzl_opcodes.h b/include/common/fzl_opcodes.h index aab733f..53976d3 100644 --- a/include/common/fzl_opcodes.h +++ b/include/common/fzl_opcodes.h @@ -4,9 +4,18 @@ // Available opcodes typedef enum { - FZL_OPCODE_LOADCONST, // Load const into T (temp) reg - FZL_OPCODE_PUSHARG, // Push argument from T into args stack - FZL_OPCODE_CALL_BUILTIN // Call builtin function + FZL_OPCODE_LOADCONST, // Load const into T (temp) reg + FZL_OPCODE_PUSHARG, // Push argument from T into args stack + FZL_OPCODE_CALL_BUILTIN, // Call builtin function + FZL_OPCODE_PUSHNUM, // Push number into stack + + FZL_OPCODE_ADD, // Sum two numbers in arg strack + FZL_OPCODE_SUB, // Subract two numbers in arg stack + FZL_OPCODE_MUL, // Multiply two numbers in arg stack + FZL_OPCODE_DIV, // Divide two numbers in arg stack + FZL_OPCODE_POW, // Power first number in arg stack by second + FZL_OPCODE_MOD, // Get module of two numbers in arg stack + FZL_OPCODE_NEG, // Negotiate number in arg stack } fzl_opcode_t; #endif // FZL_OPCODES_H diff --git a/include/compiler/fzl_parser.h b/include/compiler/fzl_parser.h index 023ea0d..ce2c31e 100644 --- a/include/compiler/fzl_parser.h +++ b/include/compiler/fzl_parser.h @@ -11,6 +11,17 @@ typedef enum FZL_NODETYPE_BLOCK, FZL_NODETYPE_CALL, FZL_NODETYPE_LITERAL, + FZL_NODETYPE_IDENTIFIER, + + FZL_NODETYPE_ADD, + FZL_NODETYPE_SUB, + FZL_NODETYPE_MUL, + FZL_NODETYPE_DIV, + FZL_NODETYPE_POW, + FZL_NODETYPE_MOD, + + FZL_NODETYPE_UNARY_PLUS, + FZL_NODETYPE_UNARY_MINUS } fzl_nodetype_t; // AST node descriptor @@ -23,11 +34,34 @@ typedef struct fzl_node union { + // Array of nested nodes (for blocks, etc) struct { struct fzl_node **entries; size_t entry_count; } list; + + // Call data + struct + { + struct fzl_node *callee; + + struct fzl_node **args; + size_t args_count; + } call; + + // Binary operations + struct + { + struct fzl_node *left; + struct fzl_node *right; + } binary_op; + + // Unary operations + struct + { + struct fzl_node *operand; + } unary_op; }; } fzl_node_t; diff --git a/include/compiler/fzl_token.h b/include/compiler/fzl_token.h index 3bc5432..1abf141 100644 --- a/include/compiler/fzl_token.h +++ b/include/compiler/fzl_token.h @@ -8,11 +8,22 @@ // Token type typedef enum { - FZL_TOKTYPE_NAME, - FZL_TOKTYPE_LPAIR, - FZL_TOKTYPE_RPAIR, - FZL_TOKTYPE_COMMA, - FZL_TOKTYPE_STR_LITERAL + FZL_TOKTYPE_NAME, // abc + + FZL_TOKTYPE_LPAREN, // ( + FZL_TOKTYPE_RPAREN, // ) + + FZL_TOKTYPE_COMMA, // , + + FZL_TOKTYPE_STR_LITERAL, // "" + FZL_TOKTYPE_NUM_LITERAL, // 123 + + FZL_TOKTYPE_STAR, // * + FZL_TOKTYPE_SLASH, // / + FZL_TOKTYPE_PLUS, // + + FZL_TOKTYPE_MINUS, // - + FZL_TOKTYPE_CARET, // ^ + FZL_TOKTYPE_PERCENT, // % } fzl_toktype_t; // Token descriptor diff --git a/src/compiler/fzl_debug.c b/src/compiler/fzl_debug.c index 8744dac..3e40d63 100644 --- a/src/compiler/fzl_debug.c +++ b/src/compiler/fzl_debug.c @@ -1,3 +1,4 @@ +#include "compiler/fzl_parser.h" #include #include #include @@ -32,12 +33,12 @@ void print_node(fzl_node_t *node, int level) switch (node->type) { case FZL_NODETYPE_CALL: - if (node->list.entry_count > 0) + if (node->call.args_count > 0) { printf("%s Call fn '%s' with args:\n", levelbuf, (char *)node->token->value); - for (size_t i = 0; i < node->list.entry_count; i++) - print_node(node->list.entries[i], level + 1); + for (size_t i = 0; i < node->call.args_count; i++) + print_node(node->call.args[i], level + 1); } else printf("%s Call fn '%s' w/o args\n", levelbuf, @@ -62,6 +63,22 @@ void print_node(fzl_node_t *node, int level) print_node(node->list.entries[i], level + 1); break; + case FZL_NODETYPE_ADD: + case FZL_NODETYPE_SUB: + case FZL_NODETYPE_MUL: + case FZL_NODETYPE_DIV: + case FZL_NODETYPE_POW: + case FZL_NODETYPE_MOD: + printf("%s Binary op (%d)\n", levelbuf, node->type); + printf("-%s LEFT:\n", levelbuf); + print_node(node->binary_op.left, level + 2); + printf("-%s RIGHT:\n", levelbuf); + print_node(node->binary_op.right, level + 2); + break; + + case FZL_NODETYPE_IDENTIFIER: + printf("%s Identifier ('%s')\n", levelbuf, (char *)node->token->value); + break; default: printf("%s Secure node\n", levelbuf); diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 704ac2d..5ba7e26 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -1,5 +1,7 @@ #include "compiler/fzl_token.h" #include +#include +#include #include #include @@ -45,7 +47,7 @@ fzl_node_t *fzl_mknode(fzl_nodetype_t type, fzl_token_t *token) // Get token at cursor static fzl_token_t *peek(fzl_parser_t *parser) { - if (!parser->cursor) + if (!parser || !parser->cursor) return NULL; return parser->cursor->token; } @@ -53,7 +55,7 @@ static fzl_token_t *peek(fzl_parser_t *parser) // Get token at (cursor + 1) static fzl_token_t *next(fzl_parser_t *parser) { - if (!parser->cursor) + if (!parser || !parser->cursor) return NULL; fzl_reader_ll_t *next = parser->cursor->next; @@ -66,105 +68,315 @@ static fzl_token_t *next(fzl_parser_t *parser) // Consume token at cursor and move to the next static fzl_token_t *consume(fzl_parser_t *parser) { - if (!parser->cursor) + if (!parser || !parser->cursor) 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; + + default: + return 0; + } +} + +fzl_node_t *parse_expression(fzl_parser_t *parser); + // Parse primary fzl_node_t *parse_primary(fzl_parser_t *parser) { - if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_STR_LITERAL) + if (!parser || !peek(parser)) + return NULL; + + if (is(parser, FZL_TOKTYPE_STR_LITERAL)) { fzl_token_t *tok = consume(parser); return fzl_mknode(FZL_NODETYPE_LITERAL, tok); } + else if (is(parser, FZL_TOKTYPE_NUM_LITERAL)) + { + fzl_token_t *tok = consume(parser); + return fzl_mknode(FZL_NODETYPE_LITERAL, tok); + } + 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), "expected rparen at %d", + parser->cursor->token->i0); + return NULL; + } + consume(parser); + return node; + } + else if (is(parser, FZL_TOKTYPE_NAME)) + { + fzl_token_t *name = consume(parser); + return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); + } snprintf(plast_err, sizeof(plast_err), "failed to parse primary at %d", peek(parser)->i0); return NULL; } -fzl_node_t *parse_expression(fzl_parser_t *parser, int precedence); - -// Parse call expression -fzl_node_t *parse_call(fzl_parser_t *parser) +// Parse postfix expressions (parens, index access, dots) +fzl_node_t *parse_postfix(fzl_parser_t *parser) { - fzl_token_t *tok = consume(parser); // - if (tok->type != FZL_TOKTYPE_NAME) + if (!parser) return NULL; - fzl_token_t *lpair = consume(parser); // ( - if (lpair->type != FZL_TOKTYPE_LPAIR) + fzl_node_t *left = parse_primary(parser); + fzl_node_t *right = NULL; + + if (!left) + { + snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %d", + peek(parser)->i0); return NULL; + } - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, tok); - node->list.entry_count = 0; - - size_t capacity = 4; - node->list.entries = malloc(capacity * sizeof(fzl_node_t *)); - node->list.entry_count = 0; - - if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_RPAIR) + while (is(parser, FZL_TOKTYPE_LPAREN)) { consume(parser); - return node; - } - while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_RPAIR) - { - fzl_node_t *arg = parse_expression(parser, 0); - if (!arg) - return NULL; + size_t args_capacity = 2; + size_t args_count = 0; + fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *)); - if (node->list.entry_count == capacity) + while (!is(parser, FZL_TOKTYPE_RPAREN)) { - capacity *= 2; - node->list.entries = - realloc(node->list.entries, capacity * sizeof(fzl_node_t *)); + fzl_node_t *arg = parse_expression(parser); + if (!arg) + { + free(args); + 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); } - node->list.entries[node->list.entry_count++] = arg; - - if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_COMMA) - consume(parser); - else if (peek(parser) && peek(parser)->type != FZL_TOKTYPE_RPAIR) + fzl_token_t *rparen = consume(parser); + if (!rparen || rparen->type != FZL_TOKTYPE_RPAREN) { + free(args); snprintf(plast_err, sizeof(plast_err), - "expected ',' or ')' after arg list"); + "expected ')' after argument list at %d", peek(parser)->i0); 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; } - fzl_token_t *rpair = consume(parser); - if (rpair->type != FZL_TOKTYPE_RPAIR) + return left; +} + +// Parse unary operations +fzl_node_t *parse_unary(fzl_parser_t *parser) +{ + if (!parser) return NULL; - return node; + if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS)) + 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) + { + snprintf(plast_err, sizeof(plast_err), "failed to parse power at %d", + peek(parser)->i0); + return NULL; + } + + if (is(parser, FZL_TOKTYPE_CARET)) + { + fzl_token_t *caret = consume(parser); + + right = parse_unary(parser); + if (!right) + { + snprintf(plast_err, sizeof(plast_err), + "failed to parse right side of power at %d", peek(parser)->i0); + 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) + { + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), "invalid expression at %u", + parser->cursor->token->i0); + 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) + { + snprintf(plast_err, sizeof(plast_err), + "unfinished factor (mul/div) expression at %u", left->token->i0); + 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) + { + snprintf(plast_err, sizeof(plast_err), "invalid expression at %u", + parser->cursor->token->i0); + 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) + { + snprintf(plast_err, sizeof(plast_err), + "unfinished term (add/sub) expression at %u", left->token->i0); + 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; } // Expression parsing -fzl_node_t *parse_expression(fzl_parser_t *parser, int precedence) +fzl_node_t *parse_expression(fzl_parser_t *parser) { - if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_NAME) - { - if (next(parser) && next(parser)->type == FZL_TOKTYPE_LPAIR) - return parse_call(parser); - } - else if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_STR_LITERAL) - return parse_primary(parser); - - snprintf(plast_err, sizeof(plast_err), "failed to parse expression at %d", - peek(parser)->i0); - return NULL; + return parse_term(parser); } // Statement parsing fzl_node_t *parse_statement(fzl_parser_t *parser) { - return parse_expression(parser, 0); + return parse_expression(parser); } // Internal parsing entry point @@ -229,7 +441,7 @@ void fzl_freeast(fzl_node_t *root) while (root) { - if (root->type == FZL_NODETYPE_BLOCK || root->type == FZL_NODETYPE_CALL) + if (root->type == FZL_NODETYPE_BLOCK) { if (root->list.entries) { @@ -240,6 +452,32 @@ void fzl_freeast(fzl_node_t *root) free(root->list.entries); } } + else if (root->type == FZL_NODETYPE_CALL) + { + if (root->call.args_count) + { + for (size_t i = 0; i < root->call.args_count; i++) + if (root->call.args[i]) + fzl_freeast(root->call.args[i]); + + free(root->call.args); + } + } + else if (root->type == FZL_NODETYPE_ADD || root->type == FZL_NODETYPE_SUB || + root->type == FZL_NODETYPE_MUL || root->type == FZL_NODETYPE_DIV || + root->type == FZL_NODETYPE_POW || root->type == FZL_NODETYPE_MOD) + { + if (root->binary_op.left) + fzl_freeast(root->binary_op.left); + if (root->binary_op.right) + fzl_freeast(root->binary_op.right); + } + else if (root->type == FZL_NODETYPE_UNARY_PLUS || + root->type == FZL_NODETYPE_UNARY_MINUS) + { + if (root->unary_op.operand) + fzl_freeast(root->unary_op.operand); + } fzl_freenode(root); root = root->next; diff --git a/src/compiler/fzl_reader.c b/src/compiler/fzl_reader.c index a4c3dcb..35c6c1e 100644 --- a/src/compiler/fzl_reader.c +++ b/src/compiler/fzl_reader.c @@ -1,5 +1,7 @@ +#include "compiler/fzl_token.h" #include #include +#include #include #include #include @@ -97,6 +99,44 @@ fzl_token_t *parse_string_literal(fzl_reader_t *reader) return tok; } +// Parse numeric literal +fzl_token_t *parse_number(fzl_reader_t *reader) +{ + if (!reader) + return NULL; + + size_t size = 0; + size_t lpos = reader->position; + + do + { + size++; + lpos++; + } while ((reader->source[lpos] >= '0' && reader->source[lpos] <= '9') && + lpos < reader->size); + + char *value = malloc(size * sizeof(char) + 1); + memcpy(value, reader->source + reader->position, size); + value[size] = '\0'; + + fzl_token_t *tok = + fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, reader->position, lpos, value, size); + free(value); + + if (!tok) + return NULL; + + reader->position += size; + return tok; +} + +// Add single-char token +fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type) +{ + size_t p = reader->position++; + return fzl_mktoken(type, p, p, NULL, 0); +} + int fzl_read(fzl_reader_t *reader) { if (reader->position >= reader->size) @@ -117,17 +157,27 @@ int fzl_read(fzl_reader_t *reader) if (curr == '\'' || curr == '"') token = parse_string_literal(reader); else if (curr == '(') - { - token = fzl_mktoken(FZL_TOKTYPE_LPAIR, p, p, NULL, 0); - reader->position++; - } + token = add_single(reader, FZL_TOKTYPE_LPAREN); else if (curr == ')') - { - token = fzl_mktoken(FZL_TOKTYPE_RPAIR, p, p, NULL, 0); - reader->position++; - } + token = add_single(reader, FZL_TOKTYPE_RPAREN); + else if (curr == ',') + token = add_single(reader, FZL_TOKTYPE_COMMA); + else if (curr == '*') + token = add_single(reader, FZL_TOKTYPE_STAR); + else if (curr == '/') + token = add_single(reader, FZL_TOKTYPE_SLASH); + else if (curr == '+') + token = add_single(reader, FZL_TOKTYPE_PLUS); + else if (curr == '-') + token = add_single(reader, FZL_TOKTYPE_MINUS); + else if (curr == '^') + token = add_single(reader, FZL_TOKTYPE_CARET); + else if (curr == '%') + token = add_single(reader, FZL_TOKTYPE_PERCENT); else if (curr >= 'A' && curr <= 'Z' || curr >= 'a' && curr <= 'z') token = parse_name(reader); + else if (curr >= '0' && curr <= '9') + token = parse_number(reader); else { sprintf(last_err, "undefined token '%c'", curr); diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index e4b3112..f26726b 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -108,9 +109,9 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node) case FZL_NODETYPE_CALL: if (node->list.entry_count > 0) { - for (size_t i = 0; i < node->list.entry_count; i++) + for (size_t i = 0; i < node->call.args_count; i++) { - if (!walk(walker, node->list.entries[i])) + if (!walk(walker, node->call.args[i])) return false; push_op(walker, FZL_OPCODE_PUSHARG); } @@ -129,13 +130,70 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node) break; case FZL_NODETYPE_LITERAL: - size_t n = add_const( - walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING, - .as.string.chars = node->token->value, - .as.string.length = node->token->value_sz}); + if (node->token->type == FZL_TOKTYPE_STR_LITERAL) + { + size_t n = add_const( + walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING, + .as.string.chars = node->token->value, + .as.string.length = node->token->value_sz}); - push_op(walker, FZL_OPCODE_LOADCONST); - push_word(walker, n); + push_op(walker, FZL_OPCODE_LOADCONST); + push_word(walker, n); + } + else if (node->token->type == FZL_TOKTYPE_NUM_LITERAL) + { + push_op(walker, FZL_OPCODE_PUSHNUM); + + uint64_t num = strtol(node->token->value, NULL, 10); + push_word(walker, num); + } + break; + + case FZL_NODETYPE_ADD: + case FZL_NODETYPE_SUB: + case FZL_NODETYPE_MUL: + case FZL_NODETYPE_DIV: + case FZL_NODETYPE_POW: + case FZL_NODETYPE_MOD: + if (!walk(walker, node->binary_op.left)) + return false; + push_op(walker, FZL_OPCODE_PUSHARG); + + if (!walk(walker, node->binary_op.right)) + return false; + push_op(walker, FZL_OPCODE_PUSHARG); + + switch (node->type) + { + case FZL_NODETYPE_ADD: + push_op(walker, FZL_OPCODE_ADD); + break; + case FZL_NODETYPE_SUB: + push_op(walker, FZL_OPCODE_SUB); + break; + case FZL_NODETYPE_MUL: + push_op(walker, FZL_OPCODE_MUL); + break; + case FZL_NODETYPE_DIV: + push_op(walker, FZL_OPCODE_DIV); + break; + case FZL_NODETYPE_POW: + push_op(walker, FZL_OPCODE_POW); + break; + case FZL_NODETYPE_MOD: + push_op(walker, FZL_OPCODE_MOD); + break; + + default: + return false; + } + break; + + case FZL_NODETYPE_UNARY_MINUS: + if (!walk(walker, node->unary_op.operand)) + return false; + + push_op(walker, FZL_OPCODE_NEG); break; } diff --git a/src/compiler/main.c b/src/compiler/main.c index 612cda5..e96d586 100644 --- a/src/compiler/main.c +++ b/src/compiler/main.c @@ -193,8 +193,14 @@ int main(int argc, char **argv) printf("---> %s\n", walker->consts->array[i].as.string.chars); printf("--> Ops:\n"); + printf("---> "); for (size_t i = 0; i < walker->op_count; i++) - printf("---> %lu\n", walker->ops[i]); + { + if (i > 0 && i < walker->op_count) + printf("->"); + printf("%lu", walker->ops[i]); + } + printf("\n"); printf("-> preparing final write\n"); } @@ -207,7 +213,7 @@ int main(int argc, char **argv) if (args->verbose) { - printf("-> output file path is: %s", outpath); + printf("-> output file path is: %s\n", outpath); printf("-> writing file..."); }