aboutsummaryrefslogtreecommitdiff
path: root/cup
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-01-29 13:52:58 -0500
committerMustafa Quraish <[email protected]>2022-01-29 13:53:57 -0500
commite403475bbf6f70b3e79b6f4503dbadcc3dad504c (patch)
tree40c77638cf96048328358e601c541ab31fb2b23a /cup
parentAdd some tests for local variables (diff)
downloadarchived-cup-e403475bbf6f70b3e79b6f4503dbadcc3dad504c.tar.xz
archived-cup-e403475bbf6f70b3e79b6f4503dbadcc3dad504c.zip
Allow uninitialized variable declarations
Diffstat (limited to 'cup')
-rw-r--r--cup/ast.h6
-rw-r--r--cup/generator.c15
-rw-r--r--cup/lexer.c3
-rw-r--r--cup/parser.c36
-rw-r--r--cup/tokens.h3
5 files changed, 51 insertions, 12 deletions
diff --git a/cup/ast.h b/cup/ast.h
index 4b18c82..efbaf84 100644
--- a/cup/ast.h
+++ b/cup/ast.h
@@ -102,12 +102,16 @@ typedef struct ast_node {
};
} literal;
- // FIXME: Different struct for assignment?
struct {
Variable var;
Node *value;
} var_decl;
+ struct {
+ Variable *var;
+ Node *value;
+ } assign;
+
Variable *variable;
};
} Node;
diff --git a/cup/generator.c b/cup/generator.c
index 1575b57..7403fac 100644
--- a/cup/generator.c
+++ b/cup/generator.c
@@ -20,10 +20,15 @@ void generate_expr_into_rax(Node *expr, FILE *out)
fprintf(out, " mov rax, %d\n", expr->literal.as_int);
} else if (expr->type == AST_VAR) {
- i64 offset = expr->variable->offset;
+ i64 offset = expr->variable->offset;
fprintf(out, " mov rax, [rbp-%lld]\n", offset);
- } else if (expr->type == OP_NEG) {
+ } else if (expr->type == OP_ASSIGN) {
+ i64 offset = expr->assign.var->offset;
+ generate_expr_into_rax(expr->assign.value, out);
+ fprintf(out, " mov [rbp-%lld], rax\n", offset);
+
+ } else if (expr->type == OP_NEG) {
generate_expr_into_rax(expr->unary_expr, out);
fprintf(out, " neg rax\n");
@@ -37,7 +42,7 @@ void generate_expr_into_rax(Node *expr, FILE *out)
} else if (expr->type == OP_BWINV) {
generate_expr_into_rax(expr->unary_expr, out);
fprintf(out, " not rax\n");
-
+
} else if (expr->type == OP_PLUS) {
generate_expr_into_rax(expr->binary.right, out);
fprintf(out, " push rax\n");
@@ -183,8 +188,8 @@ void generate_statement(Node *stmt, FILE *out)
fprintf(out, " mov [rbp-%lld], rax\n", offset);
}
} else {
- fprintf(stderr, "Unsupported statement type in generate_statement: %s\n", node_type_to_str(stmt->type));
- exit(1);
+ // Once again, default to an expression here...
+ generate_expr_into_rax(stmt, out);
}
}
diff --git a/cup/lexer.c b/cup/lexer.c
index fcfe005..88df9e0 100644
--- a/cup/lexer.c
+++ b/cup/lexer.c
@@ -162,7 +162,10 @@ Token Lexer_next(Lexer *lexer)
default: {
+ // Handle keywords explicitly
if (Lexer_starts_with(lexer, "fn")) return Lexer_make_token(lexer, TOKEN_FN, 2);
+ if (Lexer_starts_with(lexer, "if")) return Lexer_make_token(lexer, TOKEN_IF, 2);
+ if (Lexer_starts_with(lexer, "else")) return Lexer_make_token(lexer, TOKEN_ELSE, 4);
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);
diff --git a/cup/parser.c b/cup/parser.c
index ecd12f9..a47116b 100644
--- a/cup/parser.c
+++ b/cup/parser.c
@@ -119,9 +119,6 @@ Node *parse_var_declaration(Lexer *lexer)
node->var_decl.var.name = token.value.as_string;
assert_token(Lexer_next(lexer), TOKEN_COLON);
node->var_decl.var.type = parse_type(lexer);
- assert_token(Lexer_next(lexer), TOKEN_ASSIGN);
- node->var_decl.value = parse_expression(lexer);
- assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
// Set offset for variable
node->var_decl.var.offset = current_function->func.cur_stack_offset;
@@ -133,6 +130,14 @@ Node *parse_var_declaration(Lexer *lexer)
current_function->func.num_locals++;
current_function->func.cur_stack_offset += var_size;
+ token = Lexer_next(lexer);
+ if (token.type == TOKEN_ASSIGN) {
+ node->var_decl.value = parse_expression(lexer);
+ assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
+ } else {
+ assert_token(token, TOKEN_SEMICOLON);
+ }
+
return node;
}
@@ -203,7 +208,25 @@ bool is_logical_and_token(TokenType type) { return type == TOKEN_AND; }
Node *parse_logical_and(Lexer *lexer) { BINOP_PARSER(parse_equality, is_logical_and_token); }
bool is_logical_or_token(TokenType type) { return type == TOKEN_OR; }
-Node *parse_expression(Lexer *lexer) { BINOP_PARSER(parse_logical_and, is_logical_or_token); }
+Node *parse_logical_or(Lexer *lexer) { BINOP_PARSER(parse_logical_and, is_logical_or_token); }
+
+Node *parse_expression(Lexer *lexer)
+{
+ Node *node = parse_logical_or(lexer);
+ // FIXME: This is a hack to handle assignment expressions
+ // and can probably be done properly.
+ if (node->type == AST_VAR) {
+ Token token = Lexer_peek(lexer);
+ if (token.type == TOKEN_ASSIGN) {
+ Lexer_next(lexer);
+ Variable *var = node->variable;
+ node->type = OP_ASSIGN;
+ node->assign.var = var;
+ node->assign.value = parse_expression(lexer);
+ }
+ }
+ return node;
+}
Node *parse_statement(Lexer *lexer)
{
@@ -218,8 +241,9 @@ Node *parse_statement(Lexer *lexer)
} 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);
+ // Default to trying to handle it as an expression
+ node = parse_expression(lexer);
+ assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
}
return node;
diff --git a/cup/tokens.h b/cup/tokens.h
index d6c1fdd..84aacec 100644
--- a/cup/tokens.h
+++ b/cup/tokens.h
@@ -11,6 +11,8 @@
F(TOKEN_CLOSE_BRACE, "}") \
F(TOKEN_CLOSE_PAREN, ")") \
F(TOKEN_COLON, ":") \
+ F(TOKEN_COMMA, ",") \
+ F(TOKEN_ELSE, "else") \
F(TOKEN_EOF, "EOF") \
F(TOKEN_EQ, "==") \
F(TOKEN_EXCLAMATION, "!") \
@@ -18,6 +20,7 @@
F(TOKEN_GEQ, ">=") \
F(TOKEN_GT, ">") \
F(TOKEN_IDENTIFIER, "identifier") \
+ F(TOKEN_IF, "if") \
F(TOKEN_INT, "int") \
F(TOKEN_INTLIT, "integer literal") \
F(TOKEN_LEQ, "<=") \