aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/bc.c631
-rwxr-xr-xtestsuite/bc.tests5
-rw-r--r--testsuite/bc_misc2.bc3
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
174static unsigned lex_indent; 174static 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
560typedef struct BcLex { 560typedef 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
609typedef struct BcParse { 581typedef 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
628typedef struct BcProgram { 596typedef struct BcProgram {
@@ -666,26 +634,6 @@ typedef struct BcProgram {
666 634
667} BcProgram; 635} BcProgram;
668 636
669static 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
683static 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
2909static 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
2958static BC_STATUS zbc_lex_next(BcLex *l) 2982static 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
3529static BC_STATUS zbc_parse_text_init(BcParse *p, const char *text) 3559static 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
3593static void bc_parse_free(BcParse *p) 3611static 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
3628static BC_STATUS zbc_parse_else(BcParse *p); 3644static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed);
3629static BC_STATUS zbc_parse_stmt(BcParse *p);
3630static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); 3645static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
3631static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next); 3646static 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
3652static 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
3638static void bc_parse_operator(BcParse *p, BcLexType type, size_t start, 3660static 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
4072static BC_STATUS zbc_parse_endBody(BcParse *p) 4095static 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); 4108static 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
4136static 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
4153static BC_STATUS zbc_parse_if(BcParse *p) 4138static 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);
4189static 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
4217static BC_STATUS zbc_parse_while(BcParse *p) 4191static 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
4335static BC_STATUS zbc_parse_loopExit(BcParse *p, BcLexType type) 4356static 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
4374static BC_STATUS zbc_parse_func(BcParse *p) 4393static 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
4444err: 4465err:
@@ -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
4503err: 4524err:
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
4511static BC_STATUS zbc_parse_body(BcParse *p, bool brace) 4533#undef zbc_parse_stmt_possibly_auto
4534static 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
4546static 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
4679static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p) 4651static 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:
7049static BC_STATUS zbc_vm_stdin(void) 7016static 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
7448static void bc_vm_free(void) 7334static 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
7511static int bc_vm_init(const char *env_len) 7399static 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
49testing "bc define auto" \
50 "bc" \
51 "8\n9\n" \
52 "" "define w() { auto z; return 8; }; w(); 9"
53
49tar xJf bc_large.tar.xz 54tar xJf bc_large.tar.xz
50 55
51for f in bc*.bc; do 56for 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
42u() 42u()
43 43
44if (x == -4) x 44if (x == -4) x else x - 4
45else x - 4