Skip to content

Commit 80d1981

Browse files
committed
Merge logic branch: add comparison and logical operators
1 parent 122f20d commit 80d1981

2 files changed

Lines changed: 221 additions & 10 deletions

File tree

‎smoke.c‎

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ void test_syntax() {
174174
{"1*2(+4", 4},
175175
{"1*2(1+4", 4},
176176
{"a+5", 1},
177-
{"!+5", 1},
178177
{"_a+5", 1},
179178
{"#a+5", 1},
180179
{"1^^5", 3},
@@ -690,6 +689,100 @@ void test_combinatorics() {
690689
}
691690

692691

692+
void test_logic() {
693+
test_case cases[] = {
694+
{"1 && 1", 1},
695+
{"1 && 0", 0},
696+
{"0 && 1", 0},
697+
{"0 && 0", 0},
698+
{"1 || 1", 1},
699+
{"1 || 0", 1},
700+
{"0 || 1", 1},
701+
{"0 || 0", 0},
702+
{"!0", 1},
703+
{"!1", 0},
704+
{"!2", 0},
705+
706+
{"!-2", 0},
707+
{"-!2", 0},
708+
{"!!0", 0},
709+
{"!!1", 1},
710+
{"!!2", 1},
711+
{"!!-2", 1},
712+
{"!-!2", 1},
713+
{"-!!2", -1},
714+
{"--!!2", 1},
715+
716+
{"1 < 2", 1},
717+
{"2 < 2", 0},
718+
{"2 <= 2", 1},
719+
{"2 > 1", 1},
720+
{"2 > 2", 0},
721+
{"2 >= 2", 1},
722+
{"2 > -2", 1},
723+
{"-2 < 2", 1},
724+
725+
{"0 == 0", 1},
726+
{"0 != 0", 0},
727+
{"2 == 2", 1},
728+
{"2 != 2", 0},
729+
{"2 == 3", 0},
730+
{"2 != 3", 1},
731+
{"2 == 2.0001", 0},
732+
{"2 != 2.0001", 1},
733+
734+
{"1 < 2 && 2 < 3", 1},
735+
{"1 < 2 && 3 < 2", 0},
736+
{"2 < 1 && 2 < 3", 0},
737+
{"2 < 1 && 3 < 2", 0},
738+
{"1 < 2 || 2 < 3", 1},
739+
{"1 < 2 || 3 < 2", 1},
740+
{"2 < 1 || 2 < 3", 1},
741+
{"2 < 1 || 3 < 2", 0},
742+
743+
{"1 < 1+1", 1},
744+
{"1 < 1*2", 1},
745+
{"1 < 2/2", 0},
746+
{"1 < 2^2", 1},
747+
748+
{"5+5 < 4+10", 1},
749+
{"5+(5 < 4)+10", 15},
750+
{"5+(5 < 4+10)", 6},
751+
{"(5+5 < 4)+10", 10},
752+
{"5+!(5 < 4)+10", 16},
753+
{"5+!(5 < 4+10)", 5},
754+
{"!(5+5 < 4)+10", 11},
755+
756+
#ifdef TE_POW_FROM_RIGHT
757+
{"!0^2", 1},
758+
{"!0^-1", 0},
759+
{"-!0^2", -1},
760+
#else
761+
{"!0^2", 1},
762+
{"!0^-1", 1},
763+
{"-!0^2", 1},
764+
#endif
765+
766+
};
767+
768+
769+
int i;
770+
for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
771+
const char *expr = cases[i].expr;
772+
const double answer = cases[i].answer;
773+
774+
int err;
775+
const double ev = te_interp(expr, &err);
776+
lok(!err);
777+
lfequal(ev, answer);
778+
779+
if (err) {
780+
printf("FAILED: %s (%d)\n", expr, err);
781+
}
782+
}
783+
}
784+
785+
693786
int main(int argc, char *argv[])
694787
{
695788
lrun("Results", test_results);
@@ -703,6 +796,7 @@ int main(int argc, char *argv[])
703796
lrun("Optimize", test_optimize);
704797
lrun("Pow", test_pow);
705798
lrun("Combinatorics", test_combinatorics);
799+
lrun("Logic", test_logic);
706800
lresults();
707801

708802
return lfails != 0;

‎tinyexpr.c‎

Lines changed: 126 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ static double divide(double a, double b) {return a / b;}
235235
static double negate(double a) {return -a;}
236236
static double comma(double a, double b) {(void)a; return b;}
237237

238+
static double greater(double a, double b) {return a > b;}
239+
static double greater_eq(double a, double b) {return a >= b;}
240+
static double lower(double a, double b) {return a < b;}
241+
static double lower_eq(double a, double b) {return a <= b;}
242+
static double equal(double a, double b) {return a == b;}
243+
static double not_equal(double a, double b) {return a != b;}
244+
static double logical_and(double a, double b) {return a != 0.0 && b != 0.0;}
245+
static double logical_or(double a, double b) {return a != 0.0 || b != 0.0;}
246+
static double logical_not(double a) {return a == 0.0;}
247+
static double logical_notnot(double a) {return a != 0.0;}
248+
static double negate_logical_not(double a) {return -(a == 0.0);}
249+
static double negate_logical_notnot(double a) {return -(a != 0.0);}
250+
238251

239252
static void next_token(state *s) {
240253
s->type = TOK_NULL;
@@ -291,6 +304,51 @@ static void next_token(state *s) {
291304
case '/': s->type = TOK_INFIX; s->function = divide; break;
292305
case '^': s->type = TOK_INFIX; s->function = pow; break;
293306
case '%': s->type = TOK_INFIX; s->function = fmod; break;
307+
case '!':
308+
if (s->next++[0] == '=') {
309+
s->type = TOK_INFIX; s->function = not_equal;
310+
} else {
311+
s->next--;
312+
s->type = TOK_INFIX; s->function = logical_not;
313+
}
314+
break;
315+
case '=':
316+
if (s->next++[0] == '=') {
317+
s->type = TOK_INFIX; s->function = equal;
318+
} else {
319+
s->type = TOK_ERROR;
320+
}
321+
break;
322+
case '<':
323+
if (s->next++[0] == '=') {
324+
s->type = TOK_INFIX; s->function = lower_eq;
325+
} else {
326+
s->next--;
327+
s->type = TOK_INFIX; s->function = lower;
328+
}
329+
break;
330+
case '>':
331+
if (s->next++[0] == '=') {
332+
s->type = TOK_INFIX; s->function = greater_eq;
333+
} else {
334+
s->next--;
335+
s->type = TOK_INFIX; s->function = greater;
336+
}
337+
break;
338+
case '&':
339+
if (s->next++[0] == '&') {
340+
s->type = TOK_INFIX; s->function = logical_and;
341+
} else {
342+
s->type = TOK_ERROR;
343+
}
344+
break;
345+
case '|':
346+
if (s->next++[0] == '|') {
347+
s->type = TOK_INFIX; s->function = logical_or;
348+
} else {
349+
s->type = TOK_ERROR;
350+
}
351+
break;
294352
case '(': s->type = TOK_OPEN; break;
295353
case ')': s->type = TOK_CLOSE; break;
296354
case ',': s->type = TOK_SEP; break;
@@ -420,25 +478,51 @@ static te_expr *base(state *s) {
420478

421479

422480
static te_expr *power(state *s) {
423-
/* <power> = {("-" | "+")} <base> */
481+
/* <power> = {("-" | "+" | "!")} <base> */
424482
int sign = 1;
425483
while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
426484
if (s->function == sub) sign = -sign;
427485
next_token(s);
428486
}
429487

488+
int logical = 0;
489+
while (s->type == TOK_INFIX && (s->function == add || s->function == sub || s->function == logical_not)) {
490+
if (s->function == logical_not) {
491+
if (logical == 0) {
492+
logical = -1;
493+
} else {
494+
logical = -logical;
495+
}
496+
}
497+
next_token(s);
498+
}
499+
430500
te_expr *ret;
431501

432502
if (sign == 1) {
433-
ret = base(s);
503+
if (logical == 0) {
504+
ret = base(s);
505+
} else if (logical == -1) {
506+
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
507+
ret->function = logical_not;
508+
} else {
509+
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
510+
ret->function = logical_notnot;
511+
}
434512
} else {
435513
te_expr *b = base(s);
436514
CHECK_NULL(b);
437515

438516
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, b);
439517
CHECK_NULL(ret, te_free(b));
440518

441-
ret->function = negate;
519+
if (logical == 0) {
520+
ret->function = negate;
521+
} else if (logical == -1) {
522+
ret->function = negate_logical_not;
523+
} else {
524+
ret->function = negate_logical_notnot;
525+
}
442526
}
443527

444528
return ret;
@@ -450,13 +534,15 @@ static te_expr *factor(state *s) {
450534
te_expr *ret = power(s);
451535
CHECK_NULL(ret);
452536

453-
int neg = 0;
537+
const void *left_function = NULL;
454538

455-
if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) {
539+
if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) &&
540+
(ret->function == negate || ret->function == logical_not || ret->function == logical_notnot ||
541+
ret->function == negate_logical_not || ret->function == negate_logical_notnot)) {
542+
left_function = ret->function;
456543
te_expr *se = ret->parameters[0];
457544
free(ret);
458545
ret = se;
459-
neg = 1;
460546
}
461547

462548
te_expr *insertion = 0;
@@ -489,12 +575,12 @@ static te_expr *factor(state *s) {
489575
}
490576
}
491577

492-
if (neg) {
578+
if (left_function) {
493579
te_expr *prev = ret;
494580
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
495581
CHECK_NULL(ret, te_free(prev));
496582

497-
ret->function = negate;
583+
ret->function = left_function;
498584
}
499585

500586
return ret;
@@ -546,7 +632,7 @@ static te_expr *term(state *s) {
546632
}
547633

548634

549-
static te_expr *expr(state *s) {
635+
static te_expr *sum_expr(state *s) {
550636
/* <expr> = <term> {("+" | "-") <term>} */
551637
te_expr *ret = term(s);
552638
CHECK_NULL(ret);
@@ -568,6 +654,37 @@ static te_expr *expr(state *s) {
568654
}
569655

570656

657+
static te_expr *test_expr(state *s) {
658+
/* <expr> = <sum_expr> {(">" | ">=" | "<" | "<=" | "==" | "!=") <sum_expr>} */
659+
te_expr *ret = sum_expr(s);
660+
661+
while (s->type == TOK_INFIX && (s->function == greater || s->function == greater_eq ||
662+
s->function == lower || s->function == lower_eq || s->function == equal || s->function == not_equal)) {
663+
te_fun2 t = s->function;
664+
next_token(s);
665+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, sum_expr(s));
666+
ret->function = t;
667+
}
668+
669+
return ret;
670+
}
671+
672+
673+
static te_expr *expr(state *s) {
674+
/* <expr> = <test_expr> {("&&" | "||") <test_expr>} */
675+
te_expr *ret = test_expr(s);
676+
677+
while (s->type == TOK_INFIX && (s->function == logical_and || s->function == logical_or)) {
678+
te_fun2 t = s->function;
679+
next_token(s);
680+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, test_expr(s));
681+
ret->function = t;
682+
}
683+
684+
return ret;
685+
}
686+
687+
571688
static te_expr *list(state *s) {
572689
/* <list> = <expr> {"," <expr>} */
573690
te_expr *ret = expr(s);

0 commit comments

Comments
 (0)