math.c

来自「NullSofts criptable install system2.28源代」· C语言 代码 · 共 1,549 行 · 第 1/4 页

C
1,549
字号
#include <windows.h>
#include "MyMath.h"
#include "Math.h"

extern "C" int _fltused;

#ifdef __MINGW32__
int _fltused = 1;
#endif

ExpressionItem *stack;

int UserVarsCount, UserFuncsCount;
UserVar UserVars[MAX_USER_VARS];
UserFunc UserFuncs[MAX_USER_FUNCS];

void PrintTree(ExpressionItem *root, char *str);
void ParseString(char *&sp, ExpressionItem* &itemplace);
void CleanupItems(ExpressionItem* &itemplace);
void PlaceVariable(char *&vb, ParseInfo *pi);

void PlaceNewItem(char *&vb, ParseInfo *pi, int precedence)
{
    ExpressionItem *newroot;
    PlaceVariable(vb, pi);
    if (pi->item == NULL) return;

    while ((pi->OpsStack) && ((((int) pi->OpsStack->param2) < precedence)
        || ((((int)pi->OpsStack->param2) == precedence)
            && (precedence != OPERATOR_SET_PRECEDENCE))))
    {
        // second operand for our operator
        newroot = pi->OpsStack;
        *((ExpressionItem **)&(newroot->param2)) = pi->item;
        pi->OpsStack = newroot->next;
        newroot->next = NULL;
        pi->item = newroot;
    }
    // finally we have got new root
    newroot = pi->item;

    if (pi->SetupNewRoot)
    {
        (*pi->root)->next = newroot;
        pi->root = &((*pi->root)->next);
        pi->SetupNewRoot = 0;
    }
    if (*pi->place == *pi->root) *pi->place = *pi->root = newroot;
    else *pi->root = newroot;
    // no item at our pockets
    pi->item = NULL;
}

#define NSIS_VARS_COUNT 27
#define NSIS_VARS_STACK 25
#define NSIS_VARS_NSTACK 26

typedef char smallstr[2];
const smallstr NSISVariablesNames[NSIS_VARS_COUNT] = {{'r','0'}, {'r','1'}, {'r','2'}, {'r','3'}, {'r','4'}, {'r','5'}, {'r','6'}, {'r','7'}, {'r','8'}, {'r','9'},
{'R','0'}, {'R','1'}, {'R','2'}, {'R','3'}, {'R','4'}, {'R','5'}, {'R','6'}, {'R','7'}, {'R','8'}, {'R','9'},
{'C','L'}, {'I','D'}, {'O','D'}, {'E','D'}, {'L','G'}, {'S',0}, {'N','S'}};

ExpressionItem *FindVariable(char *varname)
{
    int i;

    ExpressionItem *item = AllocItem();
    // check NSIS variables
    for (i = 0; i < NSIS_VARS_COUNT; i++)
    {
        if (lstrcmpn(varname, NSISVariablesNames[i],2) == 0)
        {
            if (i == NSIS_VARS_STACK) item->type = IT_VARIABLE | ITV_STACK;
            else if (i == NSIS_VARS_NSTACK) item->type = IT_VARIABLE | ITV_NSTACK;
            else
                item->type = (IT_VARIABLE | ITV_NSIS) + i;
            return item;
        }
    }
    // no.. that's user variable
    for (i = 0; i < UserVarsCount; i++)
    {
        if (lstrcmp(varname, UserVars[i].name) == 0)
        {
            // ok. we found user var expression needed
            break;
        }
    }
    if (i == UserVarsCount)
    {
        // new variable
        UserVarsCount++;
        lstrcpy(UserVars[i].name, varname);
        UserVars[i].item = NULL;
    }
    item->type = (IT_VARIABLE | ITV_USER) + i;
    return item;
}

void PlaceVariable(char *&vb, ParseInfo *pi)
{
    if (vb <= pi->valbuf) return;
    *vb = 0;
    pi->item = FindVariable(pi->valbuf);
    vb = pi->valbuf;
}

typedef double (*math_d2)(double, double);
typedef double (*math_ddp)(double, double*);
typedef double (*math_di)(double, int*);

