diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-16 17:06:07 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-16 17:06:07 +0100 |
commit | e9519e44a65fa80fa473cfd2041af4e7f428b81a (patch) | |
tree | 57a4dbf0d5ab1c58f695db31de27575d594a77b4 | |
parent | d1d29b4245a29e56ca598d7a03d93bdf11ebc5d0 (diff) | |
download | busybox-w32-e9519e44a65fa80fa473cfd2041af4e7f428b81a.tar.gz busybox-w32-e9519e44a65fa80fa473cfd2041af4e7f428b81a.tar.bz2 busybox-w32-e9519e44a65fa80fa473cfd2041af4e7f428b81a.zip |
bc: fix handling of 'return' not in functions, and 'define f()<newline>{...}'
function old new delta
zbc_vm_process 561 597 +36
zbc_parse_stmt_possibly_auto 2232 2253 +21
zbc_lex_number 192 200 +8
zbc_num_divmod 150 156 +6
bc_vm_run 134 139 +5
bc_vm_init 757 760 +3
bc_num_printNewline 51 54 +3
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 7/0 up/down: 82/0) Total: 82 bytes
text data bss dec hex filename
982138 485 7296 989919 f1adf busybox_old
982247 485 7296 990028 f1b4c busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/bc.c | 32 | ||||
-rwxr-xr-x | testsuite/bc.tests | 5 |
2 files changed, 29 insertions, 8 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 95ba8b094..4dc382476 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -591,6 +591,8 @@ typedef struct BcParse { | |||
591 | 591 | ||
592 | //TODO: needed? Example? | 592 | //TODO: needed? Example? |
593 | size_t nbraces; | 593 | size_t nbraces; |
594 | |||
595 | size_t in_funcdef; | ||
594 | } BcParse; | 596 | } BcParse; |
595 | 597 | ||
596 | typedef struct BcProgram { | 598 | typedef struct BcProgram { |
@@ -4057,19 +4059,16 @@ static BC_STATUS zbc_parse_return(BcParse *p) | |||
4057 | { | 4059 | { |
4058 | BcStatus s; | 4060 | BcStatus s; |
4059 | BcLexType t; | 4061 | BcLexType t; |
4060 | bool paren; | ||
4061 | 4062 | ||
4062 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4063 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
4063 | |||
4064 | s = zbc_lex_next(&p->l); | 4064 | s = zbc_lex_next(&p->l); |
4065 | if (s) RETURN_STATUS(s); | 4065 | if (s) RETURN_STATUS(s); |
4066 | 4066 | ||
4067 | t = p->l.t.t; | 4067 | t = p->l.t.t; |
4068 | paren = t == BC_LEX_LPAREN; | ||
4069 | |||
4070 | if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON) | 4068 | if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON) |
4071 | bc_parse_push(p, BC_INST_RET0); | 4069 | bc_parse_push(p, BC_INST_RET0); |
4072 | else { | 4070 | else { |
4071 | bool paren = (t == BC_LEX_LPAREN); | ||
4073 | s = bc_parse_expr_empty_ok(p, 0, bc_parse_next_expr); | 4072 | s = bc_parse_expr_empty_ok(p, 0, bc_parse_next_expr); |
4074 | if (s == BC_STATUS_PARSE_EMPTY_EXP) { | 4073 | if (s == BC_STATUS_PARSE_EMPTY_EXP) { |
4075 | bc_parse_push(p, BC_INST_RET0); | 4074 | bc_parse_push(p, BC_INST_RET0); |
@@ -4390,7 +4389,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcParse *p, BcLexType type) | |||
4390 | # define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__), BC_STATUS_SUCCESS) | 4389 | # define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__), BC_STATUS_SUCCESS) |
4391 | #endif | 4390 | #endif |
4392 | 4391 | ||
4393 | static BC_STATUS zbc_parse_func(BcParse *p) | 4392 | static BC_STATUS zbc_parse_funcdef(BcParse *p) |
4394 | { | 4393 | { |
4395 | BcStatus s; | 4394 | BcStatus s; |
4396 | bool var, comma = false; | 4395 | bool var, comma = false; |
@@ -4454,7 +4453,16 @@ static BC_STATUS zbc_parse_func(BcParse *p) | |||
4454 | if (p->l.t.t != BC_LEX_LBRACE) | 4453 | if (p->l.t.t != BC_LEX_LBRACE) |
4455 | s = bc_POSIX_requires("the left brace be on the same line as the function header"); | 4454 | s = bc_POSIX_requires("the left brace be on the same line as the function header"); |
4456 | 4455 | ||
4456 | // Prevent "define z()<newline>" to be interpreted as function with empty stmt as body | ||
4457 | while (p->l.t.t == BC_LEX_NLINE) { | ||
4458 | s = zbc_lex_next(&p->l); | ||
4459 | if (s) RETURN_STATUS(s); | ||
4460 | } | ||
4461 | //TODO: GNU bc requires a {} block even if function body has single stmt, enforce this? | ||
4462 | |||
4463 | p->in_funcdef++; // to determine whether "return" stmt is allowed, and such | ||
4457 | s = zbc_parse_stmt_possibly_auto(p, true); | 4464 | s = zbc_parse_stmt_possibly_auto(p, true); |
4465 | p->in_funcdef--; | ||
4458 | if (s) RETURN_STATUS(s); | 4466 | if (s) RETURN_STATUS(s); |
4459 | 4467 | ||
4460 | bc_parse_push(p, BC_INST_RET0); | 4468 | bc_parse_push(p, BC_INST_RET0); |
@@ -4467,7 +4475,7 @@ err: | |||
4467 | RETURN_STATUS(s); | 4475 | RETURN_STATUS(s); |
4468 | } | 4476 | } |
4469 | #if ERRORS_ARE_FATAL | 4477 | #if ERRORS_ARE_FATAL |
4470 | # define zbc_parse_func(...) (zbc_parse_func(__VA_ARGS__), BC_STATUS_SUCCESS) | 4478 | # define zbc_parse_funcdef(...) (zbc_parse_funcdef(__VA_ARGS__), BC_STATUS_SUCCESS) |
4471 | #endif | 4479 | #endif |
4472 | 4480 | ||
4473 | static BC_STATUS zbc_parse_auto(BcParse *p) | 4481 | static BC_STATUS zbc_parse_auto(BcParse *p) |
@@ -4626,6 +4634,8 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed) | |||
4626 | // not when it is executed | 4634 | // not when it is executed |
4627 | QUIT_OR_RETURN_TO_MAIN; | 4635 | QUIT_OR_RETURN_TO_MAIN; |
4628 | case BC_LEX_KEY_RETURN: | 4636 | case BC_LEX_KEY_RETURN: |
4637 | if (!p->in_funcdef) | ||
4638 | RETURN_STATUS(bc_error("'return' not in a function")); | ||
4629 | s = zbc_parse_return(p); | 4639 | s = zbc_parse_return(p); |
4630 | break; | 4640 | break; |
4631 | case BC_LEX_KEY_WHILE: | 4641 | case BC_LEX_KEY_WHILE: |
@@ -4657,7 +4667,7 @@ static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p) | |||
4657 | s = bc_error("end of file"); | 4667 | s = bc_error("end of file"); |
4658 | else if (p->l.t.t == BC_LEX_KEY_DEFINE) { | 4668 | else if (p->l.t.t == BC_LEX_KEY_DEFINE) { |
4659 | dbg_lex("%s:%d p->l.t.t:BC_LEX_KEY_DEFINE", __func__, __LINE__); | 4669 | dbg_lex("%s:%d p->l.t.t:BC_LEX_KEY_DEFINE", __func__, __LINE__); |
4660 | s = zbc_parse_func(p); | 4670 | s = zbc_parse_funcdef(p); |
4661 | } else { | 4671 | } else { |
4662 | dbg_lex("%s:%d p->l.t.t:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->l.t.t); | 4672 | dbg_lex("%s:%d p->l.t.t:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->l.t.t); |
4663 | s = zbc_parse_stmt(p); | 4673 | s = zbc_parse_stmt(p); |
@@ -7021,7 +7031,13 @@ static BC_STATUS zbc_vm_stdin(void) | |||
7021 | bc_lex_file(&G.prs.l); | 7031 | bc_lex_file(&G.prs.l); |
7022 | 7032 | ||
7023 | G.use_stdin = 1; | 7033 | G.use_stdin = 1; |
7024 | s = zbc_vm_process(""); | 7034 | do { |
7035 | s = zbc_vm_process(""); | ||
7036 | // We do not stop looping on errors here. | ||
7037 | // Example: start interactive bc and enter "return". | ||
7038 | // It should say "'return' not in a function" | ||
7039 | // but should not exit. | ||
7040 | } while (G.use_stdin); | ||
7025 | RETURN_STATUS(s); | 7041 | RETURN_STATUS(s); |
7026 | } | 7042 | } |
7027 | #if ERRORS_ARE_FATAL | 7043 | #if ERRORS_ARE_FATAL |
diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 86220ad19..093b3950e 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests | |||
@@ -51,6 +51,11 @@ testing "bc define auto" \ | |||
51 | "8\n9\n" \ | 51 | "8\n9\n" \ |
52 | "" "define w() { auto z; return 8; }; w(); 9" | 52 | "" "define w() { auto z; return 8; }; w(); 9" |
53 | 53 | ||
54 | testing "bc define with body on next line" \ | ||
55 | "bc" \ | ||
56 | "8\n9\n" \ | ||
57 | "" "define w()\n{ auto z; return 8; }\nw()\n9" | ||
58 | |||
54 | tar xJf bc_large.tar.xz | 59 | tar xJf bc_large.tar.xz |
55 | 60 | ||
56 | for f in bc*.bc; do | 61 | for f in bc*.bc; do |