From 850055a766b6232a24dc4b65bcc0fb0c571288e5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Oct 2013 23:06:32 -0500 Subject: [PATCH] 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. --- src/CMakeLists.txt | 2 + src/zscript/ast.cpp | 54 +-- src/zscript/zcc_compile.cpp | 393 +++++++++++++++++++++ src/zscript/zcc_compile.h | 48 +++ src/zscript/zcc_errors.h | 8 + src/zscript/zcc_expr.cpp | 672 ++++++++++++++++++++++++++++++++++++ src/zscript/zcc_exprlist.h | 56 +++ src/zscript/zcc_parser.cpp | 13 +- src/zscript/zcc_parser.h | 107 +++--- zdoom.vcproj | 20 ++ 10 files changed, 1265 insertions(+), 108 deletions(-) create mode 100644 src/zscript/zcc_compile.cpp create mode 100644 src/zscript/zcc_compile.h create mode 100644 src/zscript/zcc_errors.h create mode 100644 src/zscript/zcc_expr.cpp create mode 100644 src/zscript/zcc_exprlist.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee814c138..152425353 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 ) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index ea7862a94..77335fcde 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.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 { diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp new file mode 100644 index 000000000..86f2d3ea2 --- /dev/null +++ b/src/zscript/zcc_compile.cpp @@ -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(node)); break; + case AST_Struct: Structs.Push(static_cast(node)); break; + case AST_Enum: break; + case AST_EnumTerminator:break; + case AST_ConstantDef: Constants.Push(static_cast(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(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(root)); + } + else if (IsUnaryOp(root->Operation)) + { + return SimplifyUnary(static_cast(root)); + } + else if (IsBinaryOp(root->Operation)) + { + return SimplifyBinary(static_cast(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(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(binary->Left), + static_cast(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(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(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(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); + val->Operation = PEX_ConstValue; + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + { + val->StringVal = AST.Strings.Alloc(static_cast(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(sym)->Value; + } + else + { + assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); + val->DoubleVal = static_cast(sym)->Float; + } + } + } + return val; +} diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h new file mode 100644 index 000000000..78632e444 --- /dev/null +++ b/src/zscript/zcc_compile.h @@ -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 Constants; + TArray Structs; + TArray 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 diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h new file mode 100644 index 000000000..bfb617b63 --- /dev/null +++ b/src/zscript/zcc_errors.h @@ -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, +}; diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp new file mode 100644 index 000000000..9d5f1e683 --- /dev/null +++ b/src/zscript/zcc_expr.cpp @@ -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); +} diff --git a/src/zscript/zcc_exprlist.h b/src/zscript/zcc_exprlist.h new file mode 100644 index 000000000..02bb8095f --- /dev/null +++ b/src/zscript/zcc_exprlist.h @@ -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 diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 32127ed46..1e3591da0 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -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) { diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 50e75fd94..9e2cf6cb3 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -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) {} diff --git a/zdoom.vcproj b/zdoom.vcproj index 124e2b998..597535708 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -3717,6 +3717,26 @@ /> + + + + + + + + + +