1. Unary-Pre operators detection fixed.
2. Unary Minus operator added (now legal, worked before?). 3. GetReference operator (&). For example (a=&b; *a=3;) will set b=3. 4. Operators precedence added (C-like), much more intellectual expressions parsing. 5. Functions redefenition added, use "#name", like "func()(1); #func()(2);". git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@2950 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
f82158960d
commit
b2574f6b3b
7 changed files with 221 additions and 189 deletions
|
@ -1,7 +1,5 @@
|
||||||
Math::Script NSIS plugin.
|
Math::Script NSIS plugin.
|
||||||
|
|
||||||
Another huge, undocumented, bug-full, but "might be useful" plugin.
|
|
||||||
|
|
||||||
C-like style scripting (operators at least).
|
C-like style scripting (operators at least).
|
||||||
Tip1: plugin watches the case of the letters.
|
Tip1: plugin watches the case of the letters.
|
||||||
Tip2: plugin makes almost no error checks. So YOU should check your script
|
Tip2: plugin makes almost no error checks. So YOU should check your script
|
||||||
|
@ -79,11 +77,15 @@ Operators (some binary, some unary):
|
||||||
>>= <<= -= += /= *= |= &= ^= %= -- ++ >> << && || <= =< >= => != ==
|
>>= <<= -= += /= *= |= &= ^= %= -- ++ >> << && || <= =< >= => != ==
|
||||||
= + - * / % < > & | ^ ~ !
|
= + - * / % < > & | ^ ~ !
|
||||||
Only some are applicable to float (logic & arithmetic) and string (+ and logic)
|
Only some are applicable to float (logic & arithmetic) and string (+ and logic)
|
||||||
of course.
|
of course.
|
||||||
|
Additional case: reference/de-reference operators (& and *). & will
|
||||||
|
give you the reference to argument which should be a variable (NSIS, user, array
|
||||||
|
item, stack), and * will convert it back to original variable. For example
|
||||||
|
(a=&b; *a=10) will set b to 10. Expression (*&a) is equal to simple (a).
|
||||||
|
|
||||||
Script is set of expressions (mathematical in general) delimeted with ';'.
|
Script is set of expressions (mathematical in general) delimeted with ';'.
|
||||||
Processing is not mathematicaly right (2+2*2 will give 8, not 6), so use round
|
Processing is mathematicaly right (2+2*2 will give 6), operations are performed
|
||||||
brakes (for ex: 2+(2*2) ).
|
in a C like order (precedence).
|
||||||
|
|
||||||
Flow control:
|
Flow control:
|
||||||
if-then-else like: #[if-expression, then-expr, else-expr]
|
if-then-else like: #[if-expression, then-expr, else-expr]
|
||||||
|
@ -159,9 +161,8 @@ Functions:
|
||||||
|
|
||||||
User-defined functions.
|
User-defined functions.
|
||||||
It's very simple. Example:
|
It's very simple. Example:
|
||||||
test(a,b)a+b;
|
test(a,b) (a+b);
|
||||||
After that test(1,2) will give you 3. If you need more than one expression, use
|
After that test(1,2) will give you 3.
|
||||||
round brakes:
|
|
||||||
test2(a,b) (a=a+b; b *= a);
|
test2(a,b) (a=a+b; b *= a);
|
||||||
The result of function is always the result of last expression.
|
The result of function is always the result of last expression.
|
||||||
As said before it better not to use stack (S) in between function calls.
|
As said before it better not to use stack (S) in between function calls.
|
||||||
|
@ -169,8 +170,8 @@ It will be better to develop variable-safe functions, i.e. functions which will
|
||||||
not corrupt variables. For this you should either push/pop them to stack, or
|
not corrupt variables. For this you should either push/pop them to stack, or
|
||||||
declare as additional arguments, which will never be used. Example:
|
declare as additional arguments, which will never be used. Example:
|
||||||
test3(a,b,c) (c=10; #{--c > 0, a=sqrt(a*b)}; a)
|
test3(a,b,c) (c=10; #{--c > 0, a=sqrt(a*b)}; a)
|
||||||
No matter how many arguments will be passed to function all three vars will be
|
No matter how many arguments will be passed to function, the values of all three
|
||||||
saved.
|
vars (a,b,c) will be saved.
|
||||||
Such variable-safe functions could be recursive:
|
Such variable-safe functions could be recursive:
|
||||||
Math::Script /NOUNLOAD 'rec(a) (#[a > 0, rec(a-1), 0]+a);'
|
Math::Script /NOUNLOAD 'rec(a) (#[a > 0, rec(a-1), 0]+a);'
|
||||||
Math::Script 'R1 = rec(10)'
|
Math::Script 'R1 = rec(10)'
|
||||||
|
@ -184,7 +185,15 @@ at example *b. CAUTION: never use the same variable as function internal referen
|
||||||
variable and external argument variable (for example test4(a,b)). It will surely
|
variable and external argument variable (for example test4(a,b)). It will surely
|
||||||
fail. Also: if you declared argument as reference - you should never supply
|
fail. Also: if you declared argument as reference - you should never supply
|
||||||
a constant expression to it. It could be either array item (array[1]), NSIS
|
a constant expression to it. It could be either array item (array[1]), NSIS
|
||||||
register R0, any of the user variables (beside the variable with the same name:)
|
register R0, any of the user variables (beside the variable with the same name:),
|
||||||
, but never the constant.
|
but never the constant.
|
||||||
|
|
||||||
|
Another may-be-useful posibility is to redeclare the function (the usual
|
||||||
|
declaration at the time when function already defined will simply call that
|
||||||
|
function). For such task you could use "#name", like "func()(1); #func()(2);".
|
||||||
|
But beware, function declaration occurs at time of parsing, so it's not possible
|
||||||
|
to perform flow controlled declaration.
|
||||||
|
SUCH IS NOT POSSIBLE: "#[a<0, #func()(1), #func()(2)]"
|
||||||
|
IT WILL SIMPLY DEFINE #func as (2), as the latest variant.
|
||||||
|
|
||||||
(c) Nik Medved (brainsucker)
|
(c) Nik Medved (brainsucker)
|
|
@ -12,42 +12,40 @@ UserVar UserVars[MAX_USER_VARS];
|
||||||
UserFunc UserFuncs[MAX_USER_FUNCS];
|
UserFunc UserFuncs[MAX_USER_FUNCS];
|
||||||
|
|
||||||
void PrintTree(ExpressionItem *root, char *str);
|
void PrintTree(ExpressionItem *root, char *str);
|
||||||
void ParseString(char *&sp, ExpressionItem* &itemplace, int options);
|
void ParseString(char *&sp, ExpressionItem* &itemplace);
|
||||||
void CleanupItems(ExpressionItem* &itemplace);
|
void CleanupItems(ExpressionItem* &itemplace);
|
||||||
|
void PlaceVariable(char *&vb, ParseInfo *pi);
|
||||||
|
|
||||||
void PlaceNewItem(ParseInfo *pi)
|
void PlaceNewItem(char *&vb, ParseInfo *pi, int precedence)
|
||||||
{
|
{
|
||||||
ExpressionItem *newroot;
|
ExpressionItem *newroot;
|
||||||
if (pi->OpsStack)
|
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
|
// second operand for our operator
|
||||||
*((ExpressionItem **)&(pi->OpsStack->param2)) = pi->item;
|
|
||||||
newroot = pi->OpsStack;
|
newroot = pi->OpsStack;
|
||||||
|
*((ExpressionItem **)&(newroot->param2)) = pi->item;
|
||||||
pi->OpsStack = newroot->next;
|
pi->OpsStack = newroot->next;
|
||||||
newroot->next = NULL;
|
newroot->next = NULL;
|
||||||
} else
|
|
||||||
{
|
|
||||||
// no operands found - we have got new root
|
|
||||||
newroot = pi->item;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sometimes there could be more than one operators at stack, pop them all
|
|
||||||
if (pi->OpsStack)
|
|
||||||
{
|
|
||||||
// Another operator which will consume first one
|
|
||||||
pi->item = newroot;
|
pi->item = newroot;
|
||||||
PlaceNewItem(pi);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
// 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_COUNT 27
|
||||||
|
@ -99,7 +97,6 @@ void PlaceVariable(char *&vb, ParseInfo *pi)
|
||||||
if (vb <= pi->valbuf) return;
|
if (vb <= pi->valbuf) return;
|
||||||
*vb = 0;
|
*vb = 0;
|
||||||
pi->item = FindVariable(pi->valbuf);
|
pi->item = FindVariable(pi->valbuf);
|
||||||
PlaceNewItem(pi);
|
|
||||||
vb = pi->valbuf;
|
vb = pi->valbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,12 +138,12 @@ const MathFunction MathFunctions[MATHFUNCNUM] = {
|
||||||
{{'m','d','f'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fmodf},
|
{{'m','d','f'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fmodf},
|
||||||
};
|
};
|
||||||
|
|
||||||
void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi, int redefine)
|
||||||
{
|
{
|
||||||
ExpressionItem *item = pi->item = AllocItem();
|
ExpressionItem *item = pi->item = AllocItem();
|
||||||
*vb = 0;
|
*vb = 0;
|
||||||
|
|
||||||
// check BUILTIN variables
|
// check BUILTIN functions
|
||||||
for (int i = 0; i < MATHFUNCNUM; i++)
|
for (int i = 0; i < MATHFUNCNUM; i++)
|
||||||
{
|
{
|
||||||
if (lstrcmpn(pi->valbuf, MathFunctions[i].name, 3) == 0)
|
if (lstrcmpn(pi->valbuf, MathFunctions[i].name, 3) == 0)
|
||||||
|
@ -154,15 +151,14 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
||||||
item->type = IT_FUNCTION | (MathFunctions[i].type << 8) | i;
|
item->type = IT_FUNCTION | (MathFunctions[i].type << 8) | i;
|
||||||
// get first argument
|
// get first argument
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, *((ExpressionItem **)(&item->param1)), 0);
|
ParseString(sp, *((ExpressionItem **)(&item->param1)));
|
||||||
if (*sp == ',')
|
if (*sp == ',')
|
||||||
{
|
{
|
||||||
// get second argument
|
// get second argument
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, *((ExpressionItem **)(&item->param2)), 0);
|
ParseString(sp, *((ExpressionItem **)(&item->param2)));
|
||||||
}
|
}
|
||||||
sp++; vb = pi->valbuf;
|
sp++; vb = pi->valbuf;
|
||||||
PlaceNewItem(pi);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,6 +168,9 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
||||||
{
|
{
|
||||||
if (lstrcmp(pi->valbuf, UserFuncs[i].name) == 0)
|
if (lstrcmp(pi->valbuf, UserFuncs[i].name) == 0)
|
||||||
{
|
{
|
||||||
|
// Function found? Redefine option specified?
|
||||||
|
if (redefine) break;
|
||||||
|
|
||||||
item->type = IT_FUNCTION | ITF_USER | i;
|
item->type = IT_FUNCTION | ITF_USER | i;
|
||||||
// get arguments list
|
// get arguments list
|
||||||
ExpressionItem **newplace = ((ExpressionItem **)(&pi->item->param1));
|
ExpressionItem **newplace = ((ExpressionItem **)(&pi->item->param1));
|
||||||
|
@ -180,22 +179,27 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
||||||
*newplace = AllocItem();
|
*newplace = AllocItem();
|
||||||
(*newplace)->type = IT_EXPRESSION;
|
(*newplace)->type = IT_EXPRESSION;
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)), 0);
|
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
|
||||||
newplace = &((*newplace)->next);
|
newplace = &((*newplace)->next);
|
||||||
}
|
}
|
||||||
sp++; vb = pi->valbuf;
|
sp++; vb = pi->valbuf;
|
||||||
PlaceNewItem(pi);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// oops, we need no item for function defenition
|
// oops, we need no item for function defenition
|
||||||
CleanupItems(item);
|
CleanupItems(item); pi->item = NULL;
|
||||||
|
|
||||||
// it's user function define
|
// it's user function define
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
char buffer[128], *buf = buffer;
|
char buffer[128], *buf = buffer;
|
||||||
UserFunc *f = &UserFuncs[UserFuncsCount++];
|
|
||||||
|
// 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);
|
lstrcpy(f->name, pi->valbuf);
|
||||||
f->varflags = 0;
|
f->varflags = 0;
|
||||||
f->varsnum = 0;
|
f->varsnum = 0;
|
||||||
|
@ -237,9 +241,13 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
||||||
f->varflags |= flags&1;
|
f->varflags |= flags&1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp++;
|
// find nearest round bracket - function body
|
||||||
|
while (*sp != '(') sp++;
|
||||||
|
sp++;
|
||||||
|
|
||||||
// now we are ready to parse function body
|
// now we are ready to parse function body
|
||||||
ParseString(sp, f->root, PSO_STOPATDELIMETER);
|
ParseString(sp, f->root);
|
||||||
|
sp++; // closing bracket
|
||||||
vb = pi->valbuf;
|
vb = pi->valbuf;
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
@ -259,9 +267,6 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsestring options
|
|
||||||
#define PSO_STOPATDELIMETER 0x1
|
|
||||||
|
|
||||||
// operator options
|
// operator options
|
||||||
#define PO_UNARYPRE 0x1 // this operator can be uniary pre (--a) for ex
|
#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_UNARYPOST 0x2 // this op can be uniary post (a++) (couldn't be binary)
|
||||||
|
@ -272,32 +277,40 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
|
||||||
#define PO_USESPRE 0x40 // operator will use pre operand
|
#define PO_USESPRE 0x40 // operator will use pre operand
|
||||||
#define PO_USESPOST 0x80 // operator will use post operan
|
#define PO_USESPOST 0x80 // operator will use post operan
|
||||||
|
|
||||||
void PlaceOp(char *&vb, int type, ParseInfo *pi)
|
void PlaceOp(char *&vb, int type, int precedence, ParseInfo *pi)
|
||||||
{
|
{
|
||||||
if ((type & PO_UNARYPRE) && ((pi->SetupNewRoot) || (*pi->root == NULL) || (((*pi->root)->type & ITEMTYPE) == IT_OPERATOR)))
|
PlaceVariable(vb, pi);
|
||||||
|
if ((type & PO_UNARYPRE) && (!pi->item))
|
||||||
{
|
{
|
||||||
// uniary pre op
|
// uniary pre op
|
||||||
pi->item = AllocItem();
|
ExpressionItem *item = AllocItem();
|
||||||
pi->item->type = type;
|
item->type = type;
|
||||||
pi->item->next = pi->OpsStack;
|
item->param2 = (EIPARAM) precedence;
|
||||||
pi->OpsStack = pi->item;
|
item->next = pi->OpsStack;
|
||||||
|
pi->OpsStack = item;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// get previous tree as items and operators of lower precedence
|
||||||
|
PlaceNewItem(vb, pi, precedence);
|
||||||
// post operators
|
// post operators
|
||||||
PlaceVariable(vb, pi);
|
ExpressionItem *item = AllocItem();
|
||||||
pi->item = AllocItem();
|
item->type = type;
|
||||||
pi->item->type = type;
|
item->param1 = (EIPARAM) (*pi->root);
|
||||||
pi->item->param1 = (int) (*pi->root);
|
|
||||||
|
if (pi->place == *pi->root) pi->place = *pi->root = NULL;
|
||||||
|
else *pi->root = NULL;
|
||||||
|
|
||||||
if (type & PO_UNARYPOST)
|
if (type & PO_UNARYPOST)
|
||||||
{
|
{
|
||||||
// uniary post op
|
// uniary post op
|
||||||
PlaceNewItem(pi);
|
pi->item = item;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// binary operator
|
// binary operator
|
||||||
pi->item->next = pi->OpsStack;
|
item->param2 = (EIPARAM) precedence;
|
||||||
pi->OpsStack = pi->item;
|
item->next = pi->OpsStack;
|
||||||
|
pi->OpsStack = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,80 +319,76 @@ void PlaceOp(char *&vb, int type, ParseInfo *pi)
|
||||||
const OpStruct Operators[OPSNUM] =
|
const OpStruct Operators[OPSNUM] =
|
||||||
{
|
{
|
||||||
// three byte ops
|
// three byte ops
|
||||||
{">>=", ITO_SHR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{{'>','>','='}, 14, ITO_SHR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"<<=", ITO_SHL | 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
|
// two byte ops
|
||||||
{"-=", ITO_MINUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
// !!! don't forget to change Set Operator Precedence !!!
|
||||||
{"+=", ITO_PLUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"-=", 14, ITO_MINUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"/=", ITO_DIV | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"+=", 14, ITO_PLUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"*=", ITO_MUL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"/=", 14, ITO_DIV | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"|=", ITO_OR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"*=", 14, ITO_MUL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"&=", ITO_AND | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"|=", 14, ITO_OR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"^=", ITO_XOR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"&=", 14, ITO_AND | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"%=", ITO_MOD | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"^=", 14, ITO_XOR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"--", ITO_DEC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"%=", 14, ITO_MOD | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"++", ITO_INC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
|
{"--", 2, ITO_DEC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{">>", ITO_SHR | PO_USESPRE | PO_USESPOST},
|
{"++", 2, ITO_INC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
|
||||||
{"<<", ITO_SHL | PO_USESPRE | PO_USESPOST},
|
{">>", 6, ITO_SHR | PO_USESPRE | PO_USESPOST},
|
||||||
|
{"<<", 6, ITO_SHL | PO_USESPRE | PO_USESPOST},
|
||||||
|
|
||||||
// logical
|
// logical
|
||||||
{"&&", ITO_LAND | PO_USESPRE | PO_USESPOST},
|
{"&&", 12, ITO_LAND | PO_USESPRE | PO_USESPOST},
|
||||||
{"||", ITO_LOR | PO_USESPRE | PO_USESPOST},
|
{"||", 13, ITO_LOR | PO_USESPRE | PO_USESPOST},
|
||||||
|
|
||||||
// comparisons
|
// comparisons
|
||||||
{"<=", ITO_LE | PO_USESPRE | PO_USESPOST},
|
{"<=", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
|
||||||
{"=<", ITO_LE | PO_USESPRE | PO_USESPOST},
|
{"=<", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
|
||||||
{">=", ITO_GE | PO_USESPRE | PO_USESPOST},
|
{">=", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
|
||||||
{"=>", ITO_GE | PO_USESPRE | PO_USESPOST},
|
{"=>", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
|
||||||
{"!=", ITO_NE | PO_USESPRE | PO_USESPOST},
|
{"!=", 8, ITO_NE | PO_USESPRE | PO_USESPOST},
|
||||||
{"==", ITO_EQ | PO_USESPRE | PO_USESPOST},
|
{"==", 8, ITO_EQ | PO_USESPRE | PO_USESPOST},
|
||||||
|
|
||||||
// single byte ops
|
// single byte ops
|
||||||
{"=", ITO_SET | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPOST},
|
// !!! don't forget to change Set Operator Precedence !!!
|
||||||
{"+", ITO_PLUS | PO_USESPRE | PO_USESPOST},
|
{"=", 14, ITO_SET | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPOST},
|
||||||
{"-", ITO_MINUS | PO_USESPRE | PO_USESPOST},
|
{"+", 5, ITO_PLUS | PO_USESPRE | PO_USESPOST},
|
||||||
{"*", ITO_MUL | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
|
{"-", 5, ITO_MINUS | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
|
||||||
{"/", ITO_DIV | PO_USESPRE | PO_USESPOST},
|
{"*", 4, ITO_MUL | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
|
||||||
{"%", ITO_MOD | PO_USESPRE | PO_USESPOST},
|
{"/", 4, ITO_DIV | PO_USESPRE | PO_USESPOST},
|
||||||
{"<", ITO_LS | PO_USESPRE | PO_USESPOST},
|
{"%", 4, ITO_MOD | PO_USESPRE | PO_USESPOST},
|
||||||
{">", ITO_GR | PO_USESPRE | PO_USESPOST},
|
{"<", 7, ITO_LS | PO_USESPRE | PO_USESPOST},
|
||||||
{"&", ITO_AND | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
|
{">", 7, ITO_GR | PO_USESPRE | PO_USESPOST},
|
||||||
{"|", ITO_OR | PO_USESPRE | PO_USESPOST},
|
{"&", 9, ITO_AND | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
|
||||||
{"^", ITO_XOR | PO_USESPRE | PO_USESPOST},
|
{"|", 11, ITO_OR | PO_USESPRE | PO_USESPOST},
|
||||||
{"~", ITO_NOT | PO_USESPOST | PO_UNARYPRE},
|
{"^", 10, ITO_XOR | PO_USESPRE | PO_USESPOST},
|
||||||
{"!", ITO_LNOT |PO_USESPOST | PO_UNARYPRE}
|
{"~", 3, ITO_NOT | PO_USESPOST | PO_UNARYPRE},
|
||||||
|
{"!", 3, ITO_LNOT |PO_USESPOST | PO_UNARYPRE}
|
||||||
};
|
};
|
||||||
|
|
||||||
void CheckForOperator(char *&sp, char *&vb, ParseInfo *pi)
|
void CheckForOperator(char *&sp, char *&vb, ParseInfo *pi)
|
||||||
{
|
{
|
||||||
for (int op = 0; op < OPSNUM; op++)
|
for (int op = 0; op < OPSNUM; op++)
|
||||||
{
|
{
|
||||||
int c = 0;
|
int c = lstrlen(Operators[op].name);
|
||||||
while ((Operators[op].name[c]) && (*(sp+c) == Operators[op].name[c])) c++;
|
if (c > 3) c = 3; // real operator length
|
||||||
if (Operators[op].name[c])
|
if (lstrcmpn(sp, Operators[op].name, c))
|
||||||
{
|
{
|
||||||
// wrong - different op
|
// wrong - different op
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// that is our op
|
// that is our op
|
||||||
sp += c;
|
sp += c;
|
||||||
PlaceOp(vb, ((int) Operators[op].type) | IT_OPERATOR, pi);
|
PlaceOp(vb, ((int) Operators[op].type) | IT_OPERATOR, Operators[op].precedence, pi);
|
||||||
if (Operators[op].type & PO_LASTOP)
|
|
||||||
{
|
|
||||||
// this op should be last in a set of items
|
|
||||||
pi->item = NULL;
|
|
||||||
ParseString(sp, pi->item, PSO_STOPATDELIMETER);
|
|
||||||
PlaceNewItem(pi);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
void ParseString(char *&sp, ExpressionItem* &itemplace)
|
||||||
{
|
{
|
||||||
ParseInfo pi = {0, NULL, NULL, itemplace, &itemplace};
|
ParseInfo pi = {0, NULL, NULL, itemplace, &itemplace};
|
||||||
|
|
||||||
|
int redefine = 0;
|
||||||
char *vb = pi.valbuf;
|
char *vb = pi.valbuf;
|
||||||
// cycle until current expression end
|
// cycle until current expression end
|
||||||
while ((*sp != 0) && (*sp != ')') && (*sp != '}') &&
|
while ((*sp != 0) && (*sp != ')') && (*sp != '}') &&
|
||||||
|
@ -394,10 +403,8 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
// expression delimeter
|
// expression delimeter
|
||||||
PlaceVariable(vb, &pi);
|
PlaceNewItem(vb, &pi, 255);
|
||||||
pi.SetupNewRoot = 1;
|
if (*pi.root) pi.SetupNewRoot = 1;
|
||||||
// check stop at delimeter option
|
|
||||||
if (options & PSO_STOPATDELIMETER) return;
|
|
||||||
sp++;
|
sp++;
|
||||||
break;
|
break;
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
@ -412,26 +419,31 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
||||||
// constant meet
|
// constant meet
|
||||||
pi.item = AllocItem();
|
pi.item = AllocItem();
|
||||||
StringToItem(sp, pi.item, STI_STRING | STI_FLOAT | STI_INT);
|
StringToItem(sp, pi.item, STI_STRING | STI_FLOAT | STI_INT);
|
||||||
PlaceNewItem(&pi);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '(': // start of function or expression
|
case '(': // start of function or expression
|
||||||
if (vb > pi.valbuf)
|
if (vb > pi.valbuf)
|
||||||
{
|
{
|
||||||
// thats function
|
// thats function
|
||||||
PlaceFunction(vb, sp, &pi);
|
PlaceFunction(vb, sp, &pi, redefine);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// expression
|
// expression
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, pi.item, 0);
|
ParseString(sp, pi.item);
|
||||||
PlaceNewItem(&pi);
|
|
||||||
if (*sp == ')') sp++;
|
if (*sp == ')') sp++;
|
||||||
}
|
}
|
||||||
|
redefine = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '#': // start of one of logical expresions
|
case '#': // start of one of logical expresions
|
||||||
sp++;
|
sp++;
|
||||||
|
if ((*sp != '[') && (*sp != '{'))
|
||||||
|
{
|
||||||
|
// function redefine flag
|
||||||
|
redefine = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
pi.item = AllocItem();
|
pi.item = AllocItem();
|
||||||
// IF or WHILE
|
// IF or WHILE
|
||||||
|
@ -439,7 +451,7 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
||||||
// first expr - logic statement
|
// first expr - logic statement
|
||||||
sp++;
|
sp++;
|
||||||
|
|
||||||
ParseString(sp, *((ExpressionItem **)(&pi.item->param1)), 0);
|
ParseString(sp, *((ExpressionItem **)(&pi.item->param1)));
|
||||||
// ok, second expr - then, third - else statement.. others???
|
// ok, second expr - then, third - else statement.. others???
|
||||||
ExpressionItem **newplace = ((ExpressionItem **)(&pi.item->param2));
|
ExpressionItem **newplace = ((ExpressionItem **)(&pi.item->param2));
|
||||||
while (*sp == ',')
|
while (*sp == ',')
|
||||||
|
@ -447,35 +459,34 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
||||||
*newplace = AllocItem();
|
*newplace = AllocItem();
|
||||||
(*newplace)->type = IT_EXPRESSION;
|
(*newplace)->type = IT_EXPRESSION;
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)), 0);
|
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
|
||||||
newplace = &((*newplace)->next);
|
newplace = &((*newplace)->next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlaceNewItem(&pi);
|
|
||||||
sp++;
|
sp++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
|
{
|
||||||
// thats array access
|
// thats array access
|
||||||
PlaceOp(vb, IT_ARRAY | ITA_ACCESS, &pi);
|
PlaceOp(vb, IT_ARRAY | ITA_ACCESS | PO_UNARYPOST, 1, &pi);
|
||||||
sp++;
|
sp++;
|
||||||
// item index
|
// item index
|
||||||
pi.item = NULL;
|
ParseString(sp, *(ExpressionItem **)&(pi.item->param2));
|
||||||
ParseString(sp, pi.item, 0);
|
|
||||||
if (*sp == ',')
|
if (*sp == ',')
|
||||||
{
|
{
|
||||||
// two indexes - string access
|
// two indexes - string access
|
||||||
ExpressionItem *it = AllocItem();
|
ExpressionItem *it = AllocItem();
|
||||||
it->type = IT_EXPRESSION;
|
it->type = IT_EXPRESSION;
|
||||||
it->param1 = (int) pi.item;
|
it->param1 = (EIPARAM) *(ExpressionItem **)&(pi.item->param2);
|
||||||
pi.item = it;
|
*(ExpressionItem **)&(pi.item->param2) = it;
|
||||||
it = it->next = AllocItem();
|
it = it->next = AllocItem();
|
||||||
it->type = IT_EXPRESSION;
|
it->type = IT_EXPRESSION;
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, *((ExpressionItem **)(&it->param1)), 0);
|
ParseString(sp, *((ExpressionItem **)(&it->param1)));
|
||||||
}
|
}
|
||||||
PlaceNewItem(&pi);
|
|
||||||
sp++;
|
sp++;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '{': // start of array define
|
case '{': // start of array define
|
||||||
|
@ -488,24 +499,22 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
||||||
|
|
||||||
// during first create our array descriptor and array pointers
|
// during first create our array descriptor and array pointers
|
||||||
ExpressionItem *ai = AllocArray(DEFAULT_ARRAY_SIZE);
|
ExpressionItem *ai = AllocArray(DEFAULT_ARRAY_SIZE);
|
||||||
pi.item->param1 = (int) ai;
|
pi.item->param1 = (EIPARAM) ai;
|
||||||
ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
|
ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
|
||||||
|
|
||||||
// parse array initializers
|
// parse array initializers
|
||||||
while (*sp != '}')
|
while (*sp != '}')
|
||||||
{
|
{
|
||||||
sp++;
|
sp++;
|
||||||
ParseString(sp, ad->array[ad->count++], 0);
|
ParseString(sp, ad->array[ad->count++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaceNewItem(&pi);
|
|
||||||
sp++;
|
sp++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '-': case '+': case '<': case '=': case '>':
|
case '-': case '+': case '<': case '=': case '>':
|
||||||
case '/': case '*': case '~': case '^': case '!':
|
case '/': case '*': case '~': case '^': case '!':
|
||||||
case '&': case '|': case '%':
|
case '&': case '|': case '%':
|
||||||
PlaceVariable(vb, &pi);
|
|
||||||
CheckForOperator(sp, vb, &pi);
|
CheckForOperator(sp, vb, &pi);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -516,7 +525,7 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
|
||||||
}
|
}
|
||||||
if (!processed) *(vb++) = *(sp++);
|
if (!processed) *(vb++) = *(sp++);
|
||||||
}
|
}
|
||||||
PlaceVariable(vb, &pi);
|
PlaceNewItem(vb, &pi, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CleanupArray(ArrayDesc *ad)
|
void CleanupArray(ArrayDesc *ad)
|
||||||
|
@ -764,7 +773,7 @@ void ItemToType(ExpressionItem* &item, int type)
|
||||||
case ITC_STRING:
|
case ITC_STRING:
|
||||||
buffer = AllocString();
|
buffer = AllocString();
|
||||||
ItemToString(buffer, item);
|
ItemToString(buffer, item);
|
||||||
item->param1 = (int) buffer;
|
item->param1 = (EIPARAM) buffer;
|
||||||
item->param2 = 0;
|
item->param2 = 0;
|
||||||
break;
|
break;
|
||||||
case ITC_FLOAT:
|
case ITC_FLOAT:
|
||||||
|
@ -831,7 +840,7 @@ void SaveResult(ExpressionItem *var, ExpressionItem *result)
|
||||||
break;
|
break;
|
||||||
case ITV_ARRITEM:
|
case ITV_ARRITEM:
|
||||||
{
|
{
|
||||||
ExpressionItem *&ei = ((ArrayDesc*)(var->param1))->array[var->param2];
|
ExpressionItem *&ei = ((ArrayDesc*)(var->param1))->array[(int)var->param2];
|
||||||
CleanupItems(ei);
|
CleanupItems(ei);
|
||||||
ei = CopyItem(result);
|
ei = CopyItem(result);
|
||||||
}
|
}
|
||||||
|
@ -904,7 +913,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
case ITV_ARRITEM:
|
case ITV_ARRITEM:
|
||||||
{
|
{
|
||||||
// array item
|
// array item
|
||||||
ExpressionItem *ei = ((ArrayDesc*)(item->param1))->array[item->param2];
|
ExpressionItem *ei = ((ArrayDesc*)(item->param1))->array[(int)item->param2];
|
||||||
if (ei)
|
if (ei)
|
||||||
result = CopyItem(ei);
|
result = CopyItem(ei);
|
||||||
else
|
else
|
||||||
|
@ -970,6 +979,13 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get-reference operator
|
||||||
|
if ((!item1) && (subtype == ITO_AND) && (!item2) && (item->param2))
|
||||||
|
{
|
||||||
|
RunTree(*((ExpressionItem**)&(item->param2)), result, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((needmore) && (!item2) && (item->param2) && (ioptions & PO_USESPOST))
|
if ((needmore) && (!item2) && (item->param2) && (ioptions & PO_USESPOST))
|
||||||
RunTree(*((ExpressionItem**)&(item->param2)), item2, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
|
RunTree(*((ExpressionItem**)&(item->param2)), item2, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
|
||||||
|
|
||||||
|
@ -984,7 +1000,12 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
} else
|
} else
|
||||||
result = item2;
|
result = item2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__int64 i1, i2, i3, i4;
|
||||||
|
if (((!item1)||((item1->type & ITEMTYPE)==IT_CONST)) &&
|
||||||
|
((!item2)||((item2->type & ITEMTYPE)==IT_CONST)))
|
||||||
|
{
|
||||||
|
|
||||||
// find the best type match for operation
|
// find the best type match for operation
|
||||||
int it1 = (item1 && (ioptions & PO_USESPRE))?(item1->type & ITEMSUBTYPE):(ITC_UNKNOWN),
|
int it1 = (item1 && (ioptions & PO_USESPRE))?(item1->type & ITEMSUBTYPE):(ITC_UNKNOWN),
|
||||||
|
@ -994,15 +1015,14 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
// convert operands to desired type
|
// convert operands to desired type
|
||||||
ItemToType(item1, type);
|
ItemToType(item1, type);
|
||||||
ItemToType(item2, type);
|
ItemToType(item2, type);
|
||||||
|
|
||||||
__int64 i1, i2, i3, i4;
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ITC_INT:
|
case ITC_INT:
|
||||||
{
|
{
|
||||||
i1 = (item1)?(*((__int64*)&item1->param1)):(0);
|
i1 = (item1)?(*((__int64*)&item1->param1)):(0);
|
||||||
i2 = (item2)?(*((__int64*)&item2->param1)):(0);
|
i2 = (item2)?(*((__int64*)&item2->param1)):(0);
|
||||||
|
|
||||||
switch (subtype)
|
switch (subtype)
|
||||||
{
|
{
|
||||||
case ITO_MINUS: i1 -= i2; break; // unary minus auto handled with NULL
|
case ITO_MINUS: i1 -= i2; break; // unary minus auto handled with NULL
|
||||||
|
@ -1106,6 +1126,10 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // check for both items constant
|
||||||
|
// the other case - usually UniaryPre operators working with non constants
|
||||||
|
else result = CopyItem(item2);
|
||||||
|
|
||||||
if (ioptions & PO_SET)
|
if (ioptions & PO_SET)
|
||||||
{
|
{
|
||||||
// Save our result in output variable
|
// Save our result in output variable
|
||||||
|
@ -1171,7 +1195,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
// push every variable
|
// push every variable
|
||||||
ExpressionItem *val;
|
ExpressionItem *val;
|
||||||
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
|
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
|
||||||
RunTree(var, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY | ITC_VARPTR);
|
RunTree(var, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
|
||||||
SaveResult(si, val);
|
SaveResult(si, val);
|
||||||
CleanupItems(val);
|
CleanupItems(val);
|
||||||
// calculate argument value and for future
|
// calculate argument value and for future
|
||||||
|
@ -1183,7 +1207,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], 0);
|
RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], 0);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY | ITC_VARPTR);
|
RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
|
||||||
}
|
}
|
||||||
ip = ip->next;
|
ip = ip->next;
|
||||||
} else vals[i] = AllocItem();
|
} else vals[i] = AllocItem();
|
||||||
|
@ -1201,7 +1225,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
|
|
||||||
|
|
||||||
// ok, call the func
|
// ok, call the func
|
||||||
RunTree(f->root, result, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY | ITC_VARPTR);
|
RunTree(f->root, result, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
|
||||||
|
|
||||||
// pop original params
|
// pop original params
|
||||||
for (int i = f->varsnum-1; i >= 0; i--)
|
for (int i = f->varsnum-1; i >= 0; i--)
|
||||||
|
@ -1209,7 +1233,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
// pop every variable
|
// pop every variable
|
||||||
ExpressionItem *val;
|
ExpressionItem *val;
|
||||||
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
|
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
|
||||||
RunTree(si, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY | ITC_VARPTR);
|
RunTree(si, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
|
||||||
SaveResult(var, val);
|
SaveResult(var, val);
|
||||||
CleanupItems(val);
|
CleanupItems(val);
|
||||||
}
|
}
|
||||||
|
@ -1222,21 +1246,21 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
if (newtype < ITC_UNKNOWN)
|
if (newtype < ITC_UNKNOWN)
|
||||||
{
|
{
|
||||||
// get as possibly close to ready expression
|
// get as possibly close to ready expression
|
||||||
RunAndGetConst(item->param1, result, newtype);
|
RunAndGetConst((int)item->param1, result, newtype);
|
||||||
if (ioptions == ITFT_CARRAY_ID)
|
if (ioptions == ITFT_CARRAY_ID)
|
||||||
CopyArray(result);
|
CopyArray(result);
|
||||||
} else if (newtype == FTT_FLOATF)
|
} else if (newtype == FTT_FLOATF)
|
||||||
{
|
{
|
||||||
// float format function
|
// float format function
|
||||||
ExpressionItem *arg1, *arg2;
|
ExpressionItem *arg1, *arg2;
|
||||||
RunAndGetConst(item->param1, arg1, ITC_FLOAT);
|
RunAndGetConst((int)item->param1, arg1, ITC_FLOAT);
|
||||||
double value = *((double*)&(arg1->param1));
|
double value = *((double*)&(arg1->param1));
|
||||||
RunAndGetConst(item->param2, arg2, ITC_INT);
|
RunAndGetConst((int)item->param2, arg2, ITC_INT);
|
||||||
int format = (int) *((__int64*)&(arg2->param1));
|
int format = (int) *((__int64*)&(arg2->param1));
|
||||||
|
|
||||||
result = AllocItem();
|
result = AllocItem();
|
||||||
result->type = IT_CONST | ITC_STRING;
|
result->type = IT_CONST | ITC_STRING;
|
||||||
result->param1 = (int) AllocString();
|
result->param1 = (EIPARAM) AllocString();
|
||||||
FloatFormat((char*) result->param1, value, format);
|
FloatFormat((char*) result->param1, value, format);
|
||||||
CleanupItems(arg1); CleanupItems(arg2);
|
CleanupItems(arg1); CleanupItems(arg2);
|
||||||
} else if (newtype == FTT_LEN)
|
} else if (newtype == FTT_LEN)
|
||||||
|
@ -1279,7 +1303,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
{
|
{
|
||||||
// ok, that's int - convert to new string (char+0)
|
// ok, that's int - convert to new string (char+0)
|
||||||
int chr = (int) (*((__int64*)&(result->param1))) & 0xFF;
|
int chr = (int) (*((__int64*)&(result->param1))) & 0xFF;
|
||||||
result->param1 = (int) AllocString();
|
result->param1 = (EIPARAM) AllocString();
|
||||||
*((char*)result->param1) = (char) chr;
|
*((char*)result->param1) = (char) chr;
|
||||||
*((char*)(result->param1+1)) = (char) 0;
|
*((char*)(result->param1+1)) = (char) 0;
|
||||||
result->type = IT_CONST | ITC_STRING;
|
result->type = IT_CONST | ITC_STRING;
|
||||||
|
@ -1289,7 +1313,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// oops :-o function call :)
|
// oops :-o function call :)
|
||||||
RunAndGetConst(item->param1, result, ITC_FLOAT);
|
RunAndGetConst((int)item->param1, result, ITC_FLOAT);
|
||||||
double &value = *((double*)&(result->param1));
|
double &value = *((double*)&(result->param1));
|
||||||
if (subtype == ITF_MATH1)
|
if (subtype == ITF_MATH1)
|
||||||
{
|
{
|
||||||
|
@ -1323,7 +1347,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
{
|
{
|
||||||
// normal 2-arg math function
|
// normal 2-arg math function
|
||||||
ExpressionItem *arg2;
|
ExpressionItem *arg2;
|
||||||
RunAndGetConst(item->param2, arg2, ITC_FLOAT);
|
RunAndGetConst((int)item->param2, arg2, ITC_FLOAT);
|
||||||
double value2 = *((double*)&(arg2->param1));
|
double value2 = *((double*)&(arg2->param1));
|
||||||
value = ((Math2FuncPtr)(MathFunctions[ioptions].fptr))(value, value2);
|
value = ((Math2FuncPtr)(MathFunctions[ioptions].fptr))(value, value2);
|
||||||
CleanupItems(arg2);
|
CleanupItems(arg2);
|
||||||
|
@ -1346,7 +1370,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
if ((*((ExpressionItem **) &(item->param2)))->type != IT_EXPRESSION)
|
if ((*((ExpressionItem **) &(item->param2)))->type != IT_EXPRESSION)
|
||||||
{
|
{
|
||||||
// one index - user need a char
|
// one index - user need a char
|
||||||
RunAndGetConst(item->param2, index, ITC_INT);
|
RunAndGetConst((int)item->param2, index, ITC_INT);
|
||||||
|
|
||||||
int pos = (int) *((__int64*)&(index->param1));
|
int pos = (int) *((__int64*)&(index->param1));
|
||||||
if (pos < 0) pos += len; // -index - means from end
|
if (pos < 0) pos += len; // -index - means from end
|
||||||
|
@ -1366,7 +1390,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
if ((*((ExpressionItem **) &(item->param2)))->param1 == 0)
|
if ((*((ExpressionItem **) &(item->param2)))->param1 == 0)
|
||||||
index = AllocItem();
|
index = AllocItem();
|
||||||
else
|
else
|
||||||
RunAndGetConst((*((ExpressionItem **) &(item->param2)))->param1, index, ITC_INT);
|
RunAndGetConst((int)(*((ExpressionItem **) &(item->param2)))->param1, index, ITC_INT);
|
||||||
if ((*((ExpressionItem **) &(item->param2)))->next->param1 == 0)
|
if ((*((ExpressionItem **) &(item->param2)))->next->param1 == 0)
|
||||||
{
|
{
|
||||||
// if second index is skipped -> -1 (till last char)
|
// if second index is skipped -> -1 (till last char)
|
||||||
|
@ -1374,7 +1398,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
*((__int64*)&(index2->param1)) = -1;
|
*((__int64*)&(index2->param1)) = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RunAndGetConst((*((ExpressionItem **) &(item->param2)))->next->param1, index2, ITC_INT);
|
RunAndGetConst((int)(*((ExpressionItem **) &(item->param2)))->next->param1, index2, ITC_INT);
|
||||||
|
|
||||||
// ok, we've got two indexes
|
// ok, we've got two indexes
|
||||||
int pos1 = (int) *((__int64*)&(index->param1));
|
int pos1 = (int) *((__int64*)&(index->param1));
|
||||||
|
@ -1403,16 +1427,16 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// argument is array
|
// argument is array
|
||||||
RunAndGetConst(item->param2, index, ITC_INT);
|
RunAndGetConst((int)item->param2, index, ITC_INT);
|
||||||
|
|
||||||
// convert array pointer to array item pointer
|
// convert array pointer to array item pointer
|
||||||
aritem->type = IT_VARIABLE | ITV_ARRITEM;
|
aritem->type = IT_VARIABLE | ITV_ARRITEM;
|
||||||
aritem->param2 = (int) *((__int64*)&(index->param1));
|
aritem->param2 = (EIPARAM) *((__int64*)&(index->param1));
|
||||||
|
|
||||||
ArrayDesc *ad = (ArrayDesc*)aritem->param1;
|
ArrayDesc *ad = (ArrayDesc*)aritem->param1;
|
||||||
if (aritem->param2 > ad->count)
|
if (((int)aritem->param2) > ad->count)
|
||||||
{
|
{
|
||||||
ad->count = aritem->param2+1;
|
ad->count = ((int)aritem->param2)+1;
|
||||||
while (ad->count > ad->size)
|
while (ad->count > ad->size)
|
||||||
{
|
{
|
||||||
// resize array
|
// resize array
|
||||||
|
@ -1453,7 +1477,7 @@ void __declspec(dllexport) Script(HWND hwndParent, int string_size,
|
||||||
popstring(buffer);
|
popstring(buffer);
|
||||||
|
|
||||||
// parse it
|
// parse it
|
||||||
ParseString(buf, root, 0);
|
ParseString(buf, root);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// dump
|
// dump
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
#define ITC_FLOAT 0x000200
|
#define ITC_FLOAT 0x000200
|
||||||
#define ITC_INT 0x000400
|
#define ITC_INT 0x000400
|
||||||
#define ITC_ARRAY 0x000800
|
#define ITC_ARRAY 0x000800
|
||||||
#define ITC_VARPTR 0x001000
|
#define ITC_UNKNOWN 0x001000
|
||||||
#define ITC_UNKNOWN 0x002000
|
|
||||||
|
|
||||||
// type function
|
// type function
|
||||||
#define FTT_FLOATF (ITC_UNKNOWN << 0)
|
#define FTT_FLOATF (ITC_UNKNOWN << 0)
|
||||||
|
@ -72,34 +71,37 @@
|
||||||
#define ITF_USER 0x000400
|
#define ITF_USER 0x000400
|
||||||
|
|
||||||
// array items sub-types
|
// array items sub-types
|
||||||
#define ITA_DEFINE 0x000100
|
#define ITA_ACCESS 0x000000
|
||||||
#define ITA_ACCESS 0x000200
|
|
||||||
|
|
||||||
#define ITEMOPTIONS 0x0000FF
|
#define ITEMOPTIONS 0x0000FF
|
||||||
|
|
||||||
// 16 bytes structure
|
// 16 bytes structure
|
||||||
typedef struct __ExpressionItem ExpressionItem;
|
typedef struct __ExpressionItem ExpressionItem;
|
||||||
|
//#define EIPARAM int
|
||||||
|
#define EIPARAM ExpressionItem*
|
||||||
typedef struct __ExpressionItem
|
typedef struct __ExpressionItem
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
int param1;
|
EIPARAM param1;
|
||||||
int param2;
|
EIPARAM param2;
|
||||||
ExpressionItem *next;
|
ExpressionItem *next;
|
||||||
} ExpressionItem;
|
} ExpressionItem;
|
||||||
|
|
||||||
typedef struct __ParseInfo
|
typedef struct __ParseInfo
|
||||||
{
|
{
|
||||||
int SetupNewRoot;
|
int SetupNewRoot;
|
||||||
ExpressionItem *item;
|
ExpressionItem *item;
|
||||||
ExpressionItem *OpsStack;
|
ExpressionItem *OpsStack;
|
||||||
ExpressionItem* &place;
|
ExpressionItem *&place;
|
||||||
ExpressionItem **root;
|
ExpressionItem **root;
|
||||||
char valbuf[108];
|
char valbuf[108];
|
||||||
} ParseInfo;
|
} ParseInfo;
|
||||||
|
|
||||||
|
#define OPERATOR_SET_PRECEDENCE 14
|
||||||
typedef struct __OpStruct
|
typedef struct __OpStruct
|
||||||
{
|
{
|
||||||
char name[4];
|
char name[3];
|
||||||
|
unsigned char precedence;
|
||||||
unsigned short int type;
|
unsigned short int type;
|
||||||
} OpStruct;
|
} OpStruct;
|
||||||
|
|
||||||
|
@ -149,9 +151,6 @@ typedef struct __MathFunction
|
||||||
#define FF_EXP 0x20 // uses exp mode (small e)
|
#define FF_EXP 0x20 // uses exp mode (small e)
|
||||||
#define FF_LEXP 0x40 // uses exp mode (large E)
|
#define FF_LEXP 0x40 // uses exp mode (large E)
|
||||||
|
|
||||||
// parsestring options
|
|
||||||
#define PSO_STOPATDELIMETER 0x1
|
|
||||||
|
|
||||||
// RunTree options
|
// RunTree options
|
||||||
#define RTO_NEEDCONST 0x0001
|
#define RTO_NEEDCONST 0x0001
|
||||||
#define RTO_PREFFEREDTYPE 0xFF00
|
#define RTO_PREFFEREDTYPE 0xFF00
|
||||||
|
|
|
@ -92,7 +92,7 @@ ExpressionItem *AllocArray(int s)
|
||||||
|
|
||||||
ExpressionItem *ai = (ExpressionItem*)dbgGlobalAlloc(GPTR,sizeof(ExpressionItem));
|
ExpressionItem *ai = (ExpressionItem*)dbgGlobalAlloc(GPTR,sizeof(ExpressionItem));
|
||||||
ai->type = IT_CONST | ITC_ARRAY;
|
ai->type = IT_CONST | ITC_ARRAY;
|
||||||
ai->param1 = (int) dbgGlobalAlloc(GPTR, sizeof(ArrayDesc));
|
ai->param1 = (EIPARAM) dbgGlobalAlloc(GPTR, sizeof(ArrayDesc));
|
||||||
|
|
||||||
ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
|
ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
|
||||||
// initialize and clear the array memory
|
// initialize and clear the array memory
|
||||||
|
@ -118,7 +118,7 @@ ExpressionItem *CopyItem(ExpressionItem *citem, int NeedConst)
|
||||||
item->type = citem->type;
|
item->type = citem->type;
|
||||||
if ((item->type & (ITEMTYPE | ITEMSUBTYPE)) == (IT_CONST | ITC_STRING))
|
if ((item->type & (ITEMTYPE | ITEMSUBTYPE)) == (IT_CONST | ITC_STRING))
|
||||||
{
|
{
|
||||||
item->param1 = (int) AllocString();
|
item->param1 = (EIPARAM) AllocString();
|
||||||
lstrcpy((LPSTR) item->param1, (LPSTR) citem->param1);
|
lstrcpy((LPSTR) item->param1, (LPSTR) citem->param1);
|
||||||
} else if (((item->type & (ITEMTYPE | ITEMSUBTYPE)) == (IT_CONST | ITC_ARRAY))
|
} else if (((item->type & (ITEMTYPE | ITEMSUBTYPE)) == (IT_CONST | ITC_ARRAY))
|
||||||
||
|
||
|
||||||
|
|
|
@ -18,7 +18,7 @@ Left=0
|
||||||
Right=-1
|
Right=-1
|
||||||
Top=9
|
Top=9
|
||||||
Bottom=55
|
Bottom=55
|
||||||
flags=MULTILINE|WANTRETURN|HSCROLL|VSCROLL
|
flags=MULTILINE|WANTRETURN|HSCROLL
|
||||||
State=""
|
State=""
|
||||||
|
|
||||||
[Field 3]
|
[Field 3]
|
||||||
|
|
|
@ -90,7 +90,7 @@ FunctionEnd
|
||||||
|
|
||||||
Function GetLine
|
Function GetLine
|
||||||
push $TEMP1
|
push $TEMP1
|
||||||
Math::Script /NOUNLOAD "DL()"
|
Math::Script /NOUNLOAD "mtsDL()"
|
||||||
pop $TEMP2
|
pop $TEMP2
|
||||||
pop $TEMP1
|
pop $TEMP1
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
@ -98,13 +98,13 @@ FunctionEnd
|
||||||
Function ExecuteScript
|
Function ExecuteScript
|
||||||
!insertmacro MUI_INSTALLOPTIONS_READ $TEMP1 "MathTest.ini" "Field 2" "State"
|
!insertmacro MUI_INSTALLOPTIONS_READ $TEMP1 "MathTest.ini" "Field 2" "State"
|
||||||
|
|
||||||
Math::Script /NOUNLOAD "TQ(s) (s = s(NS); #[s[0]=='$\"',s=s[1,]]; #[s[-1]=='$\"',s=s[,-2]]; NS = s)"
|
Math::Script /NOUNLOAD "mtsTQ(s) (s = s(NS); #[s[0]=='$\"',s=s[1,]]; #[s[-1]=='$\"',s=s[,-2]]; NS = s)"
|
||||||
Math::Script /NOUNLOAD "P(s,e, p,i) (p=-1;i=0; #{(i<l(s))&&(p<0), #[s[i,i+l(e)-1]==e, p=i]; i++}; p)"
|
Math::Script /NOUNLOAD "mtsP(s,e, p,i) (p=-1;i=0; #{(i<l(s))&&(p<0), #[s[i,i+l(e)-1]==e, p=i]; i++}; p)"
|
||||||
Math::Script /NOUNLOAD "DL(s) (s=s(NS); p=P(s,'\r\n'); #[p>=0, (NS=s[p+4,]; NS=#[p>0,s[,p-1],'']), (NS='';NS=s)])"
|
Math::Script /NOUNLOAD "mtsDL(s) (s=s(NS); p=mtsP(s,'\r\n'); #[p>=0, (NS=s[p+4,]; NS=#[p>0,s[,p-1],'']), (NS='';NS=s)])"
|
||||||
|
|
||||||
push $TEMP1
|
push $TEMP1
|
||||||
; remove ""
|
; remove ""
|
||||||
Math::Script /NOUNLOAD "TQ()"
|
Math::Script /NOUNLOAD "mtsTQ()"
|
||||||
pop $TEMP1
|
pop $TEMP1
|
||||||
|
|
||||||
; script at $TEMP1
|
; script at $TEMP1
|
||||||
|
|
BIN
Plugins/Math.dll
BIN
Plugins/Math.dll
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue