diff options
-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 | ||