- removed all code that was only there to implement the broken Simplifier that just got removed.

This commit is contained in:
Christoph Oelckers 2017-01-23 01:37:43 +01:00
parent 68c3f42a53
commit f720073b31
9 changed files with 17 additions and 1170 deletions

View file

@ -1211,7 +1211,6 @@ set (PCH_SOURCES
scripting/vm/vmframe.cpp scripting/vm/vmframe.cpp
scripting/zscript/ast.cpp scripting/zscript/ast.cpp
scripting/zscript/zcc_compile.cpp scripting/zscript/zcc_compile.cpp
scripting/zscript/zcc_expr.cpp
scripting/zscript/zcc_parser.cpp scripting/zscript/zcc_parser.cpp
sfmt/SFMT.cpp sfmt/SFMT.cpp
) )

View file

@ -240,159 +240,6 @@ size_t PType::PropagateMark()
return marked + Super::PropagateMark(); return marked + Super::PropagateMark();
} }
//==========================================================================
//
// PType :: AddConversion
//
//==========================================================================
bool PType::AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &))
{
// Make sure a conversion hasn't already been registered
for (unsigned i = 0; i < Conversions.Size(); ++i)
{
if (Conversions[i].TargetType == target)
return false;
}
Conversions.Push(Conversion(target, convertconst));
return true;
}
//==========================================================================
//
// PType :: FindConversion
//
// Returns <0 if there is no path to target. Otherwise, returns the distance
// to target and fills slots (if non-NULL) with the necessary conversions
// to get there. A result of 0 means this is the target.
//
//==========================================================================
int PType::FindConversion(PType *target, const PType::Conversion **slots, int numslots)
{
if (this == target)
{
return 0;
}
// The queue is implemented as a ring buffer
VisitQueue queue;
VisitedNodeSet visited;
// Use a breadth-first search to find the shortest path to the target.
MarkPred(NULL, -1, -1);
queue.Push(this);
visited.Insert(this);
while (!queue.IsEmpty())
{
PType *t = queue.Pop();
if (t == target)
{ // found it
if (slots != NULL)
{
if (t->Distance >= numslots)
{ // Distance is too far for the output
return -2;
}
t->FillConversionPath(slots);
}
return t->Distance + 1;
}
for (unsigned i = 0; i < t->Conversions.Size(); ++i)
{
PType *succ = t->Conversions[i].TargetType;
if (!visited.Check(succ))
{
succ->MarkPred(t, i, t->Distance + 1);
visited.Insert(succ);
queue.Push(succ);
}
}
}
return -1;
}
//==========================================================================
//
// PType :: FillConversionPath
//
// Traces backwards from the target type to the original type and fills in
// the conversions necessary to get between them. slots must point to an
// array large enough to contain the entire path.
//
//==========================================================================
void PType::FillConversionPath(const PType::Conversion **slots)
{
for (PType *node = this; node->Distance >= 0; node = node->PredType)
{
assert(node->PredType != NULL);
slots[node->Distance] = &node->PredType->Conversions[node->PredConv];
}
}
//==========================================================================
//
// PType :: VisitQueue :: Push
//
//==========================================================================
void PType::VisitQueue::Push(PType *type)
{
Queue[In] = type;
Advance(In);
assert(!IsEmpty() && "Queue overflowed");
}
//==========================================================================
//
// PType :: VisitQueue :: Pop
//
//==========================================================================
PType *PType::VisitQueue::Pop()
{
if (IsEmpty())
{
return NULL;
}
PType *node = Queue[Out];
Advance(Out);
return node;
}
//==========================================================================
//
// PType :: VisitedNodeSet :: Insert
//
//==========================================================================
void PType::VisitedNodeSet::Insert(PType *node)
{
assert(!Check(node) && "Node was already inserted");
size_t buck = Hash(node) & (countof(Buckets) - 1);
node->VisitNext = Buckets[buck];
Buckets[buck] = node;
}
//==========================================================================
//
// PType :: VisitedNodeSet :: Check
//
//==========================================================================
bool PType::VisitedNodeSet::Check(const PType *node)
{
size_t buck = Hash(node) & (countof(Buckets) - 1);
for (const PType *probe = Buckets[buck]; probe != NULL; probe = probe->VisitNext)
{
if (probe == node)
{
return true;
}
}
return false;
}
//========================================================================== //==========================================================================
// //
// PType :: WriteValue // PType :: WriteValue

