diff options
author | Denys Vlasenko | 2018-12-16 17:30:35 +0100 |
---|---|---|
committer | Denys Vlasenko | 2018-12-16 17:30:35 +0100 |
commit | 202dd1943c90dea3c5c3365dd75d4e7ac9499c5f (patch) | |
tree | b8673fed2a601867b3ecb46cf313e6d60f548fed | |
parent | e9519e44a65fa80fa473cfd2041af4e7f428b81a (diff) | |
download | busybox-202dd1943c90dea3c5c3365dd75d4e7ac9499c5f.zip busybox-202dd1943c90dea3c5c3365dd75d4e7ac9499c5f.tar.gz |
bc: fixes for multi-line if/while/for
function old new delta
zbc_vm_process 561 589 +28
zbc_lex_next_and_skip_NLINE - 22 +22
zbc_parse_stmt_possibly_auto 2232 2253 +21
zbc_lex_skip_if_at_NLINE - 14 +14
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: 2/0 grow/shrink: 7/0 up/down: 110/0) Total: 110 bytes
text data bss dec hex filename
982138 485 7296 989919 f1adf busybox_old
982275 485 7296 990056 f1b68 busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/bc.c | 43 | ||||
-rwxr-xr-x | testsuite/bc.tests | 10 |
2 files changed, 45 insertions, 8 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 4dc3824..a5d7a01 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -3018,6 +3018,29 @@ static BC_STATUS zbc_lex_next(BcLex *l) # define zbc_lex_next(...) (zbc_lex_next(__VA_ARGS__), BC_STATUS_SUCCESS) #endif +static BC_STATUS zbc_lex_skip_if_at_NLINE(BcLex *l) +{ + if (l->t.t == BC_LEX_NLINE) + RETURN_STATUS(zbc_lex_next(l)); + RETURN_STATUS(BC_STATUS_SUCCESS); +} +#if ERRORS_ARE_FATAL +# define zbc_lex_skip_if_at_NLINE(...) (zbc_lex_skip_if_at_NLINE(__VA_ARGS__), BC_STATUS_SUCCESS) +#endif + +static BC_STATUS zbc_lex_next_and_skip_NLINE(BcLex *l) +{ + BcStatus s; + s = zbc_lex_next(l); + if (s) RETURN_STATUS(s); + // if(cond)<newline>stmt is accepted too (but not 2+ newlines) + s = zbc_lex_skip_if_at_NLINE(l); + RETURN_STATUS(s); +} +#if ERRORS_ARE_FATAL +# define zbc_lex_next_and_skip_NLINE(...) (zbc_lex_next_and_skip_NLINE(__VA_ARGS__), BC_STATUS_SUCCESS) +#endif + static BC_STATUS zbc_lex_text_init(BcLex *l, const char *text) { l->buf = text; @@ -4152,7 +4175,8 @@ static BC_STATUS zbc_parse_if(BcParse *p) if (s) RETURN_STATUS(s); if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); - s = zbc_lex_next(&p->l); + // if(cond)<newline>stmt is accepted too (but not 2+ newlines) + s = zbc_lex_next_and_skip_NLINE(&p->l); if (s) RETURN_STATUS(s); bc_parse_push(p, BC_INST_JUMP_ZERO); @@ -4216,12 +4240,15 @@ static BC_STATUS zbc_parse_while(BcParse *p) s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); if (s) RETURN_STATUS(s); if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); - s = zbc_lex_next(&p->l); + + // while(cond)<newline>stmt is accepted too + s = zbc_lex_next_and_skip_NLINE(&p->l); if (s) RETURN_STATUS(s); bc_parse_push(p, BC_INST_JUMP_ZERO); bc_parse_pushIndex(p, ip.idx); +//TODO: diagnose "while(cond)<newline><newline>"? Now it is seen as "while() with empty body" s = zbc_parse_stmt(p); if (s) RETURN_STATUS(s); @@ -4321,7 +4348,9 @@ static BC_STATUS zbc_parse_for(BcParse *p) bc_vec_push(&p->exits, &ip); bc_vec_push(&p->func->labels, &ip.idx); - s = zbc_lex_next(&p->l); + + // for(...)<newline>stmt is accepted as well + s = zbc_lex_next_and_skip_NLINE(&p->l); if (s) RETURN_STATUS(s); s = zbc_parse_stmt(p); @@ -4453,11 +4482,9 @@ static BC_STATUS zbc_parse_funcdef(BcParse *p) if (p->l.t.t != BC_LEX_LBRACE) s = bc_POSIX_requires("the left brace be on the same line as the function header"); - // Prevent "define z()<newline>" to be interpreted as function with empty stmt as body - while (p->l.t.t == BC_LEX_NLINE) { - s = zbc_lex_next(&p->l); - if (s) RETURN_STATUS(s); - } + // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body + s = zbc_lex_skip_if_at_NLINE(&p->l); + if (s) RETURN_STATUS(s); //TODO: GNU bc requires a {} block even if function body has single stmt, enforce this? p->in_funcdef++; // to determine whether "return" stmt is allowed, and such diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 093b395..95cc28d 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests @@ -56,6 +56,16 @@ testing "bc define with body on next line" \ "8\n9\n" \ "" "define w()\n{ auto z; return 8; }\nw()\n9" +testing "bc if(cond)<NL>" \ + "bc" \ + "9\n" \ + "" "if(0)\n3\n9" + +testing "bc while(cond)<NL>" \ + "bc" \ + "8\n7\n6\n5\n4\n3\n2\n1\n9\n" \ + "" "i=9;while(--i)\ni\n9" + tar xJf bc_large.tar.xz for f in bc*.bc; do |