Test of .struct and .union features. Update documentation with more examples, better clarity, and fixes to incorrect data.

This commit is contained in:
bbbradsmith
2023-12-16 19:18:25 -05:00
parent 1093d169ad
commit 0d74b84ce4
2 changed files with 286 additions and 12 deletions

View File

@@ -4086,8 +4086,10 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE"
<sect1><tt>.TAG</tt><label id=".TAG"><p>
Allocate space for a struct or union.
Allocate space for a struct or union. This is equivalent to
<tt><ref id=".RES" name=".RES"></tt> with the
<tt><ref id=".SIZEOF" name=".SIZEOF"></tt> of a struct.
Example:
<tscreen><verb>
@@ -4100,6 +4102,7 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE"
.tag Point ; Allocate 4 bytes
</verb></tscreen>
See: <ref id="structs" name="&quot;Structs and unions&quot;">
<sect1><tt>.UNDEF, .UNDEFINE</tt><label id=".UNDEFINE"><p>
@@ -4865,10 +4868,15 @@ compiler, depending on the target system selected:
Structs and unions are special forms of <ref id="scopes" name="scopes">. They
are, to some degree, comparable to their C counterparts. Both have a list of
members. Each member allocates storage, and optionally may have a name whose
value, in the case of a struct, usually is the storage offset from the
beginning, and in the case of a union, doesn't change, and usually is zero.
members. Each member allocates storage, and optionally may have a name.
Each named member has a constant value equal to the storage offset from the
beginning of the structure. In the case of a union, all members are placed at
the same offset, typically 0.
Each named member also has a storage size which can be accessed with the
<ref id=".SIZEOF" name=".SIZEOF"></tt> operator. The struct or union itself also
has a <tt/.SIZEOF/ indicating its total storage size.
<sect1>Declaration<p>
@@ -4895,8 +4903,9 @@ A struct or union may 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/unions.
The storage allocators may contain a multiplier, as in the example below:
Storage allocators may contain a multiplier. A struct may also contain members
and definitions of local structs/unions. Example:
<tscreen><verb>
.struct Circle
.struct Point
@@ -4905,7 +4914,8 @@ The storage allocators may contain a multiplier, as in the example below:
Radius .word
.endstruct
</verb></tscreen>
The size of the Circle struct is 6 (three words).
In this example the size of the Circle struct is 6 (three words).
<sect1>The storage allocator keywords<p>
@@ -4915,7 +4925,7 @@ The size of the Circle struct is 6 (three words).
<tag/.BYTE, .RES/
Allocates multiples of 1 byte. <tt/.RES/ requires an operand.
<tag/.DBYTE, .WORD, .ADDR/
<tag/.DBYT, .WORD, .ADDR/
Allocates multiples of 2 bytes.
<tag/.FARADDR/
@@ -4924,6 +4934,15 @@ The size of the Circle struct is 6 (three words).
<tag/.DWORD/
Allocates multiples of 4 bytes.
<tag/.TAG/
Allocates a previously defined struct.
<tag/.STRUCT, .UNION/
Begins a nested .struct or .union definition, and allocates it.
Note that its member offset values will begin at 0, unless this nested
structure is anonymous, in which case they will instead become members of
the enclosing scope.
</descrip>
@@ -4968,13 +4987,46 @@ name=".TAG"> directive.
C: .tag Circle
</verb></tscreen>
Currently, members are just offsets from the start of the struct or union. To
Members are just offsets from the start of the struct or union. To
access a field of a struct, the member offset must be added to the address of
the struct variable itself:
<tscreen><verb>
lda C+Circle::Radius ; Load circle radius into A
lda C + Circle::Radius ; Load circle radius
lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord
</verb></tscreen>
That may change in a future version of the assembler.
Nested structures or unions are treated differently depending on whether they
are anonymous. If named, a new structure definition is created within the
enclosing scope, with its offsets beginning at 0. If anonymous, the members of
the new structure are added to the enclosing scope instead. Example:
<tscreen><verb>
.struct Object
member .byte ; Object::member = 0
named .struct Point ; Object::named = 1
xcoord .word ; Object::Point::xcoord = 0
ycoord .word ; Object::Point::ycoord = 2
.endstruct
unnamed .struct ; Object::unnamed = 5
un1 .word ; Object::un1 = 5
un2 .word ; Object::un2 = 7
.endstruct
.struct
un3 .word ; Object::un3 = 9
.endstruct
.endstruct
lda O + Object::named + Object::Point::ycoord
lda O + Object::un2
</verb></tscreen>
In this example, the first nested structure is named "Point", and its member
offsets begin at 0. On the other hand, the two anonymous structures simply
continue to add members to the enclosing Object structure.
Note that an anonymous structure does not need a member name, since all of its
members become part of the enclosing structure. The "unnamed" member in the
example is redundantly the same offset as its first member "un1.
<sect1>Limitations<p>