summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Fuhrmannek2021-09-01 17:01:00 +0200
committerBen Fuhrmannek2021-09-01 17:01:00 +0200
commit782336d8f4b9c411d344c0e7752e87631952f268 (patch)
treedeba1aed1db8b64a6b2f5a1076914fe8743e6c14 /src
parent5cdfa697666c0ed347aaa086953b7e9c7f8aa9f9 (diff)
implemented proper operand precedence using the shunting yard algorithm
Diffstat (limited to 'src')
-rw-r--r--src/sp_config_scanner.cached.c502
-rw-r--r--src/sp_config_scanner.re118
2 files changed, 394 insertions, 226 deletions
diff --git a/src/sp_config_scanner.cached.c b/src/sp_config_scanner.cached.c
index d053e5f..26a6652 100644
--- a/src/sp_config_scanner.cached.c
+++ b/src/sp_config_scanner.cached.c
@@ -78,20 +78,60 @@ static void str_dtor(zval *zv) {
78 zend_string_release_ex(Z_STR_P(zv), 1); 78 zend_string_release_ex(Z_STR_P(zv), 1);
79} 79}
80 80
81static int apply_op(int v1, char op, int v2, int neg) { 81// sy_ functions and macros are helpers for the shunting yard algorithm
82 if (neg) { v2 = !v2; } 82#define sy_res_push(val) \
83 if (cond_res_i >= 100) { cs_error_log("condition too complex on line %d", lineno); goto out; } \
84 cond_res[cond_res_i++] = val;
85#define sy_res_pop() cond_res[--cond_res_i]
86#define sy_op_push(op) \
87 if (cond_op_i >= 100) { cs_error_log("condition too complex on line %d", lineno); goto out; } \
88 cond_op[cond_op_i++] = op;
89#define sy_op_pop() cond_op[--cond_op_i]
90#define sy_op_peek() cond_op[cond_op_i-1]
91
92static inline int sy_op_precedence(char op) {
93 switch (op) {
94 case '!': return 120;
95 case '<':
96 case '>':
97 case 'L': // <=
98 case 'G': // >=
99 return 90;
100 case '&': return 70;
101 case '|': return 60;
102 case '=': return 20;
103 }
104 return 0;
105}
106static inline int sy_op_is_left_assoc(char op) {
107 switch (op) {
108 case '!': return 0;
109 }
110 return 1;
111}
112static int sy_apply_op(char op, int a, int b) {
83 switch (op) { 113 switch (op) {
84 case 0: return v2; 114 case '!': return !a;
85 case '&': return (v1 && v2); 115 case '&': return (b && a);
86 case '|': return (v1 || v2); 116 case '|': return (b || a);
87 case '<': return (v1 < v2); 117 case '<': return (b < a);
88 case '>': return (v1 > v2); 118 case 'L': return (b <= a);
89 case '=': return (v1 == v2); 119 case 'G': return (b >= a);
120 case '>': return (b > a);
121 case '=': return (b == a);
90 } 122 }
91 return 0; 123 return 0;
92} 124}
93 125
94#define APPLY_OP(v2) cond_res = apply_op(cond_res, cond_op, v2, cond_neg); cond_op = cond_neg = 0; 126#define SY_APPLY_OP_FROM_STACK() \
127 char op = sy_op_pop(); \
128 int unary = (op == '!'); \
129 if (cond_res_i < (2 - unary)) { cs_error_log("not enough input on line %d", lineno); goto out; } \
130 int a = sy_res_pop(); \
131 int b = unary ? 0 : sy_res_pop(); \
132 int res = sy_apply_op(op, a, b); \
133 sy_res_push(res);
134
95 135
96zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*)) 136zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*))
97{ 137{
@@ -111,10 +151,13 @@ const char *yyt4;
111 151
112 HashTable vars; 152 HashTable vars;
113 zend_hash_init(&vars, 10, NULL, str_dtor, 1); 153 zend_hash_init(&vars, 10, NULL, str_dtor, 1);
154 zend_hash_str_add_ptr(&vars, ZEND_STRL("PHP_VERSION_ID"), zend_string_init(ZEND_STRL(ZEND_TOSTR(PHP_VERSION_ID)), 1));
114 155
115 int cond_res = 1; 156
116 char cond_op = 0; 157 int cond_res[100] = {0};
117 int cond_neg = 0; 158 int cond_res_i = 0;
159 char cond_op[100] = {0};
160 int cond_op_i = 0;
118 161
119 int cond = yycinit; 162 int cond = yycinit;
120 long lineno = 1; 163 long lineno = 1;
@@ -527,7 +570,7 @@ yy65:
527 if (yych != ';') goto yy18; 570 if (yych != ';') goto yy18;
528 } 571 }
529 ++YYCURSOR; 572 ++YYCURSOR;
530 { cond_res = 1; goto yyc_init; } 573 { cond_res[0] = 1; goto yyc_init; }
531 } 574 }
532/* *********************************** */ 575/* *********************************** */
533yyc_cond: 576yyc_cond:
@@ -570,38 +613,46 @@ yyc_cond:
570 if (yybm[0+yych] & 8) { 613 if (yybm[0+yych] & 8) {
571 goto yy73; 614 goto yy73;
572 } 615 }
573 if (yych <= '/') { 616 if (yych <= '(') {
574 if (yych <= '\f') { 617 if (yych <= '\r') {
575 if (yych <= 0x08) goto yy71; 618 if (yych <= 0x08) goto yy71;
576 if (yych <= '\n') goto yy76; 619 if (yych <= '\n') goto yy76;
620 if (yych >= '\r') goto yy78;
577 } else { 621 } else {
578 if (yych <= '\r') goto yy78;
579 if (yych <= 0x1F) goto yy71; 622 if (yych <= 0x1F) goto yy71;
580 if (yych <= '!') goto yy79; 623 if (yych <= '!') goto yy79;
624 if (yych >= '(') goto yy81;
581 } 625 }
582 } else { 626 } else {
583 if (yych <= '^') { 627 if (yych <= 'Z') {
628 if (yych <= '/') goto yy71;
584 if (yych <= '9') { 629 if (yych <= '9') {
585 yyt1 = YYCURSOR; 630 yyt1 = YYCURSOR;
586 goto yy81; 631 goto yy83;
587 } 632 }
588 if (yych <= '@') goto yy71; 633 if (yych >= 'A') {
589 if (yych <= 'Z') {
590 yyt1 = YYCURSOR; 634 yyt1 = YYCURSOR;
591 goto yy84; 635 goto yy86;
592 } 636 }
593 } else { 637 } else {
594 if (yych == '`') goto yy71; 638 if (yych <= '_') {
595 if (yych <= 'z') { 639 if (yych >= '_') {
596 yyt1 = YYCURSOR; 640 yyt1 = YYCURSOR;
597 goto yy84; 641 goto yy86;
642 }
643 } else {
644 if (yych <= '`') goto yy71;
645 if (yych <= 'z') {
646 yyt1 = YYCURSOR;
647 goto yy86;
648 }
598 } 649 }
599 } 650 }
600 } 651 }
601yy71: 652yy71:
602 ++YYCURSOR; 653 ++YYCURSOR;
603yy72: 654yy72:
604 { cs_error_log("Syntax error in condition on line %d", lineno); return false; } 655 { cs_error_log("Syntax error in condition on line %d", lineno); goto out; }
605yy73: 656yy73:
606 yych = *++YYCURSOR; 657 yych = *++YYCURSOR;
607 if (yybm[0+yych] & 8) { 658 if (yybm[0+yych] & 8) {
@@ -618,23 +669,27 @@ yy78:
618yy79: 669yy79:
619 ++YYCURSOR; 670 ++YYCURSOR;
620 t1 = YYCURSOR - 1; 671 t1 = YYCURSOR - 1;
621 { cond_neg = (cond_neg + 1) % 2; goto yyc_cond; } 672 { sy_op_push(*t1); goto yyc_cond; }
622yy81: 673yy81:
674 ++YYCURSOR;
675 t1 = YYCURSOR - 1;
676 { sy_op_push(*t1); goto yyc_cond; }
677yy83:
623 yych = *++YYCURSOR; 678 yych = *++YYCURSOR;
624 if (yybm[0+yych] & 16) { 679 if (yybm[0+yych] & 16) {
625 goto yy81; 680 goto yy83;
626 } 681 }
627 t1 = yyt1; 682 t1 = yyt1;
628 t2 = YYCURSOR; 683 t2 = YYCURSOR;
629 { APPLY_OP(atoi(t1)); goto yyc_cond_op; } 684 { sy_res_push(atoi(t1)); goto yyc_cond_op; }
630yy84: 685yy86:
631 yyaccept = 0; 686 yyaccept = 0;
632 yych = *(YYMARKER = ++YYCURSOR); 687 yych = *(YYMARKER = ++YYCURSOR);
633 if (yybm[0+yych] & 32) { 688 if (yybm[0+yych] & 32) {
634 goto yy84; 689 goto yy86;
635 } 690 }
636 if (yych == '(') goto yy87; 691 if (yych == '(') goto yy89;
637yy86: 692yy88:
638 t1 = yyt1; 693 t1 = yyt1;
639 t2 = YYCURSOR; 694 t2 = YYCURSOR;
640 { 695 {
@@ -643,37 +698,37 @@ yy86:
643 cs_error_log("unknown variable in condition on line %d", lineno); 698 cs_error_log("unknown variable in condition on line %d", lineno);
644 goto out; 699 goto out;
645 } 700 }
646 APPLY_OP(atoi(ZSTR_VAL(tmp))); 701 sy_res_push(atoi(ZSTR_VAL(tmp)));
647 goto yyc_cond_op; 702 goto yyc_cond_op;
648 } 703 }
649yy87: 704yy89:
650 yych = *++YYCURSOR; 705 yych = *++YYCURSOR;
651 if (yych == '"') { 706 if (yych == '"') {
652 yyt2 = YYCURSOR; 707 yyt2 = YYCURSOR;
653 goto yy89; 708 goto yy91;
654 } 709 }
655 if (yych == ')') { 710 if (yych == ')') {
656 yyt2 = YYCURSOR; 711 yyt2 = YYCURSOR;
657 goto yy91; 712 goto yy93;
658 } 713 }
659yy88: 714yy90:
660 YYCURSOR = YYMARKER; 715 YYCURSOR = YYMARKER;
661 if (yyaccept == 0) { 716 if (yyaccept == 0) {
662 goto yy86; 717 goto yy88;
663 } else { 718 } else {
664 goto yy92; 719 goto yy94;
665 } 720 }
666yy89: 721yy91:
667 yych = *++YYCURSOR; 722 yych = *++YYCURSOR;
668 if (yybm[0+yych] & 64) { 723 if (yybm[0+yych] & 64) {
669 goto yy89; 724 goto yy91;
670 } 725 }
671 if (yych <= '\r') goto yy88; 726 if (yych <= '\r') goto yy90;
672 if (yych <= '"') goto yy93; 727 if (yych <= '"') goto yy95;
673 goto yy94; 728 goto yy96;
674yy91: 729yy93:
675 ++YYCURSOR; 730 ++YYCURSOR;
676yy92: 731yy94:
677 t1 = yyt1; 732 t1 = yyt1;
678 t3 = yyt2; 733 t3 = yyt2;
679 t2 = yyt2 - 1; 734 t2 = yyt2 - 1;
@@ -681,48 +736,48 @@ yy92:
681 { 736 {
682 if (t4-t3 >= 2 && strlen("extension_loaded") == t2-t1 && strncmp("extension_loaded", t1, t2-t1) == 0) { 737 if (t4-t3 >= 2 && strlen("extension_loaded") == t2-t1 && strncmp("extension_loaded", t1, t2-t1) == 0) {
683 int is_loaded = (zend_hash_str_find_ptr(&module_registry, t3+1, t4-t3-2) != NULL); 738 int is_loaded = (zend_hash_str_find_ptr(&module_registry, t3+1, t4-t3-2) != NULL);
684 APPLY_OP(is_loaded); 739 sy_res_push(is_loaded);
685 } else { 740 } else {
686 cs_error_log("unknown function in condition on line %d", lineno); 741 cs_error_log("unknown function in condition on line %d", lineno);
687 goto out; 742 goto out;
688 } 743 }
689 goto yyc_cond_op; 744 goto yyc_cond_op;
690 } 745 }
691yy93: 746yy95:
692 yych = *++YYCURSOR; 747 yych = *++YYCURSOR;
693 if (yych == ')') goto yy91; 748 if (yych == ')') goto yy93;
694 goto yy88; 749 goto yy90;
695yy94: 750yy96:
696 yych = *++YYCURSOR; 751 yych = *++YYCURSOR;
697 if (yybm[0+yych] & 64) { 752 if (yybm[0+yych] & 64) {
698 goto yy89; 753 goto yy91;
699 } 754 }
700 if (yych <= '\r') goto yy88; 755 if (yych <= '\r') goto yy90;
701 if (yych >= '#') goto yy94; 756 if (yych >= '#') goto yy96;
702 yych = *++YYCURSOR; 757 yych = *++YYCURSOR;
703 if (yybm[0+yych] & 128) { 758 if (yybm[0+yych] & 128) {
704 goto yy94; 759 goto yy96;
705 } 760 }
706 if (yych <= '\r') { 761 if (yych <= '\r') {
707 if (yych == '\n') goto yy88; 762 if (yych == '\n') goto yy90;
708 if (yych <= '\f') goto yy89; 763 if (yych <= '\f') goto yy91;
709 goto yy88; 764 goto yy90;
710 } else { 765 } else {
711 if (yych <= '"') { 766 if (yych <= '"') {
712 if (yych <= '!') goto yy89; 767 if (yych <= '!') goto yy91;
713 goto yy93; 768 goto yy95;
714 } else { 769 } else {
715 if (yych != ')') goto yy89; 770 if (yych != ')') goto yy91;
716 } 771 }
717 } 772 }
718 yyaccept = 1; 773 yyaccept = 1;
719 yych = *(YYMARKER = ++YYCURSOR); 774 yych = *(YYMARKER = ++YYCURSOR);
720 if (yybm[0+yych] & 64) { 775 if (yybm[0+yych] & 64) {
721 goto yy89; 776 goto yy91;
722 } 777 }
723 if (yych <= '\r') goto yy92; 778 if (yych <= '\r') goto yy94;
724 if (yych <= '"') goto yy93; 779 if (yych <= '"') goto yy95;
725 goto yy94; 780 goto yy96;
726 } 781 }
727/* *********************************** */ 782/* *********************************** */
728yyc_cond_op: 783yyc_cond_op:
@@ -763,75 +818,114 @@ yyc_cond_op:
763 }; 818 };
764 yych = *YYCURSOR; 819 yych = *YYCURSOR;
765 if (yybm[0+yych] & 128) { 820 if (yybm[0+yych] & 128) {
766 goto yy102; 821 goto yy104;
767 } 822 }
768 if (yych <= ':') { 823 if (yych <= ')') {
769 if (yych <= '\f') { 824 if (yych <= '\r') {
770 if (yych <= 0x08) goto yy100; 825 if (yych <= 0x08) goto yy102;
771 if (yych <= '\n') goto yy105; 826 if (yych <= '\n') goto yy107;
827 if (yych >= '\r') goto yy109;
772 } else { 828 } else {
773 if (yych <= '\r') goto yy107;
774 if (yych == '&') { 829 if (yych == '&') {
775 yyt1 = YYCURSOR; 830 yyt1 = YYCURSOR;
776 goto yy108; 831 goto yy110;
777 } 832 }
833 if (yych >= ')') goto yy111;
778 } 834 }
779 } else { 835 } else {
780 if (yych <= '=') { 836 if (yych <= '=') {
781 if (yych <= ';') goto yy109; 837 if (yych <= ':') goto yy102;
838 if (yych <= ';') goto yy113;
782 if (yych <= '<') { 839 if (yych <= '<') {
783 yyt1 = YYCURSOR; 840 yyt1 = YYCURSOR;
784 goto yy111; 841 goto yy115;
785 } 842 }
786 yyt1 = YYCURSOR; 843 yyt1 = YYCURSOR;
787 goto yy113; 844 goto yy117;
788 } else { 845 } else {
789 if (yych <= '>') { 846 if (yych <= '>') {
790 yyt1 = YYCURSOR; 847 yyt1 = YYCURSOR;
791 goto yy111; 848 goto yy115;
792 } 849 }
793 if (yych == '|') { 850 if (yych == '|') {
794 yyt1 = YYCURSOR; 851 yyt1 = YYCURSOR;
795 goto yy114; 852 goto yy118;
796 } 853 }
797 } 854 }
798 } 855 }
799yy100:
800 ++YYCURSOR;
801yy101:
802 { cs_error_log("Syntax error in condition on line %d", lineno); return false; }
803yy102: 856yy102:
857 ++YYCURSOR;
858yy103:
859 { cs_error_log("Syntax error in condition on line %d", lineno); goto out; }
860yy104:
804 yych = *++YYCURSOR; 861 yych = *++YYCURSOR;
805 if (yybm[0+yych] & 128) { 862 if (yybm[0+yych] & 128) {
806 goto yy102; 863 goto yy104;
807 } 864 }
808 { goto yyc_cond_op; } 865 { goto yyc_cond_op; }
809yy105: 866yy107:
810 ++YYCURSOR; 867 ++YYCURSOR;
811 { lineno++; goto yyc_cond_op; } 868 { lineno++; goto yyc_cond_op; }
812yy107: 869yy109:
813 yych = *++YYCURSOR; 870 yych = *++YYCURSOR;
814 if (yych == '\n') goto yy105; 871 if (yych == '\n') goto yy107;
815 goto yy101; 872 goto yy103;
816yy108: 873yy110:
817 yych = *++YYCURSOR; 874 yych = *++YYCURSOR;
818 if (yych == '&') goto yy111; 875 if (yych == '&') goto yy119;
819 goto yy101; 876 goto yy103;
820yy109:
821 ++YYCURSOR;
822 { goto yyc_init; }
823yy111: 877yy111:
824 ++YYCURSOR; 878 ++YYCURSOR;
825 t1 = yyt1; 879 {
826 { cond_op = *t1; goto yyc_cond; } 880 while (cond_op_i && sy_op_peek() != '(') {
881 SY_APPLY_OP_FROM_STACK();
882 }
883 if (cond_op_i == 0 || sy_op_peek() != '(') {
884 cs_error_log("unbalanced parathesis on line %d", lineno); goto out;
885 }
886 sy_op_pop();
887 goto yyc_cond_op;
888 }
827yy113: 889yy113:
890 ++YYCURSOR;
891 {
892 while (cond_op_i) {
893 if (sy_op_peek() == '(') { cs_error_log("unbalanced parathesis on line %d", lineno); goto out; }
894 SY_APPLY_OP_FROM_STACK();
895 }
896 if (cond_res_i > 1) { cs_error_log("invalid condition on line %d", lineno); goto out; }
897 goto yyc_init;
898 }
899yy115:
900 yych = *++YYCURSOR;
901 if (yych == '=') goto yy119;
902yy116:
903 t1 = yyt1;
904 t2 = YYCURSOR;
905 {
906 char op1 = *t1;
907 if (t2-t1 == 2) {
908 switch (op1) {
909 case '<': op1 = 'L'; break; // <=
910 case '>': op1 = 'G'; break; // >=
911 }
912 }
913 while (cond_op_i && sy_op_peek() != '(' && ((sy_op_precedence(sy_op_peek()) > sy_op_precedence(*t1)) || (sy_op_precedence(sy_op_peek()) == sy_op_precedence(*t1)) && sy_op_is_left_assoc(*t1))) {
914 SY_APPLY_OP_FROM_STACK();
915 }
916 sy_op_push(*t1);
917 goto yyc_cond;
918 }
919yy117:
828 yych = *++YYCURSOR; 920 yych = *++YYCURSOR;
829 if (yych == '=') goto yy111; 921 if (yych == '=') goto yy119;
830 goto yy101; 922 goto yy103;
831yy114: 923yy118:
832 yych = *++YYCURSOR; 924 yych = *++YYCURSOR;
833 if (yych == '|') goto yy111; 925 if (yych != '|') goto yy103;
834 goto yy101; 926yy119:
927 ++YYCURSOR;
928 goto yy116;
835 } 929 }
836/* *********************************** */ 930/* *********************************** */
837yyc_rule: 931yyc_rule:
@@ -872,158 +966,158 @@ yyc_rule:
872 }; 966 };
873 yych = *YYCURSOR; 967 yych = *YYCURSOR;
874 if (yybm[0+yych] & 8) { 968 if (yybm[0+yych] & 8) {
875 goto yy119; 969 goto yy124;
876 } 970 }
877 if (yych <= '\r') { 971 if (yych <= '\r') {
878 if (yych <= 0x08) goto yy117; 972 if (yych <= 0x08) goto yy122;
879 if (yych <= '\n') goto yy122; 973 if (yych <= '\n') goto yy127;
880 if (yych >= '\r') goto yy123; 974 if (yych >= '\r') goto yy128;
881 } else { 975 } else {
882 if (yych <= '.') { 976 if (yych <= '.') {
883 if (yych >= '.') goto yy124; 977 if (yych >= '.') goto yy129;
884 } else { 978 } else {
885 if (yych == ';') goto yy125; 979 if (yych == ';') goto yy130;
886 } 980 }
887 } 981 }
888yy117: 982yy122:
889 ++YYCURSOR; 983 ++YYCURSOR;
890yy118: 984yy123:
891 { goto end_of_rule; } 985 { goto end_of_rule; }
892yy119: 986yy124:
893 yych = *++YYCURSOR; 987 yych = *++YYCURSOR;
894 if (yybm[0+yych] & 8) { 988 if (yybm[0+yych] & 8) {
895 goto yy119; 989 goto yy124;
896 } 990 }
897 { goto yyc_rule; } 991 { goto yyc_rule; }
898yy122: 992yy127:
899 yyaccept = 0; 993 yyaccept = 0;
900 yych = *(YYMARKER = ++YYCURSOR); 994 yych = *(YYMARKER = ++YYCURSOR);
901 if (yych <= '\r') { 995 if (yych <= '\r') {
902 if (yych <= 0x08) goto yy118; 996 if (yych <= 0x08) goto yy123;
903 if (yych <= '\n') { 997 if (yych <= '\n') {
904 yyt1 = YYCURSOR; 998 yyt1 = YYCURSOR;
905 goto yy127; 999 goto yy132;
906 } 1000 }
907 if (yych <= '\f') goto yy118; 1001 if (yych <= '\f') goto yy123;
908 yyt1 = YYCURSOR; 1002 yyt1 = YYCURSOR;
909 goto yy130; 1003 goto yy135;
910 } else { 1004 } else {
911 if (yych <= ' ') { 1005 if (yych <= ' ') {
912 if (yych <= 0x1F) goto yy118; 1006 if (yych <= 0x1F) goto yy123;
913 yyt1 = YYCURSOR; 1007 yyt1 = YYCURSOR;
914 goto yy127; 1008 goto yy132;
915 } else { 1009 } else {
916 if (yych == '.') { 1010 if (yych == '.') {
917 yyt1 = YYCURSOR; 1011 yyt1 = YYCURSOR;
918 goto yy131; 1012 goto yy136;
919 } 1013 }
920 goto yy118; 1014 goto yy123;
921 } 1015 }
922 } 1016 }
923yy123: 1017yy128:
924 yyaccept = 0; 1018 yyaccept = 0;
925 yych = *(YYMARKER = ++YYCURSOR); 1019 yych = *(YYMARKER = ++YYCURSOR);
926 if (yych == '\n') goto yy133; 1020 if (yych == '\n') goto yy138;
927 goto yy118; 1021 goto yy123;
928yy124: 1022yy129:
929 yych = *++YYCURSOR; 1023 yych = *++YYCURSOR;
930 if (yych <= '^') { 1024 if (yych <= '^') {
931 if (yych <= '@') goto yy118; 1025 if (yych <= '@') goto yy123;
932 if (yych <= 'Z') { 1026 if (yych <= 'Z') {
933 yyt1 = YYCURSOR; 1027 yyt1 = YYCURSOR;
934 goto yy134; 1028 goto yy139;
935 } 1029 }
936 goto yy118; 1030 goto yy123;
937 } else { 1031 } else {
938 if (yych == '`') goto yy118; 1032 if (yych == '`') goto yy123;
939 if (yych <= 'z') { 1033 if (yych <= 'z') {
940 yyt1 = YYCURSOR; 1034 yyt1 = YYCURSOR;
941 goto yy134; 1035 goto yy139;
942 } 1036 }
943 goto yy118; 1037 goto yy123;
944 } 1038 }
945yy125: 1039yy130:
946 ++YYCURSOR; 1040 ++YYCURSOR;
947 { 1041 {
948 end_of_rule: 1042 end_of_rule:
949 if (!cond_res) { goto yyc_init; } 1043 if (!cond_res[0]) { goto yyc_init; }
950 parsed_rule[kw_i++] = (sp_parsed_keyword){0, 0, 0, 0, 0, 0}; 1044 parsed_rule[kw_i++] = (sp_parsed_keyword){0, 0, 0, 0, 0, 0};
951 if (process_rule && process_rule(parsed_rule) != SUCCESS) { 1045 if (process_rule && process_rule(parsed_rule) != SUCCESS) {
952 goto out; 1046 goto out;
953 } 1047 }
954 goto yyc_init; 1048 goto yyc_init;
955 } 1049 }
956yy127: 1050yy132:
957 yych = *++YYCURSOR; 1051 yych = *++YYCURSOR;
958 if (yybm[0+yych] & 16) { 1052 if (yybm[0+yych] & 16) {
959 goto yy127; 1053 goto yy132;
960 } 1054 }
961 if (yych == '\r') goto yy130; 1055 if (yych == '\r') goto yy135;
962 if (yych == '.') goto yy131; 1056 if (yych == '.') goto yy136;
963yy129: 1057yy134:
964 YYCURSOR = YYMARKER; 1058 YYCURSOR = YYMARKER;
965 if (yyaccept <= 1) { 1059 if (yyaccept <= 1) {
966 if (yyaccept == 0) { 1060 if (yyaccept == 0) {
967 goto yy118; 1061 goto yy123;
968 } else { 1062 } else {
969 yyt3 = yyt4 = NULL; 1063 yyt3 = yyt4 = NULL;
970 yyt2 = YYCURSOR; 1064 yyt2 = YYCURSOR;
971 goto yy136; 1065 goto yy141;
972 } 1066 }
973 } else { 1067 } else {
974 goto yy136; 1068 goto yy141;
975 } 1069 }
976yy130: 1070yy135:
977 yych = *++YYCURSOR; 1071 yych = *++YYCURSOR;
978 if (yych == '\n') goto yy127; 1072 if (yych == '\n') goto yy132;
979 goto yy129; 1073 goto yy134;
980yy131: 1074yy136:
981 ++YYCURSOR; 1075 ++YYCURSOR;
982 YYCURSOR = yyt1; 1076 YYCURSOR = yyt1;
983 { lineno++; goto yyc_rule; } 1077 { lineno++; goto yyc_rule; }
984yy133: 1078yy138:
985 yych = *++YYCURSOR; 1079 yych = *++YYCURSOR;
986 if (yych <= '\r') { 1080 if (yych <= '\r') {
987 if (yych <= 0x08) goto yy129; 1081 if (yych <= 0x08) goto yy134;
988 if (yych <= '\n') { 1082 if (yych <= '\n') {
989 yyt1 = YYCURSOR; 1083 yyt1 = YYCURSOR;
990 goto yy127; 1084 goto yy132;
991 } 1085 }
992 if (yych <= '\f') goto yy129; 1086 if (yych <= '\f') goto yy134;
993 yyt1 = YYCURSOR; 1087 yyt1 = YYCURSOR;
994 goto yy130; 1088 goto yy135;
995 } else { 1089 } else {
996 if (yych <= ' ') { 1090 if (yych <= ' ') {
997 if (yych <= 0x1F) goto yy129; 1091 if (yych <= 0x1F) goto yy134;
998 yyt1 = YYCURSOR; 1092 yyt1 = YYCURSOR;
999 goto yy127; 1093 goto yy132;
1000 } else { 1094 } else {
1001 if (yych == '.') { 1095 if (yych == '.') {
1002 yyt1 = YYCURSOR; 1096 yyt1 = YYCURSOR;
1003 goto yy131; 1097 goto yy136;
1004 } 1098 }
1005 goto yy129; 1099 goto yy134;
1006 } 1100 }
1007 } 1101 }
1008yy134: 1102yy139:
1009 yyaccept = 1; 1103 yyaccept = 1;
1010 yych = *(YYMARKER = ++YYCURSOR); 1104 yych = *(YYMARKER = ++YYCURSOR);
1011 if (yybm[0+yych] & 32) { 1105 if (yybm[0+yych] & 32) {
1012 goto yy134; 1106 goto yy139;
1013 } 1107 }
1014 if (yych == '(') { 1108 if (yych == '(') {
1015 yyt2 = YYCURSOR; 1109 yyt2 = YYCURSOR;
1016 goto yy137; 1110 goto yy142;
1017 } 1111 }
1018 yyt3 = yyt4 = NULL; 1112 yyt3 = yyt4 = NULL;
1019 yyt2 = YYCURSOR; 1113 yyt2 = YYCURSOR;
1020yy136: 1114yy141:
1021 t1 = yyt1; 1115 t1 = yyt1;
1022 t2 = yyt2; 1116 t2 = yyt2;
1023 t3 = yyt3; 1117 t3 = yyt3;
1024 t4 = yyt4; 1118 t4 = yyt4;
1025 { 1119 {
1026 if (!cond_res) { goto yyc_rule; } 1120 if (!cond_res[0]) { goto yyc_rule; }
1027 if (kw_i == max_keywords) { 1121 if (kw_i == max_keywords) {
1028 cs_error_log("Too many keywords in rule (more than %d) on line %d", max_keywords, lineno); 1122 cs_error_log("Too many keywords in rule (more than %d) on line %d", max_keywords, lineno);
1029 goto out; 1123 goto out;
@@ -1052,110 +1146,110 @@ yy136:
1052 parsed_rule[kw_i++] = kw; 1146 parsed_rule[kw_i++] = kw;
1053 goto yyc_rule; 1147 goto yyc_rule;
1054 } 1148 }
1055yy137: 1149yy142:
1056 yych = *++YYCURSOR; 1150 yych = *++YYCURSOR;
1057 if (yych <= '@') { 1151 if (yych <= '@') {
1058 if (yych <= '"') { 1152 if (yych <= '"') {
1059 if (yych <= '!') goto yy129; 1153 if (yych <= '!') goto yy134;
1060 yyt3 = YYCURSOR; 1154 yyt3 = YYCURSOR;
1061 } else { 1155 } else {
1062 if (yych == ')') { 1156 if (yych == ')') {
1063 yyt3 = yyt4 = YYCURSOR; 1157 yyt3 = yyt4 = YYCURSOR;
1064 goto yy140; 1158 goto yy145;
1065 } 1159 }
1066 goto yy129; 1160 goto yy134;
1067 } 1161 }
1068 } else { 1162 } else {
1069 if (yych <= '_') { 1163 if (yych <= '_') {
1070 if (yych <= 'Z') { 1164 if (yych <= 'Z') {
1071 yyt3 = YYCURSOR; 1165 yyt3 = YYCURSOR;
1072 goto yy141; 1166 goto yy146;
1073 } 1167 }
1074 if (yych <= '^') goto yy129; 1168 if (yych <= '^') goto yy134;
1075 yyt3 = YYCURSOR; 1169 yyt3 = YYCURSOR;
1076 goto yy141; 1170 goto yy146;
1077 } else { 1171 } else {
1078 if (yych <= '`') goto yy129; 1172 if (yych <= '`') goto yy134;
1079 if (yych <= 'z') { 1173 if (yych <= 'z') {
1080 yyt3 = YYCURSOR; 1174 yyt3 = YYCURSOR;
1081 goto yy141; 1175 goto yy146;
1082 } 1176 }
1083 goto yy129; 1177 goto yy134;
1084 } 1178 }
1085 } 1179 }
1086yy138: 1180yy143:
1087 yych = *++YYCURSOR; 1181 yych = *++YYCURSOR;
1088 if (yybm[0+yych] & 64) { 1182 if (yybm[0+yych] & 64) {
1089 goto yy138; 1183 goto yy143;
1090 } 1184 }
1091 if (yych <= '\r') goto yy129; 1185 if (yych <= '\r') goto yy134;
1092 if (yych <= '"') goto yy143; 1186 if (yych <= '"') goto yy148;
1093 goto yy144; 1187 goto yy149;
1094yy140: 1188yy145:
1095 ++YYCURSOR; 1189 ++YYCURSOR;
1096 goto yy136; 1190 goto yy141;
1097yy141: 1191yy146:
1098 yych = *++YYCURSOR; 1192 yych = *++YYCURSOR;
1099 if (yych <= '@') { 1193 if (yych <= '@') {
1100 if (yych <= ')') { 1194 if (yych <= ')') {
1101 if (yych <= '(') goto yy129; 1195 if (yych <= '(') goto yy134;
1102 yyt4 = YYCURSOR; 1196 yyt4 = YYCURSOR;
1103 goto yy140; 1197 goto yy145;
1104 } else { 1198 } else {
1105 if (yych <= '/') goto yy129; 1199 if (yych <= '/') goto yy134;
1106 if (yych <= '9') goto yy141; 1200 if (yych <= '9') goto yy146;
1107 goto yy129; 1201 goto yy134;
1108 } 1202 }
1109 } else { 1203 } else {
1110 if (yych <= '_') { 1204 if (yych <= '_') {
1111 if (yych <= 'Z') goto yy141; 1205 if (yych <= 'Z') goto yy146;
1112 if (yych <= '^') goto yy129; 1206 if (yych <= '^') goto yy134;
1113 goto yy141; 1207 goto yy146;
1114 } else { 1208 } else {
1115 if (yych <= '`') goto yy129; 1209 if (yych <= '`') goto yy134;
1116 if (yych <= 'z') goto yy141; 1210 if (yych <= 'z') goto yy146;
1117 goto yy129; 1211 goto yy134;
1118 } 1212 }
1119 } 1213 }
1120yy143: 1214yy148:
1121 yych = *++YYCURSOR; 1215 yych = *++YYCURSOR;
1122 if (yych == ')') { 1216 if (yych == ')') {
1123 yyt4 = YYCURSOR; 1217 yyt4 = YYCURSOR;
1124 goto yy140; 1218 goto yy145;
1125 } 1219 }
1126 goto yy129; 1220 goto yy134;
1127yy144: 1221yy149:
1128 yych = *++YYCURSOR; 1222 yych = *++YYCURSOR;
1129 if (yybm[0+yych] & 64) { 1223 if (yybm[0+yych] & 64) {
1130 goto yy138; 1224 goto yy143;
1131 } 1225 }
1132 if (yych <= '\r') goto yy129; 1226 if (yych <= '\r') goto yy134;
1133 if (yych >= '#') goto yy144; 1227 if (yych >= '#') goto yy149;
1134 yych = *++YYCURSOR; 1228 yych = *++YYCURSOR;
1135 if (yybm[0+yych] & 128) { 1229 if (yybm[0+yych] & 128) {
1136 goto yy144; 1230 goto yy149;
1137 } 1231 }
1138 if (yych <= '\r') { 1232 if (yych <= '\r') {
1139 if (yych == '\n') goto yy129; 1233 if (yych == '\n') goto yy134;
1140 if (yych <= '\f') goto yy138; 1234 if (yych <= '\f') goto yy143;
1141 goto yy129; 1235 goto yy134;
1142 } else { 1236 } else {
1143 if (yych <= '"') { 1237 if (yych <= '"') {
1144 if (yych <= '!') goto yy138; 1238 if (yych <= '!') goto yy143;
1145 goto yy143; 1239 goto yy148;
1146 } else { 1240 } else {
1147 if (yych != ')') goto yy138; 1241 if (yych != ')') goto yy143;
1148 yyt4 = YYCURSOR; 1242 yyt4 = YYCURSOR;
1149 } 1243 }
1150 } 1244 }
1151 yyaccept = 2; 1245 yyaccept = 2;
1152 yych = *(YYMARKER = ++YYCURSOR); 1246 yych = *(YYMARKER = ++YYCURSOR);
1153 if (yybm[0+yych] & 64) { 1247 if (yybm[0+yych] & 64) {
1154 goto yy138; 1248 goto yy143;
1155 } 1249 }
1156 if (yych <= '\r') goto yy136; 1250 if (yych <= '\r') goto yy141;
1157 if (yych <= '"') goto yy143; 1251 if (yych <= '"') goto yy148;
1158 goto yy144; 1252 goto yy149;
1159 } 1253 }
1160} 1254}
1161 1255
diff --git a/src/sp_config_scanner.re b/src/sp_config_scanner.re
index b36423b..f911df3 100644
--- a/src/sp_config_scanner.re
+++ b/src/sp_config_scanner.re
@@ -71,20 +71,60 @@ static void str_dtor(zval *zv) {
71 zend_string_release_ex(Z_STR_P(zv), 1); 71 zend_string_release_ex(Z_STR_P(zv), 1);
72} 72}
73 73
74static int apply_op(int v1, char op, int v2, int neg) { 74// sy_ functions and macros are helpers for the shunting yard algorithm
75 if (neg) { v2 = !v2; } 75#define sy_res_push(val) \
76 if (cond_res_i >= 100) { cs_error_log("condition too complex on line %d", lineno); goto out; } \
77 cond_res[cond_res_i++] = val;
78#define sy_res_pop() cond_res[--cond_res_i]
79#define sy_op_push(op) \
80 if (cond_op_i >= 100) { cs_error_log("condition too complex on line %d", lineno); goto out; } \
81 cond_op[cond_op_i++] = op;
82#define sy_op_pop() cond_op[--cond_op_i]
83#define sy_op_peek() cond_op[cond_op_i-1]
84
85static inline int sy_op_precedence(char op) {
76 switch (op) { 86 switch (op) {
77 case 0: return v2; 87 case '!': return 120;
78 case '&': return (v1 && v2); 88 case '<':
79 case '|': return (v1 || v2); 89 case '>':
80 case '<': return (v1 < v2); 90 case 'L': // <=
81 case '>': return (v1 > v2); 91 case 'G': // >=
82 case '=': return (v1 == v2); 92 return 90;
93 case '&': return 70;
94 case '|': return 60;
95 case '=': return 20;
83 } 96 }
84 return 0; 97 return 0;
85} 98}
99static inline int sy_op_is_left_assoc(char op) {
100 switch (op) {
101 case '!': return 0;
102 }
103 return 1;
104}
105static int sy_apply_op(char op, int a, int b) {
106 switch (op) {
107 case '!': return !a;
108 case '&': return (b && a);
109 case '|': return (b || a);
110 case '<': return (b < a);
111 case 'L': return (b <= a);
112 case 'G': return (b >= a);
113 case '>': return (b > a);
114 case '=': return (b == a);
115 }
116 return 0;
117}
118
119#define SY_APPLY_OP_FROM_STACK() \
120 char op = sy_op_pop(); \
121 int unary = (op == '!'); \
122 if (cond_res_i < (2 - unary)) { cs_error_log("not enough input on line %d", lineno); goto out; } \
123 int a = sy_res_pop(); \
124 int b = unary ? 0 : sy_res_pop(); \
125 int res = sy_apply_op(op, a, b); \
126 sy_res_push(res);
86 127
87#define APPLY_OP(v2) cond_res = apply_op(cond_res, cond_op, v2, cond_neg); cond_op = cond_neg = 0;
88 128
89zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*)) 129zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*))
90{ 130{
@@ -100,10 +140,13 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key
100 140
101 HashTable vars; 141 HashTable vars;
102 zend_hash_init(&vars, 10, NULL, str_dtor, 1); 142 zend_hash_init(&vars, 10, NULL, str_dtor, 1);
143 zend_hash_str_add_ptr(&vars, ZEND_STRL("PHP_VERSION_ID"), zend_string_init(ZEND_STRL(ZEND_TOSTR(PHP_VERSION_ID)), 1));
103 144
104 int cond_res = 1; 145
105 char cond_op = 0; 146 int cond_res[100] = {0};
106 int cond_neg = 0; 147 int cond_res_i = 0;
148 char cond_op[100] = {0};
149 int cond_op_i = 0;
107 150
108 int cond = yycinit; 151 int cond = yycinit;
109 long lineno = 1; 152 long lineno = 1;
@@ -141,14 +184,14 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key
141 goto yyc_init; 184 goto yyc_init;
142 } 185 }
143 <init> "@condition" ws+ { goto yyc_cond; } 186 <init> "@condition" ws+ { goto yyc_cond; }
144 <init> "@end_condition" ws* ";" { cond_res = 1; goto yyc_init; } 187 <init> "@end_condition" ws* ";" { cond_res[0] = 1; goto yyc_init; }
145 188
146 <cond> ws+ { goto yyc_cond; } 189 <cond> ws+ { goto yyc_cond; }
147 <cond> nl { lineno++; goto yyc_cond; } 190 <cond> nl { lineno++; goto yyc_cond; }
148 <cond> @t1 keyword @t2 "(" @t3 string? @t4 ")" { 191 <cond> @t1 keyword @t2 "(" @t3 string? @t4 ")" {
149 if (t4-t3 >= 2 && strlen("extension_loaded") == t2-t1 && strncmp("extension_loaded", t1, t2-t1) == 0) { 192 if (t4-t3 >= 2 && strlen("extension_loaded") == t2-t1 && strncmp("extension_loaded", t1, t2-t1) == 0) {
150 int is_loaded = (zend_hash_str_find_ptr(&module_registry, t3+1, t4-t3-2) != NULL); 193 int is_loaded = (zend_hash_str_find_ptr(&module_registry, t3+1, t4-t3-2) != NULL);
151 APPLY_OP(is_loaded); 194 sy_res_push(is_loaded);
152 } else { 195 } else {
153 cs_error_log("unknown function in condition on line %d", lineno); 196 cs_error_log("unknown function in condition on line %d", lineno);
154 goto out; 197 goto out;
@@ -161,21 +204,52 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key
161 cs_error_log("unknown variable in condition on line %d", lineno); 204 cs_error_log("unknown variable in condition on line %d", lineno);
162 goto out; 205 goto out;
163 } 206 }
164 APPLY_OP(atoi(ZSTR_VAL(tmp))); 207 sy_res_push(atoi(ZSTR_VAL(tmp)));
165 goto yyc_cond_op; 208 goto yyc_cond_op;
166 } 209 }
167 <cond> @t1 [0-9]+ @t2 { APPLY_OP(atoi(t1)); goto yyc_cond_op; } 210 <cond> @t1 [0-9]+ @t2 { sy_res_push(atoi(t1)); goto yyc_cond_op; }
168 <cond> @t1 "!" { cond_neg = (cond_neg + 1) % 2; goto yyc_cond; } 211 <cond> @t1 "!" { sy_op_push(*t1); goto yyc_cond; }
212 <cond> @t1 "(" { sy_op_push(*t1); goto yyc_cond; }
169 <cond_op> ws+ { goto yyc_cond_op; } 213 <cond_op> ws+ { goto yyc_cond_op; }
170 <cond_op> nl { lineno++; goto yyc_cond_op; } 214 <cond_op> nl { lineno++; goto yyc_cond_op; }
171 <cond_op> @t1 ( "&&" | "||" | "<" | ">" | "==" ) { cond_op = *t1; goto yyc_cond; } 215 <cond_op> @t1 ( "&&" | "||" | "<" | ">" | "==" | "<=" | ">=") @t2 {
172 <cond_op> ";" { goto yyc_init; } 216 char op1 = *t1;
173 <cond, cond_op> * { cs_error_log("Syntax error in condition on line %d", lineno); return false; } 217 if (t2-t1 == 2) {
218 switch (op1) {
219 case '<': op1 = 'L'; break; // <=
220 case '>': op1 = 'G'; break; // >=
221 }
222 }
223 while (cond_op_i && sy_op_peek() != '(' && ((sy_op_precedence(sy_op_peek()) > sy_op_precedence(*t1)) || (sy_op_precedence(sy_op_peek()) == sy_op_precedence(*t1)) && sy_op_is_left_assoc(*t1))) {
224 SY_APPLY_OP_FROM_STACK();
225 }
226 sy_op_push(*t1);
227 goto yyc_cond;
228 }
229 <cond_op> ")" {
230 while (cond_op_i && sy_op_peek() != '(') {
231 SY_APPLY_OP_FROM_STACK();
232 }
233 if (cond_op_i == 0 || sy_op_peek() != '(') {
234 cs_error_log("unbalanced parathesis on line %d", lineno); goto out;
235 }
236 sy_op_pop();
237 goto yyc_cond_op;
238 }
239 <cond_op> ";" {
240 while (cond_op_i) {
241 if (sy_op_peek() == '(') { cs_error_log("unbalanced parathesis on line %d", lineno); goto out; }
242 SY_APPLY_OP_FROM_STACK();
243 }
244 if (cond_res_i > 1) { cs_error_log("invalid condition on line %d", lineno); goto out; }
245 goto yyc_init;
246 }
247 <cond, cond_op> * { cs_error_log("Syntax error in condition on line %d", lineno); goto out; }
174 248
175 <rule> ws+ { goto yyc_rule; } 249 <rule> ws+ { goto yyc_rule; }
176 <rule> nl / ( nl | ws )* "." { lineno++; goto yyc_rule; } 250 <rule> nl / ( nl | ws )* "." { lineno++; goto yyc_rule; }
177 <rule> "." @t1 keyword @t2 ( "(" @t3 ( string? | keyword ) @t4 ")" )? { 251 <rule> "." @t1 keyword @t2 ( "(" @t3 ( string? | keyword ) @t4 ")" )? {
178 if (!cond_res) { goto yyc_rule; } 252 if (!cond_res[0]) { goto yyc_rule; }
179 if (kw_i == max_keywords) { 253 if (kw_i == max_keywords) {
180 cs_error_log("Too many keywords in rule (more than %d) on line %d", max_keywords, lineno); 254 cs_error_log("Too many keywords in rule (more than %d) on line %d", max_keywords, lineno);
181 goto out; 255 goto out;
@@ -206,7 +280,7 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key
206 } 280 }
207 <rule> ";" { 281 <rule> ";" {
208 end_of_rule: 282 end_of_rule:
209 if (!cond_res) { goto yyc_init; } 283 if (!cond_res[0]) { goto yyc_init; }
210 parsed_rule[kw_i++] = (sp_parsed_keyword){0, 0, 0, 0, 0, 0}; 284 parsed_rule[kw_i++] = (sp_parsed_keyword){0, 0, 0, 0, 0, 0};
211 if (process_rule && process_rule(parsed_rule) != SUCCESS) { 285 if (process_rule && process_rule(parsed_rule) != SUCCESS) {
212 goto out; 286 goto out;