diff options
author | pommicket <pommicket@gmail.com> | 2022-02-02 14:07:08 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-02-02 14:07:08 -0500 |
commit | 2a65d49d59918527ae32096b2094d09d62918730 (patch) | |
tree | e2803bf15b11a4178f553ea8ceb8e4b976d82ee0 | |
parent | 6ccef91d521fc077fa297a1d692eb829c1926a81 (diff) |
union initializers, fix bug with array initializers
-rw-r--r-- | 05/idents.b | 1 | ||||
-rw-r--r-- | 05/main.c | 12 | ||||
-rw-r--r-- | 05/parse.b | 81 |
3 files changed, 80 insertions, 14 deletions
diff --git a/05/idents.b b/05/idents.b index 415059c..11155d7 100644 --- a/05/idents.b +++ b/05/idents.b @@ -36,6 +36,7 @@ function ident_list_len :ilist_len_ret return len +; idxth value stored in ident list, or 0 if idx >= length function ident_list_value_at_index argument list argument idx @@ -26,7 +26,7 @@ /* */ /* typedef int x[sizeof(A)+sizeof"hello"]; */ /* typedef int y[sizeof(struct B)]; */ - +/* */ static unsigned int x={55}; static char *s = "hello"; static char *t = "goodbye"; @@ -38,4 +38,12 @@ typedef int A[sizeof x_ + sizeof u]; static int a[5] = {1,2,3}; static char b[6][7] = {{'a'},{'b'},{'c'},{'d'},{'e'}}; -static int _u = 0x12345678; +static char __b[][7] = {{'a'},"hello",'r'}; +static int _u = sizeof __b; + +union { + int a; + long b; +} x1[3] = {0x1234567890, 1ul<<60|1ul<<3, 77}; +int y1 = 0x12345678; +typedef int R[sizeof x1]; @@ -23,6 +23,18 @@ function token_is_type b = ident_list_lookup(typedefs, c) if b != 0 goto return_1 goto return_0 + +; NB: this takes a pointer to struct data, NOT a type +; Returns 1 if it's a union OR a struct with 1 member (we don't distinguish between these in any way) +function structure_is_union + argument struct + local offset + ; calculate offset of 2nd member, or 0 if there is only one member + offset = ident_list_value_at_index(struct, 1) + offset &= 0xffffffff + if offset == 0 goto return_1 ; if that's 0, it's a union or 1-element struct + goto return_0 + function parse_tokens argument tokens @@ -78,6 +90,13 @@ function parse_tokens type = types_bytes_used parse_type_declarators(prefix, prefix_end, suffix, suffix_end) parse_base_type(base_type, base_type_end) + + ; ensure rwdata_end_addr is aligned to 8 bytes + ; otherwise addresses could be screwed up + rwdata_end_addr += 7 + rwdata_end_addr >= 3 + rwdata_end_addr <= 3 + token = suffix_end if *1token == SYMBOL_LBRACE goto parse_function_definition if is_extern != 0 goto parse_tl_decl_cont ; ignore external variable declarations @@ -93,10 +112,6 @@ function parse_tokens byte 0 :parse_tl_decl_cont - ; ensure rwdata_end_addr is aligned to 8 bytes - rwdata_end_addr += 7 - rwdata_end_addr >= 3 - rwdata_end_addr <= 3 if *1token == SYMBOL_SEMICOLON goto tl_decl_loop_done if *1token != SYMBOL_COMMA goto tld_bad_stuff_after_decl @@ -229,7 +244,8 @@ function parse_tokens ; advances *p_token to the token right after the initializer ; if `type` refers to a sizeless array type (e.g. int x[] = {1,2,3};), it will be altered to the correct size ; outputs the initializer data to rwdata_end_addr, and advances it accordingly. -; after calling this, make sure to align rwdata_end_addr properly +; this aligns rwdata_end_addr before writing data, so if you want the initial value of rwdata_end_addr +; to correspond to the address, ALIGN IT FIRST. function parse_constant_initializer argument p_token argument type @@ -296,6 +312,10 @@ function parse_constant_initializer :init_good token = end c = type_sizeof(type) + ; align rwdata_end_addr to size of type + rwdata_end_addr += c - 1 + rwdata_end_addr /= c + rwdata_end_addr *= c p = output_file_data + rwdata_end_addr rwdata_end_addr += c if c == 1 goto write_initializer1 @@ -355,7 +375,7 @@ function parse_constant_initializer :array_init_loop if *1token == TOKEN_EOF goto array_init_eof parse_constant_initializer(&token, subtype) - len -= 1 + len -= 1 ; kind of horrible hack. -len will track the number of elements for sizeless arrays, and len will count down to 0 for sized arrays if len == 0 goto array_init_loop_end if *1token == SYMBOL_RBRACE goto array_init_loop_end if *1token != SYMBOL_COMMA goto bad_array_initializer @@ -363,7 +383,7 @@ function parse_constant_initializer goto array_init_loop :array_init_loop_end - if *1token == SYMBOL_COMMA goto array_init_skip + if *1token != SYMBOL_RBRACE goto array_init_noskip p = *8p_token if *1p != SYMBOL_LBRACE goto array_init_noskip ; we don't want to skip the closing } because it doesn't belong to us. :array_init_skip @@ -372,12 +392,15 @@ function parse_constant_initializer p = types + type p += 1 ; skip TYPE_ARRAY if *8p == 0 goto sizeless_array_initializer - rwdata_end_addr = addr0 - c = type_sizeof(subtype) - rwdata_end_addr += *8p * c ; e.g. int x[50] = {1,2}; advance rwdata_end_addr by 50*sizeof(int) - goto const_init_ret + ; sized array + rwdata_end_addr = addr0 + c = type_sizeof(subtype) + rwdata_end_addr += *8p * c ; e.g. int x[50] = {1,2}; advance rwdata_end_addr by 50*sizeof(int) + goto const_init_ret :sizeless_array_initializer - byte 0xcc ; @TODO + ; sizeless array + *8p = 0 - len + goto const_init_ret :array_init_eof token_error(token, .str_array_init_eof) :str_array_init_eof @@ -389,7 +412,41 @@ function parse_constant_initializer string Bad array initializer. byte 0 :parse_struct_initializer + if *1token != SYMBOL_LBRACE goto struct_init_no_lbrace ; only happens when recursing + token += 16 + :struct_init_no_lbrace + + a = type_alignof(type) + ; align rwdata_end_addr properly + rwdata_end_addr += a - 1 + rwdata_end_addr /= a + rwdata_end_addr *= a + + p = types + type + p += 1 + b = structure_is_union(*8p) + if b != 0 goto parse_union_initializer byte 0xcc ; @TODO + + :struct_init_ret + if *1token != SYMBOL_RBRACE goto struct_init_noskip + p = *8p_token + if *1p != SYMBOL_LBRACE goto struct_init_noskip ; we don't want to skip the closing } because it doesn't belong to us. + token += 16 ; skip } + :struct_init_noskip + goto const_init_ret + + :parse_union_initializer + addr0 = rwdata_end_addr + a = ident_list_value_at_index(*8p, 0) + subtype = a > 32 ; extract type + + parse_constant_initializer(&token, subtype) + + c = type_sizeof(type) + rwdata_end_addr = addr0 + c ; add full size of union to rwdata_end_addr, even if initialized member is smaller than that. + goto struct_init_ret + :parse_string_array_initializer p = types + type p += 9 |