#include #include #include "syntax.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); } } StrVec process_word(Word word) { StrVec result = make_StrVec(256); for (int i = 0; i < word.count; i++) { Chunk chunk = *get_from_Word(&word, i); switch (chunk.qmode) { case SINGLE_Q: push_to_StrVec(&result, chunk.as.lit_str); break; case DOUBLE_Q: // TODO exit(67); break; case UN_Q: // TODO: this only does literals, implement the rest split_str_on_space(chunk.as.lit_str, &result); break; } } 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) { 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); 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); 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); 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) { PipelineVec pls = make_PipelineVec(256); Pipeline* root_pl = process_token_sequence(*ast.root, &pls); return (PipelineTree){.pl_pool = pls, root_pl}; }