macross/expressionSemantics.c

1172 lines
32 KiB
C

/*
* 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.
*/
/*
expressionSemantics.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 "y.tab.h"
#include "builtInFunctions.h"
#include "errorStuff.h"
#include "expressionSemantics.h"
#include "fixups.h"
#include "listing.h"
#include "lookups.h"
#include "operandStuff.h"
#include "parserMisc.h"
#include "semanticMisc.h"
#include "statementSemantics.h"
#include "tokenStrings.h"
#include <string.h>
operandType *dbOperand; /* safe temps for dbx hacking */
expressionType *dbExpression;
symbolTableEntryType *dbSymbol;
stringType *dbString;
#define nullEvaluate(thing) if (thing==NULL) return(NULL);
#define fail(err) if (!expressionFailed) {\
error(err);\
expressionFailed = TRUE;\
}
#define fail1(err,arg) if (!expressionFailed) {\
error(err,arg);\
expressionFailed = TRUE;\
}
#define fail2(err,arg1,arg2) if (!expressionFailed) {\
error(err,arg1,arg2);\
expressionFailed = TRUE;\
}
#define qfree2(a,b) if (freeFlag) { free(a); free(b); }
#define expansionOff() {saveExpansion=expandMacros; expandMacros=FALSE;}
#define forceExpansion() {saveExpansion=expandMacros; expandMacros=TRUE;}
#define expansionOn() expandMacros=saveExpansion;
#define moreStuff(f) (generatingFixup ? moreExpression(f) : moreText(f))
#define moreStuff1(f,x) (generatingFixup? moreExpression(f,x) : moreText(f,x))
anyOldThing *
arrayLookup(arrayTermType *arrayTerm, valueKindType *kindOfThing)
{
valueType *arrayValue;
valueType *indexValue;
arrayType *array;
int index;
stringType *string;
*kindOfThing = FAIL;
arrayValue = evaluateExpression(arrayTerm->arrayName, NO_FIXUP);
if (arrayValue->kindOfValue == FAIL)
return(NULL);
indexValue = evaluateExpression(arrayTerm->arrayIndex, NO_FIXUP);
if (indexValue->kindOfValue == FAIL)
return(NULL);
if (arrayValue->kindOfValue != ARRAY_VALUE && arrayValue->kindOfValue
!= STRING_VALUE) {
error(ATTEMPT_TO_INDEX_NON_ARRAY_ERROR, valueKindString(
arrayValue->kindOfValue));
return(NULL);
} else if (indexValue->kindOfValue != ABSOLUTE_VALUE) {
error(NON_INTEGER_INDEX_ERROR, valueKindString(indexValue->
kindOfValue));
return(NULL);
}
index = indexValue->value;
if (arrayValue->kindOfValue == ARRAY_VALUE) {
array = (arrayType *)arrayValue->value;
if (index >= array->arraySize) {
error(ARRAY_INDEX_OUT_OF_RANGE_ERROR, index,
array->arraySize-1);
return(NULL);
} else if (index < 0) {
error(NEGATIVE_ARRAY_INDEX_ERROR);
return(NULL);
} else {
*kindOfThing = ARRAY_VALUE;
return((anyOldThing *)&((array->arrayContents)[index]));
}
} else {
string = (stringType *)arrayValue->value;
if (index >= strlen(string)) {
error(ARRAY_INDEX_OUT_OF_RANGE_ERROR, index,
strlen(string) - 1);
return(NULL);
} else if (index < 0) {
error(NEGATIVE_ARRAY_INDEX_ERROR);
return(NULL);
} else {
*kindOfThing = STRING_VALUE;
return((anyOldThing *) &(string[index]));
}
}
}
valueType *
evaluateArrayTerm(arrayTermType *arrayTerm)
{
anyOldThing *resultThing;
valueKindType kindOfResult;
stringType *charPtr;
valueType **valuePtr;
valueType *result;
environmentType *saveEnvironment;
bool saveExpansion;
expansionOff();
resultThing = arrayLookup(arrayTerm, &kindOfResult);
expansionOn();
if (kindOfResult == STRING_VALUE) {
charPtr = (stringType *) resultThing;
expand(moreExpression("'%c'", *charPtr));
return(newValue(ABSOLUTE_VALUE, *charPtr, EXPRESSION_OPND));
} else if (kindOfResult == FAIL) {
return(newValue(FAIL, 0, EXPRESSION_OPND));
} else if (*(valueType **)resultThing == NULL) {
error(VALUELESS_ARRAY_ELEMENT_ERROR);
return(newValue(FAIL, 0, EXPRESSION_OPND));
} else {
valuePtr = (valueType **) resultThing;
if ((*valuePtr)->kindOfValue == OPERAND_VALUE) {
saveEnvironment = currentEnvironment;
currentEnvironment = currentEnvironment->
previousEnvironment;
expansionOff();
result = evaluateOperand((*valuePtr)->value);
expansionOn();
currentEnvironment = saveEnvironment;
} else {
dupValue(result, *valuePtr);
}
expand(result->kindOfValue==ABSOLUTE_VALUE ?
moreExpression("0x%x", result->value) : (result->
kindOfValue==STRING_VALUE ? moreExpression("\"%s\"",
result->value) : 0));
return(result);
}
}
valueType *
evaluateAssignmentTerm(binopTermType *assignmentTerm, fixupKindType kindOfFixup)
{
symbolTableEntryType *targetSymbol;
valueType *target;
valueType **targetPtr;
anyOldThing *targetThing;
valueType *object;
valueType *result;
valueKindType kindOfTarget;
valueKindType newKindOfValue;
symbolInContextType *targetContext;
bool stringAssign;
char *charPtr;
char objectChar;
nullEvaluate(assignmentTerm);
sideEffectFlag = TRUE;
stringAssign = FALSE;
if (assignmentTerm->leftArgument->kindOfTerm == IDENTIFIER_EXPR) {
targetSymbol = effectiveSymbol(assignmentTerm->leftArgument->
expressionTerm.identifierUnion, &targetContext);
if (isAssignable(targetContext)) {
if ((target = targetContext->value) == NULL &&
(assignmentKindType)assignmentTerm->binop !=
ASSIGN_ASSIGN) {
error(OPERATOR_ASSIGNMENT_ON_NULL_TARGET_ERROR, tokenString(
assignmentTerm->binop));
return(object); /* wrong --needs evaluation */
}
targetPtr = &(targetContext->value);
expand(moreExpression("%s %s ", symbName(targetSymbol),
assignmentString(assignmentTerm->binop)));
} else {
if (targetContext->usage == DEAD_SYMBOL || targetContext->usage ==
UNKNOWN_SYMBOL || targetContext->usage ==
NESTED_UNKNOWN_SYMBOL) {
fail1(UNDECLARED_VARIABLE_ERROR, symbName(targetSymbol));
} else {
fail2(UNASSIGNABLE_SYMBOL_TYPE_ERROR, symbName(targetSymbol),
usageString(targetContext->usage));
}
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
} else {
targetThing = arrayLookup(assignmentTerm->leftArgument->
expressionTerm.arrayUnion, &kindOfTarget);
if (kindOfTarget == FAIL) {
return(newValue(FAIL, 0, EXPRESSION_OPND));
} else if (kindOfTarget == ARRAY_VALUE) {
targetPtr = (valueType **) targetThing;
target = *targetPtr;
} else if (kindOfTarget == STRING_VALUE) {
charPtr = (char *) targetThing;
stringAssign = TRUE;
}
}
if (isUndefined(object = evaluateExpressionInternally(assignmentTerm->
rightArgument, FALSE, kindOfFixup, FALSE))) {
result = makeUndefinedValue();
result->addressMode = object->addressMode;
return(result);
} else if (object->kindOfValue == FAIL) {
return(object); /* we can use it as it's a failure */
}
if (stringAssign) {
if (object->kindOfValue == ABSOLUTE_VALUE) {
objectChar = object->value & 0xFF;
} else {
fail(NON_CHARACTER_STRING_ASSIGNMENT_ERROR);
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
}
switch (assignmentTerm->binop) {
case ASSIGN_ASSIGN:
if (stringAssign) {
*charPtr = objectChar;
} else if (target == NULL) {
*targetPtr = object;
dupValue(result, object);
return(result);
} else {
newKindOfValue = object->kindOfValue;
target->value = object->value;
}
break;
case ADD_ASSIGN:
if (stringAssign)
*charPtr += objectChar;
else if ((newKindOfValue = addValueKind(target, object)) !=
FAIL)
target->value += object->value;
break;
case AND_ASSIGN:
if (stringAssign)
*charPtr &= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value &= object->value;
break;
case DIV_ASSIGN:
if (stringAssign)
*charPtr /= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value /= object->value;
break;
case LEFT_SHIFT_ASSIGN:
if (stringAssign)
*charPtr <<= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value <<= object->value;
break;
case MOD_ASSIGN:
if (stringAssign)
*charPtr %= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value %= object->value;
break;
case MUL_ASSIGN:
if (stringAssign)
*charPtr *= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value *= object->value;
break;
case OR_ASSIGN:
if (stringAssign)
*charPtr |= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value |= object->value;
break;
case RIGHT_SHIFT_ASSIGN:
if (stringAssign)
*charPtr >>= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value >>= object->value;
break;
case SUB_ASSIGN:
if (stringAssign)
*charPtr -= objectChar;
else if ((newKindOfValue = subValueKind(target, object)) !=
FAIL)
target->value -= object->value;
break;
case XOR_ASSIGN:
if (stringAssign)
*charPtr ^= objectChar;
else if ((newKindOfValue = opValueKind(target, object)) !=
FAIL)
target->value ^= object->value;
break;
case NO_ASSIGN:
botch("try to assign with NO_ASSIGN\n");
break;
default:
botch("bad assignment kind\n");
break;
}
if (newKindOfValue == FAIL) {
fail1(INCOMPATIBLE_ASSIGNMENT_OPERANDS_ERROR,
assignmentString(assignmentTerm->binop));
target->value = 0;
}
if (stringAssign) {
result = newValue(ABSOLUTE_VALUE, *charPtr, EXPRESSION_OPND);
} else {
target->kindOfValue = newKindOfValue;
dupValue(result, target);
}
return(result);
}
valueType *
evaluateBinopTerm(binopTermType *binopTerm, bool isTopLevel, fixupKindType kindOfFixup)
{
valueType *leftOperand;
valueType *rightOperand;
symbolTableEntryType *rightSelection;
valueKindType resultKindOfValue;
int resultValue;
operandKindType resultAddressMode;
valueType *result;
nullEvaluate(binopTerm);
if (binopTerm->binop != SUB && binopTerm->binop != ADD)
isTopLevel = FALSE;
leftOperand = evaluateExpressionInternally(binopTerm->leftArgument,
isTopLevel, kindOfFixup, FALSE);
expand(moreExpression("%s", tokenString(binopTerm->binop)));
if (binopTerm->binop != ADD)
isTopLevel = FALSE;
if (binopTerm->binop == SELECT) {
expand(moreExpression("%s", symbName((symbolTableEntryType *)
binopTerm->rightArgument)));
dupValue(rightOperand, getWorkingContext(
(symbolTableEntryType *)(binopTerm->rightArgument))->
value);
} else {
rightOperand = evaluateExpressionInternally(binopTerm->
rightArgument, FALSE, kindOfFixup, FALSE);
}
if (isLogicalOp(binopTerm->binop)) {
resultAddressMode = EXPRESSION_OPND;
} else {
resultAddressMode = leftOperand->addressMode;
if (leftOperand->addressMode!=EXPRESSION_OPND &&
rightOperand->addressMode!=EXPRESSION_OPND) {
error(MULTIPLE_ADDRESS_MODES_ERROR);
qfree2(leftOperand, rightOperand);
return(newValue(FAIL, 0, EXPRESSION_OPND));
} else if (rightOperand->addressMode != EXPRESSION_OPND) {
resultAddressMode = rightOperand->addressMode;
}
}
if ((isUndefined(leftOperand) && !isFailure(rightOperand)) ||
(isUndefined(rightOperand) && !isFailure(leftOperand))) {
qfree2(leftOperand, rightOperand);
result = makeUndefinedValue();
result->addressMode = resultAddressMode;
return(result);
}
switch (binopTerm->binop) {
case ADD:
if ((resultKindOfValue = addValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value +
rightOperand->value;
break;
case ASSIGN:
botch("assignment leaked thru to binop\n");
break;
case BITWISE_AND:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value &
rightOperand->value;
break;
case BITWISE_OR:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value |
rightOperand->value;
break;
case BITWISE_XOR:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value ^
rightOperand->value;
break;
case DIV:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
if (rightOperand->value == 0) {
fail(DIVIDE_BY_ZERO_ERROR);
resultKindOfValue = FAIL;
} else {
resultValue = leftOperand->value /
rightOperand->value;
}
break;
case EQUAL_TO:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value ==
rightOperand->value;
break;
case GREATER_THAN:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value >
rightOperand->value;
break;
case GREATER_THAN_OR_EQUAL_TO:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value >=
rightOperand->value;
break;
case LEFT_SHIFT:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value <<
rightOperand->value;
break;
case LESS_THAN:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value <
rightOperand->value;
break;
case LESS_THAN_OR_EQUAL_TO:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value <=
rightOperand->value;
break;
case LOGICAL_AND:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value &&
rightOperand->value;
break;
case LOGICAL_OR:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value ||
rightOperand->value;
break;
case LOGICAL_XOR:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = logicalXOR(leftOperand->value,
rightOperand->value);
break;
case MOD:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value %
rightOperand->value;
break;
case MUL:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value *
rightOperand->value;
break;
case NOT_EQUAL_TO:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value !=
rightOperand->value;
break;
case RIGHT_SHIFT:
if ((resultKindOfValue = opValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value >>
rightOperand->value;
break;
case SELECT:
if ((resultKindOfValue = selectValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value +
rightOperand->value;
break;
case SUB:
if ((resultKindOfValue = subValueKind(leftOperand,
rightOperand)) != FAIL)
resultValue = leftOperand->value -
rightOperand->value;
break;
default:
botch("bad binop kind\n");
break;
}
if (resultKindOfValue == FAIL) {
resultValue = 0;
fail1(INCOMPATIBLE_BINOP_OPERANDS_ERROR,
tokenString(binopTerm->binop));
}
qfree2(leftOperand, rightOperand);
return(newValue(resultKindOfValue, resultValue, resultAddressMode));
}
valueType *
evaluateCondition(conditionType condition)
{
expand(moreExpression("%s", conditionString(condition)));
return(newValue(CONDITION_VALUE, condition, EXPRESSION_OPND));
}
valueType *
evaluateBuiltInFunctionCall(symbolInContextType *workingContext, operandListType *parameters, fixupKindType kindOfFixup)
{
sideEffectFlag = TRUE;
return((*builtInFunctionTable[workingContext->value->value].
functionEntry)(parameters, kindOfFixup));
}
valueType *
evaluateFunctionCall(functionCallTermType *functionCall, fixupKindType kindOfFixup, bool isStandalone)
{
functionDefinitionType *theFunction;
int numberBound;
identifierListType *savedLocalVariableList;
int savedLabelTagNumber;
stringType *savedFunctionName;
bool savedErrorFlag;
bool savedBeneathFunction;
symbolInContextType *workingContext;
environmentType newEnvironment;
valueType *result;
bool saveExpansion;
nullEvaluate(functionCall);
sideEffectFlag = TRUE;
pushEnvironment(newEnvironment);
resultOfLastFunctionCall = NULL;
freturnExit = FALSE;
workingContext = getWorkingContext(functionCall->functionName);
expand(moreExpression("%s(", symbName(functionCall->functionName)));
if (isBuiltInFunction(workingContext)) {
popEnvironment();
result = evaluateBuiltInFunctionCall(workingContext,
functionCall->parameters, kindOfFixup);
expand(moreExpression(")"));
return(result);
} if (isFunction(workingContext)) {
theFunction = (functionDefinitionType *)workingContext->
value->value;
} else {
error(NOT_A_FUNCTION_ERROR, symbName(functionCall->
functionName));
popEnvironment();
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
savedLocalVariableList = currentLocalVariableList;
currentLocalVariableList = NULL;
savedLabelTagNumber = currentLabelTagNumber;
savedFunctionName = currentFunctionName;
currentFunctionName = symbName(theFunction->functionName);
currentLabelTagNumber = nextLabelTagNumber++;
savedErrorFlag = errorFlag;
savedBeneathFunction = beneathFunction;
errorFlag = FALSE;
if ((numberBound = bindFunctionArguments(theFunction->arguments,
functionCall->parameters, symbName(
theFunction->functionName))) > 0) {
expansionOff();
beneathFunction = TRUE;
assembleBlock(theFunction->body);
freturnExit = FALSE;
expansionOn();
} else
numberBound = -numberBound;
if (numberBound > 1)
unbindArguments(theFunction->arguments, numberBound-1);
unbindLocalVariables(currentLocalVariableList);
beneathFunction = savedBeneathFunction;
expand(moreExpression(")"));
currentLabelTagNumber = savedLabelTagNumber;
currentLocalVariableList = savedLocalVariableList;
currentFunctionName = savedFunctionName;
if (errorFlag)
error(ERROR_INSIDE_FUNCTION_ERROR, symbName(theFunction->
functionName));
else
errorFlag = savedErrorFlag;
popEnvironment();
if (resultOfLastFunctionCall != NULL) {
return(resultOfLastFunctionCall);
} else {
if (!isStandalone)
error(FUNCTION_DID_NOT_RETURN_A_VALUE_ERROR, symbName(
theFunction->functionName));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
}
valueType *
evaluateHere(void)
{
valueType *result;
expand(moreExpression("here"));
result = newValue(currentLocationCounter.kindOfValue,
currentLocationCounter.value, EXPRESSION_OPND);
result->value -= targetOffset;
return(result);
}
valueType *
evaluateIdentifier(symbolTableEntryType *identifier, bool isTopLevel, fixupKindType kindOfFixup)
{
symbolInContextType *workingContext;
valueType *resultValue;
valueType *result;
environmentType *saveEnvironment;
bool saveExpansion;
nullEvaluate(identifier);
identifier->referenceCount++;
if (symbName(identifier)[0] == '$')
identifier = generateLocalLabel(identifier);
if ((workingContext = getWorkingContext(identifier)) == NULL) {
fail1(UNDEFINED_SYMBOL_ERROR, symbName(identifier));
expand(moreExpression("%s", symbName(identifier)));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
if (workingContext->usage == DEAD_SYMBOL) {
reincarnateSymbol(workingContext, UNKNOWN_SYMBOL);
}
if (workingContext->usage == FUNCTION_SYMBOL || workingContext->usage
== BUILT_IN_FUNCTION_SYMBOL) {
fail1(FUNCTION_IS_NOT_A_VALUE_ERROR, symbName(identifier));
expand(moreExpression("%s", symbName(identifier)));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
if (workingContext->value == NULL) {
if (kindOfFixup == NO_FIXUP) {
fail1(UNDEFINED_SYMBOL_ERROR, symbName(identifier));
expand(moreExpression("%s", symbName(identifier)));
return(newValue(FAIL, 0, EXPRESSION_OPND));
} else if (kindOfFixup != NO_FIXUP_OK) {
expand(moreExpression("%s", symbName(identifier)));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
} else {
resultValue = workingContext->value;
if (workingContext->value->kindOfValue == UNDEFINED_VALUE){
if (kindOfFixup==NO_FIXUP ||
(workingContext->usage!=LABEL_SYMBOL &&
workingContext->usage!=EXTERNAL_SYMBOL &&
workingContext->usage!=UNKNOWN_SYMBOL &&
workingContext->usage!=NESTED_UNKNOWN_SYMBOL)) {
expand(moreExpression("%s", symbName(
identifier)));
if ((workingContext->attributes & GLOBAL_ATT)
!=0 && performingFixups) {
return(newValue(UNDEFINED_VALUE, 0,
resultValue->addressMode));
} else {
fail1(UNDEFINED_SYMBOL_ERROR,
symbName(identifier));
return(newValue(FAIL, 0,
EXPRESSION_OPND));
}
} else if (kindOfFixup == NO_FIXUP_OK) {
expand(moreExpression("%s", symbName(
identifier)));
return(newValue(UNDEFINED_VALUE, 0,
EXPRESSION_OPND));
}
} else if (workingContext->value->kindOfValue == FAIL) {
fail1(UNASSIGNED_SYMBOL_ERROR, symbName(identifier));
expand(moreExpression("%s", symbName(identifier)));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
if (workingContext->value->kindOfValue == OPERAND_VALUE) {
saveEnvironment = currentEnvironment;
if (workingContext->usage == ARGUMENT_SYMBOL) {
currentEnvironment = currentEnvironment->
previousEnvironment;
expand(shouldParenthesize(workingContext->
value->value) ? moreExpression("(") :
0);
} else {
expand(moreExpression("%s",
symbName(identifier)));
expansionOff();
}
resultValue = evaluateOperand(workingContext->
value->value);
if (workingContext->usage == ARGUMENT_SYMBOL) {
expand(shouldParenthesize(workingContext->
value->value) ? moreExpression(")") :
0);
} else {
expansionOn();
}
currentEnvironment = saveEnvironment;
} else if (workingContext->value->kindOfValue == BLOCK_VALUE){
sideEffectFlag = TRUE;
saveEnvironment = currentEnvironment;
currentEnvironment = currentEnvironment->
previousEnvironment;
expand((moreText("{"), endLine(), tabCount++));
assembleBlock(workingContext->value->value);
expand((tabCount--, tabIndent(), moreText("}"),
endLine()));
currentEnvironment = saveEnvironment;
return(newValue(UNDEFINED_VALUE, 0, EXPRESSION_OPND));
} else if (workingContext->usage==MVARIABLE_SYMBOL ||
workingContext->usage==VARIABLE_SYMBOL ||
workingContext->usage==MDEFINE_SYMBOL) {
expand(workingContext->value->kindOfValue==
ABSOLUTE_VALUE ? moreExpression("0x%x",
workingContext->value->value) : (
workingContext->value->kindOfValue==
STRING_VALUE ? moreExpression("\"%s\"",
workingContext->value->value) : 0));
} else {
expand(moreExpression("%s", symbName(identifier)));
}
dupValue(result, resultValue);
if (result->kindOfValue != UNDEFINED_VALUE)
workingContext->referenceCount += 1;
if (result->kindOfValue==RELOCATABLE_VALUE && (kindOfFixup!=
NO_FIXUP || performingFixups))
result->value = 0; /* it'll be relocated */
return(result);
}
}
valueType *
evaluateNumber(numberTermType number)
{
expand(moreExpression("0x%x", number));
return(newValue(ABSOLUTE_VALUE, number, EXPRESSION_OPND));
}
valueType *
evaluatePostopTerm(postOpTermType *postopTerm)
{
valueType *theOperand;
valueType **theOperandPtr;
valueKindType kindOfOperand;
valueType *result;
symbolInContextType *workingContext;
symbolTableEntryType *targetSymbol;
nullEvaluate(postopTerm);
sideEffectFlag = TRUE;
if (postopTerm->postOpArgument->kindOfTerm == IDENTIFIER_EXPR) {
targetSymbol = effectiveSymbol(postopTerm->postOpArgument->
expressionTerm.identifierUnion, &workingContext);
if (workingContext != NULL)
theOperand = workingContext->value;
else
theOperand = NULL;
} else {
theOperandPtr = (valueType **) arrayLookup(postopTerm->
postOpArgument->expressionTerm.arrayUnion,
&kindOfOperand);
if (kindOfOperand == FAIL)
theOperand = NULL;
else if (kindOfOperand == ARRAY_VALUE)
theOperand = *theOperandPtr;
else {
fail(CANT_POSTPREOP_STRING_ERROR);
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
}
switch (postopTerm->postOp) {
case INCREMENT:
if (incrementable(theOperand)) {
expand(moreExpression("%s++",symbName(targetSymbol)));
dupValue(result, theOperand);
theOperand->value += 1;
return(result);
} else {
fail1(UNPOSTINCREMENTABLE_OPERAND_ERROR,
valueKindString(theOperand->kindOfValue));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
break;
case DECREMENT:
if (decrementable(theOperand)) {
expand(moreExpression("%s--",symbName(targetSymbol)));
dupValue(result, theOperand);
theOperand->value -= 1;
return(result);
} else {
fail1(UNPOSTDECREMENTABLE_OPERAND_ERROR,
valueKindString(theOperand->kindOfValue));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
break;
default:
botch("bad postop type\n");
break;
}
}
valueType *
evaluatePreopTerm(preOpTermType *preopTerm)
{
valueType *theOperand;
valueType *result;
valueType **theOperandPtr;
valueKindType kindOfOperand;
symbolInContextType *workingContext;
symbolTableEntryType *targetSymbol;
nullEvaluate(preopTerm);
sideEffectFlag = TRUE;
if (preopTerm->preOpArgument->kindOfTerm == IDENTIFIER_EXPR) {
targetSymbol = effectiveSymbol(preopTerm->preOpArgument->
expressionTerm.identifierUnion, &workingContext);
if (workingContext != NULL)
theOperand = workingContext->value;
else
theOperand = NULL;
} else {
theOperandPtr = (valueType **) arrayLookup(preopTerm->
preOpArgument->expressionTerm.arrayUnion,
&kindOfOperand);
if (kindOfOperand == FAIL)
theOperand = NULL;
else if (kindOfOperand == ARRAY_VALUE)
theOperand = *theOperandPtr;
else {
fail(CANT_POSTPREOP_STRING_ERROR);
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
}
switch (preopTerm->preOp) {
case INCREMENT:
if (incrementable(theOperand)) {
expand(moreExpression("%++s",symbName(targetSymbol)));
theOperand->value += 1;
dupValue(result, theOperand);
return(result);
} else {
fail1(UNPREINCREMENTABLE_OPERAND_ERROR,
valueKindString(theOperand->kindOfValue));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
break;
case DECREMENT:
if (decrementable(theOperand)) {
expand(moreExpression("%--s",symbName(targetSymbol)));
theOperand->value -= 1;
dupValue(result, theOperand);
return(result);
} else {
fail1(UNPREDECREMENTABLE_OPERAND_ERROR,
valueKindString(theOperand->kindOfValue));
return(newValue(FAIL, 0, EXPRESSION_OPND));
}
break;
default:
botch("bad preop type\n");
break;
}
}
valueType *
evaluateString(stringType *string)
{
stringType *newString;
expand(moreExpression("\"%s\"", string));
newString = (stringType *)malloc(strlen(string)+1);
strcpy(newString, string);
return(newValue(STRING_VALUE, newString, EXPRESSION_OPND));
}
valueType *
evaluateUnopTerm(unopTermType *unopTerm, fixupKindType kindOfFixup)
{
valueType *theOperand;
valueKindType resultKindOfValue;
int resultValue;
operandKindType resultAddressMode;
valueType *result;
nullEvaluate(unopTerm);
expand(moreExpression("%s", tokenString(unopTerm->unop)));
theOperand = evaluateExpressionInternally(unopTerm->unopArgument,
FALSE, kindOfFixup, FALSE);
resultAddressMode = theOperand->addressMode;
if (isUndefined(theOperand)) {
qfree(theOperand);
result = makeUndefinedValue();
result->addressMode = resultAddressMode;
return(result);
}
if ((resultKindOfValue = unopValueKind(theOperand)) != FAIL) {
switch (unopTerm->unop) {
case BITWISE_NOT:
resultValue = ~theOperand->value;
break;
case HI_BYTE:
resultValue = (theOperand->value>>8) & 0xFF;
break;
case LO_BYTE:
resultValue = theOperand->value & 0xFF;
break;
case LOGICAL_NOT:
resultValue = !theOperand->value;
break;
case UNARY_MINUS:
resultValue = -theOperand->value;
break;
}
} else {
fail1(INCOMPATIBLE_UNOP_OPERAND_ERROR, tokenString(unopTerm->
unop));
resultValue = 0;
}
qfree(theOperand);
return(newValue(resultKindOfValue, resultValue, resultAddressMode));
}
valueType *
evaluateExpressionInternally(expressionType *expression, bool isTopLevel, fixupKindType kindOfFixup, bool isStandalone)
{
valueType *result;
nullEvaluate(expression);
switch (expression->kindOfTerm) {
case ARRAY_EXPR:
return(evaluateArrayTerm(expression->expressionTerm.arrayUnion));
break;
case ASSIGN_EXPR:
return(evaluateAssignmentTerm(expression->expressionTerm.binopUnion,
kindOfFixup));
break;
case BINOP_EXPR:
return(evaluateBinopTerm(expression->expressionTerm.binopUnion,
isTopLevel, kindOfFixup));
break;
case CONDITION_CODE_EXPR:
return(evaluateCondition(expression->expressionTerm.conditionTypeUnion));
break;
case FUNCTION_CALL_EXPR:
return(evaluateFunctionCall(expression->expressionTerm.functionCallUnion,
kindOfFixup, isStandalone));
break;
case HERE_EXPR:
return(evaluateHere());
break;
case IDENTIFIER_EXPR:
result = evaluateIdentifier(expression->expressionTerm.symbolTableUnion,
isTopLevel, kindOfFixup);
return(result);
break;
case NUMBER_EXPR:
return(evaluateNumber(expression->expressionTerm.numberUnion));
break;
case POSTOP_EXPR:
return(evaluatePostopTerm(expression->expressionTerm.postOpUnion));
break;
case PREOP_EXPR:
return(evaluatePreopTerm(expression->expressionTerm.preOpUnion));
break;
case SUBEXPRESSION_EXPR:
expand(moreExpression("("));
result = evaluateExpressionInternally(expression->
expressionTerm.expressionUnion, isTopLevel, kindOfFixup, FALSE);
expand(moreExpression(")"));
return(result);
break;
case STRING_EXPR:
return(evaluateString(expression->expressionTerm.stringUnion));
break;
case UNOP_EXPR:
return(evaluateUnopTerm(expression->expressionTerm.unopUnion,
kindOfFixup));
break;
case VALUE_EXPR:
if (expression->expressionTerm.valueUnion->kindOfValue ==
OPERAND_VALUE) {
return(evaluateOperand(expression->expressionTerm.
valueUnion->value));
} else {
dupValue(result, expression->expressionTerm.
valueUnion);
expand(moreExpression("0x%x", result->value));
return(result);
}
break;
default:
botch("evaluateExpression: funny expression kind %d\n",
expression->kindOfTerm);
break;
}
}
valueType *
evaluateExpression(expressionType *expression, fixupKindType kindOfFixup)
{
valueType *result;
nullEvaluate(expression);
expressionFailed = FALSE;
referencesToNote[currentOperandNumber] = NULL;
result = evaluateExpressionInternally(expression, TRUE, kindOfFixup,
FALSE);
if (result->kindOfValue == RELOCATABLE_VALUE) {
result->kindOfValue = UNDEFINED_VALUE;
result->value = 0; /* fix linker bug */
}
if (isUndefined(result)) {
flushExpressionString();
pendingFixup[currentOperandNumber] = expression;
} else
pendingFixup[currentOperandNumber] = NULL;
return(result);
}
void
evaluateExpressionStandalone(expressionType *expression)
{
bool saveExpansion;
valueType *expressionResult;
expressionFailed = FALSE;
referencesToNote[currentOperandNumber] = NULL;
standaloneExpansionFlag = amExpanding();
expansionOff();
expressionResult = evaluateExpressionInternally(expression, TRUE,
NO_FIXUP, TRUE);
expansionOn();
standaloneExpansionFlag = FALSE;
if (expressionResult != NULL)
qfree(expressionResult);
pendingFixup[0] = NULL;
}
valueType *
evaluateDefineExpression(expressionType *expression)
{
nullEvaluate(expression);
return(newValue(OPERAND_VALUE, buildOperand(EXPRESSION_OPND,
generateFixupExpression(expression)), EXPRESSION_OPND));
}
valueType *
evaluateSelectionList(selectionListType *selectionList)
{
int offset;
offset = 0;
while (selectionList != NULL) {
expand(moreExpression(".%s", symbName(selectionList->
theSymbol)));
offset += fieldValue(selectionList->theSymbol);
selectionList = selectionList->nextIdentifier;
}
return(newValue(ABSOLUTE_VALUE, offset, EXPRESSION_OPND));
}