View file

@ -214,15 +214,6 @@ public:
typedef PClassType MetaClass; typedef PClassType MetaClass;
MetaClass *GetClass() const; MetaClass *GetClass() const;
struct Conversion
{
Conversion(PType *target, void (*convert)(ZCC_ExprConstant *, class FSharedStringArena &))
: TargetType(target), ConvertConstant(convert) {}
PType *TargetType;
void (*ConvertConstant)(ZCC_ExprConstant *val, class FSharedStringArena &strdump);
};
unsigned int Size; // this type's size unsigned int Size; // this type's size
unsigned int Align; // this type's preferred alignment unsigned int Align; // this type's preferred alignment
PType *HashNext; // next type in this type table PType *HashNext; // next type in this type table
@ -235,10 +226,6 @@ public:
virtual ~PType(); virtual ~PType();
virtual bool isNumeric() { return false; } virtual bool isNumeric() { return false; }
bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &));
int FindConversion(PType *target, const Conversion **slots, int numslots);
// Writes the value of a variable of this type at (addr) to an archive, preceded by // Writes the value of a variable of this type at (addr) to an archive, preceded by
// a tag indicating its type. The tag is there so that variable types can be changed // a tag indicating its type. The tag is there so that variable types can be changed
// without completely breaking savegames, provided that the change isn't between // without completely breaking savegames, provided that the change isn't between
@ -318,54 +305,6 @@ public:
size_t PropagateMark(); size_t PropagateMark();
static void StaticInit(); static void StaticInit();
private:
// Stuff for type conversion searches
class VisitQueue
{
public:
VisitQueue() : In(0), Out(0) {}
void Push(PType *type);
PType *Pop();
bool IsEmpty() { return In == Out; }
private:
// This is a fixed-sized ring buffer.
PType *Queue[64];
int In, Out;
void Advance(int &ptr)
{
ptr = (ptr + 1) & (countof(Queue) - 1);
}
};
class VisitedNodeSet
{
public:
VisitedNodeSet() { memset(Buckets, 0, sizeof(Buckets)); }
void Insert(PType *node);
bool Check(const PType *node);
private:
PType *Buckets[32];
size_t Hash(const PType *type) { return size_t(type) >> 4; }
};
TArray<Conversion> Conversions;
PType *PredType;
PType *VisitNext;
short PredConv;
short Distance;
void MarkPred(PType *pred, int conv, int dist)
{
PredType = pred;
PredConv = conv;
Distance = dist;
}
void FillConversionPath(const Conversion **slots);
}; };
// Not-really-a-type types -------------------------------------------------- // Not-really-a-type types --------------------------------------------------

View file

