/* * Copyright (c) 1987 Fujitsu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* lookups.c -- Routines to lookup things in tables. Chip Morningstar -- Lucasfilm Ltd. 5-November-1984 */ #include "macrossTypes.h" #include "macrossGlobals.h" #include "buildStuff.h" #include "errorStuff.h" #include "garbage.h" #include "listing.h" #include "lookups.h" #include "operandStuff.h" #include "parserMisc.h" #include "semanticMisc.h" /* These routines all do basically the same thing. Various kinds of keywords and so forth are stored in hash tables. The hash buckets contain linked lists that are sorted alphabetically. */ conditionType lookupConditionCode(char *s, int hashValue) { conditionTableEntryType *result; result = (conditionTableEntryType *) prehashedStringLookup(s, conditionTable, hashValue); if (result != NULL) return(result->code); else return(NOT_FOUND_COND); } int lookupKeyword(char *s, int hashValue) { keywordTableEntryType *result; result = (keywordTableEntryType *) prehashedStringLookup(s, keywordTable, hashValue); if (result != NULL) return(result->token); else return(0); } macroTableEntryType * lookupMacroName(char *s, int hashValue) { return((macroTableEntryType *) prehashedStringLookup(s, macroTable, hashValue)); } opcodeTableEntryType * lookupOpcode(char *s, int hashValue) { return((opcodeTableEntryType *) prehashedStringLookup(s, opcodeTable, hashValue)); } /* lookupOrEnterSymbol -- if there is an entry in the symbol table for the given symbol, return that entry, otherwise create a new entry for it of the given kind and return *that* */ symbolTableEntryType * lookupOrEnterSymbol(stringType *s, symbolUsageKindType kind) { symbolTableEntryType *result; if (result = (symbolTableEntryType *)hashStringLookup(s,symbolTable)){ /* result->referenceCount++;*/ return(result); } else return((symbolTableEntryType *) hashStringEnter(buildSymbolTableEntry(s, kind), symbolTable)); } void pushSymbol(symbolTableEntryType *symbol) { symbolInContextType *newContext; newContext = typeAlloc(symbolInContextType); newContext->pushedContexts = symbol->context; symbol->context = newContext; } void popSymbol(symbolTableEntryType *symbol) { symbolInContextType *deadContext; deadContext = symbol->context; if (deadContext == NULL) botch("symbol pop underflow\n"); else { symbol->context = deadContext->pushedContexts; if (freeFlag) { if (deadContext->value != NULL) freeValue(deadContext->value); free(deadContext); } } } macroTableEntryType * createMacro(stringType *macroName) { macroTableEntryType *result; symbolTableEntryType *testSymbol; testSymbol = lookupOrEnterSymbol(macroName, MACRO_SYMBOL); if (testSymbol->context->usage != MACRO_SYMBOL) { error(SYMBOL_ALREADY_THERE_ERROR, symbName(testSymbol)); return(NULL); } else if (hashStringLookup(macroName, macroTable) != NULL) { error(SYMBOL_ALREADY_THERE_ERROR, symbName(testSymbol)); return(NULL); } else { result = (macroTableEntryType *) hashStringEnter(buildMacroTableEntry(macroName), macroTable); result->body = NULL; return(result); } } /* Generic table lookup utility routines */ genericTableEntryType * prehashedStringLookup(char *s, genericTableEntryType **table, int hashValue) { genericTableEntryType *result; int test; result = table[hashValue]; while (result != NULL) { if ((test = strcmplc(s, result->string)) == 0) break; else if (test > 0) { result = NULL; break; } else { result = result->next; } } return(result); } genericTableEntryType * hashStringLookup(char *s, genericTableEntryType **table) { return(prehashedStringLookup(s, table, hashString(s))); } genericTableEntryType * hashStringEnter(genericTableEntryType *entry, genericTableEntryType **table) { genericTableEntryType *result; genericTableEntryType *oldResult; int test; int hashValue; hashValue = hashString(entry->string); result = table[hashValue]; if (result == NULL) { table[hashValue] = entry; entry->next = NULL; return(entry); } oldResult = NULL; while (result != NULL) { if ((test = strcmplc(entry->string, result->string)) == 0) { botch("symbol table entry %s already there\n", entry->string); } else if (test > 0) { entry->next = result; if (oldResult == NULL) table[hashValue] = entry; else oldResult->next = entry; return(entry); } else { oldResult = result; result = result->next; } } if (oldResult == NULL) table[hashValue] = entry; else oldResult->next = entry; entry->next = NULL; return(entry); } int hashString(char *s) { unsigned result; result = 0; while (*s != '\0') result = (result << 1) + toLowerCase(*s++); return(result & HASH_TABLE_MASK); } bool strcmplc(char *s1, char *s2) /* string compare in lower case */ /* heavily optimized version */ { char c1; int result; do { c1 = toLowerCase(*s1++); /* if result != 0, they differ */ if (result = c1 - toLowerCase(*s2++)) { return(result); /* c1c2==pos */ } else if (!c1) { /* if they're null, we're done */ return(0); } } while (TRUE); } bool strcmplct(char *s1, char *s2) /* For tables: s2 is already lower case */ /* heavily optimized version. */ { char c1; int result; while (TRUE) { c1 = toLowerCase(*s1++); if (result = c1 - (*s2++)) { /* if result != 0, they differ */ return(result); /* c1c2==pos */ } else if (!c1) { /* if they're null, we're done */ return(0); } } } void purgeSymbol(symbolTableEntryType *symbol) { symbolInContextType *context; if ((context = getWorkingContext(symbol)) != NULL) context->usage = DEAD_SYMBOL; } void reincarnateSymbol(symbolInContextType *context, symbolUsageKindType newUsage) { context->attributes = 0; dupValue(context->value, UndefinedValue); context->usage = newUsage; } /* Routines to handle assembly-time binding of symbols to contexts. */ void pushBinding(symbolTableEntryType *symbol, valueType *newBinding, symbolUsageKindType newUsage) { pushSymbol(symbol); if (newBinding == NULL) newBinding = newValue(FAIL, 0, EXPRESSION_OPND); symbol->context->value = newBinding; symbol->context->usage = newUsage; symbol->context->environmentNumber = currentEnvironment-> environmentNumber; symbol->context->attributes = DEFINED_VARIABLE_ATT; } void popBinding(symbolTableEntryType *symbol) { popSymbol(symbol); } int /* returns number of bindings completed, negative this if failure */ bindMacroArguments(argumentDefinitionListType *argumentList, operandListType *parameterList, stringType *macroName) { int numberBound; bool arrayTag; int arrayLength; valueType **arrayContents; int i; if (argumentList == NULL) arrayTag = FALSE; else arrayTag = ((argumentListHeadType *)argumentList)->arrayTag; numberBound = 1; while (argumentList!=NULL && (!arrayTag || argumentList-> nextArgument!=NULL) && parameterList!=NULL) { pushBinding(argumentList->theArgument, newValue(OPERAND_VALUE, parameterList, EXPRESSION_OPND), ARGUMENT_SYMBOL); argumentList = argumentList->nextArgument; parameterList = parameterList->nextOperand; numberBound++; } if (!arrayTag) { if (parameterList != NULL) { error(TOO_MANY_ARGUMENTS_TO_MACRO_ERROR, macroName, numberBound-1); return(-numberBound); } while (argumentList != NULL) { pushBinding(argumentList->theArgument, newValue(FAIL, 0, EXPRESSION_OPND), ARGUMENT_SYMBOL); argumentList = argumentList->nextArgument; numberBound++; } } else { if (parameterList == NULL) { while (argumentList->nextArgument != NULL) { pushBinding(argumentList->theArgument, newValue(FAIL, 0, EXPRESSION_OPND), ARGUMENT_SYMBOL); argumentList = argumentList->nextArgument; numberBound++; } } arrayLength = countParameters(parameterList); pushBinding(argumentList->theArgument, newValue(ARRAY_VALUE, allocArray(arrayLength, &arrayContents), EXPRESSION_OPND), ARGUMENT_SYMBOL); for (i=0; inextOperand; } numberBound++; } return(numberBound); } int /* returns number of bindings completed, negative this if failure */ bindFunctionArguments(argumentDefinitionListType *argumentList, operandListType *parameterList, stringType *functionName) { valueType *argument; bool arrayTag; int arrayLength; valueType **arrayContents; int i; int numberBound; valueType *firstArgument; environmentType *saveEnvironment; if (argumentList == NULL) arrayTag = FALSE; else arrayTag = ((argumentListHeadType *)argumentList)->arrayTag; numberBound = 1; firstArgument = NULL; while (argumentList!=NULL && (!arrayTag || argumentList-> nextArgument!=NULL) && parameterList!=NULL) { saveEnvironment = currentEnvironment; currentEnvironment = currentEnvironment->previousEnvironment; argument = evaluateOperand(parameterList); currentEnvironment = saveEnvironment; if (firstArgument == NULL) firstArgument = argument; if (isUsable(argument)) { pushBinding(argumentList->theArgument, argument, ARGUMENT_SYMBOL); argumentList = argumentList->nextArgument; parameterList = parameterList->nextOperand; expand((argumentList!=NULL && parameterList!=NULL) ? moreExpression(", ") : 0); numberBound++; } else { if (isUndefined(argument)) resultOfLastFunctionCall = newValue(UNDEFINED_VALUE, 0, firstArgument->addressMode); return(-numberBound); } } if (!arrayTag) { if (parameterList != NULL) { error(TOO_MANY_ARGUMENTS_TO_FUNCTION_ERROR, functionName, numberBound - 1); return(-numberBound); } while (argumentList != NULL) { pushBinding(argumentList->theArgument, newValue(FAIL, 0, EXPRESSION_OPND), ARGUMENT_SYMBOL); argumentList = argumentList->nextArgument; numberBound++; } } else { if (parameterList == NULL) { while (argumentList->nextArgument != NULL) { pushBinding(argumentList->theArgument, newValue(FAIL, 0, EXPRESSION_OPND), ARGUMENT_SYMBOL); argumentList = argumentList->nextArgument; numberBound++; } } arrayLength = countParameters(parameterList); pushBinding(argumentList->theArgument, newValue(ARRAY_VALUE, allocArray(arrayLength, &arrayContents), EXPRESSION_OPND), ARGUMENT_SYMBOL); numberBound++; for (i=0; i previousEnvironment; argument = evaluateOperand(parameterList); currentEnvironment = saveEnvironment; if (firstArgument == NULL) firstArgument = argument; if (isUsable(argument)) { arrayContents[i] = argument; parameterList = parameterList->nextOperand; } else { if (isUndefined(argument)) resultOfLastFunctionCall = newValue(UNDEFINED_VALUE, 0, firstArgument->addressMode); return(-numberBound); } } } return(numberBound); } void unbindArguments(argumentDefinitionListType *argumentList, int numberToUnbind) { while (argumentList != NULL && numberToUnbind-- > 0) { popBinding(argumentList->theArgument); argumentList = argumentList->nextArgument; } if (numberToUnbind > 0) botch("binding count larger than number of bindings\n"); } void unbindLocalVariables(identifierListType *identifierList) { identifierListType *deadEntry; while (identifierList != NULL) { popBinding(identifierList->theSymbol); deadEntry = identifierList; identifierList = identifierList->nextIdentifier; qfree(deadEntry); } }