#define MATHFUNCNUM 29
const MathFunction MathFunctions[MATHFUNCNUM] = {
    {{'s','i','n'}, ITF_MATH1 >> 8, sin},
    {{'s','n','h'}, ITF_MATH1 >> 8, sinh},
    {{'a','s','n'}, ITF_MATH1 >> 8, asin},
    {{'c','o','s'}, ITF_MATH1 >> 8, cos},
    {{'c','s','h'}, ITF_MATH1 >> 8, cosh},
    {{'a','c','s'}, ITF_MATH1 >> 8, acos},
    {{'t','a','n'}, ITF_MATH1 >> 8, tan},
    {{'t','n','h'}, ITF_MATH1 >> 8, tanh},
    {{'a','t','n'}, ITF_MATH1 >> 8, atan},
    {{'a','b','s'}, ITF_MATH1 >> 8, fabs},
    {{'l','n',0}, ITF_MATH1 >> 8, log},
    {{'l','o','g'}, ITF_MATH1 >> 8, log10},
    {{'e','x','p'}, ITF_MATH1 >> 8, exp},
    {{'s','q','t'}, ITF_MATH1 >> 8, sqrt},
    {{'c','e','l'}, ITF_MATH1 >> 8, ceil},
    {{'f','l','r'}, ITF_MATH1 >> 8, floor},

    {{'a','t','2'}, ITF_MATH2 >> 8, (Math1FuncPtr)(math_d2)atan2},
    {{'p','o','w'}, ITF_MATH2 >> 8, (Math1FuncPtr)(math_d2)pow},
    {{'f','m','d'}, ITF_MATH2 >> 8, (Math1FuncPtr)(math_d2)fmod},

    // type conversions
    {{'i',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_INT},
    {{'s',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_STRING},
    {{'f',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_FLOAT},
    {{'a',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_ARRAY},
#define ITFT_CARRAY_ID    23
    {{'c','a',0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_ARRAY},
    {{'f','f',0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_FLOATF},
    {{'l',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_LEN},
    {{'c',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_CHAR},

    {{'f','e','x'}, ITF_MATH2 >> 8, (Math1FuncPtr)(math_di)frexp},
    {{'m','d','f'}, ITF_MATH2 >> 8, (Math1FuncPtr)(math_ddp)modf},
};

void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi, int redefine)
{
    int i;
    ExpressionItem *item = pi->item = AllocItem();
    *vb = 0;

    // check BUILTIN functions
    for (i = 0; i < MATHFUNCNUM; i++)
    {
        if (lstrcmpn(pi->valbuf, MathFunctions[i].name, 3) == 0)
        {
            item->type = IT_FUNCTION | (MathFunctions[i].type << 8) | i;
            // get first argument
            sp++;
            ParseString(sp, *((ExpressionItem **)(&item->param1)));
            if (*sp == ',')
            {
                // get second argument
                sp++;
                ParseString(sp, *((ExpressionItem **)(&item->param2)));
            }
            sp++; vb = pi->valbuf;
            return;
        }
    }

    // heh, may be it user function
    for (i = 0; i < UserFuncsCount; i++)
    {
        if (lstrcmp(pi->valbuf, UserFuncs[i].name) == 0)
        {
            // Function found? Redefine option specified?
            if (redefine) break;

            item->type = IT_FUNCTION | ITF_USER | i;
            // get arguments list
            ExpressionItem **newplace = ((ExpressionItem **)(&pi->item->param1));
            while (*sp != ')')
            {
                *newplace = AllocItem();
                (*newplace)->type = IT_EXPRESSION;
                sp++;
                ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
                newplace = &((*newplace)->next);
            }
            sp++; vb = pi->valbuf;
            return;
        }
    }

    // oops, we need no item for function defenition
    CleanupItems(item); pi->item = NULL;

    // it's user function define
    int flags = 0;
    char buffer[128], *buf = buffer;

    // workaround for redefine flag - if the function already present,
    // it will be cleared and redefined
    UserFunc *f = &UserFuncs[i];
    if (i == UserFuncsCount) UserFuncsCount++;
    else CleanupItems(f->root);

    lstrcpy(f->name, pi->valbuf);
    f->varflags = 0;
    f->varsnum = 0;
    do
    {
        sp++;
        switch (*sp)
        {
        case ' ':
            break;
        case ',':
        case ')':
            if (buf > buffer)
            {
                *buf = 0;
                // it should be user variable
                ExpressionItem *it = FindVariable(buffer);
                f->vars[f->varsnum++] = (it->type) & ITEMOPTIONS;
                CleanupItems(it);
                buf = buffer;
                flags <<= 1;
            }
            break;
        case '&':
            flags |= 1;
            break;
        default:
            *(buf++) = *sp;
            break;
        }
    }
    while (*sp != ')');

    // prepare flag for fast analisys
    for (i = 0; i < f->varsnum; i++)
    {
        f->varflags <<= 1;
        flags >>= 1;
        f->varflags |= flags&1;
    }

    // find nearest round bracket - function body
    while (*sp != '(' && *sp) sp++;
    if (!*sp)
      return;
    sp++;

    // now we are ready to parse function body
    ParseString(sp, f->root);
    sp++; // closing bracket
    vb = pi->valbuf;

#ifdef _DEBUG
  // dump function (in debug mode)
  char place[1024];
  wsprintf(place, "function %s(", f->name);
  flags = f->varflags;
  for (i = 0; i < f->varsnum; i++)
  {
    if (flags&1) lstrcat(place, "&");
    lstrcat(place, UserVars[f->vars[i]].name);
    if (i < f->varsnum-1) lstrcat(place, ", ");
    flags >>= 1;
  }
  lstrcat(place, ")");
  PrintTree(f->root, place);
#endif
}

// operator options
#define PO_UNARYPRE    0x1 // this operator can be uniary pre (--a) for ex
#define PO_UNARYPOST   0x2 // this op can be uniary post (a++) (couldn't be binary)
#define PO_PRENONCONST  0x4 // pre argument (a = b) -> a is non const
#define PO_POSTNONCONST 0x8 // post argument (b--) is non const
#define PO_LASTOP      0x10 // op should be the last item at expression (=, -=, etc)
#define PO_SET         0x20 // op will set new value to one of args
#define PO_USESPRE     0x40 // operator will use pre operand
#define PO_USESPOST    0x80 // operator will use post operan

void PlaceOp(char *&vb, int type, int precedence, ParseInfo *pi)
{
    PlaceVariable(vb, pi);
    if ((type & PO_UNARYPRE) && (!pi->item))
    {
        // uniary pre op
        ExpressionItem *item = AllocItem();
        item->type = type;
        item->param2 = (EIPARAM) precedence;
        item->next = pi->OpsStack;
        pi->OpsStack = item;
    }
    else
    {
        // get previous tree as items and operators of lower precedence
        PlaceNewItem(vb, pi, precedence);
        // post operators
        ExpressionItem *item = AllocItem();
        item->type = type;
        item->param1 = (EIPARAM) (*pi->root);

        if (*pi->place == *pi->root) *pi->place = *pi->root = NULL;
        else *pi->root = NULL;

        if (type & PO_UNARYPOST)
        {
            // uniary post op
            pi->item = item;
        } else
        {
            // binary operator
            item->param2 = (EIPARAM) precedence;
            item->next = pi->OpsStack;
            pi->OpsStack = item;
        }
    }
}

#define OPSNUM  35
const OpStruct Operators[OPSNUM] =
{
// three byte ops
{{'>','>','='}, 14, ITO_SHR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{{'<','<','='}, 14, ITO_SHL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},

// two byte ops
// !!! don't forget to change Set Operator Precedence !!!
{"-=", 14, ITO_MINUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"+=", 14, ITO_PLUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"/=", 14, ITO_DIV | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"*=", 14, ITO_MUL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"|=", 14, ITO_OR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"&=", 14, ITO_AND | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"^=", 14, ITO_XOR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"%=", 14, ITO_MOD | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"--", 2, ITO_DEC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
{"++", 2, ITO_INC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
{">>", 6, ITO_SHR | PO_USESPRE | PO_USESPOST},
{"<<", 6, ITO_SHL | PO_USESPRE | PO_USESPOST},

// logical
{"&&", 12, ITO_LAND | PO_USESPRE | PO_USESPOST},
{"||", 13, ITO_LOR | PO_USESPRE | PO_USESPOST},

// comparisons
{"<=", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
{"=<", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
{">=", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
{"=>", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
{"!=", 8, ITO_NE | PO_USESPRE | PO_USESPOST},
{"==", 8, ITO_EQ | PO_USESPRE | PO_USESPOST},

// single byte ops
// !!! don't forget to change Set Operator Precedence !!!
{"=", 14, ITO_SET | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPOST},
{"+", 5, ITO_PLUS | PO_USESPRE | PO_USESPOST},
{"-", 5, ITO_MINUS | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"*", 4, ITO_MUL | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"/", 4, ITO_DIV | PO_USESPRE | PO_USESPOST},
{"%", 4, ITO_MOD | PO_USESPRE | PO_USESPOST},
{"<", 7, ITO_LS | PO_USESPRE | PO_USESPOST},
{">", 7, ITO_GR | PO_USESPRE | PO_USESPOST},
{"&", 9, ITO_AND | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"|", 11, ITO_OR | PO_USESPRE | PO_USESPOST},
{"^", 10, ITO_XOR | PO_USESPRE | PO_USESPOST},
{"~", 3, ITO_NOT | PO_USESPOST | PO_UNARYPRE},
{"!", 3, ITO_LNOT |PO_USESPOST | PO_UNARYPRE}
};

void CheckForOperator(char *&sp, char *&vb, ParseInfo *pi)
{
    for (int op = 0; op < OPSNUM; op++)
    {
        int c = lstrlen(Operators[op].name);
        if (c > 3) c = 3; // real operator length
        if (lstrcmpn(sp, Operators[op].name, c))
        {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?