diff options
| author | Mustafa Quraish <[email protected]> | 2022-01-29 11:18:53 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-01-29 11:30:43 -0500 |
| commit | ac5681a0873a6ba64e844664eaf785f1610ef906 (patch) | |
| tree | 8b761b87201ea8c77720aeb5cb3ae6dc92bf3ea2 | |
| parent | Add relational and logical operators + refactor binop parser (diff) | |
| download | cup-ac5681a0873a6ba64e844664eaf785f1610ef906.tar.xz cup-ac5681a0873a6ba64e844664eaf785f1610ef906.zip | |
Add parsing + storing offsets for locals / move around headers
| -rw-r--r-- | cup/ast.c | 54 | ||||
| -rw-r--r-- | cup/ast.h | 25 | ||||
| -rw-r--r-- | cup/generator.c | 2 | ||||
| -rw-r--r-- | cup/lexer.c | 1 | ||||
| -rw-r--r-- | cup/parser.c | 41 | ||||
| -rw-r--r-- | cup/tokens.h | 6 | ||||
| -rw-r--r-- | cup/utils.c | 4 | ||||
| -rw-r--r-- | cup/utils.h | 5 |
8 files changed, 114 insertions, 24 deletions
@@ -12,6 +12,15 @@ char *data_type_to_str(DataType type) } } +void print_type_to_file(FILE *out, Type type) +{ + fprintf(out, "%s", data_type_to_str(type.type)); + for (int i = 0; i < type.indirection; i++) + { + fprintf(out, "*"); + } +} + char *node_type_to_str(NodeType type) { switch (type) @@ -67,6 +76,8 @@ bool is_expression(NodeType type) return type == AST_LITERAL; } +void dump_func(Node *, int); + static void do_print_ast(Node *node, int depth) { for (int i = 0; i < depth; i++) { @@ -86,18 +97,7 @@ static void do_print_ast(Node *node, int depth) } printf("}\n"); } else if (node->type == AST_FUNC) { - printf("fn %s()", node->func.name); - if (node->func.return_type.type != TYPE_NONE) { - // FIXME: Print return type properly - Type t = node->func.return_type; - printf(" -> %s", data_type_to_str(t.type)); - for (int i = 0; i < t.indirection; i++) { - printf("*"); - } - - } - printf("\n"); - do_print_ast(node->func.body, depth + 1); + dump_func(node, depth); } else if (node->type == AST_LITERAL) { printf("(literal %d)\n", node->literal.as_int); } else if (node->type == AST_RETURN) { @@ -110,11 +110,39 @@ static void do_print_ast(Node *node, int depth) printf("%s\n", node_type_to_str(node->type)); do_print_ast(node->binary.left, depth + 1); do_print_ast(node->binary.right, depth + 1); + } else if (node->type == AST_VARDECL) { + printf("var %s (", node->var.name); + print_type_to_file(stdout, node->var.type); + printf(")"); + if (node->var.value != NULL) { + printf(" = \n"); + do_print_ast(node->var.value, depth + 1); + } else { + printf("\n"); + } } else { - printf("Don't know how to handle: `%s`\n", node_type_to_str(node->type)); + printf("{{ %s }}\n", node_type_to_str(node->type)); } } +void dump_func(Node *node, int depth) +{ + printf("fn %s()", node->func.name); + if (node->func.return_type.type != TYPE_NONE) { + // FIXME: Print return type properly + printf(" -> "); + print_type_to_file(stdout, node->func.return_type); + } + if (node->func.num_locals > 0) { + printf("\n locals: \n"); + for (int i = 0; i < node->func.num_locals; i++) { + printf(" - `%s`, offset: %lld (", node->func.locals[i].name, node->func.locals[i].offset); + print_type_to_file(stdout, node->func.locals[i].type); + printf(")\n"); + } + } + do_print_ast(node->func.body, depth + 1); +} void print_ast(Node *node) { @@ -1,6 +1,6 @@ #pragma once -#include <stdbool.h> +#include "common.h" #define ENUM_AST_TYPES(F) \ F(OP_NEG, "neg") \ @@ -22,7 +22,9 @@ F(OP_LEQ, "<=") \ F(OP_GT, ">") \ F(OP_GEQ, ">=") \ + F(OP_ASSIGN, "=") \ F(AST_LITERAL, "literal") \ + F(AST_VARDECL, "variable decl") \ F(AST_RETURN, "return") \ F(AST_FUNC, "func") \ F(AST_PROGRAM, "program") \ @@ -53,6 +55,12 @@ typedef struct { int indirection; } Type; +typedef struct { + char *name; + Type type; + i64 offset; +} Variable; + typedef struct ast_node Node; typedef struct ast_node { NodeType type; @@ -63,26 +71,41 @@ typedef struct ast_node { Node *left; Node *right; } binary; + // Unary expr Node *unary_expr; + // Function definition struct { char *name; Type return_type; Node *body; + + Variable *locals; + int num_locals; + + int cur_stack_offset; // TODO: Arguments / etc? } func; + // Block of statements struct { Node **children; int num_children; } block; + struct { Type type; union { int as_int; }; } literal; + + struct { + char *name; + Type type; + Node *value; + } var; }; } Node; diff --git a/cup/generator.c b/cup/generator.c index 7bddac3..c0889cc 100644 --- a/cup/generator.c +++ b/cup/generator.c @@ -144,7 +144,7 @@ void generate_expr_into_rax(Node *expr, FILE *out) } else if (expr->type == OP_AND) { generate_expr_into_rax(expr->binary.left, out); - // If left is true, we can short-circuit + // If left is false, we can short-circuit fprintf(out, " cmp rax, 0\n"); fprintf(out, " jne .and_right_%d\n", label_counter); fprintf(out, " mov rax, 0\n"); diff --git a/cup/lexer.c b/cup/lexer.c index 3b9e070..3398599 100644 --- a/cup/lexer.c +++ b/cup/lexer.c @@ -165,6 +165,7 @@ Token Lexer_next(Lexer *lexer) if (Lexer_starts_with(lexer, "fn")) return Lexer_make_token(lexer, TOKEN_FN, 2); if (Lexer_starts_with(lexer, "return")) return Lexer_make_token(lexer, TOKEN_RETURN, 6); if (Lexer_starts_with(lexer, "int")) return Lexer_make_token(lexer, TOKEN_INT, 3); + if (Lexer_starts_with(lexer, "let")) return Lexer_make_token(lexer, TOKEN_LET, 3); if (isdigit(lexer->src[lexer->pos])) { // TODO: Parse hex and octal numbers diff --git a/cup/parser.c b/cup/parser.c index 68bd22d..8c0c29c 100644 --- a/cup/parser.c +++ b/cup/parser.c @@ -3,6 +3,8 @@ #include <stdlib.h> #include <assert.h> +static Node *current_function = NULL; + Token do_assert_token(Token token, TokenType type, char *filename, int line) { if (token.type != type) { @@ -92,6 +94,35 @@ Node *parse_literal(Lexer *lexer) Node *parse_expression(Lexer *); +Node *parse_var_declaration(Lexer *lexer) +{ + Token token = assert_token(Lexer_next(lexer), TOKEN_LET); + Node *node = Node_new(AST_VARDECL); + node->var.name = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER).value.as_string; + assert_token(Lexer_next(lexer), TOKEN_COLON); + node->var.type = parse_type(lexer); + assert_token(Lexer_next(lexer), TOKEN_ASSIGN); + node->var.value = parse_expression(lexer); + assert_token(Lexer_next(lexer), TOKEN_SEMICOLON); + + // Add variable to current function + if (!current_function || current_function->type != AST_FUNC) + die_location(token.loc, "Variable declaration outside of function"); + + int new_len = (current_function->func.num_locals + 1); + int var_size = 8; // TODO: Compute sizes based on different types + current_function->func.locals = realloc(current_function->func.locals, sizeof(Variable) * new_len); + current_function->func.locals[current_function->func.num_locals] = (Variable) { + .name = node->var.name, + .type = node->var.type, + .offset = current_function->func.cur_stack_offset, + }; + current_function->func.num_locals++; + current_function->func.cur_stack_offset += var_size; + + return node; +} + Node *parse_factor(Lexer *lexer) { // TODO: Parse more complicated things @@ -116,7 +147,7 @@ Node *parse_factor(Lexer *lexer) } else if (token.type == TOKEN_INTLIT) { expr = parse_literal(lexer); } else { - die_location(token.loc, "Expected token found in parse_factor: `%s`", token_type_to_str(token.type)); + die_location(token.loc, ": Expected token found in parse_factor: `%s`", token_type_to_str(token.type)); exit(1); } return expr; @@ -164,6 +195,8 @@ Node *parse_statement(Lexer *lexer) node = Node_new(AST_RETURN); node->unary_expr = parse_expression(lexer); assert_token(Lexer_next(lexer), TOKEN_SEMICOLON); + } else if (token.type == TOKEN_LET) { + return parse_var_declaration(lexer); } else { die_location(token.loc, ": Unexpected token in parse_statement: %s\n", token_type_to_str(token.type)); exit(1); @@ -187,10 +220,12 @@ Node *parse_block(Lexer *lexer) Node *parse_func(Lexer *lexer) { - Node *func = Node_new(AST_FUNC); Token token; - token = assert_token(Lexer_next(lexer), TOKEN_FN); + + Node *func = Node_new(AST_FUNC); + current_function = func; + token = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER); func->func.name = token.value.as_string; diff --git a/cup/tokens.h b/cup/tokens.h index d8b5070..d6c1fdd 100644 --- a/cup/tokens.h +++ b/cup/tokens.h @@ -1,11 +1,8 @@ #pragma once -#include <stdbool.h> -#include <stdint.h> +#include "common.h" #include <stdio.h> -typedef int64_t i64; - #define ENUM_TOKENS(F) \ F(TOKEN_AMPERSAND, "&") \ F(TOKEN_AND, "&&") \ @@ -25,6 +22,7 @@ typedef int64_t i64; F(TOKEN_INTLIT, "integer literal") \ F(TOKEN_LEQ, "<=") \ F(TOKEN_LSHIFT, "<<") \ + F(TOKEN_LET, "let") \ F(TOKEN_LT, "<") \ F(TOKEN_MINUS, "-") \ F(TOKEN_MINUSEQUALS, "-=") \ diff --git a/cup/utils.c b/cup/utils.c index 3a586cd..c38b191 100644 --- a/cup/utils.c +++ b/cup/utils.c @@ -13,12 +13,14 @@ void die(const char *fmt, ...) exit(1); } -void die_location(Location loc, const char *fmt, ...) +void _die_location(char *file, int line, Location loc, const char *fmt, ...) { Location_print(stderr, loc); va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); + fprintf(stderr, "\n"); + fprintf(stderr, "NOTE: Error occurred in %s:%d\n", file, line); exit(1); }
\ No newline at end of file diff --git a/cup/utils.h b/cup/utils.h index df6f56a..ae81f8d 100644 --- a/cup/utils.h +++ b/cup/utils.h @@ -1,6 +1,9 @@ #pragma once +#include "common.h" #include "tokens.h" void die(const char *fmt, ...); -void die_location(Location loc, const char *fmt, ...);
\ No newline at end of file +void _die_location(char *file, int line, Location loc, const char *fmt, ...); + +#define die_location(loc, ...) _die_location(__FILE__, __LINE__, loc, __VA_ARGS__)
\ No newline at end of file |