1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-28 19:29:53 +00:00

Added structs and unions, more work on scopes and expressions

git-svn-id: svn://svn.cc65.org/cc65/trunk@2662 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2003-11-13 22:03:24 +00:00
parent 274bafe6a5
commit 20608c81ce
14 changed files with 560 additions and 60 deletions

View File

@ -38,6 +38,7 @@ OBJS = anonname.o \
scanner.o \
segment.o \
spool.o \
struct.o \
symentry.o \
symbol.o \
symtab.o \

View File

@ -87,6 +87,7 @@ OBJS = anonname.obj \
scanner.obj \
segment.obj \
spool.obj \
struct.obj \
symbol.obj \
symentry.obj \
symtab.obj \

View File

@ -422,7 +422,7 @@ void ConsumeSep (void)
/* 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 ();

View File

@ -69,6 +69,8 @@
#include "repeat.h"
#include "segment.h"
#include "spool.h"
#include "struct.h"
#include "symbol.h"
#include "symtab.h"
@ -80,7 +82,7 @@
/* 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
@ -1494,14 +1496,6 @@ static void DoSmart (void)
static void DoStruct (void)
/* Struct definition */
{
Error ("Not implemented");
}
static void DoSunPlus (void)
/* Switch to the SUNPLUS CPU */
{
@ -1510,10 +1504,42 @@ static void DoSunPlus (void)
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);
}
@ -1619,6 +1645,7 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoUnexpected }, /* .ENDREPEAT */
{ ccNone, DoEndScope },
{ ccNone, DoUnexpected }, /* .ENDSTRUCT */
{ ccNone, DoUnexpected }, /* .ENDUNION */
{ ccNone, DoError },
{ ccNone, DoExitMacro },
{ ccNone, DoExport },
@ -1686,7 +1713,7 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoUnexpected }, /* .STRLEN */
{ ccNone, DoStruct },
{ ccNone, DoSunPlus },
{ ccNone, DoUnexpected }, /* .TAG */
{ ccNone, DoTag },
{ ccNone, DoUnexpected }, /* .TCOUNT */
{ ccNone, DoUnexpected }, /* .TIME */
{ ccNone, DoUnion },
@ -1733,7 +1760,7 @@ void HandlePseudo (void)
/* Remember the instruction, then skip it if needed */
if ((D->Flags & ccKeepToken) == 0) {
strcpy (Keyword+1, SVal);
strcpy (Keyword, SVal);
NextTok ();
}

View File

@ -162,6 +162,7 @@ struct DotKeyword {
{ ".ENDREPEAT", TOK_ENDREP },
{ ".ENDSCOPE", TOK_ENDSCOPE },
{ ".ENDSTRUCT", TOK_ENDSTRUCT },
{ ".ENDUNION", TOK_ENDUNION },
{ ".ERROR", TOK_ERROR },
{ ".EXITMAC", TOK_EXITMACRO },
{ ".EXITMACRO", TOK_EXITMACRO },

View File

@ -151,6 +151,7 @@ enum Token {
TOK_ENDREP,
TOK_ENDSCOPE,
TOK_ENDSTRUCT,
TOK_ENDUNION,
TOK_ERROR,
TOK_EXITMACRO,
TOK_EXPORT,

267
src/ca65/struct.c Normal file
View File

@ -0,0 +1,267 @@
/*****************************************************************************/
/* */
/* 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);
}

73
src/ca65/struct.h Normal file
View File

@ -0,0 +1,73 @@
/*****************************************************************************/
/* */
/* 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

View File

@ -45,13 +45,13 @@
/*****************************************************************************/
/* Data */
/* Data */
/*****************************************************************************/
/*****************************************************************************/
/* Code */
/* Code */
/*****************************************************************************/
@ -68,6 +68,7 @@ SymEntry* ParseScopedSymName (int AllocNew)
NextTok ();
} else {
Scope = CurrentScope;
/* ### Need to walk up the tree */
}
/* Resolve scopes */
@ -111,3 +112,61 @@ SymEntry* ParseScopedSymName (int AllocNew)
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;
}

View File

@ -7,7 +7,7 @@
/* */
/* */
/* (C) 1998-2003 Ullrich von Bassewitz */
/* Römerstrasse 52 */
/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@ -53,6 +53,11 @@
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.
*/

View File

@ -131,6 +131,43 @@ SymEntry* NewSymEntry (const char* Name)
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 */
{
@ -580,7 +617,7 @@ const char* GetSymName (const SymEntry* S)
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!
*/
@ -593,6 +630,18 @@ unsigned GetSymAddrSize (const SymEntry* S)
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 */
{

View File

@ -116,6 +116,15 @@ int IsLocalNameId (unsigned Name);
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 */
@ -195,11 +204,16 @@ const struct ExprNode* SymResolve (const SymEntry* Sym);
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 */

View File

@ -160,43 +160,6 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
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 */
/*****************************************************************************/
@ -272,6 +235,27 @@ SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew)
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
@ -295,7 +279,7 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
}
/* 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) {
@ -322,7 +306,7 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
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) {

View File

@ -42,6 +42,7 @@
/* common */
#include "exprdefs.h"
#include "inline.h"
/* ca65 */
#include "symentry.h"
@ -62,7 +63,8 @@
#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 */
@ -103,6 +105,12 @@ void SymLeaveLevel (void);
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
@ -112,6 +120,16 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew);
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 */