Mercurial > hg-old > index.cgi
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 } |