1831 lines
72 KiB
C
1831 lines
72 KiB
C
/* picoc expression evaluator - a stack-based expression evaluation system
|
|
* which handles operator precedence */
|
|
|
|
#include "interpreter.h"
|
|
|
|
/* whether evaluation is left to right for a given precedence level */
|
|
#define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 14)
|
|
#define BRACKET_PRECEDENCE (20)
|
|
|
|
/* If the destination is not float, we can't assign a floating value to it,
|
|
we need to convert it to integer instead */
|
|
#define ASSIGN_FP_OR_INT(value) \
|
|
if (IS_FP(BottomValue)) { \
|
|
ResultFP = ExpressionAssignFP(Parser, BottomValue, value); \
|
|
} else { \
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue, (long)(value), false); \
|
|
ResultIsInt = true; }
|
|
|
|
#define DEEP_PRECEDENCE (BRACKET_PRECEDENCE*1000)
|
|
|
|
/* local prototypes */
|
|
enum OperatorOrder
|
|
{
|
|
OrderNone,
|
|
OrderPrefix,
|
|
OrderInfix,
|
|
OrderPostfix
|
|
};
|
|
|
|
/* a stack of expressions we use in evaluation */
|
|
struct ExpressionStack
|
|
{
|
|
struct ExpressionStack *Next; /* the next lower item on the stack */
|
|
struct Value *Val; /* the value for this stack node */
|
|
enum LexToken Op; /* the operator */
|
|
short unsigned int Precedence; /* the operator precedence of this node */
|
|
unsigned char Order; /* the evaluation order of this operator */
|
|
};
|
|
|
|
/* operator precedence definitions */
|
|
struct OpPrecedence
|
|
{
|
|
unsigned int PrefixPrecedence:4;
|
|
unsigned int PostfixPrecedence:4;
|
|
unsigned int InfixPrecedence:4;
|
|
char *Name;
|
|
};
|
|
|
|
/* NOTE: the order of this array must correspond exactly to the order of
|
|
these tokens in enum LexToken */
|
|
static struct OpPrecedence OperatorPrecedence[] =
|
|
{
|
|
/* TokenNone, */ {0, 0, 0, "none"},
|
|
/* TokenComma, */ {0, 0, 0, ","},
|
|
/* TokenAssign, */ {0, 0, 2, "="},
|
|
/* TokenAddAssign, */ {0, 0, 2, "+="},
|
|
/* TokenSubtractAssign, */ {0, 0, 2, "-="},
|
|
/* TokenMultiplyAssign, */ {0, 0, 2, "*="},
|
|
/* TokenDivideAssign, */ { 0, 0, 2, "/=" },
|
|
/* TokenModulusAssign, */ { 0, 0, 2, "%=" },
|
|
/* TokenShiftLeftAssign, */ {0, 0, 2, "<<="},
|
|
/* TokenShiftRightAssign, */ { 0, 0, 2, ">>=" },
|
|
/* TokenArithmeticAndAssign, */ { 0, 0, 2, "&=" },
|
|
/* TokenArithmeticOrAssign, */ {0, 0, 2, "|="},
|
|
/* TokenArithmeticExorAssign, */ { 0, 0, 2, "^=" },
|
|
/* TokenQuestionMark, */ {0, 0, 3, "?"},
|
|
/* TokenColon, */ {0, 0, 3, ":" },
|
|
/* TokenLogicalOr, */ {0, 0, 4, "||"},
|
|
/* TokenLogicalAnd, */ {0, 0, 5, "&&"},
|
|
/* TokenArithmeticOr, */ {0, 0, 6, "|"},
|
|
/* TokenArithmeticExor, */ {0, 0, 7, "^"},
|
|
/* TokenAmpersand, */ {14, 0, 8, "&"},
|
|
/* TokenEqual, */ {0, 0, 9, "=="},
|
|
/* TokenNotEqual, */ {0, 0, 9, "!="},
|
|
/* TokenLessThan, */ {0, 0, 10, "<"},
|
|
/* TokenGreaterThan, */ {0, 0, 10, ">"},
|
|
/* TokenLessEqual, */ {0, 0, 10, "<="},
|
|
/* TokenGreaterEqual, */ {0, 0, 10, ">="},
|
|
/* TokenShiftLeft, */ {0, 0, 11, "<<"},
|
|
/* TokenShiftRight, */ {0, 0, 11, ">>"},
|
|
/* TokenPlus, */ {14, 0, 12, "+"},
|
|
/* TokenMinus, */ {14, 0, 12, "-"},
|
|
/* TokenAsterisk, */ {14, 0, 13, "*"},
|
|
/* TokenSlash, */ {0, 0, 13, "/"},
|
|
/* TokenModulus, */ {0, 0, 13, "%"},
|
|
/* TokenIncrement, */ {14, 15, 0, "++"},
|
|
/* TokenDecrement, */ {14, 15, 0, "--"},
|
|
/* TokenUnaryNot, */ {14, 0, 0, "!"},
|
|
/* TokenUnaryExor, */ {14, 0, 0, "~"},
|
|
/* TokenSizeof, */ {14, 0, 0, "sizeof"},
|
|
/* TokenCast, */ {14, 0, 0, "cast"},
|
|
/* TokenLeftSquareBracket, */ {0, 0, 15, "["},
|
|
/* TokenRightSquareBracket, */ {0, 15, 0, "]"},
|
|
/* TokenDot, */ {0, 0, 15, "."},
|
|
/* TokenArrow, */ {0, 0, 15, "->"},
|
|
/* TokenOpenBracket, */ {15, 0, 0, "("},
|
|
/* TokenCloseBracket, */ {0, 15, 0, ")"}
|
|
};
|
|
|
|
void ExpressionParseFunctionCall(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, const char *FuncName, int RunIt);
|
|
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
/* show the contents of the expression stack */
|
|
void ExpressionStackShow(Picoc *pc, struct ExpressionStack *StackTop)
|
|
{
|
|
printf("Expression stack [0x%lx,0x%lx]: ", (long)pc->HeapStackTop, (long)StackTop);
|
|
|
|
while (StackTop != NULL) {
|
|
if (StackTop->Order == OrderNone) {
|
|
/* it's a value */
|
|
if (StackTop->Val->IsLValue)
|
|
printf("lvalue=");
|
|
else
|
|
printf("value=");
|
|
|
|
switch (StackTop->Val->Typ->Base) {
|
|
case TypeVoid:
|
|
printf("void");
|
|
break;
|
|
case TypeInt:
|
|
printf("%d:int", StackTop->Val->Val->Integer);
|
|
break;
|
|
case TypeShort:
|
|
printf("%d:short", StackTop->Val->Val->ShortInteger);
|
|
break;
|
|
case TypeChar:
|
|
printf("%d:char", StackTop->Val->Val->Character);
|
|
break;
|
|
case TypeLong:
|
|
printf("%ld:long", StackTop->Val->Val->LongInteger);
|
|
break;
|
|
case TypeUnsignedShort:
|
|
printf("%d:unsigned short", StackTop->Val->Val->UnsignedShortInteger);
|
|
break;
|
|
case TypeUnsignedInt:
|
|
printf("%d:unsigned int", StackTop->Val->Val->UnsignedInteger);
|
|
break;
|
|
case TypeUnsignedLong:
|
|
printf("%ld:unsigned long", StackTop->Val->Val->UnsignedLongInteger);
|
|
break;
|
|
case TypeFP:
|
|
printf("%f:fp", StackTop->Val->Val->FP);
|
|
break;
|
|
case TypeFunction:
|
|
printf("%s:function", StackTop->Val->Val->Identifier);
|
|
break;
|
|
case TypeMacro:
|
|
printf("%s:macro", StackTop->Val->Val->Identifier);
|
|
break;
|
|
case TypePointer:
|
|
if (StackTop->Val->Val->Pointer == NULL)
|
|
printf("ptr(NULL)");
|
|
else if (StackTop->Val->Typ->FromType->Base == TypeChar)
|
|
printf("\"%s\":string", (char *)StackTop->Val->Val->Pointer);
|
|
else
|
|
printf("ptr(0x%lx)", (long)StackTop->Val->Val->Pointer);
|
|
break;
|
|
case TypeArray:
|
|
printf("array");
|
|
break;
|
|
case TypeStruct:
|
|
printf("%s:struct", StackTop->Val->Val->Identifier);
|
|
break;
|
|
case TypeUnion:
|
|
printf("%s:union", StackTop->Val->Val->Identifier);
|
|
break;
|
|
case TypeEnum:
|
|
printf("%s:enum", StackTop->Val->Val->Identifier);
|
|
break;
|
|
case Type_Type:
|
|
PrintType(StackTop->Val->Val->Typ, pc->CStdOut);
|
|
printf(":type");
|
|
break;
|
|
default:
|
|
printf("unknown");
|
|
break;
|
|
}
|
|
printf("[0x%lx,0x%lx]", (long)StackTop, (long)StackTop->Val);
|
|
} else {
|
|
/* it's an operator */
|
|
printf("op='%s' %s %d", OperatorPrecedence[(int)StackTop->Op].Name,
|
|
(StackTop->Order == OrderPrefix) ?
|
|
"prefix" : ((StackTop->Order == OrderPostfix) ? "postfix" : "infix"),
|
|
StackTop->Precedence);
|
|
printf("[0x%lx]", (long)StackTop);
|
|
}
|
|
|
|
StackTop = StackTop->Next;
|
|
if (StackTop != NULL)
|
|
printf(", ");
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
int IsTypeToken(struct ParseState * Parser, enum LexToken t,
|
|
struct Value * LexValue)
|
|
{
|
|
if (t >= TokenIntType && t <= TokenUnsignedType)
|
|
return 1; /* base type */
|
|
|
|
/* typedef'ed type? */
|
|
if (t == TokenIdentifier) {
|
|
/* see TypeParseFront, case TokenIdentifier and ParseTypedef */
|
|
struct Value * VarValue;
|
|
if (VariableDefined(Parser->pc, LexValue->Val->Pointer)) {
|
|
VariableGet(Parser->pc, Parser, LexValue->Val->Pointer, &VarValue);
|
|
if (VarValue->Typ == &Parser->pc->TypeType)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
long ExpressionCoerceInteger(struct Value *Val)
|
|
{
|
|
switch (Val->Typ->Base) {
|
|
case TypeInt: return (long)Val->Val->Integer;
|
|
case TypeChar: return (long)Val->Val->Character;
|
|
case TypeShort: return (long)Val->Val->ShortInteger;
|
|
case TypeLong: return (long)Val->Val->LongInteger;
|
|
case TypeUnsignedInt: return (long)Val->Val->UnsignedInteger;
|
|
case TypeUnsignedShort: return (long)Val->Val->UnsignedShortInteger;
|
|
case TypeUnsignedLong: return (long)Val->Val->UnsignedLongInteger;
|
|
case TypeUnsignedChar: return (long)Val->Val->UnsignedCharacter;
|
|
case TypePointer: return (long)Val->Val->Pointer;
|
|
case TypeFP: return (long)Val->Val->FP;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
unsigned long ExpressionCoerceUnsignedInteger(struct Value *Val)
|
|
{
|
|
switch (Val->Typ->Base) {
|
|
case TypeInt: return (unsigned long)Val->Val->Integer;
|
|
case TypeChar: return (unsigned long)Val->Val->Character;
|
|
case TypeShort: return (unsigned long)Val->Val->ShortInteger;
|
|
case TypeLong: return (unsigned long)Val->Val->LongInteger;
|
|
case TypeUnsignedInt: return (unsigned long)Val->Val->UnsignedInteger;
|
|
case TypeUnsignedShort: return (unsigned long)Val->Val->UnsignedShortInteger;
|
|
case TypeUnsignedLong: return (unsigned long)Val->Val->UnsignedLongInteger;
|
|
case TypeUnsignedChar: return (unsigned long)Val->Val->UnsignedCharacter;
|
|
case TypePointer: return (unsigned long)Val->Val->Pointer;
|
|
case TypeFP: return (unsigned long)Val->Val->FP;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
double ExpressionCoerceFP(struct Value *Val)
|
|
{
|
|
int IntVal;
|
|
unsigned UnsignedVal;
|
|
|
|
switch (Val->Typ->Base) {
|
|
case TypeInt:
|
|
IntVal = Val->Val->Integer;
|
|
return (double)IntVal;
|
|
case TypeChar:
|
|
IntVal = Val->Val->Character;
|
|
return (double)IntVal;
|
|
case TypeShort:
|
|
IntVal = Val->Val->ShortInteger;
|
|
return (double)IntVal;
|
|
case TypeLong:
|
|
IntVal = Val->Val->LongInteger;
|
|
return (double)IntVal;
|
|
case TypeUnsignedInt:
|
|
UnsignedVal = Val->Val->UnsignedInteger;
|
|
return (double)UnsignedVal;
|
|
case TypeUnsignedShort:
|
|
UnsignedVal = Val->Val->UnsignedShortInteger;
|
|
return (double)UnsignedVal;
|
|
case TypeUnsignedLong:
|
|
UnsignedVal = Val->Val->UnsignedLongInteger;
|
|
return (double)UnsignedVal;
|
|
case TypeUnsignedChar:
|
|
UnsignedVal = Val->Val->UnsignedCharacter;
|
|
return (double)UnsignedVal;
|
|
case TypeFP:
|
|
return Val->Val->FP;
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
/* assign an integer value */
|
|
long ExpressionAssignInt(struct ParseState *Parser, struct Value *DestValue,
|
|
long FromInt, int After)
|
|
{
|
|
long Result;
|
|
|
|
if (!DestValue->IsLValue)
|
|
ProgramFail(Parser, "can't assign to this");
|
|
|
|
if (After)
|
|
Result = ExpressionCoerceInteger(DestValue);
|
|
else
|
|
Result = FromInt;
|
|
|
|
switch (DestValue->Typ->Base) {
|
|
case TypeInt: DestValue->Val->Integer = FromInt; break;
|
|
case TypeShort: DestValue->Val->ShortInteger = (short)FromInt; break;
|
|
case TypeChar: DestValue->Val->Character = (char)FromInt; break;
|
|
case TypeLong: DestValue->Val->LongInteger = (long)FromInt; break;
|
|
case TypeUnsignedInt: DestValue->Val->UnsignedInteger = (unsigned int)FromInt; break;
|
|
case TypeUnsignedShort: DestValue->Val->UnsignedShortInteger = (unsigned short)FromInt; break;
|
|
case TypeUnsignedLong: DestValue->Val->UnsignedLongInteger = (unsigned long)FromInt; break;
|
|
case TypeUnsignedChar: DestValue->Val->UnsignedCharacter = (unsigned char)FromInt; break;
|
|
default: break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
/* assign a floating point value */
|
|
double ExpressionAssignFP(struct ParseState *Parser, struct Value *DestValue,
|
|
double FromFP)
|
|
{
|
|
if (!DestValue->IsLValue)
|
|
ProgramFail(Parser, "can't assign to this");
|
|
|
|
DestValue->Val->FP = FromFP;
|
|
return FromFP;
|
|
}
|
|
|
|
/* push a node on to the expression stack */
|
|
void ExpressionStackPushValueNode(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct Value *ValueLoc)
|
|
{
|
|
struct ExpressionStack *StackNode = VariableAlloc(Parser->pc, Parser,
|
|
sizeof(struct ExpressionStack), false);
|
|
StackNode->Next = *StackTop;
|
|
StackNode->Val = ValueLoc;
|
|
*StackTop = StackNode;
|
|
#ifdef FANCY_ERROR_MESSAGES
|
|
StackNode->Line = Parser->Line;
|
|
StackNode->CharacterPos = Parser->CharacterPos;
|
|
#endif
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
ExpressionStackShow(Parser->pc, *StackTop);
|
|
#endif
|
|
}
|
|
|
|
/* push a blank value on to the expression stack by type */
|
|
struct Value *ExpressionStackPushValueByType(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct ValueType *PushType)
|
|
{
|
|
struct Value *ValueLoc = VariableAllocValueFromType(Parser->pc, Parser,
|
|
PushType, false, NULL, false);
|
|
ExpressionStackPushValueNode(Parser, StackTop, ValueLoc);
|
|
|
|
return ValueLoc;
|
|
}
|
|
|
|
/* push a value on to the expression stack */
|
|
void ExpressionStackPushValue(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct Value *PushValue)
|
|
{
|
|
struct Value *ValueLoc = VariableAllocValueAndCopy(Parser->pc, Parser,
|
|
PushValue, false);
|
|
ExpressionStackPushValueNode(Parser, StackTop, ValueLoc);
|
|
}
|
|
|
|
void ExpressionStackPushLValue(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct Value *PushValue, int Offset)
|
|
{
|
|
struct Value *ValueLoc = VariableAllocValueShared(Parser, PushValue);
|
|
ValueLoc->Val = (void *)((char *)ValueLoc->Val + Offset);
|
|
ExpressionStackPushValueNode(Parser, StackTop, ValueLoc);
|
|
}
|
|
|
|
void ExpressionStackPushDereference(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct Value *DereferenceValue)
|
|
{
|
|
int Offset;
|
|
int DerefIsLValue;
|
|
struct Value *DerefVal;
|
|
struct Value *ValueLoc;
|
|
struct ValueType *DerefType;
|
|
void *DerefDataLoc = VariableDereferencePointer(Parser, DereferenceValue,
|
|
&DerefVal, &Offset, &DerefType, &DerefIsLValue);
|
|
if (DerefDataLoc == NULL)
|
|
ProgramFail(Parser, "NULL pointer dereference");
|
|
|
|
ValueLoc = VariableAllocValueFromExistingData(Parser, DerefType,
|
|
(union AnyValue*)DerefDataLoc, DerefIsLValue, DerefVal);
|
|
ExpressionStackPushValueNode(Parser, StackTop, ValueLoc);
|
|
}
|
|
|
|
void ExpressionPushInt(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, long IntValue)
|
|
{
|
|
struct Value *ValueLoc = VariableAllocValueFromType(Parser->pc, Parser,
|
|
&Parser->pc->IntType, false, NULL, false);
|
|
ValueLoc->Val->Integer = IntValue;
|
|
ExpressionStackPushValueNode(Parser, StackTop, ValueLoc);
|
|
}
|
|
|
|
void ExpressionPushFP(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, double FPValue)
|
|
{
|
|
struct Value *ValueLoc = VariableAllocValueFromType(Parser->pc, Parser,
|
|
&Parser->pc->FPType, false, NULL, false);
|
|
ValueLoc->Val->FP = FPValue;
|
|
ExpressionStackPushValueNode(Parser, StackTop, ValueLoc);
|
|
}
|
|
|
|
/* assign to a pointer */
|
|
void ExpressionAssignToPointer(struct ParseState *Parser, struct Value *ToValue,
|
|
struct Value *FromValue, const char *FuncName, int ParamNo,
|
|
int AllowPointerCoercion)
|
|
{
|
|
struct ValueType *PointedToType = ToValue->Typ->FromType;
|
|
|
|
if (FromValue->Typ == ToValue->Typ ||
|
|
FromValue->Typ == Parser->pc->VoidPtrType ||
|
|
(ToValue->Typ == Parser->pc->VoidPtrType &&
|
|
FromValue->Typ->Base == TypePointer))
|
|
ToValue->Val->Pointer = FromValue->Val->Pointer; /* plain old pointer assignment */
|
|
else if (FromValue->Typ->Base == TypeArray &&
|
|
(PointedToType == FromValue->Typ->FromType ||
|
|
ToValue->Typ == Parser->pc->VoidPtrType)) {
|
|
/* the form is: blah *x = array of blah */
|
|
ToValue->Val->Pointer = (void *)&FromValue->Val->ArrayMem[0];
|
|
} else if (FromValue->Typ->Base == TypePointer &&
|
|
FromValue->Typ->FromType->Base == TypeArray &&
|
|
(PointedToType == FromValue->Typ->FromType->FromType ||
|
|
ToValue->Typ == Parser->pc->VoidPtrType) ) {
|
|
/* the form is: blah *x = pointer to array of blah */
|
|
ToValue->Val->Pointer = VariableDereferencePointer(Parser, FromValue,
|
|
NULL, NULL, NULL, NULL);
|
|
} else if (IS_NUMERIC_COERCIBLE(FromValue) &&
|
|
ExpressionCoerceInteger(FromValue) == 0) {
|
|
/* null pointer assignment */
|
|
ToValue->Val->Pointer = NULL;
|
|
} else if (AllowPointerCoercion && IS_NUMERIC_COERCIBLE(FromValue)) {
|
|
/* assign integer to native pointer */
|
|
ToValue->Val->Pointer =
|
|
(void*)(unsigned long)ExpressionCoerceUnsignedInteger(FromValue);
|
|
} else if (AllowPointerCoercion && FromValue->Typ->Base == TypePointer) {
|
|
/* assign a pointer to a pointer to a different type */
|
|
ToValue->Val->Pointer = FromValue->Val->Pointer;
|
|
} else
|
|
AssignFail(Parser, "%t from %t", ToValue->Typ, FromValue->Typ, 0, 0,
|
|
FuncName, ParamNo);
|
|
}
|
|
|
|
/* assign any kind of value */
|
|
void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue,
|
|
struct Value *SourceValue, int Force, const char *FuncName, int ParamNo,
|
|
int AllowPointerCoercion)
|
|
{
|
|
if (!DestValue->IsLValue && !Force)
|
|
AssignFail(Parser, "not an lvalue", NULL, NULL, 0, 0, FuncName, ParamNo);
|
|
|
|
if (IS_NUMERIC_COERCIBLE(DestValue) &&
|
|
!IS_NUMERIC_COERCIBLE_PLUS_POINTERS(SourceValue, AllowPointerCoercion))
|
|
AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo);
|
|
|
|
switch (DestValue->Typ->Base) {
|
|
case TypeInt:
|
|
DestValue->Val->Integer = ExpressionCoerceInteger(SourceValue);
|
|
break;
|
|
case TypeShort:
|
|
DestValue->Val->ShortInteger = (short)ExpressionCoerceInteger(SourceValue);
|
|
break;
|
|
case TypeChar:
|
|
DestValue->Val->Character = (char)ExpressionCoerceInteger(SourceValue);
|
|
break;
|
|
case TypeLong:
|
|
DestValue->Val->LongInteger = ExpressionCoerceInteger(SourceValue);
|
|
break;
|
|
case TypeUnsignedInt:
|
|
DestValue->Val->UnsignedInteger = ExpressionCoerceUnsignedInteger(SourceValue);
|
|
break;
|
|
case TypeUnsignedShort:
|
|
DestValue->Val->UnsignedShortInteger =
|
|
(unsigned short)ExpressionCoerceUnsignedInteger(SourceValue);
|
|
break;
|
|
case TypeUnsignedLong:
|
|
DestValue->Val->UnsignedLongInteger =
|
|
ExpressionCoerceUnsignedInteger(SourceValue);
|
|
break;
|
|
case TypeUnsignedChar:
|
|
DestValue->Val->UnsignedCharacter =
|
|
(unsigned char)ExpressionCoerceUnsignedInteger(SourceValue);
|
|
break;
|
|
case TypeFP:
|
|
if (!IS_NUMERIC_COERCIBLE_PLUS_POINTERS(SourceValue, AllowPointerCoercion))
|
|
AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ,
|
|
0, 0, FuncName, ParamNo);
|
|
|
|
DestValue->Val->FP = ExpressionCoerceFP(SourceValue);
|
|
break;
|
|
case TypePointer:
|
|
ExpressionAssignToPointer(Parser, DestValue, SourceValue, FuncName,
|
|
ParamNo, AllowPointerCoercion);
|
|
break;
|
|
|
|
case TypeArray:
|
|
if (SourceValue->Typ->Base == TypeArray &&
|
|
DestValue->Typ->FromType == DestValue->Typ->FromType &&
|
|
DestValue->Typ->ArraySize == 0) {
|
|
/* destination array is unsized - need to resize the destination
|
|
array to the same size as the source array */
|
|
DestValue->Typ = SourceValue->Typ;
|
|
VariableRealloc(Parser, DestValue, TypeSizeValue(DestValue, false));
|
|
|
|
if (DestValue->LValueFrom != NULL) {
|
|
/* copy the resized value back to the LValue */
|
|
DestValue->LValueFrom->Val = DestValue->Val;
|
|
DestValue->LValueFrom->AnyValOnHeap = DestValue->AnyValOnHeap;
|
|
}
|
|
}
|
|
|
|
/* char array = "abcd" */
|
|
if (DestValue->Typ->FromType->Base == TypeChar &&
|
|
SourceValue->Typ->Base == TypePointer &&
|
|
SourceValue->Typ->FromType->Base == TypeChar) {
|
|
if (DestValue->Typ->ArraySize == 0) { /* char x[] = "abcd", x is unsized */
|
|
int Size = strlen(SourceValue->Val->Pointer) + 1;
|
|
#ifdef DEBUG_ARRAY_INITIALIZER
|
|
PRINT_SOURCE_POS();
|
|
fprintf(stderr, "str size: %d\n", Size);
|
|
#endif
|
|
DestValue->Typ = TypeGetMatching(Parser->pc, Parser,
|
|
DestValue->Typ->FromType, DestValue->Typ->Base,
|
|
Size, DestValue->Typ->Identifier, true);
|
|
VariableRealloc(Parser, DestValue, TypeSizeValue(DestValue,
|
|
false));
|
|
}
|
|
/* else, it's char x[10] = "abcd" */
|
|
|
|
#ifdef DEBUG_ARRAY_INITIALIZER
|
|
PRINT_SOURCE_POS();
|
|
fprintf(stderr, "char[%d] from char* (len=%d)\n",
|
|
DestValue->Typ->ArraySize,
|
|
strlen(SourceValue->Val->Pointer));
|
|
#endif
|
|
memcpy((void *)DestValue->Val, SourceValue->Val->Pointer,
|
|
TypeSizeValue(DestValue, false));
|
|
break;
|
|
}
|
|
|
|
if (DestValue->Typ != SourceValue->Typ)
|
|
AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ,
|
|
0, 0, FuncName, ParamNo);
|
|
|
|
if (DestValue->Typ->ArraySize != SourceValue->Typ->ArraySize)
|
|
AssignFail(Parser, "from an array of size %d to one of size %d",
|
|
NULL, NULL, DestValue->Typ->ArraySize,
|
|
SourceValue->Typ->ArraySize, FuncName, ParamNo);
|
|
|
|
memcpy((void *)DestValue->Val, (void *)SourceValue->Val,
|
|
TypeSizeValue(DestValue, false));
|
|
break;
|
|
|
|
case TypeStruct:
|
|
case TypeUnion:
|
|
if (DestValue->Typ != SourceValue->Typ)
|
|
AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ,
|
|
0, 0, FuncName, ParamNo);
|
|
|
|
memcpy((void *)DestValue->Val, (void *)SourceValue->Val,
|
|
TypeSizeValue(SourceValue, false));
|
|
break;
|
|
|
|
default:
|
|
AssignFail(Parser, "%t", DestValue->Typ, NULL, 0, 0, FuncName, ParamNo);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* evaluate the first half of a ternary operator x ? y : z */
|
|
void ExpressionQuestionMarkOperator(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct Value *BottomValue,
|
|
struct Value *TopValue)
|
|
{
|
|
if (!IS_NUMERIC_COERCIBLE(TopValue))
|
|
ProgramFail(Parser, "first argument to '?' should be a number");
|
|
|
|
if (ExpressionCoerceInteger(TopValue)) {
|
|
/* the condition's true, return the BottomValue */
|
|
ExpressionStackPushValue(Parser, StackTop, BottomValue);
|
|
} else {
|
|
/* the condition's false, return void */
|
|
ExpressionStackPushValueByType(Parser, StackTop, &Parser->pc->VoidType);
|
|
}
|
|
}
|
|
|
|
/* evaluate the second half of a ternary operator x ? y : z */
|
|
void ExpressionColonOperator(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, struct Value *BottomValue,
|
|
struct Value *TopValue)
|
|
{
|
|
if (TopValue->Typ->Base == TypeVoid) {
|
|
/* invoke the "else" part - return the BottomValue */
|
|
ExpressionStackPushValue(Parser, StackTop, BottomValue);
|
|
} else {
|
|
/* it was a "then" - return the TopValue */
|
|
ExpressionStackPushValue(Parser, StackTop, TopValue);
|
|
}
|
|
}
|
|
|
|
/* evaluate a prefix operator */
|
|
void ExpressionPrefixOperator(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue)
|
|
{
|
|
struct Value *Result;
|
|
union AnyValue *ValPtr;
|
|
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionPrefixOperator()\n");
|
|
#endif
|
|
|
|
switch (Op) {
|
|
case TokenAmpersand:
|
|
if (!TopValue->IsLValue)
|
|
ProgramFail(Parser, "can't get the address of this");
|
|
|
|
ValPtr = TopValue->Val;
|
|
Result = VariableAllocValueFromType(Parser->pc, Parser,
|
|
TypeGetMatching(Parser->pc, Parser, TopValue->Typ,
|
|
TypePointer, 0, Parser->pc->StrEmpty, true),
|
|
false, NULL, false);
|
|
Result->Val->Pointer = (void *)ValPtr;
|
|
ExpressionStackPushValueNode(Parser, StackTop, Result);
|
|
break;
|
|
|
|
case TokenAsterisk:
|
|
ExpressionStackPushDereference(Parser, StackTop, TopValue);
|
|
break;
|
|
|
|
case TokenSizeof:
|
|
/* return the size of the argument */
|
|
if (TopValue->Typ == &Parser->pc->TypeType)
|
|
ExpressionPushInt(Parser, StackTop, TypeSize(TopValue->Val->Typ,
|
|
TopValue->Val->Typ->ArraySize, true));
|
|
else
|
|
ExpressionPushInt(Parser, StackTop, TypeSize(TopValue->Typ,
|
|
TopValue->Typ->ArraySize, true));
|
|
break;
|
|
|
|
default:
|
|
/* an arithmetic operator */
|
|
if (TopValue->Typ == &Parser->pc->FPType) {
|
|
/* floating point prefix arithmetic */
|
|
double ResultFP = 0.0;
|
|
|
|
switch (Op) {
|
|
case TokenPlus:
|
|
ResultFP = TopValue->Val->FP;
|
|
break;
|
|
case TokenMinus:
|
|
ResultFP = -TopValue->Val->FP;
|
|
break;
|
|
case TokenIncrement:
|
|
ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP+1);
|
|
break;
|
|
case TokenDecrement:
|
|
ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP-1);
|
|
break;
|
|
case TokenUnaryNot:
|
|
ResultFP = !TopValue->Val->FP;
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
ExpressionPushFP(Parser, StackTop, ResultFP);
|
|
} else if (IS_NUMERIC_COERCIBLE(TopValue)) {
|
|
/* integer prefix arithmetic */
|
|
long ResultInt = 0;
|
|
long TopInt = ExpressionCoerceInteger(TopValue);
|
|
switch (Op) {
|
|
case TokenPlus:
|
|
ResultInt = TopInt;
|
|
break;
|
|
case TokenMinus:
|
|
ResultInt = -TopInt;
|
|
break;
|
|
case TokenIncrement:
|
|
ResultInt = ExpressionAssignInt(Parser, TopValue,
|
|
TopInt+1, false);
|
|
break;
|
|
case TokenDecrement:
|
|
ResultInt = ExpressionAssignInt(Parser, TopValue,
|
|
TopInt-1, false);
|
|
break;
|
|
case TokenUnaryNot:
|
|
ResultInt = !TopInt;
|
|
break;
|
|
case TokenUnaryExor:
|
|
ResultInt = ~TopInt;
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
ExpressionPushInt(Parser, StackTop, ResultInt);
|
|
} else if (TopValue->Typ->Base == TypePointer) {
|
|
/* pointer prefix arithmetic */
|
|
int Size = TypeSize(TopValue->Typ->FromType, 0, true);
|
|
struct Value *StackValue;
|
|
void *ResultPtr;
|
|
|
|
if (TopValue->Val->Pointer == NULL)
|
|
ProgramFail(Parser, "invalid use of a NULL pointer");
|
|
|
|
if (!TopValue->IsLValue)
|
|
ProgramFail(Parser, "can't assign to this");
|
|
|
|
switch (Op) {
|
|
case TokenIncrement:
|
|
TopValue->Val->Pointer =
|
|
(void*)((char*)TopValue->Val->Pointer+Size);
|
|
break;
|
|
case TokenDecrement:
|
|
TopValue->Val->Pointer =
|
|
(void*)((char*)TopValue->Val->Pointer-Size);
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
ResultPtr = TopValue->Val->Pointer;
|
|
StackValue = ExpressionStackPushValueByType(Parser, StackTop,
|
|
TopValue->Typ);
|
|
StackValue->Val->Pointer = ResultPtr;
|
|
} else
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* evaluate a postfix operator */
|
|
void ExpressionPostfixOperator(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue)
|
|
{
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionPostfixOperator()\n");
|
|
#endif
|
|
|
|
if (TopValue->Typ == &Parser->pc->FPType) {
|
|
/* floating point prefix arithmetic */
|
|
double ResultFP = 0.0;
|
|
|
|
switch (Op) {
|
|
case TokenIncrement:
|
|
ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP+1);
|
|
break;
|
|
case TokenDecrement:
|
|
ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP-1);
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
ExpressionPushFP(Parser, StackTop, ResultFP);
|
|
}
|
|
else if (IS_NUMERIC_COERCIBLE(TopValue)) {
|
|
long ResultInt = 0;
|
|
long TopInt = ExpressionCoerceInteger(TopValue);
|
|
switch (Op) {
|
|
case TokenIncrement:
|
|
ResultInt = ExpressionAssignInt(Parser, TopValue, TopInt+1, true);
|
|
break;
|
|
case TokenDecrement:
|
|
ResultInt = ExpressionAssignInt(Parser, TopValue, TopInt-1, true);
|
|
break;
|
|
case TokenRightSquareBracket:
|
|
ProgramFail(Parser, "not supported");
|
|
break; /* XXX */
|
|
case TokenCloseBracket:
|
|
ProgramFail(Parser, "not supported");
|
|
break; /* XXX */
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
ExpressionPushInt(Parser, StackTop, ResultInt);
|
|
} else if (TopValue->Typ->Base == TypePointer) {
|
|
/* pointer postfix arithmetic */
|
|
int Size = TypeSize(TopValue->Typ->FromType, 0, true);
|
|
struct Value *StackValue;
|
|
void *OrigPointer = TopValue->Val->Pointer;
|
|
|
|
if (TopValue->Val->Pointer == NULL)
|
|
ProgramFail(Parser, "invalid use of a NULL pointer");
|
|
|
|
if (!TopValue->IsLValue)
|
|
ProgramFail(Parser, "can't assign to this");
|
|
|
|
switch (Op) {
|
|
case TokenIncrement:
|
|
TopValue->Val->Pointer = (void*)((char*)TopValue->Val->Pointer+Size);
|
|
break;
|
|
case TokenDecrement:
|
|
TopValue->Val->Pointer = (void*)((char*)TopValue->Val->Pointer-Size);
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
StackValue = ExpressionStackPushValueByType(Parser, StackTop,
|
|
TopValue->Typ);
|
|
StackValue->Val->Pointer = OrigPointer;
|
|
}
|
|
else
|
|
ProgramFail(Parser, "invalid operation");
|
|
}
|
|
|
|
/* evaluate an infix operator */
|
|
void ExpressionInfixOperator(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, enum LexToken Op,
|
|
struct Value *BottomValue, struct Value *TopValue)
|
|
{
|
|
long ResultInt = 0;
|
|
struct Value *StackValue;
|
|
void *Pointer;
|
|
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionInfixOperator()\n");
|
|
#endif
|
|
|
|
if (BottomValue == NULL || TopValue == NULL)
|
|
ProgramFail(Parser, "invalid expression");
|
|
|
|
if (Op == TokenLeftSquareBracket) {
|
|
/* array index */
|
|
int ArrayIndex;
|
|
struct Value *Result = NULL;
|
|
|
|
if (!IS_NUMERIC_COERCIBLE(TopValue))
|
|
ProgramFail(Parser, "array index must be an integer");
|
|
|
|
ArrayIndex = ExpressionCoerceInteger(TopValue);
|
|
|
|
/* make the array element result */
|
|
switch (BottomValue->Typ->Base) {
|
|
case TypeArray:
|
|
Result = VariableAllocValueFromExistingData(Parser,
|
|
BottomValue->Typ->FromType,
|
|
(union AnyValue*)(&BottomValue->Val->ArrayMem[0]+TypeSize(BottomValue->Typ,
|
|
ArrayIndex, true)),
|
|
BottomValue->IsLValue, BottomValue->LValueFrom);
|
|
break;
|
|
case TypePointer: Result = VariableAllocValueFromExistingData(Parser,
|
|
BottomValue->Typ->FromType,
|
|
(union AnyValue*)((char*)BottomValue->Val->Pointer+TypeSize(BottomValue->Typ->FromType,
|
|
0, true) * ArrayIndex),
|
|
BottomValue->IsLValue, BottomValue->LValueFrom);
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "this %t is not an array", BottomValue->Typ);
|
|
break;
|
|
}
|
|
|
|
ExpressionStackPushValueNode(Parser, StackTop, Result);
|
|
} else if (Op == TokenQuestionMark)
|
|
ExpressionQuestionMarkOperator(Parser, StackTop, TopValue, BottomValue);
|
|
else if (Op == TokenColon)
|
|
ExpressionColonOperator(Parser, StackTop, TopValue, BottomValue);
|
|
else if ((TopValue->Typ == &Parser->pc->FPType &&
|
|
BottomValue->Typ == &Parser->pc->FPType) ||
|
|
(TopValue->Typ == &Parser->pc->FPType
|
|
&& IS_NUMERIC_COERCIBLE(BottomValue)) ||
|
|
(IS_NUMERIC_COERCIBLE(TopValue)
|
|
&& BottomValue->Typ == &Parser->pc->FPType) ) {
|
|
/* floating point infix arithmetic */
|
|
int ResultIsInt = false;
|
|
double ResultFP = 0.0;
|
|
double TopFP = (TopValue->Typ == &Parser->pc->FPType) ?
|
|
TopValue->Val->FP : (double)ExpressionCoerceInteger(TopValue);
|
|
double BottomFP = (BottomValue->Typ == &Parser->pc->FPType) ?
|
|
BottomValue->Val->FP : (double)ExpressionCoerceInteger(BottomValue);
|
|
|
|
switch (Op) {
|
|
case TokenAssign:
|
|
ASSIGN_FP_OR_INT(TopFP);
|
|
break;
|
|
case TokenAddAssign:
|
|
ASSIGN_FP_OR_INT(BottomFP + TopFP);
|
|
break;
|
|
case TokenSubtractAssign:
|
|
ASSIGN_FP_OR_INT(BottomFP - TopFP);
|
|
break;
|
|
case TokenMultiplyAssign:
|
|
ASSIGN_FP_OR_INT(BottomFP * TopFP);
|
|
break;
|
|
case TokenDivideAssign:
|
|
ASSIGN_FP_OR_INT(BottomFP / TopFP);
|
|
break;
|
|
case TokenEqual:
|
|
ResultInt = BottomFP == TopFP; ResultIsInt = true;
|
|
break;
|
|
case TokenNotEqual:
|
|
ResultInt = BottomFP != TopFP; ResultIsInt = true;
|
|
break;
|
|
case TokenLessThan:
|
|
ResultInt = BottomFP < TopFP; ResultIsInt = true;
|
|
break;
|
|
case TokenGreaterThan:
|
|
ResultInt = BottomFP > TopFP; ResultIsInt = true;
|
|
break;
|
|
case TokenLessEqual:
|
|
ResultInt = BottomFP <= TopFP; ResultIsInt = true;
|
|
break;
|
|
case TokenGreaterEqual:
|
|
ResultInt = BottomFP >= TopFP; ResultIsInt = true;
|
|
break;
|
|
case TokenPlus:
|
|
ResultFP = BottomFP + TopFP;
|
|
break;
|
|
case TokenMinus:
|
|
ResultFP = BottomFP - TopFP;
|
|
break;
|
|
case TokenAsterisk:
|
|
ResultFP = BottomFP * TopFP;
|
|
break;
|
|
case TokenSlash:
|
|
ResultFP = BottomFP / TopFP;
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
if (ResultIsInt)
|
|
ExpressionPushInt(Parser, StackTop, ResultInt);
|
|
else
|
|
ExpressionPushFP(Parser, StackTop, ResultFP);
|
|
} else if (IS_NUMERIC_COERCIBLE(TopValue) && IS_NUMERIC_COERCIBLE(BottomValue)) {
|
|
/* integer operation */
|
|
long TopInt = ExpressionCoerceInteger(TopValue);
|
|
long BottomInt = ExpressionCoerceInteger(BottomValue);
|
|
switch (Op) {
|
|
case TokenAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue, TopInt, false);
|
|
break;
|
|
case TokenAddAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt + TopInt, false);
|
|
break;
|
|
case TokenSubtractAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt-TopInt, false);
|
|
break;
|
|
case TokenMultiplyAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt*TopInt, false);
|
|
break;
|
|
case TokenDivideAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt/TopInt, false);
|
|
break;
|
|
case TokenModulusAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt%TopInt, false);
|
|
break;
|
|
case TokenShiftLeftAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt<<TopInt, false);
|
|
break;
|
|
case TokenShiftRightAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt>>TopInt, false);
|
|
break;
|
|
case TokenArithmeticAndAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt&TopInt, false);
|
|
break;
|
|
case TokenArithmeticOrAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt|TopInt, false);
|
|
break;
|
|
case TokenArithmeticExorAssign:
|
|
ResultInt = ExpressionAssignInt(Parser, BottomValue,
|
|
BottomInt^TopInt, false);
|
|
break;
|
|
case TokenLogicalOr:
|
|
ResultInt = BottomInt || TopInt;
|
|
break;
|
|
case TokenLogicalAnd:
|
|
ResultInt = BottomInt && TopInt;
|
|
break;
|
|
case TokenArithmeticOr:
|
|
ResultInt = BottomInt | TopInt;
|
|
break;
|
|
case TokenArithmeticExor:
|
|
ResultInt = BottomInt ^ TopInt;
|
|
break;
|
|
case TokenAmpersand:
|
|
ResultInt = BottomInt & TopInt;
|
|
break;
|
|
case TokenEqual:
|
|
ResultInt = BottomInt == TopInt;
|
|
break;
|
|
case TokenNotEqual:
|
|
ResultInt = BottomInt != TopInt;
|
|
break;
|
|
case TokenLessThan:
|
|
ResultInt = BottomInt < TopInt;
|
|
break;
|
|
case TokenGreaterThan:
|
|
ResultInt = BottomInt > TopInt;
|
|
break;
|
|
case TokenLessEqual:
|
|
ResultInt = BottomInt <= TopInt;
|
|
break;
|
|
case TokenGreaterEqual:
|
|
ResultInt = BottomInt >= TopInt;
|
|
break;
|
|
case TokenShiftLeft:
|
|
ResultInt = BottomInt << TopInt;
|
|
break;
|
|
case TokenShiftRight:
|
|
ResultInt = BottomInt >> TopInt;
|
|
break;
|
|
case TokenPlus:
|
|
ResultInt = BottomInt + TopInt;
|
|
break;
|
|
case TokenMinus:
|
|
ResultInt = BottomInt - TopInt;
|
|
break;
|
|
case TokenAsterisk:
|
|
ResultInt = BottomInt * TopInt;
|
|
break;
|
|
case TokenSlash:
|
|
ResultInt = BottomInt / TopInt;
|
|
break;
|
|
case TokenModulus:
|
|
ResultInt = BottomInt % TopInt;
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
|
|
ExpressionPushInt(Parser, StackTop, ResultInt);
|
|
} else if (BottomValue->Typ->Base == TypePointer &&
|
|
IS_NUMERIC_COERCIBLE(TopValue)) {
|
|
/* pointer/integer infix arithmetic */
|
|
long TopInt = ExpressionCoerceInteger(TopValue);
|
|
|
|
if (Op == TokenEqual || Op == TokenNotEqual) {
|
|
/* comparison to a NULL pointer */
|
|
if (TopInt != 0)
|
|
ProgramFail(Parser, "invalid operation");
|
|
|
|
if (Op == TokenEqual)
|
|
ExpressionPushInt(Parser, StackTop,
|
|
BottomValue->Val->Pointer == NULL);
|
|
else
|
|
ExpressionPushInt(Parser, StackTop,
|
|
BottomValue->Val->Pointer != NULL);
|
|
} else if (Op == TokenPlus || Op == TokenMinus) {
|
|
/* pointer arithmetic */
|
|
int Size = TypeSize(BottomValue->Typ->FromType, 0, true);
|
|
|
|
Pointer = BottomValue->Val->Pointer;
|
|
if (Pointer == NULL)
|
|
ProgramFail(Parser, "invalid use of a NULL pointer");
|
|
|
|
if (Op == TokenPlus)
|
|
Pointer = (void *)((char *)Pointer + TopInt * Size);
|
|
else
|
|
Pointer = (void *)((char *)Pointer - TopInt * Size);
|
|
|
|
StackValue = ExpressionStackPushValueByType(Parser, StackTop,
|
|
BottomValue->Typ);
|
|
StackValue->Val->Pointer = Pointer;
|
|
} else if (Op == TokenAssign && TopInt == 0) {
|
|
/* assign a NULL pointer */
|
|
HeapUnpopStack(Parser->pc, sizeof(struct Value));
|
|
ExpressionAssign(Parser, BottomValue, TopValue, false, NULL, 0, false);
|
|
ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
|
|
} else if (Op == TokenAddAssign || Op == TokenSubtractAssign) {
|
|
/* pointer arithmetic */
|
|
int Size = TypeSize(BottomValue->Typ->FromType, 0, true);
|
|
|
|
Pointer = BottomValue->Val->Pointer;
|
|
if (Pointer == NULL)
|
|
ProgramFail(Parser, "invalid use of a NULL pointer");
|
|
|
|
if (Op == TokenAddAssign)
|
|
Pointer = (void *)((char *)Pointer + TopInt * Size);
|
|
else
|
|
Pointer = (void *)((char *)Pointer - TopInt * Size);
|
|
|
|
HeapUnpopStack(Parser->pc, sizeof(struct Value));
|
|
BottomValue->Val->Pointer = Pointer;
|
|
ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
|
|
} else
|
|
ProgramFail(Parser, "invalid operation");
|
|
} else if (BottomValue->Typ->Base == TypePointer &&
|
|
TopValue->Typ->Base == TypePointer && Op != TokenAssign) {
|
|
/* pointer/pointer operations */
|
|
char *TopLoc = (char *)TopValue->Val->Pointer;
|
|
char *BottomLoc = (char *)BottomValue->Val->Pointer;
|
|
|
|
switch (Op) {
|
|
case TokenEqual:
|
|
ExpressionPushInt(Parser, StackTop, BottomLoc == TopLoc);
|
|
break;
|
|
case TokenNotEqual:
|
|
ExpressionPushInt(Parser, StackTop, BottomLoc != TopLoc);
|
|
break;
|
|
case TokenMinus:
|
|
ExpressionPushInt(Parser, StackTop, BottomLoc - TopLoc);
|
|
break;
|
|
default:
|
|
ProgramFail(Parser, "invalid operation");
|
|
break;
|
|
}
|
|
} else if (Op == TokenAssign) {
|
|
/* assign a non-numeric type */
|
|
HeapUnpopStack(Parser->pc, sizeof(struct Value));
|
|
/* XXX - possible bug if lvalue is a temp value and takes more than sizeof(struct Value) */
|
|
ExpressionAssign(Parser, BottomValue, TopValue, false, NULL, 0, false);
|
|
ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
|
|
} else if (Op == TokenCast) {
|
|
/* cast a value to a different type */
|
|
/* XXX - possible bug if the destination type takes more than sizeof(struct Value) + sizeof(struct ValueType *) */
|
|
struct Value *ValueLoc = ExpressionStackPushValueByType(Parser, StackTop,
|
|
BottomValue->Val->Typ);
|
|
ExpressionAssign(Parser, ValueLoc, TopValue, true, NULL, 0, true);
|
|
} else
|
|
ProgramFail(Parser, "invalid operation");
|
|
}
|
|
|
|
/* take the contents of the expression stack and compute the top until there's nothing greater than the given precedence */
|
|
void ExpressionStackCollapse(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, int Precedence, int *IgnorePrecedence)
|
|
{
|
|
int FoundPrecedence = Precedence;
|
|
struct Value *TopValue;
|
|
struct Value *BottomValue;
|
|
struct ExpressionStack *TopStackNode = *StackTop;
|
|
struct ExpressionStack *TopOperatorNode;
|
|
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionStackCollapse(%d):\n", Precedence);
|
|
ExpressionStackShow(Parser->pc, *StackTop);
|
|
#endif
|
|
while (TopStackNode != NULL && TopStackNode->Next != NULL &&
|
|
FoundPrecedence >= Precedence) {
|
|
/* find the top operator on the stack */
|
|
if (TopStackNode->Order == OrderNone)
|
|
TopOperatorNode = TopStackNode->Next;
|
|
else
|
|
TopOperatorNode = TopStackNode;
|
|
|
|
FoundPrecedence = TopOperatorNode->Precedence;
|
|
|
|
/* does it have a high enough precedence? */
|
|
if (FoundPrecedence >= Precedence && TopOperatorNode != NULL) {
|
|
/* execute this operator */
|
|
switch (TopOperatorNode->Order) {
|
|
case OrderPrefix:
|
|
/* prefix evaluation */
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("prefix evaluation\n");
|
|
#endif
|
|
TopValue = TopStackNode->Val;
|
|
|
|
/* pop the value and then the prefix operator - assume they'll still be there until we're done */
|
|
HeapPopStack(Parser->pc, NULL,
|
|
sizeof(struct ExpressionStack)+sizeof(struct Value)+TypeStackSizeValue(TopValue));
|
|
HeapPopStack(Parser->pc, TopOperatorNode,
|
|
sizeof(struct ExpressionStack));
|
|
*StackTop = TopOperatorNode->Next;
|
|
|
|
/* do the prefix operation */
|
|
if (Parser->Mode == RunModeRun /* && FoundPrecedence < *IgnorePrecedence */) {
|
|
/* run the operator */
|
|
ExpressionPrefixOperator(Parser, StackTop,
|
|
TopOperatorNode->Op, TopValue);
|
|
} else {
|
|
/* we're not running it so just return 0 */
|
|
ExpressionPushInt(Parser, StackTop, 0);
|
|
}
|
|
break;
|
|
|
|
case OrderPostfix:
|
|
/* postfix evaluation */
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("postfix evaluation\n");
|
|
#endif
|
|
TopValue = TopStackNode->Next->Val;
|
|
|
|
/* pop the postfix operator and then the value - assume they'll still be there until we're done */
|
|
HeapPopStack(Parser->pc, NULL, sizeof(struct ExpressionStack));
|
|
HeapPopStack(Parser->pc, TopValue,
|
|
sizeof(struct ExpressionStack)+sizeof(struct Value)+TypeStackSizeValue(TopValue));
|
|
*StackTop = TopStackNode->Next->Next;
|
|
|
|
/* do the postfix operation */
|
|
if (Parser->Mode == RunModeRun /* && FoundPrecedence < *IgnorePrecedence */) {
|
|
/* run the operator */
|
|
ExpressionPostfixOperator(Parser, StackTop,
|
|
TopOperatorNode->Op, TopValue);
|
|
} else {
|
|
/* we're not running it so just return 0 */
|
|
ExpressionPushInt(Parser, StackTop, 0);
|
|
}
|
|
break;
|
|
|
|
case OrderInfix:
|
|
/* infix evaluation */
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("infix evaluation\n");
|
|
#endif
|
|
TopValue = TopStackNode->Val;
|
|
if (TopValue != NULL) {
|
|
BottomValue = TopOperatorNode->Next->Val;
|
|
|
|
/* pop a value, the operator and another value - assume they'll still be there until we're done */
|
|
HeapPopStack(Parser->pc, NULL,
|
|
sizeof(struct ExpressionStack)+sizeof(struct Value)+TypeStackSizeValue(TopValue));
|
|
HeapPopStack(Parser->pc, NULL,
|
|
sizeof(struct ExpressionStack));
|
|
HeapPopStack(Parser->pc, BottomValue,
|
|
sizeof(struct ExpressionStack)+sizeof(struct Value)+TypeStackSizeValue(BottomValue));
|
|
*StackTop = TopOperatorNode->Next->Next;
|
|
|
|
/* do the infix operation */
|
|
if (Parser->Mode == RunModeRun /* && FoundPrecedence <= *IgnorePrecedence */) {
|
|
/* run the operator */
|
|
ExpressionInfixOperator(Parser, StackTop,
|
|
TopOperatorNode->Op, BottomValue, TopValue);
|
|
} else {
|
|
/* we're not running it so just return 0 */
|
|
ExpressionPushInt(Parser, StackTop, 0);
|
|
}
|
|
}
|
|
else
|
|
FoundPrecedence = -1;
|
|
break;
|
|
|
|
case OrderNone:
|
|
/* this should never happen */
|
|
assert(TopOperatorNode->Order != OrderNone);
|
|
break;
|
|
}
|
|
|
|
/* if we've returned above the ignored precedence level turn ignoring off */
|
|
if (FoundPrecedence <= *IgnorePrecedence)
|
|
*IgnorePrecedence = DEEP_PRECEDENCE;
|
|
}
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
ExpressionStackShow(Parser->pc, *StackTop);
|
|
#endif
|
|
TopStackNode = *StackTop;
|
|
}
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionStackCollapse() finished\n");
|
|
ExpressionStackShow(Parser->pc, *StackTop);
|
|
#endif
|
|
}
|
|
|
|
/* push an operator on to the expression stack */
|
|
void ExpressionStackPushOperator(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, enum OperatorOrder Order,
|
|
enum LexToken Token, int Precedence)
|
|
{
|
|
struct ExpressionStack *StackNode = VariableAlloc(Parser->pc, Parser,
|
|
sizeof(struct ExpressionStack), false);
|
|
StackNode->Next = *StackTop;
|
|
StackNode->Order = Order;
|
|
StackNode->Op = Token;
|
|
StackNode->Precedence = Precedence;
|
|
*StackTop = StackNode;
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionStackPushOperator()\n");
|
|
#endif
|
|
#ifdef FANCY_ERROR_MESSAGES
|
|
StackNode->Line = Parser->Line;
|
|
StackNode->CharacterPos = Parser->CharacterPos;
|
|
#endif
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
ExpressionStackShow(Parser->pc, *StackTop);
|
|
#endif
|
|
}
|
|
|
|
/* do the '.' and '->' operators */
|
|
void ExpressionGetStructElement(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, enum LexToken Token)
|
|
{
|
|
struct Value *Ident;
|
|
|
|
/* get the identifier following the '.' or '->' */
|
|
if (LexGetToken(Parser, &Ident, true) != TokenIdentifier)
|
|
ProgramFail(Parser, "need an structure or union member after '%s'",
|
|
(Token == TokenDot) ? "." : "->");
|
|
|
|
if (Parser->Mode == RunModeRun) {
|
|
/* look up the struct element */
|
|
struct Value *ParamVal = (*StackTop)->Val;
|
|
struct Value *StructVal = ParamVal;
|
|
struct ValueType *StructType = ParamVal->Typ;
|
|
char *DerefDataLoc = (char *)ParamVal->Val;
|
|
struct Value *MemberValue = NULL;
|
|
struct Value *Result;
|
|
|
|
/* if we're doing '->' dereference the struct pointer first */
|
|
if (Token == TokenArrow)
|
|
DerefDataLoc = VariableDereferencePointer(Parser, ParamVal, &StructVal,
|
|
NULL, &StructType, NULL);
|
|
|
|
if (StructType->Base != TypeStruct && StructType->Base != TypeUnion)
|
|
ProgramFail(Parser, "can't use '%s' on something that's not a struct or union %s : it's a %t",
|
|
(Token == TokenDot) ? "." : "->",
|
|
(Token == TokenArrow) ? "pointer" : "", ParamVal->Typ);
|
|
|
|
if (!TableGet(StructType->Members, Ident->Val->Identifier,
|
|
&MemberValue, NULL, NULL, NULL))
|
|
ProgramFail(Parser, "doesn't have a member called '%s'",
|
|
Ident->Val->Identifier);
|
|
|
|
/* pop the value - assume it'll still be there until we're done */
|
|
HeapPopStack(Parser->pc, ParamVal,
|
|
sizeof(struct ExpressionStack)+sizeof(struct Value)+TypeStackSizeValue(StructVal));
|
|
*StackTop = (*StackTop)->Next;
|
|
|
|
/* make the result value for this member only */
|
|
Result = VariableAllocValueFromExistingData(Parser, MemberValue->Typ,
|
|
(void*)(DerefDataLoc + MemberValue->Val->Integer), true,
|
|
(StructVal != NULL) ? StructVal->LValueFrom : NULL);
|
|
ExpressionStackPushValueNode(Parser, StackTop, Result);
|
|
}
|
|
}
|
|
|
|
/* parse an expression with operator precedence */
|
|
int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|
{
|
|
int PrefixState = true;
|
|
int Done = false;
|
|
int BracketPrecedence = 0;
|
|
int LocalPrecedence;
|
|
int Precedence = 0;
|
|
int IgnorePrecedence = DEEP_PRECEDENCE;
|
|
int TernaryDepth = 0;
|
|
struct Value *LexValue;
|
|
struct ExpressionStack *StackTop = NULL;
|
|
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionParse():\n");
|
|
#endif
|
|
|
|
do {
|
|
struct ParseState PreState;
|
|
enum LexToken Token;
|
|
|
|
ParserCopy(&PreState, Parser);
|
|
Token = LexGetToken(Parser, &LexValue, true);
|
|
if ((((int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) ||
|
|
(Token == TokenCloseBracket && BracketPrecedence != 0)) &&
|
|
(Token != TokenColon || TernaryDepth > 0)) {
|
|
/* it's an operator with precedence */
|
|
if (PrefixState) {
|
|
/* expect a prefix operator */
|
|
if (OperatorPrecedence[(int)Token].PrefixPrecedence == 0)
|
|
ProgramFail(Parser, "operator not expected here");
|
|
|
|
LocalPrecedence = OperatorPrecedence[(int)Token].PrefixPrecedence;
|
|
Precedence = BracketPrecedence + LocalPrecedence;
|
|
|
|
if (Token == TokenOpenBracket) {
|
|
/* it's either a new bracket level or a cast */
|
|
enum LexToken BracketToken = LexGetToken(Parser, &LexValue, false);
|
|
if (IsTypeToken(Parser, BracketToken, LexValue) &&
|
|
(StackTop == NULL || StackTop->Op != TokenSizeof)) {
|
|
/* it's a cast - get the new type */
|
|
struct ValueType *CastType;
|
|
char *CastIdentifier;
|
|
struct Value *CastTypeValue;
|
|
|
|
TypeParse(Parser, &CastType, &CastIdentifier, NULL);
|
|
if (LexGetToken(Parser, &LexValue, true) != TokenCloseBracket)
|
|
ProgramFail(Parser, "brackets not closed");
|
|
|
|
/* scan and collapse the stack to the precedence of this infix cast operator, then push */
|
|
Precedence = BracketPrecedence +
|
|
OperatorPrecedence[(int)TokenCast].PrefixPrecedence;
|
|
|
|
ExpressionStackCollapse(Parser, &StackTop, Precedence+1,
|
|
&IgnorePrecedence);
|
|
CastTypeValue = VariableAllocValueFromType(Parser->pc,
|
|
Parser, &Parser->pc->TypeType, false, NULL, false);
|
|
CastTypeValue->Val->Typ = CastType;
|
|
ExpressionStackPushValueNode(Parser, &StackTop, CastTypeValue);
|
|
ExpressionStackPushOperator(Parser, &StackTop, OrderInfix,
|
|
TokenCast, Precedence);
|
|
} else {
|
|
/* boost the bracket operator precedence */
|
|
BracketPrecedence += BRACKET_PRECEDENCE;
|
|
}
|
|
} else {
|
|
/* scan and collapse the stack to the precedence of this operator, then push */
|
|
|
|
/* take some extra care for double prefix operators, e.g. x = - -5, or x = **y */
|
|
int NextToken = LexGetToken(Parser, NULL, false);
|
|
int TempPrecedenceBoost = 0;
|
|
if (NextToken > TokenComma && NextToken < TokenOpenBracket) {
|
|
int NextPrecedence =
|
|
OperatorPrecedence[(int)NextToken].PrefixPrecedence;
|
|
|
|
/* two prefix operators with equal precedence? make
|
|
sure the innermost one runs first */
|
|
/* XXX - probably not correct, but can't find a
|
|
test that fails at this */
|
|
if (LocalPrecedence == NextPrecedence)
|
|
TempPrecedenceBoost = -1;
|
|
}
|
|
|
|
ExpressionStackCollapse(Parser, &StackTop, Precedence,
|
|
&IgnorePrecedence);
|
|
ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix,
|
|
Token, Precedence + TempPrecedenceBoost);
|
|
}
|
|
} else {
|
|
/* expect an infix or postfix operator */
|
|
if (OperatorPrecedence[(int)Token].PostfixPrecedence != 0) {
|
|
switch (Token) {
|
|
case TokenCloseBracket:
|
|
case TokenRightSquareBracket:
|
|
if (BracketPrecedence == 0) {
|
|
/* assume this bracket is after the end of the expression */
|
|
ParserCopy(Parser, &PreState);
|
|
Done = true;
|
|
} else {
|
|
/* collapse to the bracket precedence */
|
|
ExpressionStackCollapse(Parser, &StackTop,
|
|
BracketPrecedence, &IgnorePrecedence);
|
|
BracketPrecedence -= BRACKET_PRECEDENCE;
|
|
}
|
|
break;
|
|
default:
|
|
/* scan and collapse the stack to the precedence of this operator, then push */
|
|
Precedence = BracketPrecedence +
|
|
OperatorPrecedence[(int)Token].PostfixPrecedence;
|
|
ExpressionStackCollapse(Parser, &StackTop, Precedence,
|
|
&IgnorePrecedence);
|
|
ExpressionStackPushOperator(Parser, &StackTop,
|
|
OrderPostfix, Token, Precedence);
|
|
break;
|
|
}
|
|
} else if (OperatorPrecedence[(int)Token].InfixPrecedence != 0) {
|
|
/* scan and collapse the stack, then push */
|
|
Precedence = BracketPrecedence +
|
|
OperatorPrecedence[(int)Token].InfixPrecedence;
|
|
|
|
/* for right to left order, only go down to the next higher precedence so we evaluate it in reverse order */
|
|
/* for left to right order, collapse down to this precedence so we evaluate it in forward order */
|
|
if (IS_LEFT_TO_RIGHT(OperatorPrecedence[(int)Token].InfixPrecedence))
|
|
ExpressionStackCollapse(Parser, &StackTop, Precedence,
|
|
&IgnorePrecedence);
|
|
else
|
|
ExpressionStackCollapse(Parser, &StackTop, Precedence+1,
|
|
&IgnorePrecedence);
|
|
|
|
if (Token == TokenDot || Token == TokenArrow) {
|
|
/* this operator is followed by a struct element so handle it as a special case */
|
|
ExpressionGetStructElement(Parser, &StackTop, Token);
|
|
} else {
|
|
/* if it's a && or || operator we may not need to evaluate the right hand side of the expression */
|
|
if ((Token == TokenLogicalOr || Token == TokenLogicalAnd) &&
|
|
IS_NUMERIC_COERCIBLE(StackTop->Val)) {
|
|
long LHSInt = ExpressionCoerceInteger(StackTop->Val);
|
|
if (((Token == TokenLogicalOr && LHSInt) ||
|
|
(Token == TokenLogicalAnd && !LHSInt)) &&
|
|
(IgnorePrecedence > Precedence) )
|
|
IgnorePrecedence = Precedence;
|
|
}
|
|
|
|
/* push the operator on the stack */
|
|
ExpressionStackPushOperator(Parser, &StackTop,
|
|
OrderInfix, Token, Precedence);
|
|
PrefixState = true;
|
|
|
|
switch (Token) {
|
|
case TokenQuestionMark: TernaryDepth++; break;
|
|
case TokenColon: TernaryDepth--; break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
/* treat an open square bracket as an infix array index
|
|
operator followed by an open bracket */
|
|
if (Token == TokenLeftSquareBracket) {
|
|
/* boost the bracket operator precedence, then push */
|
|
BracketPrecedence += BRACKET_PRECEDENCE;
|
|
}
|
|
} else
|
|
ProgramFail(Parser, "operator not expected here");
|
|
}
|
|
} else if (Token == TokenIdentifier) {
|
|
/* it's a variable, function or a macro */
|
|
if (!PrefixState)
|
|
ProgramFail(Parser, "identifier not expected here");
|
|
|
|
if (LexGetToken(Parser, NULL, false) == TokenOpenBracket) {
|
|
ExpressionParseFunctionCall(Parser, &StackTop,
|
|
LexValue->Val->Identifier,
|
|
Parser->Mode == RunModeRun && Precedence < IgnorePrecedence);
|
|
} else {
|
|
if (Parser->Mode == RunModeRun /* && Precedence < IgnorePrecedence */) {
|
|
struct Value *VariableValue = NULL;
|
|
|
|
VariableGet(Parser->pc, Parser, LexValue->Val->Identifier,
|
|
&VariableValue);
|
|
if (VariableValue->Typ->Base == TypeMacro) {
|
|
/* evaluate a macro as a kind of simple subroutine */
|
|
struct ParseState MacroParser;
|
|
struct Value *MacroResult;
|
|
|
|
ParserCopy(&MacroParser, &VariableValue->Val->MacroDef.Body);
|
|
MacroParser.Mode = Parser->Mode;
|
|
if (VariableValue->Val->MacroDef.NumParams != 0)
|
|
ProgramFail(&MacroParser, "macro arguments missing");
|
|
|
|
if (!ExpressionParse(&MacroParser, &MacroResult) ||
|
|
LexGetToken(&MacroParser, NULL, false) != TokenEndOfFunction)
|
|
ProgramFail(&MacroParser, "expression expected");
|
|
|
|
ExpressionStackPushValueNode(Parser, &StackTop, MacroResult);
|
|
} else if (VariableValue->Typ == &Parser->pc->VoidType)
|
|
ProgramFail(Parser, "a void value isn't much use here");
|
|
else
|
|
ExpressionStackPushLValue(Parser, &StackTop,
|
|
VariableValue, 0); /* it's a value variable */
|
|
} else /* push a dummy value */
|
|
ExpressionPushInt(Parser, &StackTop, 0);
|
|
|
|
}
|
|
|
|
/* if we've successfully ignored the RHS turn ignoring off */
|
|
if (Precedence <= IgnorePrecedence)
|
|
IgnorePrecedence = DEEP_PRECEDENCE;
|
|
|
|
PrefixState = false;
|
|
} else if ((int)Token > TokenCloseBracket && (int)Token <= TokenCharacterConstant) {
|
|
/* it's a value of some sort, push it */
|
|
if (!PrefixState)
|
|
ProgramFail(Parser, "value not expected here");
|
|
|
|
PrefixState = false;
|
|
ExpressionStackPushValue(Parser, &StackTop, LexValue);
|
|
} else if (IsTypeToken(Parser, Token, LexValue)) {
|
|
/* it's a type. push it on the stack like a value. this is used in sizeof() */
|
|
struct ValueType *Typ;
|
|
char *Identifier;
|
|
struct Value *TypeValue;
|
|
|
|
if (!PrefixState)
|
|
ProgramFail(Parser, "type not expected here");
|
|
|
|
PrefixState = false;
|
|
ParserCopy(Parser, &PreState);
|
|
TypeParse(Parser, &Typ, &Identifier, NULL);
|
|
TypeValue = VariableAllocValueFromType(Parser->pc, Parser,
|
|
&Parser->pc->TypeType, false, NULL, false);
|
|
TypeValue->Val->Typ = Typ;
|
|
ExpressionStackPushValueNode(Parser, &StackTop, TypeValue);
|
|
} else {
|
|
/* it isn't a token from an expression */
|
|
ParserCopy(Parser, &PreState);
|
|
Done = true;
|
|
}
|
|
} while (!Done);
|
|
|
|
/* check that brackets have been closed */
|
|
if (BracketPrecedence > 0)
|
|
ProgramFail(Parser, "brackets not closed");
|
|
|
|
/* scan and collapse the stack to precedence 0 */
|
|
ExpressionStackCollapse(Parser, &StackTop, 0, &IgnorePrecedence);
|
|
|
|
/* fix up the stack and return the result if we're in run mode */
|
|
if (StackTop != NULL) {
|
|
/* all that should be left is a single value on the stack */
|
|
if (Parser->Mode == RunModeRun) {
|
|
if (StackTop->Order != OrderNone || StackTop->Next != NULL)
|
|
ProgramFail(Parser, "invalid expression");
|
|
|
|
*Result = StackTop->Val;
|
|
HeapPopStack(Parser->pc, StackTop, sizeof(struct ExpressionStack));
|
|
} else
|
|
HeapPopStack(Parser->pc, StackTop->Val,
|
|
sizeof(struct ExpressionStack)+sizeof(struct Value)+TypeStackSizeValue(StackTop->Val));
|
|
}
|
|
|
|
#ifdef DEBUG_EXPRESSIONS
|
|
printf("ExpressionParse() done\n\n");
|
|
ExpressionStackShow(Parser->pc, StackTop);
|
|
#endif
|
|
return StackTop != NULL;
|
|
}
|
|
|
|
/* do a parameterised macro call */
|
|
void ExpressionParseMacroCall(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, const char *MacroName,
|
|
struct MacroDef *MDef)
|
|
{
|
|
int ArgCount;
|
|
enum LexToken Token;
|
|
struct Value *ReturnValue = NULL;
|
|
struct Value *Param;
|
|
struct Value **ParamArray = NULL;
|
|
|
|
if (Parser->Mode == RunModeRun) {
|
|
/* create a stack frame for this macro */
|
|
ExpressionStackPushValueByType(Parser, StackTop, &Parser->pc->FPType); /* largest return type there is */
|
|
ReturnValue = (*StackTop)->Val;
|
|
HeapPushStackFrame(Parser->pc);
|
|
ParamArray = HeapAllocStack(Parser->pc,
|
|
sizeof(struct Value*)*MDef->NumParams);
|
|
if (ParamArray == NULL)
|
|
ProgramFail(Parser, "(ExpressionParseMacroCall) out of memory");
|
|
} else
|
|
ExpressionPushInt(Parser, StackTop, 0);
|
|
|
|
/* parse arguments */
|
|
ArgCount = 0;
|
|
do {
|
|
if (ExpressionParse(Parser, &Param)) {
|
|
if (Parser->Mode == RunModeRun) {
|
|
if (ArgCount < MDef->NumParams)
|
|
ParamArray[ArgCount] = Param;
|
|
else
|
|
ProgramFail(Parser, "too many arguments to %s()", MacroName);
|
|
}
|
|
|
|
ArgCount++;
|
|
Token = LexGetToken(Parser, NULL, true);
|
|
if (Token != TokenComma && Token != TokenCloseBracket)
|
|
ProgramFail(Parser, "comma expected");
|
|
} else {
|
|
/* end of argument list? */
|
|
Token = LexGetToken(Parser, NULL, true);
|
|
if (!TokenCloseBracket)
|
|
ProgramFail(Parser, "bad argument");
|
|
}
|
|
|
|
} while (Token != TokenCloseBracket);
|
|
|
|
if (Parser->Mode == RunModeRun) {
|
|
/* evaluate the macro */
|
|
struct ParseState MacroParser;
|
|
int Count;
|
|
struct Value *EvalValue;
|
|
|
|
if (ArgCount < MDef->NumParams)
|
|
ProgramFail(Parser, "not enough arguments to '%s'", MacroName);
|
|
|
|
if (MDef->Body.Pos == NULL)
|
|
ProgramFail(Parser, "ExpressionParseMacroCall MacroName: '%s' is undefined", MacroName);
|
|
|
|
ParserCopy(&MacroParser, &MDef->Body);
|
|
MacroParser.Mode = Parser->Mode;
|
|
VariableStackFrameAdd(Parser, MacroName, 0);
|
|
Parser->pc->TopStackFrame->NumParams = ArgCount;
|
|
Parser->pc->TopStackFrame->ReturnValue = ReturnValue;
|
|
for (Count = 0; Count < MDef->NumParams; Count++)
|
|
VariableDefine(Parser->pc, Parser, MDef->ParamName[Count],
|
|
ParamArray[Count], NULL, true);
|
|
|
|
ExpressionParse(&MacroParser, &EvalValue);
|
|
ExpressionAssign(Parser, ReturnValue, EvalValue, true, MacroName, 0, false);
|
|
VariableStackFramePop(Parser);
|
|
HeapPopStackFrame(Parser->pc);
|
|
}
|
|
}
|
|
|
|
/* do a function call */
|
|
void ExpressionParseFunctionCall(struct ParseState *Parser,
|
|
struct ExpressionStack **StackTop, const char *FuncName, int RunIt)
|
|
{
|
|
int ArgCount;
|
|
enum LexToken Token = LexGetToken(Parser, NULL, true); /* open bracket */
|
|
enum RunMode OldMode = Parser->Mode;
|
|
struct Value *ReturnValue = NULL;
|
|
struct Value *FuncValue = NULL;
|
|
struct Value *Param;
|
|
struct Value **ParamArray = NULL;
|
|
|
|
if (RunIt) {
|
|
/* get the function definition */
|
|
VariableGet(Parser->pc, Parser, FuncName, &FuncValue);
|
|
|
|
if (FuncValue->Typ->Base == TypeMacro) {
|
|
/* this is actually a macro, not a function */
|
|
ExpressionParseMacroCall(Parser, StackTop, FuncName,
|
|
&FuncValue->Val->MacroDef);
|
|
return;
|
|
}
|
|
|
|
if (FuncValue->Typ->Base != TypeFunction)
|
|
ProgramFail(Parser, "%t is not a function - can't call",
|
|
FuncValue->Typ);
|
|
|
|
ExpressionStackPushValueByType(Parser, StackTop,
|
|
FuncValue->Val->FuncDef.ReturnType);
|
|
ReturnValue = (*StackTop)->Val;
|
|
HeapPushStackFrame(Parser->pc);
|
|
ParamArray = HeapAllocStack(Parser->pc,
|
|
sizeof(struct Value*)*FuncValue->Val->FuncDef.NumParams);
|
|
if (ParamArray == NULL)
|
|
ProgramFail(Parser, "(ExpressionParseFunctionCall) out of memory");
|
|
} else {
|
|
ExpressionPushInt(Parser, StackTop, 0);
|
|
Parser->Mode = RunModeSkip;
|
|
}
|
|
|
|
/* parse arguments */
|
|
ArgCount = 0;
|
|
do {
|
|
if (RunIt && ArgCount < FuncValue->Val->FuncDef.NumParams)
|
|
ParamArray[ArgCount] = VariableAllocValueFromType(Parser->pc, Parser,
|
|
FuncValue->Val->FuncDef.ParamType[ArgCount], false, NULL, false);
|
|
|
|
if (ExpressionParse(Parser, &Param)) {
|
|
if (RunIt) {
|
|
if (ArgCount < FuncValue->Val->FuncDef.NumParams) {
|
|
ExpressionAssign(Parser, ParamArray[ArgCount], Param, true,
|
|
FuncName, ArgCount+1, false);
|
|
VariableStackPop(Parser, Param);
|
|
} else {
|
|
if (!FuncValue->Val->FuncDef.VarArgs)
|
|
ProgramFail(Parser, "too many arguments to %s()", FuncName);
|
|
}
|
|
}
|
|
|
|
ArgCount++;
|
|
Token = LexGetToken(Parser, NULL, true);
|
|
if (Token != TokenComma && Token != TokenCloseBracket)
|
|
ProgramFail(Parser, "comma expected");
|
|
} else {
|
|
/* end of argument list? */
|
|
Token = LexGetToken(Parser, NULL, true);
|
|
if (!TokenCloseBracket)
|
|
ProgramFail(Parser, "bad argument");
|
|
}
|
|
|
|
} while (Token != TokenCloseBracket);
|
|
|
|
if (RunIt) {
|
|
/* run the function */
|
|
if (ArgCount < FuncValue->Val->FuncDef.NumParams)
|
|
ProgramFail(Parser, "not enough arguments to '%s'", FuncName);
|
|
|
|
if (FuncValue->Val->FuncDef.Intrinsic == NULL) {
|
|
/* run a user-defined function */
|
|
int Count;
|
|
int OldScopeID = Parser->ScopeID;
|
|
struct ParseState FuncParser;
|
|
|
|
if (FuncValue->Val->FuncDef.Body.Pos == NULL)
|
|
ProgramFail(Parser, "ExpressionParseFunctionCall FuncName: '%s' is undefined", FuncName);
|
|
|
|
ParserCopy(&FuncParser, &FuncValue->Val->FuncDef.Body);
|
|
VariableStackFrameAdd(Parser, FuncName,
|
|
FuncValue->Val->FuncDef.Intrinsic ? FuncValue->Val->FuncDef.NumParams : 0);
|
|
Parser->pc->TopStackFrame->NumParams = ArgCount;
|
|
Parser->pc->TopStackFrame->ReturnValue = ReturnValue;
|
|
|
|
/* Function parameters should not go out of scope */
|
|
Parser->ScopeID = -1;
|
|
|
|
for (Count = 0; Count < FuncValue->Val->FuncDef.NumParams; Count++)
|
|
VariableDefine(Parser->pc, Parser,
|
|
FuncValue->Val->FuncDef.ParamName[Count], ParamArray[Count],
|
|
NULL, true);
|
|
|
|
Parser->ScopeID = OldScopeID;
|
|
|
|
if (ParseStatement(&FuncParser, true) != ParseResultOk)
|
|
ProgramFail(&FuncParser, "function body expected");
|
|
|
|
if (RunIt) {
|
|
if (FuncParser.Mode == RunModeRun &&
|
|
FuncValue->Val->FuncDef.ReturnType != &Parser->pc->VoidType)
|
|
ProgramFail(&FuncParser,
|
|
"no value returned from a function returning %t",
|
|
FuncValue->Val->FuncDef.ReturnType);
|
|
|
|
else if (FuncParser.Mode == RunModeGoto)
|
|
ProgramFail(&FuncParser, "couldn't find goto label '%s'",
|
|
FuncParser.SearchGotoLabel);
|
|
}
|
|
|
|
VariableStackFramePop(Parser);
|
|
} else
|
|
FuncValue->Val->FuncDef.Intrinsic(Parser, ReturnValue, ParamArray,
|
|
ArgCount);
|
|
|
|
HeapPopStackFrame(Parser->pc);
|
|
}
|
|
|
|
Parser->Mode = OldMode;
|
|
}
|
|
|
|
/* parse an expression */
|
|
long ExpressionParseInt(struct ParseState *Parser)
|
|
{
|
|
long Result = 0;
|
|
struct Value *Val;
|
|
|
|
if (!ExpressionParse(Parser, &Val))
|
|
ProgramFail(Parser, "expression expected");
|
|
|
|
if (Parser->Mode == RunModeRun) {
|
|
if (!IS_NUMERIC_COERCIBLE(Val))
|
|
ProgramFail(Parser, "integer value expected instead of %t", Val->Typ);
|
|
|
|
Result = ExpressionCoerceInteger(Val);
|
|
VariableStackPop(Parser, Val);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|