summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--05/constants.b6
-rw-r--r--05/main.c4
-rw-r--r--05/parse.b109
-rw-r--r--05/util.b2
4 files changed, 84 insertions, 37 deletions
diff --git a/05/constants.b b/05/constants.b
index 06b141f..a04fc1d 100644
--- a/05/constants.b
+++ b/05/constants.b
@@ -134,7 +134,8 @@
; - for unary operators, the operand
; - for casts, the operand (type is given by type member)
; - for binary operators, the first operand followed by the second
-; - for the operators . and ->, the first argument is a 64-bit pointer to the name of the member and the second is the left hand side of the . / ->
+; - for the operators . and ->, the first argument is the expression on the left-hand side, and the second argument is a 64-bit offset.
+; we could use a 32-bit offset but that would cause things to be unaligned.
; - for the ternary operator ? :, the first followed by the second followed by the third
; - for function calls, the function, followed by each of the arguments to the function — info indicates the number of arguments
; Note that file/line number are not stored in expressions.
@@ -685,3 +686,6 @@
:str_union
string union
byte 0
+:str_typedef ; currently only used for nice debug output
+ string typedef
+ byte 0
diff --git a/05/main.c b/05/main.c
index 0f69d38..31c99fc 100644
--- a/05/main.c
+++ b/05/main.c
@@ -13,7 +13,7 @@ typedef struct A {
long double c;
unsigned long d;
char e[3];
- char c[2];
- char d;
long f;
} A;
+
+typedef int x[(int)&((struct A*)0)->e];
diff --git a/05/parse.b b/05/parse.b
index 10c718d..f2ebb7f 100644
--- a/05/parse.b
+++ b/05/parse.b
@@ -61,20 +61,22 @@ function parse_tokens
suffix = prefix_end + 16
suffix_end = type_get_suffix_end(prefix)
- putc('B)
- putc(':)
- print_tokens(base_type, base_type_end)
- putc('P)
- putc(':)
- print_tokens(prefix, prefix_end)
- putc('S)
- putc(':)
- print_tokens(suffix, suffix_end)
+ ;putc('B)
+ ;putc(':)
+ ;print_tokens(base_type, base_type_end)
+ ;putc('P)
+ ;putc(':)
+ ;print_tokens(prefix, prefix_end)
+ ;putc('S)
+ ;putc(':)
+ ;print_tokens(suffix, suffix_end)
type = types_bytes_used
parse_type_declarators(prefix, prefix_end, suffix, suffix_end)
parse_base_type(base_type)
+ puts(.str_typedef)
+ putc(32)
print_type(type)
putc(10)
@@ -322,14 +324,11 @@ function parse_type_declarators
*1out = TYPE_ARRAY
types_bytes_used += 1
- local prev_types
- local prev_types_bytes_used
; little hack to avoid screwing up types like double[sizeof(int)]
- ; temporarily switch out types array to parse the cast's type
- prev_types = types
+ ; temporarily pretend we're using a lot more of types
+ local prev_types_bytes_used
prev_types_bytes_used = types_bytes_used
- types = malloc(4000)
- types_init(types, &types_bytes_used)
+ types_bytes_used += 4000
expr = malloc(4000)
p = suffix
@@ -341,8 +340,7 @@ function parse_type_declarators
evaluate_constant_expression(prefix, expr, &n)
if n < 0 goto bad_array_size
free(expr)
- free(types)
- types = prev_types
+
types_bytes_used = prev_types_bytes_used
out = types + types_bytes_used
@@ -606,6 +604,10 @@ function parse_base_type
if *1member_prefix_end != TOKEN_IDENTIFIER goto member_no_identifier
member_name = member_prefix_end + 8
member_name = *8member_name
+
+ c = ident_list_lookup_check(struct, member_name, 0)
+ if c == 1 goto duplicate_member
+
member_suffix = member_prefix_end + 16
member_suffix_end = type_get_suffix_end(member_prefix)
member_type = types_bytes_used
@@ -635,6 +637,11 @@ function parse_base_type
if *1p != SYMBOL_COMMA goto struct_bad_declaration
p += 16 ; skip comma
goto struct_defn_decl_loop
+ :duplicate_member
+ token_error(p, .str_duplicate_member)
+ :str_duplicate_member
+ string Duplicate member in struct/union.
+ byte 0
:struct_defn_decl_loop_end
p += 16 ; skip semicolon
goto struct_defn_loop
@@ -856,7 +863,7 @@ function parse_expression
local first_token
:parse_expression_top
- ;print_tokens(tokens, tokens_end)
+ print_tokens(tokens, tokens_end)
type = out + 4
@@ -944,7 +951,7 @@ function parse_expression
n = best - tokens
c = *1best
-
+
if best == tokens goto parse_expr_unary
; it's a binary expression.
@@ -1206,16 +1213,41 @@ function parse_expression
:parse_expr_member ; -> or .
p = best + 16
if *1p != TOKEN_IDENTIFIER goto bad_expression
+
+ a = out + 4 ; pointer to type ID
+ out = parse_expression(tokens, best, out)
+ a = types + *4a
+ if c == EXPRESSION_DOT goto type_dot
+ if *1a != TYPE_POINTER goto arrow_non_pointer
+ a += 1
+ :type_dot
+ if *1a != TYPE_STRUCT goto member_non_struct
+ a += 1
+ a = *8a ; pointer to struct data
p += 8
- *8out = *8p ; copy identifier name
+ c = ident_list_lookup(a, *8p)
+ if c == 0 goto member_not_in_struct
+ *8out = c & 0xffffffff ; offset
+ *4type = c > 32 ; type
+ out += 8
p += 8
if p != tokens_end goto bad_expression ; e.g. foo->bar hello
- out += 8
- out = parse_expression(tokens, best, out)
- ; @TODO: typing
return out
-
-
+ :arrow_non_pointer
+ token_error(p, .str_arrow_non_pointer)
+ :str_arrow_non_pointer
+ string Trying to use -> operator on a non-pointer type.
+ byte 0
+ :member_non_struct
+ token_error(p, .str_member_non_struct)
+ :str_member_non_struct
+ string Trying to access member of something other than a (complete) structure/union.
+ byte 0
+ :member_not_in_struct
+ token_error(p, .str_member_not_in_struct)
+ :str_member_not_in_struct
+ string Trying to access non-existent member of structure or union.
+ byte 0
:parse_conditional
depth = 0 ; bracket depth
n = 0 ; ? : depth
@@ -1947,10 +1979,21 @@ function operator_precedence
if op == SYMBOL_MINUS goto return_0xe0
if op == SYMBOL_TILDE goto return_0xe0
if op == SYMBOL_NOT goto return_0xe0
- if op == SYMBOL_LPAREN goto return_0xe8 ; casts
+ if op == SYMBOL_LPAREN goto cast_precedence
return 0xffff
-
+ :cast_precedence
+ ; make sure this actually is a cast
+ ; this is necessary to handle both
+ ; - (x)->something
+ ; and - (int)x->something
+ ; correctly (in the first case, the arrow is the top-level operator, but in the second, the cast is)
+ token += 16
+ local b
+ b = token_is_type(token)
+ if b == 0 goto return_0xffff
+ goto return_0xe8 ; it's a cast
+
function unary_op_to_expression_type
argument op
if op == SYMBOL_PLUS_PLUS goto return_EXPRESSION_PRE_INCREMENT
@@ -2194,21 +2237,19 @@ function print_expression
:print_expr_dot
putc(40)
expression += 8
- p = *8expression
- expression += 8
expression = print_expression(expression)
- putc('.)
- puts(p)
+ puts(.str_dot)
+ putn(*8expression)
+ expression += 8
putc(41)
return expression
:print_expr_arrow
putc(40)
expression += 8
- p = *8expression
- expression += 8
expression = print_expression(expression)
puts(.str_arrow)
- puts(p)
+ putn(*8expression)
+ expression += 8
putc(41)
return expression
:print_post_increment
diff --git a/05/util.b b/05/util.b
index 0d9a401..142a143 100644
--- a/05/util.b
+++ b/05/util.b
@@ -734,6 +734,8 @@ function leftmost_1bit
return 0xe8
:return_0xf0
return 0xf0
+:return_0xffff
+ return 0xffff
function syscall
; I've done some testing, and this should be okay even if