fix recogniation of IN token in for command nested within case command

This commit is contained in:
Chet Ramey
2024-04-15 10:11:38 -04:00
parent 136cdf8108
commit a06616a689
7 changed files with 88 additions and 12 deletions
+22 -1
View File
@@ -9155,4 +9155,25 @@ redir.c
get expanded again.
Fixes bug reported by squeaky <q7d9y9muja@liamekaens.com>
4/12
----
parse.y
- expecting_in_command: new variable, set to FOR or CASE depending on
which command is expecting the IN token to follow it
- {save,restore}_parser_state: save and restore expecting_in_command
in `incmd' member
- special_case_tokens: for POSIX rule 6, check expecting_in_token
instead of last_read_token/token_before_that for case/for command
and whether we should return IN and maybe set PST_CASEPAT
- special_case_tokens: reset expecting_in_command before returning DO
- read_token_word: set expecting_in_command if last_read_token was
CASE or FOR and we are returning a WORD
- reset_parser: reset expecting_in_command
- parse_comsub,parse_compound_assignment: reset expecting_in_command
Fixes bug reported by nbowler@draconx.ca
parser.h
- incmd: new member of parser_state, saves and restores the value of
expecting_in_command
- PST_FORCMD: new parser state, used to say if we're parsing a `for'
command and waiting for an IN token (not used yet)
+2 -2
View File
@@ -1042,12 +1042,12 @@ getconf_all (WORD_LIST *list)
int r;
r = EXECUTION_SUCCESS;
path = list ? list->word->word : 0;
path = list ? list->word->word : "/";
for (c = vars; c->name != NULL; ++c)
{
#if 0
if (c->call == PATHCONF && path == 0)
continue; /* Don't print pathconf vars if no path supplied */
#if 0
if (c->call != PATHCONF && path)
continue; /* Only print pathconf vars if path supplied */
#endif
+24 -9
View File
@@ -3035,6 +3035,7 @@ static int esacs_needed_count;
/* When non-zero, we can read IN as an acceptable token, regardless of how
many newlines we read. */
static int expecting_in_token;
static int expecting_in_command; /* XXX - maybe save previous? */
static void
push_heredoc (REDIRECT *r)
@@ -3119,12 +3120,15 @@ static int open_brace_count;
if (word_token_alist[i].token == ESAC) { \
parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \
esacs_needed_count--; \
} else if (word_token_alist[i].token == CASE) \
} else if (word_token_alist[i].token == CASE) { \
parser_state |= PST_CASESTMT; \
else if (word_token_alist[i].token == COND_END) \
expecting_in_command = CASE; \
} else if (word_token_alist[i].token == COND_END) \
parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \
else if (word_token_alist[i].token == COND_START) \
parser_state |= PST_CONDCMD; \
else if (word_token_alist[i].token == FOR) \
expecting_in_command = FOR; \
else if (word_token_alist[i].token == '{') \
open_brace_count++; \
else if (word_token_alist[i].token == '}' && open_brace_count) \
@@ -3300,19 +3304,20 @@ special_case_tokens (const char *tokstr)
/* Posix grammar rule 6 */
if ((last_read_token == WORD) &&
#if defined (SELECT_COMMAND)
((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) &&
(token_before_that == FOR || token_before_that == CASE || token_before_that == SELECT) &&
#else
((token_before_that == FOR) || (token_before_that == CASE)) &&
(token_before_that == FOR || token_before_that == CASE) &&
#endif
(tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0))
{
if (token_before_that == CASE)
if (expecting_in_command == CASE)
{
parser_state |= PST_CASEPAT;
esacs_needed_count++;
}
if (expecting_in_token)
expecting_in_token--;
expecting_in_command = 0;
return (IN);
}
@@ -3322,12 +3327,13 @@ special_case_tokens (const char *tokstr)
if (expecting_in_token && (last_read_token == WORD || last_read_token == '\n') &&
(tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0))
{
if (parser_state & PST_CASESTMT)
if (expecting_in_command == CASE && (parser_state & PST_CASESTMT))
{
parser_state |= PST_CASEPAT;
esacs_needed_count++;
}
expecting_in_token--;
expecting_in_command = 0;
return (IN);
}
/* Posix grammar rule 6, third word in FOR: for i; do command-list; done */
@@ -3335,6 +3341,7 @@ special_case_tokens (const char *tokstr)
(tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0'))
{
expecting_in_token--;
expecting_in_command = 0;
return (DO);
}
@@ -3349,6 +3356,7 @@ special_case_tokens (const char *tokstr)
{
if (expecting_in_token)
expecting_in_token--;
expecting_in_command = 0;
return (DO);
}
@@ -3457,6 +3465,7 @@ reset_parser (void)
need_here_doc = 0;
redir_stack[0] = 0;
esacs_needed_count = expecting_in_token = 0;
expecting_in_command = 0;
simplecmd_lineno = line_number;
@@ -4422,8 +4431,9 @@ parse_comsub (int qc, int open, int close, size_t *lenp, int flags)
/* State flags we don't want to persist into command substitutions. */
parser_state &= ~(PST_REGEXP|PST_EXTPAT|PST_CONDCMD|PST_CONDEXPR|PST_COMPASSIGN);
/* Could do PST_CASESTMT too, but that also affects history. Setting
expecting_in_token below should take care of the parsing requirements.
/* Could do PST_CASESTMT too, but that also affects history. Ditto for
PST_FORCMD. Setting expecting_in_token and expecting_in_command below
should take care of the parsing requirements.
Unsetting PST_REDIRLIST isn't strictly necessary because of how we set
token_to_read below, but we do it anyway. */
parser_state &= ~(PST_CASEPAT|PST_ALEXPNEXT|PST_SUBSHELL|PST_REDIRLIST);
@@ -4442,6 +4452,7 @@ parse_comsub (int qc, int open, int close, size_t *lenp, int flags)
/* These are reset by reset_parser() */
need_here_doc = 0;
esacs_needed_count = expecting_in_token = 0;
expecting_in_command = 0;
/* We want to expand aliases on this pass if we're in posix mode, since the
standard says you have to take aliases into account when looking for the
@@ -5763,8 +5774,9 @@ got_token:
function_dstart = line_number;
break;
case CASE:
case SELECT:
case FOR:
expecting_in_command = last_read_token;
case SELECT:
expecting_in_token++;
break;
}
@@ -6996,6 +7008,7 @@ parse_compound_assignment (size_t *retlenp)
parser_state |= PST_COMPASSIGN;
esacs_needed_count = expecting_in_token = 0;
expecting_in_command = 0;
/* We're not pushing any new input here, we're reading from the current input
source. If that's an alias, we have to be prepared for the alias to get
@@ -7126,6 +7139,7 @@ save_parser_state (sh_parser_state_t *ps)
ps->esacs_needed = esacs_needed_count;
ps->expecting_in = expecting_in_token;
ps->incmd = expecting_in_command;
if (need_here_doc == 0)
ps->redir_stack[0] = 0;
@@ -7190,6 +7204,7 @@ restore_parser_state (sh_parser_state_t *ps)
esacs_needed_count = ps->esacs_needed;
expecting_in_token = ps->expecting_in;
expecting_in_command = ps->incmd;
#if 0
for (i = 0; i < HEREDOC_MAX; i++)
+1
View File
@@ -53,6 +53,7 @@
#define PST_STRING 0x1000000 /* parsing a string to a command or word list */
#define PST_CMDBLTIN 0x2000000 /* last token was the `command' builtin */
#define PST_FUNSUBST 0x4000000 /* parsing a foreground command substitution */
#define PST_FORCMD 0x8000000 /* parsing for command -- not used yet */
/* Definition of the delimiter stack. Needed by parse.y and bashhist.c. */
struct dstack {
+1
View File
@@ -215,6 +215,7 @@ typedef struct _sh_parser_state_t
int esacs_needed;
int expecting_in;
int incmd;
/* structures affecting the parser */
void *pushed_strings;
+3
View File
@@ -15,3 +15,6 @@ bash5: -c: line 1: `for()'
in
done
ok 1
x
x
x
+35
View File
@@ -63,4 +63,39 @@ in
foo) echo "ok 1";;
esac' $bashname
# POSIX grammar rule 6 with <linebreak> consisting of multiple newlines and
# nested case and for commands
case x in x)
for x
in x
do
echo $x
done
esac
# need to recognize IN here
case x in x)
for x
in x
do
echo $x
done
esac
# recognize both IN and DO
case x in x)
for x
in x
do
echo $x
done
esac