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

View file

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

View file

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

View file

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

View file

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

View file

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

Binary file not shown.