aboutsummaryrefslogtreecommitdiff
path: root/cup/parser.c
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-01-29 12:30:40 -0500
committerMustafa Quraish <[email protected]>2022-01-29 12:30:40 -0500
commit9bf1055b110c838846898652b1a0cbb667ec1db6 (patch)
tree9230588b34c9ac20f2e3216b1e68de7b9e0d1239 /cup/parser.c
parentRestore line/col count in Lexer_peek to get correct locations (diff)
downloadarchived-cup-9bf1055b110c838846898652b1a0cbb667ec1db6.tar.xz
archived-cup-9bf1055b110c838846898652b1a0cbb667ec1db6.zip
Now supporting local variables! :^)
Diffstat (limited to 'cup/parser.c')
-rw-r--r--cup/parser.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/cup/parser.c b/cup/parser.c
index 8c0c29c..ecd12f9 100644
--- a/cup/parser.c
+++ b/cup/parser.c
@@ -1,6 +1,7 @@
#include "parser.h"
#include "utils.h"
#include <stdlib.h>
+#include <string.h>
#include <assert.h>
static Node *current_function = NULL;
@@ -47,7 +48,16 @@ NodeType binary_token_to_op(TokenType type)
}
}
-
+Variable *find_local_variable(Token *token)
+{
+ assert_token(*token, TOKEN_IDENTIFIER);
+ for (int i = 0; i < current_function->func.num_locals; i++) {
+ if (strcmp(current_function->func.locals[i]->name, token->value.as_string) == 0) {
+ return current_function->func.locals[i];
+ }
+ }
+ return NULL;
+}
void Node_add_child(Node *parent, Node *child)
{
@@ -97,26 +107,29 @@ Node *parse_expression(Lexer *);
Node *parse_var_declaration(Lexer *lexer)
{
Token token = assert_token(Lexer_next(lexer), TOKEN_LET);
+ // TODO: Reuse this for globals? Or maybe just make a new function?
+ if (!current_function || current_function->type != AST_FUNC)
+ die_location(token.loc, "Variable declaration outside of function");
+
+ token = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER);
+ if (find_local_variable(&token) != NULL)
+ die_location(token.loc, "Variable `%s` already declared", token.value.as_string);
+
Node *node = Node_new(AST_VARDECL);
- node->var.name = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER).value.as_string;
+ node->var_decl.var.name = token.value.as_string;
assert_token(Lexer_next(lexer), TOKEN_COLON);
- node->var.type = parse_type(lexer);
+ node->var_decl.var.type = parse_type(lexer);
assert_token(Lexer_next(lexer), TOKEN_ASSIGN);
- node->var.value = parse_expression(lexer);
+ node->var_decl.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");
+ // Set offset for variable
+ node->var_decl.var.offset = current_function->func.cur_stack_offset;
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.locals = realloc(current_function->func.locals, sizeof(Variable *) * new_len);
+ current_function->func.locals[current_function->func.num_locals] = &node->var_decl.var;
current_function->func.num_locals++;
current_function->func.cur_stack_offset += var_size;
@@ -146,6 +159,13 @@ Node *parse_factor(Lexer *lexer)
assert_token(Lexer_next(lexer), TOKEN_CLOSE_PAREN);
} else if (token.type == TOKEN_INTLIT) {
expr = parse_literal(lexer);
+ } else if (token.type == TOKEN_IDENTIFIER) {
+ Lexer_next(lexer);
+ Variable *var = find_local_variable(&token);
+ if (var == NULL)
+ die_location(token.loc, "Could not find variable `%s`", token.value.as_string);
+ expr = Node_new(AST_VAR);
+ expr->variable = var;
} else {
die_location(token.loc, ": Expected token found in parse_factor: `%s`", token_type_to_str(token.type));
exit(1);