diff options
-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 |