os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

commit cd03ec0cd9a0978b73cb47771eeaef9fd9c6e7ab
parent e98815b06bc941a0b653656b6176c614e78fca0d
Author: erai <erai@omiltem.net>
Date:   Thu, 12 Sep 2024 12:48:56 -0400

Less than minimal shell

Diffstat:
Msh.c | 521++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 314 insertions(+), 207 deletions(-)

diff --git a/sh.c b/sh.c @@ -10,7 +10,6 @@ struct shell { buf: *byte; len: int; cap: int; - quoted: int; status: int; } @@ -27,8 +26,6 @@ enum { T_NOT, T_LPAR, T_RPAR, - T_LBRA, - T_RBRA, } feedc(s: *shell) { @@ -197,26 +194,13 @@ feed(s: *shell) { return; } - if s.c == '{' { - feedc(s); - s.tt = T_LBRA; - return; - } - if s.c == ')' { feedc(s); s.tt = T_RPAR; return; } - if s.c == '}' { - feedc(s); - s.tt = T_RBRA; - return; - } - s.len = 0; - s.quoted = 0; s.tt = T_WORD; loop { @@ -234,14 +218,12 @@ feed(s: *shell) { } if s.c == '\\' { - s.quoted = 1; feedc(s); feedw(s); continue; } if s.c == '"' { - s.quoted = 1; feed_quote(s); continue; } @@ -259,16 +241,52 @@ feed(s: *shell) { } } +enum { + C_NOP, + C_IN, + C_OUT, + C_CMD, + C_ARG, + C_FOR, + C_SUBSHELL, + C_AND, + C_OR, + C_PIPE, +} + +struct cmd { + kind: int; + word: *byte; + next: *cmd; + arg: *cmd; + redir: *cmd; + cond: *cmd; + body: *cmd; + other: *cmd; +} + +mkcmd(s: *shell, kind: int): *cmd { + var c: *cmd; + c = alloc(s.a, sizeof(*c)):*cmd; + bzero(c:*byte, sizeof(*c)); + c.kind = kind; + return c; +} + // command = LF // | and_or LF -parse_command(s: *shell): int { +parse_command(s: *shell): *cmd { + var c: *cmd; + if s.tt == T_LF { + c = mkcmd(s, C_NOP); feed(s); - return 1; + return c; } - if !parse_and_or(s) { - return 0; + c = parse_and_or(s); + if !c { + return 0:*cmd; } if s.tt != T_LF { @@ -276,127 +294,163 @@ parse_command(s: *shell): int { } feed(s); - return 1; + return c; } // and_or = pipeline // | pipeline '||' and_or // | pipeine '&&' and_or -parse_and_or(s: *shell): int { - if !parse_pipeline(s) { - return 0; +parse_and_or(s: *shell): *cmd { + var c: *cmd; + var link: **cmd; + var p: *cmd; + var t: *cmd; + + c = 0:*cmd; + link = &c; + + c = parse_pipeline(s); + if !c { + return 0:*cmd; } loop { - if s.tt != T_AND && s.tt != T_OR { - return 1; + if s.tt == T_AND { + feed(s); + p = parse_pipeline(s); + if ! p { + die("expected pipeline"); + } + t = mkcmd(s, C_AND); + t.cond = *link; + t.other = p; + *link = t; + link = &t.other; } - feed(s); - if !parse_pipeline(s) { - die("expected pipeline"); + if s.tt == T_OR { + feed(s); + p = parse_pipeline(s); + if ! p { + die("expected pipeline"); + } + t = mkcmd(s, C_OR); + t.cond = *link; + t.other = p; + *link = t; + link = &t.other; } + + return c; } } // pipeline = '!' pipeline // | compound // | compound '|' pipeline -parse_pipeline(s: *shell): int { +parse_pipeline(s: *shell): *cmd { + var neg: int; + var c: *cmd; + var link: **cmd; + var p: *cmd; + var t: *cmd; + + c = 0:*cmd; + link = &c; + if s.tt == T_NOT { loop { if s.tt != T_NOT { break; } feed(s); + neg = neg + 1; } - if !parse_compound(s) { + c = parse_compound(s); + if !c { die("expected compound"); } } else { - if !parse_compound(s) { - return 0; + c = parse_compound(s); + if !c { + return 0:*cmd; } } loop { if s.tt != T_PIPE { - return 1; + return c; } feed(s); - if !parse_compound(s) { + p = parse_compound(s); + if !p { die("expected compound"); } - } -} -// compound = subshell | brace | if | for | while | simple -parse_compound(s: *shell): int { - if parse_subshell(s) { - return 1; - } else if parse_brace(s) { - return 1; - } else if parse_if(s) { - return 1; - } else if parse_for(s) { - return 1; - } else if parse_while(s) { - return 1; - } else if parse_simple(s) { - return 1; - } else { - return 0; + t = mkcmd(s, C_PIPE); + t.cond = *link; + t.body = p; + *link = t; + link = &t.body; } } -// subshell = '(' command_list ')' -// | subshell redir_list -parse_subshell(s: *shell): int { - if s.tt != T_LPAR { - return 0; - } - feed(s); +// compound = subshell | if | for | simple +parse_compound(s: *shell): *cmd { + var c: *cmd; - loop { - if !parse_command(s) { - break; - } + c = parse_subshell(s); + if c { + return c; } - if s.tt != T_RPAR { - die("expected )"); + c = parse_for(s); + if c { + return c; } - feed(s); - parse_redir_list(s); + c = parse_simple(s); + if c { + return c; + } - return 1; + return 0:*cmd; } -// brace = '{' command_list '}' -// | brace redir_list -parse_brace(s: *shell): int { - if s.tt != T_LBRA { - return 0; +// subshell = '(' command_list ')' +// | subshell redir_list +parse_subshell(s: *shell): *cmd { + var body: *cmd; + var link: **cmd; + var t: *cmd; + + body = 0:*cmd; + link = &body; + + if s.tt != T_LPAR { + return 0:*cmd; } feed(s); loop { - if !parse_command(s) { + t = parse_command(s); + if !t { break; } + *link = t; + link = &t.next; } - if s.tt != T_RBRA { - die("expected }"); + if s.tt != T_RPAR { + die("expected )"); } feed(s); - parse_redir_list(s); - - return 1; + t = mkcmd(s, C_SUBSHELL); + t.redir = parse_redir_list(s); + return t; } parse_keyword(s: *shell, key: *byte): int { @@ -404,10 +458,6 @@ parse_keyword(s: *shell, key: *byte): int { return 0; } - if s.quoted { - return 0; - } - if s.len != strlen(key) { return 0; } @@ -421,73 +471,29 @@ parse_keyword(s: *shell, key: *byte): int { return 1; } -// if = 'if' command 'then' command_list else_fi -// else_fi = 'elif' command 'then' command_list else_fi -// | 'else' command_list 'fi' -// | 'fi' -parse_if(s: *shell): int { - if !parse_keyword(s, "if") { - return 0; - } - - if !parse_command(s) { - die("expected command"); - } - - if !parse_keyword(s, "then") { - die("expected then"); - } - - loop { - if parse_keyword(s, "fi") { - break; - } - - if parse_keyword(s, "elif") { - if !parse_command(s) { - die("expected command"); - } - - if !parse_keyword(s, "then") { - die("expected then"); - } - continue; - } - - if parse_keyword(s, "else") { - loop { - if parse_keyword(s, "fi") { - break; - } - - if !parse_command(s) { - die("expected command"); - } - } - break; - } - - if !parse_command(s) { - die("expected command"); - } - } - - parse_redir_list(s); - - return 1; -} - // for = 'for' NAME 'in' word_list LF 'do' command_list 'done' // | for redir_list -parse_for(s: *shell): int { +parse_for(s: *shell): *cmd { + var arg: *cmd; + var arg_link: **cmd; + var body: *cmd; + var body_link: **cmd; + var t: *cmd; + var w: *byte; + + arg = 0:*cmd; + arg_link = &arg; + body = 0:*cmd; + body_link = &body; + if !parse_keyword(s, "for") { - return 0; + return 0:*cmd; } - if s.tt != T_WORD { + w = take(s); + if !w { die("expceted name"); } - feed(s); if !parse_keyword(s, "in") { die("expected in"); @@ -499,11 +505,14 @@ parse_for(s: *shell): int { break; } - if s.tt != T_WORD { + w = take(s); + if !w { die("expected word"); } - - feed(s); + t = mkcmd(s, C_ARG); + t.word = w; + *arg_link = t; + arg_link = &t.next; } if !parse_keyword(s, "do") { @@ -515,99 +524,196 @@ parse_for(s: *shell): int { break; } - if !parse_command(s) { - die("expected command"); - } - } - - parse_redir_list(s); - - return 1; -} - -// while = 'while' command 'do' command_list 'done' -// | while redir_list -parse_while(s: *shell): int { - if !parse_keyword(s, "while") { - return 0; - } - - if !parse_command(s) { - die("expected command"); - } - - if !parse_keyword(s, "do") { - die("expceted do"); - } - - loop { - if !parse_keyword(s, "done") { - break; - } - - if !parse_command(s) { + t = parse_command(s); + if !t { die("expected command"); } + *body_link = t; + body_link = &t.next; } - parse_redir_list(s); - - return 1; + t = mkcmd(s, C_FOR); + t.arg = arg; + t.body = body; + t.redir = parse_redir_list(s); + return t; } // simple = word // | redir // | word simple // | redir simple -parse_simple(s: *shell): int { - if s.tt == T_WORD { - feed(s); - } else if !parse_redir(s) { - return 0; +parse_simple(s: *shell): *cmd { + var arg: *cmd; + var arg_link: **cmd; + var redir: *cmd; + var redir_link: **cmd; + var c: *cmd; + var t: *cmd; + var w: *byte; + + arg = 0:*cmd; + arg_link = &arg; + redir = 0:*cmd; + redir_link = &redir; + + w = take(s); + if w { + t = mkcmd(s, C_ARG); + t.word = w; + *arg_link = t; + arg_link = &t.next; + } else { + t = parse_redir(s); + if t { + *redir_link = t; + redir_link = &t.next; + } else { + return 0: *cmd; + } } loop { - if s.tt == T_WORD { - feed(s); - } else if !parse_redir(s) { - return 1; + w = take(s); + if w { + t = mkcmd(s, C_ARG); + t.word = w; + *arg_link = t; + arg_link = &t.next; + continue; + } + + t = parse_redir(s); + if t { + *redir_link = t; + redir_link = &t.next; + continue; } + + t = mkcmd(s, C_CMD); + t.arg = arg; + t.redir = redir; + return t; } } // redir_list = // | redir redir_list -parse_redir_list(s: *shell): int { +parse_redir_list(s: *shell): *cmd { + var c: *cmd; + var t: *cmd; + var link: **cmd; + + c = 0:*cmd; + link = &c; + loop { - if !parse_redir(s) { - return 1; + t = parse_redir(s); + if !t { + return c; } + *link = t; + link = &t.next; } } +take(s: *shell): *byte { + var w: *byte; + + if s.tt != T_WORD { + return 0: *byte; + } + + w = alloc(s.a, s.len + 1); + memcpy(w, s.buf, s.len); + w[s.len] = 0:byte; + feed(s); + + return w; +} + // redir = '>' word // | '<' word -parse_redir(s: *shell): int { - if s.tt != T_IN && s.tt != T_OUT { - return 0; +parse_redir(s: *shell): *cmd { + var c: *cmd; + var w: *byte; + + if s.tt == T_IN { + feed(s); + c = mkcmd(s, C_IN); + w = take(s); + if !w { + die("expected word"); + } + c.word = w; + return c; } - feed(s); - if s.tt != T_WORD { - die("expected word"); + if s.tt == T_OUT { + feed(s); + c = mkcmd(s, C_OUT); + w = take(s); + if !w { + die("expected word"); + } + c.word = w; + return c; } - feed(s); - return 1; + return 0:*cmd; } -execute_command(s: *shell) { - die("noimpl"); +execute_command(s: *shell, c: *cmd) { + if c.kind == C_NOP { + return; + } else if c.kind == C_CMD { + } else if c.kind == C_FOR { + c = c.body; + loop { + if !c { + break; + } + execute_command(s, c); + c = c.next; + } + } else if c.kind == C_SUBSHELL { + c = c.body; + loop { + if !c { + break; + } + execute_command(s, c); + c = c.next; + } + } else if c.kind == C_AND { + execute_command(s, c.cond); + if s.status == 0 { + execute_command(s, c.other); + } + } else if c.kind == C_OR { + execute_command(s, c.cond); + if s.status != 0 { + execute_command(s, c.other); + } + } else if c.kind == C_PIPE { + execute_command(s, c.cond); + c = c.body; + loop { + if !c { + break; + } + execute_command(s, c); + c = c.body; + } + } else { + die("invalid"); + } } main(argc: int, argv: **byte, envp: **byte) { var a: alloc; var s: shell; + var c: *cmd; var i: int; var fd: int; setup_alloc(&a); @@ -657,10 +763,11 @@ main(argc: int, argv: **byte, envp: **byte) { exit(s.status); } - if !parse_command(&s) { + c = parse_command(&s); + if !c { exit(127); } - execute_command(&s); + execute_command(&s, c); } }