/* * 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. */ /* statementSemantics.c -- Routines to eat up a parse tree and spit out code. Chip Morningstar -- Lucasfilm Ltd. 12-November-1984 */ #include "macrossTypes.h" #include "macrossGlobals.h" #include "actions.h" #include "debugPrint.h" #include "emitBranch.h" #include "emitStuff.h" #include "errorStuff.h" #include "expressionSemantics.h" #include "fixups.h" #include "garbage.h" #include "lexer.h" #include "listing.h" #include "lookups.h" #include "operandStuff.h" #include "parserMisc.h" #include "semanticMisc.h" #include "statementSemantics.h" #include "structSemantics.h" #include "tokenStrings.h" operandType *dbOperand; /* safe temps for dbx hacking */ expressionType *dbExpression; symbolTableEntryType *dbSymbol; bool newIncludeFile = FALSE; static bool insideConstraintBlock = FALSE; bool nullStatementFlag = FALSE; #define nullAssemble(thing) if (thing==NULL) return; #define nullAssembleNULL(thing) if (thing==NULL) return NULL; #define sideEffectBomb() if (beneathFunction) {\ error(SIDE_EFFECT_ERROR, currentFunctionName);\ break; } #define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;} #define expansionOn() expandMacros=saveExpansion; void assembleBlock(blockType *block) { nullAssemble(block); assembleStatement(block, FALSE, NULL); } simpleFixupListType * assembleBlockInsideIf(blockType *block, simpleFixupListType *ongoingFixupList) { nullAssembleNULL(block); return(assembleStatement(block, TRUE, ongoingFixupList)); } bool operandCheck(opcodeTableEntryType *opcode, int numberOfOperands, valueType **evaluatedOperands) { int i; for (i=0; iaddressMode)] & opcode-> permissibleOperandModes) == 0) { error(ILLEGAL_OPERAND_TYPE_ERROR, opcode->mnemonic); return(FALSE); } } return(TRUE); } void assembleMachineInstruction(opcodeTableEntryType *opcode, operandListType *operands) { int i; int op; valueType *evaluatedOperands[MAX_NUMBER_OF_OPERANDS]; valueType *value; nullAssemble(opcode); expand(moreText("%s\t", opcode->mnemonic)); for (op=1; operands!=NULL && op<=opcode->maxNumberOfOperands; op++, operands=operands->nextOperand) { newFixupAddressMode = EXPRESSION_OPND; evaluatedOperands[op-1] = value = evaluateOperand(operands); fixupAddressMode[op-1] = newFixupAddressMode; currentOperandNumber++; expand(isUndefined(value) ? (finishOperand = TRUE) : expandOperand(value->addressMode, operandBuffer[op-1])); if (value==NULL || value->kindOfValue == FAIL){ error(BAD_INSTRUCTION_OPERAND_ERROR, opcode-> mnemonic); if (freeFlag) for (i=1; imnemonic, opcode->maxNumberOfOperands); } else if (op < opcode->minNumberOfOperands) { error(TOO_FEW_INSTRUCTION_OPERANDS_ERROR, opcode->mnemonic, opcode->minNumberOfOperands); } else if (operandCheck(opcode, op, evaluatedOperands)) { (*instructionActionTable[(int)opcode->addressClass])(opcode, op, evaluatedOperands); } expand((expandOperands(op), endLine())); if (freeFlag) for (i=0; ibody == NULL) { error(UNDEFINED_MACRO_ERROR, macroInstruction->macroName); return; } pushEnvironment(newEnvironment); savedLocalVariableList = currentLocalVariableList; currentLocalVariableList = NULL; savedLabelTagNumber = currentLabelTagNumber; currentLabelTagNumber = nextLabelTagNumber++; savedErrorFlag = errorFlag; errorFlag = FALSE; saveListingOn = listingOn; if ((numberBound = bindMacroArguments(macroInstruction->arguments, operands, macroInstruction->macroName)) > 0) { macroCallDepth++; listingOn = amExpanding(); assembleBlock(macroInstruction->body); macroCallDepth--; } else numberBound = -numberBound; if (numberBound > 1) unbindArguments(macroInstruction->arguments, numberBound-1); unbindLocalVariables(currentLocalVariableList); if (errorFlag) error(ERROR_INSIDE_MACRO_ERROR, macroInstruction->macroName); else errorFlag = savedErrorFlag; currentLabelTagNumber = savedLabelTagNumber; currentLocalVariableList = savedLocalVariableList; listingOn = saveListingOn; popEnvironment(); } void assembleAlignStatement(alignStatementBodyType *alignStatement) { int alignment; bool saveExpansion; nullAssemble(alignStatement); expansionOff(); alignment = intValue(evaluateExpression(alignStatement, NO_FIXUP)); expansionOn(); expand((moreText("align\t0x%x", alignment), endLine())); if (alignment > 0) if (currentCodeMode == ABSOLUTE_BUFFER) { if (structNestingDepth == 0) currentLocationCounter.value = alignment * ((currentLocationCounter.value + alignment - 1) / alignment); else currentFieldOffset = alignment * ((currentFieldOffset + alignment - 1) / alignment); } else { if (insideConstraintBlock) error(ALIGN_INSIDE_CONSTRAIN_ERROR); else addBreak(ALIGN_BREAK, alignment); } else error(IMPROPER_ALIGNMENT_VALUE_ERROR); } void assembleAssertStatement(assertStatementBodyType *assertStatement) { valueType *test; valueType *message; bool saveExpansion; expansionOff(); test = evaluateExpression(assertStatement->condition, NO_FIXUP); expansionOn(); if (test == NULL || test->kindOfValue != ABSOLUTE_VALUE) { error(INVALID_ASSERT_CONDITION_ERROR); } else if (!test->value) { if (assertStatement->message == NULL) error(ASSERT_ERROR); else { expansionOff(); message = evaluateExpression(assertStatement->message, NO_FIXUP); expansionOn(); if (message == NULL || message->kindOfValue != STRING_VALUE) error(INVALID_ASSERT_MESSAGE_ERROR); else error(ASSERT_WITH_MESSAGE_ERROR, message-> value); } } } void assembleBlockStatement(blockStatementBodyType *blockStatement) { valueType *blockIncrement; int blockSize; blockSize = 0; nullAssemble(blockStatement); expand(moreText("block\t")); while (blockStatement != NULL) { blockIncrement = evaluateExpression(blockStatement-> theExpression, NO_FIXUP); blockSize += intValue(blockIncrement); blockStatement = blockStatement->nextExpression; expand((expandExpression(NULL, NULL), blockStatement!=NULL ? moreText(", ") : 0)); qfree(blockIncrement); } expand(endLine()); if (blockSize >= 0) { if (structNestingDepth != 0) { while (blockSize-- > 0) emitByte(0); } else if (currentCodeMode == RELOCATABLE_BUFFER) { while (blockSize-- > 0) emitByte(0); } else { if (produceLinkableObject) reserveAbsolute(currentLocationCounter.value, blockSize); currentLocationCounter.value += blockSize; } } else error(NEGATIVE_BLOCK_SIZE_ERROR); } void assembleByteStatement(byteStatementBodyType *byteStatement) { valueType *byteValue; nullAssemble(byteStatement); expand(moreText("byte\t")); while (byteStatement != NULL) { byteValue = evaluateExpression(byteStatement->theExpression, BYTE_FIXUP); if (byteValue->kindOfValue == STRING_VALUE) { emitString(byteValue->value); } else { putFixupsHere(BYTE_FIXUP, 0); emitByteValue(byteValue); } qfree(byteValue); byteStatement = byteStatement->nextExpression; expand((expandExpression(NULL, NULL), byteStatement != NULL ? moreText(", ") : 0)); } expand(endLine()); } void assembleConstrainStatement(constrainStatementBodyType *constrainStatement) { valueType *constraintValue; int constraint; addressType startAddress; addressType endAddress; bool saveExpansion; expansionOff(); constraintValue = evaluateExpression(constrainStatement->constraint, NO_FIXUP); expansionOn(); if (constraintValue == NULL || constraintValue->kindOfValue != ABSOLUTE_VALUE) { error(INVALID_CONSTRAINT_VALUE_ERROR); return; } constraint = constraintValue->value; expand((moreText("constrain (0x%x) {", constraint), endLine(), tabCount++)); if (currentCodeMode == ABSOLUTE_BUFFER) { startAddress = currentLocationCounter.value; assembleBlock(constrainStatement->constrainedBlock); endAddress = currentLocationCounter.value; if ((startAddress / constraint) != (endAddress / constraint)) error(CONSTRAINT_ERROR, constraint); } else { if (insideConstraintBlock) { error(CONSTRAIN_INSIDE_CONSTRAIN_ERROR); assembleBlock(constrainStatement->constrainedBlock); } else { insideConstraintBlock = TRUE; addBreak(CONSTRAIN_BREAK, constraint); assembleBlock(constrainStatement->constrainedBlock); addBreak(END_CONSTRAIN_BREAK, 0); insideConstraintBlock = FALSE; } } expand((tabCount--, startLineMarked(), tabIndent(), moreText("}"), endLine())); } void assembleDbyteStatement(dbyteStatementBodyType *dbyteStatement) { valueType *wordValue; nullAssemble(dbyteStatement); expand(moreText("dbyte\t")); while (dbyteStatement != NULL) { wordValue = swabValue(evaluateExpression(dbyteStatement-> theExpression, DBYTE_FIXUP)); dbyteStatement = dbyteStatement->nextExpression; expand((expandExpression(NULL, NULL), dbyteStatement != NULL ? moreText(", ") : 0)); putFixupsHere(DBYTE_FIXUP, 0); emitWordValue(wordValue); qfree(wordValue); } expand(endLine()); } void assembleDefineStatement(defineStatementBodyType *defineStatement) { symbolTableEntryType *symbolToDefine; symbolInContextType *contextToDefine; bool saveExpansion; nullAssemble(defineStatement); symbolToDefine = effectiveSymbol(defineStatement->theSymbol, &contextToDefine); if (isDefinable(contextToDefine)) { expand(moreText("define %s = ", symbName(symbolToDefine))); if (contextToDefine->usage == DEAD_SYMBOL) { reincarnateSymbol(contextToDefine, DEFINE_SYMBOL); } else if (contextToDefine->usage == NESTED_UNKNOWN_SYMBOL) { contextToDefine->usage = DEFINE_SYMBOL; } if (alreadyDefined(contextToDefine)) error(REDEFINITION_OF_SYMBOL_ERROR, symbName( symbolToDefine)); else { if (defineStatement->theValue != NULL) { contextToDefine->value = evaluateDefineExpression( defineStatement->theValue); contextToDefine->usage = DEFINE_SYMBOL; expand(expandExpression(NULL, NULL)); } else contextToDefine->value = newValue(FAIL, 0, EXPRESSION_OPND); contextToDefine->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; contextToDefine->attributes |= DEFINED_VARIABLE_ATT; } expand(endLine()); } else { error(SYMBOL_ALREADY_THERE_ERROR, symbName(symbolToDefine)); } } void assembleDoUntilStatement(doUntilStatementBodyType *doUntilStatement) { valueType topOfLoop; nullAssemble(doUntilStatement); topOfLoop = currentLocationCounter; if (doUntilStatement->doUntilCondition == NEVER_COND) topOfLoop.value -= targetOffset; expand((moreText("do {"), endLine(), tabCount++)); assembleBlock(doUntilStatement->doUntilLoop); expand((tabCount--, startLineMarked(), tabIndent(), moreText("} until %s", conditionString(doUntilStatement-> doUntilCondition)), endLine())); if (doUntilStatement->doUntilCondition == ALWAYS_COND) { return; } else if (doUntilStatement->doUntilCondition != NEVER_COND) { emitRelativeBranch(invertConditionCode(doUntilStatement-> doUntilCondition), &topOfLoop, NULL); } else { emitJump(&topOfLoop, NULL); } } void assembleDoWhileStatement(doWhileStatementBodyType *doWhileStatement) { valueType topOfLoop; nullAssemble(doWhileStatement); topOfLoop = currentLocationCounter; if (doWhileStatement->doWhileCondition == ALWAYS_COND) topOfLoop.value -= targetOffset; expand((moreText("do {"), endLine(), tabCount++)); assembleBlock(doWhileStatement->doWhileLoop); expand((tabCount--, startLineMarked(), tabIndent(), moreText("} while %s", conditionString(doWhileStatement-> doWhileCondition)), endLine())); if (doWhileStatement->doWhileCondition == NEVER_COND) { return; } else if (doWhileStatement->doWhileCondition != ALWAYS_COND) { emitRelativeBranch(doWhileStatement->doWhileCondition, &topOfLoop, NULL); } else { emitJump(&topOfLoop, NULL); } } void assembleExternStatement(externStatementBodyType *externStatement) { symbolInContextType *context; symbolTableEntryType *theSymbol; expand(moreText("extern\t")); while (externStatement != NULL) { theSymbol = effectiveSymbol(externStatement->theSymbol, &context); expand(moreText("%s", symbName(theSymbol))); if (context != NULL) { if (context->usage == LABEL_SYMBOL || context->usage == EXTERNAL_SYMBOL || context->usage == UNKNOWN_SYMBOL || context->usage == NESTED_UNKNOWN_SYMBOL) { context->attributes |= GLOBAL_ATT; } else { error(BAD_KIND_OF_SYMBOL_TO_MAKE_EXTERNAL_ERROR, usageString(context->usage)); } } externStatement = externStatement->nextIdentifier; expand(externStatement != NULL ? moreText(", ") : 0); } expand(endLine()); } void assembleFreturnStatement(freturnStatementBodyType *freturnStatement) { freturnExit = TRUE; resultOfLastFunctionCall = evaluateExpression(freturnStatement, NO_FIXUP_OK); } void assembleFunctionStatement(functionStatementBodyType *functionStatement) { symbolTableEntryType *newFunctionSymbol; functionDefinitionType *newFunction; symbolInContextType *context; nullAssemble(functionStatement); if (currentEnvironment != &globalEnvironment) { error(FUNCTION_DEFINITION_INSIDE_FUNCTION_ERROR); return; } newFunctionSymbol = lookupOrEnterSymbol(functionStatement-> functionName, FUNCTION_SYMBOL); context = getBaseContext(newFunctionSymbol); if (context->usage != FUNCTION_SYMBOL) { if (context->usage == UNKNOWN_FUNCTION_SYMBOL) { context->usage = FUNCTION_SYMBOL; } else { error(SYMBOL_ALREADY_THERE_ERROR, symbName( newFunctionSymbol)); return; } } else if (isDefined(context->value)) { error(FUNCTION_ALREADY_EXISTS_ERROR, symbName( newFunctionSymbol)); return; } newFunction = typeAlloc(functionDefinitionType); newFunction->functionName = newFunctionSymbol; newFunction->arguments = functionStatement->theArguments; newFunction->body = functionStatement->theBlock; newFunction->ordinal = -1; newFunction->nextExternalFunction = NULL; context->value = newValue(FUNCTION_VALUE, newFunction, EXPRESSION_OPND); context->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; } void assembleGroupStatement(blockType *groupStatement) { expand((startLineMarked(), tabIndent(), moreText("{"), endLine(), tabCount++)); assembleBlock(groupStatement); expand((tabCount--, startLineMarked(), tabIndent(), moreText("}"), endLine())); } simpleFixupListType * assembleIfStatement(ifStatementBodyType *ifStatement, bool terminalIf, simpleFixupListType *ongoingFixupList) { valueType fixupLocation1[COMPOUND_BRANCH_MAX]; simpleFixupListType *fixupLocation2; if (backwardsCompatibleIfFlag) { assembleIfStatementOldStyle(ifStatement); return(NULL); } nullAssembleNULL(ifStatement); fixupLocation2 = ongoingFixupList; if (ifStatement->ifCondition != ALWAYS_COND && ifStatement-> ifCondition != NEVER_COND) { emitRelativeBranch(invertConditionCode(ifStatement-> ifCondition), NULL, fixupLocation1); expand((moreText("if %s {", conditionString(ifStatement-> ifCondition)), endLine(), tabCount++)); } else if (ifStatement->ifCondition == ALWAYS_COND) { expand((moreText("{"), endLine(), tabCount++)); } if (ifStatement->consequence != NULL && ifStatement->ifCondition != NEVER_COND) fixupLocation2 = assembleBlockInsideIf(ifStatement-> consequence, fixupLocation2); expand((tabCount--, startLineMarked())); if (ifStatement->continuation.continuationBodyUnion != NULL && ifStatement->ifCondition != NEVER_COND && ifStatement->ifCondition != ALWAYS_COND) fixupLocation2 = emitJump(NULL, fixupLocation2); if (ifStatement->ifCondition != ALWAYS_COND && ifStatement-> ifCondition != NEVER_COND) fixupBranch(fixupLocation1, currentLocationCounter); if (ifStatement->continuation.continuationBodyUnion != NULL && ifStatement->ifCondition != ALWAYS_COND) { expand((tabIndent(), moreText("} else "))); fixupLocation2 = assembleIfStatement(ifStatement-> continuation.continuationBodyUnion, terminalIf, fixupLocation2); } else { expand((tabIndent(), moreText("}"), endLine())); } if (terminalIf) { return(fixupLocation2); } else { fixupJump(fixupLocation2, currentLocationCounter); return(NULL); } } void assembleIfStatementOldStyle(ifStatementBodyType *ifStatement) { valueType fixupLocation1[COMPOUND_BRANCH_MAX]; simpleFixupListType *fixupLocation2; nullAssemble(ifStatement); if (ifStatement->ifCondition != ALWAYS_COND) { emitRelativeBranch(invertConditionCode(ifStatement-> ifCondition), NULL, fixupLocation1); expand((moreText("if %s {", conditionString(ifStatement-> ifCondition)), endLine(), tabCount++)); } else { expand((moreText("{"), endLine(), tabCount++)); } if (ifStatement->consequence != NULL) assembleBlock(ifStatement->consequence); expand((tabCount--, startLineMarked())); if (ifStatement->continuation.continuationBodyUnion != NULL) fixupLocation2 = emitJump(NULL, NULL); if (ifStatement->ifCondition != ALWAYS_COND) fixupBranch(fixupLocation1, currentLocationCounter); if (ifStatement->continuation.continuationBodyUnion != NULL) { expand((tabIndent(), moreText("} else "))); assembleIfStatementOldStyle(ifStatement->continuation.continuationBodyUnion); } else { expand((tabIndent(), moreText("}"), endLine())); } if (ifStatement->continuation.continuationBodyUnion != NULL) fixupJump(fixupLocation2, currentLocationCounter); } void assembleIncludeStatement(includeStatementBodyType *includeStatement) { stringType *fileName; valueType *possibleFileName; bool saveExpansion; expansionOff(); possibleFileName = evaluateExpression(includeStatement, NO_FIXUP); expansionOn(); if (possibleFileName->kindOfValue == STRING_VALUE) { fileName = (stringType *)possibleFileName->value; newIncludeFile = TRUE; expand((moreText("include \"%s\"", fileName), endLine())); pushInputFileStack(saveString(fileName)); } else { error(INCLUDE_FILE_NOT_A_STRING_VALUE_ERROR); } } void assembleInstructionStatement(instructionStatementBodyType *instructionStatement, int cumulativeLineNumber) { nullAssemble(instructionStatement); switch(instructionStatement->kindOfInstruction) { case OPCODE_INSTRUCTION: if (amListing()) saveIndexForListing(INSTRUCTION_STATEMENT, cumulativeLineNumber); expand((startLine(), expandLabel(), tabIndent())); assembleMachineInstruction(instructionStatement-> theInstruction.opcodeUnion, instructionStatement->theOperands); break; case MACRO_INSTRUCTION: if (amListing() && !amExpanding()) saveIndexForListing(INSTRUCTION_STATEMENT, cumulativeLineNumber); assembleMacro(instructionStatement->theInstruction.macroUnion, instructionStatement->theOperands); break; default: botch("bad instruction type=%d\n", instructionStatement-> kindOfInstruction, 0, 0); break; } } void assembleLongStatement(longStatementBodyType *longStatement) { valueType *longValue; nullAssemble(longStatement); expand(moreText("long\t")); while (longStatement != NULL) { longValue = evaluateExpression(longStatement->theExpression, LONG_FIXUP); longStatement = longStatement->nextExpression; expand((expandExpression(NULL, NULL), longStatement != NULL ? moreText(", ") : 0)); putFixupsHere(LONG_FIXUP, 0); emitLongValue(longValue); qfree(longValue); } expand(endLine()); } void assembleMacroStatement(macroStatementBodyType *macroStatement) { macroTableEntryType *newMacro; nullAssemble(macroStatement); if (currentEnvironment != &globalEnvironment) { error(MACRO_DEFINITION_INSIDE_MACRO_ERROR); return; } newMacro = macroStatement->theMacro; if (newMacro == NULL) return; if (newMacro->body != NULL) { error(MACRO_ALREADY_EXISTS_ERROR, macroStatement->theMacro-> macroName); return; } newMacro->arguments = macroStatement->theArguments; newMacro->body = macroStatement->theBlock; } void assembleMdefineStatement(defineStatementBodyType *mdefineStatement) { bool saveExpansion; nullAssemble(mdefineStatement); expansionOff(); pushBinding(mdefineStatement->theSymbol, evaluateDefineExpression( mdefineStatement->theValue), MDEFINE_SYMBOL); expansionOn(); addNewLocalVariable(mdefineStatement->theSymbol); } void assembleMdoUntilStatement(mdoUntilStatementBodyType *mdoUntilStatement) { bool saveListingOn; nullAssemble(mdoUntilStatement); saveListingOn = listingOn; do { assembleBlock(mdoUntilStatement->mdoUntilLoop); listingOn = amExpanding(); } while (!booleanTest(mdoUntilStatement->mdoUntilCondition)); listingOn = saveListingOn; } void assembleMdoWhileStatement(mdoWhileStatementBodyType *mdoWhileStatement) { bool saveListingOn; nullAssemble(mdoWhileStatement); saveListingOn = listingOn; do { assembleBlock(mdoWhileStatement->mdoWhileLoop); listingOn = amExpanding(); } while (booleanTest(mdoWhileStatement->mdoWhileCondition)); listingOn = saveListingOn; } void assembleMforStatement(mforStatementBodyType *mforStatement) { bool saveListingOn; bool saveExpansion; nullAssemble(mforStatement); saveListingOn = listingOn; expansionOff(); for (evaluateExpression(mforStatement->initExpression, NO_FIXUP); booleanTest(mforStatement->testExpression); evaluateExpression(mforStatement->incrExpression, NO_FIXUP)) { expansionOn(); assembleBlock(mforStatement->forLoop); listingOn = amExpanding(); expansionOff(); } expansionOn(); listingOn = saveListingOn; } void assembleMifStatement(mifStatementBodyType *mifStatement, int cumulativeLineNumber) { while (mifStatement != NULL) { if (mifStatement->mifCondition == NULL) { assembleBlock(mifStatement->mifConsequence); break; } else if (booleanTest(mifStatement->mifCondition)) { assembleBlock(mifStatement->mifConsequence); break; } else { mifStatement = mifStatement->mifContinuation. mifContinuationBodyUnion; } } if (amListing()) saveEndMifForListing(cumulativeLineNumber); } void assembleMswitchStatement(mswitchStatementBodyType *mswitchStatement) { valueType *switchValue; caseListType *caseList; caseType *theCase; bool matched; expressionListType *tagExpressionList; valueType *tagValue; bool saveExpansion; expansionOff(); switchValue = evaluateExpression(mswitchStatement->switchExpression, NO_FIXUP); expansionOn(); if (switchValue->kindOfValue != ABSOLUTE_VALUE && switchValue->kindOfValue != STRING_VALUE) { error(INVALID_SWITCH_VALUE_KIND, valueKindString(switchValue-> kindOfValue)); return; } for (caseList=mswitchStatement->cases; caseList!=NULL; caseList=caseList-> nextCase) { theCase = caseList->theCase; if (theCase->caseTags == NULL) { assembleBlock(theCase->caseBody); break; } else { matched = FALSE; for (tagExpressionList=theCase->caseTags; tagExpressionList!=NULL; tagExpressionList=tagExpressionList->nextExpression) { expansionOff(); tagValue = evaluateExpression(tagExpressionList-> theExpression, NO_FIXUP); expansionOn(); if (tagValue->kindOfValue != ABSOLUTE_VALUE && tagValue-> kindOfValue != STRING_VALUE) { error(INVALID_CASE_VALUE_KIND, valueKindString(tagValue-> kindOfValue)); continue; } if (tagValue->kindOfValue != switchValue->kindOfValue) continue; if (tagValue->kindOfValue == ABSOLUTE_VALUE) { if (tagValue->value != switchValue->value) continue; } else { if (strcmplc(tagValue->value, switchValue->value) != 0) continue; } matched = TRUE; break; } if (matched) { assembleBlock(theCase->caseBody); break; } } } } void assembleMvariableStatement(mvariableStatementBodyType *mvariableStatement) { identifierListType *newLocalVariable; int initCount; bool saveExpansion; nullAssemble(mvariableStatement); expansionOff(); if (mvariableStatement->theDimension == NULL) { if ((initCount = expressionListLength(mvariableStatement-> theValue)) == 1) { pushBinding(mvariableStatement->theSymbol, evaluateExpression(mvariableStatement-> theValue->theExpression, NO_FIXUP), MVARIABLE_SYMBOL); } else if (initCount > 1) { error(TOO_MANY_VARIABLE_INITIALIZERS_ERROR); } else { pushBinding(mvariableStatement->theSymbol, NULL, MVARIABLE_SYMBOL); } } else { pushBinding(mvariableStatement->theSymbol, createArray( mvariableStatement->theDimension, mvariableStatement-> theValue), MVARIABLE_SYMBOL); } expansionOn(); newLocalVariable = typeAlloc(identifierListType); newLocalVariable->theSymbol = mvariableStatement->theSymbol; newLocalVariable->nextIdentifier = currentLocalVariableList; currentLocalVariableList = newLocalVariable; } void assembleMwhileStatement(mwhileStatementBodyType *mwhileStatement) { bool saveListingOn; nullAssemble(mwhileStatement); saveListingOn = listingOn; while (booleanTest(mwhileStatement->mwhileCondition)) { assembleBlock(mwhileStatement->mwhileLoop); listingOn = amExpanding(); } listingOn = saveListingOn; } void assembleOrgStatement(orgStatementBodyType *orgStatement) { valueType *orgAddress; bool saveExpansion; nullAssemble(orgStatement); targetOffset = 0; expansionOff(); orgAddress = evaluateExpression(orgStatement, NO_FIXUP); expansionOn(); if (absoluteValue(orgAddress) || relocatableValue(orgAddress)) { if (relocatableValue(¤tLocationCounter) && absoluteValue(orgAddress)) { savedRelocatableCurrentLocationCounter = currentLocationCounter; currentCodeMode = ABSOLUTE_BUFFER; } currentLocationCounter.kindOfValue = orgAddress->kindOfValue; currentLocationCounter.value = orgAddress->value; expand((moreText("org\t0x%x", orgAddress->value), endLine())); } else { error(BAD_ORG_ADDRESS_ERROR, valueKindString(orgAddress-> kindOfValue)); } qfree(orgAddress); } void assemblePerformStatement(performStatementBodyType *performStatement) { nullAssemble(performStatement); sideEffectFlag = FALSE; evaluateExpressionStandalone(performStatement); if (!sideEffectFlag) warning(PERFORM_WITHOUT_SIDE_EFFECT_ERROR); } void assembleRelStatement(relStatementBodyType *relStatement) { targetOffset = 0; if (!relocatableValue(¤tLocationCounter)) { currentLocationCounter = savedRelocatableCurrentLocationCounter; currentCodeMode = RELOCATABLE_BUFFER; } expand((moreText("rel"), endLine())); addBreak(BREAK_BREAK, 0); } void assembleStartStatement(startStatementBodyType *startStatement) { nullAssemble(startStatement); expand(moreText("start\t")); if (haveUserStartAddress) { expand((moreText("*fail*"), endLine())); error(START_ADDRESS_ALREADY_GIVEN_ERROR); } else { startAddress = evaluateExpression(startStatement,NO_FIXUP_OK); if (startAddress->kindOfValue == UNDEFINED_VALUE) { startAddress = (valueType *)generateFixupExpression( startStatement); haveUserStartAddress = TRUE; fixupStartAddress = TRUE; } else if (startAddress->kindOfValue != ABSOLUTE_VALUE && startAddress->kindOfValue!=RELOCATABLE_VALUE){ expand((moreText("*fail*"), endLine())); error(BAD_START_ADDRESS_ERROR); } else { expand((expandExpression(NULL, NULL), endLine())); haveUserStartAddress = TRUE; fixupStartAddress = FALSE; } } } void assembleStringStatement(stringStatementBodyType *stringStatement) { valueType *byteValue; nullAssemble(stringStatement); expand(moreText("string\t")); while (stringStatement != NULL) { byteValue = evaluateExpression(stringStatement->theExpression, BYTE_FIXUP); if (byteValue->kindOfValue == STRING_VALUE) { emitString(byteValue->value); emitByte('\0'); } else { putFixupsHere(BYTE_FIXUP, 0); emitByteValue(byteValue); } qfree(byteValue); stringStatement = stringStatement->nextExpression; expand((expandExpression(NULL, NULL), stringStatement != NULL ? moreText(", ") : 0)); } expand(endLine()); } void assembleStructStatement(structStatementBodyType *structStatement) { nullAssemble(structStatement); if (structStatement->structBody == NULL) instantiateStruct(structStatement); else assembleStructDefinition(structStatement); } void assembleTargetStatement(targetStatementBodyType *targetStatement) { valueType *targetAddress; bool saveExpansion; nullAssemble(targetStatement); targetOffset = 0; expansionOff(); targetAddress = evaluateExpression(targetStatement, NO_FIXUP); expansionOn(); if (absoluteValue(targetAddress)) { expand((moreText("target\t0x%x", targetAddress-> value), endLine())); targetOffset = currentLocationCounter.value - targetAddress->value; } else { error(BAD_TARGET_ADDRESS_ERROR, valueKindString( targetAddress->kindOfValue)); } qfree(targetAddress); } void assembleUndefineStatement(undefineStatementBodyType *undefineStatement) { expand(moreText("undefine\t")); while (undefineStatement != NULL) { expand(moreText("%s", symbName(undefineStatement->theSymbol))); purgeSymbol(effectiveSymbol(undefineStatement->theSymbol, NULL)); undefineStatement = undefineStatement->nextIdentifier; expand(undefineStatement != NULL ? moreText(", ") : 0); } expand(endLine()); } void assembleVariableStatement(variableStatementBodyType *variableStatement) { symbolTableEntryType *newVariable; symbolInContextType *contextForVariable; int initCount; nullAssemble(variableStatement); newVariable = effectiveSymbol(variableStatement->theSymbol, &contextForVariable); if (isPotentialVariable(contextForVariable)) { expand(moreText("variable %s = ", symbName(newVariable))); if (contextForVariable->usage == DEAD_SYMBOL) { reincarnateSymbol(contextForVariable, VARIABLE_SYMBOL); } else if (contextForVariable->usage == NESTED_UNKNOWN_SYMBOL) { contextForVariable->usage = VARIABLE_SYMBOL; } if (alreadyDefined(contextForVariable)) { error(REDEFINITION_OF_SYMBOL_ERROR, symbName(newVariable)); } else { if (variableStatement->theDimension == NULL) { if ((initCount = expressionListLength(variableStatement-> theValue)) == 1) { contextForVariable->value = evaluateExpression( variableStatement->theValue->theExpression, NO_FIXUP); expand(expandExpression(NULL, NULL)); } else { if (initCount > 1) error(TOO_MANY_VARIABLE_INITIALIZERS_ERROR); expand(moreText("*fail*")); contextForVariable->value = newValue(FAIL, 0, EXPRESSION_OPND); } } else { contextForVariable->value = createArray(variableStatement-> theDimension, variableStatement->theValue); } contextForVariable->environmentNumber = GLOBAL_ENVIRONMENT_NUMBER; contextForVariable->attributes |= DEFINED_VARIABLE_ATT; } expand(endLine()); } else { error(SYMBOL_ALREADY_THERE_ERROR, symbName(newVariable)); } } void assembleWhileStatement(whileStatementBodyType *whileStatement) { valueType topOfLoop; valueType fixupLocation[COMPOUND_BRANCH_MAX]; nullAssemble(whileStatement); if (whileStatement->whileCondition == NEVER_COND) { return; } else if (whileStatement->whileCondition != ALWAYS_COND) { emitRelativeBranch(invertConditionCode(whileStatement-> whileCondition), NULL, fixupLocation); topOfLoop = currentLocationCounter; } else { topOfLoop = currentLocationCounter; topOfLoop.value -= targetOffset; } expand((moreText("while %s {", conditionString(whileStatement-> whileCondition)), endLine(), tabCount++)); assembleBlock(whileStatement->whileLoop); expand((tabCount--, startLineMarked(), tabIndent(), moreText("}"), endLine())); if (whileStatement->whileCondition != ALWAYS_COND) { emitRelativeBranch(whileStatement->whileCondition, &topOfLoop, NULL); fixupBranch(fixupLocation, currentLocationCounter); } else { emitJump(&topOfLoop, NULL); } } void assembleWordStatement(wordStatementBodyType *wordStatement) { valueType *word; nullAssemble(wordStatement); expand(moreText("word\t")); while (wordStatement != NULL) { word = evaluateExpression(wordStatement->theExpression, WORD_FIXUP); wordStatement = wordStatement->nextExpression; expand((expandExpression(NULL, NULL), wordStatement != NULL ? moreText(", ") : 0)); putFixupsHere(WORD_FIXUP, 0); emitWordValue(word); qfree(word); } expand(endLine()); } bool assembleStatementBody(statementKindType kind, statementBodyType body, int cumulativeLineNumber, bool worryAboutIf, simpleFixupListType **ifFixupList) { bool result; result = TRUE; if (amListing() && kind != INSTRUCTION_STATEMENT && !beneathFunction) saveIndexForListing(kind, cumulativeLineNumber); switch (kind) { case ALIGN_STATEMENT: sideEffectBomb(); assembleAlignStatement(body.alignUnion); if (amListing()) saveIndexForListing(ALIGN_STATEMENT, cumulativeLineNumber); break; case ASSERT_STATEMENT: assembleAssertStatement(body.assertUnion); break; case BLOCK_STATEMENT: sideEffectBomb(); assembleBlockStatement(body.blockUnion); break; case BYTE_STATEMENT: sideEffectBomb(); assembleByteStatement(body.byteUnion); break; case CONSTRAIN_STATEMENT: sideEffectBomb(); assembleConstrainStatement(body.constrainUnion); break; case DBYTE_STATEMENT: sideEffectBomb(); assembleDbyteStatement(body.dbyteUnion); break; case DEFINE_STATEMENT: sideEffectBomb(); assembleDefineStatement(body.defineUnion); break; case DO_UNTIL_STATEMENT: sideEffectBomb(); assembleDoUntilStatement(body.doUntilUnion); break; case DO_WHILE_STATEMENT: sideEffectBomb(); assembleDoWhileStatement(body.doWhileUnion); break; case EXTERN_STATEMENT: sideEffectBomb(); assembleExternStatement(body.externUnion); break; case FRETURN_STATEMENT: assembleFreturnStatement(body.freturnUnion); /* result = FALSE;*/ break; case FUNCTION_STATEMENT: assembleFunctionStatement(body.functionUnion); break; case GROUP_STATEMENT: assembleGroupStatement(body.groupUnion); break; case IF_STATEMENT: sideEffectBomb(); if (worryAboutIf) { *ifFixupList = assembleIfStatement(body.ifUnion, worryAboutIf, *ifFixupList); } else { assembleIfStatement(body.ifUnion, worryAboutIf, NULL); } break; case INCLUDE_STATEMENT: sideEffectBomb(); assembleIncludeStatement(body.includeUnion); break; case INSTRUCTION_STATEMENT: sideEffectBomb(); assembleInstructionStatement(body.instructionUnion, cumulativeLineNumber); break; case LONG_STATEMENT: sideEffectBomb(); assembleLongStatement(body.longUnion); break; case MACRO_STATEMENT: assembleMacroStatement(body.macroUnion); break; case MDEFINE_STATEMENT: assembleMdefineStatement(body.defineUnion); break; case MDO_UNTIL_STATEMENT: assembleMdoUntilStatement(body.mdoUntilUnion); break; case MDO_WHILE_STATEMENT: assembleMdoWhileStatement(body.mdoWhileUnion); break; case MFOR_STATEMENT: assembleMforStatement(body.mforUnion); break; case MIF_STATEMENT: assembleMifStatement(body.mifUnion, cumulativeLineNumber); break; case MSWITCH_STATEMENT: assembleMswitchStatement(body.mswitchUnion); break; case MVARIABLE_STATEMENT: assembleMvariableStatement(body.mvariableUnion); break; case MWHILE_STATEMENT: assembleMwhileStatement(body.mwhileUnion); break; case NULL_STATEMENT: nullStatementFlag = TRUE; expand(labeledLine() ? (startLineMarked(), expandLabel(), endLine()) : 0); break; case ORG_STATEMENT: sideEffectBomb(); assembleOrgStatement(body.orgUnion); if (amListing()) saveIndexForListing(ORG_STATEMENT, cumulativeLineNumber); break; case PERFORM_STATEMENT: assemblePerformStatement(body.performUnion); break; case REL_STATEMENT: sideEffectBomb(); assembleRelStatement(body.relUnion); if (amListing()) saveIndexForListing(REL_STATEMENT, cumulativeLineNumber); break; case START_STATEMENT: assembleStartStatement(body.startUnion); break; case STRING_STATEMENT: sideEffectBomb(); assembleStringStatement(body.stringUnion); break; case STRUCT_STATEMENT: sideEffectBomb(); assembleStructStatement(body.structUnion); break; case TARGET_STATEMENT: sideEffectBomb(); assembleTargetStatement(body.targetUnion); break; case UNDEFINE_STATEMENT: sideEffectBomb(); assembleUndefineStatement(body.undefineUnion); break; case VARIABLE_STATEMENT: sideEffectBomb(); assembleVariableStatement(body.variableUnion); break; case WHILE_STATEMENT: sideEffectBomb(); assembleWhileStatement(body.whileUnion); break; case WORD_STATEMENT: sideEffectBomb(); assembleWordStatement(body.wordUnion); break; default: botch("assembleStatementBody doesn't know kind %d\n", kind, 0, 0); break; } /* return(result);*/ return(!freturnExit); } void assembleLabelList(labelListType *labelList) { while (labelList != NULL) { if (structNestingDepth == 0) valueLabel(labelList->theLabel, newValue(currentLocationCounter.kindOfValue, currentLocationCounter.value, EXPRESSION_OPND)); else valueField(labelList->theLabel, newValue(FIELD_VALUE, currentFieldOffset, EXPRESSION_OPND)); labelList = labelList->nextLabel; } } simpleFixupListType * assembleStatement(statementType *statement, bool insideIf, simpleFixupListType *ongoingFixupList) { char *saveFileName; int saveLineNumber; int saveCumulativeLineNumber; simpleFixupListType *result; statementEvaluationDepth++; expand(flushExpressionString()); saveFileName = currentFileName; saveLineNumber = currentLineNumber; result = ongoingFixupList; while (statement != NULL) { currentFileName = statement->fileName; currentLineNumber = statement->lineNumber; expand(listableStatement(statement->kindOfStatement) ? startLine() : 0); assembleLabelList(statement->labels); expand(listableStatement(statement->kindOfStatement) ? (expandLabel(), tabIndent()) : 0); if (assembleStatementBody(statement->kindOfStatement, statement->statementBody, statement-> cumulativeLineNumber, insideIf && isLastStatementInBlock(statement), &result)) { statementType *next = statement->nextStatement; if (freeFlag && statementEvaluationDepth == 1) freeStatement(statement); statement = next; } else { if (freeFlag && statementEvaluationDepth == 1) freeStatement(statement); freturnExit = TRUE; break; } } if (!newIncludeFile) { currentFileName = saveFileName; currentLineNumber = saveLineNumber; } else { newIncludeFile = FALSE; } statementEvaluationDepth--; return(result); } void eatStatement(statementType *statement) { if (debug) { printf("assembling:\n"); printStatement(statement); } assembleStatement(statement, FALSE, NULL); }