diff options
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | redes/exec.c | 147 | ||||
| -rw-r--r-- | redes/main.c | 23 | ||||
| -rw-r--r-- | redes/preproc.c | 135 | ||||
| -rw-r--r-- | src/exec.c | 194 | ||||
| -rw-r--r-- | src/exec.h | 26 | ||||
| -rw-r--r-- | src/expand.c | 104 | ||||
| -rw-r--r-- | src/expand.h | 31 | ||||
| -rw-r--r-- | src/lexparse.c (renamed from redes/lexparse.c) | 0 | ||||
| -rw-r--r-- | src/main.c | 10 | ||||
| -rw-r--r-- | src/preproc.c | 393 | ||||
| -rw-r--r-- | src/preproc.h | 116 | ||||
| -rw-r--r-- | src/stages.h (renamed from redes/stages.h) | 0 | ||||
| -rw-r--r-- | src/syntax.h (renamed from redes/syntax.h) | 0 |
14 files changed, 187 insertions, 997 deletions
@@ -1,6 +1,3 @@ build: - @gcc -g src/main.c src/exec.c src/expand.c src/preproc.c src/utils.c -o bin/yeesh -lreadline - + @gcc -g src/main.c src/exec.c src/preproc.c src/lexparse.c src/utils.c -o bin/yeesh -lreadline -redesbuild: - @gcc -g redes/main.c redes/exec.c redes/preproc.c redes/lexparse.c src/utils.c -o bin/reyeesh -lreadline diff --git a/redes/exec.c b/redes/exec.c deleted file mode 100644 index afdf140..0000000 --- a/redes/exec.c +++ /dev/null @@ -1,147 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/wait.h> - -#include "syntax.h" - - -void execute_cmd(ExecutableCommand cmd, int* pgid) { - - pid_t pid = fork(); - - if (pid == 0) { - - if (*pgid == -1) { - setpgid(0, 0); - } else { - setpgid(0, *pgid); - } - - dup2(cmd.stdin_fd, STDIN_FILENO); - dup2(cmd.stdout_fd, STDOUT_FILENO); - - for (int i = 0; i < cmd.redirects.count; i++) { - FdRedirect fd_rd = *get_from_FdRedirectVec(&cmd.redirects, i); - dup2(fd_rd.to, fd_rd.redirected); - } - - for (int j = 0; j < cmd.open_fds.count; j++) { - int fd = *get_from_IntVec(&cmd.open_fds, j); - close(fd); - } - - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - - execvp(cmd.args[0], cmd.args); - exit(67); - } - - if (*pgid == -1) { - setpgid(pid, pid); - *pgid = pid; - } else { - setpgid(pid, *pgid); - } -} - - -ExecutableCommand process_pl_command(PlCommand pl_cmd) { - StrVec arg_vec = make_StrVec(256); - for (int i = 0; i < pl_cmd.args.count; i++) { - Arg arg = *get_from_ArgVec(&pl_cmd.args, i); - switch (arg.kind) { - case ARG_LIT: - push_to_StrVec(&arg_vec, arg.as.lit_str); - break; - default: - exit(67); - } - } - - FdRedirectVec fd_redirs = make_FdRedirectVec(256); - IntVec open_fds = make_IntVec(256); - for (int j = 0; j < pl_cmd.redirects.count; j++) { - Redirect redir = *get_from_RedirectVec(&pl_cmd.redirects, j); - FdRedirect fd_redir; - int fd; - switch (redir.kind) { - case REDIR_READ: - fd = open(redir.as.filename, O_RDONLY, 0644); - push_to_IntVec(&open_fds, fd); - fd_redir = (FdRedirect){.to = fd, .redirected = STDIN_FILENO}; - break; - case REDIR_WRITE_APPEND: - fd = open(redir.as.filename, O_WRONLY | O_CREAT | O_APPEND, 0644); - push_to_IntVec(&open_fds, fd); - fd_redir = (FdRedirect){.to = fd, .redirected = STDOUT_FILENO}; - break; - case REDIR_WRITE_TRUNC: - fd = open(redir.as.filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - push_to_IntVec(&open_fds, fd); - fd_redir = (FdRedirect){.to = fd, .redirected = STDOUT_FILENO}; - break; - default: - exit(67); - } - push_to_FdRedirectVec(&fd_redirs, fd_redir); -} - - char** args = malloc(sizeof(char*) * (arg_vec.count + 1)); - for (int i = 0; i < arg_vec.count; i++) { - args[i] = *get_from_StrVec(&arg_vec, i); - } - args[arg_vec.count] = NULL; - - return (ExecutableCommand){.args = args, .redirects = fd_redirs, .open_fds = open_fds}; -} - - -void execute_command_pipeline(Pipeline pipeline) { - int trunk_fd = STDIN_FILENO; - int pgid = -1; - - - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - - for (int i = 0; i < pipeline.count; i++) { - PlCommand cmd = *get_from_Pipeline(&pipeline, i); - ExecutableCommand exec_cmd = process_pl_command(cmd); - - exec_cmd.stdin_fd = trunk_fd; - if (i > 0) { - push_to_IntVec(&exec_cmd.open_fds, trunk_fd); - } - - exec_cmd.stdout_fd = STDOUT_FILENO; - - if (cmd.conn == CONN_PIPE) { - int pipe_fds[2]; - pipe(pipe_fds); - exec_cmd.stdout_fd = pipe_fds[1]; - push_to_IntVec(&exec_cmd.open_fds, pipe_fds[1]); - trunk_fd = pipe_fds[0]; - } - - execute_cmd(exec_cmd, &pgid); - - for (int j = 0; j < exec_cmd.open_fds.count; j++) { - int fd = *get_from_IntVec(&exec_cmd.open_fds, j); - close(fd); - } - } - - tcsetpgrp(STDIN_FILENO, pgid); - while (waitpid(-pgid, NULL, 0) > 0); - tcsetpgrp(STDIN_FILENO, getpgrp()); -} - -void execute_pipeline_tree(PipelineTree pltree) { - execute_command_pipeline(*pltree.root); -} diff --git a/redes/main.c b/redes/main.c deleted file mode 100644 index dc451f9..0000000 --- a/redes/main.c +++ /dev/null @@ -1,23 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <readline/readline.h> -#include <readline/history.h> -#include <string.h> - -#include "syntax.h" -#include "stages.h" - - -int main() { - char* line; - while (1) { - line = readline("$ "); - if (line[0] == '\0') continue; - if (strcmp(line, "exit") == 0) exit(0); - add_history(line); - Ast ast = lex(line); - PipelineTree pltree = process_ast(ast); - execute_pipeline_tree(pltree); - } - free(line); -} diff --git a/redes/preproc.c b/redes/preproc.c deleted file mode 100644 index 63e618f..0000000 --- a/redes/preproc.c +++ /dev/null @@ -1,135 +0,0 @@ -#include <assert.h> -#include <stdio.h> -#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; - 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; - default: - exit(62); - } - } - } - return push_to_PipelineVec(pl_pool, pl); -} - - -PipelineTree process_ast(Ast ast) { - PipelineVec pls = make_PipelineVec(256); - TokenVec root_toks = *ast.root; - Pipeline* root_pl = process_token_sequence(root_toks, &pls); - return (PipelineTree){.pl_pool = pls, root_pl}; -} @@ -1,38 +1,35 @@ #include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <sys/wait.h> -#include "utils.h" -#include "exec.h" -#include "preproc.h" -#include "expand.h" +#include "syntax.h" -void execute_command(Command cmd, int* pgid) { +void execute_cmd(ExecutableCommand cmd, int* pgid) { pid_t pid = fork(); - + if (pid == 0) { - if (*pgid == -1) { + + if (*pgid == -1) { setpgid(0, 0); } else { setpgid(0, *pgid); } - + dup2(cmd.stdin_fd, STDIN_FILENO); dup2(cmd.stdout_fd, STDOUT_FILENO); - for (int j = 0; j < cmd.redirs.count; j++) { - FdRedirect fd_rd = *get_from_FdRedirectVec(&cmd.redirs, j); - dup2(fd_rd.new_fd, fd_rd.old_fd); + for (int i = 0; i < cmd.redirects.count; i++) { + FdRedirect fd_rd = *get_from_FdRedirectVec(&cmd.redirects, i); + dup2(fd_rd.to, fd_rd.redirected); } - for (int i = 0; i < cmd.child_close_fds.count; i++) { - close(*get_from_IntVec(&cmd.child_close_fds, i)); + for (int j = 0; j < cmd.open_fds.count; j++) { + int fd = *get_from_IntVec(&cmd.open_fds, j); + close(fd); } signal(SIGINT, SIG_DFL); @@ -53,102 +50,90 @@ void execute_command(Command cmd, int* pgid) { } } -Command make_command(ExpandedPipelineElement elem) { - Command cmd = { - .child_close_fds = make_IntVec(64), - .parent_close_fds = make_IntVec(64), - .redirs = make_FdRedirectVec(32), - .term = elem.conn, - }; - StrVec arg_strs = make_StrVec(256); - for (int i = 0; i < elem.cmd_slots.count; i++) { - Slot curr_slot = *get_from_SlotVec(&elem.cmd_slots, i); - Slot next_slot; + +ExecutableCommand process_pl_command(PlCommand pl_cmd) { + StrVec arg_vec = make_StrVec(256); + for (int i = 0; i < pl_cmd.args.count; i++) { + Arg arg = *get_from_ArgVec(&pl_cmd.args, i); + switch (arg.kind) { + case ARG_LIT: + push_to_StrVec(&arg_vec, arg.as.lit_str); + break; + default: + exit(67); + } + } + + FdRedirectVec fd_redirs = make_FdRedirectVec(256); + IntVec open_fds = make_IntVec(256); + for (int j = 0; j < pl_cmd.redirects.count; j++) { + Redirect redir = *get_from_RedirectVec(&pl_cmd.redirects, j); + FdRedirect fd_redir; int fd; - FdRedirect redir; - switch (curr_slot.kind) { - case SLOT_STR: - push_to_StrVec(&arg_strs, curr_slot.as.str); + switch (redir.kind) { + case REDIR_READ: + fd = open(redir.as.filename, O_RDONLY, 0644); + push_to_IntVec(&open_fds, fd); + fd_redir = (FdRedirect){.to = fd, .redirected = STDIN_FILENO}; + break; + case REDIR_WRITE_APPEND: + fd = open(redir.as.filename, O_WRONLY | O_CREAT | O_APPEND, 0644); + push_to_IntVec(&open_fds, fd); + fd_redir = (FdRedirect){.to = fd, .redirected = STDOUT_FILENO}; break; - case SLOT_SPEC: - switch (curr_slot.as.spec) { - case READ_REDIR: - i++; - next_slot = *get_from_SlotVec(&elem.cmd_slots, i); - if (next_slot.kind != SLOT_STR) exit(6); - fd = open(next_slot.as.str, O_RDONLY, 0644); - redir = (FdRedirect){.old_fd = STDIN_FILENO, .new_fd = fd}; - push_to_FdRedirectVec(&cmd.redirs, redir); - push_to_IntVec(&cmd.parent_close_fds, fd); - push_to_IntVec(&cmd.child_close_fds, fd); - break; - case WRITE_REDIR_TRUNC: - i++; - next_slot = *get_from_SlotVec(&elem.cmd_slots, i); - if (next_slot.kind != SLOT_STR) exit(6); - fd = open(next_slot.as.str, O_WRONLY | O_CREAT | O_TRUNC , 0644); - redir = (FdRedirect){.old_fd = STDOUT_FILENO, .new_fd = fd}; - push_to_FdRedirectVec(&cmd.redirs, redir); - push_to_IntVec(&cmd.parent_close_fds, fd); - push_to_IntVec(&cmd.child_close_fds, fd); - break; - case WRITE_REDIR_APPEND: - i++; - next_slot = *get_from_SlotVec(&elem.cmd_slots, i); - if (next_slot.kind != SLOT_STR) exit(6); - fd = open(next_slot.as.str, O_WRONLY | O_CREAT | O_APPEND, 0644); - redir = (FdRedirect){.old_fd = STDOUT_FILENO, .new_fd = fd}; - push_to_FdRedirectVec(&cmd.redirs, redir); - push_to_IntVec(&cmd.parent_close_fds, fd); - push_to_IntVec(&cmd.child_close_fds, fd); - break; - default: - exit(7); - } + case REDIR_WRITE_TRUNC: + fd = open(redir.as.filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + push_to_IntVec(&open_fds, fd); + fd_redir = (FdRedirect){.to = fd, .redirected = STDOUT_FILENO}; break; default: exit(67); - // TODO: other slot kinds } - } - cmd.args = malloc(sizeof(char*) * arg_strs.count); - for (int j = 0; j < arg_strs.count; j++) { - cmd.args[j] = *get_from_StrVec(&arg_strs, j); - } - return cmd; + push_to_FdRedirectVec(&fd_redirs, fd_redir); } + char** args = malloc(sizeof(char*) * (arg_vec.count + 1)); + for (int i = 0; i < arg_vec.count; i++) { + args[i] = *get_from_StrVec(&arg_vec, i); + } + args[arg_vec.count] = NULL; + + return (ExecutableCommand){.args = args, .redirects = fd_redirs, .open_fds = open_fds}; +} -void run_cmds(CommandVec cmds) { - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); +void execute_command_pipeline(Pipeline pipeline) { int trunk_fd = STDIN_FILENO; int pgid = -1; - for (int i = 0; i < cmds.count; i++) { - Command cmd = *get_from_CommandVec(&cmds, i); - cmd.stdin_fd = trunk_fd; + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + + for (int i = 0; i < pipeline.count; i++) { + PlCommand cmd = *get_from_Pipeline(&pipeline, i); + ExecutableCommand exec_cmd = process_pl_command(cmd); + + exec_cmd.stdin_fd = trunk_fd; if (i > 0) { - push_to_IntVec(&cmd.child_close_fds, trunk_fd); - push_to_IntVec(&cmd.parent_close_fds, trunk_fd); + push_to_IntVec(&exec_cmd.open_fds, trunk_fd); } - cmd.stdout_fd = STDOUT_FILENO; - if (cmd.term == CONN_PIPE) { + exec_cmd.stdout_fd = STDOUT_FILENO; + + if (cmd.conn == CONN_PIPE) { int pipe_fds[2]; pipe(pipe_fds); - cmd.stdout_fd = pipe_fds[1]; - push_to_IntVec(&cmd.child_close_fds, pipe_fds[1]); - push_to_IntVec(&cmd.parent_close_fds, pipe_fds[1]); + exec_cmd.stdout_fd = pipe_fds[1]; + push_to_IntVec(&exec_cmd.open_fds, pipe_fds[1]); trunk_fd = pipe_fds[0]; } - execute_command(cmd, &pgid); - - for (int j = 0; j < cmd.parent_close_fds.count; j++) { - close(*get_from_IntVec(&cmd.parent_close_fds, j)); + execute_cmd(exec_cmd, &pgid); + + for (int j = 0; j < exec_cmd.open_fds.count; j++) { + int fd = *get_from_IntVec(&exec_cmd.open_fds, j); + close(fd); } } @@ -157,33 +142,6 @@ void run_cmds(CommandVec cmds) { tcsetpgrp(STDIN_FILENO, getpgrp()); } - -CommandVec make_cmd_vec_pl(ExpandedPipeline pl) { - CommandVec cmds = make_CommandVec(256); - for (int i = 0; i < pl.count; i++) { - ExpandedPipelineElement elem = *get_from_ExpandedPipeline(&pl, i); - Command cmd = make_command(elem); - push_to_CommandVec(&cmds, cmd); - } - return cmds; -} - - -void process_input_line(char* line, ShellState* shstate) { - PreprocArena arena = { - .tokens = make_TokenVec(256), - .chunks = make_ChunkVec(256), - .regions = make_RegionVec(256), - }; - TokenPtrVec line_tok_ptrs = lex(line, &arena); - Token* line_toks = malloc(sizeof(Token) * line_tok_ptrs.count); - for (int i = 0; i < line_tok_ptrs.count; i++) { - line_toks[i] = **get_from_TokenPtrVec(&line_tok_ptrs, i); - } - Pipeline pl = parse_tokstream(line_toks); - ExpandedPipeline exp_pl = expand_pipeline(&pl, shstate); - CommandVec cmds = make_cmd_vec_pl(exp_pl); - run_cmds(cmds); - free(line_toks); +void execute_pipeline_tree(PipelineTree pltree) { + execute_command_pipeline(*pltree.root); } - diff --git a/src/exec.h b/src/exec.h deleted file mode 100644 index 9ee8164..0000000 --- a/src/exec.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "utils.h" -#include "preproc.h" - - -typedef struct { - int old_fd; - int new_fd; -} FdRedirect; - -DECLARE_VEC(FdRedirect, FdRedirectVec) - -typedef struct { - char** args; - FdRedirectVec redirs; - int stdin_fd; - int stdout_fd; - IntVec child_close_fds; - IntVec parent_close_fds; - Connector term; -} Command; - -DECLARE_VEC(Command, CommandVec) - -void process_input_line(char* line, ShellState* shstate); diff --git a/src/expand.c b/src/expand.c deleted file mode 100644 index 11764f9..0000000 --- a/src/expand.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "expand.h" -#include "preproc.h" -#include "utils.h" -#include <string.h> - - -typedef struct { - QuotationMode qmode; - char* content; -} ExpandedChunk; - - -ExpandedChunk expand_chunk(Chunk chunk, ShellState* shstate) { - char* content; - if (chunk.qmode == SINGLE_Q || chunk.kind == LITERAL) { - if (chunk.qmode == SINGLE_Q && chunk.kind != LITERAL) exit(69); - content = chunk.as.literal_str; - } else if (chunk.kind == VAR_EXP) { - content = get_var(chunk.as.varname, shstate); - } else if (chunk.kind == REGION_EXP) { - exit(7); // Not supported yet; arithm - } - return (ExpandedChunk){.qmode = chunk.qmode, .content = content}; -} - - -typedef struct { - StrVec complete_strs; - String active_str; -} WordSplittingGerm; - -void add_expchunk(char* next_str, WordSplittingGerm* curr_res) { - for (int pos = 0; pos < strlen(next_str); pos++) { - if (next_str[pos] == ' ') { - push_to_StrVec(&curr_res->complete_strs, inner(&curr_res->active_str)); - curr_res->active_str = make_String(256); - } else { - push_to_String(&curr_res->active_str, next_str[pos]); - } - } -} - - -void expand_word(Word word, SlotVec* target, ShellState* shstate) { - WordSplittingGerm curr_res = { - .complete_strs = make_StrVec(256), - .active_str = make_String(256) - }; - for (int i = 0; i < word.count; i++) { - Chunk chunk = **get_from_Word(&word, i); - ExpandedChunk expchunk = expand_chunk(chunk, shstate); - switch (expchunk.qmode) { - case UN_Q: - add_expchunk(expchunk.content, &curr_res); - break; - case SINGLE_Q: - append_str_to_String(&curr_res.active_str, expchunk.content); - break; - case DOUBLE_Q: - // TODO: further expansions here - append_str_to_String(&curr_res.active_str, expchunk.content); - break; - } - } - if (curr_res.active_str.count > 0) { - push_to_StrVec(&curr_res.complete_strs, inner(&curr_res.active_str)); - } - for (int j = 0; j < curr_res.complete_strs.count; j++) { - char* str = *get_from_StrVec(&curr_res.complete_strs, j); - push_to_SlotVec(target, (Slot){.kind = SLOT_STR, .as.str = str}); - } -} - -ExpandedPipelineElement expand_pipeline_element(PipelineElement elem, ShellState* shstate) { - ExpandedPipelineElement result = {.cmd_slots = make_SlotVec(256), .conn = elem.conn}; - for (int i = 0; i < elem.cmd_toks.count; i++) { - Token curr_tok = *get_from_TokenVec(&elem.cmd_toks, i); - switch (curr_tok.kind) { - case TOK_WORD: - expand_word(curr_tok.as.word, &result.cmd_slots, shstate); - break; - case TOK_SPECIAL: - push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_SPEC, .as.spec = curr_tok.as.spec}); - break; - case TOK_PROCSUB_IN: - push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_PROC_IN, .as.proc_reg= curr_tok.as.procsub_region}); - break; - case TOK_PROCSUB_OUT: - push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_PROC_OUT, .as.proc_reg= curr_tok.as.procsub_region}); - break; - } - } - return result; -} - -ExpandedPipeline expand_pipeline(Pipeline* pl, ShellState *shstate) { - ExpandedPipeline exp_pl = make_ExpandedPipeline(256); - for (int i = 0; i < pl->count; i++) { - PipelineElement elem = *get_from_Pipeline(pl, i); - ExpandedPipelineElement exp_elem = expand_pipeline_element(elem, shstate); - push_to_ExpandedPipeline(&exp_pl, exp_elem); - } - return exp_pl; -} diff --git a/src/expand.h b/src/expand.h deleted file mode 100644 index b353f39..0000000 --- a/src/expand.h +++ /dev/null @@ -1,31 +0,0 @@ -# pragma once - -#include "preproc.h" -#include "utils.h" - -typedef enum { - SLOT_STR, - SLOT_SPEC, - SLOT_PROC_IN, - SLOT_PROC_OUT, -} SlotKind; - -typedef struct { - SlotKind kind; - union { - char* str; - SpecialToken spec; - Region* proc_reg; - } as; -} Slot; - -DECLARE_VEC(Slot, SlotVec) - -typedef struct { - SlotVec cmd_slots; - Connector conn; -} ExpandedPipelineElement; - -DECLARE_VEC(ExpandedPipelineElement, ExpandedPipeline) - -ExpandedPipeline expand_pipeline(Pipeline* pl, ShellState* shstate); diff --git a/redes/lexparse.c b/src/lexparse.c index 3a55b33..3a55b33 100644 --- a/redes/lexparse.c +++ b/src/lexparse.c @@ -4,20 +4,20 @@ #include <readline/history.h> #include <string.h> -#include "exec.h" +#include "syntax.h" +#include "stages.h" int main() { char* line; - ShellState shstate = {.shell_vars = make_KeyValMap(1), .aliases = make_KeyValMap(1)}; while (1) { line = readline("$ "); if (line[0] == '\0') continue; if (strcmp(line, "exit") == 0) exit(0); add_history(line); - process_input_line(line, &shstate); + Ast ast = lex(line); + PipelineTree pltree = process_ast(ast); + execute_pipeline_tree(pltree); } free(line); } - - diff --git a/src/preproc.c b/src/preproc.c index 4cd1c5b..63e618f 100644 --- a/src/preproc.c +++ b/src/preproc.c @@ -1,318 +1,135 @@ -#include <ctype.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> +#include <assert.h> #include <stdio.h> +#include "syntax.h" -#include "preproc.h" -#include "utils.h" - - -// Lexing - -typedef struct { - char* str; - size_t pos; -} RawLine; - - -String collect_identifier(RawLine* line) { - String id_buf = make_String(256); - while (line->str[line->pos] == '_' || isalnum(line->str[line->pos])) { - push_to_String(&id_buf, line->str[line->pos++]); - } - return id_buf; -} - - - -TokenPtrVec lex_level(RawLine* line, char until, PreprocArena* arena); - - -void expect_char(RawLine* line, char expected) { - if (line->str[line->pos] != expected) { - exit(45); // TODO: nicer handling - } - line->pos++; -} - - -/* -MaybeChunk lex_expansion_chunk(RawLine* line, RegionVec* reg_arena, QuotationMode qmode) { - line->pos++; // Consume $ - if (line->str[line->pos] == '(') { - line->pos++; - if (line->str[line->pos] == '(') { - exit(1); - // TODO: this (and potentially the other parsers must be custom, we need to recognize arithm-internal parens from the terminating `))` ) - - - TokenVec inner_toks = lex_level(line, ')', reg_arena); - expect_char(line, ')'); - expect_char(line, ')'); - Region* reg_ptr = push_to_RegionVec( - reg_arena, - (Region){.mode = ARITHM, .tokens = inner_toks} - ); - return (MaybeChunk){ - .some = true, - .value = (Chunk){ - .qmode = qmode, - .kind = REGION_EXP, - .as.reg_ptr = reg_ptr - }, - }; - } else { - TokenVec inner_toks = lex_level(line, ')', reg_arena); - expect_char(line, ')'); - Region* reg_ptr = push_to_RegionVec( - reg_arena, - (Region){.mode = CMDS, .tokens = inner_toks} - ); - return (MaybeChunk) { - .some = true, - .value = (Chunk){ - .qmode = qmode, - .kind = REGION_EXP, - .as.reg_ptr = reg_ptr, - } - }; - } - } else { - String id_name = collect_identifier(line); - if (id_name.count > 0) { - return (MaybeChunk){ - .some = true, - .value = (Chunk){ - .qmode = qmode, - .kind = VAR_EXP, - .as.varname = inner(&id_name), - } - }; - } - } - return (MaybeChunk){.some = false}; -} -*/ - - -void lex_double_quoted_section(RawLine* line, Word* coll, PreprocArena* arena) { - line->pos++; - String accum = make_String(256); - while (line->str[line->pos] != '\"') { - if (line->str[line->pos] == '\0') exit(43); - - MaybeChunk exp_chunk = {.some = false}; - - if (line->str[line->pos] == '$') { - exit(1); - /* - exp_chunk = lex_expansion_chunk(line, reg_arena, DOUBLE_Q); - if (!exp_chunk.some) { - push_to_String(&accum, '$'); - } - */ +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(&accum, line->str[line->pos++]); - } - // TODO: other special cases beyond $ - - if (exp_chunk.some) { - if (accum.count > 0) { - Chunk accum_chunk = {.qmode = DOUBLE_Q, .kind = LITERAL, .as.literal_str = inner(&accum)}; - Chunk* accum_ptr = push_to_ChunkVec(&arena->chunks, accum_chunk); - push_to_Word(coll, accum_ptr); - accum = make_String(256); - } - Chunk* exp_ptr = push_to_ChunkVec(&arena->chunks, exp_chunk.value); - push_to_Word(coll, exp_ptr); - exp_chunk.some = false; + push_to_String(&buf, str[pos]); } } - line->pos++; - if (accum.count > 0) { - Chunk accum_chunk = {.qmode = DOUBLE_Q, .kind = LITERAL, .as.literal_str = inner(&accum)}; - Chunk* accum_ptr = push_to_ChunkVec(&arena->chunks, accum_chunk); - push_to_Word(coll, accum_ptr); - accum = make_String(256); - } -} - -Chunk next_word_unquoted(RawLine* line, RegionVec* reg_arena) { - String buf = make_String(256); - for (char c; (c=line->str[line->pos], c != '$' && c != '\0' && c != ' '); line->pos++) { - push_to_String(&buf, c); + if (buf.count > 0) { + char* buf_str = inner(&buf); + push_to_StrVec(result, buf_str); } - return (Chunk){.qmode = UN_Q, .kind = LITERAL, .as.literal_str = inner(&buf)}; } - -Chunk collect_single_quoted_section(RawLine* line) { - line->pos++; // Consume quote mark - String chunk_str = make_String(256); - while (line->str[line->pos] != '\'') { - if (line->str[line->pos] == '\0') exit(44); - push_to_String(&chunk_str, line->str[line->pos++]); +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; + } } - line->pos++; // Consume closing quote - return (Chunk){ - .qmode = SINGLE_Q, - .kind = LITERAL, - .as.literal_str = inner(&chunk_str), - }; + return result; } typedef struct { - Word word_germ; - String unq_liter_germ; -} LexState; - - -void close_word_and_lit_germs(LexState* state, TokenPtrVec* toks, PreprocArena* arena) { - if (state->unq_liter_germ.count > 0) { - Chunk chu = { - .qmode = UN_Q, - .kind = LITERAL, - .as.literal_str = inner(&state->unq_liter_germ) - }; - Chunk* chu_ptr = push_to_ChunkVec(&arena->chunks, chu); - push_to_Word(&state->word_germ, chu_ptr); - state->unq_liter_germ = make_String(256); - } - if (state->word_germ.count > 0) { - Token tok = {.kind = TOK_WORD, .as.word = state->word_germ}; - Token* tok_ptr = push_to_TokenVec(&arena->tokens, tok); - push_to_TokenPtrVec(toks, tok_ptr); - state->word_germ = make_Word(256); - } -} + TokenKind kind; + union { + char* word; + SpecialToken spec; + } as; +} ExpandedToken; -TokenPtrVec lex_level(RawLine* line, char until, PreprocArena* arena) { +DECLARE_VEC(ExpandedToken, ExpandedTokenVec) - TokenPtrVec line_toks = make_TokenPtrVec(256); - LexState state = { - .word_germ = make_Word(256), - .unq_liter_germ = make_String(256) - }; +Pipeline* process_token_sequence(TokenVec tokens, PipelineVec* pl_pool) { - while (line->str[line->pos] != until) { + ExpandedTokenVec exp_tokens = make_ExpandedTokenVec(256); - if (line->str[line->pos] == ' ') { - close_word_and_lit_germs(&state, &line_toks, arena); - while (line->str[line->pos] == ' ') line->pos++; - continue; + 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)}); + } } + } - Token* tok_ptr; + Pipeline pl = make_Pipeline(256); + size_t tok_pos = 0; - switch (line->str[line->pos]) { - case '\'': - push_to_Word(&state.word_germ, push_to_ChunkVec(&arena->chunks, collect_single_quoted_section(line))); - break; - case '\"': - lex_double_quoted_section(line, &state.word_germ, arena); - break; - case '|': - line->pos++; - close_word_and_lit_germs(&state, &line_toks, arena); - tok_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = PIPE}); - push_to_TokenPtrVec(&line_toks, tok_ptr); - break; - case '$': - exit(1); - /* - line->pos++; - MaybeChunk mchunk = lex_expansion_chunk(line, reg_arena, UN_Q); - if (mchunk.some) { - push_to_Word(&state.word_germ, mchunk.value); - } else { - push_to_String(&state.unq_liter_germ, '$'); - } - */ - break; - case '>': - close_word_and_lit_germs(&state, &line_toks, arena); - line->pos++; + PlCommand curr_cmd = {.args = make_ArgVec(256), .redirects = make_RedirectVec(256), .conn = CONN_EOL}; - switch (line->str[line->pos]) { - case '(': - line->pos++; - TokenPtrVec sub_regtoks = lex_level(line, ')', arena); - line->pos++; - Region subreg = {.mode = CMDS, .tokens = sub_regtoks}; - Region* subreg_ptr = push_to_RegionVec(&arena->regions, subreg); - Token tok = {.kind = TOK_PROCSUB_OUT, .as.procsub_region = subreg_ptr}; - tok_ptr = push_to_TokenVec(&arena->tokens, tok); - push_to_TokenPtrVec(&line_toks, tok_ptr); - break; - case '>': - line->pos++; - tok_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = WRITE_REDIR_APPEND}); - push_to_TokenPtrVec(&line_toks, tok_ptr); + 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; + 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; default: - tok_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = WRITE_REDIR_TRUNC}); - push_to_TokenPtrVec(&line_toks, tok_ptr); + exit(62); } - break; - case '<': - close_word_and_lit_germs(&state, &line_toks, arena); - line->pos++; - if (line->str[line->pos] == '(') { - line->pos++; - TokenPtrVec sub_regtoks = lex_level(line, ')', arena); - line->pos++; - Region subreg = {.mode = CMDS, .tokens = sub_regtoks}; - Region* reg_ptr = push_to_RegionVec(&arena->regions, subreg); - Token reg_tok = {.kind = TOK_PROCSUB_IN, .as.procsub_region = reg_ptr}; - Token* reg_tok_ptr = push_to_TokenVec(&arena->tokens, reg_tok); - push_to_TokenPtrVec(&line_toks, reg_tok_ptr); - } else { - Token* redir_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = READ_REDIR}); - push_to_TokenPtrVec(&line_toks, redir_ptr); - } - break; - default: - push_to_String(&state.unq_liter_germ, line->str[line->pos++]); } - } - // TODO: handle until char _and_ EOL - close_word_and_lit_germs(&state, &line_toks, arena); - return line_toks; -} - - -TokenPtrVec lex(char* input, PreprocArena* arena) { - RawLine line = {.str = input, .pos = 0}; - TokenPtrVec toks = lex_level(&line, '\0', arena); - Token* eol_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = EOL}); - push_to_TokenPtrVec(&toks, eol_ptr); - return toks; + } + return push_to_PipelineVec(pl_pool, pl); } - - -// Parsing - -Pipeline parse_tokstream(Token* toks) { - size_t tok_pos = 0; - Pipeline result = make_Pipeline(256); - TokenVec tok_buf = make_TokenVec(256); - while (true) { - Token curr_tok = toks[tok_pos++]; - if (curr_tok.kind == TOK_SPECIAL && curr_tok.as.spec == PIPE) { - push_to_Pipeline(&result, (PipelineElement){.cmd_toks = tok_buf, .conn = CONN_PIPE}); - tok_buf = make_TokenVec(256); - } else if (curr_tok.kind == TOK_SPECIAL && curr_tok.as.spec == EOL) { - push_to_Pipeline(&result, (PipelineElement){.cmd_toks = tok_buf, .conn = CONN_EOL}); - break; - } else { - push_to_TokenVec(&tok_buf, curr_tok); - } - } - return result; +PipelineTree process_ast(Ast ast) { + PipelineVec pls = make_PipelineVec(256); + TokenVec root_toks = *ast.root; + Pipeline* root_pl = process_token_sequence(root_toks, &pls); + return (PipelineTree){.pl_pool = pls, root_pl}; } diff --git a/src/preproc.h b/src/preproc.h deleted file mode 100644 index 7907f9d..0000000 --- a/src/preproc.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include "utils.h" - -typedef struct Region Region; - - -// Lexing stage -typedef enum { - UN_Q, - SINGLE_Q, - DOUBLE_Q, -} QuotationMode; - -typedef enum { - LITERAL, - REGION_EXP, - VAR_EXP, // TODO: Later include other exps -} ChunkKind; - -typedef struct { - ChunkKind kind; - QuotationMode qmode; - union { - char* literal_str; - Region* reg_ptr; - char* varname; - } as; -} Chunk; -DECLARE_MAYBE(Chunk, MaybeChunk); -DECLARE_VEC(Chunk*, Word) - -typedef enum { - TOK_WORD, - TOK_SPECIAL, - TOK_PROCSUB_IN, - TOK_PROCSUB_OUT, -} TokenKind; - -typedef enum { - PIPE, - WRITE_REDIR_TRUNC, - WRITE_REDIR_APPEND, - READ_REDIR, - EOL, -} SpecialToken; -DECLARE_MAYBE(SpecialToken, MaybeSpecialToken) - -typedef struct { - TokenKind kind; - - union { - Word word; - SpecialToken spec; - Region* procsub_region; - } as; -} Token; - - -DECLARE_VEC(Token*, TokenPtrVec) - - -typedef enum { - CMDS, - ARITHM, -} RegionMode; - -struct Region { - RegionMode mode; - TokenPtrVec tokens; -}; -DECLARE_VEC(Region, RegionVec) - - - -DECLARE_VEC(Chunk, ChunkVec) -DECLARE_VEC(Token, TokenVec) - - - -// Lexing - -typedef struct { - RegionVec regions; - TokenVec tokens; - ChunkVec chunks; -} PreprocArena; - - -TokenPtrVec lex(char* input, PreprocArena* arena); - - -// Parsing - -typedef enum { - CONN_PIPE, - CONN_EOL, - // TODO: add the |& thingy -} Connector; - -DECLARE_MAYBE(Connector, MaybeConnector) - -typedef struct { - TokenVec cmd_toks; - Connector conn; -} PipelineElement; - -DECLARE_VEC(PipelineElement, Pipeline) - -Pipeline parse_tokstream(Token* tokstream); - - - - - - diff --git a/redes/stages.h b/src/stages.h index 4faaf14..4faaf14 100644 --- a/redes/stages.h +++ b/src/stages.h diff --git a/redes/syntax.h b/src/syntax.h index 0cdb76c..0cdb76c 100644 --- a/redes/syntax.h +++ b/src/syntax.h |
