diff options
| author | Mustafa Quraish <[email protected]> | 2022-02-06 23:13:05 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-02-07 03:18:08 -0500 |
| commit | 502067ade0e38e4b84134d729dee3e34c8d2890e (patch) | |
| tree | 605f404331e479f830595a8c6ec635be718fbf17 /compiler/ast.cup | |
| parent | [cup] Add ability to import files (diff) | |
| download | cup-502067ade0e38e4b84134d729dee3e34c8d2890e.tar.xz cup-502067ade0e38e4b84134d729dee3e34c8d2890e.zip | |
[cup] Port over all the type-checking/pointer arithmetic stuff
There's still some work to be done when checking function call args,
etc, but the general mechanism of actually propagating the type back
up the AST is now here from the C compiler.
... Not to say that was very good, but it's passable enough for now.
More improvements to come in the future!
Diffstat (limited to 'compiler/ast.cup')
| -rw-r--r-- | compiler/ast.cup | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/compiler/ast.cup b/compiler/ast.cup index 2ba677b..b452241 100644 --- a/compiler/ast.cup +++ b/compiler/ast.cup @@ -336,4 +336,130 @@ fn dump_ast(node: Node*, depth: int) { } else { putsln(node_type_to_string(node.typ)); } +} + +// Defined below. +fn type_check_unary(node: Node*, token: Token*): Node*; + +fn decay_array_to_pointer(node: Node*, token: Token*): Node* { + // We can only take the address of an lvalue, so we need to ensure that + if (is_lvalue(node.typ) && node.etyp.typ == TYPE_ARRAY) { + let address = node_new(AST_ADDROF); + address.d.unary = node; + address = type_check_unary(address, token); + node = address; + } + return node; +} + +fn type_check_unary(node: Node*, token: Token*): Node* { + let old_type = node.d.unary.etyp; + + if (node.typ != AST_ADDROF && old_type.typ == TYPE_STRUCT) + die_loc(here, &token.loc, "Performing invalid unary operation on struct type"); + + if (node.typ == AST_NOT) { + node.etyp = type_new(TYPE_INT); + } else if (node.typ == AST_ADDROF) { + let ptr = type_new(TYPE_PTR); + // The address of an array is a pointer to the first element + ptr.ptr = old_type.typ == TYPE_ARRAY ? old_type.ptr : old_type; + node.etyp = ptr; + } else if (node.typ == AST_DEREF) { + if (old_type.typ != TYPE_PTR) + die_loc(here, &token.loc, "Cannot dereference non-pointer type"); + node.etyp = old_type.ptr; + // If the dereferenced type is an array, we need to decay it to a + // pointer to the first element. + node = decay_array_to_pointer(node, token); + } else if (node.typ == AST_NEG) { + if (old_type.typ != TYPE_INT) + die_loc(here, &token.loc, "Cannot negate non-integer type"); + node.etyp = type_new(TYPE_INT); + } else { + // Default to not changing the type + node.etyp = old_type; + } + return node; +} + +fn type_check_binary(node: Node*, token: Token*): Node* +{ + let lhs = node.d.binary.lhs.etyp; + let rhs = node.d.binary.rhs.etyp; + + if (lhs.typ == TYPE_STRUCT || rhs.typ == TYPE_STRUCT) + die_loc(here, &token.loc, "Performing invalid binary operation on struct type"); + + if (node.typ == AST_PLUS) { + if (is_int_type(lhs) && is_int_type(rhs)) { + node.etyp = type_new(TYPE_INT); + } else if (lhs.typ == TYPE_PTR && is_int_type(rhs)) { + node.etyp = lhs; + // Pointer arithmetic! + if (size_for_type(lhs.ptr) != 1) { + let mul = node_new(AST_MUL); + mul.d.binary.lhs = node.d.binary.rhs; + mul.d.binary.rhs = node_from_int_literal(size_for_type(lhs.ptr)); + node.d.binary.rhs = mul; + } + } else if (is_int_type(lhs) && rhs.typ == TYPE_PTR) { + node.etyp = rhs; + // Pointer arithmetic! + if (size_for_type(rhs.ptr) != 1) { + let mul = node_new(AST_MUL); + mul.d.binary.lhs = node.d.binary.lhs; + mul.d.binary.rhs = node_from_int_literal(size_for_type(rhs.ptr)); + node.d.binary.lhs = mul; + } + } else { + die_loc(here, &token.loc, "Cannot add non-integer types"); + } + } else if (node.typ == AST_MINUS) { + if (is_int_type(lhs) && is_int_type(rhs)) { + node.etyp = type_new(TYPE_INT); + } else if (lhs.typ == TYPE_PTR && is_int_type(rhs)) { + node.etyp = lhs; + // Pointer arithmetic! + if (size_for_type(lhs.ptr) != 1) { + let mul = node_new(AST_MUL); + mul.d.binary.lhs = node.d.binary.rhs; + mul.d.binary.rhs = node_from_int_literal(size_for_type(lhs.ptr)); + node.d.binary.rhs = mul; + } + } else if (is_int_type(lhs) && rhs.typ == TYPE_PTR) { + node.etyp = rhs; + // Pointer arithmetic! + if (size_for_type(rhs.ptr) != 1) { + let mul = node_new(AST_MUL); + mul.d.binary.lhs = node.d.binary.lhs; + mul.d.binary.rhs = node_from_int_literal(size_for_type(rhs.ptr)); + node.d.binary.lhs = mul; + } + } else if (lhs.typ == TYPE_PTR && rhs.typ == TYPE_PTR) { + node.etyp = type_new(TYPE_INT); + if (!types_equal(lhs.ptr, rhs.ptr)) + die_loc(here, &token.loc, "Cannot subtract pointers of different types"); + + // Pointer arithmetic! (Divide by size of element) + if (size_for_type(lhs.ptr) != 1) { + let mul = node_new(AST_MUL); + mul.d.binary.lhs = node.d.binary.lhs; + mul.d.binary.rhs = node_from_int_literal(size_for_type(lhs.ptr)); + node.d.binary.lhs = mul; + } + } else { + die_loc(here, &token.loc, "Cannot subtract non-integer types"); + } + } else if (node.typ == AST_MUL || node.typ == AST_DIV || node.typ == AST_MOD) { + if (is_int_type(lhs) && is_int_type(rhs)) { + node.etyp = lhs; + } else { + die_loc2(here, &token.loc, "Cannot do operation non-integer types:", node_type_to_string(node.typ)); + } + } else { + // FIXME: This isn't very correct, but it's probably good enough for now + node.etyp = type_new(TYPE_INT); + } + return node; }
\ No newline at end of file |