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:
kichik 2003-09-22 22:56:52 +00:00
parent f82158960d
commit b2574f6b3b
7 changed files with 221 additions and 189 deletions

View file

@ -1,7 +1,5 @@
Math::Script NSIS plugin.
Another huge, undocumented, bug-full, but "might be useful" plugin.
C-like style scripting (operators at least).
Tip1: plugin watches the case of the letters.
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)
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 ';'.
Processing is not mathematicaly right (2+2*2 will give 8, not 6), so use round
brakes (for ex: 2+(2*2) ).
Processing is mathematicaly right (2+2*2 will give 6), operations are performed
in a C like order (precedence).
Flow control:
if-then-else like: #[if-expression, then-expr, else-expr]
@ -159,9 +161,8 @@ Functions:
User-defined functions.
It's very simple. Example:
test(a,b)a+b;
After that test(1,2) will give you 3. If you need more than one expression, use
round brakes:
test(a,b) (a+b);
After that test(1,2) will give you 3.
test2(a,b) (a=a+b; b *= a);
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.
@ -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
declare as additional arguments, which will never be used. Example:
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
saved.
No matter how many arguments will be passed to function, the values of all three
vars (a,b,c) will be saved.
Such variable-safe functions could be recursive:
Math::Script /NOUNLOAD 'rec(a) (#[a > 0, rec(a-1), 0]+a);'
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
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
register R0, any of the user variables (beside the variable with the same name:)
, but never the constant.
register R0, any of the user variables (beside the variable with the same name:),
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)

View file

@ -12,42 +12,40 @@ UserVar UserVars[MAX_USER_VARS];
UserFunc UserFuncs[MAX_USER_FUNCS];
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 PlaceVariable(char *&vb, ParseInfo *pi);
void PlaceNewItem(ParseInfo *pi)
void PlaceNewItem(char *&vb, ParseInfo *pi, int precedence)
{
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
*((ExpressionItem **)&(pi->OpsStack->param2)) = pi->item;
// second operand for our operator
newroot = pi->OpsStack;
*((ExpressionItem **)&(newroot->param2)) = pi->item;
pi->OpsStack = newroot->next;
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;
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
@ -99,7 +97,6 @@ void PlaceVariable(char *&vb, ParseInfo *pi)
if (vb <= pi->valbuf) return;
*vb = 0;
pi->item = FindVariable(pi->valbuf);
PlaceNewItem(pi);
vb = pi->valbuf;
}
@ -141,12 +138,12 @@ const MathFunction MathFunctions[MATHFUNCNUM] = {
{{'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();
*vb = 0;
// check BUILTIN variables
// check BUILTIN functions
for (int i = 0; i < MATHFUNCNUM; i++)
{
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;
// get first argument
sp++;
ParseString(sp, *((ExpressionItem **)(&item->param1)), 0);
ParseString(sp, *((ExpressionItem **)(&item->param1)));
if (*sp == ',')
{
// get second argument
sp++;
ParseString(sp, *((ExpressionItem **)(&item->param2)), 0);
ParseString(sp, *((ExpressionItem **)(&item->param2)));
}
sp++; vb = pi->valbuf;
PlaceNewItem(pi);
sp++; vb = pi->valbuf;
return;
}
}
@ -172,6 +168,9 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
{
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));
@ -180,22 +179,27 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
*newplace = AllocItem();
(*newplace)->type = IT_EXPRESSION;
sp++;
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)), 0);
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
newplace = &((*newplace)->next);
}
sp++; vb = pi->valbuf;
PlaceNewItem(pi);
sp++; vb = pi->valbuf;
return;
}
}
// oops, we need no item for function defenition
CleanupItems(item);
CleanupItems(item); pi->item = NULL;
// it's user function define
int flags = 0;
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);
f->varflags = 0;
f->varsnum = 0;
@ -237,9 +241,13 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
f->varflags |= flags&1;
}
sp++;
// find nearest round bracket - function body
while (*sp != '(') sp++;
sp++;
// now we are ready to parse function body
ParseString(sp, f->root, PSO_STOPATDELIMETER);
ParseString(sp, f->root);
sp++; // closing bracket
vb = pi->valbuf;
#ifdef _DEBUG
@ -259,9 +267,6 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
#endif
}
// parsestring options
#define PSO_STOPATDELIMETER 0x1
// 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)
@ -272,32 +277,40 @@ void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi)
#define PO_USESPRE 0x40 // operator will use pre operand
#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
pi->item = AllocItem();
pi->item->type = type;
pi->item->next = pi->OpsStack;
pi->OpsStack = pi->item;
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
PlaceVariable(vb, pi);
pi->item = AllocItem();
pi->item->type = type;
pi->item->param1 = (int) (*pi->root);
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
PlaceNewItem(pi);
pi->item = item;
} else
{
// binary operator
pi->item->next = pi->OpsStack;
pi->OpsStack = pi->item;
item->param2 = (EIPARAM) precedence;
item->next = pi->OpsStack;
pi->OpsStack = item;
}
}
}
@ -306,80 +319,76 @@ void PlaceOp(char *&vb, int type, ParseInfo *pi)
const OpStruct Operators[OPSNUM] =
{
// three byte ops
{">>=", 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_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
{"-=", ITO_MINUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"+=", ITO_PLUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"/=", ITO_DIV | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"*=", ITO_MUL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"|=", ITO_OR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"&=", ITO_AND | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"^=", ITO_XOR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"%=", ITO_MOD | 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},
{"++", ITO_INC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
{">>", ITO_SHR | PO_USESPRE | PO_USESPOST},
{"<<", ITO_SHL | PO_USESPRE | PO_USESPOST},
// !!! 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
{"&&", ITO_LAND | PO_USESPRE | PO_USESPOST},
{"||", ITO_LOR | PO_USESPRE | PO_USESPOST},
{"&&", 12, ITO_LAND | PO_USESPRE | PO_USESPOST},
{"||", 13, ITO_LOR | PO_USESPRE | PO_USESPOST},
// comparisons
{"<=", ITO_LE | PO_USESPRE | PO_USESPOST},
{"=<", ITO_LE | PO_USESPRE | PO_USESPOST},
{">=", ITO_GE | PO_USESPRE | PO_USESPOST},
{"=>", ITO_GE | PO_USESPRE | PO_USESPOST},
{"!=", ITO_NE | PO_USESPRE | PO_USESPOST},
{"==", ITO_EQ | PO_USESPRE | PO_USESPOST},
{"<=", 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
{"=", ITO_SET | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPOST},
{"+", ITO_PLUS | PO_USESPRE | PO_USESPOST},
{"-", ITO_MINUS | PO_USESPRE | PO_USESPOST},
{"*", ITO_MUL | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"/", ITO_DIV | PO_USESPRE | PO_USESPOST},
{"%", ITO_MOD | PO_USESPRE | PO_USESPOST},
{"<", ITO_LS | PO_USESPRE | PO_USESPOST},
{">", ITO_GR | PO_USESPRE | PO_USESPOST},
{"&", ITO_AND | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"|", ITO_OR | PO_USESPRE | PO_USESPOST},
{"^", ITO_XOR | PO_USESPRE | PO_USESPOST},
{"~", ITO_NOT | PO_USESPOST | PO_UNARYPRE},
{"!", ITO_LNOT |PO_USESPOST | PO_UNARYPRE}
// !!! 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 = 0;
while ((Operators[op].name[c]) && (*(sp+c) == Operators[op].name[c])) c++;
if (Operators[op].name[c])
{
int c = lstrlen(Operators[op].name);
if (c > 3) c = 3; // real operator length
if (lstrcmpn(sp, Operators[op].name, c))
{
// wrong - different op
continue;
}
// that is our op
sp += c;
PlaceOp(vb, ((int) Operators[op].type) | IT_OPERATOR, 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);
}
PlaceOp(vb, ((int) Operators[op].type) | IT_OPERATOR, Operators[op].precedence, pi);
break;
}
}
void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
void ParseString(char *&sp, ExpressionItem* &itemplace)
{
ParseInfo pi = {0, NULL, NULL, itemplace, &itemplace};
int redefine = 0;
char *vb = pi.valbuf;
// cycle until current expression end
while ((*sp != 0) && (*sp != ')') && (*sp != '}') &&
@ -394,10 +403,8 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
break;
case ';':
// expression delimeter
PlaceVariable(vb, &pi);
pi.SetupNewRoot = 1;
// check stop at delimeter option
if (options & PSO_STOPATDELIMETER) return;
PlaceNewItem(vb, &pi, 255);
if (*pi.root) pi.SetupNewRoot = 1;
sp++;
break;
case '0': case '1': case '2': case '3': case '4':
@ -412,26 +419,31 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
// constant meet
pi.item = AllocItem();
StringToItem(sp, pi.item, STI_STRING | STI_FLOAT | STI_INT);
PlaceNewItem(&pi);
break;
case '(': // start of function or expression
if (vb > pi.valbuf)
{
// thats function
PlaceFunction(vb, sp, &pi);
PlaceFunction(vb, sp, &pi, redefine);
} else
{
// expression
sp++;
ParseString(sp, pi.item, 0);
PlaceNewItem(&pi);
ParseString(sp, pi.item);
if (*sp == ')') sp++;
}
redefine = 0;
break;
case '#': // start of one of logical expresions
sp++;
sp++;
if ((*sp != '[') && (*sp != '{'))
{
// function redefine flag
redefine = 1;
break;
}
{
pi.item = AllocItem();
// IF or WHILE
@ -439,7 +451,7 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
// first expr - logic statement
sp++;
ParseString(sp, *((ExpressionItem **)(&pi.item->param1)), 0);
ParseString(sp, *((ExpressionItem **)(&pi.item->param1)));
// ok, second expr - then, third - else statement.. others???
ExpressionItem **newplace = ((ExpressionItem **)(&pi.item->param2));
while (*sp == ',')
@ -447,35 +459,34 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
*newplace = AllocItem();
(*newplace)->type = IT_EXPRESSION;
sp++;
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)), 0);
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
newplace = &((*newplace)->next);
}
}
PlaceNewItem(&pi);
sp++;
break;
case '[':
{
// thats array access
PlaceOp(vb, IT_ARRAY | ITA_ACCESS, &pi);
PlaceOp(vb, IT_ARRAY | ITA_ACCESS | PO_UNARYPOST, 1, &pi);
sp++;
// item index
pi.item = NULL;
ParseString(sp, pi.item, 0);
ParseString(sp, *(ExpressionItem **)&(pi.item->param2));
if (*sp == ',')
{
// two indexes - string access
ExpressionItem *it = AllocItem();
it->type = IT_EXPRESSION;
it->param1 = (int) pi.item;
pi.item = it;
it->param1 = (EIPARAM) *(ExpressionItem **)&(pi.item->param2);
*(ExpressionItem **)&(pi.item->param2) = it;
it = it->next = AllocItem();
it->type = IT_EXPRESSION;
sp++;
ParseString(sp, *((ExpressionItem **)(&it->param1)), 0);
ParseString(sp, *((ExpressionItem **)(&it->param1)));
}
PlaceNewItem(&pi);
sp++;
}
break;
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
ExpressionItem *ai = AllocArray(DEFAULT_ARRAY_SIZE);
pi.item->param1 = (int) ai;
pi.item->param1 = (EIPARAM) ai;
ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
// parse array initializers
while (*sp != '}')
{
sp++;
ParseString(sp, ad->array[ad->count++], 0);
ParseString(sp, ad->array[ad->count++]);
}
PlaceNewItem(&pi);
sp++;
}
break;
case '-': case '+': case '<': case '=': case '>':
case '/': case '*': case '~': case '^': case '!':
case '&': case '|': case '%':
PlaceVariable(vb, &pi);
CheckForOperator(sp, vb, &pi);
break;
@ -516,7 +525,7 @@ void ParseString(char *&sp, ExpressionItem* &itemplace, int options)
}
if (!processed) *(vb++) = *(sp++);
}
PlaceVariable(vb, &pi);
PlaceNewItem(vb, &pi, 255);
}
void CleanupArray(ArrayDesc *ad)
@ -764,7 +773,7 @@ void ItemToType(ExpressionItem* &item, int type)
case ITC_STRING:
buffer = AllocString();
ItemToString(buffer, item);
item->param1 = (int) buffer;
item->param1 = (EIPARAM) buffer;
item->param2 = 0;
break;
case ITC_FLOAT:
@ -831,7 +840,7 @@ void SaveResult(ExpressionItem *var, ExpressionItem *result)
break;
case ITV_ARRITEM:
{
ExpressionItem *&ei = ((ArrayDesc*)(var->param1))->array[var->param2];
ExpressionItem *&ei = ((ArrayDesc*)(var->param1))->array[(int)var->param2];
CleanupItems(ei);
ei = CopyItem(result);
}
@ -904,7 +913,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
case ITV_ARRITEM:
{
// array item
ExpressionItem *ei = ((ArrayDesc*)(item->param1))->array[item->param2];
ExpressionItem *ei = ((ArrayDesc*)(item->param1))->array[(int)item->param2];
if (ei)
result = CopyItem(ei);
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))
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
result = item2;
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
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
ItemToType(item1, type);
ItemToType(item2, type);
__int64 i1, i2, i3, i4;
switch (type)
{
case ITC_INT:
{
i1 = (item1)?(*((__int64*)&item1->param1)):(0);
i2 = (item2)?(*((__int64*)&item2->param1)):(0);
switch (subtype)
{
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;
}
} // check for both items constant
// the other case - usually UniaryPre operators working with non constants
else result = CopyItem(item2);
if (ioptions & PO_SET)
{
// Save our result in output variable
@ -1171,7 +1195,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
// push every variable
ExpressionItem *val;
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);
CleanupItems(val);
// 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);
} 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;
} else vals[i] = AllocItem();
@ -1201,7 +1225,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
// 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
for (int i = f->varsnum-1; i >= 0; i--)
@ -1209,7 +1233,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
// pop every variable
ExpressionItem *val;
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);
CleanupItems(val);
}
@ -1222,21 +1246,21 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
if (newtype < ITC_UNKNOWN)
{
// get as possibly close to ready expression
RunAndGetConst(item->param1, result, newtype);
RunAndGetConst((int)item->param1, result, newtype);
if (ioptions == ITFT_CARRAY_ID)
CopyArray(result);
} else if (newtype == FTT_FLOATF)
{
// float format function
ExpressionItem *arg1, *arg2;
RunAndGetConst(item->param1, arg1, ITC_FLOAT);
RunAndGetConst((int)item->param1, arg1, ITC_FLOAT);
double value = *((double*)&(arg1->param1));
RunAndGetConst(item->param2, arg2, ITC_INT);
RunAndGetConst((int)item->param2, arg2, ITC_INT);
int format = (int) *((__int64*)&(arg2->param1));
result = AllocItem();
result->type = IT_CONST | ITC_STRING;
result->param1 = (int) AllocString();
result->param1 = (EIPARAM) AllocString();
FloatFormat((char*) result->param1, value, format);
CleanupItems(arg1); CleanupItems(arg2);
} 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)
int chr = (int) (*((__int64*)&(result->param1))) & 0xFF;
result->param1 = (int) AllocString();
result->param1 = (EIPARAM) AllocString();
*((char*)result->param1) = (char) chr;
*((char*)(result->param1+1)) = (char) 0;
result->type = IT_CONST | ITC_STRING;
@ -1289,7 +1313,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
} else
{
// oops :-o function call :)
RunAndGetConst(item->param1, result, ITC_FLOAT);
RunAndGetConst((int)item->param1, result, ITC_FLOAT);
double &value = *((double*)&(result->param1));
if (subtype == ITF_MATH1)
{
@ -1323,7 +1347,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
{
// normal 2-arg math function
ExpressionItem *arg2;
RunAndGetConst(item->param2, arg2, ITC_FLOAT);
RunAndGetConst((int)item->param2, arg2, ITC_FLOAT);
double value2 = *((double*)&(arg2->param1));
value = ((Math2FuncPtr)(MathFunctions[ioptions].fptr))(value, value2);
CleanupItems(arg2);
@ -1346,7 +1370,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
if ((*((ExpressionItem **) &(item->param2)))->type != IT_EXPRESSION)
{
// 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));
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)
index = AllocItem();
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 second index is skipped -> -1 (till last char)
@ -1374,7 +1398,7 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
*((__int64*)&(index2->param1)) = -1;
}
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
int pos1 = (int) *((__int64*)&(index->param1));
@ -1403,16 +1427,16 @@ void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
} else
{
// argument is array
RunAndGetConst(item->param2, index, ITC_INT);
RunAndGetConst((int)item->param2, index, ITC_INT);
// convert array pointer to array item pointer
aritem->type = IT_VARIABLE | ITV_ARRITEM;
aritem->param2 = (int) *((__int64*)&(index->param1));
aritem->param2 = (EIPARAM) *((__int64*)&(index->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)
{
// resize array
@ -1453,7 +1477,7 @@ void __declspec(dllexport) Script(HWND hwndParent, int string_size,
popstring(buffer);
// parse it
ParseString(buf, root, 0);
ParseString(buf, root);
#ifdef _DEBUG
// dump

View file

@ -18,8 +18,7 @@
#define ITC_FLOAT 0x000200
#define ITC_INT 0x000400
#define ITC_ARRAY 0x000800
#define ITC_VARPTR 0x001000
#define ITC_UNKNOWN 0x002000
#define ITC_UNKNOWN 0x001000
// type function
#define FTT_FLOATF (ITC_UNKNOWN << 0)
@ -72,34 +71,37 @@
#define ITF_USER 0x000400
// array items sub-types
#define ITA_DEFINE 0x000100
#define ITA_ACCESS 0x000200
#define ITA_ACCESS 0x000000
#define ITEMOPTIONS 0x0000FF
// 16 bytes structure
typedef struct __ExpressionItem ExpressionItem;
//#define EIPARAM int
#define EIPARAM ExpressionItem*
typedef struct __ExpressionItem
{
int type;
int param1;
int param2;
EIPARAM param1;
EIPARAM param2;
ExpressionItem *next;
} ExpressionItem;
typedef struct __ParseInfo
{
int SetupNewRoot;
ExpressionItem *item;
ExpressionItem *OpsStack;
ExpressionItem* &place;
ExpressionItem **root;
int SetupNewRoot;
ExpressionItem *item;
ExpressionItem *OpsStack;
ExpressionItem *&place;
ExpressionItem **root;
char valbuf[108];
} ParseInfo;
#define OPERATOR_SET_PRECEDENCE 14
typedef struct __OpStruct
{
char name[4];
char name[3];
unsigned char precedence;
unsigned short int type;
} OpStruct;
@ -149,9 +151,6 @@ typedef struct __MathFunction
#define FF_EXP 0x20 // uses exp mode (small e)
#define FF_LEXP 0x40 // uses exp mode (large E)
// parsestring options
#define PSO_STOPATDELIMETER 0x1
// RunTree options
#define RTO_NEEDCONST 0x0001
#define RTO_PREFFEREDTYPE 0xFF00

View file

@ -92,7 +92,7 @@ ExpressionItem *AllocArray(int s)
ExpressionItem *ai = (ExpressionItem*)dbgGlobalAlloc(GPTR,sizeof(ExpressionItem));
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));
// initialize and clear the array memory
@ -118,7 +118,7 @@ ExpressionItem *CopyItem(ExpressionItem *citem, int NeedConst)
item->type = citem->type;
if ((item->type & (ITEMTYPE | ITEMSUBTYPE)) == (IT_CONST | ITC_STRING))
{
item->param1 = (int) AllocString();
item->param1 = (EIPARAM) AllocString();
lstrcpy((LPSTR) item->param1, (LPSTR) citem->param1);
} else if (((item->type & (ITEMTYPE | ITEMSUBTYPE)) == (IT_CONST | ITC_ARRAY))
||

View file

@ -18,7 +18,7 @@ Left=0
Right=-1
Top=9
Bottom=55
flags=MULTILINE|WANTRETURN|HSCROLL|VSCROLL
flags=MULTILINE|WANTRETURN|HSCROLL
State=""
[Field 3]

View file

@ -90,7 +90,7 @@ FunctionEnd
Function GetLine
push $TEMP1
Math::Script /NOUNLOAD "DL()"
Math::Script /NOUNLOAD "mtsDL()"
pop $TEMP2
pop $TEMP1
FunctionEnd
@ -98,13 +98,13 @@ FunctionEnd
Function ExecuteScript
!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 "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 "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 "mtsTQ(s) (s = s(NS); #[s[0]=='$\"',s=s[1,]]; #[s[-1]=='$\"',s=s[,-2]]; NS = s)"
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 "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
; remove ""
Math::Script /NOUNLOAD "TQ()"
Math::Script /NOUNLOAD "mtsTQ()"
pop $TEMP1
; script at $TEMP1