diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-16 16:03:03 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-16 16:10:38 +0100 |
commit | d1d29b4245a29e56ca598d7a03d93bdf11ebc5d0 (patch) | |
tree | 28425d3549a37a53503334b57ace61fef58417ce | |
parent | 99b37623356a1555359df1c011d4a6732918a5c4 (diff) | |
download | busybox-w32-d1d29b4245a29e56ca598d7a03d93bdf11ebc5d0.tar.gz busybox-w32-d1d29b4245a29e56ca598d7a03d93bdf11ebc5d0.tar.bz2 busybox-w32-d1d29b4245a29e56ca598d7a03d93bdf11ebc5d0.zip |
bc: partially rewrite parser, tests pass, ^C might be broken now
The entire control construct (if/while/for/funcdef) or {} block is
"eaten" by the corresponding parsing function, instead of maintaining
special "block flag stack" with magic bits in it, and returning to main
input loop after every inner statement (every input line, essentially).
This required moving line input deep into lexer - now zbc_lex_next()
triggers more reading when needed.
"block flag stack" is gone.
Correctness of ^C handling wasn't checked, might need fixing now.
if/else syntax is changed to match GNU bc: "else" can not be on
the next line (the rationale is that "if (1) 2" statement in interactive
mode should execute and print 2 instead of waiting for possible
"else ..." line).
This change fixes the following examples:
if (1) if (1) 1 else 2 else 3
if (0) 1 else if (1) 2
define w() { auto z; return 1; }
function old new delta
zbc_parse_stmt_possibly_auto - 2232 +2232
zbc_vm_process 89 561 +472
zbc_lex_next 1982 2296 +314
bc_vm_init 749 757 +8
bc_parse_expr_empty_ok 2016 2021 +5
bc_num_printNewline 54 51 -3
zbc_program_read 289 280 -9
bc_parse_free 47 38 -9
bc_parse_reset 126 113 -13
bc_parse_create 108 92 -16
bc_parse_push_block_flag 47 - -47
bc_parse_noElse 48 - -48
zbc_parse_text_init 113 59 -54
zbc_parse_body 121 - -121
zbc_parse_else 125 - -125
zbc_parse_endBody 254 - -254
bc_vm_run 421 134 -287
zbc_parse_auto 290 - -290
zcommon_parse 476 - -476
zbc_parse_stmt 1682 7 -1675
------------------------------------------------------------------------------
(add/remove: 1/7 grow/shrink: 4/8 up/down: 3031/-3427) Total: -396 bytes
text data bss dec hex filename
982586 485 7296 990367 f1c9f busybox_old
982138 485 7296 989919 f1adf busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/bc.c | 631 | ||||
-rwxr-xr-x | testsuite/bc.tests | 5 | ||||
-rw-r--r-- | testsuite/bc_misc2.bc | 3 |
3 files changed, 266 insertions, 373 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 | ||
diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 79ece2669..86220ad19 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests | |||
@@ -46,6 +46,11 @@ testing "bc if 0 else if 1" \ | |||
46 | "2\n9\n" \ | 46 | "2\n9\n" \ |
47 | "" "if (0) 1 else if (1) 2; 9" | 47 | "" "if (0) 1 else if (1) 2; 9" |
48 | 48 | ||
49 | testing "bc define auto" \ | ||
50 | "bc" \ | ||
51 | "8\n9\n" \ | ||
52 | "" "define w() { auto z; return 8; }; w(); 9" | ||
53 | |||
49 | tar xJf bc_large.tar.xz | 54 | tar xJf bc_large.tar.xz |
50 | 55 | ||
51 | for f in bc*.bc; do | 56 | for f in bc*.bc; do |
diff --git a/testsuite/bc_misc2.bc b/testsuite/bc_misc2.bc index f5a6a6b13..44fc40fa1 100644 --- a/testsuite/bc_misc2.bc +++ b/testsuite/bc_misc2.bc | |||
@@ -41,5 +41,4 @@ define u() { | |||
41 | 41 | ||
42 | u() | 42 | u() |
43 | 43 | ||
44 | if (x == -4) x | 44 | if (x == -4) x else x - 4 |
45 | else x - 4 | ||