diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-16 17:30:35 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-16 17:30:35 +0100 |
commit | 202dd1943c90dea3c5c3365dd75d4e7ac9499c5f (patch) | |
tree | b8673fed2a601867b3ecb46cf313e6d60f548fed | |
parent | e9519e44a65fa80fa473cfd2041af4e7f428b81a (diff) | |
download | busybox-w32-202dd1943c90dea3c5c3365dd75d4e7ac9499c5f.tar.gz busybox-w32-202dd1943c90dea3c5c3365dd75d4e7ac9499c5f.tar.bz2 busybox-w32-202dd1943c90dea3c5c3365dd75d4e7ac9499c5f.zip |
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 4dc382476..a5d7a01c0 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -3018,6 +3018,29 @@ static BC_STATUS zbc_lex_next(BcLex *l) | |||
3018 | # define zbc_lex_next(...) (zbc_lex_next(__VA_ARGS__), BC_STATUS_SUCCESS) | 3018 | # define zbc_lex_next(...) (zbc_lex_next(__VA_ARGS__), BC_STATUS_SUCCESS) |
3019 | #endif | 3019 | #endif |
3020 | 3020 | ||
3021 | static BC_STATUS zbc_lex_skip_if_at_NLINE(BcLex *l) | ||
3022 | { | ||
3023 | if (l->t.t == BC_LEX_NLINE) | ||
3024 | RETURN_STATUS(zbc_lex_next(l)); | ||
3025 | RETURN_STATUS(BC_STATUS_SUCCESS); | ||
3026 | } | ||
3027 | #if ERRORS_ARE_FATAL | ||
3028 | # define zbc_lex_skip_if_at_NLINE(...) (zbc_lex_skip_if_at_NLINE(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
3029 | #endif | ||
3030 | |||
3031 | static BC_STATUS zbc_lex_next_and_skip_NLINE(BcLex *l) | ||
3032 | { | ||
3033 | BcStatus s; | ||
3034 | s = zbc_lex_next(l); | ||
3035 | if (s) RETURN_STATUS(s); | ||
3036 | // if(cond)<newline>stmt is accepted too (but not 2+ newlines) | ||
3037 | s = zbc_lex_skip_if_at_NLINE(l); | ||
3038 | RETURN_STATUS(s); | ||
3039 | } | ||
3040 | #if ERRORS_ARE_FATAL | ||
3041 | # define zbc_lex_next_and_skip_NLINE(...) (zbc_lex_next_and_skip_NLINE(__VA_ARGS__), BC_STATUS_SUCCESS) | ||
3042 | #endif | ||
3043 | |||
3021 | static BC_STATUS zbc_lex_text_init(BcLex *l, const char *text) | 3044 | static BC_STATUS zbc_lex_text_init(BcLex *l, const char *text) |
3022 | { | 3045 | { |
3023 | l->buf = text; | 3046 | l->buf = text; |
@@ -4152,7 +4175,8 @@ static BC_STATUS zbc_parse_if(BcParse *p) | |||
4152 | if (s) RETURN_STATUS(s); | 4175 | if (s) RETURN_STATUS(s); |
4153 | 4176 | ||
4154 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | 4177 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); |
4155 | s = zbc_lex_next(&p->l); | 4178 | // if(cond)<newline>stmt is accepted too (but not 2+ newlines) |
4179 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
4156 | if (s) RETURN_STATUS(s); | 4180 | if (s) RETURN_STATUS(s); |
4157 | 4181 | ||
4158 | bc_parse_push(p, BC_INST_JUMP_ZERO); | 4182 | bc_parse_push(p, BC_INST_JUMP_ZERO); |
@@ -4216,12 +4240,15 @@ static BC_STATUS zbc_parse_while(BcParse *p) | |||
4216 | s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); | 4240 | s = zbc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); |
4217 | if (s) RETURN_STATUS(s); | 4241 | if (s) RETURN_STATUS(s); |
4218 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | 4242 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); |
4219 | s = zbc_lex_next(&p->l); | 4243 | |
4244 | // while(cond)<newline>stmt is accepted too | ||
4245 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
4220 | if (s) RETURN_STATUS(s); | 4246 | if (s) RETURN_STATUS(s); |
4221 | 4247 | ||
4222 | bc_parse_push(p, BC_INST_JUMP_ZERO); | 4248 | bc_parse_push(p, BC_INST_JUMP_ZERO); |
4223 | bc_parse_pushIndex(p, ip.idx); | 4249 | bc_parse_pushIndex(p, ip.idx); |
4224 | 4250 | ||
4251 | //TODO: diagnose "while(cond)<newline><newline>"? Now it is seen as "while() with empty body" | ||
4225 | s = zbc_parse_stmt(p); | 4252 | s = zbc_parse_stmt(p); |
4226 | if (s) RETURN_STATUS(s); | 4253 | if (s) RETURN_STATUS(s); |
4227 | 4254 | ||
@@ -4321,7 +4348,9 @@ static BC_STATUS zbc_parse_for(BcParse *p) | |||
4321 | 4348 | ||
4322 | bc_vec_push(&p->exits, &ip); | 4349 | bc_vec_push(&p->exits, &ip); |
4323 | bc_vec_push(&p->func->labels, &ip.idx); | 4350 | bc_vec_push(&p->func->labels, &ip.idx); |
4324 | s = zbc_lex_next(&p->l); | 4351 | |
4352 | // for(...)<newline>stmt is accepted as well | ||
4353 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
4325 | if (s) RETURN_STATUS(s); | 4354 | if (s) RETURN_STATUS(s); |
4326 | 4355 | ||
4327 | s = zbc_parse_stmt(p); | 4356 | s = zbc_parse_stmt(p); |
@@ -4453,11 +4482,9 @@ static BC_STATUS zbc_parse_funcdef(BcParse *p) | |||
4453 | if (p->l.t.t != BC_LEX_LBRACE) | 4482 | if (p->l.t.t != BC_LEX_LBRACE) |
4454 | s = bc_POSIX_requires("the left brace be on the same line as the function header"); | 4483 | s = bc_POSIX_requires("the left brace be on the same line as the function header"); |
4455 | 4484 | ||
4456 | // Prevent "define z()<newline>" to be interpreted as function with empty stmt as body | 4485 | // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body |
4457 | while (p->l.t.t == BC_LEX_NLINE) { | 4486 | s = zbc_lex_skip_if_at_NLINE(&p->l); |
4458 | s = zbc_lex_next(&p->l); | 4487 | if (s) RETURN_STATUS(s); |
4459 | if (s) RETURN_STATUS(s); | ||
4460 | } | ||
4461 | //TODO: GNU bc requires a {} block even if function body has single stmt, enforce this? | 4488 | //TODO: GNU bc requires a {} block even if function body has single stmt, enforce this? |
4462 | 4489 | ||
4463 | p->in_funcdef++; // to determine whether "return" stmt is allowed, and such | 4490 | p->in_funcdef++; // to determine whether "return" stmt is allowed, and such |
diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 093b3950e..95cc28dad 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests | |||
@@ -56,6 +56,16 @@ testing "bc define with body on next line" \ | |||
56 | "8\n9\n" \ | 56 | "8\n9\n" \ |
57 | "" "define w()\n{ auto z; return 8; }\nw()\n9" | 57 | "" "define w()\n{ auto z; return 8; }\nw()\n9" |
58 | 58 | ||
59 | testing "bc if(cond)<NL>" \ | ||
60 | "bc" \ | ||
61 | "9\n" \ | ||
62 | "" "if(0)\n3\n9" | ||
63 | |||
64 | testing "bc while(cond)<NL>" \ | ||
65 | "bc" \ | ||
66 | "8\n7\n6\n5\n4\n3\n2\n1\n9\n" \ | ||
67 | "" "i=9;while(--i)\ni\n9" | ||
68 | |||
59 | tar xJf bc_large.tar.xz | 69 | tar xJf bc_large.tar.xz |
60 | 70 | ||
61 | for f in bc*.bc; do | 71 | for f in bc*.bc; do |