Structs and unions are special forms of scopes. They are to some degree comparable to their C counterparts. Both have a list of members. Each member allocates storage and may optionally have a name, which, in case of a struct, is the offset from the beginning and, in case of a union, is always zero.
Here is an example for a very simple struct with two members and a total size of 4 bytes:
.struct Point xcoord .word ycoord .word .endstruct
A union shares the total space between all its members, its size is the same as that of the largest member.
A struct or union must not necessarily have a name. If it is anonymous, no local scope is opened, the identifiers used to name the members are placed into the current scope instead.
A struct may contain unnamed members and definitions of local structs. The storage allocators may contain a multiplier, as in the example below:
.struct Circle .struct Point .word 2 ; Allocate two words .endstruct Radius .word .endstruct
Using the .TAG keyword, it is possible to reserve space for an already defined struct or unions within another struct:
.struct Point xcoord .word ycoord .word .endstruct .struct Circle Origin .tag Point Radius .byte .endstruct
Space for a struct or union may be allocated using the .TAG directive.
C: .tag Circle
Currently, members are just offsets from the start of the struct or union. To access a field of a struct, the member offset has to be added to the address of the struct itself:
lda C+Circle::Radius ; Load circle radius into A
This may change in a future version of the assembler.
Structs and unions are currently implemented as nested symbol tables (in fact, they were a by-product of the improved scoping rules). Currently, the assembler has no idea of types. This means that the .TAG keyword will only allocate space. You won't be able to initialize variables declared with .TAG, and adding an embedded structure to another structure with .TAG will not make this structure accessible by using the '::' operator.