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:
parent
274bafe6a5
commit
20608c81ce
14 changed files with 560 additions and 60 deletions
|
@ -38,6 +38,7 @@ OBJS = anonname.o \
|
||||||
scanner.o \
|
scanner.o \
|
||||||
segment.o \
|
segment.o \
|
||||||
spool.o \
|
spool.o \
|
||||||
|
struct.o \
|
||||||
symentry.o \
|
symentry.o \
|
||||||
symbol.o \
|
symbol.o \
|
||||||
symtab.o \
|
symtab.o \
|
||||||
|
|
|
@ -87,6 +87,7 @@ OBJS = anonname.obj \
|
||||||
scanner.obj \
|
scanner.obj \
|
||||||
segment.obj \
|
segment.obj \
|
||||||
spool.obj \
|
spool.obj \
|
||||||
|
struct.obj \
|
||||||
symbol.obj \
|
symbol.obj \
|
||||||
symentry.obj \
|
symentry.obj \
|
||||||
symtab.obj \
|
symtab.obj \
|
||||||
|
|
|
@ -422,7 +422,7 @@ void ConsumeSep (void)
|
||||||
/* Accept an EOF as separator */
|
/* Accept an EOF as separator */
|
||||||
if (Tok != TOK_EOF) {
|
if (Tok != TOK_EOF) {
|
||||||
if (Tok != TOK_SEP) {
|
if (Tok != TOK_SEP) {
|
||||||
Error ("Too many characters");
|
Error ("Unexpected trailing garbage characters");
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
} else {
|
} else {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
|
|
|
@ -69,6 +69,8 @@
|
||||||
#include "repeat.h"
|
#include "repeat.h"
|
||||||
#include "segment.h"
|
#include "segment.h"
|
||||||
#include "spool.h"
|
#include "spool.h"
|
||||||
|
#include "struct.h"
|
||||||
|
#include "symbol.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@
|
||||||
|
|
||||||
|
|
||||||
/* Keyword we're about to handle */
|
/* Keyword we're about to handle */
|
||||||
static char Keyword [sizeof (SVal)+1] = ".";
|
static char Keyword [sizeof (SVal)+1];
|
||||||
|
|
||||||
/* Segment stack */
|
/* Segment stack */
|
||||||
#define MAX_PUSHED_SEGMENTS 16
|
#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)
|
static void DoSunPlus (void)
|
||||||
/* Switch to the SUNPLUS CPU */
|
/* Switch to the SUNPLUS CPU */
|
||||||
{
|
{
|
||||||
|
@ -1510,10 +1504,42 @@ static void DoSunPlus (void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DoUnion (void)
|
static void DoTag (void)
|
||||||
/* Union definition */
|
/* 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, DoUnexpected }, /* .ENDREPEAT */
|
||||||
{ ccNone, DoEndScope },
|
{ ccNone, DoEndScope },
|
||||||
{ ccNone, DoUnexpected }, /* .ENDSTRUCT */
|
{ ccNone, DoUnexpected }, /* .ENDSTRUCT */
|
||||||
|
{ ccNone, DoUnexpected }, /* .ENDUNION */
|
||||||
{ ccNone, DoError },
|
{ ccNone, DoError },
|
||||||
{ ccNone, DoExitMacro },
|
{ ccNone, DoExitMacro },
|
||||||
{ ccNone, DoExport },
|
{ ccNone, DoExport },
|
||||||
|
@ -1686,7 +1713,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
||||||
{ ccNone, DoUnexpected }, /* .STRLEN */
|
{ ccNone, DoUnexpected }, /* .STRLEN */
|
||||||
{ ccNone, DoStruct },
|
{ ccNone, DoStruct },
|
||||||
{ ccNone, DoSunPlus },
|
{ ccNone, DoSunPlus },
|
||||||
{ ccNone, DoUnexpected }, /* .TAG */
|
{ ccNone, DoTag },
|
||||||
{ ccNone, DoUnexpected }, /* .TCOUNT */
|
{ ccNone, DoUnexpected }, /* .TCOUNT */
|
||||||
{ ccNone, DoUnexpected }, /* .TIME */
|
{ ccNone, DoUnexpected }, /* .TIME */
|
||||||
{ ccNone, DoUnion },
|
{ ccNone, DoUnion },
|
||||||
|
@ -1733,7 +1760,7 @@ void HandlePseudo (void)
|
||||||
|
|
||||||
/* Remember the instruction, then skip it if needed */
|
/* Remember the instruction, then skip it if needed */
|
||||||
if ((D->Flags & ccKeepToken) == 0) {
|
if ((D->Flags & ccKeepToken) == 0) {
|
||||||
strcpy (Keyword+1, SVal);
|
strcpy (Keyword, SVal);
|
||||||
NextTok ();
|
NextTok ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,7 @@ struct DotKeyword {
|
||||||
{ ".ENDREPEAT", TOK_ENDREP },
|
{ ".ENDREPEAT", TOK_ENDREP },
|
||||||
{ ".ENDSCOPE", TOK_ENDSCOPE },
|
{ ".ENDSCOPE", TOK_ENDSCOPE },
|
||||||
{ ".ENDSTRUCT", TOK_ENDSTRUCT },
|
{ ".ENDSTRUCT", TOK_ENDSTRUCT },
|
||||||
|
{ ".ENDUNION", TOK_ENDUNION },
|
||||||
{ ".ERROR", TOK_ERROR },
|
{ ".ERROR", TOK_ERROR },
|
||||||
{ ".EXITMAC", TOK_EXITMACRO },
|
{ ".EXITMAC", TOK_EXITMACRO },
|
||||||
{ ".EXITMACRO", TOK_EXITMACRO },
|
{ ".EXITMACRO", TOK_EXITMACRO },
|
||||||
|
|
|
@ -151,6 +151,7 @@ enum Token {
|
||||||
TOK_ENDREP,
|
TOK_ENDREP,
|
||||||
TOK_ENDSCOPE,
|
TOK_ENDSCOPE,
|
||||||
TOK_ENDSTRUCT,
|
TOK_ENDSTRUCT,
|
||||||
|
TOK_ENDUNION,
|
||||||
TOK_ERROR,
|
TOK_ERROR,
|
||||||
TOK_EXITMACRO,
|
TOK_EXITMACRO,
|
||||||
TOK_EXPORT,
|
TOK_EXPORT,
|
||||||
|
|
267
src/ca65/struct.c
Normal file
267
src/ca65/struct.c
Normal 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
73
src/ca65/struct.h
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ SymEntry* ParseScopedSymName (int AllocNew)
|
||||||
NextTok ();
|
NextTok ();
|
||||||
} else {
|
} else {
|
||||||
Scope = CurrentScope;
|
Scope = CurrentScope;
|
||||||
|
/* ### Need to walk up the tree */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resolve scopes */
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 1998-2003 Ullrich von Bassewitz */
|
/* (C) 1998-2003 Ullrich von Bassewitz */
|
||||||
/* Römerstrasse 52 */
|
/* Römerstraße 52 */
|
||||||
/* D-70794 Filderstadt */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
|
@ -55,6 +55,11 @@ struct SymEntry* ParseScopedSymName (int AllowNew);
|
||||||
* and return the symbol table entry.
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of symbol.h */
|
/* End of symbol.h */
|
||||||
|
|
|
@ -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)
|
void SymRef (SymEntry* S)
|
||||||
/* Mark the given symbol as referenced */
|
/* 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 address size of the symbol. Beware: This function will just
|
||||||
* return the AddrSize member, it will not look at the expression!
|
* 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)
|
unsigned GetSymIndex (const SymEntry* S)
|
||||||
/* Return the symbol index for the given symbol */
|
/* Return the symbol index for the given symbol */
|
||||||
{
|
{
|
||||||
|
|
|
@ -116,6 +116,15 @@ int IsLocalNameId (unsigned Name);
|
||||||
SymEntry* NewSymEntry (const char* Name);
|
SymEntry* NewSymEntry (const char* Name);
|
||||||
/* Allocate a symbol table entry, initialize and return it */
|
/* 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)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE void SymAddExprRef (SymEntry* Sym, struct ExprNode* Expr)
|
INLINE void SymAddExprRef (SymEntry* Sym, struct ExprNode* Expr)
|
||||||
/* Add an expression reference to this symbol */
|
/* Add an expression reference to this symbol */
|
||||||
|
@ -195,11 +204,16 @@ const struct ExprNode* SymResolve (const SymEntry* Sym);
|
||||||
const char* GetSymName (const SymEntry* Sym);
|
const char* GetSymName (const SymEntry* Sym);
|
||||||
/* Return the name of the symbol */
|
/* 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 address size of the symbol. Beware: This function will just
|
||||||
* return the AddrSize member, it will not look at the expression!
|
* 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);
|
unsigned GetSymIndex (const SymEntry* Sym);
|
||||||
/* Return the symbol index for the given symbol */
|
/* Return the symbol index for the given symbol */
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
/* 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)
|
SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
|
||||||
/* Find a new symbol table entry in the given table. If AllocNew is given and
|
/* 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
|
* 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 */
|
/* 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 we found an entry, return it */
|
||||||
if (Cmp == 0) {
|
if (Cmp == 0) {
|
||||||
|
@ -322,7 +306,7 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
|
||||||
unsigned Hash = HashStr (Name) % Scope->TableSlots;
|
unsigned Hash = HashStr (Name) % Scope->TableSlots;
|
||||||
|
|
||||||
/* Search for the entry */
|
/* 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 we found an entry, return it */
|
||||||
if (Cmp == 0) {
|
if (Cmp == 0) {
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
#include "exprdefs.h"
|
#include "exprdefs.h"
|
||||||
|
#include "inline.h"
|
||||||
|
|
||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "symentry.h"
|
#include "symentry.h"
|
||||||
|
@ -62,7 +63,8 @@
|
||||||
#define ST_GLOBAL 0x00 /* Root level */
|
#define ST_GLOBAL 0x00 /* Root level */
|
||||||
#define ST_PROC 0x01 /* .PROC */
|
#define ST_PROC 0x01 /* .PROC */
|
||||||
#define ST_SCOPE 0x02 /* .SCOPE */
|
#define ST_SCOPE 0x02 /* .SCOPE */
|
||||||
#define ST_STUCT 0x03 /* .STRUCT */
|
#define ST_STRUCT 0x03 /* .STRUCT */
|
||||||
|
#define ST_UNION 0x04 /* .UNION */
|
||||||
#define ST_UNDEF 0xFF
|
#define ST_UNDEF 0xFF
|
||||||
|
|
||||||
/* A symbol table */
|
/* A symbol table */
|
||||||
|
@ -103,6 +105,12 @@ void SymLeaveLevel (void);
|
||||||
SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew);
|
SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew);
|
||||||
/* Find a scope in the given enclosing scope */
|
/* 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);
|
SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew);
|
||||||
/* Find a new symbol table entry in the given table. If AllocNew is given and
|
/* 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
|
* 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);
|
int SymIsZP (SymEntry* Sym);
|
||||||
/* Return true if the symbol is explicitly marked as zeropage symbol */
|
/* 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 ();
|
unsigned char GetCurrentSymTabType ();
|
||||||
/* Return the type of the current symbol table */
|
/* Return the type of the current symbol table */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue