hush: preparatory work for implementing functions
This commit is contained in:
parent
9af22c7626
commit
c373527e4f
155
shell/hush.c
155
shell/hush.c
@ -2903,37 +2903,38 @@ static void initialize_context(struct parse_context *ctx)
|
|||||||
* case, function, and select are obnoxious, save those for later.
|
* case, function, and select are obnoxious, save those for later.
|
||||||
*/
|
*/
|
||||||
#if HAS_KEYWORDS
|
#if HAS_KEYWORDS
|
||||||
static int reserved_word(o_string *word, struct parse_context *ctx)
|
struct reserved_combo {
|
||||||
{
|
char literal[6];
|
||||||
struct reserved_combo {
|
unsigned char res;
|
||||||
char literal[6];
|
unsigned char assignment_flag;
|
||||||
unsigned char res;
|
int flag;
|
||||||
unsigned char assignment_flag;
|
};
|
||||||
int flag;
|
enum {
|
||||||
};
|
FLAG_END = (1 << RES_NONE ),
|
||||||
enum {
|
|
||||||
FLAG_END = (1 << RES_NONE ),
|
|
||||||
#if ENABLE_HUSH_IF
|
#if ENABLE_HUSH_IF
|
||||||
FLAG_IF = (1 << RES_IF ),
|
FLAG_IF = (1 << RES_IF ),
|
||||||
FLAG_THEN = (1 << RES_THEN ),
|
FLAG_THEN = (1 << RES_THEN ),
|
||||||
FLAG_ELIF = (1 << RES_ELIF ),
|
FLAG_ELIF = (1 << RES_ELIF ),
|
||||||
FLAG_ELSE = (1 << RES_ELSE ),
|
FLAG_ELSE = (1 << RES_ELSE ),
|
||||||
FLAG_FI = (1 << RES_FI ),
|
FLAG_FI = (1 << RES_FI ),
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_HUSH_LOOPS
|
#if ENABLE_HUSH_LOOPS
|
||||||
FLAG_FOR = (1 << RES_FOR ),
|
FLAG_FOR = (1 << RES_FOR ),
|
||||||
FLAG_WHILE = (1 << RES_WHILE),
|
FLAG_WHILE = (1 << RES_WHILE),
|
||||||
FLAG_UNTIL = (1 << RES_UNTIL),
|
FLAG_UNTIL = (1 << RES_UNTIL),
|
||||||
FLAG_DO = (1 << RES_DO ),
|
FLAG_DO = (1 << RES_DO ),
|
||||||
FLAG_DONE = (1 << RES_DONE ),
|
FLAG_DONE = (1 << RES_DONE ),
|
||||||
FLAG_IN = (1 << RES_IN ),
|
FLAG_IN = (1 << RES_IN ),
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_HUSH_CASE
|
#if ENABLE_HUSH_CASE
|
||||||
FLAG_MATCH = (1 << RES_MATCH),
|
FLAG_MATCH = (1 << RES_MATCH),
|
||||||
FLAG_ESAC = (1 << RES_ESAC ),
|
FLAG_ESAC = (1 << RES_ESAC ),
|
||||||
#endif
|
#endif
|
||||||
FLAG_START = (1 << RES_XXXX ),
|
FLAG_START = (1 << RES_XXXX ),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct reserved_combo* match_reserved_word(o_string *word)
|
||||||
|
{
|
||||||
/* Mostly a list of accepted follow-up reserved words.
|
/* Mostly a list of accepted follow-up reserved words.
|
||||||
* FLAG_END means we are done with the sequence, and are ready
|
* FLAG_END means we are done with the sequence, and are ready
|
||||||
* to turn the compound list into a command.
|
* to turn the compound list into a command.
|
||||||
@ -2961,6 +2962,16 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
|
|||||||
{ "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END },
|
{ "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
const struct reserved_combo *r;
|
||||||
|
|
||||||
|
for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) {
|
||||||
|
if (strcmp(word->data, r->literal) == 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static int reserved_word(o_string *word, struct parse_context *ctx)
|
||||||
|
{
|
||||||
#if ENABLE_HUSH_CASE
|
#if ENABLE_HUSH_CASE
|
||||||
static const struct reserved_combo reserved_match = {
|
static const struct reserved_combo reserved_match = {
|
||||||
"", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
|
"", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
|
||||||
@ -2968,52 +2979,51 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
|
|||||||
#endif
|
#endif
|
||||||
const struct reserved_combo *r;
|
const struct reserved_combo *r;
|
||||||
|
|
||||||
for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) {
|
r = match_reserved_word(word);
|
||||||
if (strcmp(word->data, r->literal) != 0)
|
if (!r)
|
||||||
continue;
|
return 0;
|
||||||
debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
|
|
||||||
|
debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
|
||||||
#if ENABLE_HUSH_CASE
|
#if ENABLE_HUSH_CASE
|
||||||
if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE)
|
if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE)
|
||||||
/* "case word IN ..." - IN part starts first match part */
|
/* "case word IN ..." - IN part starts first match part */
|
||||||
r = &reserved_match;
|
r = &reserved_match;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if (r->flag == 0) { /* '!' */
|
if (r->flag == 0) { /* '!' */
|
||||||
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
|
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
|
||||||
syntax(NULL);
|
|
||||||
IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
|
|
||||||
}
|
|
||||||
ctx->ctx_inverted = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (r->flag & FLAG_START) {
|
|
||||||
struct parse_context *new;
|
|
||||||
debug_printf("push stack\n");
|
|
||||||
new = xmalloc(sizeof(*new));
|
|
||||||
*new = *ctx; /* physical copy */
|
|
||||||
initialize_context(ctx);
|
|
||||||
ctx->stack = new;
|
|
||||||
} else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
|
|
||||||
syntax(NULL);
|
syntax(NULL);
|
||||||
ctx->ctx_res_w = RES_SNTX;
|
IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
ctx->ctx_res_w = r->res;
|
ctx->ctx_inverted = 1;
|
||||||
ctx->old_flag = r->flag;
|
|
||||||
if (ctx->old_flag & FLAG_END) {
|
|
||||||
struct parse_context *old;
|
|
||||||
debug_printf("pop stack\n");
|
|
||||||
done_pipe(ctx, PIPE_SEQ);
|
|
||||||
old = ctx->stack;
|
|
||||||
old->command->group = ctx->list_head;
|
|
||||||
old->command->subshell = 0;
|
|
||||||
*ctx = *old; /* physical copy */
|
|
||||||
free(old);
|
|
||||||
}
|
|
||||||
word->o_assignment = r->assignment_flag;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
if (r->flag & FLAG_START) {
|
||||||
|
struct parse_context *new;
|
||||||
|
debug_printf("push stack\n");
|
||||||
|
new = xmalloc(sizeof(*new));
|
||||||
|
*new = *ctx; /* physical copy */
|
||||||
|
initialize_context(ctx);
|
||||||
|
ctx->stack = new;
|
||||||
|
} else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
|
||||||
|
syntax(NULL);
|
||||||
|
ctx->ctx_res_w = RES_SNTX;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ctx->ctx_res_w = r->res;
|
||||||
|
ctx->old_flag = r->flag;
|
||||||
|
if (ctx->old_flag & FLAG_END) {
|
||||||
|
struct parse_context *old;
|
||||||
|
debug_printf("pop stack\n");
|
||||||
|
done_pipe(ctx, PIPE_SEQ);
|
||||||
|
old = ctx->stack;
|
||||||
|
old->command->group = ctx->list_head;
|
||||||
|
old->command->subshell = 0;
|
||||||
|
*ctx = *old; /* physical copy */
|
||||||
|
free(old);
|
||||||
|
}
|
||||||
|
word->o_assignment = r->assignment_flag;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -3892,6 +3902,17 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
|
|||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if 0 /* TODO: implement functions */
|
||||||
|
if (dest->length != 0 /* not just () but word() */
|
||||||
|
&& dest->nonnull == 0 /* not a"b"c() */
|
||||||
|
&& ctx->command->argv == NULL /* it's the first word */
|
||||||
|
&& i_peek(input) == ')'
|
||||||
|
) {
|
||||||
|
bb_error_msg("seems like a function definition");
|
||||||
|
if (match_reserved_word(dest))
|
||||||
|
bb_error_msg("but '%s' is a reserved word!", dest->data);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
case '{':
|
case '{':
|
||||||
if (parse_group(dest, ctx, input, ch) != 0) {
|
if (parse_group(dest, ctx, input, ch) != 0) {
|
||||||
@ -3905,7 +3926,9 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
|
|||||||
goto case_semi;
|
goto case_semi;
|
||||||
#endif
|
#endif
|
||||||
case '}':
|
case '}':
|
||||||
/* proper use of this character is caught by end_trigger */
|
/* proper use of this character is caught by end_trigger:
|
||||||
|
* if we see {, we call parse_group(..., end_trigger='}')
|
||||||
|
* and it will match } earlier (not here). */
|
||||||
syntax("unexpected } or )");
|
syntax("unexpected } or )");
|
||||||
debug_printf_parse("parse_stream return 1: unexpected '}'\n");
|
debug_printf_parse("parse_stream return 1: unexpected '}'\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user