From 1a9a5f26879644da4d65797ca23a26e59ea61b2d Mon Sep 17 00:00:00 2001 From: cuz Date: Tue, 2 Dec 2003 22:09:45 +0000 Subject: [PATCH] More work on .sizeof git-svn-id: svn://svn.cc65.org/cc65/trunk@2702 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65/expr.c | 42 +++++++-- src/ca65/main.c | 34 ++++++- src/ca65/pseudo.c | 16 +++- src/ca65/sizeof.c | 21 +++++ src/ca65/sizeof.h | 6 ++ src/ca65/struct.c | 9 +- src/ca65/symbol.c | 225 +++++++++++++++++++++++++++------------------- src/ca65/symbol.h | 21 ++++- 8 files changed, 261 insertions(+), 113 deletions(-) diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 8280cc4e1..b74e23fc8 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -42,6 +42,7 @@ #include "exprdefs.h" #include "print.h" #include "shift.h" +#include "strbuf.h" #include "tgttrans.h" #include "version.h" #include "xmalloc.h" @@ -385,16 +386,43 @@ static ExprNode* FuncReferenced (void) static ExprNode* FuncSizeOf (void) /* Handle the .SIZEOF function */ { - /* Get the struct for the scoped struct name */ - SymTable* Struct = ParseScopedSymTable (SYM_FIND_EXISTING); + StrBuf FullName = AUTO_STRBUF_INITIALIZER; + char Name[sizeof (SVal)]; + SymTable* Scope; + SymEntry* Sym; + SymEntry* SizeSym; + long Size; - /* Check if the given symbol is really a struct */ - if (GetSymTabType (Struct) != ST_STRUCT) { - Error ("Argument to .SIZEOF is not a struct"); + + /* Parse the scope and the name */ + SymTable* ParentScope = ParseScopedIdent (Name, &FullName); + + /* Check if the parent scope is valid */ + if (ParentScope == 0) { + /* No such scope */ + DoneStrBuf (&FullName); return GenLiteralExpr (0); - } else { - return Symbol (GetSizeOfScope (Struct)); } + + /* The scope is valid, search first for a child scope, then for a symbol */ + if ((Scope = SymFindScope (ParentScope, Name, SYM_FIND_EXISTING)) != 0) { + /* Yep, it's a scope */ + SizeSym = GetSizeOfScope (Scope); + } else if ((Sym = SymFind (ParentScope, Name, SYM_FIND_EXISTING)) != 0) { + SizeSym = GetSizeOfSymbol (Sym); + } else { + Error ("Unknown symbol or scope: `%s'", SB_GetConstBuf (&FullName)); + return GenLiteralExpr (0); + } + + /* Check if we have a size */ + if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) { + Error ("Size of `%s' is unknown", SB_GetConstBuf (&FullName)); + return GenLiteralExpr (0); + } + + /* Return the size */ + return GenLiteralExpr (Size); } diff --git a/src/ca65/main.c b/src/ca65/main.c index 69f9ec00d..0b40393f7 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -68,6 +68,7 @@ #include "pseudo.h" #include "scanner.h" #include "segment.h" +#include "sizeof.h" #include "spool.h" #include "symtab.h" #include "ulabel.h" @@ -373,8 +374,11 @@ static void DoPCAssign (void) static void OneLine (void) /* Assemble one line */ -{ - int Done = 0; +{ + Segment* Seg = 0; + unsigned long PC = 0; + SymEntry* Sym = 0; + int Done = 0; /* Initialize the new listing line if we are actually reading from file * and not from internally pushed input. @@ -396,7 +400,6 @@ static void OneLine (void) int HadWS = WS; /* Generate the symbol table entry, then skip the name */ - SymEntry* Sym; if (Tok == TOK_IDENT) { Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW); } else { @@ -417,8 +420,15 @@ static void OneLine (void) /* Don't allow anything after a symbol definition */ Done = 1; } else { - /* Define a label */ + /* A label. Remember the current segment, so we can later + * determine the size of the data stored under the label. + */ + Seg = ActiveSeg; + PC = GetPC (); + + /* Define the label */ SymDef (Sym, GenCurrentPC (), ADDR_SIZE_DEFAULT, SF_LABEL); + /* Skip the colon. If NoColonLabels is enabled, allow labels * without a colon if there is no whitespace before the * identifier. @@ -461,6 +471,22 @@ static void OneLine (void) DoPCAssign (); } } + + /* If we have defined a label, remember its size. Sym is also set by + * a symbol assignment, but in this case Done is false, so we don't + * come here. + */ + if (Sym) { + unsigned long Size; + if (Seg == ActiveSeg) { + /* Same segment */ + Size = GetPC () - PC; + } else { + /* The line has switched the segment */ + Size = 0; + } + DefSizeOfSymbol (Sym, Size); + } } /* Line separator must come here */ diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 8a277b955..b6460fe72 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -69,6 +69,7 @@ #include "pseudo.h" #include "repeat.h" #include "segment.h" +#include "sizeof.h" #include "spool.h" #include "struct.h" #include "symbol.h" @@ -1507,11 +1508,12 @@ static void DoSunPlus (void) static void DoTag (void) /* Allocate space for a struct */ -{ +{ + SymEntry* SizeSym; long Size; /* Read the struct name */ - SymTable* Struct = ParseScopedSymTable (SYM_FIND_EXISTING); + SymTable* Struct = ParseScopedSymTable (); /* Check the supposed struct */ if (Struct == 0) { @@ -1523,8 +1525,14 @@ static void DoTag (void) return; } - /* Get the size of the struct */ - Size = GetSymVal (SymFind (Struct, ".size", SYM_FIND_EXISTING)); + /* Get the symbol that defines the size of the struct */ + SizeSym = GetSizeOfScope (Struct); + + /* Check if it does exist and if its value is known */ + if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) { + ErrorSkip ("Size of struct/union is unknown"); + return; + } /* Optional multiplicator may follow */ if (Tok == TOK_COMMA) { diff --git a/src/ca65/sizeof.c b/src/ca65/sizeof.c index 5e2b7b7d5..ae2210a04 100644 --- a/src/ca65/sizeof.c +++ b/src/ca65/sizeof.c @@ -33,6 +33,9 @@ +/* common */ +#include "addrsize.h" + /* ca65 */ #include "sizeof.h" #include "symtab.h" @@ -80,3 +83,21 @@ SymEntry* GetSizeOfSymbol (SymEntry* Sym) +SymEntry* DefSizeOfScope (SymTable* Scope, long Size) +/* Define the size of a scope and return the size symbol */ +{ + SymEntry* SizeSym = GetSizeOfScope (Scope); + SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE); +} + + + +SymEntry* DefSizeOfSymbol (SymEntry* Sym, long Size) +/* Define the size of a symbol and return the size symbol */ +{ + SymEntry* SizeSym = GetSizeOfSymbol (Sym); + SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE); +} + + + diff --git a/src/ca65/sizeof.h b/src/ca65/sizeof.h index 26794cb26..547a36212 100644 --- a/src/ca65/sizeof.h +++ b/src/ca65/sizeof.h @@ -66,6 +66,12 @@ struct SymEntry* GetSizeOfSymbol (struct SymEntry* Sym); * does not exist. */ +struct SymEntry* DefSizeOfScope (struct SymTable* Scope, long Size); +/* Define the size of a scope and return the size symbol */ + +struct SymEntry* DefSizeOfSymbol (struct SymEntry* Sym, long Size); +/* Define the size of a symbol and return the size symbol */ + /* End of sizeof.h */ diff --git a/src/ca65/struct.c b/src/ca65/struct.c index 99154c73e..cb757e0a0 100644 --- a/src/ca65/struct.c +++ b/src/ca65/struct.c @@ -121,10 +121,10 @@ static long DoStructInternal (long Offs, unsigned Type) while (Tok != TOK_ENDSTRUCT && Tok != TOK_ENDUNION && Tok != TOK_EOF) { long MemberSize; - SymEntry* Sym; SymTable* Struct; /* The format is "[identifier] storage-allocator [, multiplicator]" */ + SymEntry* Sym = 0; if (Tok == TOK_IDENT) { /* We have an identifier, generate a symbol */ Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW); @@ -168,7 +168,7 @@ static long DoStructInternal (long Offs, unsigned Type) case TOK_TAG: NextTok (); - Struct = ParseScopedSymTable (SYM_FIND_EXISTING); + Struct = ParseScopedSymTable (); if (Struct == 0) { Error ("Unknown struct/union"); } else if (GetSymTabType (Struct) != ST_STRUCT) { @@ -200,6 +200,11 @@ static long DoStructInternal (long Offs, unsigned Type) } } + /* Assign the size to the member if it has a name */ + if (Sym) { + DefSizeOfSymbol (Sym, MemberSize); + } + /* Next member */ if (Type == STRUCT) { /* Struct */ diff --git a/src/ca65/symbol.c b/src/ca65/symbol.c index 685c0e45e..abc371a25 100644 --- a/src/ca65/symbol.c +++ b/src/ca65/symbol.c @@ -35,6 +35,9 @@ #include +/* common */ +#include "strbuf.h" + /* ca65 */ #include "error.h" #include "nexttok.h" @@ -45,14 +48,103 @@ /*****************************************************************************/ -/* Data */ +/* Code */ /*****************************************************************************/ -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ +SymTable* ParseScopedIdent (char* Name, StrBuf* FullName) +/* Parse a (possibly scoped) identifer. Name must point to a buffer big enough + * to hold such an identifier. The scope of the name must exist and is returned + * as function result, while the last part (the identifier) which may be either + * a symbol or a scope depending on the context is returned in Name. FullName + * is a string buffer that is used to store the full name of the identifier + * including the scope. It is used internally and may be used by the caller + * for error messages or similar. + */ +{ + /* Get the starting table */ + SymTable* Scope; + if (Tok == TOK_NAMESPACE) { + + /* Start from the root scope */ + Scope = RootScope; + + } else if (Tok == TOK_IDENT) { + + /* Remember the name and skip it */ + SB_AppendStr (FullName, strcpy (Name, SVal)); + NextTok (); + + /* If no namespace symbol follows, we're already done */ + if (Tok != TOK_NAMESPACE) { + SB_Terminate (FullName); + return CurrentScope; + } + + /* The scope must exist, so search for it starting with the current + * scope. + */ + Scope = SymFindAnyScope (CurrentScope, Name); + if (Scope == 0) { + /* Scope not found */ + SB_Terminate (FullName); + Error ("No such scope: `%s'", SB_GetConstBuf (FullName)); + return 0; + } + + } else { + + /* Invalid token */ + Error ("Identifier expected"); + SB_Terminate (FullName); + Name[0] = '\0'; + return 0; + + } + + /* Skip the namespace token that follows */ + SB_AppendStr (FullName, "::"); + NextTok (); + + /* Resolve scopes. */ + while (1) { + + /* Next token must be an identifier. */ + if (Tok != TOK_IDENT) { + Error ("Identifier expected"); + SB_Terminate (FullName); + Name[0] = '\0'; + return 0; + } + + /* Remember and skip the identifier */ + SB_AppendStr (FullName, strcpy (Name, SVal)); + NextTok (); + + /* If a namespace token follows, we search for another scope, otherwise + * the name is a symbol and we're done. + */ + if (Tok != TOK_NAMESPACE) { + /* Symbol */ + SB_Terminate (FullName); + return Scope; + } + + /* Search for the child scope */ + Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING); + if (Scope == 0) { + /* Scope not found */ + SB_Terminate (FullName); + Error ("No such scope: `%s'", SB_GetConstBuf (FullName)); + return 0; + } + + /* Skip the namespace token that follows */ + SB_AppendStr (FullName, "::"); + NextTok (); + } +} @@ -61,110 +153,57 @@ SymEntry* ParseScopedSymName (int AllocNew) * and return the symbol table entry. */ { - /* Get the starting table */ - SymTable* Scope; - if (Tok == TOK_NAMESPACE) { - Scope = RootScope; - NextTok (); + StrBuf FullName = AUTO_STRBUF_INITIALIZER; + char Ident[sizeof (SVal)]; + + /* Parse the scoped symbol name */ + SymTable* Scope = ParseScopedIdent (Ident, &FullName); + + /* We don't need FullName any longer */ + DoneStrBuf (&FullName); + + /* Check if the scope is valid. Errors have already been diagnosed by + * the routine, so just exit. + */ + if (Scope) { + /* Search for the symbol and return it */ + return SymFind (Scope, Ident, AllocNew); } else { - Scope = CurrentScope; - /* ### Need to walk up the tree */ - } - - /* Resolve scopes */ - while (1) { - - /* An identifier must follow. Remember and skip it. */ - char Name[sizeof (SVal)]; - if (Tok != TOK_IDENT) { - Error ("Identifier expected"); - return 0; - } - strcpy (Name, SVal); - NextTok (); - - /* If the next token is a namespace token, handle the name as the - * name of a scope, otherwise it's the name of a symbol in that - * scope. + /* No scope ==> no symbol. To avoid errors in the calling routine that + * may not expect NULL to be returned if AllocNew is true, create a new + * symbol. */ - - if (Tok == TOK_NAMESPACE) { - - /* Search for the child scope */ - Scope = SymFindScope (Scope, Name, AllocNew); - - /* Skip the namespace token */ - NextTok (); - - /* If we didn't find the scope, bail out */ - if (Scope == 0) { - return 0; - } - + if (AllocNew) { + return NewSymEntry (Ident); } else { - - /* Search for the symbol and return it */ - return SymFind (Scope, Name, AllocNew); - + return 0; } } } -SymTable* ParseScopedSymTable (int AllocNew) +SymTable* ParseScopedSymTable (void) /* 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; - } + StrBuf FullName = AUTO_STRBUF_INITIALIZER; + char Ident[sizeof (SVal)]; - /* 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 (); - } + /* Parse the scoped symbol name */ + SymTable* Scope = ParseScopedIdent (Ident, &FullName); + + /* We don't need FullName any longer */ + DoneStrBuf (&FullName); + + /* Check if the scope is valid. Errors have already been diagnosed by + * the routine, so just exit. + */ + if (Scope) { + /* Search for the last scope */ + Scope = SymFindScope (Scope, Ident, SYM_FIND_EXISTING); } - - /* 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; } diff --git a/src/ca65/symbol.h b/src/ca65/symbol.h index e8e1fa950..6282a0f5a 100644 --- a/src/ca65/symbol.h +++ b/src/ca65/symbol.h @@ -39,23 +39,38 @@ /*****************************************************************************/ -/* Data */ +/* Forwards */ /*****************************************************************************/ +struct StrBuf; +struct SymTable; + + + /*****************************************************************************/ /* Code */ /*****************************************************************************/ +struct SymTable* ParseScopedIdent (char* Name, struct StrBuf* FullName); +/* Parse a (possibly scoped) identifer. Name must point to a buffer big enough + * to hold such an identifier. The scope of the name must exist and is returned + * as function result, while the last part (the identifier) which may be either + * a symbol or a scope depending on the context is returned in Name. FullName + * is a string buffer that is used to store the full name of the identifier + * including the scope. It is used internally and may be used by the caller + * for error messages or similar. + */ + 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); +struct SymTable* ParseScopedSymTable (void); /* Parse a (possibly scoped) symbol table (scope) name, search for it in the * symbol space and return the symbol table struct. */