union initializers, fix bug with array initializers

This commit is contained in:
pommicket 2022-02-02 14:07:08 -05:00
parent 6ccef91d52
commit 2a65d49d59
3 changed files with 80 additions and 14 deletions

View file

@ -36,6 +36,7 @@ function ident_list_len
:ilist_len_ret :ilist_len_ret
return len return len
; idxth value stored in ident list, or 0 if idx >= length
function ident_list_value_at_index function ident_list_value_at_index
argument list argument list
argument idx argument idx

View file

@ -26,7 +26,7 @@
/* */ /* */
/* typedef int x[sizeof(A)+sizeof"hello"]; */ /* typedef int x[sizeof(A)+sizeof"hello"]; */
/* typedef int y[sizeof(struct B)]; */ /* typedef int y[sizeof(struct B)]; */
/* */
static unsigned int x={55}; static unsigned int x={55};
static char *s = "hello"; static char *s = "hello";
static char *t = "goodbye"; static char *t = "goodbye";
@ -38,4 +38,12 @@ typedef int A[sizeof x_ + sizeof u];
static int a[5] = {1,2,3}; static int a[5] = {1,2,3};
static char b[6][7] = {{'a'},{'b'},{'c'},{'d'},{'e'}}; 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];

View file

@ -24,6 +24,18 @@ function token_is_type
if b != 0 goto return_1 if b != 0 goto return_1
goto return_0 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 function parse_tokens
argument tokens argument tokens
local token local token
@ -78,6 +90,13 @@ function parse_tokens
type = types_bytes_used type = types_bytes_used
parse_type_declarators(prefix, prefix_end, suffix, suffix_end) parse_type_declarators(prefix, prefix_end, suffix, suffix_end)
parse_base_type(base_type, base_type_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 token = suffix_end
if *1token == SYMBOL_LBRACE goto parse_function_definition if *1token == SYMBOL_LBRACE goto parse_function_definition
if is_extern != 0 goto parse_tl_decl_cont ; ignore external variable declarations if is_extern != 0 goto parse_tl_decl_cont ; ignore external variable declarations
@ -93,10 +112,6 @@ function parse_tokens
byte 0 byte 0
:parse_tl_decl_cont :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_SEMICOLON goto tl_decl_loop_done
if *1token != SYMBOL_COMMA goto tld_bad_stuff_after_decl 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 ; 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 ; 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. ; 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 function parse_constant_initializer
argument p_token argument p_token
argument type argument type
@ -296,6 +312,10 @@ function parse_constant_initializer
:init_good :init_good
token = end token = end
c = type_sizeof(type) 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 p = output_file_data + rwdata_end_addr
rwdata_end_addr += c rwdata_end_addr += c
if c == 1 goto write_initializer1 if c == 1 goto write_initializer1
@ -355,7 +375,7 @@ function parse_constant_initializer
:array_init_loop :array_init_loop
if *1token == TOKEN_EOF goto array_init_eof if *1token == TOKEN_EOF goto array_init_eof
parse_constant_initializer(&token, subtype) 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 len == 0 goto array_init_loop_end
if *1token == SYMBOL_RBRACE goto array_init_loop_end if *1token == SYMBOL_RBRACE goto array_init_loop_end
if *1token != SYMBOL_COMMA goto bad_array_initializer if *1token != SYMBOL_COMMA goto bad_array_initializer
@ -363,7 +383,7 @@ function parse_constant_initializer
goto array_init_loop goto array_init_loop
:array_init_loop_end :array_init_loop_end
if *1token == SYMBOL_COMMA goto array_init_skip if *1token != SYMBOL_RBRACE goto array_init_noskip
p = *8p_token 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. 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 :array_init_skip
@ -372,12 +392,15 @@ function parse_constant_initializer
p = types + type p = types + type
p += 1 ; skip TYPE_ARRAY p += 1 ; skip TYPE_ARRAY
if *8p == 0 goto sizeless_array_initializer if *8p == 0 goto sizeless_array_initializer
rwdata_end_addr = addr0 ; sized array
c = type_sizeof(subtype) rwdata_end_addr = addr0
rwdata_end_addr += *8p * c ; e.g. int x[50] = {1,2}; advance rwdata_end_addr by 50*sizeof(int) c = type_sizeof(subtype)
goto const_init_ret 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 :sizeless_array_initializer
byte 0xcc ; @TODO ; sizeless array
*8p = 0 - len
goto const_init_ret
:array_init_eof :array_init_eof
token_error(token, .str_array_init_eof) token_error(token, .str_array_init_eof)
:str_array_init_eof :str_array_init_eof
@ -389,7 +412,41 @@ function parse_constant_initializer
string Bad array initializer. string Bad array initializer.
byte 0 byte 0
:parse_struct_initializer :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 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 :parse_string_array_initializer
p = types + type p = types + type
p += 9 p += 9