bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: No form commsub if last token ends with & or ;


From: Grisha Levit
Subject: Re: No form commsub if last token ends with & or ;
Date: Sun, 18 Jun 2023 04:59:26 -0400

On Sunday, May 28, 2023, Grisha Levit <grishalevit@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 (";");
 }


reply via email to

[Prev in Thread] Current Thread [Next in Thread]