aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-06 01:18:39 -0500
committerMustafa Quraish <[email protected]>2022-02-06 01:18:39 -0500
commit108a59b91ca6263054ed0bf905df405f5f8bd3fb (patch)
tree35f4d55ba05b063977242ecc4bd7feaed216cfb0 /compiler
parent[cup] Add support for global (initialized) variables (diff)
downloadcup-108a59b91ca6263054ed0bf905df405f5f8bd3fb.tar.xz
cup-108a59b91ca6263054ed0bf905df405f5f8bd3fb.zip
[cup] Flesh out some more boilerplate based on C implementation
No feature has really been fully added here, just fleshing out some more of the global variables / functions / conditions here so it's easier to implement them later on
Diffstat (limited to 'compiler')
-rw-r--r--compiler/parser.cup144
-rw-r--r--compiler/tokens.cup3
2 files changed, 145 insertions, 2 deletions
diff --git a/compiler/parser.cup b/compiler/parser.cup
index ffd8d8a..9093f84 100644
--- a/compiler/parser.cup
+++ b/compiler/parser.cup
@@ -11,6 +11,10 @@ let p_cur_stack_offset = 0;
let p_global_variables = vector_new();
let p_global_offset = 0;
+let p_lexer_stack = vector_new();
+let p_constant_stack = vector_new();
+let p_compound_type_stack = vector_new();
+
fn block_stack_push(block: Node*) {
vector_push(p_block_stack, block);
}
@@ -20,6 +24,13 @@ fn block_stack_pop() {
p_cur_stack_offset = p_cur_stack_offset - block.d.block.locals_size;
}
+fn constant_push(name: char*, value: int) {
+ let node = node_new(AST_CONSTANT);
+ node.d.constant.name = name;
+ node.d.constant.value = node_from_int_literal(value);
+ vector_push(p_constant_stack, node);
+}
+
fn find_local_variable(token: Token*): Variable* {
if (p_current_function == null) return null;
@@ -44,6 +55,16 @@ fn find_local_variable(token: Token*): Variable* {
return null;
}
+fn find_compound_type(token: Token*): Type* {
+ for (let i = p_compound_type_stack.size - 1; i >= 0; --i) {
+ let typ: Type* = p_compound_type_stack.data[i];
+ if (streq(token.value.as_string, typ.struct_name)) {
+ return typ;
+ }
+ }
+ return null;
+}
+
fn find_global_variable(token: Token*): Variable* {
for (let i = 0; i < p_global_variables.size; ++i) {
let var: Variable* = p_global_variables.data[i];
@@ -64,14 +85,60 @@ fn find_function_definition(token: Token*): Node* {
return null;
}
+fn find_constant(token: Token*): Node* {
+ for (let i = 0; i < p_constant_stack.size; ++i) {
+ let constant: Node* = p_constant_stack.data[i];
+ if (streq(token.value.as_string, constant.d.constant.name)) {
+ return constant;
+ }
+ }
+ return null;
+}
+
fn identifier_exists(token: Token*): int {
if (find_local_variable(token)) return true;
if (find_global_variable(token)) return true;
if (find_function_definition(token)) return true;
if (find_builtin_function(token)) return true;
+ if (find_compound_type(token)) return true;
+ if (find_constant(token)) return true;
return false;
}
+fn eval_constexp(node: Node*): int {
+ if (node.typ == AST_LITERAL) {
+ if (node.etyp.typ != TYPE_INT)
+ die("Constant expressions can only contain integer literals/constants.");
+ return node.d.literal.as_int;
+ } else if (is_binary_op(node.typ)) {
+ let left = eval_constexp(node.d.binary.lhs);
+ let right = eval_constexp(node.d.binary.rhs);
+ if (node.typ == AST_PLUS) return left + right;
+ else if (node.typ == AST_MINUS) return left - right;
+ else if (node.typ == AST_BWOR) return left | right;
+ else if (node.typ == AST_BWAND) return left & right;
+ else if (node.typ == AST_XOR) return left ^ right;
+ else if (node.typ == AST_MUL) return left * right;
+ else if (node.typ == AST_DIV) return left / right;
+ else if (node.typ == AST_MOD) return left % right;
+ else if (node.typ == AST_MUL) return left * right;
+ else if (node.typ == AST_MUL) return left * right;
+ else {
+ die("Unsupported binary operator in constant expression.");
+ }
+ }
+ else if (node.typ == AST_NEG) return -eval_constexp(node.d.unary);
+ else if (node.typ == AST_BWINV) return ~eval_constexp(node.d.unary);
+ else if (node.typ == AST_NOT) return !eval_constexp(node.d.unary);
+ else {
+ die("Unsupported constant expression.");
+ }
+ return 0;
+}
+
+fn parse_constant_declaration(lexer: Lexer*): Node* {
+ die("parse_constant_declaration is not implemented yet.");
+}
fn parse_literal(lexer: Lexer*): Node* {
let token: Token;
@@ -106,6 +173,11 @@ fn parse_type(lexer: Lexer*): Type* {
} else if (token.typ == TOKEN_VOID) {
lexer_next(lexer, &token);
typ = type_new(TYPE_VOID);
+ } else {
+ lexer_next_assert(lexer, &token, TOKEN_IDENTIFIER);
+ typ = find_compound_type(&token);
+ if (!typ)
+ die_loc2(&token.loc, "Unknown token in parse_type: ", token.value.as_string);
}
let running = true;
@@ -117,7 +189,26 @@ fn parse_type(lexer: Lexer*): Type* {
ptr.ptr = typ;
typ = ptr;
} else if (token.typ == TOKEN_OPEN_BRACKET) {
- die("Array types not yet implemented");
+ lexer_next(lexer, &token);
+ let arr = type_new(TYPE_ARRAY);
+ arr.ptr = typ;
+
+ lexer_next(lexer, &token);
+ if (token.typ == TOKEN_INTLIT) {
+ arr.array_size = token.value.as_int;
+ } else if (token.typ == TOKEN_IDENTIFIER) {
+ let constant = find_constant(&token);
+ if (!constant)
+ die_loc2(&token.loc, "Could not find constant: ", token.value.as_string);
+ // FIXME: This is a complete mess.
+ let value = constant.d.constant.value;
+ arr.array_size = value.d.literal.as_int;
+ } else {
+ die_loc(&token.loc, "Expected a constant expression for array size");
+ }
+ lexer_next_assert(lexer, &token, TOKEN_CLOSE_BRACKET);
+ typ = arr;
+
} else {
running = false;
}
@@ -188,7 +279,14 @@ fn parse_identifier(lexer: Lexer*): Node* {
return parse_function_call_args(lexer, func);
}
+ let constant = find_constant(&token);
+ if (constant != null) {
+ // TODO: Make sure this is an integer
+ return constant.d.constant.value;
+ }
+
die_loc2(&token.loc, "Unknown identifier in parse_identifier: ", token.value.as_string);
+ return null;
}
fn parse_factor(lexer: Lexer*): Node* {
@@ -206,6 +304,39 @@ fn parse_factor(lexer: Lexer*): Node* {
expr = node_new(AST_BWINV);
expr.d.unary = parse_factor(lexer);
+ } else if (token.typ == TOKEN_PLUSPLUS) {
+ lexer_next(lexer, &token);
+ expr = node_new(AST_ASSIGN);
+ expr.d.assign.lhs = parse_factor(lexer);
+ if (!is_lvalue(expr.d.assign.lhs.typ))
+ die_loc(&token.loc, "Cannot increment non-lvalue");
+
+ let plus = node_new(AST_PLUS);
+ plus.d.binary.lhs = expr.d.assign.lhs;
+ plus.d.binary.rhs = node_from_int_literal(1);
+ expr.d.assign.rhs = plus;
+
+ // --x is changed to (x = x - 1)
+ } else if (token.typ == TOKEN_MINUSMINUS) {
+ lexer_next(lexer, &token);
+ expr = node_new(AST_ASSIGN);
+ expr.d.assign.lhs = parse_factor(lexer);
+ if (!is_lvalue(expr.d.assign.lhs.typ))
+ die_loc(&token.loc, "Cannot decrement non-lvalue");
+
+ let minus = node_new(AST_MINUS);
+ minus.d.binary.lhs = expr.d.assign.lhs;
+ minus.d.binary.rhs = node_from_int_literal(1);
+ expr.d.assign.rhs = minus;
+
+ // FIXME: This should probably go somewhere else more appropriate
+ } else if (token.typ == TOKEN_SIZEOF) {
+ lexer_next(lexer, &token);
+ lexer_next_assert(lexer, &token, TOKEN_OPEN_PAREN);
+ let typ = parse_type(lexer);
+ lexer_next_assert(lexer, &token, TOKEN_CLOSE_PAREN);
+ expr = node_from_int_literal(size_for_type(typ));
+
} else if (token.typ == TOKEN_EXCLAMATION) {
lexer_next(lexer, &token);
expr = node_new(AST_NOT);
@@ -222,9 +353,18 @@ fn parse_factor(lexer: Lexer*): Node* {
} else if (token.typ == TOKEN_IDENTIFIER) {
expr = parse_identifier(lexer);
+ } else if (token.typ == TOKEN_AMPERSAND) {
+ die("TOKEN_AMPERSAND not implemented in parse_factor");
+
+ } else if (token.typ == TOKEN_STAR) {
+ die("TOKEN_STAR not implemented in parse_factor");
+
} else {
die_loc2(&token.loc, ": Unexpected token found in parse_factor: ", token_type_to_string(token.typ));
}
+
+ // TODO: Handle postfix operators here.
+
return expr;
}
@@ -522,7 +662,7 @@ fn parse_function_params(lexer: Lexer*, func: Node*) {
let var: Variable* = func.d.func.args.data[i];
var.offset = offset;
// TODO: (Here and other uses of `size_for_type`):
- // Should we only align to max(8, type->size) instead?
+ // Should we only align to max(8, type.size) instead?
let var_size = align_up(size_for_type(var.typ), 8);
offset = offset - var_size;
}
diff --git a/compiler/tokens.cup b/compiler/tokens.cup
index e991610..cf1b011 100644
--- a/compiler/tokens.cup
+++ b/compiler/tokens.cup
@@ -57,6 +57,7 @@ enum TokenType {
TOKEN_INT,
TOKEN_LET,
TOKEN_RETURN,
+ TOKEN_SIZEOF,
TOKEN_STRUCT,
TOKEN_UNION,
TOKEN_VOID,
@@ -135,6 +136,7 @@ fn token_type_to_string(typ: int): char* {
if (typ == TOKEN_INT) return "TOKEN_INT";
if (typ == TOKEN_LET) return "TOKEN_LET";
if (typ == TOKEN_RETURN) return "TOKEN_RETURN";
+ if (typ == TOKEN_SIZEOF) return "TOKEN_SIZEOF";
if (typ == TOKEN_STRUCT) return "TOKEN_STRUCT";
if (typ == TOKEN_UNION) return "TOKEN_UNION";
if (typ == TOKEN_VOID) return "TOKEN_VOID";
@@ -157,6 +159,7 @@ fn keyword_to_string(typ: int): char* {
if (typ == TOKEN_INT) return "int";
if (typ == TOKEN_LET) return "let";
if (typ == TOKEN_RETURN) return "return";
+ if (typ == TOKEN_SIZEOF) return "sizeof";
if (typ == TOKEN_STRUCT) return "struct";
if (typ == TOKEN_UNION) return "union";
if (typ == TOKEN_VOID) return "void";