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 | "\ |
