fix problem with other operator after '?'

This commit is contained in:
2018-05-02 14:32:58 +02:00
parent 4e30b97c99
commit f4f01fc684
2 changed files with 74 additions and 59 deletions
+69 -57
View File
@@ -8,8 +8,8 @@
int exprDebug;
static int parseSubExpr(const char **pp, long *v, int pr, int op);
static long parseString(const char **pp, const char **pstart);
#define parseExpr(pp,v) parseSubExpr(pp, v, 0, 0)
#define skipSpace(p) while (isspace((unsigned char)*p)) p++
static int parseValue(const char **pp, long *v)
@@ -32,13 +32,14 @@ static int parseValue(const char **pp, long *v)
/* handle unary operators */
p++;
if (!parseValue(&p, &val)) return 0; /* no valid value */
if (exprDebug) printf("parseValue: %c %ld\n", o, val);
if (o == '-') val=-val;
else if (o == '~') val=~val;
else if (o == '!') val=!val;
}
else if (o == '(')
{
/* handle sub-expression */
/* handle sub-expression */
p++;
if (parseExpr(&p, &val) < 0) return 0; /* no valid expression */
skipSpace(p);
@@ -84,18 +85,33 @@ static char parseSep(const char **pp, const char *seps)
}
struct {char str[4]; int pr;} ops[] = {
{"",0},
{"**",11},
{"*", 10},{"/",10},{"%",10},
{"+",9},{"-",9},
{"<<",8},{">>>",8},{">>",8},
{"<=>",7},{"<=",7},{">=",7},{"<",7},{">",7},
{"==",6},{"!=",6},
{"&&",5},{"||",5},
{"&",4},{"^",3},{"|",2},
{":=",0},
{"**",14},
{"*", 13},{"/",13},{"%",13},
{"+",12},{"-",12},
{"<<",11},{">>>",11},{">>",11},
{"<=>",9},
{"<=",8},{">=",8},{"<",8},{">",8},
{"==",7},{"!=",7},
{"&&",3},{"||",2},
{"&",6},{"^",5},{"|",4},
{"?:",1},{"?",1}
};
enum op {
op_none,
op_pow,
op_mul,op_div,op_mod,
op_plus,op_minus,
op_lshift,op_urshift,op_rshift,
op_cmp,
op_lteq,op_gteq,op_lt,op_gt,
op_eq,op_neq,
op_logicand,op_logicor,
op_bitand,op_bitxor,op_bitor,
op_alt,op_if
};
static int startsWith(const char *p, const char *s)
{
int i = 0;
@@ -131,20 +147,17 @@ static int parseSubExpr(const char **pp, long *v, int pr, int o)
long val2;
int o2 = o;
if (exprDebug) printf("parseExpr(%d): start %ld %s %s\n", pr, val, ops[o].str, p);
if (exprDebug) printf("parseExpr(%d): start %ld %s \"%s\"\n", pr, val, ops[o].str, p);
do {
if (!parseValue(&p, &val2))
{
if (exprDebug)
{
if (o) printf("parseExpr(%d): no value after %ld %s\n", pr, val, ops[o].str);
else printf("parseExpr(%d): no value\n", pr);
}
if (exprDebug) printf("parseExpr(%d): no value after %ld %s\n", pr, val, ops[o].str);
return -1;
}
nextop:
if ((o2 = parseOp(&p)))
{
if (exprDebug) printf("parseExpr(%d): %ld %s %ld %s %s\n", pr, val, ops[o].str, val2, ops[o2].str, p);
if (exprDebug) printf("parseExpr(%d): %ld %s %ld %s \"%s\"\n", pr, val, ops[o].str, val2, ops[o2].str, p);
if (o && ops[o2].pr > ops[o].pr)
{
if ((o2 = parseSubExpr(&p, &val2, ops[o].pr, o2)) < 0)
@@ -154,50 +167,54 @@ static int parseSubExpr(const char **pp, long *v, int pr, int o)
}
}
}
if (exprDebug) printf("parseExpr(%d): %ld %s %ld", pr, val, ops[o].str, val2);
if (exprDebug) printf("parseExpr(%d): calc %ld %s %ld\n", pr, val, ops[o].str, val2);
switch (o)
{
case 0: val = val2; break;
case 1: val = ipow(val, val2); break;
case 2: val *= val2; break;
case 3: val /= val2; break;
case 4: val %= val2; break;
case 5: val += val2; break;
case 6: val -= val2; break;
case 7: val <<= val2; break;
case 8: val = (unsigned long)val >> val2; break;
case 9: val >>= val2; break;
case 10: val = val < val2 ? -1 : val == val2 ? 0 : 1; break;
case 11: val = val <= val2; break;
case 12: val = val >= val2; break;
case 13: val = val < val2; break;
case 14: val = val > val2; break;
case 15: val = val == val2; break;
case 16: val = val != val2; break;
case 17: val = val && val2; break;
case 18: val = val || val2; break;
case 19: val &= val2; break;
case 20: val ^= val2; break;
case 21: val |= val2; break;
case 22: if (!val) val = val2; break;
case op_none: val = val2; break;
case op_pow: val = ipow(val, val2); break;
case op_mul: val *= val2; break;
case op_div: val /= val2; break;
case op_mod: val %= val2; break;
case op_plus: val += val2; break;
case op_minus: val -= val2; break;
case op_lshift: val <<= val2; break;
case op_urshift: val = (unsigned long)val >> val2; break;
case op_rshift: val >>= val2; break;
case op_min: if (val2 < val) val = val2; break;
case op_max: if (val2 > val) val = val2; break;
case op_cmp: val = val < val2 ? -1 : val == val2 ? 0 : 1; break;
case op_lteq: val = val <= val2; break;
case op_gteq: val = val >= val2; break;
case op_lt: val = val < val2; break;
case op_gt: val = val > val2; break;
case op_eq: val = val == val2; break;
case op_neq: val = val != val2; break;
case op_logicand: val = val && val2; break;
case op_logicor: val = val || val2; break;
case op_bitand: val &= val2; break;
case op_bitxor: val ^= val2; break;
case op_bitor: val |= val2; break;
case op_alt: if (!val) val = val2; break;
}
if (exprDebug) printf(" = %ld\n", val);
if (o2 == 23) /* ? ... : ... */
if (exprDebug) printf("parseExpr(%d): result %ld\n", pr, val);
if (o2 == op_if)
{
long val3 = 0;
val2 = 1;
if (exprDebug) printf("parseExpr(%d) if %ld ...\n", pr, val);
if (exprDebug) printf("parseExpr(%d) if %ld\n", pr, val);
if ((o2 = parseExpr(&p, &val2)) >= 0)
{
if (exprDebug) printf("parseExpr(%d) then %ld\n", pr, val2);
if (parseSep(&p, ":"))
{
if (exprDebug) printf("parseExpr(%d) : found\n", pr);
parseExpr(&p, &val3);
if (exprDebug) printf("parseExpr(%d) else %ld\n", pr, val3);
}
}
if (exprDebug) printf("parseExpr(%d) if %ld then %ld else %ld\n", pr, val, val2, val3);
val = val ? val2 : val3;
break;
if (exprDebug) printf("parseExpr(%d): result %ld, o2=%d, rest \"%s\" \n", pr, val, o2, p);
if (o2 == -1) goto nextop;
}
o = o2;
} while (ops[o].pr && pr <= ops[o].pr);
@@ -207,7 +224,7 @@ static int parseSubExpr(const char **pp, long *v, int pr, int o)
return o;
}
const char *getFormat(const char **pp)
static const char *getFormat(const char **pp)
{
static char format [20];
const char *p = *pp;
@@ -234,7 +251,7 @@ const char *getFormat(const char **pp)
return NULL;
}
int parseSlice(const char **pp, long* pstart, long* plength)
static int parseSlice(const char **pp, long* pstart, long* plength)
{
const char *p = *pp;
long slice_start = 0;
@@ -274,7 +291,7 @@ int parseSlice(const char **pp, long* pstart, long* plength)
return 1;
}
long parseString(const char **pp, const char **pstart)
static long parseString(const char **pp, const char **pstart)
{
const char *p = *pp;
const char *string_start = p;
@@ -353,12 +370,7 @@ size_t replaceExpressions(const char *r, char *buffer, size_t buffersize)
/* unformatted expression */
w += sprintf(w, "%ld", val);
*w = 0;
if (exprDebug) printf("simple expression %s\n", s);
}
else if (*r == ',')
{
/* single comma */
*w++ = *r++;
if (exprDebug) printf("expression %s\n", s);
}
else {
/* unquoted string (i.e plain word) */
@@ -369,7 +381,7 @@ size_t replaceExpressions(const char *r, char *buffer, size_t buffersize)
if (exprDebug) printf("plain word '%s'\n", s);
}
/* copy space */
while (isspace((unsigned char)*r)) *w++ = *r++;
while (isspace((unsigned char)*r) || *r == ',') *w++ = *r++;
/* terminate */
*w = 0;
}
+5 -2
View File
@@ -9,6 +9,9 @@ x=x, !x, !!x, -x, --x, ~x, ~~x, x?, x??
x=10+3, 10-3, 10*3, 10/3, 10%3, 10**3
# $(x) should be: 13, 7, 30, 3, 1, 1000
x=7**-2 7**-1 7**0 7**1 7**2 7**3 7**4 7**5 7**6
# $(x) should be: 0 0 1 7 49 343 2401 16807 117649
x=%x -10<<2, %x -10>>2, %x -10>>>2
# $(x) should be: ffffffffffffffd8, fffffffffffffffd, 3ffffffffffffffd
@@ -24,8 +27,8 @@ x=20<20 20<=20 20==20 20>=20 20>20 20<=>20
x=20<10 20<=10 20==10 20>=10 20>10 20<=>10
# $(x) should be: 0 0 0 1 1 1
x= (0|0)(0|1)(1|0)(1|1) (0&0)(0&1)(1&0)(1&1)
# $(x) should be: 0111 0001
x= (0|0)(0|1)(1|0)(1|1) (0&0)(0&1)(1&0)(1&1) (0^0)(0^1)(1^0)(1^1)
# $(x) should be: 0111 0001 0110
x=1*2*3+4*5*6-7-8
# $(x) should be: 111