mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-05 08:02:03 +00:00
b1a83bfd26
* everything related to scripting is now placed in a subdirectory 'scripting', which itself is separated into DECORATE, ZSCRIPT, the VM and code generation. * a few items have been moved to different headers so that the DECORATE parser definitions can mostly be kept local. The only exception at the moment is the flags interface on which 3 source files depend.
517 lines
21 KiB
C++
517 lines
21 KiB
C++
/*
|
|
** zcc_expr.cpp
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright -2016 Randy Heit
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include "dobject.h"
|
|
#include "sc_man.h"
|
|
#include "c_console.h"
|
|
#include "c_dispatch.h"
|
|
#include "w_wad.h"
|
|
#include "cmdlib.h"
|
|
#include "m_alloc.h"
|
|
#include "zcc_parser.h"
|
|
#include "templates.h"
|
|
|
|
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
|
|
|
|
static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena);
|
|
|
|
ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] =
|
|
{
|
|
#define xx(a,z) { #a, NULL },
|
|
#include "zcc_exprlist.h"
|
|
};
|
|
|
|
// Structures used for initializing operator overloads
|
|
struct OpProto1
|
|
{
|
|
EZCCExprType Op;
|
|
PType **Type;
|
|
EvalConst1op EvalConst;
|
|
};
|
|
|
|
struct OpProto2
|
|
{
|
|
EZCCExprType Op;
|
|
PType **Res, **Ltype, **Rtype;
|
|
EvalConst2op EvalConst;
|
|
};
|
|
|
|
static struct FreeOpInfoProtos
|
|
{
|
|
~FreeOpInfoProtos()
|
|
{
|
|
for (size_t i = 0; i < countof(ZCC_OpInfo); ++i)
|
|
{
|
|
ZCC_OpInfo[i].FreeAllProtos();
|
|
}
|
|
}
|
|
} ProtoFreeer;
|
|
|
|
void ZCC_OpInfoType::FreeAllProtos()
|
|
{
|
|
for (ZCC_OpProto *proto = Protos, *next = NULL; proto != NULL; proto = next)
|
|
{
|
|
next = proto->Next;
|
|
delete proto;
|
|
}
|
|
Protos = NULL;
|
|
}
|
|
|
|
void ZCC_OpInfoType::AddProto(PType *res, PType *optype, EvalConst1op evalconst)
|
|
{
|
|
ZCC_OpProto *proto = new ZCC_OpProto(res, optype, NULL);
|
|
proto->EvalConst1 = evalconst;
|
|
proto->Next = Protos;
|
|
Protos = proto;
|
|
}
|
|
|
|
void ZCC_OpInfoType::AddProto(PType *res, PType *ltype, PType *rtype, EvalConst2op evalconst)
|
|
{
|
|
assert(ltype != NULL);
|
|
ZCC_OpProto *proto = new ZCC_OpProto(res, ltype, rtype);
|
|
proto->EvalConst2 = evalconst;
|
|
proto->Next = Protos;
|
|
Protos = proto;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ZCC_OpInfoType :: FindBestProto (Unary)
|
|
//
|
|
// Finds the "best" prototype for this operand type. Best is defined as the
|
|
// one that requires the fewest conversions. Also returns the conversion
|
|
// route necessary to get from the input type to the desired type.
|
|
//
|
|
//==========================================================================
|
|
|
|
ZCC_OpProto *ZCC_OpInfoType::FindBestProto(PType *optype, const PType::Conversion **route, int &numslots)
|
|
{
|
|
assert(optype != NULL);
|
|
|
|
const PType::Conversion *routes[2][CONVERSION_ROUTE_SIZE];
|
|
const PType::Conversion **best_route = NULL;
|
|
int cur_route = 0;
|
|
ZCC_OpProto *best_proto = NULL;
|
|
int best_dist = INT_MAX;
|
|
|
|
// Find the best prototype.
|
|
for (ZCC_OpProto *proto = Protos; best_dist != 0 && proto != NULL; proto = proto->Next)
|
|
{
|
|
if (proto->Type2 != NULL)
|
|
{ // Not a unary prototype.
|
|
continue;
|
|
}
|
|
int dist = optype->FindConversion(proto->Type1, routes[cur_route], CONVERSION_ROUTE_SIZE);
|
|
if (dist >= 0 && dist < best_dist)
|
|
{
|
|
best_dist = dist;
|
|
best_proto = proto;
|
|
best_route = routes[cur_route];
|
|
cur_route ^= 1;
|
|
}
|
|
}
|
|
// Copy best conversion route to the caller's array.
|
|
if (best_route != NULL && route != NULL && numslots > 0)
|
|
{
|
|
numslots = MIN(numslots, best_dist);
|
|
if (numslots > 0)
|
|
{
|
|
memcpy(route, best_route, sizeof(*route) * numslots);
|
|
}
|
|
}
|
|
return best_proto;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ZCC_OpInfoType :: FindBestProto (Binary)
|
|
//
|
|
// Finds the "best" prototype for the given operand types. Here, best is
|
|
// defined as the one that requires the fewest conversions for *one* of the
|
|
// operands. For prototypes with matching distances, the first one found
|
|
// is used. ZCC_InitOperators() initializes the prototypes in order such
|
|
// that this will result in the precedences: double > uint > int
|
|
//
|
|
//==========================================================================
|
|
|
|
ZCC_OpProto *ZCC_OpInfoType::FindBestProto(
|
|
PType *left, const PType::Conversion **route1, int &numslots1,
|
|
PType *right, const PType::Conversion **route2, int &numslots2)
|
|
{
|
|
assert(left != NULL && right != NULL);
|
|
|
|
const PType::Conversion *routes[2][2][CONVERSION_ROUTE_SIZE];
|
|
const PType::Conversion **best_route1 = NULL, **best_route2 = NULL;
|
|
int cur_route1 = 0, cur_route2 = 0;
|
|
int best_dist1 = INT_MAX, best_dist2 = INT_MAX;
|
|
|
|
ZCC_OpProto *best_proto = NULL;
|
|
int best_low_dist = INT_MAX;
|
|
|
|
for (ZCC_OpProto *proto = Protos; best_low_dist != 0 && proto != NULL; proto = proto->Next)
|
|
{
|
|
if (proto->Type2 == NULL)
|
|
{ // Not a binary prototype
|
|
continue;
|
|
}
|
|
int dist1 = left->FindConversion(proto->Type1, routes[0][cur_route1], CONVERSION_ROUTE_SIZE);
|
|
int dist2 = right->FindConversion(proto->Type2, routes[1][cur_route2], CONVERSION_ROUTE_SIZE);
|
|
if (dist1 < 0 || dist2 < 0)
|
|
{ // one or both operator types are unreachable
|
|
continue;
|
|
}
|
|
// Do not count F32->F64 conversions in the distance comparisons. If we do, then
|
|
// [[float32 (op) int]] will choose the integer version instead of the floating point
|
|
// version, which we do not want.
|
|
int test_dist1 = dist1, test_dist2 = dist2;
|
|
if (test_dist1 > 0 && routes[0][cur_route1][0]->ConvertConstant == FtoD)
|
|
{
|
|
test_dist1--;
|
|
}
|
|
if (test_dist2 > 0 && routes[1][cur_route2][0]->ConvertConstant == FtoD)
|
|
{
|
|
test_dist2--;
|
|
}
|
|
int dist = MIN(test_dist1, test_dist2);
|
|
if (dist < best_low_dist)
|
|
{
|
|
best_low_dist = dist;
|
|
best_proto = proto;
|
|
best_dist1 = dist1;
|
|
best_dist2 = dist2;
|
|
best_route1 = routes[0][cur_route1];
|
|
best_route2 = routes[1][cur_route2];
|
|
cur_route1 ^= 1;
|
|
cur_route2 ^= 1;
|
|
}
|
|
}
|
|
// Copy best conversion route to the caller's arrays.
|
|
if (best_route1 != NULL && route1 != NULL && numslots1 > 0)
|
|
{
|
|
numslots1 = MIN(numslots1, best_dist1);
|
|
if (numslots1 > 0)
|
|
{
|
|
memcpy(route1, best_route1, sizeof(*route1) * numslots1);
|
|
}
|
|
}
|
|
if (best_route2 != NULL && route2 != NULL && numslots2 > 0)
|
|
{
|
|
numslots2 = MIN(numslots2, best_dist2);
|
|
if (numslots2 > 0)
|
|
{
|
|
memcpy(route2, best_route2, sizeof(*route2) * numslots2);
|
|
}
|
|
}
|
|
return best_proto;
|
|
}
|
|
|
|
static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
|
|
static ZCC_ExprConstant *EvalConcat(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &strings)
|
|
{
|
|
FString str = *l->StringVal + *r->StringVal;
|
|
l->StringVal = strings.Alloc(str);
|
|
return l;
|
|
}
|
|
|
|
static ZCC_ExprConstant *EvalLTGTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
|
{
|
|
l->IntVal = l->IntVal < r->IntVal ? -1 : l->IntVal == r->IntVal ? 0 : 1;
|
|
return l;
|
|
}
|
|
|
|
static ZCC_ExprConstant *EvalLTGTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
|
{
|
|
l->IntVal = l->UIntVal < r->UIntVal ? -1 : l->UIntVal == r->UIntVal ? 0 : 1;
|
|
l->Type = TypeSInt32;
|
|
return l;
|
|
}
|
|
|
|
static ZCC_ExprConstant *EvalLTGTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
|
{
|
|
l->IntVal = l->DoubleVal < r->DoubleVal ? -1 : l->DoubleVal == r->DoubleVal ? 0 : 1;
|
|
l->Type = TypeSInt32;
|
|
return l;
|
|
}
|
|
|
|
void ZCC_InitOperators()
|
|
{
|
|
// Prototypes are added from lowest to highest conversion precedence.
|
|
|
|
// Unary operators
|
|
static const OpProto1 UnaryOpInit[] =
|
|
{
|
|
{ PEX_PostInc , (PType **)&TypeSInt32, EvalIdentity },
|
|
{ PEX_PostInc , (PType **)&TypeUInt32, EvalIdentity },
|
|
{ PEX_PostInc , (PType **)&TypeFloat64, EvalIdentity },
|
|
|
|
{ PEX_PostDec , (PType **)&TypeSInt32, EvalIdentity },
|
|
{ PEX_PostDec , (PType **)&TypeUInt32, EvalIdentity },
|
|
{ PEX_PostDec , (PType **)&TypeFloat64, EvalIdentity },
|
|
|
|
{ PEX_PreInc , (PType **)&TypeSInt32, [](auto *val) { val->IntVal += 1; return val; } },
|
|
{ PEX_PreInc , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal += 1; return val; } },
|
|
{ PEX_PreInc , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal += 1; return val; } },
|
|
|
|
{ PEX_PreDec , (PType **)&TypeSInt32, [](auto *val) { val->IntVal -= 1; return val; } },
|
|
{ PEX_PreDec , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal -= 1; return val; } },
|
|
{ PEX_PreDec , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal -= 1; return val; } },
|
|
|
|
{ PEX_Negate , (PType **)&TypeSInt32, [](auto *val) { val->IntVal = -val->IntVal; return val; } },
|
|
{ PEX_Negate , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal = -val->DoubleVal; return val; } },
|
|
|
|
{ PEX_AntiNegate , (PType **)&TypeSInt32, EvalIdentity },
|
|
{ PEX_AntiNegate , (PType **)&TypeUInt32, EvalIdentity },
|
|
{ PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity },
|
|
|
|
{ PEX_BitNot , (PType **)&TypeSInt32, [](auto *val) { val->IntVal = ~val->IntVal; return val; } },
|
|
{ PEX_BitNot , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal = ~val->UIntVal; return val; } },
|
|
|
|
{ PEX_BoolNot , (PType **)&TypeBool, [](auto *val) { val->IntVal = !val->IntVal; return val; } },
|
|
};
|
|
for (size_t i = 0; i < countof(UnaryOpInit); ++i)
|
|
{
|
|
ZCC_OpInfo[UnaryOpInit[i].Op].AddProto(*UnaryOpInit[i].Type, *UnaryOpInit[i].Type, UnaryOpInit[i].EvalConst);
|
|
}
|
|
|
|
// Binary operators
|
|
static const OpProto2 BinaryOpInit[] =
|
|
{
|
|
{ PEX_Add , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal += r->IntVal; return l; } },
|
|
{ PEX_Add , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal += r->UIntVal; return l; } },
|
|
{ PEX_Add , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal += r->DoubleVal; return l; } },
|
|
|
|
{ PEX_Sub , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal -= r->IntVal; return l; } },
|
|
{ PEX_Sub , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal -= r->UIntVal; return l; } },
|
|
{ PEX_Sub , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal -= r->DoubleVal; return l; } },
|
|
|
|
{ PEX_Mul , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal *= r->IntVal; return l; } },
|
|
{ PEX_Mul , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal *= r->UIntVal; return l; } },
|
|
{ PEX_Mul , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal *= r->DoubleVal; return l; } },
|
|
|
|
{ PEX_Div , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal /= r->IntVal; return l; } },
|
|
{ PEX_Div , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal /= r->UIntVal; return l; } },
|
|
{ PEX_Div , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal /= r->DoubleVal; return l; } },
|
|
|
|
{ PEX_Mod , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal %= r->IntVal; return l; } },
|
|
{ PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal %= r->UIntVal; return l; } },
|
|
{ PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); return l; } },
|
|
|
|
{ PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); return l; } },
|
|
|
|
{ PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat },
|
|
|
|
{ PEX_BitAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal &= r->IntVal; return l; } },
|
|
{ PEX_BitAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal &= r->UIntVal; return l; } },
|
|
|
|
{ PEX_BitOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal |= r->IntVal; return l; } },
|
|
{ PEX_BitOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal |= r->UIntVal; return l; } },
|
|
|
|
{ PEX_BitXor , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal ^= r->IntVal; return l; } },
|
|
{ PEX_BitXor , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal ^= r->UIntVal; return l; } },
|
|
|
|
{ PEX_BoolAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal && r->IntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_BoolAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal && r->UIntVal; l->Type = TypeBool; return l; } },
|
|
|
|
{ PEX_BoolOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal || r->IntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_BoolOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal || r->UIntVal; l->Type = TypeBool; return l; } },
|
|
|
|
{ PEX_LeftShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal <<= r->UIntVal; return l; } },
|
|
{ PEX_LeftShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal <<= r->UIntVal; return l; } },
|
|
|
|
{ PEX_RightShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal >>= r->UIntVal; return l; } },
|
|
{ PEX_RightShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal >>= r->UIntVal; return l; } },
|
|
|
|
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal < r->IntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal < r->UIntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal < r->DoubleVal; l->Type = TypeBool; return l; } },
|
|
|
|
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal <= r->IntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal <= r->UIntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal <= r->DoubleVal; l->Type = TypeBool; return l; } },
|
|
|
|
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal == r->IntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal == r->UIntVal; l->Type = TypeBool; return l; } },
|
|
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal == r->DoubleVal; l->Type = TypeBool; return l; } },
|
|
|
|
{ PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTGTEQSInt32 },
|
|
{ PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTGTEQUInt32 },
|
|
{ PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTGTEQFloat64 },
|
|
};
|
|
for (size_t i = 0; i < countof(BinaryOpInit); ++i)
|
|
{
|
|
ZCC_OpInfo[BinaryOpInit[i].Op].AddProto(*BinaryOpInit[i].Res, *BinaryOpInit[i].Ltype, *BinaryOpInit[i].Rtype, BinaryOpInit[i].EvalConst);
|
|
}
|
|
}
|
|
|
|
static void IntToS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
// Integers always fill out the full sized 32-bit field, so converting
|
|
// from a smaller sized integer to a 32-bit one is as simple as changing
|
|
// the type field.
|
|
expr->Type = TypeSInt32;
|
|
}
|
|
|
|
static void S32toS8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->IntVal = ((expr->IntVal << 24) >> 24);
|
|
expr->Type = TypeSInt8;
|
|
}
|
|
|
|
static void S32toS16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->IntVal = ((expr->IntVal << 16) >> 16);
|
|
expr->Type = TypeSInt16;
|
|
}
|
|
|
|
static void S32toU8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->IntVal &= 0xFF;
|
|
expr->Type = TypeUInt8;
|
|
}
|
|
|
|
static void S32toU16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->IntVal &= 0xFFFF;
|
|
expr->Type = TypeUInt16;
|
|
}
|
|
|
|
static void S32toU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->Type = TypeUInt32;
|
|
}
|
|
|
|
static void S32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->DoubleVal = expr->IntVal;
|
|
expr->Type = TypeFloat64;
|
|
}
|
|
|
|
static void DtoS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->IntVal = (int)expr->DoubleVal;
|
|
expr->Type = TypeSInt32;
|
|
}
|
|
|
|
static void U32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->DoubleVal = expr->UIntVal;
|
|
expr->Type = TypeFloat64;
|
|
}
|
|
|
|
static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
expr->UIntVal = (unsigned int)expr->DoubleVal;
|
|
expr->Type = TypeUInt32;
|
|
}
|
|
|
|
static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
// Constant single precision numbers are stored as doubles.
|
|
assert(expr->Type == TypeFloat32);
|
|
expr->Type = TypeFloat64;
|
|
}
|
|
|
|
static void DtoF(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
// Truncate double precision to single precision.
|
|
float poop = (float)expr->DoubleVal;
|
|
expr->DoubleVal = poop;
|
|
expr->Type = TypeFloat32;
|
|
}
|
|
|
|
static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
char str[16];
|
|
int len = mysnprintf(str, countof(str), "%i", expr->IntVal);
|
|
expr->StringVal = str_arena.Alloc(str, len);
|
|
expr->Type = TypeString;
|
|
}
|
|
|
|
static void U32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
char str[16];
|
|
int len = mysnprintf(str, countof(str), "%u", expr->UIntVal);
|
|
expr->StringVal = str_arena.Alloc(str, len);
|
|
expr->Type = TypeString;
|
|
}
|
|
|
|
static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
|
|
{
|
|
// Convert to a string with enough precision such that converting
|
|
// back to a double will not lose any data.
|
|
char str[64];
|
|
IGNORE_FORMAT_PRE
|
|
int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal);
|
|
IGNORE_FORMAT_POST
|
|
expr->StringVal = str_arena.Alloc(str, len);
|
|
expr->Type = TypeString;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ZCC_InitConversions
|
|
//
|
|
//==========================================================================
|
|
|
|
void ZCC_InitConversions()
|
|
{
|
|
TypeUInt8->AddConversion(TypeSInt32, IntToS32);
|
|
TypeSInt8->AddConversion(TypeSInt32, IntToS32);
|
|
TypeUInt16->AddConversion(TypeSInt32, IntToS32);
|
|
TypeSInt16->AddConversion(TypeSInt32, IntToS32);
|
|
|
|
TypeUInt32->AddConversion(TypeSInt32, IntToS32);
|
|
TypeUInt32->AddConversion(TypeFloat64, U32toD);
|
|
TypeUInt32->AddConversion(TypeString, U32toS);
|
|
|
|
TypeSInt32->AddConversion(TypeUInt8, S32toU8);
|
|
TypeSInt32->AddConversion(TypeSInt8, S32toS8);
|
|
TypeSInt32->AddConversion(TypeSInt16, S32toS16);
|
|
TypeSInt32->AddConversion(TypeUInt16, S32toU16);
|
|
TypeSInt32->AddConversion(TypeUInt32, S32toU32);
|
|
TypeSInt32->AddConversion(TypeFloat64, S32toD);
|
|
TypeSInt32->AddConversion(TypeString, S32toS);
|
|
|
|
TypeFloat32->AddConversion(TypeFloat64, FtoD);
|
|
|
|
TypeFloat64->AddConversion(TypeUInt32, DtoU32);
|
|
TypeFloat64->AddConversion(TypeSInt32, DtoS32);
|
|
TypeFloat64->AddConversion(TypeFloat32, DtoF);
|
|
TypeFloat64->AddConversion(TypeString, DtoS);
|
|
}
|