aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-16 17:06:07 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-16 17:06:07 +0100
commite9519e44a65fa80fa473cfd2041af4e7f428b81a (patch)
tree57a4dbf0d5ab1c58f695db31de27575d594a77b4
parentd1d29b4245a29e56ca598d7a03d93bdf11ebc5d0 (diff)
downloadbusybox-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.c32
-rwxr-xr-xtestsuite/bc.tests5
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
596typedef struct BcProgram { 598typedef 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
4393static BC_STATUS zbc_parse_func(BcParse *p) 4392static 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
4473static BC_STATUS zbc_parse_auto(BcParse *p) 4481static 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
54testing "bc define with body on next line" \
55 "bc" \
56 "8\n9\n" \
57 "" "define w()\n{ auto z; return 8; }\nw()\n9"
58
54tar xJf bc_large.tar.xz 59tar xJf bc_large.tar.xz
55 60
56for f in bc*.bc; do 61for f in bc*.bc; do