#define MAX_VALUES 32
#define IOBUFFERS 256
-static double parsedvalues[MAX_VALUES];
+static double parsedvaluesd[MAX_VALUES];
+static TCHAR *parsedvaluess[MAX_VALUES];
// operators
// precedence operators associativity
return 3;
case '+': case '-':
return 2;
- case '=': case '@': case '>': case '<':
+ case '=': case '@': case '@' | 0x80: case '>': case '<': case '>' | 0x80: case '<' | 0x80:
return 1;
+ case ':':
+ return -1;
+ case '?':
+ return -2;
}
return 0;
}
case '|': case '&': case '^':
return true;
// right to left
- case '=': case '!': case '@': case '>': case '<':
+ case '=': case '!': case '@': case '@' | 0x80: case '>': case '<': case '>' | 0x80: case '<' | 0x80:
return false;
}
return false;
static unsigned int op_arg_count(const TCHAR c)
{
switch(c) {
- case '*': case '/': case '%': case '+': case '-': case '=': case '@': case '<': case '>':
- case '|': case '&': case '^':
+ case '?':
+ return 3;
+ case '*': case '/': case '%': case '+': case '-': case '=': case '@': case '@' | 0x80: case '<': case '>':
+ case '|': case '&': case '^': case '<' | 0x80: case '>' | 0x80:
return 2;
case '!':
+ case ':':
return 1;
default:
return c - 'A';
return 0;
}
-#define is_operator(c) (c == '+' || c == '-' || c == '/' || c == '*' || c == '!' || c == '%' || c == '=' || c == '|' || c == '&' || c == '^' || c == '@' || c == '>' || c == '<')
+#define is_operator(c) (c == '+' || c == '-' || c == '/' || c == '*' || c == '!' || c == '%' || c == '=' || \
+ c == '|' || c == '&' || c == '^' || c == '@' || c == ('@' | 0x80) || c == '>' || c == '<' || c == ('>' | 0x80) || c == ('<' | 0x80) || \
+ c == '?' || c == ':')
#define is_function(c) (c >= 'A' && c <= 'Z')
#define is_ident(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))
{
TCHAR *s;
double val;
+ TCHAR *vals;
};
-static double docalcx(TCHAR op, double v1, double v2)
+static double stacktoval(struct calcstack *st)
+{
+ if (st->s) {
+ if (_tcslen(st->s) == 1 && st->s[0] >= 'a' && st->s[0] <= 'z')
+ return parsedvaluesd[st->s[0] - 'a'];
+ return _tstof(st->s);
+ } else {
+ return st->val;
+ }
+}
+
+static bool isstackstring(struct calcstack *st)
+{
+ if (st->vals && st->vals[0]) {
+ return true;
+ }
+ if (st->s) {
+ if (_tcslen(st->s) == 1 && st->s[0] >= 'a' && st->s[0] <= 'z') {
+ TCHAR *s = parsedvaluess[st->s[0] - 'a'];
+ if (s) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static TCHAR *stacktostring(struct calcstack *st)
+{
+ if (st->s) {
+ if (_tcslen(st->s) == 1 && st->s[0] >= 'a' && st->s[0] <= 'z') {
+ TCHAR *s = parsedvaluess[st->s[0] - 'a'];
+ if (s) {
+ st->vals = my_strdup(s);
+ xfree(st->s);
+ st->s = NULL;
+ return st->vals;
+ }
+ double v = parsedvaluesd[st->s[0] - 'a'];
+ TCHAR tmp[256];
+ _stprintf(tmp, _T("%d"), (int)v);
+ st->vals = my_strdup(tmp);
+ xfree(st->s);
+ st->s = NULL;
+ return st->vals;
+ }
+ }
+ if (!st->vals || !st->vals[0]) {
+ TCHAR tmp[256];
+ _stprintf(tmp, _T("%d"), (int)st->val);
+ xfree(st->vals);
+ st->vals = my_strdup(tmp);
+ }
+ return st->vals;
+}
+
+
+static TCHAR *docalcxs(TCHAR op, TCHAR *v1, TCHAR *v2, double *voutp)
{
+ TCHAR tmp[MAX_DPATH];
+ tmp[0] = 0;
+
+ switch(op)
+ {
+ case '+':
+ _tcscpy(tmp, v1);
+ _tcscat(tmp, v2);
+ break;
+ case '@':
+ if (!_tcsicmp(v1, v2)) {
+ *voutp = 1;
+ return my_strdup(_T(""));
+ } else {
+ *voutp = 0;
+ return my_strdup(_T(""));
+ }
+ break;
+ case '@' | 0x80:
+ if (!_tcsicmp(v1, v2)) {
+ *voutp = 0;
+ return my_strdup(_T(""));
+ } else {
+ *voutp = 1;
+ return my_strdup(_T(""));
+ }
+ break;
+ case ':':
+ _tcscpy(tmp, v1);
+ break;
+ default:
+ return NULL;
+ }
+ return my_strdup(tmp);
+}
+
+static bool docalcx(TCHAR op, double v1, double v2, double *valp)
+{
+ double v = 0;
switch (op)
{
case '-':
- return v1 - v2;
+ v = v1 - v2;
+ break;
case '+':
- return v1 + v2;
- case '*':
- return v1 * v2;
- case '/':
- return v1 / v2;
- case '\\':
- return (int)v1 % (int)v2;
+ v = v1 + v2;
+ break;
+ case '*':
+ v = v1 * v2;
+ break;
+ case '/':
+ v = v1 / v2;
+ break;
+ case '\\':
+ v = (int)v1 % (int)v2;
+ break;
case '|':
- return (int)v1 | (int)v2;
+ v = (int)v1 | (int)v2;
+ break;
case '&':
- return (int)v1 & (int)v2;
+ v = (int)v1 & (int)v2;
+ break;
case '^':
- return (int)v1 ^ (int)v2;
+ v = (int)v1 ^ (int)v2;
+ break;
case '@':
- return (int)v1 == (int)v2;
+ v = (int)v1 == (int)v2;
+ break;
+ case '@' | 0x80:
+ v = (int)v1 != (int)v2;
+ break;
case '>':
- return (int)v1 > (int)v2;
+ v = (int)v1 > (int)v2;
+ break;
case '<':
- return (int)v1 < (int)v2;
- }
- return 0;
-}
-
-static double stacktoval(struct calcstack *st)
-{
- if (st->s) {
- if (_tcslen(st->s) == 1 && st->s[0] >= 'a' && st->s[0] <= 'z')
- return parsedvalues[st->s[0] - 'a'];
- return _tstof (st->s);
- } else {
- return st->val;
- }
+ v = (int)v1 < (int)v2;
+ break;
+ case '<' | 0x80:
+ if ((uae_u32)v2 < 32) {
+ v = (uae_u32)v1 << (uae_u32)v2;
+ }
+ break;
+ case '>' | 0x80:
+ if ((uae_u32)v2 < 32) {
+ v = (uae_u32)v1 >> (uae_u32)v2;
+ }
+ break;
+ case ':':
+ v = v1;
+ break;
+ default:
+ return false;
+ }
+ *valp = v;
+ return true;
}
-static double docalc2(TCHAR op, struct calcstack *sv1, struct calcstack *sv2)
+static bool docalc2(TCHAR op, struct calcstack *sv1, struct calcstack *sv2, double *valp, TCHAR *sp)
{
- double v1, v2;
-
- v1 = stacktoval(sv1);
- v2 = stacktoval(sv2);
- return docalcx (op, v1, v2);
+ *sp = NULL;
+ *valp = 0;
+ if (isstackstring(sv1) || isstackstring(sv2)) {
+ TCHAR *v1 = stacktostring(sv1);
+ TCHAR *v2 = stacktostring(sv2);
+ double vout = 0;
+ TCHAR *s = docalcxs(op, v1, v2, &vout);
+ if (!s) {
+ return false;
+ }
+ _tcscpy(sp, s);
+ xfree(s);
+ if (vout) {
+ *valp = vout;
+ }
+ return true;
+ } else {
+ double v1 = stacktoval(sv1);
+ double v2 = stacktoval(sv2);
+ return docalcx(op, v1, v2, valp);
+ }
}
-static double docalc1(TCHAR op, struct calcstack *sv1, double v2)
+static bool docalc1(TCHAR op, struct calcstack *sv1, double v2, double *valp, TCHAR *sp)
{
- double v1;
-
- v1 = stacktoval(sv1);
- return docalcx (op, v1, v2);
+ if (isstackstring(sv1)) {
+ TCHAR *v1 = stacktostring(sv1);
+ double vout;
+ TCHAR *s = docalcxs(op, v1, _T(""), &vout);
+ if (!s) {
+ return false;
+ }
+ _tcscpy(sp, s);
+ xfree(s);
+ return true;
+ } else {
+ double v1 = stacktoval(sv1);
+ return docalcx(op, v1, v2, valp);
+ }
}
#if CALC_DEBUG
return s;
}
-static bool execution_order(const TCHAR *input, double *outval)
+static struct calcstack stack[STACK_SIZE] = { 0 };
+
+static bool execution_order(const TCHAR *input, double *outval, TCHAR *outstring, int maxlen)
{
const TCHAR *strpos = input, *strend = input + _tcslen(input);
TCHAR c, res[4];
unsigned int sl = 0, rn = 0;
- struct calcstack stack[STACK_SIZE] = { { 0 } }, *sc, *sc2;
+ struct calcstack *sc, *sc2;
double val = 0;
- int i;
+ TCHAR vals[MAX_DPATH];
+ int i;
bool ok = false;
+ vals[0] = 0;
// While there are input tokens left
while(strpos < strend) {
if(nargs == 1) {
sc = &stack[sl - 1];
sl--;
- val = docalc1 (c, sc, val);
+ docalc1 (c, sc, val, &val, vals);
calc_log ((_T("%c %s = %f;\n"), c, stacktostr(sc), val));
}
- else {
+ else if (nargs == 2) {
sc = &stack[sl - 2];
calc_log ((_T("%s %c "), stacktostr(sc), c));
sc2 = &stack[sl - 1];
- val = docalc2 (c, sc, sc2);
- sl--;sl--;
+ docalc2 (c, sc, sc2, &val, vals);
+ sl--;sl--;
calc_log ((_T("%s = %f;\n"), stacktostr(sc2), val));
+ } else if (nargs == 3) {
+ // ternary
+ sc = &stack[sl - 3];
+ if (sc->val != 0) {
+ sc2 = &stack[sl - 2];
+ } else {
+ sc2 = &stack[sl - 1];
+ }
+ sl--;sl--;sl--;
+ if (isstackstring(sc2)) {
+ TCHAR *c = stacktostring(sc2);
+ _tcscpy(vals, c);
+ xfree(c);
+ }
+ val = stacktoval(sc2);
}
}
// Push the returned results, if any, back onto the stack.
stack[sl].val = val;
+ xfree(stack[sl].vals);
+ stack[sl].vals = my_strdup(vals);
stack[sl].s = NULL;
++sl;
}
calc_log ((_T("result = %f\n"), val));
if (outval)
*outval = val;
+ if (outstring) {
+ if (vals && _tcslen(vals) >= maxlen) {
+ vals[maxlen] = 0;
+ }
+ _tcscpy(outstring, vals ? vals : _T(""));
+ }
ok = true;
}
for (i = 0; i < STACK_SIZE; i++)
in[2] = ' ';
in[3] = ' ';
in[4] = ' ';
- }
+ } else if (in[0] == '>' && in[1] == '>') {
+ in[0] = '>' | 0x80;
+ in[1] = ' ';
+ } else if (in[0] == '<' && in[1] == '<') {
+ in[0] = '<' | 0x80;
+ in[1] = ' ';
+ } else if (in[0] == '"' || in[0] == '\'') {
+ TCHAR *quoted = in;
+ TCHAR quotec = *in;
+ *in++ = 0;
+ if (ident >= MAX_VALUES)
+ return false;
+ *p++ = ident + 'a';
+ while (*in != 0 && *in != quotec) {
+ in++;
+ }
+ if (*in != quotec) {
+ return false;
+ }
+ *in = 0;
+ parsedvaluess[ident++] = my_strdup(quoted + 1);
+ while (quoted <= in) {
+ *quoted++ = ' ';
+ }
+ continue;
+ }
if (*in == '=' && *(in + 1) == '=') {
*in = '@';
*(in + 1) = ' ';
}
- if (_istdigit (*in)) {
+ if (*in == '!' && *(in + 1) == '=') {
+ *in = '@' | 0x80;
+ *(in + 1) = ' ';
+ }
+ if (_istdigit (*in)) {
if (ident >= MAX_VALUES)
return false;
if (op > 1 && (in[-1] == '-' || in[-1] == '+')) {
in++;
tmp = *in;
*in = 0;
- parsedvalues[ident++] = _tstof (instart);
+ parsedvaluesd[ident++] = _tstof (instart);
*in = tmp;
op = 0;
} else {
return true;
}
-bool calc(const TCHAR *input, double *outval)
+int calc(const TCHAR *input, double *outval, TCHAR *outstring, int maxlen)
{
TCHAR output[IOBUFFERS], output2[IOBUFFERS];
+ int ret = -1;
calc_log ((_T("IN: '%s'\n"), input));
+ if (outval) {
+ *outval = 0;
+ }
+ if (outstring) {
+ outstring[0] = 0;
+ }
if (parse_values(input, output2)) {
if(shunting_yard(output2, output)) {
calc_log ((_T("RPN OUT: %s\n"), output));
- if(!execution_order(output, outval)) {
+ if(!execution_order(output, outval, outstring, maxlen)) {
calc_log ((_T("PARSE ERROR!\n")));
} else {
- return true;
+ if (outstring && outstring[0]) {
+ ret = -1;
+ } else {
+ ret = 1;
+ }
}
}
}
- return false;
+ for (int i = 0; i < MAX_VALUES; i++) {
+ xfree(parsedvaluess[i]);
+ parsedvaluesd[i] = 0;
+ parsedvaluess[i] = NULL;
+ }
+ for (int i = 0; i < STACK_SIZE; i++) {
+ struct calcstack *s = &stack[i];
+ xfree(s->vals);
+ xfree(s->s);
+ memset(s, 0, sizeof(struct calcstack));
+ }
+ return ret;
}
bool iscalcformula (const TCHAR *formula)