/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2012, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <string.h>
+/* common */
+#include "strbuf.h"
+
/* ca65 */
#include "error.h"
#include "nexttok.h"
#include "scanner.h"
#include "symbol.h"
-#include "symtab.h"
-
-
-
-/*****************************************************************************/
-/* Data */
-/*****************************************************************************/
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-SymEntry* ParseScopedSymName (int AllocNew)
-/* Parse a (possibly scoped) symbol name, search for it in the symbol table
- * and return the symbol table entry.
+SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
+/* Parse a (possibly scoped) identifer. 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) {
+
+ /* Clear both passed string buffers */
+ SB_Clear (Name);
+ SB_Clear (FullName);
+
+ /* Get the starting table */
+ if (CurTok.Tok == TOK_NAMESPACE) {
+
+ /* Start from the root scope */
Scope = RootScope;
+
+ } else if (CurTok.Tok == TOK_IDENT) {
+
+ /* Remember the name and skip it */
+ SB_Copy (Name, &CurTok.SVal);
NextTok ();
+
+ /* If no namespace symbol follows, we're already done */
+ if (CurTok.Tok != TOK_NAMESPACE) {
+ SB_Terminate (FullName);
+ return CurrentScope;
+ }
+
+ /* Pass the scope back to the caller */
+ SB_Append (FullName, Name);
+
+ /* 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: `%m%p'", FullName);
+ return 0;
+ }
+
} else {
- Scope = CurrentScope;
- /* ### Need to walk up the tree */
+
+ /* Invalid token */
+ Error ("Identifier expected");
+ return 0;
+
}
- /* Resolve scopes */
+ /* Skip the namespace token that follows */
+ SB_AppendStr (FullName, "::");
+ NextTok ();
+
+ /* Resolve scopes. */
while (1) {
- /* An identifier must follow. Remember and skip it. */
- char Name[sizeof (SVal)];
- if (Tok != TOK_IDENT) {
+ /* Next token must be an identifier. */
+ if (CurTok.Tok != TOK_IDENT) {
Error ("Identifier expected");
return 0;
}
- strcpy (Name, SVal);
+
+ /* Remember and skip the identifier */
+ SB_Copy (Name, &CurTok.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.
+ /* If a namespace token follows, we search for another scope, otherwise
+ * the name is a symbol and we're done.
*/
+ if (CurTok.Tok != TOK_NAMESPACE) {
+ /* Symbol */
+ return Scope;
+ }
- if (Tok == TOK_NAMESPACE) {
-
- /* Search for the child scope */
- Scope = SymFindScope (Scope, Name, AllocNew);
+ /* Pass the scope back to the caller */
+ SB_Append (FullName, Name);
- /* Skip the namespace token */
- NextTok ();
+ /* Search for the child scope */
+ Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING);
+ if (Scope == 0) {
+ /* Scope not found */
+ Error ("No such scope: `%m%p'", FullName);
+ return 0;
+ }
- /* If we didn't find the scope, bail out */
- if (Scope == 0) {
- return 0;
- }
+ /* Skip the namespace token that follows */
+ SB_AppendStr (FullName, "::");
+ NextTok ();
+ }
+}
- } else {
- /* Search for the symbol and return it */
- return SymFind (Scope, Name, AllocNew);
+SymEntry* ParseScopedSymName (SymFindAction Action)
+/* Parse a (possibly scoped) symbol name, search for it in the symbol table
+ * and return the symbol table entry.
+ */
+{
+ StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
+ StrBuf Ident = STATIC_STRBUF_INITIALIZER;
+ int NoScope;
+ SymEntry* Sym;
+
+ /* Parse the scoped symbol name */
+ SymTable* Scope = ParseScopedIdent (&Ident, &ScopeName);
+
+ /* If ScopeName is empty, no scope was specified */
+ NoScope = SB_IsEmpty (&ScopeName);
+
+ /* We don't need ScopeName any longer */
+ SB_Done (&ScopeName);
+
+ /* 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. If no scope was specified,
+ * search also in the upper levels.
+ */
+ if (NoScope && (Action & SYM_ALLOC_NEW) == 0) {
+ Sym = SymFindAny (Scope, &Ident);
+ } else {
+ Sym = SymFind (Scope, &Ident, Action);
+ }
+ } else {
+ /* No scope ==> no symbol. To avoid errors in the calling routine that
+ * may not expect NULL to be returned if Action contains SYM_ALLOC_NEW,
+ * create a new symbol.
+ */
+ if (Action & SYM_ALLOC_NEW) {
+ Sym = NewSymEntry (&Ident, SF_NONE);
+ } else {
+ Sym = 0;
}
}
+
+ /* Deallocate memory for ident */
+ SB_Done (&Ident);
+
+ /* Return the symbol found */
+ return Sym;
}
-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 ScopeName = STATIC_STRBUF_INITIALIZER;
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
+ int NoScope;
- /* 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) {
+ /* Parse the scoped symbol name */
+ SymTable* Scope = ParseScopedIdent (&Name, &ScopeName);
- /* Search for the child scope if we have a valid parent */
- if (Scope) {
- Scope = SymFindScope (Scope, SVal, AllocNew);
- }
+ /* If ScopeName is empty, no scope was specified */
+ NoScope = SB_IsEmpty (&ScopeName);
- /* Skip the name token */
- NextTok ();
+ /* We don't need FullName any longer */
+ SB_Done (&ScopeName);
- /* If a namespace token follows, read on, otherwise bail out */
- if (Tok == TOK_NAMESPACE) {
- NextTok ();
- if (Tok != TOK_IDENT) {
- Error ("Identifier expected");
- }
+ /* If we got no error, search for the child scope withint the enclosing one.
+ * Beware: If no explicit parent scope was specified, search in all upper
+ * levels.
+ */
+ if (Scope) {
+ /* Search for the last scope */
+ if (NoScope) {
+ Scope = SymFindAnyScope (Scope, &Name);
} else {
- break;
+ Scope = SymFindScope (Scope, &Name, SYM_FIND_EXISTING);
}
}
- /* Return the scope we found or created */
+ /* Free memory for name */
+ SB_Done (&Name);
+
+ /* Return the scope found */
return Scope;
}
+SymEntry* ParseAnySymName (SymFindAction Action)
+/* Parse a cheap local symbol or a a (possibly scoped) symbol name, search
+ * for it in the symbol table and return the symbol table entry.
+ */
+{
+ SymEntry* Sym;
+
+ /* Distinguish cheap locals and other symbols */
+ if (CurTok.Tok == TOK_LOCAL_IDENT) {
+ Sym = SymFindLocal (SymLast, &CurTok.SVal, Action);
+ NextTok ();
+ } else {
+ Sym = ParseScopedSymName (Action);
+ }
+
+ /* Return the symbol found */
+ return Sym;
+}