diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-17 16:54:37 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-17 17:00:29 +0100 |
commit | 4b72aebe80aaa50a765d5ff61d7d67ed731502d9 (patch) | |
tree | d922437e5da9bf034d78622dc2f5b1e0e0f539db | |
parent | b44a7f1d6642e2da39e9f27e0b504f662ca443a2 (diff) | |
download | busybox-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.c | 282 | ||||
-rwxr-xr-x | testsuite/bc.tests | 5 |
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. |
392 | typedef enum BcLexType { | 392 | typedef 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. | ||
562 | enum { | ||
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 | }; | ||
576 | static 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. | ||
594 | static 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 | ||
613 | static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1 | ||
614 | int8_t | ||
615 | dc_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 | ||
558 | typedef struct BcLex { | 643 | typedef 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. | ||
742 | enum { | ||
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 | }; | ||
753 | static 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. | ||
770 | static 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 | ||
788 | typedef uint32_t BcParseNext; | ||
789 | |||
790 | // These identify what tokens can come after expressions in certain cases. | ||
791 | enum { | ||
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 | ||
809 | static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1 | ||
810 | int8_t | ||
811 | dc_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) | |||
3535 | IF_BC(static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p);) | 3520 | IF_BC(static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p);) |
3536 | IF_DC(static BC_STATUS zdc_parse_parse(BcParse *p);) | 3521 | IF_DC(static BC_STATUS zdc_parse_parse(BcParse *p);) |
3537 | 3522 | ||
3523 | // "Parse" half of "parse,execute,repeat" main loop | ||
3538 | static BC_STATUS zcommon_parse(BcParse *p) | 3524 | static 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 | ||
3628 | static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed); | 3619 | static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags); |
3629 | static BC_STATUS zbc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); | 3620 | |
3630 | static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next); | 3621 | static 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 | |||
3632 | static 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 | ||
3634 | static BC_STATUS zbc_parse_stmt(BcParse *p) | 3635 | static 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) | |||
3699 | static BC_STATUS zbc_parse_params(BcParse *p, uint8_t flags) | 3700 | static 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 |
4533 | static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next) | 4538 | static 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 | ||
4801 | static 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) | |||
5008 | static BC_STATUS zcommon_parse_expr(BcParse *p, uint8_t flags) | 4988 | static 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 | ||
79 | testing "bc { print 1 }" \ | ||
80 | "bc" \ | ||
81 | "1" \ | ||
82 | "" "{ print 1 }" | ||
83 | |||
79 | testing "bc nested loops and breaks" \ | 84 | testing "bc nested loops and breaks" \ |
80 | "bc" \ | 85 | "bc" \ |
81 | "\ | 86 | "\ |