1 /*****************************************************************************/
5 /* .STRUCT/.UNION commands */
9 /* (C) 2003-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
53 /*****************************************************************************/
55 /*****************************************************************************/
66 /*****************************************************************************/
68 /*****************************************************************************/
72 static long Member (long AllocSize)
73 /* Read one struct member and return its size */
77 /* A multiplicator may follow */
78 if (CurTok.Tok != TOK_SEP) {
79 Multiplicator = ConstExpression ();
80 if (Multiplicator <= 0) {
81 ErrorSkip ("Range error");
84 AllocSize *= Multiplicator;
87 /* Check the size for a reasonable value */
88 if (AllocSize >= 0x10000) {
89 ErrorSkip ("Range error");
98 static long DoStructInternal (long Offs, unsigned Type)
99 /* Handle the .STRUCT command */
103 /* Outside of other structs, we need a name. Inside another struct or
104 * union, the struct may be anonymous, in which case no new lexical level
107 int Anon = (CurTok.Tok != TOK_IDENT);
109 /* Enter a new scope, then skip the name */
110 SymEnterLevel (&CurTok.SVal, ST_STRUCT, ADDR_SIZE_ABS, 0);
112 /* Start at zero offset in the new scope */
116 /* Test for end of line */
119 /* Read until end of struct */
120 while (CurTok.Tok != TOK_ENDSTRUCT &&
121 CurTok.Tok != TOK_ENDUNION &&
122 CurTok.Tok != TOK_EOF) {
128 /* Allow empty and comment lines */
129 if (CurTok.Tok == TOK_SEP) {
134 /* The format is "[identifier] storage-allocator [, multiplicator]" */
136 if (CurTok.Tok == TOK_IDENT) {
138 /* Beware: An identifier may also be a macro, in which case we have
141 Macro* M = FindMacro (&CurTok.SVal);
147 /* We have an identifier, generate a symbol */
148 Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW);
150 /* Assign the symbol the offset of the current member */
151 SymDef (Sym, GenLiteralExpr (Offs), ADDR_SIZE_DEFAULT, SF_NONE);
153 /* Skip the member name */
157 /* Read storage allocators */
158 MemberSize = 0; /* In case of errors, use zero */
159 switch (CurTok.Tok) {
163 MemberSize = Member (1);
170 MemberSize = Member (2);
175 MemberSize = Member (3);
180 MemberSize = Member (4);
185 if (CurTok.Tok == TOK_SEP) {
186 ErrorSkip ("Size is missing");
188 MemberSize = Member (1);
194 Struct = ParseScopedSymTable ();
196 ErrorSkip ("Unknown struct/union");
197 } else if (GetSymTabType (Struct) != ST_STRUCT) {
198 ErrorSkip ("Not a struct/union");
200 SymEntry* SizeSym = GetSizeOfScope (Struct);
201 if (!SymIsDef (SizeSym) || !SymIsConst (SizeSym, &MemberSize)) {
202 ErrorSkip ("Size of struct/union is unknown");
205 MemberSize = Member (MemberSize);
210 MemberSize = DoStructInternal (Offs, STRUCT);
215 MemberSize = DoStructInternal (Offs, UNION);
219 if (!CheckConditionals ()) {
220 /* Not a conditional directive */
221 ErrorSkip ("Invalid storage allocator in struct/union");
225 /* Assign the size to the member if it has a name */
227 DefSizeOfSymbol (Sym, MemberSize);
231 if (Type == STRUCT) {
237 if (MemberSize > Size) {
242 /* Expect end of line */
246 /* If this is not a anon struct, enter a special symbol named ".size"
247 * into the symbol table of the struct that holds the size of the
248 * struct. Since the symbol starts with a dot, it cannot be accessed
250 * Leave the struct scope level.
254 SymEntry* SizeSym = GetSizeOfScope (CurrentScope);
255 SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE);
257 /* Close the struct scope */
261 /* End of struct/union definition */
262 if (Type == STRUCT) {
263 Consume (TOK_ENDSTRUCT, "`.ENDSTRUCT' expected");
265 Consume (TOK_ENDUNION, "`.ENDUNION' expected");
268 /* Return the size of the struct */
274 long GetStructSize (SymTable* Struct)
275 /* Get the size of a struct or union */
277 SymEntry* SizeSym = FindSizeOfScope (Struct);
279 Error ("Size of struct/union is unknown");
282 return GetSymVal (SizeSym);
289 /* Handle the .STRUCT command */
291 DoStructInternal (0, STRUCT);
297 /* Handle the .UNION command */
299 DoStructInternal (0, UNION);