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:
Randy Heit 2013-10-23 23:06:32 -05:00
parent d0968af9a6
commit 850055a766
10 changed files with 1265 additions and 108 deletions

View file

@ -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
)

View file

@ -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
View 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
View 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
View 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
View 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);
}

View 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

View file

@ -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)
{

View file

@ -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) {}

View file

@ -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"
>