/* 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 */
    unsigned short 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, ")"}
};


#ifdef DEBUG_EXPRESSIONS
static void ExpressionStackShow(Picoc *pc, struct ExpressionStack *StackTop);
#endif
static int IsTypeToken(struct ParseState * Parser, enum LexToken t, struct Value * LexValue);
static long ExpressionAssignInt(struct ParseState *Parser, struct Value *DestValue, long FromInt, int After);
static double ExpressionAssignFP(struct ParseState *Parser, struct Value *DestValue, double FromFP);
static void ExpressionStackPushValueNode(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *ValueLoc);
static struct Value *ExpressionStackPushValueByType(struct ParseState *Parser, struct ExpressionStack **StackTop, struct ValueType *PushType);
static void ExpressionStackPushValue(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *PushValue);
static void ExpressionStackPushLValue(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *PushValue, int Offset);
static void ExpressionStackPushDereference(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *DereferenceValue);
static void ExpressionPushInt(struct ParseState *Parser, struct ExpressionStack **StackTop, long IntValue);
static void ExpressionPushFP(struct ParseState *Parser, struct ExpressionStack **StackTop, double FPValue);
static void ExpressionAssignToPointer(struct ParseState *Parser, struct Value *ToValue, struct Value *FromValue, const char *FuncName, int ParamNo, int AllowPointerCoercion);
static void ExpressionQuestionMarkOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *BottomValue, struct Value *TopValue);
static void ExpressionColonOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *BottomValue, struct Value *TopValue);
static void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue);
static void ExpressionPostfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue);
static void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *BottomValue, struct Value *TopValue);
static void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack **StackTop, int Precedence, int *IgnorePrecedence);
static void ExpressionStackPushOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum OperatorOrder Order, enum LexToken Token, int Precedence);
static void ExpressionParseMacroCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *MacroName, struct MacroDef *MDef);
static 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)
{
    switch (Val->Typ->Base) {
    case TypeInt:
        return (double)Val->Val->Integer;
    case TypeChar:
        return (double)Val->Val->Character;
    case TypeShort:
        return (double)Val->Val->ShortInteger;
    case TypeLong:
        return (double)Val->Val->LongInteger;
    case TypeUnsignedInt:
        return (double)Val->Val->UnsignedInteger;
    case TypeUnsignedShort:
        return (double)Val->Val->UnsignedShortInteger;
    case TypeUnsignedLong:
        return (double)Val->Val->UnsignedLongInteger;
    case TypeUnsignedChar:
        return (double)Val->Val->UnsignedCharacter;
    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 = (int)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(*StackNode), 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(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);
    // jdp: an ugly hack to a) assign the correct value and b) properly print long values
    ValueLoc->Val->UnsignedLongInteger = (unsigned long)IntValue;
    ValueLoc->Val->LongInteger = (long)IntValue;
    ValueLoc->Val->Integer = (int)IntValue;
    ValueLoc->Val->ShortInteger = (short)IntValue;
    ValueLoc->Val->UnsignedShortInteger = (unsigned short)IntValue;
    ValueLoc->Val->UnsignedInteger = (unsigned int)IntValue;
    ValueLoc->Val->UnsignedCharacter = (unsigned char)IntValue;
    ValueLoc->Val->Character = (char)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(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 = (int)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 = SourceValue->Val->LongInteger;
        break;
    case TypeUnsignedInt:
        DestValue->Val->UnsignedInteger =
            (unsigned int)ExpressionCoerceUnsignedInteger(SourceValue);
        break;
    case TypeUnsignedShort:
        DestValue->Val->UnsignedShortInteger =
            (unsigned short)ExpressionCoerceUnsignedInteger(SourceValue);
        break;
    case TypeUnsignedLong:
        DestValue->Val->UnsignedLongInteger = SourceValue->Val->UnsignedLongInteger;
        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 = (double)ExpressionCoerceFP(SourceValue);
        break;
    case TypePointer:
        ExpressionAssignToPointer(Parser, DestValue, SourceValue, FuncName,
            ParamNo, AllowPointerCoercion);
        break;
    case TypeArray:
        if (SourceValue->Typ->Base == TypeArray && 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;
    struct ValueType *Typ;

#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:
        if(StackTop != NULL && (*StackTop) != NULL && (*StackTop)->Op == TokenSizeof)
            /* ignored */
            ExpressionStackPushValueByType(Parser, StackTop, TopValue->Typ);
        else
            ExpressionStackPushDereference(Parser, StackTop, TopValue);
        break;
    case TokenSizeof:
        /* return the size of the argument */
        if (TopValue->Typ == &Parser->pc->TypeType)
            Typ = TopValue->Val->Typ;
        else
            Typ = TopValue->Typ;
        if (Typ->FromType != NULL && Typ->FromType->Base == TypeStruct)
            Typ = Typ->FromType;
        ExpressionPushInt(Parser, StackTop, TypeSize(Typ, 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 = 0;
            if (TopValue->Typ->Base == TypeLong)
                TopInt = TopValue->Val->LongInteger;
            else
                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 = 0;
            if (Op != TokenUnaryNot && TopValue->Val->Pointer == NULL)
                ProgramFail(Parser, "a. invalid use of a NULL pointer");
            if (!TopValue->IsLValue)
                ProgramFail(Parser, "can't assign to this");
            switch (Op) {
            case TokenIncrement:
                ResultPtr = TopValue->Val->Pointer =
                    (void*)((char*)TopValue->Val->Pointer+Size);
                break;
            case TokenDecrement:
                ResultPtr = TopValue->Val->Pointer =
                    (void*)((char*)TopValue->Val->Pointer-Size);
                break;
            case TokenUnaryNot:
                /* conditionally checking a pointer's value, we only want
                    to change the stack value (ResultPtr) and not the pointer's
                    actual value  */
                TopValue->Val->Pointer =
                    (void*)((char*)TopValue->Val->Pointer);
                    ResultPtr = TopValue->Val->Pointer ? NULL : (void*)0x01;
                break;
            default:
                ProgramFail(Parser, "invalid operation");
                break;
            }
            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, "b. 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);
            if (BottomValue->Typ->Base == TypeUnsignedInt || BottomValue->Typ->Base == TypeUnsignedLong)
                ResultInt = ExpressionAssignInt(Parser, BottomValue, (uint64_t) BottomInt >> TopInt, false);
            else
                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, "c. 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, "d. 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 s
            izeof(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:
            default:
                /* 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(*StackNode), 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(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 parameterized 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 */
        /* largest return type there is */
        ExpressionStackPushValueByType(Parser, StackTop, &Parser->pc->FPType);
        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 (Token != 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 (Token != 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 {
            // FIXME: too many parameters?
            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_PLUS_POINTERS(Val, true))
            ProgramFail(Parser, "integer value expected instead of %t", Val->Typ);

        Result = ExpressionCoerceInteger(Val);
        VariableStackPop(Parser, Val);
    }

    return Result;
}