@ -513,7 +513,7 @@ static void OpenExprType(FLispString &out, EZCCExprType type)
if (unsigned(type) < PEX_COUNT_OF) if (unsigned(type) < PEX_COUNT_OF)
{ {
mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName); mysnprintf(buf, countof(buf), "expr %d", type);
} }
else else
{ {

View file

@ -86,6 +86,20 @@ int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls)
return static_cast<FxConstant*>(ex)->GetValue().GetInt(); return static_cast<FxConstant*>(ex)->GetValue().GetInt();
} }
FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls)
{
FCompileContext ctx(cls, false);
FxExpression *ex = new FxStringCast(ConvertNode(node));
ex = ex->Resolve(ctx);
if (ex == nullptr) return "";
if (!ex->isConstant())
{
ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant");
return "";
}
return static_cast<FxConstant*>(ex)->GetValue().GetString();
}
//========================================================================== //==========================================================================
// //
@ -822,300 +836,6 @@ bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work)
} }
//==========================================================================
//
// ZCCCompiler :: Simplify
//
// For an expression,
// Evaluate operators whose arguments are both constants, replacing it
// with a new constant.
// For a binary operator with one constant argument, put it on the right-
// hand operand, where permitted.
// Perform automatic type promotion.
//
//==========================================================================
ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym, bool wantconstant)
{
SimplifyingConstant = wantconstant;
return DoSimplify(root, sym);
}
ZCC_Expression *ZCCCompiler::DoSimplify(ZCC_Expression *root, PSymbolTable *sym)
{
if (root->NodeType == AST_ExprUnary)
{
return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root), sym);
}
else if (root->NodeType == AST_ExprBinary)
{
return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root), sym);
}
else if (root->Operation == PEX_ID)
{
return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root), sym);
}
else if (root->Operation == PEX_MemberAccess)
{
return SimplifyMemberAccess(static_cast<ZCC_ExprMemberAccess *>(root), sym);
}
else if (root->Operation == PEX_FuncCall)
{
return SimplifyFunctionCall(static_cast<ZCC_ExprFuncCall *>(root), sym);
}
return root;
}
//==========================================================================
//
// ZCCCompiler :: SimplifyUnary
//
//==========================================================================
ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *sym)
{
unary->Operand = DoSimplify(unary->Operand, sym);
if (unary->Operand->Type == nullptr)
{
return unary;
}
ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand);
if (op == NULL)
{ // Oh, poo!
unary->Type = TypeError;
}
else if (unary->Operand->Operation == PEX_ConstValue)
{
return op->EvalConst1(static_cast<ZCC_ExprConstant *>(unary->Operand));
}
return unary;
}
//==========================================================================
//
// ZCCCompiler :: SimplifyBinary
//
//==========================================================================
ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *sym)
{
binary->Left = DoSimplify(binary->Left, sym);
binary->Right = DoSimplify(binary->Right, sym);
if (binary->Left->Type == nullptr || binary->Right->Type == nullptr)
{
// We do not know yet what this is so we cannot promote it (yet.)
return binary;
}
ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right);
if (op == NULL)
{
binary->Type = TypeError;
}
else if (binary->Left->Operation == PEX_ConstValue &&
binary->Right->Operation == PEX_ConstValue)
{
return op->EvalConst2(static_cast<ZCC_ExprConstant *>(binary->Left),
static_cast<ZCC_ExprConstant *>(binary->Right), AST.Strings);
}
return binary;
}
//==========================================================================
//
// ZCCCompiler :: SimplifyMemberAccess
//
//==========================================================================
ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *symt)
{
PSymbolTable *symtable;
// TBD: Is it safe to simplify the left side here when not processing a constant?
dotop->Left = DoSimplify(dotop->Left, symt);
if (dotop->Left->Operation == PEX_TypeRef)
{ // Type refs can be evaluated now.
PType *ref = static_cast<ZCC_ExprTypeRef *>(dotop->Left)->RefType;
PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable);
if (sym != nullptr)
{
ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable);
if (expr != nullptr)
{
return expr;
}
}
}
else if (dotop->Left->Operation == PEX_Super)
{
symt = symt->GetParentTable();
if (symt != nullptr)
{
PSymbol *sym = symt->FindSymbolInTable(dotop->Right, symtable);
if (sym != nullptr)
{
ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable);
if (expr != nullptr)
{
return expr;
}
}
}
}
return dotop;
}
//==========================================================================
//
// ZCCCompiler :: SimplifyFunctionCall
//
// This may replace a function call with cast(s), since they look like the
// same thing to the parser.
//
//==========================================================================
ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *sym)
{
ZCC_FuncParm *parm;
int parmcount = 0;
parm = callop->Parameters;
if (parm != NULL)
{
do
{
parmcount++;
assert(parm->NodeType == AST_FuncParm);
parm->Value = DoSimplify(parm->Value, sym);
parm = static_cast<ZCC_FuncParm *>(parm->SiblingNext);
}
while (parm != callop->Parameters);
}
// Only simplify the 'function' part if we want to retrieve a constant.
// This is necessary to evaluate the type casts, but for actual functions
// the simplification process is destructive and has to be avoided.
if (SimplifyingConstant)
{
callop->Function = DoSimplify(callop->Function, sym);
}
// If the left side is a type ref, then this is actually a cast
// and not a function call.
if (callop->Function->Operation == PEX_TypeRef)
{
if (parmcount != 1)
{
Error(callop, "Type cast requires one parameter");
callop->ToErrorNode();
}
else
{
PType *dest = static_cast<ZCC_ExprTypeRef *>(callop->Function)->RefType;
const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
int routelen = parm->Value->Type->FindConversion(dest, route, countof(route));
if (routelen < 0)
{
///FIXME: Need real type names
Error(callop, "Cannot convert %s to %s", parm->Value->Type->DescriptiveName(), dest->DescriptiveName());
callop->ToErrorNode();
}
else
{
ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen);
assert(val->Type == dest);
return val;
}
}
}
return callop;
}
//==========================================================================
//
// ZCCCompiler :: PromoteUnary
//
// Converts the operand into a format preferred by the operator.
//
//==========================================================================
ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr)
{
if (expr->Type == TypeError)
{
return NULL;
}
const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
int routelen = countof(route);
ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen);
if (proto != NULL)
{
expr = ApplyConversion(expr, route, routelen);
}
return proto;
}
//==========================================================================
//
// ZCCCompiler :: PromoteBinary
//
// Converts the operands into a format (hopefully) compatible with the
// operator.
//
//==========================================================================
ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right)
{
// If either operand is of type 'error', the result is also 'error'
if (left->Type == TypeError || right->Type == TypeError)
{
return NULL;
}
const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE];
int route1len = countof(route1), route2len = countof(route2);
ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len);
if (proto != NULL)
{
left = ApplyConversion(left, route1, route1len);
right = ApplyConversion(right, route2, route2len);
}
return proto;
}
//==========================================================================
//
// ZCCCompiler :: ApplyConversion
//
//==========================================================================
ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen)
{
for (int i = 0; i < routelen; ++i)
{
if (expr->Operation != PEX_ConstValue)
{
expr = AddCastNode(route[i]->TargetType, expr);
}
else
{
route[i]->ConvertConstant(static_cast<ZCC_ExprConstant *>(expr), AST.Strings);
}
}
return expr;
}
//==========================================================================
//
// ZCCCompiler :: AddCastNode
//
//==========================================================================
ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr)
{
assert(expr->Operation != PEX_ConstValue && "Expression must not be constant");
// TODO: add a node here
return expr;
}
//========================================================================== //==========================================================================
// //
// ZCCCompiler :: IdentifyIdentifier // ZCCCompiler :: IdentifyIdentifier
@ -1781,78 +1501,6 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
return baseType; return baseType;
} }
//==========================================================================
//
// ZCCCompiler :: GetInt - Input must be a constant expression
//
//==========================================================================
int ZCCCompiler::GetInt(ZCC_Expression *expr)
{
if (expr->Type == TypeError)
{
return 0;
}
const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
int routelen = expr->Type->FindConversion(TypeSInt32, route, countof(route));
if (routelen < 0)
{
Error(expr, "Cannot convert to integer");
return 0;
}
else
{
if (expr->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
{
Warn(expr, "Truncation of floating point value");
}
auto ex = static_cast<ZCC_ExprConstant *>(ApplyConversion(expr, route, routelen));
return ex->IntVal;
}
}
double ZCCCompiler::GetDouble(ZCC_Expression *expr)
{
if (expr->Type == TypeError)
{
return 0;
}
const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
int routelen = expr->Type->FindConversion(TypeFloat64, route, countof(route));
if (routelen < 0)
{
Error(expr, "Cannot convert to float");
return 0;
}
else
{
auto ex = static_cast<ZCC_ExprConstant *>(ApplyConversion(expr, route, routelen));
return ex->DoubleVal;
}
}
const char *ZCCCompiler::GetString(ZCC_Expression *expr, bool silent)
{
if (expr->Type == TypeError)
{
return nullptr;
}
else if (expr->Type->IsKindOf(RUNTIME_CLASS(PString)))
{
return static_cast<ZCC_ExprConstant *>(expr)->StringVal->GetChars();
}
else if (expr->Type->IsKindOf(RUNTIME_CLASS(PName)))
{
// Ugh... What a mess...
return FName(ENamedName(static_cast<ZCC_ExprConstant *>(expr)->IntVal)).GetChars();
}
else
{
if (!silent) Error(expr, "Cannot convert to string");
return nullptr;
}
}
//========================================================================== //==========================================================================
// //
// Parses an actor property's parameters and calls the handler // Parses an actor property's parameters and calls the handler
@ -2921,7 +2569,7 @@ void ZCCCompiler::CompileStates()
auto l = sl->Lights; auto l = sl->Lights;
do do
{ {
AddStateLight(&state, GetString(l)); AddStateLight(&state, StringConstFromNode(l, c->Type()));
l = static_cast<decltype(l)>(l->SiblingNext); l = static_cast<decltype(l)>(l->SiblingNext);
} while (l != sl->Lights); } while (l != sl->Lights);
} }

