#include #include #include "syntax.h" #include "utils.h" void split_str_on_space(char* str, StrVec* result) { String buf = make_String(256); for (int pos = 0; str[pos] != '\0'; pos++) { if (str[pos] == ' ') { push_to_StrVec(result, inner(&buf)); buf = make_String(256); } else { push_to_String(&buf, str[pos]); } } if (buf.count > 0) { char* buf_str = inner(&buf); push_to_StrVec(result, buf_str); } } void process_chunk(Chunk chunk, StrVec* result, ShellState* shstate) { assert(!(chunk.qmode == SINGLE_Q && chunk.kind != CHUNK_LIT)); char* chunk_val; switch (chunk.kind) { case CHUNK_LIT: chunk_val = chunk.as.lit_str; break; case CHUNK_VAR: chunk_val = get_var(chunk.as.varname, shstate); break; default: exit(77); } if (chunk.qmode == UN_Q) { split_str_on_space(chunk_val, result); } else { push_to_StrVec(result, chunk_val); } } StrVec process_word(Word word, ShellState* shstate) { StrVec result = make_StrVec(256); for (int i = 0; i < word.count; i++) { Chunk chunk = *get_from_Word(&word, i); process_chunk(chunk, &result, shstate); } return result; } typedef struct { TokenKind kind; union { char* word; SpecialToken spec; } as; } ExpandedToken; DECLARE_VEC(ExpandedToken, ExpandedTokenVec) Pipeline* process_token_sequence(TokenVec tokens, PipelineVec* pl_pool, ShellState* shstate) { ExpandedTokenVec exp_tokens = make_ExpandedTokenVec(256); for (int m = 0; m < tokens.count; m++) { Token tok = *get_from_TokenVec(&tokens, m); StrVec strs; switch (tok.kind) { case TOK_SPEC: push_to_ExpandedTokenVec(&exp_tokens, (ExpandedToken){.kind = TOK_SPEC, .as.spec = tok.as.spec}); break; case TOK_WORD: strs = process_word(tok.as.word, shstate); for (int n = 0; n < strs.count; n++) { push_to_ExpandedTokenVec(&exp_tokens, (ExpandedToken){.kind = TOK_WORD, .as.word = *get_from_StrVec(&strs, n)}); } } } Pipeline pl = make_Pipeline(256); size_t tok_pos = 0; PlCommand curr_cmd = {.args = make_ArgVec(256), .redirects = make_RedirectVec(256), .conn = CONN_EOL}; PlCommand* root_pl; for (int i = 0; i < exp_tokens.count; i++) { ExpandedToken curr_tok = *get_from_ExpandedTokenVec(&exp_tokens, i); ExpandedToken next_tok; Redirect rd; Pipeline* sub_pl; switch (curr_tok.kind) { case TOK_WORD: push_to_ArgVec(&curr_cmd.args, (Arg){.kind = ARG_LIT, .as.lit_str = curr_tok.as.word}); break; case TOK_SPEC: switch (curr_tok.as.spec.kind) { case SPEC_OP: switch (curr_tok.as.spec.as.op) { case OP_PIPE: curr_cmd.conn = CONN_PIPE; push_to_Pipeline(&pl, curr_cmd); curr_cmd = (PlCommand){.args = make_ArgVec(256), .redirects = make_RedirectVec(256), .conn = CONN_EOL}; break; case OP_EOL: push_to_Pipeline(&pl, curr_cmd); break; case OP_REDIR_R: next_tok = *get_from_ExpandedTokenVec(&exp_tokens, ++i); assert(next_tok.kind == TOK_WORD); rd = (Redirect){.kind = REDIR_READ, .as.filename = next_tok.as.word}; push_to_RedirectVec(&curr_cmd.redirects, rd); break; case OP_REDIR_W_APPEND: next_tok = *get_from_ExpandedTokenVec(&exp_tokens, ++i); assert(next_tok.kind == TOK_WORD); rd = (Redirect){.kind = REDIR_WRITE_APPEND, .as.filename = next_tok.as.word}; push_to_RedirectVec(&curr_cmd.redirects, rd); break; case OP_REDIR_W_TRUNC: next_tok = *get_from_ExpandedTokenVec(&exp_tokens, ++i); assert(next_tok.kind == TOK_WORD); rd = (Redirect){.kind = REDIR_WRITE_TRUNC, .as.filename = next_tok.as.word}; push_to_RedirectVec(&curr_cmd.redirects, rd); break; default: exit(63); } break; case SPEC_SUB_IN: sub_pl = process_token_sequence(*(TokenVec*)curr_tok.as.spec.as.proc_sub_region, pl_pool, shstate); push_to_ArgVec(&curr_cmd.args, (Arg){.kind = ARG_PS_IN, .as.sub_pipeline = sub_pl}); break; case SPEC_SUB_OUT: sub_pl = process_token_sequence(*(TokenVec*)curr_tok.as.spec.as.proc_sub_region, pl_pool, shstate); push_to_ArgVec(&curr_cmd.args, (Arg){.kind = ARG_PS_OUT, .as.sub_pipeline = sub_pl}); break; } } } return push_to_PipelineVec(pl_pool, pl); } PipelineTree process_ast(Ast ast, ShellState* shstate) { PipelineVec pls = make_PipelineVec(256); Pipeline* root_pl = process_token_sequence(*ast.root, &pls, shstate); return (PipelineTree){.pl_pool = pls, root_pl}; }