hush: preparatory work for implementing functions
No binary (build failed)
—
(log yok)
| @@ -2903,37 +2903,38 @@ static void initialize_context(struct parse_context *ctx) | |
| * case, function, and select are obnoxious, save those for later. | |
| */ | |
| #if HAS_KEYWORDS | |
| - | static int reserved_word(o_string *word, struct parse_context *ctx) |
| - | { |
| - | struct reserved_combo { |
| - | char literal[6]; |
| - | unsigned char res; |
| - | unsigned char assignment_flag; |
| - | int flag; |
| - | }; |
| - | enum { |
| - | FLAG_END = (1 << RES_NONE ), |
| + | struct reserved_combo { |
| + | char literal[6]; |
| + | unsigned char res; |
| + | unsigned char assignment_flag; |
| + | int flag; |
| + | }; |
| + | enum { |
| + | FLAG_END = (1 << RES_NONE ), |
| #if ENABLE_HUSH_IF | |
| - | FLAG_IF = (1 << RES_IF ), |
| - | FLAG_THEN = (1 << RES_THEN ), |
| - | FLAG_ELIF = (1 << RES_ELIF ), |
| - | FLAG_ELSE = (1 << RES_ELSE ), |
| - | FLAG_FI = (1 << RES_FI ), |
| + | FLAG_IF = (1 << RES_IF ), |
| + | FLAG_THEN = (1 << RES_THEN ), |
| + | FLAG_ELIF = (1 << RES_ELIF ), |
| + | FLAG_ELSE = (1 << RES_ELSE ), |
| + | FLAG_FI = (1 << RES_FI ), |
| #endif | |
| #if ENABLE_HUSH_LOOPS | |
| - | FLAG_FOR = (1 << RES_FOR ), |
| - | FLAG_WHILE = (1 << RES_WHILE), |
| - | FLAG_UNTIL = (1 << RES_UNTIL), |
| - | FLAG_DO = (1 << RES_DO ), |
| - | FLAG_DONE = (1 << RES_DONE ), |
| - | FLAG_IN = (1 << RES_IN ), |
| + | FLAG_FOR = (1 << RES_FOR ), |
| + | FLAG_WHILE = (1 << RES_WHILE), |
| + | FLAG_UNTIL = (1 << RES_UNTIL), |
| + | FLAG_DO = (1 << RES_DO ), |
| + | FLAG_DONE = (1 << RES_DONE ), |
| + | FLAG_IN = (1 << RES_IN ), |
| #endif | |
| #if ENABLE_HUSH_CASE | |
| - | FLAG_MATCH = (1 << RES_MATCH), |
| - | FLAG_ESAC = (1 << RES_ESAC ), |
| + | FLAG_MATCH = (1 << RES_MATCH), |
| + | FLAG_ESAC = (1 << RES_ESAC ), |
| #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. | |
| * FLAG_END means we are done with the sequence, and are ready | |
| * 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 }, | |
| #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 | |
| static const struct reserved_combo reserved_match = { | |
| "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC | |
| @@ -2968,52 +2979,51 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |
| #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) |
| - | continue; |
| - | debug_printf("found reserved word %s, res %d\n", r->literal, r->res); |
| + | r = match_reserved_word(word); |
| + | if (!r) |
| + | return 0; |
| + | |
| + | debug_printf("found reserved word %s, res %d\n", r->literal, r->res); |
| #if ENABLE_HUSH_CASE | |
| - | if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE) |
| - | /* "case word IN ..." - IN part starts first match part */ |
| - | r = &reserved_match; |
| - | else |
| + | if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE) |
| + | /* "case word IN ..." - IN part starts first match part */ |
| + | r = &reserved_match; |
| + | else |
| #endif | |
| - | if (r->flag == 0) { /* '!' */ |
| - | 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))) { |
| + | if (r->flag == 0) { /* '!' */ |
| + | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ |
| 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); |
| + | IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) |
| } | |
| - | word->o_assignment = r->assignment_flag; |
| + | ctx->ctx_inverted = 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 | |
| @@ -3892,6 +3902,17 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |
| ) { | |
| 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 | |
| case '{': | |
| 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; | |
| #endif | |
| 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 )"); | |
| debug_printf_parse("parse_stream return 1: unexpected '}'\n"); | |
| return 1; | |