mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
Add evaluation of constant unary and binary expressions
- Added ZCCCompiler class as a place to generate IR and symbols from an AST. Right now, all it does is simplify constant expressions into constant values. - Do type promotion on the AST where appropriate. - Added true and false tokens to the parser driver.
This commit is contained in:
parent
d0968af9a6
commit
850055a766
10 changed files with 1265 additions and 108 deletions
|
@ -952,6 +952,8 @@ add_executable( zdoom WIN32
|
|||
zscript/vmdisasm.cpp
|
||||
zscript/vmexec.cpp
|
||||
zscript/vmframe.cpp
|
||||
zscript/zcc_compile.cpp
|
||||
zscript/zcc_expr.cpp
|
||||
zscript/zcc_parser.cpp
|
||||
autozend.cpp
|
||||
)
|
||||
|
|
|
@ -442,61 +442,11 @@ static void PrintClassType(FLispString &out, ZCC_TreeNode *node)
|
|||
|
||||
static void OpenExprType(FLispString &out, EZCCExprType type)
|
||||
{
|
||||
static const char *const types[] =
|
||||
{
|
||||
"nil",
|
||||
"id",
|
||||
"super",
|
||||
"self",
|
||||
"const",
|
||||
"func-call",
|
||||
"array-access",
|
||||
"member-access",
|
||||
"post-inc",
|
||||
"post-dec",
|
||||
"pre-inc",
|
||||
"pre-dec",
|
||||
"negate",
|
||||
"anti-negate",
|
||||
"bit-not",
|
||||
"bool-not",
|
||||
"size-of",
|
||||
"align-of",
|
||||
"add",
|
||||
"sub",
|
||||
"mul",
|
||||
"div",
|
||||
"mod",
|
||||
"pow",
|
||||
"cross-product",
|
||||
"dot-product",
|
||||
"left-shift",
|
||||
"right-shift",
|
||||
"concat",
|
||||
"lt",
|
||||
"gt",
|
||||
"lteq",
|
||||
"gteq",
|
||||
"ltgteq",
|
||||
"is",
|
||||
"eqeq",
|
||||
"neq",
|
||||
"apreq",
|
||||
"bit-and",
|
||||
"bit-or",
|
||||
"bit-xor",
|
||||
"bool-and",
|
||||
"bool-or",
|
||||
"scope",
|
||||
"trinary",
|
||||
};
|
||||
assert(countof(types) == PEX_COUNT_OF);
|
||||
|
||||
char buf[32];
|
||||
|
||||
if (unsigned(type) < countof(types))
|
||||
if (unsigned(type) < PEX_COUNT_OF)
|
||||
{
|
||||
mysnprintf(buf, countof(buf), "expr-%s", types[type]);
|
||||
mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
393
src/zscript/zcc_compile.cpp
Normal file
393
src/zscript/zcc_compile.cpp
Normal file
|
@ -0,0 +1,393 @@
|
|||
#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 "zcc_compile.h"
|
||||
#include "v_text.h"
|
||||
#include "gdtoa.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols)
|
||||
: Outer(_outer), Symbols(_symbols), AST(ast), ErrorCount(0), WarnCount(0)
|
||||
{
|
||||
// Group top-level nodes by type
|
||||
if (ast.TopNode != NULL)
|
||||
{
|
||||
ZCC_TreeNode *node = ast.TopNode;
|
||||
do
|
||||
{
|
||||
switch (node->NodeType)
|
||||
{
|
||||
case AST_Class: Classes.Push(static_cast<ZCC_Class *>(node)); break;
|
||||
case AST_Struct: Structs.Push(static_cast<ZCC_Struct *>(node)); break;
|
||||
case AST_Enum: break;
|
||||
case AST_EnumTerminator:break;
|
||||
case AST_ConstantDef: Constants.Push(static_cast<ZCC_ConstantDef *>(node)); break;
|
||||
default: assert(0 && "Unhandled AST node type"); break;
|
||||
}
|
||||
node = node->SiblingNext;
|
||||
}
|
||||
while (node != ast.TopNode);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: Message
|
||||
//
|
||||
// Prints a warning or error message, and increments the appropriate
|
||||
// counter.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...)
|
||||
{
|
||||
FString composed;
|
||||
|
||||
composed.Format("%s%s, line %d: ",
|
||||
errnum & ZCCERR_ERROR ? TEXTCOLOR_RED : TEXTCOLOR_ORANGE,
|
||||
node->SourceName->GetChars(), node->SourceLoc);
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, msg);
|
||||
composed.VAppendFormat(msg, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
composed += '\n';
|
||||
PrintString(PRINT_HIGH, composed);
|
||||
|
||||
if (errnum & ZCCERR_ERROR)
|
||||
{
|
||||
ErrorCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
WarnCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: Compile
|
||||
//
|
||||
// Compile everything defined at this level.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int ZCCCompiler::Compile()
|
||||
{
|
||||
CompileConstants();
|
||||
return ErrorCount;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: CompileConstants
|
||||
//
|
||||
// Make symbols from every constant defined at this level.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ZCCCompiler::CompileConstants()
|
||||
{
|
||||
for (unsigned i = 0; i < Constants.Size(); ++i)
|
||||
{
|
||||
ZCC_ConstantDef *def = Constants[i];
|
||||
if (def->Symbol == NULL)
|
||||
{
|
||||
PSymbolConst *sym = CompileConstant(def);
|
||||
if (NULL == Symbols.AddSymbol(sym))
|
||||
{
|
||||
Message(Constants[i], ERR_symbol_redefinition, "Redefinition of symbol '%s'", FName(def->Name).GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: CompileConstant
|
||||
//
|
||||
// For every constant definition, evaluate its value (which should result
|
||||
// in a constant), and create a symbol for it. Simplify() uses recursion
|
||||
// to resolve constants used before their declarations.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def)
|
||||
{
|
||||
assert(def->Symbol == NULL);
|
||||
|
||||
def->Symbol = (PSymbolConst *)(void *)1; // mark as being defined (avoid recursion)
|
||||
ZCC_Expression *val = Simplify(def->Value);
|
||||
def->Value = val;
|
||||
PSymbolConst *sym = NULL;
|
||||
if (val->NodeType == AST_ExprConstant)
|
||||
{
|
||||
ZCC_ExprConstant *cval = static_cast<ZCC_ExprConstant *>(val);
|
||||
if (cval->Type == TypeString)
|
||||
{
|
||||
sym = new PSymbolConstString(def->Name, *(cval->StringVal));
|
||||
}
|
||||
else if (cval->Type->IsA(RUNTIME_CLASS(PInt)))
|
||||
{
|
||||
sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->IntVal);
|
||||
}
|
||||
else if (cval->Type->IsA(RUNTIME_CLASS(PFloat)))
|
||||
{
|
||||
sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->DoubleVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(def->Value, ERR_bad_const_def_type, "Bad type for constant definiton");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(def->Value, ERR_const_def_not_constant, "Constant definition requires a constant value");
|
||||
}
|
||||
if (sym == NULL)
|
||||
{
|
||||
// Create a dummy constant so we don't make any undefined value warnings.
|
||||
sym = new PSymbolConstNumeric(def->Name, TypeError, 0);
|
||||
}
|
||||
def->Symbol = sym;
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
if (root->Operation == PEX_ID)
|
||||
{
|
||||
return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root));
|
||||
}
|
||||
else if (IsUnaryOp(root->Operation))
|
||||
{
|
||||
return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root));
|
||||
}
|
||||
else if (IsBinaryOp(root->Operation))
|
||||
{
|
||||
return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root));
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: SimplifyUnary
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary)
|
||||
{
|
||||
unary->Operand = Simplify(unary->Operand);
|
||||
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)
|
||||
{
|
||||
binary->Left = Simplify(binary->Left);
|
||||
binary->Right = Simplify(binary->Right);
|
||||
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 :: 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
|
||||
//
|
||||
// Returns a node that represents what the identifer stands for.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode)
|
||||
{
|
||||
// First things first: Check the symbol table.
|
||||
PSymbol *sym;
|
||||
if (NULL != (sym = Symbols.FindSymbol(idnode->Identifier, true)))
|
||||
{
|
||||
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||
{
|
||||
return NodeFromSymbolConst(static_cast<PSymbolConst *>(sym), idnode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
// Identifier didn't refer to anything good, so type error it.
|
||||
idnode->Type = TypeError;
|
||||
idnode->Operation = PEX_Nil;
|
||||
return idnode;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: NodeFromSymoblConst
|
||||
//
|
||||
// Returns a new AST constant node with the symbol's content.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID *idnode)
|
||||
{
|
||||
ZCC_ExprConstant *val = static_cast<ZCC_ExprConstant *>(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode));
|
||||
val->Operation = PEX_ConstValue;
|
||||
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString)))
|
||||
{
|
||||
val->StringVal = AST.Strings.Alloc(static_cast<PSymbolConstString *>(sym)->Str);
|
||||
val->Type = TypeString;
|
||||
}
|
||||
else
|
||||
{
|
||||
val->Type = sym->ValueType;
|
||||
if (val->Type != TypeError)
|
||||
{
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt)))
|
||||
{
|
||||
val->IntVal = static_cast<PSymbolConstNumeric *>(sym)->Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat)));
|
||||
val->DoubleVal = static_cast<PSymbolConstNumeric *>(sym)->Float;
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
48
src/zscript/zcc_compile.h
Normal file
48
src/zscript/zcc_compile.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef ZCC_COMPILE_H
|
||||
#define ZCC_COMPILE_H
|
||||
|
||||
#include "zcc_errors.h"
|
||||
|
||||
class ZCCCompiler
|
||||
{
|
||||
public:
|
||||
ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols);
|
||||
int Compile();
|
||||
|
||||
private:
|
||||
void CompileConstants();
|
||||
PSymbolConst *CompileConstant(ZCC_ConstantDef *def);
|
||||
|
||||
TArray<ZCC_ConstantDef *> Constants;
|
||||
TArray<ZCC_Struct *> Structs;
|
||||
TArray<ZCC_Class *> Classes;
|
||||
|
||||
ZCC_Expression *Simplify(ZCC_Expression *root);
|
||||
ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary);
|
||||
ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary);
|
||||
ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
|
||||
ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right);
|
||||
|
||||
void PromoteToInt(ZCC_Expression *&expr);
|
||||
void PromoteToUInt(ZCC_Expression *&expr);
|
||||
void PromoteToDouble(ZCC_Expression *&expr);
|
||||
void PromoteToString(ZCC_Expression *&expr);
|
||||
|
||||
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);
|
||||
ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID *idnode);
|
||||
|
||||
void Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...);
|
||||
|
||||
DObject *Outer;
|
||||
PSymbolTable &Symbols;
|
||||
ZCC_AST &AST;
|
||||
int ErrorCount;
|
||||
int WarnCount;
|
||||
};
|
||||
|
||||
void ZCC_InitConversions();
|
||||
|
||||
#endif
|
8
src/zscript/zcc_errors.h
Normal file
8
src/zscript/zcc_errors.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#define ZCCERR_ERROR 0x40000000
|
||||
|
||||
enum EZCCError
|
||||
{
|
||||
ERR_const_def_not_constant = 20000 | ZCCERR_ERROR,
|
||||
ERR_bad_const_def_type = 20001 | ZCCERR_ERROR,
|
||||
ERR_symbol_redefinition = 20002 | ZCCERR_ERROR,
|
||||
};
|
672
src/zscript/zcc_expr.cpp
Normal file
672
src/zscript/zcc_expr.cpp
Normal file
|
@ -0,0 +1,672 @@
|
|||
#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))
|
||||
|
||||
extern PSymbolTable GlobalSymbols;
|
||||
|
||||
ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] =
|
||||
{
|
||||
#define xx(a,n) { n, #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;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
int dist = MIN(dist1, 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 *EvalIncFloat64(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->DoubleVal++;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalIncInt32(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->IntVal++;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalDecFloat64(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->DoubleVal--;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalDecInt32(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->IntVal--;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalNegateFloat64(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->DoubleVal = -val->DoubleVal;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalNegateInt32(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->IntVal = -val->IntVal;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalBitNot(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->IntVal = ~val->IntVal;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalBoolNot(ZCC_ExprConstant *val)
|
||||
{
|
||||
val->IntVal = !val->IntVal;
|
||||
return val;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalAddFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->DoubleVal += r->DoubleVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalAddInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal += r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalSubFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->DoubleVal -= r->DoubleVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalSubInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal -= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalMulFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->DoubleVal *= r->DoubleVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalMulUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->UIntVal *= r->UIntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalMulSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal *= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalDivFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->DoubleVal /= r->DoubleVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalDivUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->UIntVal /= r->UIntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalDivSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal /= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalModFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal);
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalModUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->UIntVal %= r->UIntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalModSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal %= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalPow(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->DoubleVal = pow(l->DoubleVal, r->DoubleVal);
|
||||
return l;
|
||||
}
|
||||
|
||||
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 *EvalBitAnd(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal &= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalBitOr(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal |= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalBitXor(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal ^= r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalBoolAnd(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->IntVal && r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalBoolOr(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->IntVal || r->IntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalSHL(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal <<= r->UIntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalSHR_S(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal >>= r->UIntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalSHR_U(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->UIntVal >>= r->UIntVal;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalLTSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->IntVal < r->IntVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalLTUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->UIntVal < r->UIntVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalLTFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->DoubleVal < r->DoubleVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalLTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->IntVal <= r->IntVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalLTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->UIntVal <= r->UIntVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalLTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->DoubleVal <= r->DoubleVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalEQEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->IntVal == r->IntVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalEQEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->UIntVal == r->UIntVal;
|
||||
l->Type = TypeBool;
|
||||
return l;
|
||||
}
|
||||
|
||||
static ZCC_ExprConstant *EvalEQEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
|
||||
{
|
||||
l->IntVal = l->DoubleVal == r->DoubleVal;
|
||||
l->Type = TypeBool;
|
||||
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, EvalIncInt32 },
|
||||
{ PEX_PreInc , (PType **)&TypeUInt32, EvalIncInt32 },
|
||||
{ PEX_PreInc , (PType **)&TypeFloat64, EvalIncFloat64 },
|
||||
|
||||
{ PEX_PreDec , (PType **)&TypeSInt32, EvalDecInt32 },
|
||||
{ PEX_PreDec , (PType **)&TypeUInt32, EvalDecInt32 },
|
||||
{ PEX_PreDec , (PType **)&TypeFloat64, EvalDecFloat64 },
|
||||
|
||||
{ PEX_Negate , (PType **)&TypeSInt32, EvalNegateInt32 },
|
||||
{ PEX_Negate , (PType **)&TypeFloat64, EvalNegateFloat64 },
|
||||
|
||||
{ PEX_AntiNegate , (PType **)&TypeSInt32, EvalIdentity },
|
||||
{ PEX_AntiNegate , (PType **)&TypeUInt32, EvalIdentity },
|
||||
{ PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity },
|
||||
|
||||
{ PEX_BitNot , (PType **)&TypeSInt32, EvalBitNot },
|
||||
{ PEX_BitNot , (PType **)&TypeUInt32, EvalBitNot },
|
||||
|
||||
{ PEX_BoolNot , (PType **)&TypeBool, EvalBoolNot },
|
||||
};
|
||||
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, EvalAddInt32 },
|
||||
{ PEX_Add , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalAddInt32 },
|
||||
{ PEX_Add , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalAddFloat64 },
|
||||
|
||||
{ PEX_Sub , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalSubInt32 },
|
||||
{ PEX_Sub , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSubInt32 },
|
||||
{ PEX_Sub , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalSubFloat64 },
|
||||
|
||||
{ PEX_Mul , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalMulSInt32 },
|
||||
{ PEX_Mul , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalMulUInt32 },
|
||||
{ PEX_Mul , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalMulFloat64 },
|
||||
|
||||
{ PEX_Div , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalDivSInt32 },
|
||||
{ PEX_Div , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalDivUInt32 },
|
||||
{ PEX_Div , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalDivFloat64 },
|
||||
|
||||
{ PEX_Mod , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalModSInt32 },
|
||||
{ PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalModUInt32 },
|
||||
{ PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalModFloat64 },
|
||||
|
||||
{ PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalPow },
|
||||
|
||||
{ PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat },
|
||||
|
||||
{ PEX_BitAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitAnd },
|
||||
{ PEX_BitAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitAnd },
|
||||
|
||||
{ PEX_BitOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitOr },
|
||||
{ PEX_BitOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitOr },
|
||||
|
||||
{ PEX_BitXor , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitXor },
|
||||
{ PEX_BitXor , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitXor },
|
||||
|
||||
{ PEX_BoolAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBoolAnd },
|
||||
{ PEX_BoolAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBoolAnd },
|
||||
|
||||
{ PEX_BoolOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBoolOr },
|
||||
{ PEX_BoolOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBoolOr },
|
||||
|
||||
{ PEX_LeftShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, EvalSHL },
|
||||
{ PEX_LeftShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSHL },
|
||||
|
||||
{ PEX_RightShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, EvalSHR_S },
|
||||
{ PEX_RightShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSHR_U },
|
||||
|
||||
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTSInt32 },
|
||||
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTUInt32 },
|
||||
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTFloat64 },
|
||||
|
||||
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTEQSInt32 },
|
||||
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTEQUInt32 },
|
||||
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTEQFloat64 },
|
||||
|
||||
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalEQEQSInt32 },
|
||||
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalEQEQUInt32 },
|
||||
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalEQEQFloat64 },
|
||||
|
||||
{ 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 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];
|
||||
int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal);
|
||||
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);
|
||||
|
||||
TypeFloat64->AddConversion(TypeUInt32, DtoU32);
|
||||
TypeFloat64->AddConversion(TypeSInt32, DtoS32);
|
||||
TypeFloat64->AddConversion(TypeString, DtoS);
|
||||
}
|
56
src/zscript/zcc_exprlist.h
Normal file
56
src/zscript/zcc_exprlist.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Name n-ary
|
||||
xx(Nil, 0)
|
||||
|
||||
xx(ID, 0)
|
||||
xx(Super, 0)
|
||||
xx(Self, 0)
|
||||
xx(ConstValue, 0)
|
||||
xx(FuncCall, 0)
|
||||
xx(ArrayAccess, 0)
|
||||
xx(MemberAccess, 0)
|
||||
|
||||
xx(PostInc, 1)
|
||||
xx(PostDec, 1)
|
||||
|
||||
xx(PreInc, 1)
|
||||
xx(PreDec, 1)
|
||||
xx(Negate, 1)
|
||||
xx(AntiNegate, 1)
|
||||
xx(BitNot, 1)
|
||||
xx(BoolNot, 1)
|
||||
xx(SizeOf, 1)
|
||||
xx(AlignOf, 1)
|
||||
|
||||
xx(Add, 2)
|
||||
xx(Sub, 2)
|
||||
xx(Mul, 2)
|
||||
xx(Div, 2)
|
||||
xx(Mod, 2)
|
||||
xx(Pow, 2)
|
||||
xx(CrossProduct, 2)
|
||||
xx(DotProduct, 2)
|
||||
xx(LeftShift, 2)
|
||||
xx(RightShift, 2)
|
||||
xx(Concat, 2)
|
||||
|
||||
xx(LT, 2)
|
||||
xx(LTEQ, 2)
|
||||
xx(LTGTEQ, 2)
|
||||
xx(Is, 2)
|
||||
|
||||
xx(EQEQ, 2)
|
||||
xx(APREQ, 2)
|
||||
|
||||
xx(BitAnd, 2)
|
||||
xx(BitOr, 2)
|
||||
xx(BitXor, 2)
|
||||
xx(BoolAnd, 2)
|
||||
xx(BoolOr, 2)
|
||||
|
||||
xx(Scope, 0)
|
||||
|
||||
xx(Trinary, 2)
|
||||
|
||||
xx(Cast, 1)
|
||||
|
||||
#undef xx
|
|
@ -5,8 +5,8 @@
|
|||
#include "w_wad.h"
|
||||
#include "cmdlib.h"
|
||||
#include "m_alloc.h"
|
||||
#include "memarena.h"
|
||||
#include "zcc_parser.h"
|
||||
#include "zcc_compile.h"
|
||||
|
||||
static FString ZCCTokenName(int terminal);
|
||||
|
||||
|
@ -106,6 +106,8 @@ static void InitTokenMap()
|
|||
TOKENDEF2(TK_Map, ZCC_MAP, NAME_map);
|
||||
TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_array);
|
||||
TOKENDEF (TK_Void, ZCC_VOID);
|
||||
TOKENDEF (TK_True, ZCC_TRUE);
|
||||
TOKENDEF (TK_False, ZCC_FALSE);
|
||||
TOKENDEF ('[', ZCC_LBRACKET);
|
||||
TOKENDEF (']', ZCC_RBRACKET);
|
||||
TOKENDEF (TK_In, ZCC_IN);
|
||||
|
@ -144,6 +146,9 @@ static void InitTokenMap()
|
|||
TOKENDEF (TK_UIntConst, ZCC_UINTCONST);
|
||||
TOKENDEF (TK_FloatConst, ZCC_FLOATCONST);
|
||||
TOKENDEF (TK_NonWhitespace, ZCC_NWS);
|
||||
|
||||
ZCC_InitOperators();
|
||||
ZCC_InitConversions();
|
||||
}
|
||||
#undef TOKENDEF
|
||||
#undef TOKENDEF2
|
||||
|
@ -249,16 +254,18 @@ static void DoParse(const char *filename)
|
|||
ZCCParse(parser, ZCC_EOF, value, &state);
|
||||
ZCCParse(parser, 0, value, &state);
|
||||
ZCCParseFree(parser, free);
|
||||
|
||||
PSymbolTable symbols;
|
||||
ZCCCompiler cc(state, NULL, symbols);
|
||||
cc.Compile();
|
||||
#ifdef _DEBUG
|
||||
if (f != NULL)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
FString ast = ZCC_PrintAST(state.TopNode);
|
||||
FString astfile = ExtractFileBase(filename, false);
|
||||
astfile << ".ast";
|
||||
#ifdef _DEBUG
|
||||
f = fopen(astfile, "w");
|
||||
if (f != NULL)
|
||||
{
|
||||
|
|
|
@ -121,59 +121,8 @@ enum EZCCBuiltinType
|
|||
|
||||
enum EZCCExprType
|
||||
{
|
||||
PEX_Nil,
|
||||
|
||||
PEX_ID,
|
||||
PEX_Super,
|
||||
PEX_Self,
|
||||
PEX_ConstValue,
|
||||
PEX_FuncCall,
|
||||
PEX_ArrayAccess,
|
||||
PEX_MemberAccess,
|
||||
PEX_PostInc,
|
||||
PEX_PostDec,
|
||||
|
||||
PEX_PreInc,
|
||||
PEX_PreDec,
|
||||
PEX_Negate,
|
||||
PEX_AntiNegate,
|
||||
PEX_BitNot,
|
||||
PEX_BoolNot,
|
||||
PEX_SizeOf,
|
||||
PEX_AlignOf,
|
||||
|
||||
PEX_Add,
|
||||
PEX_Sub,
|
||||
PEX_Mul,
|
||||
PEX_Div,
|
||||
PEX_Mod,
|
||||
PEX_Pow,
|
||||
PEX_CrossProduct,
|
||||
PEX_DotProduct,
|
||||
PEX_LeftShift,
|
||||
PEX_RightShift,
|
||||
PEX_Concat,
|
||||
|
||||
PEX_LT,
|
||||
PEX_GT,
|
||||
PEX_LTEQ,
|
||||
PEX_GTEQ,
|
||||
PEX_LTGTEQ,
|
||||
PEX_Is,
|
||||
|
||||
PEX_EQEQ,
|
||||
PEX_NEQ,
|
||||
PEX_APREQ,
|
||||
|
||||
PEX_BitAnd,
|
||||
PEX_BitOr,
|
||||
PEX_BitXor,
|
||||
PEX_BoolAnd,
|
||||
PEX_BoolOr,
|
||||
|
||||
PEX_Scope,
|
||||
|
||||
PEX_Trinary,
|
||||
#define xx(a,z) PEX_##a,
|
||||
#include "zcc_exprlist.h"
|
||||
|
||||
PEX_COUNT_OF
|
||||
};
|
||||
|
@ -345,6 +294,7 @@ struct ZCC_ExprConstant : ZCC_Expression
|
|||
{
|
||||
FString *StringVal;
|
||||
int IntVal;
|
||||
unsigned int UIntVal;
|
||||
double DoubleVal;
|
||||
};
|
||||
};
|
||||
|
@ -491,8 +441,59 @@ struct ZCC_FuncDeclarator : ZCC_Declarator
|
|||
ZCC_Statement *Body;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
BYTE Nary:2; // n-ary-ness of operator
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
#define CONVERSION_ROUTE_SIZE 8
|
||||
|
||||
FString ZCC_PrintAST(ZCC_TreeNode *root);
|
||||
|
||||
void ZCC_InitOperators();
|
||||
|
||||
extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF];
|
||||
|
||||
static inline bool IsUnaryOp(EZCCExprType op)
|
||||
{
|
||||
assert((unsigned)op < (unsigned)PEX_COUNT_OF);
|
||||
return ZCC_OpInfo[op].Nary == 1;
|
||||
}
|
||||
static inline bool IsBinaryOp(EZCCExprType op)
|
||||
{
|
||||
assert((unsigned)op < (unsigned)PEX_COUNT_OF);
|
||||
return ZCC_OpInfo[op].Nary == 2;
|
||||
}
|
||||
|
||||
struct ZCC_AST
|
||||
{
|
||||
ZCC_AST() : TopNode(NULL) {}
|
||||
|
|
20
zdoom.vcproj
20
zdoom.vcproj
|
@ -3717,6 +3717,26 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_compile.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_compile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_errors.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_expr.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_exprlist.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_parser.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in a new issue