aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-17 16:54:37 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-17 17:00:29 +0100
commit4b72aebe80aaa50a765d5ff61d7d67ed731502d9 (patch)
treed922437e5da9bf034d78622dc2f5b1e0e0f539db
parentb44a7f1d6642e2da39e9f27e0b504f662ca443a2 (diff)
downloadbusybox-w32-4b72aebe80aaa50a765d5ff61d7d67ed731502d9.tar.gz
busybox-w32-4b72aebe80aaa50a765d5ff61d7d67ed731502d9.tar.bz2
busybox-w32-4b72aebe80aaa50a765d5ff61d7d67ed731502d9.zip
bc: remove "error after expression parsing" check
It is misplaced: caller knows better what can or cannot follow the expression. Sometimes even caller's caller: "if (1) return a+b else..." - parser of "return" does not know that "else" after it is valid, parser of stmt does not know it either, - only parser of "if" knows it! The removed code balked on e.g. "{ print 1 }" statement. This does not break any valid programs, but starts accepting some invalid ones, e.g. "print 1 print 2" would work. function old new delta zcommon_parse_expr 40 32 -8 zbc_parse_name 509 494 -15 zbc_parse_stmt_possibly_auto 1678 1638 -40 bc_parse_expr_empty_ok 2025 1977 -48 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/4 up/down: 0/-111) Total: -111 bytes text data bss dec hex filename 981599 485 7296 989380 f18c4 busybox_old 981488 485 7296 989269 f1855 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--miscutils/bc.c282
-rwxr-xr-xtestsuite/bc.tests5
2 files changed, 136 insertions, 151 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 214ea44ab..45d9eb8eb 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -390,7 +390,6 @@ typedef struct BcInstPtr {
390 390
391// BC_LEX_NEG is not used in lexing; it is only for parsing. 391// BC_LEX_NEG is not used in lexing; it is only for parsing.
392typedef enum BcLexType { 392typedef enum BcLexType {
393
394 BC_LEX_EOF, 393 BC_LEX_EOF,
395 BC_LEX_INVALID, 394 BC_LEX_INVALID,
396 395
@@ -553,7 +552,93 @@ enum {
553 | (1 << 19) // 19 552 | (1 << 19) // 19
554}; 553};
555#define bc_lex_kws_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK) 554#define bc_lex_kws_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK)
555
556// This is a bit array that corresponds to token types. An entry is
557// true if the token is valid in an expression, false otherwise.
558// Used to figure out when expr parsing should stop *without error message*
559// - 0 element indicates this condition. 1 means "this token is to be eaten
560// as part of the expression", token can them still be determined to be invalid
561// by later processing.
562enum {
563#define EXBITS(a,b,c,d,e,f,g,h) \
564 ((uint64_t)((a << 0)+(b << 1)+(c << 2)+(d << 3)+(e << 4)+(f << 5)+(g << 6)+(h << 7)))
565 BC_PARSE_EXPRS_BITS = 0
566 + (EXBITS(0,0,1,1,1,1,1,1) << (0*8)) // 0: eof inval ++ -- - ^ * /
567 + (EXBITS(1,1,1,1,1,1,1,1) << (1*8)) // 8: % + - == <= >= != <
568 + (EXBITS(1,1,1,1,1,1,1,1) << (2*8)) // 16: > ! || && ^= *= /= %=
569 + (EXBITS(1,1,1,0,0,1,1,0) << (3*8)) // 24: += -= = NL WS ( ) [
570 + (EXBITS(0,0,0,0,0,0,1,1) << (4*8)) // 32: , ] { ; } STR NAME NUM
571 + (EXBITS(0,0,0,0,0,0,0,1) << (5*8)) // 40: auto break cont define else for halt ibase
572 + (EXBITS(0,1,1,1,1,0,0,1) << (6*8)) // 48: if last len limits obase print quit read - bug, why "limits" is allowed?
573 + (EXBITS(0,1,1,0,0,0,0,0) << (7*8)) // 56: return scale sqrt while
574#undef EXBITS
575};
576static ALWAYS_INLINE long bc_parse_exprs(unsigned i)
577{
578#if ULONG_MAX > 0xffffffff
579 // 64-bit version (will not work correctly for 32-bit longs!)
580 return BC_PARSE_EXPRS_BITS & (1UL << i);
581#else
582 // 32-bit version
583 unsigned long m = (uint32_t)BC_PARSE_EXPRS_BITS;
584 if (i >= 32) {
585 m = (uint32_t)(BC_PARSE_EXPRS_BITS >> 32);
586 i &= 31;
587 }
588 return m & (1UL << i);
556#endif 589#endif
590}
591
592// This is an array of data for operators that correspond to
593// [BC_LEX_OP_INC...BC_LEX_OP_ASSIGN] token types.
594static const uint8_t bc_parse_ops[] = {
595#define OP(p,l) ((int)(l) * 0x10 + (p))
596 OP(0, false), OP( 0, false ), // inc dec
597 OP(1, false), // neg
598 OP(2, false), // pow
599 OP(3, true ), OP( 3, true ), OP( 3, true ), // mul div mod
600 OP(4, true ), OP( 4, true ), // + -
601 OP(6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), // == <= >= != < >
602 OP(1, false), // not
603 OP(7, true ), OP( 7, true ), // or and
604 OP(5, false), OP( 5, false ), OP( 5, false ), OP( 5, false ), OP( 5, false ), // ^= *= /= %= +=
605 OP(5, false), OP( 5, false ), // -= =
606#undef OP
607};
608#define bc_parse_op_PREC(i) (bc_parse_ops[i] & 0x0f)
609#define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
610#endif // ENABLE_BC
611
612#if ENABLE_DC
613static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1
614int8_t
615dc_parse_insts[] = {
616 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
617 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
618 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
619 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
620 BC_INST_INVALID, BC_INST_INVALID,
621 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
622 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
623 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
624 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
625 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
626 BC_INST_INVALID, BC_INST_INVALID,
627 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
628 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
629 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
630 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
631 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
632 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
633 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
634 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
635 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
636 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
637 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
638 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
639};
640#endif // ENABLE_DC
641
557 642
558typedef struct BcLex { 643typedef struct BcLex {
559 const char *buf; 644 const char *buf;
@@ -735,106 +820,6 @@ struct globals {
735#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b')) 820#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
736#define IS_DC (ENABLE_DC && (!ENABLE_BC || applet_name[0] != 'b')) 821#define IS_DC (ENABLE_DC && (!ENABLE_BC || applet_name[0] != 'b'))
737 822
738#if ENABLE_BC
739
740// This is a bit array that corresponds to token types. An entry is
741// true if the token is valid in an expression, false otherwise.
742enum {
743 BC_PARSE_EXPRS_BITS = 0
744 + ((uint64_t)((0 << 0)+(0 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (0*8))
745 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (1*8))
746 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (2*8))
747 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(0 << 3)+(0 << 4)+(1 << 5)+(1 << 6)+(0 << 7)) << (3*8))
748 + ((uint64_t)((0 << 0)+(0 << 1)+(0 << 2)+(0 << 3)+(0 << 4)+(0 << 5)+(1 << 6)+(1 << 7)) << (4*8))
749 + ((uint64_t)((0 << 0)+(0 << 1)+(0 << 2)+(0 << 3)+(0 << 4)+(0 << 5)+(0 << 6)+(1 << 7)) << (5*8))
750 + ((uint64_t)((0 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(0 << 5)+(0 << 6)+(1 << 7)) << (6*8))
751 + ((uint64_t)((0 << 0)+(1 << 1)+(1 << 2)+(0 << 3) ) << (7*8))
752};
753static ALWAYS_INLINE long bc_parse_exprs(unsigned i)
754{
755#if ULONG_MAX > 0xffffffff
756 // 64-bit version (will not work correctly for 32-bit longs!)
757 return BC_PARSE_EXPRS_BITS & (1UL << i);
758#else
759 // 32-bit version
760 unsigned long m = (uint32_t)BC_PARSE_EXPRS_BITS;
761 if (i >= 32) {
762 m = (uint32_t)(BC_PARSE_EXPRS_BITS >> 32);
763 i &= 31;
764 }
765 return m & (1UL << i);
766#endif
767}
768
769// This is an array of data for operators that correspond to token types.
770static const uint8_t bc_parse_ops[] = {
771#define OP(p,l) ((int)(l) * 0x10 + (p))
772 OP(0, false), OP( 0, false ), // inc dec
773 OP(1, false), // neg
774 OP(2, false),
775 OP(3, true ), OP( 3, true ), OP( 3, true ), // pow mul div
776 OP(4, true ), OP( 4, true ), // mod + -
777 OP(6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), // == <= >= != < >
778 OP(1, false), // not
779 OP(7, true ), OP( 7, true ), // or and
780 OP(5, false), OP( 5, false ), OP( 5, false ), OP( 5, false ), OP( 5, false ), // ^= *= /= %= +=
781 OP(5, false), OP( 5, false ), // -= =
782#undef OP
783};
784#define bc_parse_op_PREC(i) (bc_parse_ops[i] & 0x0f)
785#define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
786
787// Byte array of up to 4 BC_LEX's, packed into 32-bit word
788typedef uint32_t BcParseNext;
789
790// These identify what tokens can come after expressions in certain cases.
791enum {
792#define BC_PARSE_NEXT4(a,b,c,d) ( (a) | ((b)<<8) | ((c)<<16) | ((((d)|0x80)<<24)) )
793#define BC_PARSE_NEXT2(a,b) BC_PARSE_NEXT4(a,b,0xff,0xff)
794#define BC_PARSE_NEXT1(a) BC_PARSE_NEXT4(a,0xff,0xff,0xff)
795 bc_parse_next_expr = BC_PARSE_NEXT4(BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF),
796 bc_parse_next_param = BC_PARSE_NEXT2(BC_LEX_RPAREN, BC_LEX_COMMA),
797 bc_parse_next_print = BC_PARSE_NEXT4(BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF),
798 bc_parse_next_rel = BC_PARSE_NEXT1(BC_LEX_RPAREN),
799 bc_parse_next_elem = BC_PARSE_NEXT1(BC_LEX_RBRACKET),
800 bc_parse_next_for = BC_PARSE_NEXT1(BC_LEX_SCOLON),
801 bc_parse_next_read = BC_PARSE_NEXT2(BC_LEX_NLINE, BC_LEX_EOF),
802#undef BC_PARSE_NEXT4
803#undef BC_PARSE_NEXT2
804#undef BC_PARSE_NEXT1
805};
806#endif // ENABLE_BC
807
808#if ENABLE_DC
809static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1
810int8_t
811dc_parse_insts[] = {
812 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
813 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
814 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
815 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
816 BC_INST_INVALID, BC_INST_INVALID,
817 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
818 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
819 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
820 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
821 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
822 BC_INST_INVALID, BC_INST_INVALID,
823 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
824 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
825 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
826 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
827 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
828 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
829 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
830 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
831 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
832 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
833 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
834 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
835};
836#endif // ENABLE_DC
837
838// In configurations where errors abort instead of propagating error 823// In configurations where errors abort instead of propagating error
839// return code up the call chain, functions returning BC_STATUS 824// return code up the call chain, functions returning BC_STATUS
840// actually don't return anything, they always succeed and return "void". 825// actually don't return anything, they always succeed and return "void".
@@ -3535,9 +3520,15 @@ static void bc_parse_number(BcParse *p)
3535IF_BC(static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p);) 3520IF_BC(static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p);)
3536IF_DC(static BC_STATUS zdc_parse_parse(BcParse *p);) 3521IF_DC(static BC_STATUS zdc_parse_parse(BcParse *p);)
3537 3522
3523// "Parse" half of "parse,execute,repeat" main loop
3538static BC_STATUS zcommon_parse(BcParse *p) 3524static BC_STATUS zcommon_parse(BcParse *p)
3539{ 3525{
3540 if (IS_BC) { 3526 if (IS_BC) {
3527// FIXME: "eating" of stmt delemiters is coded inconsistently
3528// (sometimes zbc_parse_stmt() eats the delimiter, sometimes don't),
3529// which causes bugs such as "print 1 print 2" erroneously accepted,
3530// or "print 1 else 2" detecting parse error only after executing
3531// "print 1" part.
3541 IF_BC(RETURN_STATUS(zbc_parse_stmt_or_funcdef(p));) 3532 IF_BC(RETURN_STATUS(zbc_parse_stmt_or_funcdef(p));)
3542 } 3533 }
3543 IF_DC(RETURN_STATUS(zdc_parse_parse(p));) 3534 IF_DC(RETURN_STATUS(zdc_parse_parse(p));)
@@ -3625,10 +3616,20 @@ static void bc_parse_create(BcParse *p, size_t func)
3625// first in the expr enum. Note: This only works for binary operators. 3616// 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)) 3617#define BC_TOKEN_2_INST(t) ((char) ((t) - BC_LEX_NEG + BC_INST_NEG))
3627 3618
3628static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed); 3619static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags);
3629static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); 3620
3630static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next); 3621static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags)
3622{
3623 BcStatus s;
3624
3625 s = bc_parse_expr_empty_ok(p, flags);
3626 if (s == BC_STATUS_PARSE_EMPTY_EXP)
3627 RETURN_STATUS(bc_error("empty expression"));
3628 RETURN_STATUS(s);
3629}
3631#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS) 3630#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
3631
3632static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed);
3632#define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__) COMMA_SUCCESS) 3633#define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__) COMMA_SUCCESS)
3633 3634
3634static BC_STATUS zbc_parse_stmt(BcParse *p) 3635static BC_STATUS zbc_parse_stmt(BcParse *p)
@@ -3699,26 +3700,30 @@ static BC_STATUS zbc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3699static BC_STATUS zbc_parse_params(BcParse *p, uint8_t flags) 3700static BC_STATUS zbc_parse_params(BcParse *p, uint8_t flags)
3700{ 3701{
3701 BcStatus s; 3702 BcStatus s;
3702 bool comma = false;
3703 size_t nparams; 3703 size_t nparams;
3704 3704
3705 dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); 3705 dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t);
3706 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3707
3706 s = zbc_lex_next(&p->l); 3708 s = zbc_lex_next(&p->l);
3707 if (s) RETURN_STATUS(s); 3709 if (s) RETURN_STATUS(s);
3708 3710
3709 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) { 3711 nparams = 0;
3710 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY; 3712 if (p->l.t.t != BC_LEX_RPAREN) {
3711 s = zbc_parse_expr(p, flags, bc_parse_next_param); 3713 for (;;) {
3712 if (s) RETURN_STATUS(s); 3714 s = zbc_parse_expr(p, flags);
3713 3715 if (s) RETURN_STATUS(s);
3714 comma = p->l.t.t == BC_LEX_COMMA; 3716 nparams++;
3715 if (comma) { 3717 if (p->l.t.t != BC_LEX_COMMA) {
3718 if (p->l.t.t == BC_LEX_RPAREN)
3719 break;
3720 RETURN_STATUS(bc_error_bad_token());
3721 }
3716 s = zbc_lex_next(&p->l); 3722 s = zbc_lex_next(&p->l);
3717 if (s) RETURN_STATUS(s); 3723 if (s) RETURN_STATUS(s);
3718 } 3724 }
3719 } 3725 }
3720 3726
3721 if (comma) RETURN_STATUS(bc_error_bad_token());
3722 bc_parse_push(p, BC_INST_CALL); 3727 bc_parse_push(p, BC_INST_CALL);
3723 bc_parse_pushIndex(p, nparams); 3728 bc_parse_pushIndex(p, nparams);
3724 3729
@@ -3785,7 +3790,7 @@ static BC_STATUS zbc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3785 } else { 3790 } else {
3786 *type = BC_INST_ARRAY_ELEM; 3791 *type = BC_INST_ARRAY_ELEM;
3787 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL); 3792 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3788 s = zbc_parse_expr(p, flags, bc_parse_next_elem); 3793 s = zbc_parse_expr(p, flags);
3789 if (s) goto err; 3794 if (s) goto err;
3790 } 3795 }
3791 s = zbc_lex_next(&p->l); 3796 s = zbc_lex_next(&p->l);
@@ -3848,7 +3853,7 @@ static BC_STATUS zbc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3848 s = zbc_lex_next(&p->l); 3853 s = zbc_lex_next(&p->l);
3849 if (s) RETURN_STATUS(s); 3854 if (s) RETURN_STATUS(s);
3850 3855
3851 s = zbc_parse_expr(p, flags, bc_parse_next_rel); 3856 s = zbc_parse_expr(p, flags);
3852 if (s) RETURN_STATUS(s); 3857 if (s) RETURN_STATUS(s);
3853 3858
3854 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); 3859 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
@@ -3879,7 +3884,7 @@ static BC_STATUS zbc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3879 s = zbc_lex_next(&p->l); 3884 s = zbc_lex_next(&p->l);
3880 if (s) RETURN_STATUS(s); 3885 if (s) RETURN_STATUS(s);
3881 3886
3882 s = zbc_parse_expr(p, flags, bc_parse_next_rel); 3887 s = zbc_parse_expr(p, flags);
3883 if (s) RETURN_STATUS(s); 3888 if (s) RETURN_STATUS(s);
3884 if (p->l.t.t != BC_LEX_RPAREN) 3889 if (p->l.t.t != BC_LEX_RPAREN)
3885 RETURN_STATUS(bc_error_bad_token()); 3890 RETURN_STATUS(bc_error_bad_token());
@@ -3999,7 +4004,7 @@ static BC_STATUS zbc_parse_print(BcParse *p)
3999 if (type == BC_LEX_STR) { 4004 if (type == BC_LEX_STR) {
4000 s = zbc_parse_string(p, BC_INST_PRINT_POP); 4005 s = zbc_parse_string(p, BC_INST_PRINT_POP);
4001 } else { 4006 } else {
4002 s = zbc_parse_expr(p, 0, bc_parse_next_print); 4007 s = zbc_parse_expr(p, 0);
4003 bc_parse_push(p, BC_INST_PRINT_POP); 4008 bc_parse_push(p, BC_INST_PRINT_POP);
4004 } 4009 }
4005 if (s) RETURN_STATUS(s); 4010 if (s) RETURN_STATUS(s);
@@ -4025,7 +4030,7 @@ static BC_STATUS zbc_parse_return(BcParse *p)
4025 bc_parse_push(p, BC_INST_RET0); 4030 bc_parse_push(p, BC_INST_RET0);
4026 else { 4031 else {
4027 bool paren = (t == BC_LEX_LPAREN); 4032 bool paren = (t == BC_LEX_LPAREN);
4028 s = bc_parse_expr_empty_ok(p, 0, bc_parse_next_expr); 4033 s = bc_parse_expr_empty_ok(p, 0);
4029 if (s == BC_STATUS_PARSE_EMPTY_EXP) { 4034 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4030 bc_parse_push(p, BC_INST_RET0); 4035 bc_parse_push(p, BC_INST_RET0);
4031 s = zbc_lex_next(&p->l); 4036 s = zbc_lex_next(&p->l);
@@ -4063,7 +4068,7 @@ static BC_STATUS zbc_parse_if(BcParse *p)
4063 4068
4064 s = zbc_lex_next(&p->l); 4069 s = zbc_lex_next(&p->l);
4065 if (s) RETURN_STATUS(s); 4070 if (s) RETURN_STATUS(s);
4066 s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); 4071 s = zbc_parse_expr(p, BC_PARSE_REL);
4067 if (s) RETURN_STATUS(s); 4072 if (s) RETURN_STATUS(s);
4068 4073
4069 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); 4074 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
@@ -4123,7 +4128,7 @@ static BC_STATUS zbc_parse_while(BcParse *p)
4123 bc_vec_push(&p->exits, &ip_idx); 4128 bc_vec_push(&p->exits, &ip_idx);
4124 bc_vec_push(&p->func->labels, &ip_idx); 4129 bc_vec_push(&p->func->labels, &ip_idx);
4125 4130
4126 s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); 4131 s = zbc_parse_expr(p, BC_PARSE_REL);
4127 if (s) RETURN_STATUS(s); 4132 if (s) RETURN_STATUS(s);
4128 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); 4133 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4129 4134
@@ -4158,7 +4163,7 @@ static BC_STATUS zbc_parse_for(BcParse *p)
4158 if (s) RETURN_STATUS(s); 4163 if (s) RETURN_STATUS(s);
4159 4164
4160 if (p->l.t.t != BC_LEX_SCOLON) 4165 if (p->l.t.t != BC_LEX_SCOLON)
4161 s = zbc_parse_expr(p, 0, bc_parse_next_for); 4166 s = zbc_parse_expr(p, 0);
4162 else 4167 else
4163 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init"); 4168 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4164 4169
@@ -4175,7 +4180,7 @@ static BC_STATUS zbc_parse_for(BcParse *p)
4175 bc_vec_push(&p->func->labels, &p->func->code.len); 4180 bc_vec_push(&p->func->labels, &p->func->code.len);
4176 4181
4177 if (p->l.t.t != BC_LEX_SCOLON) 4182 if (p->l.t.t != BC_LEX_SCOLON)
4178 s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for); 4183 s = zbc_parse_expr(p, BC_PARSE_REL);
4179 else 4184 else
4180 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition"); 4185 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4181 4186
@@ -4192,7 +4197,7 @@ static BC_STATUS zbc_parse_for(BcParse *p)
4192 bc_vec_push(&p->func->labels, &p->func->code.len); 4197 bc_vec_push(&p->func->labels, &p->func->code.len);
4193 4198
4194 if (p->l.t.t != BC_LEX_RPAREN) 4199 if (p->l.t.t != BC_LEX_RPAREN)
4195 s = zbc_parse_expr(p, 0, bc_parse_next_rel); 4200 s = zbc_parse_expr(p, 0);
4196 else 4201 else
4197 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update"); 4202 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4198 4203
@@ -4444,7 +4449,7 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed)
4444 case BC_LEX_KEY_READ: 4449 case BC_LEX_KEY_READ:
4445 case BC_LEX_KEY_SCALE: 4450 case BC_LEX_KEY_SCALE:
4446 case BC_LEX_KEY_SQRT: 4451 case BC_LEX_KEY_SQRT:
4447 s = zbc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr); 4452 s = zbc_parse_expr(p, BC_PARSE_PRINT);
4448 break; 4453 break;
4449 case BC_LEX_STR: 4454 case BC_LEX_STR:
4450 s = zbc_parse_string(p, BC_INST_PRINT_STR); 4455 s = zbc_parse_string(p, BC_INST_PRINT_STR);
@@ -4530,7 +4535,7 @@ static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p)
4530#define zbc_parse_stmt_or_funcdef(...) (zbc_parse_stmt_or_funcdef(__VA_ARGS__) COMMA_SUCCESS) 4535#define zbc_parse_stmt_or_funcdef(...) (zbc_parse_stmt_or_funcdef(__VA_ARGS__) COMMA_SUCCESS)
4531 4536
4532// This is not a "z" function: can also return BC_STATUS_PARSE_EMPTY_EXP 4537// This is not a "z" function: can also return BC_STATUS_PARSE_EMPTY_EXP
4533static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next) 4538static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags)
4534{ 4539{
4535 BcStatus s = BC_STATUS_SUCCESS; 4540 BcStatus s = BC_STATUS_SUCCESS;
4536 BcInst prev = BC_INST_PRINT; 4541 BcInst prev = BC_INST_PRINT;
@@ -4766,19 +4771,6 @@ static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext ne
4766 if (prev == BC_INST_BOOL_NOT || nexprs != 1) 4771 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4767 return bc_error_bad_expression(); 4772 return bc_error_bad_expression();
4768 4773
4769//TODO: why is this needed at all?
4770 // next is BcParseNext, byte array of up to 4 BC_LEX's, packed into 32-bit word
4771 for (;;) {
4772 if (t == (next & 0x7f))
4773 goto ok;
4774 if (next & 0x80) // last element?
4775 break;
4776 next >>= 8;
4777 }
4778 if (t != BC_LEX_KEY_ELSE)
4779 return bc_error_bad_expression();
4780 ok:
4781
4782 if (!(flags & BC_PARSE_REL) && nrelops) { 4774 if (!(flags & BC_PARSE_REL) && nrelops) {
4783 s = bc_POSIX_does_not_allow("comparison operators outside if or loops"); 4775 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
4784 IF_ERROR_RETURN_POSSIBLE(if (s) return s); 4776 IF_ERROR_RETURN_POSSIBLE(if (s) return s);
@@ -4797,18 +4789,6 @@ static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext ne
4797 return s; 4789 return s;
4798} 4790}
4799 4791
4800#undef zbc_parse_expr
4801static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4802{
4803 BcStatus s;
4804
4805 s = bc_parse_expr_empty_ok(p, flags, next);
4806 if (s == BC_STATUS_PARSE_EMPTY_EXP)
4807 RETURN_STATUS(bc_error("empty expression"));
4808 RETURN_STATUS(s);
4809}
4810#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
4811
4812#endif // ENABLE_BC 4792#endif // ENABLE_BC
4813 4793
4814#if ENABLE_DC 4794#if ENABLE_DC
@@ -5008,7 +4988,7 @@ static BC_STATUS zdc_parse_parse(BcParse *p)
5008static BC_STATUS zcommon_parse_expr(BcParse *p, uint8_t flags) 4988static BC_STATUS zcommon_parse_expr(BcParse *p, uint8_t flags)
5009{ 4989{
5010 if (IS_BC) { 4990 if (IS_BC) {
5011 IF_BC(RETURN_STATUS(zbc_parse_expr(p, flags, bc_parse_next_read))); 4991 IF_BC(RETURN_STATUS(zbc_parse_expr(p, flags)));
5012 } else { 4992 } else {
5013 IF_DC(RETURN_STATUS(zdc_parse_expr(p, flags))); 4993 IF_DC(RETURN_STATUS(zdc_parse_expr(p, flags)));
5014 } 4994 }
diff --git a/testsuite/bc.tests b/testsuite/bc.tests
index d057bea17..e0a45a8bd 100755
--- a/testsuite/bc.tests
+++ b/testsuite/bc.tests
@@ -76,6 +76,11 @@ testing "bc print 1,2,3" \
76 "123" \ 76 "123" \
77 "" "print 1,2,3" 77 "" "print 1,2,3"
78 78
79testing "bc { print 1 }" \
80 "bc" \
81 "1" \
82 "" "{ print 1 }"
83
79testing "bc nested loops and breaks" \ 84testing "bc nested loops and breaks" \
80 "bc" \ 85 "bc" \
81 "\ 86 "\