mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-22 12:11:21 +00:00
812 lines
21 KiB
C++
812 lines
21 KiB
C++
/*
|
|
** c_expr.cpp
|
|
** Console commands dealing with mathematical expressions
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 1998-2006 Randy Heit
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
// HEADER FILES ------------------------------------------------------------
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include "c_dispatch.h"
|
|
#include "c_cvars.h"
|
|
#include "cmdlib.h"
|
|
#include "printf.h"
|
|
|
|
// MACROS ------------------------------------------------------------------
|
|
|
|
// TYPES -------------------------------------------------------------------
|
|
|
|
enum EProductionType
|
|
{
|
|
PROD_String, PROD_Double
|
|
};
|
|
|
|
struct FProduction
|
|
{
|
|
EProductionType Type;
|
|
};
|
|
|
|
struct FStringProd : public FProduction
|
|
{
|
|
char Value[1];
|
|
};
|
|
|
|
struct FDoubleProd : public FProduction
|
|
{
|
|
double Value;
|
|
};
|
|
|
|
struct FProducer
|
|
{
|
|
char Token[4];
|
|
FProduction *(*DoubleProducer) (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *(*StringProducer) (FStringProd *prod1, FStringProd *prod2);
|
|
};
|
|
|
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
|
|
|
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
|
|
|
bool IsFloat (const char *str);
|
|
|
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
|
|
|
static FProduction *ParseExpression (FCommandLine &argv, int &parsept);
|
|
static const char *CIsNum (const char *str);
|
|
static FStringProd *NewStringProd (const char *str);
|
|
static FStringProd *NewStringProd (size_t len);
|
|
static FDoubleProd *NewDoubleProd (double val);
|
|
static FStringProd *DoubleToString (FProduction *prod);
|
|
static FDoubleProd *StringToDouble (FProduction *prod);
|
|
void MaybeStringCoerce (FProduction *&prod1, FProduction *&prod2);
|
|
void MustStringCoerce (FProduction *&prod1, FProduction *&prod2);
|
|
void DoubleCoerce (FProduction *&prod1, FProduction *&prod2);
|
|
|
|
FProduction *ProdAddDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdAddStr (FStringProd *prod1, FStringProd *prod2);
|
|
FProduction *ProdSubDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdMulDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdDivDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdModDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdPowDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdLTDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdLTEDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdGTDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdGTEDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdEqDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdNeqDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdXorDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdAndDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdOrDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdLAndDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdLOrDbl (FDoubleProd *prod1, FDoubleProd *prod2);
|
|
FProduction *ProdLTStr (FStringProd *prod1, FStringProd *prod2);
|
|
FProduction *ProdLTEStr (FStringProd *prod1, FStringProd *prod2);
|
|
FProduction *ProdGTStr (FStringProd *prod1, FStringProd *prod2);
|
|
FProduction *ProdGTEStr (FStringProd *prod1, FStringProd *prod2);
|
|
FProduction *ProdEqStr (FStringProd *prod1, FStringProd *prod2);
|
|
FProduction *ProdNeqStr (FStringProd *prod1, FStringProd *prod2);
|
|
|
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
|
|
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
|
|
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
|
|
|
static FProducer Producers[] =
|
|
{
|
|
{ "+", ProdAddDbl, ProdAddStr },
|
|
{ "-", ProdSubDbl, NULL },
|
|
{ "*", ProdMulDbl, NULL },
|
|
{ "/", ProdDivDbl, NULL },
|
|
{ "%", ProdModDbl, NULL },
|
|
{ "^", ProdPowDbl, NULL },
|
|
{ "<", ProdLTDbl, ProdLTStr },
|
|
{ "<=", ProdLTEDbl, ProdLTEStr },
|
|
{ ">", ProdGTDbl, ProdGTStr },
|
|
{ ">=", ProdGTEDbl, ProdGTEStr },
|
|
{ "=", ProdEqDbl, ProdEqStr },
|
|
{ "==", ProdEqDbl, ProdEqStr },
|
|
{ "!=", ProdNeqDbl, ProdNeqStr },
|
|
{ "<>", ProdNeqDbl, ProdNeqStr },
|
|
{ "xor", ProdXorDbl, NULL },
|
|
{ "&", ProdAndDbl, NULL },
|
|
{ "|", ProdOrDbl, NULL },
|
|
{ "&&", ProdLAndDbl, NULL },
|
|
{ "||", ProdLOrDbl, NULL }
|
|
};
|
|
|
|
// CODE --------------------------------------------------------------------
|
|
|
|
//==========================================================================
|
|
//
|
|
// ParseExpression
|
|
//
|
|
// Builds a production from an expression. The supported syntax is LISP-like
|
|
// but without parentheses.
|
|
//
|
|
//==========================================================================
|
|
|
|
static FProduction *ParseExpression (FCommandLine &argv, int &parsept)
|
|
{
|
|
if (parsept >= argv.argc())
|
|
return NULL;
|
|
|
|
const char *token = argv[parsept++];
|
|
FProduction *prod1 = NULL, *prod2 = NULL, *prod3 = NULL;
|
|
|
|
if (IsFloat (token))
|
|
{
|
|
return NewDoubleProd (atof(token));
|
|
}
|
|
else if (stricmp (token, "true") == 0)
|
|
{
|
|
return NewDoubleProd (1.0);
|
|
}
|
|
else if (stricmp (token, "false") == 0)
|
|
{
|
|
return NewDoubleProd (0.0);
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < countof(Producers); ++i)
|
|
{
|
|
if (strcmp (Producers[i].Token, token) == 0)
|
|
{
|
|
prod1 = ParseExpression (argv, parsept);
|
|
prod2 = ParseExpression (argv, parsept);
|
|
if (prod1 == NULL || prod2 == NULL)
|
|
{
|
|
goto missing;
|
|
}
|
|
if (Producers[i].StringProducer == NULL)
|
|
{
|
|
DoubleCoerce (prod1, prod2);
|
|
}
|
|
else if (Producers[i].DoubleProducer == NULL)
|
|
{
|
|
MustStringCoerce (prod1, prod2);
|
|
}
|
|
else
|
|
{
|
|
MaybeStringCoerce (prod1, prod2);
|
|
}
|
|
if (prod1->Type == PROD_String)
|
|
{
|
|
prod3 = Producers[i].StringProducer ((FStringProd *)prod1, (FStringProd *)prod2);
|
|
}
|
|
else
|
|
{
|
|
prod3 = Producers[i].DoubleProducer ((FDoubleProd *)prod1, (FDoubleProd *)prod2);
|
|
}
|
|
goto done;
|
|
}
|
|
}
|
|
if (strcmp ("!", token) == 0)
|
|
{
|
|
prod1 = ParseExpression (argv, parsept);
|
|
if (prod1 == NULL)
|
|
{
|
|
goto missing;
|
|
}
|
|
if (prod1->Type == PROD_String)
|
|
{
|
|
prod1 = StringToDouble (prod1);
|
|
}
|
|
prod3 = NewDoubleProd (!static_cast<FDoubleProd *>(prod1)->Value);
|
|
goto done;
|
|
}
|
|
return NewStringProd (token);
|
|
}
|
|
|
|
missing:
|
|
Printf ("Missing argument to %s\n", token);
|
|
|
|
done:
|
|
if (prod2 != NULL) M_Free (prod2);
|
|
if (prod1 != NULL) M_Free (prod1);
|
|
return prod3;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// IsFloat
|
|
//
|
|
//==========================================================================
|
|
|
|
bool IsFloat (const char *str)
|
|
{
|
|
const char *pt;
|
|
|
|
if (*str == '+' || *str == '-')
|
|
str++;
|
|
|
|
if (*str == '.')
|
|
{
|
|
pt = str;
|
|
}
|
|
else
|
|
{
|
|
pt = CIsNum (str);
|
|
if (pt == NULL)
|
|
return false;
|
|
}
|
|
if (*pt == '.')
|
|
{
|
|
pt = CIsNum (pt+1);
|
|
if (pt == NULL)
|
|
return false;
|
|
}
|
|
if (*pt == 'e' || *pt == 'E')
|
|
{
|
|
pt++;
|
|
if (*pt == '+' || *pt == '-')
|
|
pt++;
|
|
pt = CIsNum (pt);
|
|
}
|
|
return pt != NULL && *pt == 0;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// IsNum
|
|
//
|
|
//==========================================================================
|
|
|
|
static const char *CIsNum (const char *str)
|
|
{
|
|
const char *start = str;
|
|
|
|
while (*str)
|
|
{
|
|
if (*str >= '0' && *str <= '9')
|
|
str++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
return (str > start) ? str : NULL;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// NewStringProd (from a string)
|
|
//
|
|
//==========================================================================
|
|
|
|
static FStringProd *NewStringProd (const char *str)
|
|
{
|
|
FStringProd *prod = (FStringProd *)M_Malloc (sizeof(FStringProd)+strlen(str));
|
|
prod->Type = PROD_String;
|
|
strcpy (prod->Value, str);
|
|
return prod;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// NewStringProd (from a length)
|
|
//
|
|
//==========================================================================
|
|
|
|
static FStringProd *NewStringProd (size_t len)
|
|
{
|
|
FStringProd *prod = (FStringProd *)M_Malloc (sizeof(FStringProd)+len);
|
|
prod->Type = PROD_String;
|
|
prod->Value[0] = 0;
|
|
return prod;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// NewDoubleProd
|
|
//
|
|
//==========================================================================
|
|
|
|
static FDoubleProd *NewDoubleProd (double val)
|
|
{
|
|
FDoubleProd *prod = (FDoubleProd *)M_Malloc (sizeof(FDoubleProd));
|
|
prod->Type = PROD_Double;
|
|
prod->Value = val;
|
|
return prod;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DoubleToString
|
|
//
|
|
//==========================================================================
|
|
|
|
static FStringProd *DoubleToString (FProduction *prod)
|
|
{
|
|
char buf[128];
|
|
FStringProd *newprod;
|
|
|
|
mysnprintf (buf, countof(buf), "%g", static_cast<FDoubleProd *>(prod)->Value);
|
|
newprod = NewStringProd (buf);
|
|
M_Free (prod);
|
|
return newprod;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// StringToDouble
|
|
//
|
|
//==========================================================================
|
|
|
|
static FDoubleProd *StringToDouble (FProduction *prod)
|
|
{
|
|
FDoubleProd *newprod;
|
|
|
|
newprod = NewDoubleProd (atof (static_cast<FStringProd *>(prod)->Value));
|
|
M_Free (prod);
|
|
return newprod;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// MaybeStringCoerce
|
|
//
|
|
// If one of the parameters is a string, convert the other to a string.
|
|
//
|
|
//==========================================================================
|
|
|
|
void MaybeStringCoerce (FProduction *&prod1, FProduction *&prod2)
|
|
{
|
|
if (prod1->Type == PROD_String)
|
|
{
|
|
if (prod2->Type == PROD_Double)
|
|
{
|
|
prod2 = DoubleToString (prod2);
|
|
}
|
|
}
|
|
else if (prod2->Type == PROD_String)
|
|
{
|
|
prod1 = DoubleToString (prod1);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// MustStringCoerce
|
|
//
|
|
// Ensures that both parameters are strings
|
|
//
|
|
//==========================================================================
|
|
|
|
void MustStringCoerce (FProduction *&prod1, FProduction *&prod2)
|
|
{
|
|
if (prod1->Type == PROD_Double)
|
|
{
|
|
prod1 = DoubleToString (prod1);
|
|
}
|
|
if (prod2->Type == PROD_Double)
|
|
{
|
|
prod2 = DoubleToString (prod2);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DoubleCoerce
|
|
//
|
|
// Ensures that both parameters are doubles
|
|
//
|
|
//==========================================================================
|
|
|
|
void DoubleCoerce (FProduction *&prod1, FProduction *&prod2)
|
|
{
|
|
if (prod1->Type == PROD_String)
|
|
{
|
|
prod1 = StringToDouble (prod1);
|
|
}
|
|
if (prod2->Type == PROD_String)
|
|
{
|
|
prod2 = StringToDouble (prod2);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdAddDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdAddDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value + prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdAddStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdAddStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
size_t len = strlen (prod1->Value) + strlen (prod2->Value) + 1;
|
|
FStringProd *prod = NewStringProd (len);
|
|
strcpy (prod->Value, prod1->Value);
|
|
strcat (prod->Value, prod2->Value);
|
|
return prod;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdSubDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdSubDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value - prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdMulDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdMulDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value * prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdDivDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdDivDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value / prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdModDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdModDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (fmod (prod1->Value, prod2->Value));
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdPowDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdPowDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (pow (prod1->Value, prod2->Value));
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdLTDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdLTDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value < prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdLTEDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdLTEDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value <= prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdGTDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdGTDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value > prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdGTEDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdGTEDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value >= prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdEqDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdEqDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value == prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdNeqDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdNeqDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd (prod1->Value != prod2->Value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdLTStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdLTStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
return NewDoubleProd (stricmp (prod1->Value, prod2->Value) < 0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdLTEStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdLTEStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
return NewDoubleProd (stricmp (prod1->Value, prod2->Value) <= 0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdGTStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdGTStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
return NewDoubleProd (stricmp (prod1->Value, prod2->Value) > 0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdGTEStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdGTEStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
return NewDoubleProd (stricmp (prod1->Value, prod2->Value) >= 0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdEqStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdEqStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
return NewDoubleProd (stricmp (prod1->Value, prod2->Value) == 0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdNeqStr
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdNeqStr (FStringProd *prod1, FStringProd *prod2)
|
|
{
|
|
return NewDoubleProd (stricmp (prod1->Value, prod2->Value) != 0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdXorDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdXorDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd ((double)((int64_t)prod1->Value ^ (int64_t)prod2->Value));
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdAndDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdAndDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd ((double)((int64_t)prod1->Value & (int64_t)prod2->Value));
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdOrDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdOrDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd ((double)((int64_t)prod1->Value | (int64_t)prod2->Value));
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdLAndDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdLAndDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd ((double)((int64_t)prod1->Value && (int64_t)prod2->Value));
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ProdLOrDbl
|
|
//
|
|
//==========================================================================
|
|
|
|
FProduction *ProdLOrDbl (FDoubleProd *prod1, FDoubleProd *prod2)
|
|
{
|
|
return NewDoubleProd ((double)((int64_t)prod1->Value || (int64_t)prod2->Value));
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
//==========================================================================
|
|
//
|
|
// CCMD test
|
|
//
|
|
// If <expr> is non-zero, execute <true cmd>.
|
|
// If <expr> is zero, execute [false cmd] if specified.
|
|
//
|
|
//==========================================================================
|
|
|
|
CCMD (test)
|
|
{
|
|
int parsept = 1;
|
|
FProduction *prod = ParseExpression (argv, parsept);
|
|
|
|
if (prod == NULL || parsept >= argv.argc())
|
|
{
|
|
Printf ("Usage: test <expr> <true cmd> [false cmd]\n");
|
|
}
|
|
else
|
|
{
|
|
if (prod->Type == PROD_String)
|
|
{
|
|
prod = StringToDouble (prod);
|
|
}
|
|
|
|
if (static_cast<FDoubleProd *>(prod)->Value != 0.0)
|
|
{
|
|
AddCommandString (argv[parsept]);
|
|
}
|
|
else if (++parsept < argv.argc())
|
|
{
|
|
AddCommandString (argv[parsept]);
|
|
}
|
|
}
|
|
if (prod != NULL)
|
|
{
|
|
M_Free (prod);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// CCMD eval
|
|
//
|
|
// Evaluates an expression and either prints it to the console or stores
|
|
// it in an existing cvar.
|
|
//
|
|
//==========================================================================
|
|
|
|
CCMD (eval)
|
|
{
|
|
if (argv.argc() >= 2)
|
|
{
|
|
int parsept = 1;
|
|
FProduction *prod = ParseExpression (argv, parsept);
|
|
|
|
if (prod != NULL)
|
|
{
|
|
if (parsept < argv.argc())
|
|
{
|
|
FBaseCVar *var = FindCVar (argv[parsept], NULL);
|
|
if (var == NULL)
|
|
{
|
|
Printf ("Unknown variable %s\n", argv[parsept]);
|
|
}
|
|
else
|
|
{
|
|
UCVarValue val;
|
|
|
|
if (prod->Type == PROD_Double)
|
|
{
|
|
val.Float = (float)static_cast<FDoubleProd *>(prod)->Value;
|
|
var->SetGenericRep (val, CVAR_Float);
|
|
}
|
|
else
|
|
{
|
|
val.String = static_cast<FStringProd *>(prod)->Value;
|
|
var->SetGenericRep (val, CVAR_String);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (prod->Type == PROD_Double)
|
|
{
|
|
Printf ("%g\n", static_cast<FDoubleProd *>(prod)->Value);
|
|
}
|
|
else
|
|
{
|
|
Printf ("%s\n", static_cast<FStringProd *>(prod)->Value);
|
|
}
|
|
}
|
|
M_Free (prod);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Printf ("Usage: eval <expression> [variable]\n");
|
|
}
|