From 202dd1943c90dea3c5c3365dd75d4e7ac9499c5f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Dec 2018 17:30:35 +0100 Subject: 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 --- miscutils/bc.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'miscutils') 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) # 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)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)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)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)"? 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(...)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()" 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()" 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 -- cgit v1.2.3