On Sunday, May 28, 2023, Grisha Levit <grishale...@gmail.com> wrote: > Missing final `;': > > "$BASH" --pretty-print <<< $'${ : \;;}' > ${ : \; } >
The latest set of fixes to this code solves these cases but others have issues: $ bash --pretty-print <<<$'${ : \;;\n}' ${ : \; } $ bash --pretty-print <<<$'${ : \;\n\n}' ${ : \; } $ bash --pretty-print <<<$'${ : \&;\n}' ${ : \& } $ bash --pretty-print <<<$'${ : \&;\n\n}' ${ : \& } I think it might be ok to just have print_comsub handle adding the final semicolon when needed instead of trying to add it after the fact in parse_comsub? (Patch below includes earlier fixes to semicolon() from https://lists.gnu.org/archive/html/bug-bash/2023-06/msg00018.html) --- diff --git a/externs.h b/externs.h index a1363d4d..b1eb53dc 100644 --- a/externs.h +++ b/externs.h @@ -36,7 +36,7 @@ extern intmax_t evalexp (const char *, int, int *); #define FUNC_EXTERNAL 0x02 extern char *make_command_string (COMMAND *); -extern char *print_comsub (COMMAND *); +extern char *print_comsub (COMMAND *, int); extern char *named_function_string (char *, COMMAND *, int); extern void print_command (COMMAND *); diff --git a/parse.y b/parse.y index c139a4d7..150bba65 100644 --- a/parse.y +++ b/parse.y @@ -4297,7 +4297,7 @@ static char * parse_comsub (int qc, int open, int close, size_t *lenp, int flags) { int peekc, r; - int start_lineno, dolbrace_spec, local_extglob, was_extpat, was_word; + int start_lineno, dolbrace_spec, local_extglob, was_extpat; char *ret, *tcmd; size_t retlen; sh_parser_state_t ps; @@ -4342,7 +4342,6 @@ parse_comsub (int qc, int open, int close, size_t *lenp, int flags) save_parser_state (&ps); was_extpat = (parser_state & PST_EXTPAT); - was_word = 0; /* State flags we don't want to persist into command substitutions. */ parser_state &= ~(PST_REGEXP|PST_EXTPAT|PST_CONDCMD|PST_CONDEXPR|PST_COMPASSIGN); @@ -4388,14 +4387,6 @@ parse_comsub (int qc, int open, int close, size_t *lenp, int flags) r = yyparse (); - if (open == '{') - { - if (current_token == shell_eof_token && - (last_read_token == ';' || last_read_token == '\n') && - (token_before_that == WORD || token_before_that == ASSIGNMENT_WORD)) - was_word = 1; - } - if (need_here_doc > 0) { internal_warning ("command substitution: %d unterminated here-document%s", need_here_doc, (need_here_doc == 1) ? "" : "s"); @@ -4459,7 +4450,7 @@ INTERNAL_DEBUG(("current_token (%d) != shell_eof_token (%c)", current_token, she restore_parser_state (&ps); pushed_string_list = saved_strings; - tcmd = print_comsub (parsed_command); /* returns static memory */ + tcmd = print_comsub (parsed_command, open); /* returns static memory */ retlen = strlen (tcmd); if (open == '(') /* ) */ { @@ -4481,17 +4472,10 @@ INTERNAL_DEBUG(("current_token (%d) != shell_eof_token (%c)", current_token, she } else /* open == '{' } */ { - int lastc; - - lastc = tcmd[retlen - 1]; retlen++; - ret = xmalloc (retlen + 4); + ret = xmalloc (retlen + 3); ret[0] = (dolbrace_spec == '|') ? '|' : ' '; - strcpy (ret + 1, tcmd); /* ( */ - if (was_word) - ret[retlen++] = ';'; - else if (lastc != '\n' && lastc != ';' && lastc != '&') - ret[retlen++] = ';'; + strcpy (ret + 1, tcmd); ret[retlen++] = ' '; } ret[retlen++] = close; diff --git a/print_cmd.c b/print_cmd.c index 29870837..0a403c6f 100644 --- a/print_cmd.c +++ b/print_cmd.c @@ -161,12 +161,14 @@ make_command_string (COMMAND *command) back into an external representation without turning newlines into `;'. Placeholder for other changes, if any are necessary. */ char * -print_comsub (COMMAND *command) +print_comsub (COMMAND *command, int open) { char *ret; printing_comsub++; ret = make_command_string (command); + if (open == '{') + semicolon(); printing_comsub--; return ret; } @@ -1446,9 +1448,11 @@ indent (int amount) static void semicolon (void) { - if (command_string_index > 0 && - (the_printed_command[command_string_index - 1] == '&' || - the_printed_command[command_string_index - 1] == '\n')) + if ((command_string_index > 1 && + (the_printed_command[command_string_index - 2] == ' ' && + the_printed_command[command_string_index - 1] == '&')) || + (command_string_index > 0 && + (the_printed_command[command_string_index - 1] == '\n'))) return; cprintf (";"); }