View file

@ -92,6 +92,7 @@ public:
private: private:
int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls);
FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls);
void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode);
void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer);
void CreateStructTypes(); void CreateStructTypes();
@ -115,9 +116,6 @@ private:
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag); void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
int GetInt(ZCC_Expression *expr);
double GetDouble(ZCC_Expression *expr);
const char *GetString(ZCC_Expression *expr, bool silent = false);
void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass); void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass);
void InitFunctions(); void InitFunctions();
@ -132,18 +130,6 @@ private:
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false); PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
ZCC_Expression *Simplify(ZCC_Expression *root, PSymbolTable *Symbols, bool wantconstant);
ZCC_Expression *DoSimplify(ZCC_Expression *root, PSymbolTable *Symbols);
ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *Symbols);
ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *Symbols);
ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *Symbols);
ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *Symbols);
ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right);
ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen);
ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr);
ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym); ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym);
ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table); ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table);
ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode);

View file

@ -1,530 +0,0 @@
/*
** 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"
#include "math/cmath.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 = g_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_GT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal > r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_GT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal > r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_GT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal > r->DoubleVal; l->Type = TypeBool; return l; } },
{ PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal >= r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal >= r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal >= r->DoubleVal; l->Type = TypeBool; return l; } },
{ PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal != r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal != r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_NEQ , (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);
}

View file

@ -408,9 +408,6 @@ void ParseScripts()
{ {
InitTokenMap(); InitTokenMap();
} }
ZCC_InitOperators();
ZCC_InitConversions();
int lump, lastlump = 0; int lump, lastlump = 0;
FScriptPosition::ResetErrorCounter(); FScriptPosition::ResetErrorCounter();

View file

@ -527,47 +527,8 @@ struct ZCC_FlagStmt : ZCC_Statement
bool set; bool set;
}; };
typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *);
typedef ZCC_ExprConstant *(*EvalConst2op)(ZCC_ExprConstant *, ZCC_ExprConstant *, FSharedStringArena &);
struct ZCC_OpProto
{
ZCC_OpProto *Next;
PType *ResType;
PType *Type1;
PType *Type2;
union
{
EvalConst1op EvalConst1;
EvalConst2op EvalConst2;
};
ZCC_OpProto(PType *res, PType *t1, PType *t2)
: ResType(res), Type1(t1), Type2(t2) {}
};
struct ZCC_OpInfoType
{
const char *OpName;
ZCC_OpProto *Protos;
void AddProto(PType *res, PType *optype, EvalConst1op evalconst);
void AddProto(PType *res, PType *left, PType *right, EvalConst2op evalconst);
ZCC_OpProto *FindBestProto(PType *optype, const PType::Conversion **route, int &numslots);
ZCC_OpProto *FindBestProto(PType *left, const PType::Conversion **route1, int &numslots,
PType *right, const PType::Conversion **route2, int &numslots2);
void FreeAllProtos();
};
#define CONVERSION_ROUTE_SIZE 8
FString ZCC_PrintAST(ZCC_TreeNode *root); FString ZCC_PrintAST(ZCC_TreeNode *root);
void ZCC_InitOperators();
extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF];
struct ZCC_AST struct ZCC_AST
{ {