diff options
Diffstat (limited to 'miscutils/bc.c')
| -rw-r--r-- | miscutils/bc.c | 631 |
1 files changed, 260 insertions, 371 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 374279889..95ba8b094 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
| @@ -171,7 +171,7 @@ | |||
| 171 | #define DEBUG_EXEC 0 | 171 | #define DEBUG_EXEC 0 |
| 172 | 172 | ||
| 173 | #if DEBUG_LEXER | 173 | #if DEBUG_LEXER |
| 174 | static unsigned lex_indent; | 174 | static uint8_t lex_indent; |
| 175 | #define dbg_lex(...) \ | 175 | #define dbg_lex(...) \ |
| 176 | do { \ | 176 | do { \ |
| 177 | fprintf(stderr, "%*s", lex_indent, ""); \ | 177 | fprintf(stderr, "%*s", lex_indent, ""); \ |
| @@ -558,19 +558,16 @@ enum { | |||
| 558 | #endif | 558 | #endif |
| 559 | 559 | ||
| 560 | typedef struct BcLex { | 560 | typedef struct BcLex { |
| 561 | |||
| 562 | const char *buf; | 561 | const char *buf; |
| 563 | size_t i; | 562 | size_t i; |
| 564 | size_t line; | 563 | size_t line; |
| 565 | size_t len; | 564 | size_t len; |
| 566 | bool newline; | 565 | bool newline; |
| 567 | |||
| 568 | struct { | 566 | struct { |
| 569 | BcLexType t; | 567 | BcLexType t; |
| 570 | BcLexType last; | 568 | BcLexType last; |
| 571 | BcVec v; | 569 | BcVec v; |
| 572 | } t; | 570 | } t; |
| 573 | |||
| 574 | } BcLex; | 571 | } BcLex; |
| 575 | 572 | ||
| 576 | #define BC_PARSE_STREND ((char) UCHAR_MAX) | 573 | #define BC_PARSE_STREND ((char) UCHAR_MAX) |
| @@ -581,37 +578,9 @@ typedef struct BcLex { | |||
| 581 | #define BC_PARSE_NOREAD (1 << 3) | 578 | #define BC_PARSE_NOREAD (1 << 3) |
| 582 | #define BC_PARSE_ARRAY (1 << 4) | 579 | #define BC_PARSE_ARRAY (1 << 4) |
| 583 | 580 | ||
| 584 | #define BC_PARSE_TOP_FLAG_PTR(parse) ((parse)->bf_top) | ||
| 585 | #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse))) | ||
| 586 | #define BC_PARSE_FLAG_STACK_EMPTY(p) ((p)->bf_top == (p)->bf_base) | ||
| 587 | |||
| 588 | #define BC_PARSE_FLAG_FUNC_INNER (1 << 0) | ||
| 589 | #define BC_PARSE_FLAG_FUNC (1 << 1) | ||
| 590 | #define BC_PARSE_FLAG_BODY (1 << 2) | ||
| 591 | #define BC_PARSE_FLAG_LOOP (1 << 3) | ||
| 592 | #define BC_PARSE_FLAG_LOOP_INNER (1 << 4) | ||
| 593 | #define BC_PARSE_FLAG_IF (1 << 5) | ||
| 594 | #define BC_PARSE_FLAG_ELSE (1 << 6) | ||
| 595 | #define BC_PARSE_FLAG_IF_END (1 << 7) | ||
| 596 | |||
| 597 | // If we have none of the above bits, we can stop parsing and execute already parsed chunk | ||
| 598 | #define BC_PARSE_CAN_EXEC(parse) (BC_PARSE_TOP_FLAG(parse) == 0) | ||
| 599 | |||
| 600 | #define BC_PARSE_FUNC_INNER(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER) | ||
| 601 | #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC) | ||
| 602 | #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY) | ||
| 603 | #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP) | ||
| 604 | #define BC_PARSE_LOOP_INNER(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER) | ||
| 605 | #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF) | ||
| 606 | #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE) | ||
| 607 | #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END) | ||
| 608 | |||
| 609 | typedef struct BcParse { | 581 | typedef struct BcParse { |
| 610 | BcLex l; | 582 | BcLex l; |
| 611 | 583 | ||
| 612 | uint8_t *bf_base; | ||
| 613 | uint8_t *bf_top; | ||
| 614 | |||
| 615 | BcVec exits; | 584 | BcVec exits; |
| 616 | BcVec conds; | 585 | BcVec conds; |
| 617 | 586 | ||
| @@ -620,9 +589,8 @@ typedef struct BcParse { | |||
| 620 | BcFunc *func; | 589 | BcFunc *func; |
| 621 | size_t fidx; | 590 | size_t fidx; |
| 622 | 591 | ||
| 592 | //TODO: needed? Example? | ||
| 623 | size_t nbraces; | 593 | size_t nbraces; |
| 624 | //FIXME: "define w(x) { auto z; return 1; }" fails to parse | ||
| 625 | bool auto_part; | ||
| 626 | } BcParse; | 594 | } BcParse; |
| 627 | 595 | ||
| 628 | typedef struct BcProgram { | 596 | typedef struct BcProgram { |
| @@ -666,26 +634,6 @@ typedef struct BcProgram { | |||
| 666 | 634 | ||
| 667 | } BcProgram; | 635 | } BcProgram; |
| 668 | 636 | ||
| 669 | static void bc_parse_push_block_flag(BcParse *p, uint8_t flags) | ||
| 670 | { | ||
| 671 | size_t size; | ||
| 672 | uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); | ||
| 673 | flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP)); | ||
| 674 | flags |= BC_PARSE_FLAG_BODY; | ||
| 675 | |||
| 676 | size = p->bf_top - p->bf_base; | ||
| 677 | p->bf_base = xrealloc(p->bf_base, size + 2); | ||
| 678 | p->bf_top = p->bf_base + size + 1; | ||
| 679 | dbg_lex("%s:%d pushed block flag lvl:%d bits:0x%02x", __func__, __LINE__, size + 1, flags); | ||
| 680 | *p->bf_top = flags; | ||
| 681 | } | ||
| 682 | |||
| 683 | static ALWAYS_INLINE void bc_parse_pop_block_flag(BcParse *p) | ||
| 684 | { | ||
| 685 | p->bf_top--; | ||
| 686 | dbg_lex("%s:%d popped block flag lvl:%d bits:0x%02x", __func__, __LINE__, p->bf_top - p->bf_base, *p->bf_top); | ||
| 687 | } | ||
| 688 | |||
| 689 | #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n)) | 637 | #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n)) |
| 690 | 638 | ||
| 691 | #define BC_PROG_MAIN (0) | 639 | #define BC_PROG_MAIN (0) |
| @@ -747,6 +695,7 @@ struct globals { | |||
| 747 | IF_FEATURE_BC_SIGNALS(smallint ttyin;) | 695 | IF_FEATURE_BC_SIGNALS(smallint ttyin;) |
| 748 | IF_FEATURE_CLEAN_UP(smallint exiting;) | 696 | IF_FEATURE_CLEAN_UP(smallint exiting;) |
| 749 | smallint in_read; | 697 | smallint in_read; |
| 698 | smallint use_stdin; | ||
| 750 | 699 | ||
| 751 | BcParse prs; | 700 | BcParse prs; |
| 752 | BcProgram prog; | 701 | BcProgram prog; |
| @@ -756,6 +705,7 @@ struct globals { | |||
| 756 | unsigned err_line; | 705 | unsigned err_line; |
| 757 | 706 | ||
| 758 | BcVec files; | 707 | BcVec files; |
| 708 | BcVec stdin_buffer; | ||
| 759 | 709 | ||
| 760 | char *env_args; | 710 | char *env_args; |
| 761 | 711 | ||
| @@ -1052,6 +1002,7 @@ static void quit(void) | |||
| 1052 | if (ferror(stdin)) | 1002 | if (ferror(stdin)) |
| 1053 | bb_perror_msg_and_die("input error"); | 1003 | bb_perror_msg_and_die("input error"); |
| 1054 | fflush_and_check(); | 1004 | fflush_and_check(); |
| 1005 | dbg_exec("quit(): exiting with exitcode SUCCESS"); | ||
| 1055 | exit(0); | 1006 | exit(0); |
| 1056 | } | 1007 | } |
| 1057 | 1008 | ||
| @@ -2955,6 +2906,79 @@ static BC_STATUS zcommon_lex_token(BcLex *l) | |||
| 2955 | IF_DC(RETURN_STATUS(zdc_lex_token(l));) | 2906 | IF_DC(RETURN_STATUS(zdc_lex_token(l));) |
| 2956 | } | 2907 | } |
| 2957 | 2908 | ||
| 2909 | static bool bc_lex_more_input(BcLex *l) | ||
| 2910 | { | ||
| 2911 | size_t str; | ||
| 2912 | bool comment; | ||
| 2913 | |||
| 2914 | bc_vec_pop_all(&G.stdin_buffer); | ||
| 2915 | |||
| 2916 | // This loop is complex because the vm tries not to send any lines that end | ||
| 2917 | // with a backslash to the parser. The reason for that is because the parser | ||
| 2918 | // treats a backslash+newline combo as whitespace, per the bc spec. In that | ||
| 2919 | // case, and for strings and comments, the parser will expect more stuff. | ||
| 2920 | comment = false; | ||
| 2921 | str = 0; | ||
| 2922 | for (;;) { | ||
| 2923 | size_t prevlen = G.stdin_buffer.len; | ||
| 2924 | char *string; | ||
| 2925 | |||
| 2926 | bc_read_line(&G.stdin_buffer); | ||
| 2927 | // No more input means EOF | ||
| 2928 | if (G.stdin_buffer.len <= prevlen + 1) // (we expect +1 for NUL byte) | ||
| 2929 | break; | ||
| 2930 | |||
| 2931 | string = G.stdin_buffer.v + prevlen; | ||
| 2932 | while (*string) { | ||
| 2933 | char c = *string; | ||
| 2934 | if (string == G.stdin_buffer.v || string[-1] != '\\') { | ||
| 2935 | if (IS_BC) | ||
| 2936 | str ^= (c == '"'); | ||
| 2937 | else { | ||
| 2938 | if (c == ']') | ||
| 2939 | str -= 1; | ||
| 2940 | else if (c == '[') | ||
| 2941 | str += 1; | ||
| 2942 | } | ||
| 2943 | } | ||
| 2944 | string++; | ||
| 2945 | if (c == '/' && *string == '*') { | ||
| 2946 | comment = true; | ||
| 2947 | string++; | ||
| 2948 | continue; | ||
| 2949 | } | ||
| 2950 | if (c == '*' && *string == '/') { | ||
| 2951 | comment = false; | ||
| 2952 | string++; | ||
| 2953 | } | ||
| 2954 | } | ||
| 2955 | if (str != 0 || comment) { | ||
| 2956 | G.stdin_buffer.len--; // backstep over the trailing NUL byte | ||
| 2957 | continue; | ||
| 2958 | } | ||
| 2959 | |||
| 2960 | // Check for backslash+newline. | ||
| 2961 | // we do not check that last char is '\n' - | ||
| 2962 | // if it is not, then it's EOF, and looping back | ||
| 2963 | // to bc_read_line() will detect it: | ||
| 2964 | string -= 2; | ||
| 2965 | if (string >= G.stdin_buffer.v && *string == '\\') { | ||
| 2966 | G.stdin_buffer.len--; | ||
| 2967 | continue; | ||
| 2968 | } | ||
| 2969 | |||
| 2970 | break; | ||
| 2971 | } | ||
| 2972 | |||
| 2973 | l->buf = G.stdin_buffer.v; | ||
| 2974 | l->i = 0; | ||
| 2975 | //bb_error_msg("G.stdin_buffer.len:%d '%s'", G.stdin_buffer.len, G.stdin_buffer.v); | ||
| 2976 | l->len = G.stdin_buffer.len - 1; // do not include NUL | ||
| 2977 | |||
| 2978 | G.use_stdin = (l->len != 0); | ||
| 2979 | return G.use_stdin; | ||
| 2980 | } | ||
| 2981 | |||
| 2958 | static BC_STATUS zbc_lex_next(BcLex *l) | 2982 | static BC_STATUS zbc_lex_next(BcLex *l) |
| 2959 | { | 2983 | { |
| 2960 | BcStatus s; | 2984 | BcStatus s; |
| @@ -2964,10 +2988,16 @@ static BC_STATUS zbc_lex_next(BcLex *l) | |||
| 2964 | 2988 | ||
| 2965 | l->line += l->newline; | 2989 | l->line += l->newline; |
| 2966 | G.err_line = l->line; | 2990 | G.err_line = l->line; |
| 2967 | l->t.t = BC_LEX_EOF; | ||
| 2968 | 2991 | ||
| 2992 | l->t.t = BC_LEX_EOF; | ||
| 2993 | //this NL handling is bogus | ||
| 2969 | l->newline = (l->i == l->len); | 2994 | l->newline = (l->i == l->len); |
| 2970 | if (l->newline) RETURN_STATUS(BC_STATUS_SUCCESS); | 2995 | if (l->newline) { |
| 2996 | if (!G.use_stdin || !bc_lex_more_input(l)) | ||
| 2997 | RETURN_STATUS(BC_STATUS_SUCCESS); | ||
| 2998 | // here it's guaranteed that l->i is below l->len | ||
| 2999 | l->newline = false; | ||
| 3000 | } | ||
| 2971 | 3001 | ||
| 2972 | // Loop until failure or we don't have whitespace. This | 3002 | // Loop until failure or we don't have whitespace. This |
| 2973 | // is so the parser doesn't get inundated with whitespace. | 3003 | // is so the parser doesn't get inundated with whitespace. |
| @@ -3528,19 +3558,8 @@ static BC_STATUS zcommon_parse(BcParse *p) | |||
| 3528 | 3558 | ||
| 3529 | static BC_STATUS zbc_parse_text_init(BcParse *p, const char *text) | 3559 | static BC_STATUS zbc_parse_text_init(BcParse *p, const char *text) |
| 3530 | { | 3560 | { |
| 3531 | BcStatus s; | ||
| 3532 | |||
| 3533 | p->func = bc_program_func(p->fidx); | 3561 | p->func = bc_program_func(p->fidx); |
| 3534 | 3562 | ||
| 3535 | if (!text[0] && !BC_PARSE_CAN_EXEC(p)) { | ||
| 3536 | p->l.t.t = BC_LEX_INVALID; | ||
| 3537 | s = BC_STATUS_SUCCESS; | ||
| 3538 | ERROR_RETURN(s =) zcommon_parse(p); | ||
| 3539 | if (s) RETURN_STATUS(s); | ||
| 3540 | if (!BC_PARSE_CAN_EXEC(p)) | ||
| 3541 | RETURN_STATUS(bc_error("file is not executable")); | ||
| 3542 | } | ||
| 3543 | |||
| 3544 | RETURN_STATUS(zbc_lex_text_init(&p->l, text)); | 3563 | RETURN_STATUS(zbc_lex_text_init(&p->l, text)); |
| 3545 | } | 3564 | } |
| 3546 | #if ERRORS_ARE_FATAL | 3565 | #if ERRORS_ARE_FATAL |
| @@ -3580,9 +3599,8 @@ static void bc_parse_reset(BcParse *p) | |||
| 3580 | 3599 | ||
| 3581 | p->l.i = p->l.len; | 3600 | p->l.i = p->l.len; |
| 3582 | p->l.t.t = BC_LEX_EOF; | 3601 | p->l.t.t = BC_LEX_EOF; |
| 3583 | p->auto_part = (p->nbraces = 0); | 3602 | p->nbraces = 0; |
| 3584 | 3603 | ||
| 3585 | p->bf_top = p->bf_base; // pop all flags | ||
| 3586 | bc_vec_pop_all(&p->exits); | 3604 | bc_vec_pop_all(&p->exits); |
| 3587 | bc_vec_pop_all(&p->conds); | 3605 | bc_vec_pop_all(&p->conds); |
| 3588 | bc_vec_pop_all(&p->ops); | 3606 | bc_vec_pop_all(&p->ops); |
| @@ -3592,7 +3610,6 @@ static void bc_parse_reset(BcParse *p) | |||
| 3592 | 3610 | ||
| 3593 | static void bc_parse_free(BcParse *p) | 3611 | static void bc_parse_free(BcParse *p) |
| 3594 | { | 3612 | { |
| 3595 | free(p->bf_base); | ||
| 3596 | bc_vec_free(&p->exits); | 3613 | bc_vec_free(&p->exits); |
| 3597 | bc_vec_free(&p->conds); | 3614 | bc_vec_free(&p->conds); |
| 3598 | bc_vec_free(&p->ops); | 3615 | bc_vec_free(&p->ops); |
| @@ -3604,12 +3621,11 @@ static void bc_parse_create(BcParse *p, size_t func) | |||
| 3604 | memset(p, 0, sizeof(BcParse)); | 3621 | memset(p, 0, sizeof(BcParse)); |
| 3605 | 3622 | ||
| 3606 | bc_lex_init(&p->l); | 3623 | bc_lex_init(&p->l); |
| 3607 | p->bf_top = p->bf_base = xzalloc(1); | ||
| 3608 | bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL); | 3624 | bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL); |
| 3609 | bc_vec_init(&p->conds, sizeof(size_t), NULL); | 3625 | bc_vec_init(&p->conds, sizeof(size_t), NULL); |
| 3610 | bc_vec_init(&p->ops, sizeof(BcLexType), NULL); | 3626 | bc_vec_init(&p->ops, sizeof(BcLexType), NULL); |
| 3611 | 3627 | ||
| 3612 | // p->auto_part = p->nbraces = 0; - already is | 3628 | // p->nbraces = 0; - already is |
| 3613 | bc_parse_updateFunc(p, func); | 3629 | bc_parse_updateFunc(p, func); |
| 3614 | } | 3630 | } |
| 3615 | 3631 | ||
| @@ -3625,14 +3641,20 @@ static void bc_parse_create(BcParse *p, size_t func) | |||
| 3625 | // first in the expr enum. Note: This only works for binary operators. | 3641 | // first in the expr enum. Note: This only works for binary operators. |
| 3626 | #define BC_TOKEN_2_INST(t) ((char) ((t) - BC_LEX_NEG + BC_INST_NEG)) | 3642 | #define BC_TOKEN_2_INST(t) ((char) ((t) - BC_LEX_NEG + BC_INST_NEG)) |
| 3627 | 3643 | ||
| 3628 | static BC_STATUS zbc_parse_else(BcParse *p); | 3644 | static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed); |
| 3629 | static BC_STATUS zbc_parse_stmt(BcParse *p); | ||
| 3630 | static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); | 3645 | static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); |
| 3631 | static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next); | 3646 | static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next); |
| 3632 | #if ERRORS_ARE_FATAL | 3647 | #if ERRORS_ARE_FATAL |
| 3633 | # define zbc_parse_else(...) (zbc_parse_else(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
| 3634 | # define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
| 3635 | # define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__), BC_STATUS_SUCCESS) | 3648 | # define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 3649 | # defone zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
| 3650 | #endif | ||
| 3651 | |||
| 3652 | static BC_STATUS zbc_parse_stmt(BcParse *p) | ||
| 3653 | { | ||
| 3654 | RETURN_STATUS(zbc_parse_stmt_possibly_auto(p, false)); | ||
| 3655 | } | ||
| 3656 | #if ERRORS_ARE_FATAL | ||
| 3657 | # define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
| 3636 | #endif | 3658 | #endif |
| 3637 | 3659 | ||
| 3638 | static void bc_parse_operator(BcParse *p, BcLexType type, size_t start, | 3660 | static void bc_parse_operator(BcParse *p, BcLexType type, size_t start, |
| @@ -4037,7 +4059,7 @@ static BC_STATUS zbc_parse_return(BcParse *p) | |||
| 4037 | BcLexType t; | 4059 | BcLexType t; |
| 4038 | bool paren; | 4060 | bool paren; |
| 4039 | 4061 | ||
| 4040 | if (!BC_PARSE_FUNC(p)) RETURN_STATUS(bc_error_bad_token()); | 4062 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
| 4041 | 4063 | ||
| 4042 | s = zbc_lex_next(&p->l); | 4064 | s = zbc_lex_next(&p->l); |
| 4043 | if (s) RETURN_STATUS(s); | 4065 | if (s) RETURN_STATUS(s); |
| @@ -4063,97 +4085,62 @@ static BC_STATUS zbc_parse_return(BcParse *p) | |||
| 4063 | bc_parse_push(p, BC_INST_RET); | 4085 | bc_parse_push(p, BC_INST_RET); |
| 4064 | } | 4086 | } |
| 4065 | 4087 | ||
| 4088 | dbg_lex_done("%s:%d done", __func__, __LINE__); | ||
| 4066 | RETURN_STATUS(s); | 4089 | RETURN_STATUS(s); |
| 4067 | } | 4090 | } |
| 4068 | #if ERRORS_ARE_FATAL | 4091 | #if ERRORS_ARE_FATAL |
| 4069 | # define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__), BC_STATUS_SUCCESS) | 4092 | # define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4070 | #endif | 4093 | #endif |
| 4071 | 4094 | ||
| 4072 | static BC_STATUS zbc_parse_endBody(BcParse *p) | 4095 | static void bc_parse_noElse(BcParse *p) |
| 4073 | { | 4096 | { |
| 4074 | BcStatus s = BC_STATUS_SUCCESS; | 4097 | BcInstPtr *ip; |
| 4075 | 4098 | size_t *label; | |
| 4076 | if (BC_PARSE_FLAG_STACK_EMPTY(p)) | ||
| 4077 | RETURN_STATUS(bc_error_bad_token()); | ||
| 4078 | |||
| 4079 | if (BC_PARSE_IF(p)) { | ||
| 4080 | uint8_t *flag_ptr; | ||
| 4081 | 4099 | ||
| 4082 | while (p->l.t.t == BC_LEX_NLINE) { | 4100 | ip = bc_vec_top(&p->exits); |
| 4083 | s = zbc_lex_next(&p->l); | 4101 | label = bc_vec_item(&p->func->labels, ip->idx); |
| 4084 | if (s) RETURN_STATUS(s); | 4102 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); |
| 4085 | } | 4103 | *label = p->func->code.len; |
| 4086 | 4104 | ||
| 4087 | bc_parse_pop_block_flag(p); | 4105 | bc_vec_pop(&p->exits); |
| 4106 | } | ||
| 4088 | 4107 | ||
| 4089 | flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); | 4108 | static BC_STATUS zbc_parse_else(BcParse *p) |
| 4090 | dbg_lex("%s:%d setting BC_PARSE_FLAG_IF_END bit", __func__, __LINE__); | 4109 | { |
| 4091 | *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END); | 4110 | BcStatus s; |
| 4111 | BcInstPtr ip; | ||
| 4092 | 4112 | ||
| 4093 | if (p->l.t.t == BC_LEX_KEY_ELSE) | 4113 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
| 4094 | s = zbc_parse_else(p); | ||
| 4095 | } | ||
| 4096 | else if (BC_PARSE_ELSE(p)) { | ||
| 4097 | BcInstPtr *ip; | ||
| 4098 | size_t *label; | ||
| 4099 | 4114 | ||
| 4100 | ip = bc_vec_top(&p->exits); | 4115 | ip.idx = p->func->labels.len; |
| 4101 | label = bc_vec_item(&p->func->labels, ip->idx); | 4116 | ip.func = ip.len = 0; |
| 4102 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | ||
| 4103 | *label = p->func->code.len; | ||
| 4104 | 4117 | ||
| 4105 | bc_vec_pop(&p->exits); | 4118 | dbg_lex("%s:%d after if() body: BC_INST_JUMP to %d", __func__, __LINE__, ip.idx); |
| 4106 | bc_parse_pop_block_flag(p); | 4119 | bc_parse_push(p, BC_INST_JUMP); |
| 4107 | } | 4120 | bc_parse_pushIndex(p, ip.idx); |
| 4108 | else if (BC_PARSE_FUNC_INNER(p)) { | ||
| 4109 | bc_parse_push(p, BC_INST_RET0); | ||
| 4110 | bc_parse_updateFunc(p, BC_PROG_MAIN); | ||
| 4111 | bc_parse_pop_block_flag(p); | ||
| 4112 | } | ||
| 4113 | else { | ||
| 4114 | BcInstPtr *ip = bc_vec_top(&p->exits); | ||
| 4115 | size_t *label = bc_vec_top(&p->conds); | ||
| 4116 | 4121 | ||
| 4117 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, *label); | 4122 | dbg_lex("%s:%d calling bc_parse_noElse()", __func__, __LINE__); |
| 4118 | bc_parse_push(p, BC_INST_JUMP); | 4123 | bc_parse_noElse(p); |
| 4119 | bc_parse_pushIndex(p, *label); | ||
| 4120 | 4124 | ||
| 4121 | label = bc_vec_item(&p->func->labels, ip->idx); | 4125 | bc_vec_push(&p->exits, &ip); |
| 4122 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | 4126 | bc_vec_push(&p->func->labels, &ip.idx); |
| 4123 | *label = p->func->code.len; | ||
| 4124 | 4127 | ||
| 4125 | bc_vec_pop(&p->exits); | 4128 | s = zbc_parse_stmt(p); |
| 4126 | bc_vec_pop(&p->conds); | 4129 | if (s) RETURN_STATUS(s); |
| 4127 | bc_parse_pop_block_flag(p); | ||
| 4128 | } | ||
| 4129 | 4130 | ||
| 4131 | dbg_lex_done("%s:%d done", __func__, __LINE__); | ||
| 4130 | RETURN_STATUS(s); | 4132 | RETURN_STATUS(s); |
| 4131 | } | 4133 | } |
| 4132 | #if ERRORS_ARE_FATAL | 4134 | #if ERRORS_ARE_FATAL |
| 4133 | # define zbc_parse_endBody(...) (zbc_parse_endBody(__VA_ARGS__), BC_STATUS_SUCCESS) | 4135 | # define zbc_parse_else(...) (zbc_parse_else(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4134 | #endif | 4136 | #endif |
| 4135 | 4137 | ||
| 4136 | static void bc_parse_noElse(BcParse *p) | ||
| 4137 | { | ||
| 4138 | BcInstPtr *ip; | ||
| 4139 | size_t *label; | ||
| 4140 | uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); | ||
| 4141 | |||
| 4142 | dbg_lex("%s:%d clearing BC_PARSE_FLAG_IF_END bit", __func__, __LINE__); | ||
| 4143 | *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END)); | ||
| 4144 | |||
| 4145 | ip = bc_vec_top(&p->exits); | ||
| 4146 | label = bc_vec_item(&p->func->labels, ip->idx); | ||
| 4147 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | ||
| 4148 | *label = p->func->code.len; | ||
| 4149 | |||
| 4150 | bc_vec_pop(&p->exits); | ||
| 4151 | } | ||
| 4152 | |||
| 4153 | static BC_STATUS zbc_parse_if(BcParse *p) | 4138 | static BC_STATUS zbc_parse_if(BcParse *p) |
| 4154 | { | 4139 | { |
| 4155 | BcStatus s; | 4140 | BcStatus s; |
| 4156 | BcInstPtr ip; | 4141 | BcInstPtr ip; |
| 4142 | BcInstPtr *ipp; | ||
| 4143 | size_t *label; | ||
| 4157 | 4144 | ||
| 4158 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4145 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
| 4159 | s = zbc_lex_next(&p->l); | 4146 | s = zbc_lex_next(&p->l); |
| @@ -4164,60 +4151,50 @@ static BC_STATUS zbc_parse_if(BcParse *p) | |||
| 4164 | if (s) RETURN_STATUS(s); | 4151 | if (s) RETURN_STATUS(s); |
| 4165 | s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); | 4152 | s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); |
| 4166 | if (s) RETURN_STATUS(s); | 4153 | if (s) RETURN_STATUS(s); |
| 4167 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | ||
| 4168 | 4154 | ||
| 4155 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | ||
| 4169 | s = zbc_lex_next(&p->l); | 4156 | s = zbc_lex_next(&p->l); |
| 4170 | if (s) RETURN_STATUS(s); | 4157 | if (s) RETURN_STATUS(s); |
| 4171 | bc_parse_push(p, BC_INST_JUMP_ZERO); | ||
| 4172 | 4158 | ||
| 4159 | bc_parse_push(p, BC_INST_JUMP_ZERO); | ||
| 4173 | ip.idx = p->func->labels.len; | 4160 | ip.idx = p->func->labels.len; |
| 4174 | ip.func = ip.len = 0; | 4161 | ip.func = ip.len = 0; |
| 4175 | |||
| 4176 | bc_parse_pushIndex(p, ip.idx); | 4162 | bc_parse_pushIndex(p, ip.idx); |
| 4163 | //TODO: can get rid of p->exits stack? | ||
| 4177 | bc_vec_push(&p->exits, &ip); | 4164 | bc_vec_push(&p->exits, &ip); |
| 4178 | bc_vec_push(&p->func->labels, &ip.idx); | 4165 | bc_vec_push(&p->func->labels, &ip.idx); |
| 4179 | bc_parse_push_block_flag(p, BC_PARSE_FLAG_IF); | ||
| 4180 | 4166 | ||
| 4181 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 4167 | s = zbc_parse_stmt(p); |
| 4182 | RETURN_STATUS(BC_STATUS_SUCCESS); | 4168 | if (s) RETURN_STATUS(s); |
| 4183 | } | 4169 | dbg_lex("%s:%d in if after stmt: p->l.t.t:%d", __func__, __LINE__, p->l.t.t); |
| 4184 | #if ERRORS_ARE_FATAL | 4170 | if (p->l.t.t == BC_LEX_KEY_ELSE) { |
| 4185 | # define zbc_parse_if(...) (zbc_parse_if(__VA_ARGS__), BC_STATUS_SUCCESS) | 4171 | s = zbc_lex_next(&p->l); |
| 4186 | #endif | 4172 | if (s) RETURN_STATUS(s); |
| 4187 | 4173 | dbg_lex("%s:%d calling zbc_parse_else(), p->l.t.t:%d", __func__, __LINE__, p->l.t.t); | |
| 4188 | #undef zbc_parse_else | 4174 | s = zbc_parse_else(p); |
| 4189 | static BC_STATUS zbc_parse_else(BcParse *p) | 4175 | } |
| 4190 | { | ||
| 4191 | BcInstPtr ip; | ||
| 4192 | |||
| 4193 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | ||
| 4194 | if (!BC_PARSE_IF_END(p)) RETURN_STATUS(bc_error_bad_token()); | ||
| 4195 | |||
| 4196 | ip.idx = p->func->labels.len; | ||
| 4197 | ip.func = ip.len = 0; | ||
| 4198 | |||
| 4199 | dbg_lex("%s:%d after if() body: BC_INST_JUMP to %d", __func__, __LINE__, ip.idx); | ||
| 4200 | bc_parse_push(p, BC_INST_JUMP); | ||
| 4201 | bc_parse_pushIndex(p, ip.idx); | ||
| 4202 | 4176 | ||
| 4203 | dbg_lex("%s:%d calling bc_parse_noElse()", __func__, __LINE__); | 4177 | ipp = bc_vec_top(&p->exits); |
| 4204 | bc_parse_noElse(p); | 4178 | label = bc_vec_item(&p->func->labels, ipp->idx); |
| 4179 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | ||
| 4180 | *label = p->func->code.len; | ||
| 4205 | 4181 | ||
| 4206 | bc_vec_push(&p->exits, &ip); | 4182 | bc_vec_pop(&p->exits); |
| 4207 | bc_vec_push(&p->func->labels, &ip.idx); | ||
| 4208 | bc_parse_push_block_flag(p, BC_PARSE_FLAG_ELSE); | ||
| 4209 | 4183 | ||
| 4210 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 4184 | dbg_lex_done("%s:%d done", __func__, __LINE__); |
| 4211 | RETURN_STATUS(zbc_lex_next(&p->l)); | 4185 | RETURN_STATUS(s); |
| 4212 | } | 4186 | } |
| 4213 | #if ERRORS_ARE_FATAL | 4187 | #if ERRORS_ARE_FATAL |
| 4214 | # define zbc_parse_else(...) (zbc_parse_else(__VA_ARGS__), BC_STATUS_SUCCESS) | 4188 | # define zbc_parse_if(...) (zbc_parse_if(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4215 | #endif | 4189 | #endif |
| 4216 | 4190 | ||
| 4217 | static BC_STATUS zbc_parse_while(BcParse *p) | 4191 | static BC_STATUS zbc_parse_while(BcParse *p) |
| 4218 | { | 4192 | { |
| 4219 | BcStatus s; | 4193 | BcStatus s; |
| 4220 | BcInstPtr ip; | 4194 | BcInstPtr ip; |
| 4195 | BcInstPtr *ipp; | ||
| 4196 | size_t *label; | ||
| 4197 | size_t n; | ||
| 4221 | 4198 | ||
| 4222 | s = zbc_lex_next(&p->l); | 4199 | s = zbc_lex_next(&p->l); |
| 4223 | if (s) RETURN_STATUS(s); | 4200 | if (s) RETURN_STATUS(s); |
| @@ -4245,9 +4222,29 @@ static BC_STATUS zbc_parse_while(BcParse *p) | |||
| 4245 | 4222 | ||
| 4246 | bc_parse_push(p, BC_INST_JUMP_ZERO); | 4223 | bc_parse_push(p, BC_INST_JUMP_ZERO); |
| 4247 | bc_parse_pushIndex(p, ip.idx); | 4224 | bc_parse_pushIndex(p, ip.idx); |
| 4248 | bc_parse_push_block_flag(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); | ||
| 4249 | 4225 | ||
| 4250 | RETURN_STATUS(BC_STATUS_SUCCESS); | 4226 | s = zbc_parse_stmt(p); |
| 4227 | if (s) RETURN_STATUS(s); | ||
| 4228 | |||
| 4229 | n = *((size_t *) bc_vec_top(&p->conds)); | ||
| 4230 | bc_parse_push(p, BC_INST_JUMP); | ||
| 4231 | bc_parse_pushIndex(p, n); | ||
| 4232 | |||
| 4233 | ipp = bc_vec_top(&p->exits); | ||
| 4234 | label = bc_vec_top(&p->conds); | ||
| 4235 | |||
| 4236 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, *label); | ||
| 4237 | bc_parse_push(p, BC_INST_JUMP); | ||
| 4238 | bc_parse_pushIndex(p, *label); | ||
| 4239 | |||
| 4240 | label = bc_vec_item(&p->func->labels, ipp->idx); | ||
| 4241 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | ||
| 4242 | *label = p->func->code.len; | ||
| 4243 | |||
| 4244 | bc_vec_pop(&p->exits); | ||
| 4245 | bc_vec_pop(&p->conds); | ||
| 4246 | |||
| 4247 | RETURN_STATUS(s); | ||
| 4251 | } | 4248 | } |
| 4252 | #if ERRORS_ARE_FATAL | 4249 | #if ERRORS_ARE_FATAL |
| 4253 | # define zbc_parse_while(...) (zbc_parse_while(__VA_ARGS__), BC_STATUS_SUCCESS) | 4250 | # define zbc_parse_while(...) (zbc_parse_while(__VA_ARGS__), BC_STATUS_SUCCESS) |
| @@ -4257,7 +4254,10 @@ static BC_STATUS zbc_parse_for(BcParse *p) | |||
| 4257 | { | 4254 | { |
| 4258 | BcStatus s; | 4255 | BcStatus s; |
| 4259 | BcInstPtr ip; | 4256 | BcInstPtr ip; |
| 4257 | BcInstPtr *ipp; | ||
| 4258 | size_t *label; | ||
| 4260 | size_t cond_idx, exit_idx, body_idx, update_idx; | 4259 | size_t cond_idx, exit_idx, body_idx, update_idx; |
| 4260 | size_t n; | ||
| 4261 | 4261 | ||
| 4262 | dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); | 4262 | dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); |
| 4263 | s = zbc_lex_next(&p->l); | 4263 | s = zbc_lex_next(&p->l); |
| @@ -4324,7 +4324,28 @@ static BC_STATUS zbc_parse_for(BcParse *p) | |||
| 4324 | bc_vec_push(&p->func->labels, &ip.idx); | 4324 | bc_vec_push(&p->func->labels, &ip.idx); |
| 4325 | s = zbc_lex_next(&p->l); | 4325 | s = zbc_lex_next(&p->l); |
| 4326 | if (s) RETURN_STATUS(s); | 4326 | if (s) RETURN_STATUS(s); |
| 4327 | bc_parse_push_block_flag(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); | 4327 | |
| 4328 | s = zbc_parse_stmt(p); | ||
| 4329 | if (s) RETURN_STATUS(s); | ||
| 4330 | |||
| 4331 | n = *((size_t *) bc_vec_top(&p->conds)); | ||
| 4332 | bc_parse_push(p, BC_INST_JUMP); | ||
| 4333 | bc_parse_pushIndex(p, n); | ||
| 4334 | |||
| 4335 | ipp = bc_vec_top(&p->exits); | ||
| 4336 | label = bc_vec_top(&p->conds); | ||
| 4337 | |||
| 4338 | //TODO: commonalize? | ||
| 4339 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, *label); | ||
| 4340 | bc_parse_push(p, BC_INST_JUMP); | ||
| 4341 | bc_parse_pushIndex(p, *label); | ||
| 4342 | |||
| 4343 | label = bc_vec_item(&p->func->labels, ipp->idx); | ||
| 4344 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | ||
| 4345 | *label = p->func->code.len; | ||
| 4346 | |||
| 4347 | bc_vec_pop(&p->exits); | ||
| 4348 | bc_vec_pop(&p->conds); | ||
| 4328 | 4349 | ||
| 4329 | RETURN_STATUS(BC_STATUS_SUCCESS); | 4350 | RETURN_STATUS(BC_STATUS_SUCCESS); |
| 4330 | } | 4351 | } |
| @@ -4332,14 +4353,12 @@ static BC_STATUS zbc_parse_for(BcParse *p) | |||
| 4332 | # define zbc_parse_for(...) (zbc_parse_for(__VA_ARGS__), BC_STATUS_SUCCESS) | 4353 | # define zbc_parse_for(...) (zbc_parse_for(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4333 | #endif | 4354 | #endif |
| 4334 | 4355 | ||
| 4335 | static BC_STATUS zbc_parse_loopExit(BcParse *p, BcLexType type) | 4356 | static BC_STATUS zbc_parse_break_or_continue(BcParse *p, BcLexType type) |
| 4336 | { | 4357 | { |
| 4337 | BcStatus s; | 4358 | BcStatus s; |
| 4338 | size_t i; | 4359 | size_t i; |
| 4339 | BcInstPtr *ip; | 4360 | BcInstPtr *ip; |
| 4340 | 4361 | ||
| 4341 | if (!BC_PARSE_LOOP(p)) RETURN_STATUS(bc_error_bad_token()); | ||
| 4342 | |||
| 4343 | if (type == BC_LEX_KEY_BREAK) { | 4362 | if (type == BC_LEX_KEY_BREAK) { |
| 4344 | if (p->exits.len == 0) RETURN_STATUS(bc_error_bad_token()); | 4363 | if (p->exits.len == 0) RETURN_STATUS(bc_error_bad_token()); |
| 4345 | 4364 | ||
| @@ -4368,14 +4387,13 @@ static BC_STATUS zbc_parse_loopExit(BcParse *p, BcLexType type) | |||
| 4368 | RETURN_STATUS(zbc_lex_next(&p->l)); | 4387 | RETURN_STATUS(zbc_lex_next(&p->l)); |
| 4369 | } | 4388 | } |
| 4370 | #if ERRORS_ARE_FATAL | 4389 | #if ERRORS_ARE_FATAL |
| 4371 | # define zbc_parse_loopExit(...) (zbc_parse_loopExit(__VA_ARGS__), BC_STATUS_SUCCESS) | 4390 | # define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4372 | #endif | 4391 | #endif |
| 4373 | 4392 | ||
| 4374 | static BC_STATUS zbc_parse_func(BcParse *p) | 4393 | static BC_STATUS zbc_parse_func(BcParse *p) |
| 4375 | { | 4394 | { |
| 4376 | BcStatus s; | 4395 | BcStatus s; |
| 4377 | bool var, comma = false; | 4396 | bool var, comma = false; |
| 4378 | uint8_t flags; | ||
| 4379 | char *name; | 4397 | char *name; |
| 4380 | 4398 | ||
| 4381 | s = zbc_lex_next(&p->l); | 4399 | s = zbc_lex_next(&p->l); |
| @@ -4430,15 +4448,18 @@ static BC_STATUS zbc_parse_func(BcParse *p) | |||
| 4430 | 4448 | ||
| 4431 | if (comma) RETURN_STATUS(bc_error("bad function definition")); | 4449 | if (comma) RETURN_STATUS(bc_error("bad function definition")); |
| 4432 | 4450 | ||
| 4433 | flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY; | ||
| 4434 | bc_parse_push_block_flag(p, flags); | ||
| 4435 | |||
| 4436 | s = zbc_lex_next(&p->l); | 4451 | s = zbc_lex_next(&p->l); |
| 4437 | if (s) RETURN_STATUS(s); | 4452 | if (s) RETURN_STATUS(s); |
| 4438 | 4453 | ||
| 4439 | if (p->l.t.t != BC_LEX_LBRACE) | 4454 | if (p->l.t.t != BC_LEX_LBRACE) |
| 4440 | s = bc_POSIX_requires("the left brace be on the same line as the function header"); | 4455 | s = bc_POSIX_requires("the left brace be on the same line as the function header"); |
| 4441 | 4456 | ||
| 4457 | s = zbc_parse_stmt_possibly_auto(p, true); | ||
| 4458 | if (s) RETURN_STATUS(s); | ||
| 4459 | |||
| 4460 | bc_parse_push(p, BC_INST_RET0); | ||
| 4461 | bc_parse_updateFunc(p, BC_PROG_MAIN); | ||
| 4462 | |||
| 4442 | RETURN_STATUS(s); | 4463 | RETURN_STATUS(s); |
| 4443 | 4464 | ||
| 4444 | err: | 4465 | err: |
| @@ -4455,12 +4476,11 @@ static BC_STATUS zbc_parse_auto(BcParse *p) | |||
| 4455 | bool comma, var, one; | 4476 | bool comma, var, one; |
| 4456 | char *name; | 4477 | char *name; |
| 4457 | 4478 | ||
| 4458 | if (!p->auto_part) RETURN_STATUS(bc_error_bad_token()); | 4479 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
| 4459 | |||
| 4460 | s = zbc_lex_next(&p->l); | 4480 | s = zbc_lex_next(&p->l); |
| 4461 | if (s) RETURN_STATUS(s); | 4481 | if (s) RETURN_STATUS(s); |
| 4462 | 4482 | ||
| 4463 | p->auto_part = comma = false; | 4483 | comma = false; |
| 4464 | one = p->l.t.t == BC_LEX_NAME; | 4484 | one = p->l.t.t == BC_LEX_NAME; |
| 4465 | 4485 | ||
| 4466 | while (p->l.t.t == BC_LEX_NAME) { | 4486 | while (p->l.t.t == BC_LEX_NAME) { |
| @@ -4498,91 +4518,53 @@ static BC_STATUS zbc_parse_auto(BcParse *p) | |||
| 4498 | if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON) | 4518 | if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON) |
| 4499 | RETURN_STATUS(bc_error_bad_token()); | 4519 | RETURN_STATUS(bc_error_bad_token()); |
| 4500 | 4520 | ||
| 4521 | dbg_lex_done("%s:%d done", __func__, __LINE__); | ||
| 4501 | RETURN_STATUS(zbc_lex_next(&p->l)); | 4522 | RETURN_STATUS(zbc_lex_next(&p->l)); |
| 4502 | 4523 | ||
| 4503 | err: | 4524 | err: |
| 4504 | free(name); | 4525 | free(name); |
| 4526 | dbg_lex_done("%s:%d done (ERROR)", __func__, __LINE__); | ||
| 4505 | RETURN_STATUS(s); | 4527 | RETURN_STATUS(s); |
| 4506 | } | 4528 | } |
| 4507 | #if ERRORS_ARE_FATAL | 4529 | #if ERRORS_ARE_FATAL |
| 4508 | # define zbc_parse_auto(...) (zbc_parse_auto(__VA_ARGS__), BC_STATUS_SUCCESS) | 4530 | # define zbc_parse_auto(...) (zbc_parse_auto(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4509 | #endif | 4531 | #endif |
| 4510 | 4532 | ||
| 4511 | static BC_STATUS zbc_parse_body(BcParse *p, bool brace) | 4533 | #undef zbc_parse_stmt_possibly_auto |
| 4534 | static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed) | ||
| 4512 | { | 4535 | { |
| 4513 | BcStatus s = BC_STATUS_SUCCESS; | 4536 | BcStatus s = BC_STATUS_SUCCESS; |
| 4514 | uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); | ||
| 4515 | |||
| 4516 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | ||
| 4517 | *flag_ptr &= ~(BC_PARSE_FLAG_BODY); | ||
| 4518 | 4537 | ||
| 4519 | if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) { | 4538 | dbg_lex_enter("%s:%d entered, p->l.t.t:%d", __func__, __LINE__, p->l.t.t); |
| 4520 | dbg_lex("%s:%d BC_PARSE_FLAG_FUNC_INNER", __func__, __LINE__); | ||
| 4521 | if (!brace) RETURN_STATUS(bc_error_bad_token()); | ||
| 4522 | |||
| 4523 | p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO; | ||
| 4524 | |||
| 4525 | if (!p->auto_part) { | ||
| 4526 | s = zbc_parse_auto(p); | ||
| 4527 | if (s) RETURN_STATUS(s); | ||
| 4528 | } | ||
| 4529 | 4539 | ||
| 4530 | if (p->l.t.t == BC_LEX_NLINE) s = zbc_lex_next(&p->l); | 4540 | if (p->l.t.t == BC_LEX_NLINE) { |
| 4541 | dbg_lex_done("%s:%d done (seen BC_LEX_NLINE)", __func__, __LINE__); | ||
| 4542 | RETURN_STATUS(zbc_lex_next(&p->l)); | ||
| 4531 | } | 4543 | } |
| 4532 | else { | 4544 | if (p->l.t.t == BC_LEX_SCOLON) { |
| 4533 | dbg_lex("%s:%d !BC_PARSE_FLAG_FUNC_INNER", __func__, __LINE__); | 4545 | dbg_lex_done("%s:%d done (seen BC_LEX_SCOLON)", __func__, __LINE__); |
| 4534 | s = zbc_parse_stmt(p); | 4546 | RETURN_STATUS(zbc_lex_next(&p->l)); |
| 4535 | if (!s && !brace && !BC_PARSE_BODY(p)) s = zbc_parse_endBody(p); | ||
| 4536 | } | 4547 | } |
| 4537 | 4548 | ||
| 4538 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 4549 | if (p->l.t.t == BC_LEX_LBRACE) { |
| 4539 | RETURN_STATUS(s); | 4550 | dbg_lex("%s:%d BC_LEX_LBRACE: (auto_allowed:%d)", __func__, __LINE__, auto_allowed); |
| 4540 | } | 4551 | do { |
| 4541 | #if ERRORS_ARE_FATAL | ||
| 4542 | # define zbc_parse_body(...) (zbc_parse_body(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
| 4543 | #endif | ||
| 4544 | |||
| 4545 | #undef zbc_parse_stmt | ||
| 4546 | static BC_STATUS zbc_parse_stmt(BcParse *p) | ||
| 4547 | { | ||
| 4548 | BcStatus s = BC_STATUS_SUCCESS; | ||
| 4549 | |||
| 4550 | dbg_lex_enter("%s:%d entered, p->l.t.t:%d", __func__, __LINE__, p->l.t.t); | ||
| 4551 | switch (p->l.t.t) { | ||
| 4552 | case BC_LEX_NLINE: | ||
| 4553 | dbg_lex_done("%s:%d done (seen BC_LEX_NLINE)", __func__, __LINE__); | ||
| 4554 | RETURN_STATUS(zbc_lex_next(&p->l)); | ||
| 4555 | |||
| 4556 | case BC_LEX_KEY_ELSE: | ||
| 4557 | dbg_lex("%s:%d BC_LEX_KEY_ELSE:", __func__, __LINE__); | ||
| 4558 | p->auto_part = false; | ||
| 4559 | break; | ||
| 4560 | |||
| 4561 | case BC_LEX_LBRACE: | ||
| 4562 | dbg_lex("%s:%d BC_LEX_LBRACE:", __func__, __LINE__); | ||
| 4563 | if (!BC_PARSE_BODY(p)) RETURN_STATUS(bc_error_bad_token()); | ||
| 4564 | ++p->nbraces; | ||
| 4565 | s = zbc_lex_next(&p->l); | 4552 | s = zbc_lex_next(&p->l); |
| 4566 | if (s) RETURN_STATUS(s); | 4553 | if (s) RETURN_STATUS(s); |
| 4567 | dbg_lex_done("%s:%d done (returning zbc_parse_body())", __func__, __LINE__); | 4554 | } while (p->l.t.t == BC_LEX_NLINE); |
| 4568 | RETURN_STATUS(zbc_parse_body(p, true)); | 4555 | if (auto_allowed && p->l.t.t == BC_LEX_KEY_AUTO) { |
| 4569 | 4556 | dbg_lex("%s:%d calling zbc_parse_auto()", __func__, __LINE__); | |
| 4570 | case BC_LEX_KEY_AUTO: | 4557 | s = zbc_parse_auto(p); |
| 4571 | dbg_lex("%s:%d BC_LEX_KEY_AUTO:", __func__, __LINE__); | 4558 | if (s) RETURN_STATUS(s); |
| 4572 | RETURN_STATUS(zbc_parse_auto(p)); | 4559 | } |
| 4573 | 4560 | while (p->l.t.t != BC_LEX_RBRACE) { | |
| 4574 | default: | 4561 | dbg_lex("%s:%d block parsing loop", __func__, __LINE__); |
| 4575 | p->auto_part = false; | 4562 | s = zbc_parse_stmt(p); |
| 4576 | if (BC_PARSE_IF_END(p)) { | 4563 | if (s) RETURN_STATUS(s); |
| 4577 | bc_parse_noElse(p); | 4564 | } |
| 4578 | dbg_lex_done("%s:%d done (BC_PARSE_IF_END is true)", __func__, __LINE__); | 4565 | s = zbc_lex_next(&p->l); |
| 4579 | RETURN_STATUS(BC_STATUS_SUCCESS); | 4566 | dbg_lex_done("%s:%d done (seen BC_LEX_RBRACE)", __func__, __LINE__); |
| 4580 | } | 4567 | RETURN_STATUS(s); |
| 4581 | if (BC_PARSE_BODY(p)) { | ||
| 4582 | dbg_lex_done("%s:%d done (returning zbc_parse_body())", __func__, __LINE__); | ||
| 4583 | RETURN_STATUS(zbc_parse_body(p, false)); | ||
| 4584 | } | ||
| 4585 | break; | ||
| 4586 | } | 4568 | } |
| 4587 | 4569 | ||
| 4588 | dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); | 4570 | dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); |
| @@ -4603,26 +4585,12 @@ static BC_STATUS zbc_parse_stmt(BcParse *p) | |||
| 4603 | case BC_LEX_KEY_SQRT: | 4585 | case BC_LEX_KEY_SQRT: |
| 4604 | s = zbc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr); | 4586 | s = zbc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr); |
| 4605 | break; | 4587 | break; |
| 4606 | case BC_LEX_KEY_ELSE: | ||
| 4607 | s = zbc_parse_else(p); | ||
| 4608 | break; | ||
| 4609 | case BC_LEX_SCOLON: | ||
| 4610 | while (!s && p->l.t.t == BC_LEX_SCOLON) s = zbc_lex_next(&p->l); | ||
| 4611 | break; | ||
| 4612 | case BC_LEX_RBRACE: | ||
| 4613 | if (p->nbraces == 0) | ||
| 4614 | RETURN_STATUS(bc_error_bad_token()); | ||
| 4615 | --p->nbraces; | ||
| 4616 | s = zbc_lex_next(&p->l); | ||
| 4617 | if (!s) | ||
| 4618 | s = zbc_parse_endBody(p); | ||
| 4619 | break; | ||
| 4620 | case BC_LEX_STR: | 4588 | case BC_LEX_STR: |
| 4621 | s = zbc_parse_string(p, BC_INST_PRINT_STR); | 4589 | s = zbc_parse_string(p, BC_INST_PRINT_STR); |
| 4622 | break; | 4590 | break; |
| 4623 | case BC_LEX_KEY_BREAK: | 4591 | case BC_LEX_KEY_BREAK: |
| 4624 | case BC_LEX_KEY_CONTINUE: | 4592 | case BC_LEX_KEY_CONTINUE: |
| 4625 | s = zbc_parse_loopExit(p, p->l.t.t); | 4593 | s = zbc_parse_break_or_continue(p, p->l.t.t); |
| 4626 | break; | 4594 | break; |
| 4627 | case BC_LEX_KEY_FOR: | 4595 | case BC_LEX_KEY_FOR: |
| 4628 | s = zbc_parse_for(p); | 4596 | s = zbc_parse_for(p); |
| @@ -4637,8 +4605,6 @@ static BC_STATUS zbc_parse_stmt(BcParse *p) | |||
| 4637 | case BC_LEX_KEY_LIMITS: | 4605 | case BC_LEX_KEY_LIMITS: |
| 4638 | // "limits" is a compile-time command, | 4606 | // "limits" is a compile-time command, |
| 4639 | // the output is produced at _parse time_. | 4607 | // the output is produced at _parse time_. |
| 4640 | s = zbc_lex_next(&p->l); | ||
| 4641 | if (s) RETURN_STATUS(s); | ||
| 4642 | printf( | 4608 | printf( |
| 4643 | "BC_BASE_MAX = "BC_MAX_OBASE_STR "\n" | 4609 | "BC_BASE_MAX = "BC_MAX_OBASE_STR "\n" |
| 4644 | "BC_DIM_MAX = "BC_MAX_DIM_STR "\n" | 4610 | "BC_DIM_MAX = "BC_MAX_DIM_STR "\n" |
| @@ -4649,6 +4615,7 @@ static BC_STATUS zbc_parse_stmt(BcParse *p) | |||
| 4649 | "MAX Exponent = "BC_MAX_EXP_STR "\n" | 4615 | "MAX Exponent = "BC_MAX_EXP_STR "\n" |
| 4650 | "Number of vars = "BC_MAX_VARS_STR "\n" | 4616 | "Number of vars = "BC_MAX_VARS_STR "\n" |
| 4651 | ); | 4617 | ); |
| 4618 | s = zbc_lex_next(&p->l); | ||
| 4652 | break; | 4619 | break; |
| 4653 | case BC_LEX_KEY_PRINT: | 4620 | case BC_LEX_KEY_PRINT: |
| 4654 | s = zbc_parse_print(p); | 4621 | s = zbc_parse_print(p); |
| @@ -4669,11 +4636,16 @@ static BC_STATUS zbc_parse_stmt(BcParse *p) | |||
| 4669 | break; | 4636 | break; |
| 4670 | } | 4637 | } |
| 4671 | 4638 | ||
| 4639 | if (s || G_interrupt) { | ||
| 4640 | bc_parse_reset(p); | ||
| 4641 | s = BC_STATUS_FAILURE; | ||
| 4642 | } | ||
| 4643 | |||
| 4672 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 4644 | dbg_lex_done("%s:%d done", __func__, __LINE__); |
| 4673 | RETURN_STATUS(s); | 4645 | RETURN_STATUS(s); |
| 4674 | } | 4646 | } |
| 4675 | #if ERRORS_ARE_FATAL | 4647 | #if ERRORS_ARE_FATAL |
| 4676 | # define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS) | 4648 | # define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4677 | #endif | 4649 | #endif |
| 4678 | 4650 | ||
| 4679 | static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p) | 4651 | static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p) |
| @@ -4682,22 +4654,15 @@ static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p) | |||
| 4682 | 4654 | ||
| 4683 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4655 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
| 4684 | if (p->l.t.t == BC_LEX_EOF) | 4656 | if (p->l.t.t == BC_LEX_EOF) |
| 4685 | s = BC_PARSE_FLAG_STACK_EMPTY(p) ? bc_error("end of file") : bc_error("block end could not be found"); | 4657 | s = bc_error("end of file"); |
| 4686 | else if (p->l.t.t == BC_LEX_KEY_DEFINE) { | 4658 | else if (p->l.t.t == BC_LEX_KEY_DEFINE) { |
| 4687 | dbg_lex("%s:%d p->l.t.t:BC_LEX_KEY_DEFINE", __func__, __LINE__); | 4659 | dbg_lex("%s:%d p->l.t.t:BC_LEX_KEY_DEFINE", __func__, __LINE__); |
| 4688 | if (!BC_PARSE_CAN_EXEC(p)) | ||
| 4689 | RETURN_STATUS(bc_error_bad_token()); | ||
| 4690 | s = zbc_parse_func(p); | 4660 | s = zbc_parse_func(p); |
| 4691 | } else { | 4661 | } else { |
| 4692 | dbg_lex("%s:%d p->l.t.t:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->l.t.t); | 4662 | dbg_lex("%s:%d p->l.t.t:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->l.t.t); |
| 4693 | s = zbc_parse_stmt(p); | 4663 | s = zbc_parse_stmt(p); |
| 4694 | } | 4664 | } |
| 4695 | 4665 | ||
| 4696 | if (s || G_interrupt) { | ||
| 4697 | bc_parse_reset(p); | ||
| 4698 | s = BC_STATUS_FAILURE; | ||
| 4699 | } | ||
| 4700 | |||
| 4701 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 4666 | dbg_lex_done("%s:%d done", __func__, __LINE__); |
| 4702 | RETURN_STATUS(s); | 4667 | RETURN_STATUS(s); |
| 4703 | } | 4668 | } |
| @@ -4940,6 +4905,7 @@ static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext ne | |||
| 4940 | if (prev == BC_INST_BOOL_NOT || nexprs != 1) | 4905 | if (prev == BC_INST_BOOL_NOT || nexprs != 1) |
| 4941 | return bc_error_bad_expression(); | 4906 | return bc_error_bad_expression(); |
| 4942 | 4907 | ||
| 4908 | //TODO: why is this needed at all? | ||
| 4943 | // next is BcParseNext, byte array of up to 4 BC_LEX's, packed into 32-bit word | 4909 | // next is BcParseNext, byte array of up to 4 BC_LEX's, packed into 32-bit word |
| 4944 | for (;;) { | 4910 | for (;;) { |
| 4945 | if (t == (next & 0x7f)) | 4911 | if (t == (next & 0x7f)) |
| @@ -4948,7 +4914,8 @@ static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext ne | |||
| 4948 | break; | 4914 | break; |
| 4949 | next >>= 8; | 4915 | next >>= 8; |
| 4950 | } | 4916 | } |
| 4951 | return bc_error_bad_expression(); | 4917 | if (t != BC_LEX_KEY_ELSE) |
| 4918 | return bc_error_bad_expression(); | ||
| 4952 | ok: | 4919 | ok: |
| 4953 | 4920 | ||
| 4954 | if (!(flags & BC_PARSE_REL) && nrelops) { | 4921 | if (!(flags & BC_PARSE_REL) && nrelops) { |
| @@ -6766,6 +6733,7 @@ static BC_STATUS zbc_program_exec(void) | |||
| 6766 | s = zbc_program_incdec(inst); | 6733 | s = zbc_program_incdec(inst); |
| 6767 | break; | 6734 | break; |
| 6768 | case BC_INST_HALT: | 6735 | case BC_INST_HALT: |
| 6736 | dbg_exec("BC_INST_HALT:"); | ||
| 6769 | QUIT_OR_RETURN_TO_MAIN; | 6737 | QUIT_OR_RETURN_TO_MAIN; |
| 6770 | break; | 6738 | break; |
| 6771 | case BC_INST_RET: | 6739 | case BC_INST_RET: |
| @@ -6939,6 +6907,7 @@ static BC_STATUS zbc_program_exec(void) | |||
| 6939 | break; | 6907 | break; |
| 6940 | } | 6908 | } |
| 6941 | case BC_INST_QUIT: | 6909 | case BC_INST_QUIT: |
| 6910 | dbg_exec("BC_INST_NEG:"); | ||
| 6942 | if (G.prog.stack.len <= 2) | 6911 | if (G.prog.stack.len <= 2) |
| 6943 | QUIT_OR_RETURN_TO_MAIN; | 6912 | QUIT_OR_RETURN_TO_MAIN; |
| 6944 | bc_vec_npop(&G.prog.stack, 2); | 6913 | bc_vec_npop(&G.prog.stack, 2); |
| @@ -6994,14 +6963,12 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
| 6994 | dbg_lex("%s:%d G.prs.l.t.t:%d", __func__, __LINE__, G.prs.l.t.t); | 6963 | dbg_lex("%s:%d G.prs.l.t.t:%d", __func__, __LINE__, G.prs.l.t.t); |
| 6995 | ERROR_RETURN(s =) zcommon_parse(&G.prs); | 6964 | ERROR_RETURN(s =) zcommon_parse(&G.prs); |
| 6996 | if (s) RETURN_STATUS(s); | 6965 | if (s) RETURN_STATUS(s); |
| 6997 | } | ||
| 6998 | dbg_lex("%s:%d G.prs.l.t.t:BC_LEX_EOF", __func__, __LINE__); | ||
| 6999 | |||
| 7000 | if (BC_PARSE_CAN_EXEC(&G.prs)) { | ||
| 7001 | s = zbc_program_exec(); | 6966 | s = zbc_program_exec(); |
| 7002 | fflush_and_check(); | 6967 | if (s) { |
| 7003 | if (s) | ||
| 7004 | bc_program_reset(); | 6968 | bc_program_reset(); |
| 6969 | break; | ||
| 6970 | } | ||
| 6971 | fflush_and_check(); | ||
| 7005 | } | 6972 | } |
| 7006 | 6973 | ||
| 7007 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 6974 | dbg_lex_done("%s:%d done", __func__, __LINE__); |
| @@ -7049,91 +7016,12 @@ err: | |||
| 7049 | static BC_STATUS zbc_vm_stdin(void) | 7016 | static BC_STATUS zbc_vm_stdin(void) |
| 7050 | { | 7017 | { |
| 7051 | BcStatus s; | 7018 | BcStatus s; |
| 7052 | BcVec buffer; | ||
| 7053 | size_t str; | ||
| 7054 | bool comment; | ||
| 7055 | 7019 | ||
| 7056 | //G.prog.file = NULL; - already is | 7020 | //G.prog.file = NULL; - already is |
| 7057 | bc_lex_file(&G.prs.l); | 7021 | bc_lex_file(&G.prs.l); |
| 7058 | 7022 | ||
| 7059 | bc_char_vec_init(&buffer); | 7023 | G.use_stdin = 1; |
| 7060 | 7024 | s = zbc_vm_process(""); | |
| 7061 | // This loop is complex because the vm tries not to send any lines that end | ||
| 7062 | // with a backslash to the parser. The reason for that is because the parser | ||
| 7063 | // treats a backslash+newline combo as whitespace, per the bc spec. In that | ||
| 7064 | // case, and for strings and comments, the parser will expect more stuff. | ||
| 7065 | s = BC_STATUS_SUCCESS; | ||
| 7066 | comment = false; | ||
| 7067 | str = 0; | ||
| 7068 | for (;;) { | ||
| 7069 | size_t prevlen = buffer.len; | ||
| 7070 | char *string; | ||
| 7071 | |||
| 7072 | bc_read_line(&buffer); | ||
| 7073 | // No more input means EOF | ||
| 7074 | if (buffer.len <= prevlen + 1) // (we expect +1 for NUL byte) | ||
| 7075 | break; | ||
| 7076 | |||
| 7077 | string = buffer.v + prevlen; | ||
| 7078 | while (*string) { | ||
| 7079 | char c = *string; | ||
| 7080 | if (string == buffer.v || string[-1] != '\\') { | ||
| 7081 | if (IS_BC) | ||
| 7082 | str ^= (c == '"'); | ||
| 7083 | else { | ||
| 7084 | if (c == ']') | ||
| 7085 | str -= 1; | ||
| 7086 | else if (c == '[') | ||
| 7087 | str += 1; | ||
| 7088 | } | ||
| 7089 | } | ||
| 7090 | string++; | ||
| 7091 | if (c == '/' && *string == '*') { | ||
| 7092 | comment = true; | ||
| 7093 | string++; | ||
| 7094 | continue; | ||
| 7095 | } | ||
| 7096 | if (c == '*' && *string == '/') { | ||
| 7097 | comment = false; | ||
| 7098 | string++; | ||
| 7099 | } | ||
| 7100 | } | ||
| 7101 | if (str || comment) { | ||
| 7102 | buffer.len--; // backstep over the trailing NUL byte | ||
| 7103 | continue; | ||
| 7104 | } | ||
| 7105 | |||
| 7106 | // Check for backslash+newline. | ||
| 7107 | // we do not check that last char is '\n' - | ||
| 7108 | // if it is not, then it's EOF, and looping back | ||
| 7109 | // to bc_read_line() will detect it: | ||
| 7110 | string -= 2; | ||
| 7111 | if (string >= buffer.v && *string == '\\') { | ||
| 7112 | buffer.len--; | ||
| 7113 | continue; | ||
| 7114 | } | ||
| 7115 | |||
| 7116 | s = zbc_vm_process(buffer.v); | ||
| 7117 | if (s) { | ||
| 7118 | if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin) { | ||
| 7119 | // Debug config, non-interactive mode: | ||
| 7120 | // return all the way back to main. | ||
| 7121 | // Non-debug builds do not come here, they exit. | ||
| 7122 | break; | ||
| 7123 | } | ||
| 7124 | } | ||
| 7125 | |||
| 7126 | bc_vec_pop_all(&buffer); | ||
| 7127 | } | ||
| 7128 | |||
| 7129 | if (str) { | ||
| 7130 | s = bc_error("string end could not be found"); | ||
| 7131 | } | ||
| 7132 | else if (comment) { | ||
| 7133 | s = bc_error("comment end could not be found"); | ||
| 7134 | } | ||
| 7135 | |||
| 7136 | bc_vec_free(&buffer); | ||
| 7137 | RETURN_STATUS(s); | 7025 | RETURN_STATUS(s); |
| 7138 | } | 7026 | } |
| 7139 | #if ERRORS_ARE_FATAL | 7027 | #if ERRORS_ARE_FATAL |
| @@ -7412,9 +7300,6 @@ static BC_STATUS zbc_vm_exec(void) | |||
| 7412 | if (IS_BC || (option_mask32 & BC_FLAG_I)) | 7300 | if (IS_BC || (option_mask32 & BC_FLAG_I)) |
| 7413 | s = zbc_vm_stdin(); | 7301 | s = zbc_vm_stdin(); |
| 7414 | 7302 | ||
| 7415 | if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) | ||
| 7416 | s = zbc_vm_process(""); | ||
| 7417 | |||
| 7418 | RETURN_STATUS(s); | 7303 | RETURN_STATUS(s); |
| 7419 | } | 7304 | } |
| 7420 | #if ERRORS_ARE_FATAL | 7305 | #if ERRORS_ARE_FATAL |
| @@ -7443,6 +7328,7 @@ static void bc_program_free(void) | |||
| 7443 | bc_num_free(&G.prog.last); | 7328 | bc_num_free(&G.prog.last); |
| 7444 | bc_num_free(&G.prog.zero); | 7329 | bc_num_free(&G.prog.zero); |
| 7445 | bc_num_free(&G.prog.one); | 7330 | bc_num_free(&G.prog.one); |
| 7331 | bc_vec_free(&G.stdin_buffer); | ||
| 7446 | } | 7332 | } |
| 7447 | 7333 | ||
| 7448 | static void bc_vm_free(void) | 7334 | static void bc_vm_free(void) |
| @@ -7506,6 +7392,8 @@ static void bc_program_init(void) | |||
| 7506 | bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free); | 7392 | bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free); |
| 7507 | bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL); | 7393 | bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL); |
| 7508 | bc_vec_push(&G.prog.stack, &ip); | 7394 | bc_vec_push(&G.prog.stack, &ip); |
| 7395 | |||
| 7396 | bc_char_vec_init(&G.stdin_buffer); | ||
| 7509 | } | 7397 | } |
| 7510 | 7398 | ||
| 7511 | static int bc_vm_init(const char *env_len) | 7399 | static int bc_vm_init(const char *env_len) |
| @@ -7562,6 +7450,7 @@ static BcStatus bc_vm_run(void) | |||
| 7562 | # endif | 7450 | # endif |
| 7563 | FREE_G(); | 7451 | FREE_G(); |
| 7564 | #endif | 7452 | #endif |
| 7453 | dbg_exec("exiting with exitcode %d", st); | ||
| 7565 | return st; | 7454 | return st; |
| 7566 | } | 7455 | } |
| 7567 | 7456 | ||
