aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-01-29 11:18:53 -0500
committerMustafa Quraish <[email protected]>2022-01-29 11:30:43 -0500
commitac5681a0873a6ba64e844664eaf785f1610ef906 (patch)
tree8b761b87201ea8c77720aeb5cb3ae6dc92bf3ea2
parentAdd relational and logical operators + refactor binop parser (diff)
downloadcup-ac5681a0873a6ba64e844664eaf785f1610ef906.tar.xz
cup-ac5681a0873a6ba64e844664eaf785f1610ef906.zip
Add parsing + storing offsets for locals / move around headers
-rw-r--r--cup/ast.c54
-rw-r--r--cup/ast.h25
-rw-r--r--cup/generator.c2
-rw-r--r--cup/lexer.c1
-rw-r--r--cup/parser.c41
-rw-r--r--cup/tokens.h6
-rw-r--r--cup/utils.c4
-rw-r--r--cup/utils.h5
8 files changed, 114 insertions, 24 deletions
diff --git a/cup/ast.c b/cup/ast.c
index 3565274..f9b24d1 100644
--- a/cup/ast.c
+++ b/cup/ast.c
@@ -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)
{
diff --git a/cup/ast.h b/cup/ast.h
index 6e05257..c4e9836 100644
--- a/cup/ast.h
+++ b/cup/ast.h
@@ -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