diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-17 00:07:48 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-17 00:07:48 +0100 |
| commit | 94f72a387c13e4620635ee47ec7c5aa6bbbb473c (patch) | |
| tree | b232271dd8ebe72499e29dbbb88e7cba6eb62042 /miscutils | |
| parent | 5ebd2a612843821989f979b4277931d53b90671d (diff) | |
| download | busybox-w32-94f72a387c13e4620635ee47ec7c5aa6bbbb473c.tar.gz busybox-w32-94f72a387c13e4620635ee47ec7c5aa6bbbb473c.tar.bz2 busybox-w32-94f72a387c13e4620635ee47ec7c5aa6bbbb473c.zip | |
bc: factor out common code
function old new delta
zbc_parse_stmt_allow_NLINE_before - 59 +59
bc_parse_pushJUMP_ZERO - 27 +27
bc_parse_pushJUMP - 27 +27
rewrite_label_to_current - 19 +19
zbc_vm_process 594 599 +5
zbc_lex_next_and_skip_NLINE 22 - -22
zbc_parse_stmt_fail_if_bare_NLINE 28 - -28
zbc_parse_stmt_possibly_auto 1909 1678 -231
------------------------------------------------------------------------------
(add/remove: 4/2 grow/shrink: 1/1 up/down: 137/-281) Total: -144 bytes
text data bss dec hex filename
981879 485 7296 989660 f19dc busybox_old
981755 485 7296 989536 f1960 busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils')
| -rw-r--r-- | miscutils/bc.c | 108 |
1 files changed, 51 insertions, 57 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 56a2bca71..9f23a0601 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
| @@ -3556,6 +3556,18 @@ static void bc_parse_pushIndex(BcParse *p, size_t idx) | |||
| 3556 | } | 3556 | } |
| 3557 | } | 3557 | } |
| 3558 | 3558 | ||
| 3559 | static void bc_parse_pushJUMP(BcParse *p, size_t idx) | ||
| 3560 | { | ||
| 3561 | bc_parse_push(p, BC_INST_JUMP); | ||
| 3562 | bc_parse_pushIndex(p, idx); | ||
| 3563 | } | ||
| 3564 | |||
| 3565 | static void bc_parse_pushJUMP_ZERO(BcParse *p, size_t idx) | ||
| 3566 | { | ||
| 3567 | bc_parse_push(p, BC_INST_JUMP_ZERO); | ||
| 3568 | bc_parse_pushIndex(p, idx); | ||
| 3569 | } | ||
| 3570 | |||
| 3559 | static void bc_parse_number(BcParse *p) | 3571 | static void bc_parse_number(BcParse *p) |
| 3560 | { | 3572 | { |
| 3561 | char *num = xstrdup(p->l.t.v.v); | 3573 | char *num = xstrdup(p->l.t.v.v); |
| @@ -3677,14 +3689,19 @@ static BC_STATUS zbc_parse_stmt(BcParse *p) | |||
| 3677 | # define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS) | 3689 | # define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 3678 | #endif | 3690 | #endif |
| 3679 | 3691 | ||
| 3680 | static BC_STATUS zbc_parse_stmt_fail_if_bare_NLINE(BcParse *p, bool auto_allowed, const char *after_X) | 3692 | static BC_STATUS zbc_parse_stmt_allow_NLINE_before(BcParse *p, const char *after_X) |
| 3681 | { | 3693 | { |
| 3694 | // "if(cond)<newline>stmt" is accepted too, but not 2+ newlines. | ||
| 3695 | // Same for "else", "while()", "for()". | ||
| 3696 | BcStatus s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
| 3697 | if (s) RETURN_STATUS(s); | ||
| 3682 | if (p->l.t.t == BC_LEX_NLINE) | 3698 | if (p->l.t.t == BC_LEX_NLINE) |
| 3683 | RETURN_STATUS(bc_error_fmt("no statement after '%s'", after_X)); | 3699 | RETURN_STATUS(bc_error_fmt("no statement after '%s'", after_X)); |
| 3684 | RETURN_STATUS(zbc_parse_stmt_possibly_auto(p, auto_allowed)); | 3700 | |
| 3701 | RETURN_STATUS(zbc_parse_stmt(p)); | ||
| 3685 | } | 3702 | } |
| 3686 | #if ERRORS_ARE_FATAL | 3703 | #if ERRORS_ARE_FATAL |
| 3687 | # define zbc_parse_stmt_fail_if_bare_NLINE(...) (zbc_parse_stmt_fail_if_bare_NLINE(__VA_ARGS__), BC_STATUS_SUCCESS) | 3704 | # define zbc_parse_stmt_allow_NLINE_before(...) (zbc_parse_stmt_allow_NLINE_before(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 3688 | #endif | 3705 | #endif |
| 3689 | 3706 | ||
| 3690 | static void bc_parse_operator(BcParse *p, BcLexType type, size_t start, | 3707 | static void bc_parse_operator(BcParse *p, BcLexType type, size_t start, |
| @@ -4106,11 +4123,16 @@ static BC_STATUS zbc_parse_return(BcParse *p) | |||
| 4106 | # define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__), BC_STATUS_SUCCESS) | 4123 | # define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__), BC_STATUS_SUCCESS) |
| 4107 | #endif | 4124 | #endif |
| 4108 | 4125 | ||
| 4126 | static void rewrite_label_to_current(BcParse *p, size_t idx) | ||
| 4127 | { | ||
| 4128 | size_t *label = bc_vec_item(&p->func->labels, idx); | ||
| 4129 | *label = p->func->code.len; | ||
| 4130 | } | ||
| 4131 | |||
| 4109 | static BC_STATUS zbc_parse_if(BcParse *p) | 4132 | static BC_STATUS zbc_parse_if(BcParse *p) |
| 4110 | { | 4133 | { |
| 4111 | BcStatus s; | 4134 | BcStatus s; |
| 4112 | size_t ip_idx; | 4135 | size_t ip_idx; |
| 4113 | size_t *label; | ||
| 4114 | 4136 | ||
| 4115 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4137 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
| 4116 | s = zbc_lex_next(&p->l); | 4138 | s = zbc_lex_next(&p->l); |
| @@ -4123,45 +4145,35 @@ static BC_STATUS zbc_parse_if(BcParse *p) | |||
| 4123 | if (s) RETURN_STATUS(s); | 4145 | if (s) RETURN_STATUS(s); |
| 4124 | 4146 | ||
| 4125 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | 4147 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); |
| 4126 | // if(cond)<newline>stmt is accepted too (but not 2+ newlines) | ||
| 4127 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
| 4128 | if (s) RETURN_STATUS(s); | ||
| 4129 | 4148 | ||
| 4130 | bc_parse_push(p, BC_INST_JUMP_ZERO); | ||
| 4131 | ip_idx = p->func->labels.len; | 4149 | ip_idx = p->func->labels.len; |
| 4132 | bc_parse_pushIndex(p, ip_idx); | 4150 | bc_parse_pushJUMP_ZERO(p, ip_idx); |
| 4133 | bc_vec_push(&p->func->labels, &ip_idx); | 4151 | bc_vec_push(&p->func->labels, &ip_idx); |
| 4134 | 4152 | ||
| 4135 | s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "if"); | 4153 | s = zbc_parse_stmt_allow_NLINE_before(p, "if"); |
| 4136 | if (s) RETURN_STATUS(s); | 4154 | if (s) RETURN_STATUS(s); |
| 4137 | 4155 | ||
| 4138 | dbg_lex("%s:%d in if after stmt: p->l.t.t:%d", __func__, __LINE__, p->l.t.t); | 4156 | dbg_lex("%s:%d in if after stmt: p->l.t.t:%d", __func__, __LINE__, p->l.t.t); |
| 4139 | if (p->l.t.t == BC_LEX_KEY_ELSE) { | 4157 | if (p->l.t.t == BC_LEX_KEY_ELSE) { |
| 4140 | size_t ip2_idx; | 4158 | size_t ip2_idx; |
| 4141 | 4159 | ||
| 4142 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
| 4143 | if (s) RETURN_STATUS(s); | ||
| 4144 | |||
| 4145 | ip2_idx = p->func->labels.len; | 4160 | ip2_idx = p->func->labels.len; |
| 4146 | 4161 | ||
| 4147 | dbg_lex("%s:%d after if() body: BC_INST_JUMP to %d", __func__, __LINE__, ip2_idx); | 4162 | dbg_lex("%s:%d after if() body: BC_INST_JUMP to %d", __func__, __LINE__, ip2_idx); |
| 4148 | bc_parse_push(p, BC_INST_JUMP); | 4163 | bc_parse_pushJUMP(p, ip2_idx); |
| 4149 | bc_parse_pushIndex(p, ip2_idx); | ||
| 4150 | 4164 | ||
| 4151 | label = bc_vec_item(&p->func->labels, ip_idx); | 4165 | dbg_lex("%s:%d rewriting 'if_zero' label to jump to 'else'-> %d", __func__, __LINE__, p->func->code.len); |
| 4152 | dbg_lex("%s:%d rewriting 'if_zero' label to jump to 'else': %d -> %d", __func__, __LINE__, *label, p->func->code.len); | 4166 | rewrite_label_to_current(p, ip_idx); |
| 4153 | *label = p->func->code.len; | ||
| 4154 | 4167 | ||
| 4155 | bc_vec_push(&p->func->labels, &ip2_idx); | 4168 | bc_vec_push(&p->func->labels, &ip2_idx); |
| 4156 | ip_idx = ip2_idx; | 4169 | ip_idx = ip2_idx; |
| 4157 | 4170 | ||
| 4158 | s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "else"); | 4171 | s = zbc_parse_stmt_allow_NLINE_before(p, "else"); |
| 4159 | if (s) RETURN_STATUS(s); | 4172 | if (s) RETURN_STATUS(s); |
| 4160 | } | 4173 | } |
| 4161 | 4174 | ||
| 4162 | label = bc_vec_item(&p->func->labels, ip_idx); | 4175 | dbg_lex("%s:%d rewriting label to jump after 'if' body-> %d", __func__, __LINE__, p->func->code.len); |
| 4163 | dbg_lex("%s:%d rewriting label to jump after 'if' body: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | 4176 | rewrite_label_to_current(p, ip_idx); |
| 4164 | *label = p->func->code.len; | ||
| 4165 | 4177 | ||
| 4166 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 4178 | dbg_lex_done("%s:%d done", __func__, __LINE__); |
| 4167 | RETURN_STATUS(s); | 4179 | RETURN_STATUS(s); |
| @@ -4173,7 +4185,6 @@ static BC_STATUS zbc_parse_if(BcParse *p) | |||
| 4173 | static BC_STATUS zbc_parse_while(BcParse *p) | 4185 | static BC_STATUS zbc_parse_while(BcParse *p) |
| 4174 | { | 4186 | { |
| 4175 | BcStatus s; | 4187 | BcStatus s; |
| 4176 | size_t *label; | ||
| 4177 | size_t cond_idx; | 4188 | size_t cond_idx; |
| 4178 | size_t ip_idx; | 4189 | size_t ip_idx; |
| 4179 | 4190 | ||
| @@ -4196,23 +4207,16 @@ static BC_STATUS zbc_parse_while(BcParse *p) | |||
| 4196 | if (s) RETURN_STATUS(s); | 4207 | if (s) RETURN_STATUS(s); |
| 4197 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | 4208 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); |
| 4198 | 4209 | ||
| 4199 | // while(cond)<newline>stmt is accepted too | 4210 | bc_parse_pushJUMP_ZERO(p, ip_idx); |
| 4200 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
| 4201 | if (s) RETURN_STATUS(s); | ||
| 4202 | 4211 | ||
| 4203 | bc_parse_push(p, BC_INST_JUMP_ZERO); | 4212 | s = zbc_parse_stmt_allow_NLINE_before(p, "while"); |
| 4204 | bc_parse_pushIndex(p, ip_idx); | ||
| 4205 | |||
| 4206 | s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "while"); | ||
| 4207 | if (s) RETURN_STATUS(s); | 4213 | if (s) RETURN_STATUS(s); |
| 4208 | 4214 | ||
| 4209 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, cond_idx); | 4215 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, cond_idx); |
| 4210 | bc_parse_push(p, BC_INST_JUMP); | 4216 | bc_parse_pushJUMP(p, cond_idx); |
| 4211 | bc_parse_pushIndex(p, cond_idx); | ||
| 4212 | 4217 | ||
| 4213 | label = bc_vec_item(&p->func->labels, ip_idx); | 4218 | dbg_lex("%s:%d rewriting label-> %d", __func__, __LINE__, p->func->code.len); |
| 4214 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | 4219 | rewrite_label_to_current(p, ip_idx); |
| 4215 | *label = p->func->code.len; | ||
| 4216 | 4220 | ||
| 4217 | bc_vec_pop(&p->exits); | 4221 | bc_vec_pop(&p->exits); |
| 4218 | bc_vec_pop(&p->conds); | 4222 | bc_vec_pop(&p->conds); |
| @@ -4226,7 +4230,6 @@ static BC_STATUS zbc_parse_while(BcParse *p) | |||
| 4226 | static BC_STATUS zbc_parse_for(BcParse *p) | 4230 | static BC_STATUS zbc_parse_for(BcParse *p) |
| 4227 | { | 4231 | { |
| 4228 | BcStatus s; | 4232 | BcStatus s; |
| 4229 | size_t *label; | ||
| 4230 | size_t cond_idx, exit_idx, body_idx, update_idx; | 4233 | size_t cond_idx, exit_idx, body_idx, update_idx; |
| 4231 | 4234 | ||
| 4232 | dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); | 4235 | dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); |
| @@ -4264,10 +4267,8 @@ static BC_STATUS zbc_parse_for(BcParse *p) | |||
| 4264 | s = zbc_lex_next(&p->l); | 4267 | s = zbc_lex_next(&p->l); |
| 4265 | if (s) RETURN_STATUS(s); | 4268 | if (s) RETURN_STATUS(s); |
| 4266 | 4269 | ||
| 4267 | bc_parse_push(p, BC_INST_JUMP_ZERO); | 4270 | bc_parse_pushJUMP_ZERO(p, exit_idx); |
| 4268 | bc_parse_pushIndex(p, exit_idx); | 4271 | bc_parse_pushJUMP(p, body_idx); |
| 4269 | bc_parse_push(p, BC_INST_JUMP); | ||
| 4270 | bc_parse_pushIndex(p, body_idx); | ||
| 4271 | 4272 | ||
| 4272 | bc_vec_push(&p->conds, &update_idx); | 4273 | bc_vec_push(&p->conds, &update_idx); |
| 4273 | bc_vec_push(&p->func->labels, &p->func->code.len); | 4274 | bc_vec_push(&p->func->labels, &p->func->code.len); |
| @@ -4280,28 +4281,20 @@ static BC_STATUS zbc_parse_for(BcParse *p) | |||
| 4280 | if (s) RETURN_STATUS(s); | 4281 | if (s) RETURN_STATUS(s); |
| 4281 | 4282 | ||
| 4282 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); | 4283 | if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); |
| 4283 | bc_parse_push(p, BC_INST_JUMP); | 4284 | bc_parse_pushJUMP(p, cond_idx); |
| 4284 | bc_parse_pushIndex(p, cond_idx); | ||
| 4285 | bc_vec_push(&p->func->labels, &p->func->code.len); | 4285 | bc_vec_push(&p->func->labels, &p->func->code.len); |
| 4286 | 4286 | ||
| 4287 | bc_vec_push(&p->exits, &exit_idx); | 4287 | bc_vec_push(&p->exits, &exit_idx); |
| 4288 | bc_vec_push(&p->func->labels, &exit_idx); | 4288 | bc_vec_push(&p->func->labels, &exit_idx); |
| 4289 | 4289 | ||
| 4290 | // for(...)<newline>stmt is accepted as well | 4290 | s = zbc_parse_stmt_allow_NLINE_before(p, "for"); |
| 4291 | s = zbc_lex_next_and_skip_NLINE(&p->l); | ||
| 4292 | if (s) RETURN_STATUS(s); | ||
| 4293 | |||
| 4294 | s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "for"); | ||
| 4295 | if (s) RETURN_STATUS(s); | 4291 | if (s) RETURN_STATUS(s); |
| 4296 | 4292 | ||
| 4297 | //TODO: commonalize? | ||
| 4298 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, update_idx); | 4293 | dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, update_idx); |
| 4299 | bc_parse_push(p, BC_INST_JUMP); | 4294 | bc_parse_pushJUMP(p, update_idx); |
| 4300 | bc_parse_pushIndex(p, update_idx); | ||
| 4301 | 4295 | ||
| 4302 | label = bc_vec_item(&p->func->labels, exit_idx); | 4296 | dbg_lex("%s:%d rewriting label-> %d", __func__, __LINE__, p->func->code.len); |
| 4303 | dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); | 4297 | rewrite_label_to_current(p, exit_idx); |
| 4304 | *label = p->func->code.len; | ||
| 4305 | 4298 | ||
| 4306 | bc_vec_pop(&p->exits); | 4299 | bc_vec_pop(&p->exits); |
| 4307 | bc_vec_pop(&p->conds); | 4300 | bc_vec_pop(&p->conds); |
| @@ -4325,8 +4318,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcParse *p, BcLexType type) | |||
| 4325 | i = *(size_t*)bc_vec_top(&p->conds); | 4318 | i = *(size_t*)bc_vec_top(&p->conds); |
| 4326 | } | 4319 | } |
| 4327 | 4320 | ||
| 4328 | bc_parse_push(p, BC_INST_JUMP); | 4321 | bc_parse_pushJUMP(p, i); |
| 4329 | bc_parse_pushIndex(p, i); | ||
| 4330 | 4322 | ||
| 4331 | s = zbc_lex_next(&p->l); | 4323 | s = zbc_lex_next(&p->l); |
| 4332 | if (s) RETURN_STATUS(s); | 4324 | if (s) RETURN_STATUS(s); |
| @@ -4407,10 +4399,12 @@ static BC_STATUS zbc_parse_funcdef(BcParse *p) | |||
| 4407 | // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body | 4399 | // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body |
| 4408 | s = zbc_lex_skip_if_at_NLINE(&p->l); | 4400 | s = zbc_lex_skip_if_at_NLINE(&p->l); |
| 4409 | if (s) RETURN_STATUS(s); | 4401 | if (s) RETURN_STATUS(s); |
| 4410 | //TODO: GNU bc requires a {} block even if function body has single stmt, enforce this? | 4402 | //GNU bc requires a {} block even if function body has single stmt, enforce this? |
| 4403 | if (p->l.t.t != BC_LEX_LBRACE) | ||
| 4404 | RETURN_STATUS(bc_error("function { body } expected")); | ||
| 4411 | 4405 | ||
| 4412 | p->in_funcdef++; // to determine whether "return" stmt is allowed, and such | 4406 | p->in_funcdef++; // to determine whether "return" stmt is allowed, and such |
| 4413 | s = zbc_parse_stmt_fail_if_bare_NLINE(p, true, "define"); | 4407 | s = zbc_parse_stmt_possibly_auto(p, true); |
| 4414 | p->in_funcdef--; | 4408 | p->in_funcdef--; |
| 4415 | if (s) RETURN_STATUS(s); | 4409 | if (s) RETURN_STATUS(s); |
| 4416 | 4410 | ||
