comparison lwlib/lw_expr.c @ 346:a82c55070624

Added expression parsing infrastructure and misc fixes
author lost@starbug
date Sat, 27 Mar 2010 19:04:03 -0600
parents 7b4123dce741
children 1649bc7bda5a
comparison
equal deleted inserted replaced
345:7416c3f9c321 346:a82c55070624
31 #include "lw_error.h" 31 #include "lw_error.h"
32 #include "lw_string.h" 32 #include "lw_string.h"
33 33
34 static lw_expr_fn_t *evaluate_special = NULL; 34 static lw_expr_fn_t *evaluate_special = NULL;
35 static lw_expr_fn2_t *evaluate_var = NULL; 35 static lw_expr_fn2_t *evaluate_var = NULL;
36 static lw_expr_fn3_t *parse_term = NULL;
37
38 void lw_expr_set_term_parser(lw_expr_fn3_t *fn)
39 {
40 parse_term = fn;
41 }
36 42
37 void lw_expr_set_special_handler(lw_expr_fn_t *fn) 43 void lw_expr_set_special_handler(lw_expr_fn_t *fn)
38 { 44 {
39 evaluate_special = fn; 45 evaluate_special = fn;
40 } 46 }
351 if (o1 || o2) 357 if (o1 || o2)
352 return 0; 358 return 0;
353 return 1; 359 return 1;
354 } 360 }
355 361
356 void lw_expr_simplify(lw_expr_t E) 362 void lw_expr_simplify(lw_expr_t E, void *priv)
357 { 363 {
358 struct lw_expr_opers *o; 364 struct lw_expr_opers *o;
359 365
360 again: 366 again:
361 // try to resolve non-constant terms to constants here 367 // try to resolve non-constant terms to constants here
362 if (E -> type == lw_expr_type_special && evaluate_special) 368 if (E -> type == lw_expr_type_special && evaluate_special)
363 { 369 {
364 lw_expr_t te; 370 lw_expr_t te;
365 371
366 te = evaluate_special(E -> value, E -> value2); 372 te = evaluate_special(E -> value, E -> value2, priv);
367 if (te) 373 if (te)
368 { 374 {
369 for (o = E -> operands; o; o = o -> next) 375 for (o = E -> operands; o; o = o -> next)
370 lw_expr_destroy(o -> p); 376 lw_expr_destroy(o -> p);
371 if (E -> type == lw_expr_type_var) 377 if (E -> type == lw_expr_type_var)
387 393
388 if (E -> type == lw_expr_type_var && evaluate_var) 394 if (E -> type == lw_expr_type_var && evaluate_var)
389 { 395 {
390 lw_expr_t te; 396 lw_expr_t te;
391 397
392 te = evaluate_var(E -> value2); 398 te = evaluate_var(E -> value2, priv);
393 if (te) 399 if (te)
394 { 400 {
395 for (o = E -> operands; o; o = o -> next) 401 for (o = E -> operands; o; o = o -> next)
396 lw_expr_destroy(o -> p); 402 lw_expr_destroy(o -> p);
397 if (E -> type == lw_expr_type_var) 403 if (E -> type == lw_expr_type_var)
418 // sort "constants" to the start of each operand list for + and * 424 // sort "constants" to the start of each operand list for + and *
419 lw_expr_simplify_sortconstfirst(E); 425 lw_expr_simplify_sortconstfirst(E);
420 426
421 // simplify operands 427 // simplify operands
422 for (o = E -> operands; o; o = o -> next) 428 for (o = E -> operands; o; o = o -> next)
423 lw_expr_simplify(o -> p); 429 lw_expr_simplify(o -> p, priv);
424 430
425 for (o = E -> operands; o; o = o -> next) 431 for (o = E -> operands; o; o = o -> next)
426 { 432 {
427 if (o -> p -> type != lw_expr_type_int) 433 if (o -> p -> type != lw_expr_type_int)
428 break; 434 break;
635 } 641 }
636 } 642 }
637 return; 643 return;
638 } 644 }
639 } 645 }
646
647 /*
648
649 The following two functions are co-routines which evaluate an infix
650 expression. lw_expr_parse_term checks for unary prefix operators then, if
651 none found, passes the string off the the defined helper function to
652 determine what the term really is. It also handles parentheses.
653
654 lw_expr_parse_expr evaluates actual expressions with infix operators. It
655 respects the order of operations.
656
657 The end of an expression is determined by the presence of any of the
658 following conditions:
659
660 1. a NUL character
661 2. a whitespace character
662 3. a )
663 4. a ,
664 5. any character that is not recognized as a term
665
666 lw_expr_parse_term returns NULL if there is no term (end of expr, etc.)
667
668 lw_expr_parse_expr returns NULL if there is no expression or on a syntax
669 error.
670
671 */
672
673 lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec);
674
675 lw_expr_t lw_expr_parse_term(char **p, void *priv)
676 {
677 lw_expr_t term, term2;
678
679 eval_next:
680 if (!**p || isspace(**p) || **p == ')' || **p == ']')
681 return NULL;
682
683 // parentheses
684 if (**p == '(')
685 {
686 (*p)++;
687 term = lw_expr_parse_expr(p, priv, 0);
688 if (**p != ')')
689 {
690 lw_expr_destroy(term);
691 return NULL;
692 }
693 (*p)++;
694 return term;
695 }
696
697 // unary +
698 if (**p == '+')
699 {
700 (*p)++;
701 goto eval_next;
702 }
703
704 // unary - (prec 200)
705 if (**p == '-')
706 {
707 (*p)++;
708 term = lw_expr_parse_expr(p, priv, 200);
709 if (!term)
710 return NULL;
711
712 term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_neg, term);
713 lw_expr_destroy(term);
714 return term2;
715 }
716
717 // unary ^ or ~ (complement, prec 200)
718 if (**p == '^' || **p == '~')
719 {
720 (*p)++;
721 term = lw_expr_parse_expr(p, priv, 200);
722 if (!term)
723 return NULL;
724
725 term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_com, term);
726 lw_expr_destroy(term);
727 return term2;
728 }
729
730 // non-operator - pass to caller
731 return parse_term(p, priv);
732 }
733
734 lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec)
735 {
736 static const struct operinfo
737 {
738 int opernum;
739 char *operstr;
740 int operprec;
741 } operators[] =
742 {
743 { lw_expr_oper_plus, "+", 100 },
744 { lw_expr_oper_minus, "-", 100 },
745 { lw_expr_oper_times, "*", 100 },
746 { lw_expr_oper_divide, "/", 150 },
747 { lw_expr_oper_mod, "%", 150 },
748 { lw_expr_oper_intdiv, "\\", 150 },
749
750 { lw_expr_oper_and, "&&", 25 },
751 { lw_expr_oper_or, "||", 25 },
752
753 { lw_expr_oper_bwand, "&", 50 },
754 { lw_expr_oper_bwor, "|", 50 },
755 { lw_expr_oper_bwxor, "^", 50 },
756
757 { lw_expr_oper_none, "", 0 }
758 };
759
760 int opern, i;
761 lw_expr_t term1, term2, term3;
762
763 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']')
764 return NULL;
765
766 term1 = lw_expr_parse_term(p, priv);
767 if (!term1)
768 return NULL;
769
770 eval_next:
771 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']')
772 return term1;
773
774 // expecting an operator here
775 for (opern = 0; operators[opern].opernum != lw_expr_oper_none; opern++)
776 {
777 for (i = 0; (*p)[i] && operators[opern].operstr[i] && ((*p)[i] == operators[opern].operstr[i]); i++)
778 /* do nothing */;
779 if (operators[opern].operstr[i] == '\0')
780 break;
781 }
782
783 if (operators[opern].opernum == lw_expr_oper_none)
784 {
785 // unrecognized operator
786 lw_expr_destroy(term1);
787 return NULL;
788 }
789
790 // operator number is in opern, length of oper in i
791
792 // logic:
793 // if the precedence of this operation is <= to the "prec" flag,
794 // we simply return without advancing the input pointer; the operator
795 // will be evaluated again in the enclosing function call
796 if (operators[opern].operprec <= prec)
797 return term1;
798
799 // logic:
800 // we have a higher precedence operator here so we will advance the
801 // input pointer to the next term and let the expression evaluator
802 // loose on it after which time we will push our operator onto the
803 // stack and then go on with the expression evaluation
804 (*p) += i;
805
806 // evaluate next expression(s) of higher precedence
807 term2 = lw_expr_parse_expr(p, priv, operators[opern].operprec);
808 if (!term2)
809 {
810 lw_expr_destroy(term1);
811 return NULL;
812 }
813
814 // now create operator
815 term3 = lw_expr_build(lw_expr_type_oper, operators[opern].opernum, term1, term2);
816 lw_expr_destroy(term1);
817 lw_expr_destroy(term2);
818
819 // the new "expression" is the next "left operand"
820 term1 = term3;
821
822 // continue evaluating
823 goto eval_next;
824 }
825
826 lw_expr_t lw_expr_parse(char **p, void *priv)
827 {
828 return lw_expr_parse_expr(p, priv, 0);
829 }