scanner.o \
segment.o \
spool.o \
+ struct.o \
symentry.o \
symbol.o \
symtab.o \
scanner.obj \
segment.obj \
spool.obj \
+ struct.obj \
symbol.obj \
symentry.obj \
symtab.obj \
/* Accept an EOF as separator */
if (Tok != TOK_EOF) {
if (Tok != TOK_SEP) {
- Error ("Too many characters");
+ Error ("Unexpected trailing garbage characters");
SkipUntilSep ();
} else {
NextTok ();
#include "repeat.h"
#include "segment.h"
#include "spool.h"
+#include "struct.h"
+#include "symbol.h"
#include "symtab.h"
/* Keyword we're about to handle */
-static char Keyword [sizeof (SVal)+1] = ".";
+static char Keyword [sizeof (SVal)+1];
/* Segment stack */
#define MAX_PUSHED_SEGMENTS 16
-static void DoStruct (void)
-/* Struct definition */
-{
- Error ("Not implemented");
-}
-
-
-
static void DoSunPlus (void)
/* Switch to the SUNPLUS CPU */
{
-static void DoUnion (void)
-/* Union definition */
+static void DoTag (void)
+/* Allocate space for a struct */
{
- Error ("Not implemented");
+ long Size;
+
+ /* Read the struct name */
+ SymTable* Struct = ParseScopedSymTable (SYM_FIND_EXISTING);
+
+ /* Check the supposed struct */
+ if (Struct == 0) {
+ ErrorSkip ("Unknown struct");
+ return;
+ }
+ if (GetSymTabType (Struct) != ST_STRUCT) {
+ ErrorSkip ("Not a struct");
+ return;
+ }
+
+ /* Get the size of the struct */
+ Size = GetSymVal (SymFind (Struct, ".size", SYM_FIND_EXISTING));
+
+ /* Optional multiplicator may follow */
+ if (Tok == TOK_COMMA) {
+ long Multiplicator;
+ NextTok ();
+ Multiplicator = ConstExpression ();
+ /* Multiplicator must make sense */
+ if (Multiplicator <= 0) {
+ ErrorSkip ("Range error");
+ return;
+ }
+ Size *= Multiplicator;
+ }
+
+ /* Emit fill fragments */
+ EmitFill (Size);
}
{ ccNone, DoUnexpected }, /* .ENDREPEAT */
{ ccNone, DoEndScope },
{ ccNone, DoUnexpected }, /* .ENDSTRUCT */
+ { ccNone, DoUnexpected }, /* .ENDUNION */
{ ccNone, DoError },
{ ccNone, DoExitMacro },
{ ccNone, DoExport },
{ ccNone, DoUnexpected }, /* .STRLEN */
{ ccNone, DoStruct },
{ ccNone, DoSunPlus },
- { ccNone, DoUnexpected }, /* .TAG */
+ { ccNone, DoTag },
{ ccNone, DoUnexpected }, /* .TCOUNT */
{ ccNone, DoUnexpected }, /* .TIME */
{ ccNone, DoUnion },
/* Remember the instruction, then skip it if needed */
if ((D->Flags & ccKeepToken) == 0) {
- strcpy (Keyword+1, SVal);
+ strcpy (Keyword, SVal);
NextTok ();
}
{ ".ENDREPEAT", TOK_ENDREP },
{ ".ENDSCOPE", TOK_ENDSCOPE },
{ ".ENDSTRUCT", TOK_ENDSTRUCT },
+ { ".ENDUNION", TOK_ENDUNION },
{ ".ERROR", TOK_ERROR },
{ ".EXITMAC", TOK_EXITMACRO },
{ ".EXITMACRO", TOK_EXITMACRO },
TOK_ENDREP,
TOK_ENDSCOPE,
TOK_ENDSTRUCT,
+ TOK_ENDUNION,
TOK_ERROR,
TOK_EXITMACRO,
TOK_EXPORT,
--- /dev/null
+/*****************************************************************************/
+/* */
+/* struct.c */
+/* */
+/* .STRUCT command */
+/* */
+/* */
+/* */
+/* (C) 2003 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "addrsize.h"
+
+/* ca65 */
+#include "error.h"
+#include "expr.h"
+#include "nexttok.h"
+#include "scanner.h"
+#include "symbol.h"
+#include "symtab.h"
+#include "struct.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+enum {
+ STRUCT,
+ UNION
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static long Member (long AllocSize)
+/* Read one struct member and return its size */
+{
+ long Multiplicator;
+
+ /* A comma and a multiplicator may follow */
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ Multiplicator = ConstExpression ();
+ if (Multiplicator <= 0) {
+ Error ("Range error");
+ Multiplicator = 1;
+ }
+ AllocSize *= Multiplicator;
+ }
+
+ /* Return the size */
+ return AllocSize;
+}
+
+
+
+static long DoStructInternal (long Offs, unsigned Type)
+/* Handle the .STRUCT command */
+{
+ long Size = 0;
+
+ /* Outside of other structs, we need a name. Inside another struct or
+ * union, the struct may be anonymous, in which case no new lexical level
+ * is started.
+ */
+ int Anon = (Tok != TOK_IDENT);
+ if (Anon) {
+ unsigned char T = GetCurrentSymTabType ();
+ if (T != ST_STRUCT) {
+ ErrorSkip ("Struct/union needs a name");
+ return 0;
+ }
+ } else {
+ /* Enter a new scope, then skip the name */
+ SymEnterLevel (SVal, ST_STRUCT, ADDR_SIZE_ABS);
+ NextTok ();
+ /* Start at zero offset in the new scope */
+ Offs = 0;
+ }
+
+ /* Test for end of line */
+ ConsumeSep ();
+
+ /* Read until end of struct */
+ while (Tok != TOK_ENDSTRUCT && Tok != TOK_ENDUNION && Tok != TOK_EOF) {
+
+ long MemberSize;
+ SymEntry* Sym;
+ SymTable* Struct;
+
+ /* The format is "[identifier] storage-allocator [, multiplicator]" */
+ if (Tok == TOK_IDENT) {
+ /* We have an identifier, generate a symbol */
+ Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW);
+
+ /* Assign the symbol the offset of the current member */
+ SymDef (Sym, GenLiteralExpr (Offs), ADDR_SIZE_DEFAULT, SF_NONE);
+
+ /* Skip the member name */
+ NextTok ();
+ }
+
+ /* Read storage allocators */
+ MemberSize = 0; /* In case of errors, use zero */
+ switch (Tok) {
+
+ case TOK_BYTE:
+ NextTok ();
+ MemberSize = Member (1);
+ break;
+
+ case TOK_DBYT:
+ case TOK_WORD:
+ case TOK_ADDR:
+ NextTok ();
+ MemberSize = Member (2);
+ break;
+
+ case TOK_FARADDR:
+ NextTok ();
+ MemberSize = Member (3);
+ break;
+
+ case TOK_DWORD:
+ NextTok ();
+ MemberSize = Member (4);
+ break;
+
+ case TOK_RES:
+ Error ("Not implemented");
+ break;
+
+ case TOK_TAG:
+ NextTok ();
+ Struct = ParseScopedSymTable (SYM_FIND_EXISTING);
+ if (Struct == 0) {
+ Error ("Unknown struct/union");
+ } else if (GetSymTabType (Struct) != ST_STRUCT) {
+ Error ("Not a struct/union");
+ } else {
+ MemberSize = Member (GetStructSize (Struct));
+ }
+ break;
+
+ case TOK_STRUCT:
+ NextTok ();
+ MemberSize = DoStructInternal (Offs, STRUCT);
+ break;
+
+ case TOK_UNION:
+ NextTok ();
+ MemberSize = DoStructInternal (Offs, UNION);
+ break;
+
+ default:
+ Error ("Invalid storage allocator in struct/union");
+ SkipUntilSep ();
+ }
+
+ /* Next member */
+ if (Type == STRUCT) {
+ /* Struct */
+ Offs += MemberSize;
+ Size += MemberSize;
+ } else {
+ /* Union */
+ if (MemberSize > Size) {
+ Size = MemberSize;
+ }
+ }
+
+ /* Expect end of line */
+ ConsumeSep ();
+ }
+
+ /* If this is not a anon struct, enter a special symbol named ".size"
+ * into the symbol table of the struct that holds the size of the
+ * struct. Since the symbol starts with a dot, it cannot be accessed
+ * by user code.
+ * Leave the struct scope level.
+ */
+ if (!Anon) {
+ /* Add a symbol */
+ SymEntry* SizeSym = SymFind (CurrentScope, ".size", SYM_ALLOC_NEW);
+ SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE);
+
+ /* Close the struct scope */
+ SymLeaveLevel ();
+ }
+
+ /* End of struct/union definition */
+ if (Type == STRUCT) {
+ Consume (TOK_ENDSTRUCT, "`.ENDSTRUCT' expected");
+ } else {
+ Consume (TOK_ENDUNION, "`.ENDUNION' expected");
+ }
+
+ /* Return the size of the struct */
+ return Size;
+}
+
+
+
+long GetStructSize (SymTable* Struct)
+/* Get the size of a struct or union */
+{
+ SymEntry* Sym = SymFind (Struct, ".size", SYM_FIND_EXISTING);
+ if (Sym == 0) {
+ Error ("Size of struct/union is unknown");
+ return 0;
+ } else {
+ return GetSymVal (Sym);
+ }
+}
+
+
+
+void DoStruct (void)
+/* Handle the .STRUCT command */
+{
+ DoStructInternal (0, STRUCT);
+}
+
+
+
+void DoUnion (void)
+/* Handle the .UNION command */
+{
+ DoStructInternal (0, UNION);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* struct.h */
+/* */
+/* .STRUCT command */
+/* */
+/* */
+/* */
+/* (C) 2003 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef STRUCT_H
+#define STRUCT_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+struct SymTable;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+long GetStructSize (SymTable* Struct);
+/* Get the size of a struct */
+
+void DoStruct (void);
+/* Handle the .STRUCT command */
+
+void DoUnion (void);
+/* Handle the .UNION command */
+
+
+
+/* End of struct.h */
+
+#endif
+
+
+
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
NextTok ();
} else {
Scope = CurrentScope;
+ /* ### Need to walk up the tree */
}
/* Resolve scopes */
+SymTable* ParseScopedSymTable (int AllocNew)
+/* Parse a (possibly scoped) symbol table (scope) name, search for it in the
+ * symbol space and return the symbol table struct.
+ */
+{
+ /* Get the starting table */
+ SymTable* Scope;
+ if (Tok == TOK_NAMESPACE) {
+ Scope = RootScope;
+ NextTok ();
+ } else {
+ Scope = CurrentScope;
+ if (Tok != TOK_IDENT) {
+ Error ("Identifier expected");
+ return Scope;
+ }
+
+ /* If no new scope should be allocated, the scope may specify any
+ * scope in any of the parent scopes, so search for it.
+ */
+ if (!AllocNew) {
+ Scope = SymFindAnyScope (Scope, SVal);
+ NextTok ();
+ if (Tok != TOK_NAMESPACE) {
+ return Scope;
+ }
+ NextTok ();
+ }
+ }
+
+ /* Resolve scopes. */
+ while (Tok == TOK_IDENT) {
+
+ /* Search for the child scope if we have a valid parent */
+ if (Scope) {
+ Scope = SymFindScope (Scope, SVal, AllocNew);
+ }
+
+ /* Skip the name token */
+ NextTok ();
+
+ /* If a namespace token follows, read on, otherwise bail out */
+ if (Tok == TOK_NAMESPACE) {
+ NextTok ();
+ if (Tok != TOK_IDENT) {
+ Error ("Identifier expected");
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* Return the scope we found or created */
+ return Scope;
+}
+
+
+
/* */
/* */
/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
struct SymEntry* ParseScopedSymName (int AllowNew);
/* Parse a (possibly scoped) symbol name, search for it in the symbol table
* and return the symbol table entry.
+ */
+
+struct SymTable* ParseScopedSymTable (int AllocNew);
+/* Parse a (possibly scoped) symbol table (scope) name, search for it in the
+ * symbol space and return the symbol table struct.
*/
+int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
+/* Search in the given tree for a name. If we find the symbol, the function
+ * will return 0 and put the entry pointer into E. If we did not find the
+ * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
+ * E will be set to the last entry, and the result of the function is <0 if
+ * the entry should be inserted on the left side, and >0 if it should get
+ * inserted on the right side.
+ */
+{
+ /* Is there a tree? */
+ if (T == 0) {
+ *E = 0;
+ return 1;
+ }
+
+ /* We have a table, search it */
+ while (1) {
+
+ /* Get the symbol name */
+ const char* SymName = GetString (T->Name);
+
+ /* Choose next entry */
+ int Cmp = strcmp (Name, SymName);
+ if (Cmp < 0 && T->Left) {
+ T = T->Left;
+ } else if (Cmp > 0&& T->Right) {
+ T = T->Right;
+ } else {
+ /* Found or end of search, return the result */
+ *E = T;
+ return Cmp;
+ }
+ }
+}
+
+
+
void SymRef (SymEntry* S)
/* Mark the given symbol as referenced */
{
-unsigned GetSymAddrSize (const SymEntry* S)
+unsigned char GetSymAddrSize (const SymEntry* S)
/* Return the address size of the symbol. Beware: This function will just
* return the AddrSize member, it will not look at the expression!
*/
+long GetSymVal (SymEntry* S)
+/* Return the value of a symbol assuming it's constant. FAIL will be called
+ * in case the symbol is undefined or not constant.
+ */
+{
+ long Val;
+ CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
+ return Val;
+}
+
+
+
unsigned GetSymIndex (const SymEntry* S)
/* Return the symbol index for the given symbol */
{
SymEntry* NewSymEntry (const char* Name);
/* Allocate a symbol table entry, initialize and return it */
+int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E);
+/* Search in the given tree for a name. If we find the symbol, the function
+ * will return 0 and put the entry pointer into E. If we did not find the
+ * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
+ * E will be set to the last entry, and the result of the function is <0 if
+ * the entry should be inserted on the left side, and >0 if it should get
+ * inserted on the right side.
+ */
+
#if defined(HAVE_INLINE)
INLINE void SymAddExprRef (SymEntry* Sym, struct ExprNode* Expr)
/* Add an expression reference to this symbol */
const char* GetSymName (const SymEntry* Sym);
/* Return the name of the symbol */
-unsigned GetSymAddrSize (const SymEntry* Sym);
+unsigned char GetSymAddrSize (const SymEntry* Sym);
/* Return the address size of the symbol. Beware: This function will just
* return the AddrSize member, it will not look at the expression!
*/
+long GetSymVal (SymEntry* Sym);
+/* Return the value of a symbol assuming it's constant. FAIL will be called
+ * in case the symbol is undefined or not constant.
+ */
+
unsigned GetSymIndex (const SymEntry* Sym);
/* Return the symbol index for the given symbol */
-static int SearchSymTree (SymEntry* T, const char* Name, SymEntry** E)
-/* Search in the given tree for a name. If we find the symbol, the function
- * will return 0 and put the entry pointer into E. If we did not find the
- * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
- * E will be set to the last entry, and the result of the function is <0 if
- * the entry should be inserted on the left side, and >0 if it should get
- * inserted on the right side.
- */
-{
- /* Is there a tree? */
- if (T == 0) {
- *E = 0;
- return 1;
- }
-
- /* We have a table, search it */
- while (1) {
-
- /* Get the symbol name */
- const char* SymName = GetString (T->Name);
-
- /* Choose next entry */
- int Cmp = strcmp (Name, SymName);
- if (Cmp < 0 && T->Left) {
- T = T->Left;
- } else if (Cmp > 0&& T->Right) {
- T = T->Right;
- } else {
- /* Found or end of search, return the result */
- *E = T;
- return Cmp;
- }
- }
-}
-
-
-
/*****************************************************************************/
/* Code */
/*****************************************************************************/
+SymTable* SymFindAnyScope (SymTable* Parent, const char* Name)
+/* Find a scope in the given or any of its parent scopes. The function will
+ * never create a new symbol, since this can only be done in one specific
+ * scope.
+ */
+{
+ SymTable* Scope;
+ do {
+ /* Search in the current table */
+ Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING);
+ if (Scope == 0) {
+ /* Not found, search in the parent scope, if we have one */
+ Parent = Parent->Parent;
+ }
+ } while (Scope == 0 && Parent != 0);
+
+ return Scope;
+}
+
+
+
SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
/* Find a new symbol table entry in the given table. If AllocNew is given and
* the entry is not found, create a new one. Return the entry found, or the
}
/* Search for the symbol if we have a table */
- Cmp = SearchSymTree (SymLast->Locals, Name, &S);
+ Cmp = SymSearchTree (SymLast->Locals, Name, &S);
/* If we found an entry, return it */
if (Cmp == 0) {
unsigned Hash = HashStr (Name) % Scope->TableSlots;
/* Search for the entry */
- Cmp = SearchSymTree (Scope->Table[Hash], Name, &S);
+ Cmp = SymSearchTree (Scope->Table[Hash], Name, &S);
/* If we found an entry, return it */
if (Cmp == 0) {
/* common */
#include "exprdefs.h"
+#include "inline.h"
/* ca65 */
#include "symentry.h"
#define ST_GLOBAL 0x00 /* Root level */
#define ST_PROC 0x01 /* .PROC */
#define ST_SCOPE 0x02 /* .SCOPE */
-#define ST_STUCT 0x03 /* .STRUCT */
+#define ST_STRUCT 0x03 /* .STRUCT */
+#define ST_UNION 0x04 /* .UNION */
#define ST_UNDEF 0xFF
/* A symbol table */
SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew);
/* Find a scope in the given enclosing scope */
+SymTable* SymFindAnyScope (SymTable* Parent, const char* Name);
+/* Find a scope in the given or any of its parent scopes. The function will
+ * never create a new symbol, since this can only be done in one specific
+ * scope.
+ */
+
SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew);
/* Find a new symbol table entry in the given table. If AllocNew is given and
* the entry is not found, create a new one. Return the entry found, or the
int SymIsZP (SymEntry* Sym);
/* Return true if the symbol is explicitly marked as zeropage symbol */
+#if defined(HAVE_INLINE)
+INLINE unsigned char GetSymTabType (const SymTable* S)
+/* Return the type of the given symbol table */
+{
+ return S->Type;
+}
+#else
+# define GetSymTabType(S) ((S)->Type)
+#endif
+
unsigned char GetCurrentSymTabType ();
/* Return the type of the current symbol table */