diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-26 18:32:43 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-26 18:32:43 +0100 |
| commit | 7d32e25bf33c98af6878715907ebbf297ef3d64a (patch) | |
| tree | 94de45b3d5b0ab4b093e48a53b85d94d1c3327d9 | |
| parent | 63ad7993845fbf59264e22295ae9c06250832119 (diff) | |
| download | busybox-w32-7d32e25bf33c98af6878715907ebbf297ef3d64a.tar.gz busybox-w32-7d32e25bf33c98af6878715907ebbf297ef3d64a.tar.bz2 busybox-w32-7d32e25bf33c98af6878715907ebbf297ef3d64a.zip | |
bc: prepare for char-by-char input handling
function old new delta
peek_inbuf - 292 +292
parse_lex_by_checking_eq_sign - 26 +26
eat_inbuf - 22 +22
zbc_vm_execute_FILE 52 61 +9
bc_lex_lineComment 29 30 +1
zbc_lex_number 174 172 -2
bc_vm_run 104 99 -5
zbc_num_divmod 156 150 -6
bc_lex_file 24 - -24
bc_lex_assign 26 - -26
zbc_lex_next 1982 1587 -395
------------------------------------------------------------------------------
(add/remove: 3/2 grow/shrink: 2/4 up/down: 350/-458) Total: -108 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | miscutils/bc.c | 443 | ||||
| -rw-r--r-- | testsuite/dc_strings_results.txt | 8 |
2 files changed, 214 insertions, 237 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index f4e499f13..5789869a7 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
| @@ -713,7 +713,6 @@ dc_LEX_to_INST[] = { // starts at XC_LEX_OP_POWER // corresponding XC/DC_L | |||
| 713 | typedef struct BcParse { | 713 | typedef struct BcParse { |
| 714 | smallint lex; // was BcLexType // first member is most used | 714 | smallint lex; // was BcLexType // first member is most used |
| 715 | smallint lex_last; // was BcLexType | 715 | smallint lex_last; // was BcLexType |
| 716 | bool lex_newline; | ||
| 717 | size_t lex_line; | 716 | size_t lex_line; |
| 718 | const char *lex_inbuf; | 717 | const char *lex_inbuf; |
| 719 | const char *lex_end; | 718 | const char *lex_end; |
| @@ -2741,147 +2740,6 @@ static BC_STATUS zbc_num_parse(BcNum *n, const char *val, unsigned base_t) | |||
| 2741 | } | 2740 | } |
| 2742 | #define zbc_num_parse(...) (zbc_num_parse(__VA_ARGS__) COMMA_SUCCESS) | 2741 | #define zbc_num_parse(...) (zbc_num_parse(__VA_ARGS__) COMMA_SUCCESS) |
| 2743 | 2742 | ||
| 2744 | static void bc_lex_lineComment(void) | ||
| 2745 | { | ||
| 2746 | BcParse *p = &G.prs; | ||
| 2747 | // Try: echo -n '#foo' | bc | ||
| 2748 | p->lex = XC_LEX_WHITESPACE; | ||
| 2749 | while (p->lex_inbuf < p->lex_end && *p->lex_inbuf != '\n') | ||
| 2750 | p->lex_inbuf++; | ||
| 2751 | } | ||
| 2752 | |||
| 2753 | static void bc_lex_whitespace(void) | ||
| 2754 | { | ||
| 2755 | BcParse *p = &G.prs; | ||
| 2756 | p->lex = XC_LEX_WHITESPACE; | ||
| 2757 | for (;;) { | ||
| 2758 | char c = *p->lex_inbuf; | ||
| 2759 | if (c == '\n') // this is XC_LEX_NLINE, not XC_LEX_WHITESPACE | ||
| 2760 | break; | ||
| 2761 | if (!isspace(c)) | ||
| 2762 | break; | ||
| 2763 | p->lex_inbuf++; | ||
| 2764 | } | ||
| 2765 | } | ||
| 2766 | |||
| 2767 | static BC_STATUS zbc_lex_number(char start) | ||
| 2768 | { | ||
| 2769 | BcParse *p = &G.prs; | ||
| 2770 | const char *buf = p->lex_inbuf; | ||
| 2771 | size_t len, i, ccnt; | ||
| 2772 | bool pt; | ||
| 2773 | |||
| 2774 | pt = (start == '.'); | ||
| 2775 | p->lex = XC_LEX_NUMBER; | ||
| 2776 | ccnt = i = 0; | ||
| 2777 | for (;;) { | ||
| 2778 | char c = buf[i]; | ||
| 2779 | if (c == '\0') | ||
| 2780 | break; | ||
| 2781 | if (c == '\\' && buf[i + 1] == '\n') { | ||
| 2782 | i += 2; | ||
| 2783 | //number_of_backslashes++ - see comment below | ||
| 2784 | continue; | ||
| 2785 | } | ||
| 2786 | if (!isdigit(c) && (c < 'A' || c > 'F')) { | ||
| 2787 | if (c != '.') break; | ||
| 2788 | // if '.' was already seen, stop on second one: | ||
| 2789 | if (pt) break; | ||
| 2790 | pt = true; | ||
| 2791 | } | ||
| 2792 | // buf[i] is one of "0-9A-F." | ||
| 2793 | i++; | ||
| 2794 | if (c != '.') | ||
| 2795 | ccnt = i; | ||
| 2796 | } | ||
| 2797 | //ccnt is the number of chars in the number string, excluding possible | ||
| 2798 | //trailing "[\<newline>].[\<newline>]" (with any number of \<NL> repetitions). | ||
| 2799 | //i is buf[i] index of the first not-yet-parsed char after that. | ||
| 2800 | p->lex_inbuf += i; | ||
| 2801 | |||
| 2802 | // This might overestimate the size, if there are "\<NL>"'s | ||
| 2803 | // in the number. Subtracting number_of_backslashes*2 correctly | ||
| 2804 | // is not that easy: consider that in the case of "NNN.\<NL>" | ||
| 2805 | // loop above will count "\<NL>" before it realizes it is not | ||
| 2806 | // in fact *inside* the number: | ||
| 2807 | len = ccnt + 1; // +1 byte for NUL termination | ||
| 2808 | |||
| 2809 | // This check makes sense only if size_t is (much) larger than BC_MAX_NUM. | ||
| 2810 | if (SIZE_MAX > (BC_MAX_NUM | 0xff)) { | ||
| 2811 | if (len > BC_MAX_NUM) | ||
| 2812 | RETURN_STATUS(bc_error("number too long: must be [1,"BC_MAX_NUM_STR"]")); | ||
| 2813 | } | ||
| 2814 | |||
| 2815 | bc_vec_pop_all(&p->lex_strnumbuf); | ||
| 2816 | bc_vec_expand(&p->lex_strnumbuf, 1 + len); | ||
| 2817 | bc_vec_push(&p->lex_strnumbuf, &start); | ||
| 2818 | |||
| 2819 | while (ccnt != 0) { | ||
| 2820 | // If we have hit a backslash, skip it. We don't have | ||
| 2821 | // to check for a newline because it's guaranteed. | ||
| 2822 | if (*buf == '\\') { | ||
| 2823 | buf += 2; | ||
| 2824 | ccnt -= 2; | ||
| 2825 | continue; | ||
| 2826 | } | ||
| 2827 | bc_vec_push(&p->lex_strnumbuf, buf); | ||
| 2828 | buf++; | ||
| 2829 | ccnt--; | ||
| 2830 | } | ||
| 2831 | |||
| 2832 | bc_vec_pushZeroByte(&p->lex_strnumbuf); | ||
| 2833 | |||
| 2834 | RETURN_STATUS(BC_STATUS_SUCCESS); | ||
| 2835 | } | ||
| 2836 | #define zbc_lex_number(...) (zbc_lex_number(__VA_ARGS__) COMMA_SUCCESS) | ||
| 2837 | |||
| 2838 | static void bc_lex_name(void) | ||
| 2839 | { | ||
| 2840 | BcParse *p = &G.prs; | ||
| 2841 | size_t i; | ||
| 2842 | const char *buf; | ||
| 2843 | |||
| 2844 | p->lex = XC_LEX_NAME; | ||
| 2845 | |||
| 2846 | i = 0; | ||
| 2847 | buf = p->lex_inbuf - 1; | ||
| 2848 | for (;;) { | ||
| 2849 | char c = buf[i]; | ||
| 2850 | if ((c < 'a' || c > 'z') && !isdigit(c) && c != '_') break; | ||
| 2851 | i++; | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | #if 0 // We do not protect against people with gigabyte-long names | ||
| 2855 | // This check makes sense only if size_t is (much) larger than BC_MAX_STRING. | ||
| 2856 | if (SIZE_MAX > (BC_MAX_STRING | 0xff)) { | ||
| 2857 | if (i > BC_MAX_STRING) | ||
| 2858 | return bc_error("name too long: must be [1,"BC_MAX_STRING_STR"]"); | ||
| 2859 | } | ||
| 2860 | #endif | ||
| 2861 | bc_vec_string(&p->lex_strnumbuf, i, buf); | ||
| 2862 | |||
| 2863 | // Increment the index. We minus 1 because it has already been incremented. | ||
| 2864 | p->lex_inbuf += i - 1; | ||
| 2865 | |||
| 2866 | //return BC_STATUS_SUCCESS; | ||
| 2867 | } | ||
| 2868 | |||
| 2869 | static void bc_lex_init(void) | ||
| 2870 | { | ||
| 2871 | bc_char_vec_init(&G.prs.lex_strnumbuf); | ||
| 2872 | } | ||
| 2873 | |||
| 2874 | static void bc_lex_free(void) | ||
| 2875 | { | ||
| 2876 | bc_vec_free(&G.prs.lex_strnumbuf); | ||
| 2877 | } | ||
| 2878 | |||
| 2879 | static void bc_lex_file(void) | ||
| 2880 | { | ||
| 2881 | G.err_line = G.prs.lex_line = 1; | ||
| 2882 | G.prs.lex_newline = false; | ||
| 2883 | } | ||
| 2884 | |||
| 2885 | static bool bc_lex_more_input(void) | 2743 | static bool bc_lex_more_input(void) |
| 2886 | { | 2744 | { |
| 2887 | BcParse *p = &G.prs; | 2745 | BcParse *p = &G.prs; |
| @@ -2996,6 +2854,147 @@ static bool bc_lex_more_input(void) | |||
| 2996 | return G.input_buffer.len > 1; | 2854 | return G.input_buffer.len > 1; |
| 2997 | } | 2855 | } |
| 2998 | 2856 | ||
| 2857 | // p->lex_inbuf points to the current string to be parsed. | ||
| 2858 | // if p->lex_inbuf points to '\0', it's either EOF or it points after | ||
| 2859 | // last processed line's terminating '\n' (and more reading needs to be done | ||
| 2860 | // to get next character). | ||
| 2861 | // | ||
| 2862 | // If you are in a situation where that is a possibility, call peek_inbuf(). | ||
| 2863 | // If necessary, it performs more reading and changes p->lex_inbuf, | ||
| 2864 | // then it returns *p->lex_inbuf (which will be '\0' only if it's EOF). | ||
| 2865 | // After it, just referencing *p->lex_inbuf is valid, and if it wasn't '\0', | ||
| 2866 | // it's ok to do p->lex_inbuf++ once without end-of-buffer checking. | ||
| 2867 | // | ||
| 2868 | // eat_inbuf() is equvalent to "peek_inbuf(); if (c) p->lex_inbuf++": | ||
| 2869 | // it returns current char and advances the pointer (if not EOF). | ||
| 2870 | // After eat_inbuf(), referencing p->lex_inbuf[-1] and *p->lex_inbuf is valid. | ||
| 2871 | // | ||
| 2872 | // In many cases, you can use fast *p->lex_inbuf instead of peek_inbuf(): | ||
| 2873 | // unless prev char might have been '\n', *p->lex_inbuf is '\0' ONLY | ||
| 2874 | // on real EOF, not end-of-buffer. | ||
| 2875 | static char peek_inbuf(void) | ||
| 2876 | { | ||
| 2877 | if (G.prs.lex_inbuf == G.prs.lex_end) { | ||
| 2878 | if (G.prs.lex_input_fp) | ||
| 2879 | if (!bc_lex_more_input()) | ||
| 2880 | G.prs.lex_input_fp = NULL; | ||
| 2881 | } | ||
| 2882 | return *G.prs.lex_inbuf; | ||
| 2883 | } | ||
| 2884 | static char eat_inbuf(void) | ||
| 2885 | { | ||
| 2886 | char c = peek_inbuf(); | ||
| 2887 | if (c) G.prs.lex_inbuf++; | ||
| 2888 | return c; | ||
| 2889 | } | ||
| 2890 | |||
| 2891 | static void bc_lex_lineComment(void) | ||
| 2892 | { | ||
| 2893 | BcParse *p = &G.prs; | ||
| 2894 | char c; | ||
| 2895 | |||
| 2896 | // Try: echo -n '#foo' | bc | ||
| 2897 | p->lex = XC_LEX_WHITESPACE; | ||
| 2898 | |||
| 2899 | // We depend here on input being done in whole lines: | ||
| 2900 | // '\0' which isn't the EOF can only be seen after '\n'. | ||
| 2901 | while ((c = *p->lex_inbuf) != '\n' && c != '\0') | ||
| 2902 | p->lex_inbuf++; | ||
| 2903 | } | ||
| 2904 | |||
| 2905 | static void bc_lex_whitespace(void) | ||
| 2906 | { | ||
| 2907 | BcParse *p = &G.prs; | ||
| 2908 | |||
| 2909 | p->lex = XC_LEX_WHITESPACE; | ||
| 2910 | for (;;) { | ||
| 2911 | // We depend here on input being done in whole lines: | ||
| 2912 | // '\0' which isn't the EOF can only be seen after '\n'. | ||
| 2913 | char c = *p->lex_inbuf; | ||
| 2914 | if (c == '\n') // this is XC_LEX_NLINE, not XC_LEX_WHITESPACE | ||
| 2915 | break; | ||
| 2916 | if (!isspace(c)) | ||
| 2917 | break; | ||
| 2918 | p->lex_inbuf++; | ||
| 2919 | } | ||
| 2920 | } | ||
| 2921 | |||
| 2922 | static BC_STATUS zbc_lex_number(char last) | ||
| 2923 | { | ||
| 2924 | BcParse *p = &G.prs; | ||
| 2925 | bool pt; | ||
| 2926 | |||
| 2927 | bc_vec_pop_all(&p->lex_strnumbuf); | ||
| 2928 | bc_vec_pushByte(&p->lex_strnumbuf, last); | ||
| 2929 | |||
| 2930 | pt = (last == '.'); | ||
| 2931 | p->lex = XC_LEX_NUMBER; | ||
| 2932 | for (;;) { | ||
| 2933 | // We depend here on input being done in whole lines: | ||
| 2934 | // '\0' which isn't the EOF can only be seen after '\n'. | ||
| 2935 | char c = *p->lex_inbuf; | ||
| 2936 | check_c: | ||
| 2937 | if (c == '\0') | ||
| 2938 | break; | ||
| 2939 | if (c == '\\' && p->lex_inbuf[1] == '\n') { | ||
| 2940 | p->lex_inbuf += 2; | ||
| 2941 | p->lex_line++; | ||
| 2942 | c = peek_inbuf(); // force next line to be read | ||
| 2943 | goto check_c; | ||
| 2944 | } | ||
| 2945 | if (!isdigit(c) && (c < 'A' || c > 'F')) { | ||
| 2946 | if (c != '.') break; | ||
| 2947 | // if '.' was already seen, stop on second one: | ||
| 2948 | if (pt) break; | ||
| 2949 | pt = true; | ||
| 2950 | } | ||
| 2951 | // c is one of "0-9A-F." | ||
| 2952 | last = c; | ||
| 2953 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); | ||
| 2954 | p->lex_inbuf++; | ||
| 2955 | } | ||
| 2956 | if (last == '.') // remove trailing '.' if any | ||
| 2957 | bc_vec_pop(&p->lex_strnumbuf); | ||
| 2958 | bc_vec_pushZeroByte(&p->lex_strnumbuf); | ||
| 2959 | |||
| 2960 | G.err_line = G.prs.lex_line; | ||
| 2961 | RETURN_STATUS(BC_STATUS_SUCCESS); | ||
| 2962 | } | ||
| 2963 | #define zbc_lex_number(...) (zbc_lex_number(__VA_ARGS__) COMMA_SUCCESS) | ||
| 2964 | |||
| 2965 | static void bc_lex_name(void) | ||
| 2966 | { | ||
| 2967 | BcParse *p = &G.prs; | ||
| 2968 | size_t i; | ||
| 2969 | const char *buf; | ||
| 2970 | |||
| 2971 | p->lex = XC_LEX_NAME; | ||
| 2972 | |||
| 2973 | // Since names can't cross lines with \<newline>, | ||
| 2974 | // we depend on the fact that whole line is in the buffer | ||
| 2975 | i = 0; | ||
| 2976 | buf = p->lex_inbuf - 1; | ||
| 2977 | for (;;) { | ||
| 2978 | char c = buf[i]; | ||
| 2979 | if ((c < 'a' || c > 'z') && !isdigit(c) && c != '_') break; | ||
| 2980 | i++; | ||
| 2981 | } | ||
| 2982 | |||
| 2983 | #if 0 // We do not protect against people with gigabyte-long names | ||
| 2984 | // This check makes sense only if size_t is (much) larger than BC_MAX_STRING. | ||
| 2985 | if (SIZE_MAX > (BC_MAX_STRING | 0xff)) { | ||
| 2986 | if (i > BC_MAX_STRING) | ||
| 2987 | return bc_error("name too long: must be [1,"BC_MAX_STRING_STR"]"); | ||
| 2988 | } | ||
| 2989 | #endif | ||
| 2990 | bc_vec_string(&p->lex_strnumbuf, i, buf); | ||
| 2991 | |||
| 2992 | // Increment the index. We minus 1 because it has already been incremented. | ||
| 2993 | p->lex_inbuf += i - 1; | ||
| 2994 | |||
| 2995 | //return BC_STATUS_SUCCESS; | ||
| 2996 | } | ||
| 2997 | |||
| 2999 | IF_BC(static BC_STATUS zbc_lex_token(void);) | 2998 | IF_BC(static BC_STATUS zbc_lex_token(void);) |
| 3000 | IF_DC(static BC_STATUS zdc_lex_token(void);) | 2999 | IF_DC(static BC_STATUS zdc_lex_token(void);) |
| 3001 | #define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS) | 3000 | #define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS) |
| @@ -3007,26 +3006,18 @@ static BC_STATUS zbc_lex_next(void) | |||
| 3007 | BcStatus s; | 3006 | BcStatus s; |
| 3008 | 3007 | ||
| 3009 | p->lex_last = p->lex; | 3008 | p->lex_last = p->lex; |
| 3010 | if (p->lex_last == XC_LEX_EOF) RETURN_STATUS(bc_error("end of file")); | 3009 | if (p->lex_last == XC_LEX_EOF) |
| 3011 | 3010 | RETURN_STATUS(bc_error("end of file")); | |
| 3012 | p->lex_line += p->lex_newline; | ||
| 3013 | G.err_line = p->lex_line; | ||
| 3014 | p->lex_newline = false; | ||
| 3015 | 3011 | ||
| 3016 | // Loop until failure or we don't have whitespace. This | 3012 | // Loop until failure or we don't have whitespace. This |
| 3017 | // is so the parser doesn't get inundated with whitespace. | 3013 | // is so the parser doesn't get inundated with whitespace. |
| 3018 | // Comments are also XC_LEX_WHITESPACE tokens and eaten here. | 3014 | // Comments are also XC_LEX_WHITESPACE tokens and eaten here. |
| 3019 | s = BC_STATUS_SUCCESS; | 3015 | s = BC_STATUS_SUCCESS; |
| 3020 | do { | 3016 | do { |
| 3021 | if (p->lex_inbuf == p->lex_end) { | 3017 | if (*p->lex_inbuf == '\0') { |
| 3022 | p->lex = XC_LEX_EOF; | 3018 | p->lex = XC_LEX_EOF; |
| 3023 | if (!G.prs.lex_input_fp) | 3019 | if (peek_inbuf() == '\0') |
| 3024 | RETURN_STATUS(BC_STATUS_SUCCESS); | 3020 | RETURN_STATUS(BC_STATUS_SUCCESS); |
| 3025 | if (!bc_lex_more_input()) { | ||
| 3026 | G.prs.lex_input_fp = NULL; | ||
| 3027 | RETURN_STATUS(BC_STATUS_SUCCESS); | ||
| 3028 | } | ||
| 3029 | // here it's guaranteed that p->lex_ibuf is below p->lex_end | ||
| 3030 | } | 3021 | } |
| 3031 | p->lex_next_at = p->lex_inbuf; | 3022 | p->lex_next_at = p->lex_inbuf; |
| 3032 | dbg_lex("next string to parse:'%.*s'", | 3023 | dbg_lex("next string to parse:'%.*s'", |
| @@ -3126,80 +3117,70 @@ static BC_STATUS zbc_lex_identifier(void) | |||
| 3126 | static BC_STATUS zbc_lex_string(void) | 3117 | static BC_STATUS zbc_lex_string(void) |
| 3127 | { | 3118 | { |
| 3128 | BcParse *p = &G.prs; | 3119 | BcParse *p = &G.prs; |
| 3129 | size_t len, nls, i; | ||
| 3130 | 3120 | ||
| 3131 | p->lex = XC_LEX_STR; | 3121 | p->lex = XC_LEX_STR; |
| 3132 | 3122 | bc_vec_pop_all(&p->lex_strnumbuf); | |
| 3133 | nls = 0; | ||
| 3134 | i = 0; | ||
| 3135 | for (;;) { | 3123 | for (;;) { |
| 3136 | char c = p->lex_inbuf[i]; | 3124 | char c = peek_inbuf(); // strings can cross lines |
| 3137 | if (c == '\0') { | 3125 | if (c == '\0') { |
| 3138 | p->lex_inbuf += i; | 3126 | RETURN_STATUS(bc_error("unterminated string1")); |
| 3139 | RETURN_STATUS(bc_error("unterminated string")); | ||
| 3140 | } | 3127 | } |
| 3141 | if (c == '"') | 3128 | if (c == '"') |
| 3142 | break; | 3129 | break; |
| 3143 | nls += (c == '\n'); | 3130 | if (c == '\n') |
| 3144 | i++; | 3131 | p->lex_line++; |
| 3145 | } | 3132 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); |
| 3146 | 3133 | p->lex_inbuf++; | |
| 3147 | len = i; | ||
| 3148 | // This check makes sense only if size_t is (much) larger than BC_MAX_STRING. | ||
| 3149 | if (SIZE_MAX > (BC_MAX_STRING | 0xff)) { | ||
| 3150 | if (len > BC_MAX_STRING) | ||
| 3151 | RETURN_STATUS(bc_error("string too long: must be [1,"BC_MAX_STRING_STR"]")); | ||
| 3152 | } | 3134 | } |
| 3153 | bc_vec_string(&p->lex_strnumbuf, len, p->lex_inbuf); | 3135 | bc_vec_pushZeroByte(&p->lex_strnumbuf); |
| 3136 | p->lex_inbuf++; | ||
| 3154 | 3137 | ||
| 3155 | p->lex_inbuf += i + 1; | ||
| 3156 | p->lex_line += nls; | ||
| 3157 | G.err_line = p->lex_line; | 3138 | G.err_line = p->lex_line; |
| 3158 | |||
| 3159 | RETURN_STATUS(BC_STATUS_SUCCESS); | 3139 | RETURN_STATUS(BC_STATUS_SUCCESS); |
| 3160 | } | 3140 | } |
| 3161 | #define zbc_lex_string(...) (zbc_lex_string(__VA_ARGS__) COMMA_SUCCESS) | 3141 | #define zbc_lex_string(...) (zbc_lex_string(__VA_ARGS__) COMMA_SUCCESS) |
| 3162 | 3142 | ||
| 3163 | static void bc_lex_assign(unsigned with_and_without) | 3143 | static void parse_lex_by_checking_eq_sign(unsigned with_and_without) |
| 3164 | { | 3144 | { |
| 3165 | BcParse *p = &G.prs; | 3145 | BcParse *p = &G.prs; |
| 3166 | if (*p->lex_inbuf == '=') { | 3146 | if (*p->lex_inbuf == '=') { |
| 3147 | // ^^^ not using peek_inbuf() since '==' etc can't be split across lines | ||
| 3167 | p->lex_inbuf++; | 3148 | p->lex_inbuf++; |
| 3168 | with_and_without >>= 8; // store "with" value | 3149 | with_and_without >>= 8; // store "with" value |
| 3169 | } // else store "without" value | 3150 | } // else store "without" value |
| 3170 | p->lex = (with_and_without & 0xff); | 3151 | p->lex = (with_and_without & 0xff); |
| 3171 | } | 3152 | } |
| 3172 | #define bc_lex_assign(with, without) \ | 3153 | #define parse_lex_by_checking_eq_sign(with, without) \ |
| 3173 | bc_lex_assign(((with)<<8)|(without)) | 3154 | parse_lex_by_checking_eq_sign(((with)<<8)|(without)) |
| 3174 | 3155 | ||
| 3175 | static BC_STATUS zbc_lex_comment(void) | 3156 | static BC_STATUS zbc_lex_comment(void) |
| 3176 | { | 3157 | { |
| 3177 | BcParse *p = &G.prs; | 3158 | BcParse *p = &G.prs; |
| 3178 | size_t i, nls = 0; | ||
| 3179 | const char *buf = p->lex_inbuf; | ||
| 3180 | 3159 | ||
| 3181 | p->lex = XC_LEX_WHITESPACE; | 3160 | p->lex = XC_LEX_WHITESPACE; |
| 3182 | i = 0; /* here lex_inbuf[0] is the '*' of opening comment delimiter */ | 3161 | // here lex_inbuf is at '*' of opening comment delimiter |
| 3183 | for (;;) { | 3162 | for (;;) { |
| 3184 | char c = buf[++i]; | 3163 | char c; |
| 3164 | |||
| 3165 | p->lex_inbuf++; | ||
| 3166 | c = peek_inbuf(); | ||
| 3185 | check_star: | 3167 | check_star: |
| 3186 | if (c == '*') { | 3168 | if (c == '*') { |
| 3187 | c = buf[++i]; | 3169 | p->lex_inbuf++; |
| 3170 | c = peek_inbuf(); | ||
| 3188 | if (c == '/') | 3171 | if (c == '/') |
| 3189 | break; | 3172 | break; |
| 3190 | goto check_star; | 3173 | goto check_star; |
| 3191 | } | 3174 | } |
| 3192 | if (c == '\0') { | 3175 | if (c == '\0') { |
| 3193 | p->lex_inbuf += i; | ||
| 3194 | RETURN_STATUS(bc_error("unterminated comment")); | 3176 | RETURN_STATUS(bc_error("unterminated comment")); |
| 3195 | } | 3177 | } |
| 3196 | nls += (c == '\n'); | 3178 | if (c == '\n') |
| 3179 | p->lex_line++; | ||
| 3197 | } | 3180 | } |
| 3181 | p->lex_inbuf++; // skip trailing '/' | ||
| 3198 | 3182 | ||
| 3199 | p->lex_inbuf += i + 1; | ||
| 3200 | p->lex_line += nls; | ||
| 3201 | G.err_line = p->lex_line; | 3183 | G.err_line = p->lex_line; |
| 3202 | |||
| 3203 | RETURN_STATUS(BC_STATUS_SUCCESS); | 3184 | RETURN_STATUS(BC_STATUS_SUCCESS); |
| 3204 | } | 3185 | } |
| 3205 | #define zbc_lex_comment(...) (zbc_lex_comment(__VA_ARGS__) COMMA_SUCCESS) | 3186 | #define zbc_lex_comment(...) (zbc_lex_comment(__VA_ARGS__) COMMA_SUCCESS) |
| @@ -3209,7 +3190,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3209 | { | 3190 | { |
| 3210 | BcParse *p = &G.prs; | 3191 | BcParse *p = &G.prs; |
| 3211 | BcStatus s = BC_STATUS_SUCCESS; | 3192 | BcStatus s = BC_STATUS_SUCCESS; |
| 3212 | char c = *p->lex_inbuf++; | 3193 | char c = eat_inbuf(); |
| 3213 | char c2; | 3194 | char c2; |
| 3214 | 3195 | ||
| 3215 | // This is the workhorse of the lexer. | 3196 | // This is the workhorse of the lexer. |
| @@ -3217,11 +3198,10 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3217 | // case '\0': // probably never reached | 3198 | // case '\0': // probably never reached |
| 3218 | // p->lex_inbuf--; | 3199 | // p->lex_inbuf--; |
| 3219 | // p->lex = XC_LEX_EOF; | 3200 | // p->lex = XC_LEX_EOF; |
| 3220 | // p->lex_newline = true; | ||
| 3221 | // break; | 3201 | // break; |
| 3222 | case '\n': | 3202 | case '\n': |
| 3203 | p->lex_line++; | ||
| 3223 | p->lex = XC_LEX_NLINE; | 3204 | p->lex = XC_LEX_NLINE; |
| 3224 | p->lex_newline = true; | ||
| 3225 | break; | 3205 | break; |
| 3226 | case '\t': | 3206 | case '\t': |
| 3227 | case '\v': | 3207 | case '\v': |
| @@ -3231,7 +3211,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3231 | bc_lex_whitespace(); | 3211 | bc_lex_whitespace(); |
| 3232 | break; | 3212 | break; |
| 3233 | case '!': | 3213 | case '!': |
| 3234 | bc_lex_assign(XC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT); | 3214 | parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT); |
| 3235 | if (p->lex == BC_LEX_OP_BOOL_NOT) { | 3215 | if (p->lex == BC_LEX_OP_BOOL_NOT) { |
| 3236 | s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("!"); | 3216 | s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("!"); |
| 3237 | if (s) RETURN_STATUS(s); | 3217 | if (s) RETURN_STATUS(s); |
| @@ -3246,7 +3226,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3246 | bc_lex_lineComment(); | 3226 | bc_lex_lineComment(); |
| 3247 | break; | 3227 | break; |
| 3248 | case '%': | 3228 | case '%': |
| 3249 | bc_lex_assign(BC_LEX_OP_ASSIGN_MODULUS, XC_LEX_OP_MODULUS); | 3229 | parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MODULUS, XC_LEX_OP_MODULUS); |
| 3250 | break; | 3230 | break; |
| 3251 | case '&': | 3231 | case '&': |
| 3252 | c2 = *p->lex_inbuf; | 3232 | c2 = *p->lex_inbuf; |
| @@ -3265,7 +3245,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3265 | p->lex = (BcLexType)(c - '(' + BC_LEX_LPAREN); | 3245 | p->lex = (BcLexType)(c - '(' + BC_LEX_LPAREN); |
| 3266 | break; | 3246 | break; |
| 3267 | case '*': | 3247 | case '*': |
| 3268 | bc_lex_assign(BC_LEX_OP_ASSIGN_MULTIPLY, XC_LEX_OP_MULTIPLY); | 3248 | parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MULTIPLY, XC_LEX_OP_MULTIPLY); |
| 3269 | break; | 3249 | break; |
| 3270 | case '+': | 3250 | case '+': |
| 3271 | c2 = *p->lex_inbuf; | 3251 | c2 = *p->lex_inbuf; |
| @@ -3273,7 +3253,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3273 | p->lex_inbuf++; | 3253 | p->lex_inbuf++; |
| 3274 | p->lex = BC_LEX_OP_INC; | 3254 | p->lex = BC_LEX_OP_INC; |
| 3275 | } else | 3255 | } else |
| 3276 | bc_lex_assign(BC_LEX_OP_ASSIGN_PLUS, XC_LEX_OP_PLUS); | 3256 | parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_PLUS, XC_LEX_OP_PLUS); |
| 3277 | break; | 3257 | break; |
| 3278 | case ',': | 3258 | case ',': |
| 3279 | p->lex = BC_LEX_COMMA; | 3259 | p->lex = BC_LEX_COMMA; |
| @@ -3284,7 +3264,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3284 | p->lex_inbuf++; | 3264 | p->lex_inbuf++; |
| 3285 | p->lex = BC_LEX_OP_DEC; | 3265 | p->lex = BC_LEX_OP_DEC; |
| 3286 | } else | 3266 | } else |
| 3287 | bc_lex_assign(BC_LEX_OP_ASSIGN_MINUS, XC_LEX_OP_MINUS); | 3267 | parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MINUS, XC_LEX_OP_MINUS); |
| 3288 | break; | 3268 | break; |
| 3289 | case '.': | 3269 | case '.': |
| 3290 | if (isdigit(*p->lex_inbuf)) | 3270 | if (isdigit(*p->lex_inbuf)) |
| @@ -3299,7 +3279,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3299 | if (c2 == '*') | 3279 | if (c2 == '*') |
| 3300 | s = zbc_lex_comment(); | 3280 | s = zbc_lex_comment(); |
| 3301 | else | 3281 | else |
| 3302 | bc_lex_assign(BC_LEX_OP_ASSIGN_DIVIDE, XC_LEX_OP_DIVIDE); | 3282 | parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_DIVIDE, XC_LEX_OP_DIVIDE); |
| 3303 | break; | 3283 | break; |
| 3304 | case '0': | 3284 | case '0': |
| 3305 | case '1': | 3285 | case '1': |
| @@ -3323,13 +3303,13 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3323 | p->lex = BC_LEX_SCOLON; | 3303 | p->lex = BC_LEX_SCOLON; |
| 3324 | break; | 3304 | break; |
| 3325 | case '<': | 3305 | case '<': |
| 3326 | bc_lex_assign(XC_LEX_OP_REL_LE, XC_LEX_OP_REL_LT); | 3306 | parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_LE, XC_LEX_OP_REL_LT); |
| 3327 | break; | 3307 | break; |
| 3328 | case '=': | 3308 | case '=': |
| 3329 | bc_lex_assign(XC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN); | 3309 | parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN); |
| 3330 | break; | 3310 | break; |
| 3331 | case '>': | 3311 | case '>': |
| 3332 | bc_lex_assign(XC_LEX_OP_REL_GE, XC_LEX_OP_REL_GT); | 3312 | parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_GE, XC_LEX_OP_REL_GT); |
| 3333 | break; | 3313 | break; |
| 3334 | case '[': | 3314 | case '[': |
| 3335 | case ']': | 3315 | case ']': |
| @@ -3343,7 +3323,7 @@ static BC_STATUS zbc_lex_token(void) | |||
| 3343 | s = bc_error_bad_character(c); | 3323 | s = bc_error_bad_character(c); |
| 3344 | break; | 3324 | break; |
| 3345 | case '^': | 3325 | case '^': |
| 3346 | bc_lex_assign(BC_LEX_OP_ASSIGN_POWER, XC_LEX_OP_POWER); | 3326 | parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_POWER, XC_LEX_OP_POWER); |
| 3347 | break; | 3327 | break; |
| 3348 | case 'a': | 3328 | case 'a': |
| 3349 | case 'b': | 3329 | case 'b': |
| @@ -3422,43 +3402,30 @@ static BC_STATUS zdc_lex_register(void) | |||
| 3422 | static BC_STATUS zdc_lex_string(void) | 3402 | static BC_STATUS zdc_lex_string(void) |
| 3423 | { | 3403 | { |
| 3424 | BcParse *p = &G.prs; | 3404 | BcParse *p = &G.prs; |
| 3425 | size_t depth, nls, i; | 3405 | size_t depth; |
| 3426 | 3406 | ||
| 3427 | p->lex = XC_LEX_STR; | 3407 | p->lex = XC_LEX_STR; |
| 3428 | bc_vec_pop_all(&p->lex_strnumbuf); | 3408 | bc_vec_pop_all(&p->lex_strnumbuf); |
| 3429 | 3409 | ||
| 3430 | nls = 0; | ||
| 3431 | depth = 1; | 3410 | depth = 1; |
| 3432 | i = 0; | ||
| 3433 | for (;;) { | 3411 | for (;;) { |
| 3434 | char c = p->lex_inbuf[i]; | 3412 | char c = peek_inbuf(); |
| 3435 | if (c == '\0') { | 3413 | if (c == '\0') { |
| 3436 | p->lex_inbuf += i; | 3414 | RETURN_STATUS(bc_error("unterminated string")); |
| 3437 | RETURN_STATUS(bc_error("string end could not be found")); | ||
| 3438 | } | ||
| 3439 | nls += (c == '\n'); | ||
| 3440 | if (i == 0 || p->lex_inbuf[i - 1] != '\\') { | ||
| 3441 | if (c == '[') depth++; | ||
| 3442 | if (c == ']') | ||
| 3443 | if (--depth == 0) | ||
| 3444 | break; | ||
| 3445 | } | 3415 | } |
| 3446 | bc_vec_push(&p->lex_strnumbuf, &p->lex_inbuf[i]); | 3416 | if (c == '[') depth++; |
| 3447 | i++; | 3417 | if (c == ']') |
| 3418 | if (--depth == 0) | ||
| 3419 | break; | ||
| 3420 | if (c == '\n') | ||
| 3421 | p->lex_line++; | ||
| 3422 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); | ||
| 3423 | p->lex_inbuf++; | ||
| 3448 | } | 3424 | } |
| 3449 | i++; | ||
| 3450 | |||
| 3451 | bc_vec_pushZeroByte(&p->lex_strnumbuf); | 3425 | bc_vec_pushZeroByte(&p->lex_strnumbuf); |
| 3452 | // This check makes sense only if size_t is (much) larger than BC_MAX_STRING. | 3426 | p->lex_inbuf++; // skip trailing ']' |
| 3453 | if (SIZE_MAX > (BC_MAX_STRING | 0xff)) { | ||
| 3454 | if (i > BC_MAX_STRING) | ||
| 3455 | RETURN_STATUS(bc_error("string too long: must be [1,"BC_MAX_STRING_STR"]")); | ||
| 3456 | } | ||
| 3457 | 3427 | ||
| 3458 | p->lex_inbuf += i; | ||
| 3459 | p->lex_line += nls; | ||
| 3460 | G.err_line = p->lex_line; | 3428 | G.err_line = p->lex_line; |
| 3461 | |||
| 3462 | RETURN_STATUS(BC_STATUS_SUCCESS); | 3429 | RETURN_STATUS(BC_STATUS_SUCCESS); |
| 3463 | } | 3430 | } |
| 3464 | #define zdc_lex_string(...) (zdc_lex_string(__VA_ARGS__) COMMA_SUCCESS) | 3431 | #define zdc_lex_string(...) (zdc_lex_string(__VA_ARGS__) COMMA_SUCCESS) |
| @@ -3486,7 +3453,7 @@ static BC_STATUS zdc_lex_token(void) | |||
| 3486 | } | 3453 | } |
| 3487 | 3454 | ||
| 3488 | s = BC_STATUS_SUCCESS; | 3455 | s = BC_STATUS_SUCCESS; |
| 3489 | c = *p->lex_inbuf++; | 3456 | c = eat_inbuf(); |
| 3490 | if (c >= '%' && c <= '~' | 3457 | if (c >= '%' && c <= '~' |
| 3491 | && (p->lex = dc_char_to_LEX[c - '%']) != XC_LEX_INVALID | 3458 | && (p->lex = dc_char_to_LEX[c - '%']) != XC_LEX_INVALID |
| 3492 | ) { | 3459 | ) { |
| @@ -3507,15 +3474,14 @@ static BC_STATUS zdc_lex_token(void) | |||
| 3507 | // commands are not executed on pressing <enter>). | 3474 | // commands are not executed on pressing <enter>). |
| 3508 | // IOW: typing "1p<enter>" should print "1" _at once_, | 3475 | // IOW: typing "1p<enter>" should print "1" _at once_, |
| 3509 | // not after some more input. | 3476 | // not after some more input. |
| 3477 | p->lex_line++; | ||
| 3510 | p->lex = XC_LEX_NLINE; | 3478 | p->lex = XC_LEX_NLINE; |
| 3511 | p->lex_newline = true; | ||
| 3512 | break; | 3479 | break; |
| 3513 | case '\t': | 3480 | case '\t': |
| 3514 | case '\v': | 3481 | case '\v': |
| 3515 | case '\f': | 3482 | case '\f': |
| 3516 | case '\r': | 3483 | case '\r': |
| 3517 | case ' ': | 3484 | case ' ': |
| 3518 | p->lex_newline = 0; // was (c == '\n') | ||
| 3519 | bc_lex_whitespace(); | 3485 | bc_lex_whitespace(); |
| 3520 | break; | 3486 | break; |
| 3521 | case '!': | 3487 | case '!': |
| @@ -3702,7 +3668,7 @@ static void bc_parse_free(void) | |||
| 3702 | IF_BC(bc_vec_free(&p->exits);) | 3668 | IF_BC(bc_vec_free(&p->exits);) |
| 3703 | IF_BC(bc_vec_free(&p->conds);) | 3669 | IF_BC(bc_vec_free(&p->conds);) |
| 3704 | IF_BC(bc_vec_free(&p->ops);) | 3670 | IF_BC(bc_vec_free(&p->ops);) |
| 3705 | bc_lex_free(); | 3671 | bc_vec_free(&G.prs.lex_strnumbuf); |
| 3706 | } | 3672 | } |
| 3707 | 3673 | ||
| 3708 | static void bc_parse_create(size_t fidx) | 3674 | static void bc_parse_create(size_t fidx) |
| @@ -3710,7 +3676,7 @@ static void bc_parse_create(size_t fidx) | |||
| 3710 | BcParse *p = &G.prs; | 3676 | BcParse *p = &G.prs; |
| 3711 | memset(p, 0, sizeof(BcParse)); | 3677 | memset(p, 0, sizeof(BcParse)); |
| 3712 | 3678 | ||
| 3713 | bc_lex_init(); | 3679 | bc_char_vec_init(&G.prs.lex_strnumbuf); |
| 3714 | IF_BC(bc_vec_init(&p->exits, sizeof(size_t), NULL);) | 3680 | IF_BC(bc_vec_init(&p->exits, sizeof(size_t), NULL);) |
| 3715 | IF_BC(bc_vec_init(&p->conds, sizeof(size_t), NULL);) | 3681 | IF_BC(bc_vec_init(&p->conds, sizeof(size_t), NULL);) |
| 3716 | IF_BC(bc_vec_init(&p->ops, sizeof(BcLexType), NULL);) | 3682 | IF_BC(bc_vec_init(&p->ops, sizeof(BcLexType), NULL);) |
| @@ -4753,11 +4719,13 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4753 | switch (t) { | 4719 | switch (t) { |
| 4754 | case BC_LEX_OP_INC: | 4720 | case BC_LEX_OP_INC: |
| 4755 | case BC_LEX_OP_DEC: | 4721 | case BC_LEX_OP_DEC: |
| 4722 | dbg_lex("%s:%d LEX_OP_INC/DEC", __func__, __LINE__); | ||
| 4756 | s = zbc_parse_incdec(&prev, &paren_expr, &nexprs, flags); | 4723 | s = zbc_parse_incdec(&prev, &paren_expr, &nexprs, flags); |
| 4757 | rprn = bin_last = false; | 4724 | rprn = bin_last = false; |
| 4758 | //get_token = false; - already is | 4725 | //get_token = false; - already is |
| 4759 | break; | 4726 | break; |
| 4760 | case XC_LEX_OP_MINUS: | 4727 | case XC_LEX_OP_MINUS: |
| 4728 | dbg_lex("%s:%d LEX_OP_MINUS", __func__, __LINE__); | ||
| 4761 | s = zbc_parse_minus(&prev, ops_bgn, rprn, &nexprs); | 4729 | s = zbc_parse_minus(&prev, ops_bgn, rprn, &nexprs); |
| 4762 | rprn = false; | 4730 | rprn = false; |
| 4763 | //get_token = false; - already is | 4731 | //get_token = false; - already is |
| @@ -4770,6 +4738,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4770 | case BC_LEX_OP_ASSIGN_PLUS: | 4738 | case BC_LEX_OP_ASSIGN_PLUS: |
| 4771 | case BC_LEX_OP_ASSIGN_MINUS: | 4739 | case BC_LEX_OP_ASSIGN_MINUS: |
| 4772 | case BC_LEX_OP_ASSIGN: | 4740 | case BC_LEX_OP_ASSIGN: |
| 4741 | dbg_lex("%s:%d LEX_ASSIGNxyz", __func__, __LINE__); | ||
| 4773 | if (prev != XC_INST_VAR && prev != XC_INST_ARRAY_ELEM | 4742 | if (prev != XC_INST_VAR && prev != XC_INST_ARRAY_ELEM |
| 4774 | && prev != XC_INST_SCALE && prev != XC_INST_IBASE | 4743 | && prev != XC_INST_SCALE && prev != XC_INST_IBASE |
| 4775 | && prev != XC_INST_OBASE && prev != BC_INST_LAST | 4744 | && prev != XC_INST_OBASE && prev != BC_INST_LAST |
| @@ -4794,6 +4763,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4794 | case BC_LEX_OP_BOOL_NOT: | 4763 | case BC_LEX_OP_BOOL_NOT: |
| 4795 | case BC_LEX_OP_BOOL_OR: | 4764 | case BC_LEX_OP_BOOL_OR: |
| 4796 | case BC_LEX_OP_BOOL_AND: | 4765 | case BC_LEX_OP_BOOL_AND: |
| 4766 | dbg_lex("%s:%d LEX_OP_xyz", __func__, __LINE__); | ||
| 4797 | if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) | 4767 | if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) |
| 4798 | || (t != BC_LEX_OP_BOOL_NOT && prev == XC_INST_BOOL_NOT) | 4768 | || (t != BC_LEX_OP_BOOL_NOT && prev == XC_INST_BOOL_NOT) |
| 4799 | ) { | 4769 | ) { |
| @@ -4808,6 +4778,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4808 | bin_last = (t != BC_LEX_OP_BOOL_NOT); | 4778 | bin_last = (t != BC_LEX_OP_BOOL_NOT); |
| 4809 | break; | 4779 | break; |
| 4810 | case BC_LEX_LPAREN: | 4780 | case BC_LEX_LPAREN: |
| 4781 | dbg_lex("%s:%d LEX_LPAREN", __func__, __LINE__); | ||
| 4811 | if (BC_PARSE_LEAF(prev, rprn)) | 4782 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4812 | return bc_error_bad_expression(); | 4783 | return bc_error_bad_expression(); |
| 4813 | bc_vec_push(&p->ops, &t); | 4784 | bc_vec_push(&p->ops, &t); |
| @@ -4817,6 +4788,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4817 | rprn = bin_last = false; | 4788 | rprn = bin_last = false; |
| 4818 | break; | 4789 | break; |
| 4819 | case BC_LEX_RPAREN: | 4790 | case BC_LEX_RPAREN: |
| 4791 | dbg_lex("%s:%d LEX_RPAREN", __func__, __LINE__); | ||
| 4820 | if (bin_last || prev == XC_INST_BOOL_NOT) | 4792 | if (bin_last || prev == XC_INST_BOOL_NOT) |
| 4821 | return bc_error_bad_expression(); | 4793 | return bc_error_bad_expression(); |
| 4822 | if (nparens == 0) { | 4794 | if (nparens == 0) { |
| @@ -4833,6 +4805,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4833 | bin_last = false; | 4805 | bin_last = false; |
| 4834 | break; | 4806 | break; |
| 4835 | case XC_LEX_NAME: | 4807 | case XC_LEX_NAME: |
| 4808 | dbg_lex("%s:%d LEX_NAME", __func__, __LINE__); | ||
| 4836 | if (BC_PARSE_LEAF(prev, rprn)) | 4809 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4837 | return bc_error_bad_expression(); | 4810 | return bc_error_bad_expression(); |
| 4838 | s = zbc_parse_name(&prev, flags & ~BC_PARSE_NOCALL); | 4811 | s = zbc_parse_name(&prev, flags & ~BC_PARSE_NOCALL); |
| @@ -4842,6 +4815,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4842 | nexprs++; | 4815 | nexprs++; |
| 4843 | break; | 4816 | break; |
| 4844 | case XC_LEX_NUMBER: | 4817 | case XC_LEX_NUMBER: |
| 4818 | dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__); | ||
| 4845 | if (BC_PARSE_LEAF(prev, rprn)) | 4819 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4846 | return bc_error_bad_expression(); | 4820 | return bc_error_bad_expression(); |
| 4847 | bc_parse_pushNUM(); | 4821 | bc_parse_pushNUM(); |
| @@ -4854,6 +4828,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4854 | case BC_LEX_KEY_IBASE: | 4828 | case BC_LEX_KEY_IBASE: |
| 4855 | case BC_LEX_KEY_LAST: | 4829 | case BC_LEX_KEY_LAST: |
| 4856 | case BC_LEX_KEY_OBASE: | 4830 | case BC_LEX_KEY_OBASE: |
| 4831 | dbg_lex("%s:%d LEX_IBASE/LAST/OBASE", __func__, __LINE__); | ||
| 4857 | if (BC_PARSE_LEAF(prev, rprn)) | 4832 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4858 | return bc_error_bad_expression(); | 4833 | return bc_error_bad_expression(); |
| 4859 | prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE); | 4834 | prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE); |
| @@ -4865,6 +4840,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4865 | break; | 4840 | break; |
| 4866 | case BC_LEX_KEY_LENGTH: | 4841 | case BC_LEX_KEY_LENGTH: |
| 4867 | case BC_LEX_KEY_SQRT: | 4842 | case BC_LEX_KEY_SQRT: |
| 4843 | dbg_lex("%s:%d LEX_LEN/SQRT", __func__, __LINE__); | ||
| 4868 | if (BC_PARSE_LEAF(prev, rprn)) | 4844 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4869 | return bc_error_bad_expression(); | 4845 | return bc_error_bad_expression(); |
| 4870 | s = zbc_parse_builtin(t, flags, &prev); | 4846 | s = zbc_parse_builtin(t, flags, &prev); |
| @@ -4874,6 +4850,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4874 | nexprs++; | 4850 | nexprs++; |
| 4875 | break; | 4851 | break; |
| 4876 | case BC_LEX_KEY_READ: | 4852 | case BC_LEX_KEY_READ: |
| 4853 | dbg_lex("%s:%d LEX_READ", __func__, __LINE__); | ||
| 4877 | if (BC_PARSE_LEAF(prev, rprn)) | 4854 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4878 | return bc_error_bad_expression(); | 4855 | return bc_error_bad_expression(); |
| 4879 | s = zbc_parse_read(); | 4856 | s = zbc_parse_read(); |
| @@ -4884,6 +4861,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
| 4884 | nexprs++; | 4861 | nexprs++; |
| 4885 | break; | 4862 | break; |
| 4886 | case BC_LEX_KEY_SCALE: | 4863 | case BC_LEX_KEY_SCALE: |
| 4864 | dbg_lex("%s:%d LEX_SCALE", __func__, __LINE__); | ||
| 4887 | if (BC_PARSE_LEAF(prev, rprn)) | 4865 | if (BC_PARSE_LEAF(prev, rprn)) |
| 4888 | return bc_error_bad_expression(); | 4866 | return bc_error_bad_expression(); |
| 4889 | s = zbc_parse_scale(&prev, flags); | 4867 | s = zbc_parse_scale(&prev, flags); |
| @@ -5348,7 +5326,7 @@ static BC_STATUS zbc_program_read(void) | |||
| 5348 | 5326 | ||
| 5349 | sv_parse = G.prs; // struct copy | 5327 | sv_parse = G.prs; // struct copy |
| 5350 | bc_parse_create(BC_PROG_READ); | 5328 | bc_parse_create(BC_PROG_READ); |
| 5351 | //bc_lex_file(&G.prs.l); - not needed, error line info is not printed for read() | 5329 | //G.err_line = G.prs.lex_line = 1; - not needed, error line info is not printed for read() |
| 5352 | 5330 | ||
| 5353 | s = zbc_parse_text_init(buf.v); | 5331 | s = zbc_parse_text_init(buf.v); |
| 5354 | if (s) goto exec_err; | 5332 | if (s) goto exec_err; |
| @@ -6950,7 +6928,7 @@ static BC_STATUS zbc_vm_execute_FILE(FILE *fp, const char *filename) | |||
| 6950 | 6928 | ||
| 6951 | G.prs.lex_filename = filename; | 6929 | G.prs.lex_filename = filename; |
| 6952 | G.prs.lex_input_fp = fp; | 6930 | G.prs.lex_input_fp = fp; |
| 6953 | bc_lex_file(); | 6931 | G.err_line = G.prs.lex_line = 1; |
| 6954 | 6932 | ||
| 6955 | do { | 6933 | do { |
| 6956 | s = zbc_vm_process(""); | 6934 | s = zbc_vm_process(""); |
| @@ -7232,7 +7210,6 @@ static BC_STATUS zbc_vm_exec(void) | |||
| 7232 | // We know that internal library is not buggy, | 7210 | // We know that internal library is not buggy, |
| 7233 | // thus error checking is normally disabled. | 7211 | // thus error checking is normally disabled. |
| 7234 | # define DEBUG_LIB 0 | 7212 | # define DEBUG_LIB 0 |
| 7235 | bc_lex_file(); | ||
| 7236 | s = zbc_vm_process(bc_lib); | 7213 | s = zbc_vm_process(bc_lib); |
| 7237 | if (DEBUG_LIB && s) RETURN_STATUS(s); | 7214 | if (DEBUG_LIB && s) RETURN_STATUS(s); |
| 7238 | } | 7215 | } |
diff --git a/testsuite/dc_strings_results.txt b/testsuite/dc_strings_results.txt index d606637cc..e49b9b288 100644 --- a/testsuite/dc_strings_results.txt +++ b/testsuite/dc_strings_results.txt | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | 13 | 1 | 13 |
| 2 | Hello, World! | 2 | Hello, World! |
| 3 | 16 | 3 | Hello, \[ World!]ZpR |
| 4 | Hello, \[ World! | 4 | [Hello, \[ World!]pR |
| 5 | 16 | 5 | [Hello, \] World!]ZpR |
| 6 | Hello, \] World! | 6 | [Hello, \] World! |
| 7 | 1 | 7 | 1 |
| 8 | 2 | 8 | 2 |
| 9 | 3 | 9 | 3 |
