union initializers, fix bug with array initializers
This commit is contained in:
parent
6ccef91d52
commit
2a65d49d59
3 changed files with 80 additions and 14 deletions
|
@ -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
|
||||||
|
|
12
05/main.c
12
05/main.c
|
@ -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];
|
||||||
|
|
81
05/parse.b
81
05/parse.b
|
@ -23,6 +23,18 @@ function token_is_type
|
||||||
b = ident_list_lookup(typedefs, c)
|
b = ident_list_lookup(typedefs, c)
|
||||||
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
|
||||||
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue