SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* 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; }
void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, unsigned char AddrSize, SymEntry* ScopeLabel) /* Enter a new lexical level */ { /* Map a default address size to something real */ if (AddrSize == ADDR_SIZE_DEFAULT) { /* Use the segment address size */ AddrSize = GetCurrentSegAddrSize (); } /* If we have a current scope, search for the given name and create a ** new one if it doesn't exist. If this is the root scope, just create it. */ if (CurrentScope) { /* Search for the scope, create a new one */ CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW); /* Check if the scope has been defined before */ if (CurrentScope->Flags & ST_DEFINED) { Error ("Duplicate scope `%m%p'", ScopeName); } } else { CurrentScope = RootScope = NewSymTable (0, ScopeName); } /* Mark the scope as defined and set type, address size and owner symbol */ CurrentScope->Flags |= ST_DEFINED; CurrentScope->AddrSize = AddrSize; CurrentScope->Type = Type; CurrentScope->Label = ScopeLabel; /* If this is a scope that allows to emit data into segments, add spans ** for all currently existing segments. Doing this for just a few scope ** types is not really necessary but an optimization, because it does not ** allocate memory for useless data (unhandled types here don't occupy ** space in any segment). */ if (CurrentScope->Type <= SCOPE_HAS_DATA) { OpenSpanList (&CurrentScope->Spans); } }
SymTable* ParseScopedSymTable (void) /* Parse a (possibly scoped) symbol table (scope) name, search for it in the * symbol space and return the symbol table struct. */ { StrBuf ScopeName = STATIC_STRBUF_INITIALIZER; StrBuf Name = STATIC_STRBUF_INITIALIZER; int NoScope; /* Parse the scoped symbol name */ SymTable* Scope = ParseScopedIdent (&Name, &ScopeName); /* If ScopeName is empty, no scope was specified */ NoScope = SB_IsEmpty (&ScopeName); /* We don't need FullName any longer */ SB_Done (&ScopeName); /* 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 { Scope = SymFindScope (Scope, &Name, SYM_FIND_EXISTING); } } /* Free memory for name */ SB_Done (&Name); /* Return the scope found */ return Scope; }
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. */ { SymTable* Scope; /* 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 { /* Invalid token */ Error ("Identifier expected"); return 0; } /* Skip the namespace token that follows */ SB_AppendStr (FullName, "::"); NextTok (); /* Resolve scopes. */ while (1) { /* Next token must be an identifier. */ if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); return 0; } /* Remember and skip the identifier */ SB_Copy (Name, &CurTok.SVal); NextTok (); /* 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; } /* Pass the scope back to the caller */ SB_Append (FullName, Name); /* 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; } /* Skip the namespace token that follows */ SB_AppendStr (FullName, "::"); NextTok (); } }