diff options
Diffstat (limited to 'sys/cmd/rc')
-rw-r--r-- | sys/cmd/rc/code.c | 30 | ||||
-rw-r--r-- | sys/cmd/rc/exec.c | 331 | ||||
-rw-r--r-- | sys/cmd/rc/exec.h | 3 | ||||
-rw-r--r-- | sys/cmd/rc/job.c | 36 | ||||
-rw-r--r-- | sys/cmd/rc/lex.c | 97 | ||||
-rw-r--r-- | sys/cmd/rc/main.c | 6 | ||||
-rw-r--r-- | sys/cmd/rc/parse.c | 451 | ||||
-rw-r--r-- | sys/cmd/rc/parse.h | 48 | ||||
-rw-r--r-- | sys/cmd/rc/rc.h | 58 | ||||
-rw-r--r-- | sys/cmd/rc/syntax.y | 42 | ||||
-rw-r--r-- | sys/cmd/rc/sys.c | 43 | ||||
-rw-r--r-- | sys/cmd/rc/tree.c | 24 | ||||
-rw-r--r-- | sys/cmd/rc/wait.c | 2 |
13 files changed, 778 insertions, 393 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c index 38cc06a..c5b1987 100644 --- a/sys/cmd/rc/code.c +++ b/sys/cmd/rc/code.c @@ -43,7 +43,7 @@ void walk(Tree *node) { Tree *n; - int addr; + int addr1, addr2; if(!node) return; @@ -104,18 +104,18 @@ walk(Tree *node) case '&': emitf(Xasync); - addr = emiti(0); + addr1 = emiti(0); walk(node->child[0]); emitf(Xexit); - storepc(addr); + storepc(addr1); break; case Tsubshell: emitf(Xsubshell); - addr = emiti(0); + addr1 = emiti(0); walk(node->child[0]); emitf(Xexit); - storepc(addr); + storepc(addr1); break; case Tbang: @@ -132,6 +132,26 @@ walk(Tree *node) walk(node->child[0]); break; + case Tpipe: + emitf(Xpipe); + + emiti(node->redir.fd[0]); + emiti(node->redir.fd[1]); + addr1 = emiti(0); + addr2 = emiti(0); + + walk(node->child[0]); + emitf(Xexit); + storepc(addr1); + + walk(node->child[1]); + emitf(Xreturn); + storepc(addr2); + + emitf(Xpipewait); + + break; + case '=': for(n=node; node && node->type == '='; node = node->child[2]) ; diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c index 217f7ee..f9af866 100644 --- a/sys/cmd/rc/exec.c +++ b/sys/cmd/rc/exec.c @@ -10,6 +10,12 @@ struct Builtin{ void (*func)(void); }; +struct State { + int async; +}; + +static struct State state; + // ----------------------------------------------------------------------- // globals @@ -138,6 +144,14 @@ path(char *w) static inline void +undoredirs(void) +{ + while(runner->redir.end != runner->redir.start) + Xpopredir(); +} + +static inline +void defaultsignal(void) { signal(SIGINT, SIG_DFL); @@ -150,15 +164,50 @@ defaultsignal(void) static inline void -setpid(int pid) +setpid(Thread *job, int pid) +{ + job->pid = pid; + if(job->pgid <= 0){ + job->pgid = pid; + addjob(job); + } + + setpgid(pid, job->pgid); +} + +/* fork/execute helpers */ + +static inline +void +initchild(Thread *job, int fg) { - runner->pid = pid; - if(runner->pgid <= 0){ - runner->pgid = runner->pid; - addjob(runner); + int pid = getpid(); + setpid(job, pid); + + if(job->flag.user){ + if(fg) + tcsetpgrp(0, job->pgid); + else + job->flag.user = 0; + defaultsignal(); } - setpgid(pid, runner->pgid); + clearwait(job); +} + +static inline +void +initparent(Thread *job, int pid, int fg) +{ + setpid(job, pid); + + if(job->flag.user){ + if(!fg){ + tcsetpgrp(0, job->pgid); + job->flag.user = 0; + } + } + addwait(job, pid); } static @@ -171,6 +220,7 @@ xx(void) return; } + redirect(runner->redir.end); execute(runner->args->word, path(runner->args->word->str)); poplist(); } @@ -180,29 +230,20 @@ int xforkx(void) { int n, pid; - char buf[ERRMAX]; switch(pid=fork()){ case -1: + Xerror("try again\n"); return -1; case 0: // child - clearwait(runner); - runner->link = nil; - - if(shell.interactive){ - setpid(getpid()); - tcsetpgrp(0, runner->pgid); - defaultsignal(); - } + initchild(runner, 1); pushword("exec"); xx(); - exit(2); // NOTE: xx does not return! - /*unreachable*/ + exit(2); // NOTE: unreachable: xx does not return default: // parent - addwait(runner, pid); - setpid(pid); // ensure the state matches for parent and child + initparent(runner, pid, 0); return pid; } @@ -217,15 +258,14 @@ pushredir(int type, int from, int to) r->type = type; r->from = from; r->to = to; - r->link = runner->redir; - runner->redir = r; + r->link = runner->redir.end, runner->redir.end = r; } /* byte code */ static void -run(Code *c, int pc, Var *local, int keeppid) +run(Code *c, int pc, Var *local, int inherit) { Thread *new = emalloc(sizeof(*new)); @@ -237,10 +277,17 @@ run(Code *c, int pc, Var *local, int keeppid) new->args = nil; new->local = local; - new->redir = nil; - new->flag.i = 0; - new->flag.eof = 0; + new->flag.eof = 0; + if(runner){ + new->pid = runner->pid; + new->flag.user = runner->flag.user; + new->redir.end = new->redir.start = runner->redir.end; + }else{ + new->pid = shell.pid; + new->flag.user = shell.interactive; + new->redir.end = new->redir.start = nil; + } new->wait.status = 0; new->wait.len = 0; @@ -248,14 +295,14 @@ run(Code *c, int pc, Var *local, int keeppid) new->wait.on = nil; new->status = 0; - if(keeppid) - new->pgid = runner->pgid, new->pid = runner->pid; + if(inherit) + new->pgid = runner->pgid; else - new->pgid = new->pid = -1; + new->pgid = -1; new->line = 0; - new->link = runner; - new->next = nil; + new->caller = runner; + new->link = nil; runner = new; } @@ -354,9 +401,7 @@ xdot(void) } if(fd<0){ - print(shell.err, "%s: ", base); - //setstatus("can't open"); - Xerror(".: can't open\n"); + print(shell.err, "failed open: %s: ", base); return; } /* set up for a new command loop */ @@ -432,7 +477,7 @@ xjob(void) int i; Thread *job; - for(i=0, job = shell.jobs; job; job = job->next, i++) + for(i=0, job = shell.jobs; job; job = job->link, i++) report(job,i); poplist(); @@ -454,16 +499,16 @@ xfg(void) } i = atoi(runner->args->word->str); - popword(); // [jobid] + popword(); // [pid|num] - for(job=shell.jobs; i > 0; job=job->next, --i) + for(job=shell.jobs; i > 0; job=job->link, --i) ; poplist(); // this goes here? wakeup(job); - job->link = runner, runner = job; // XXX: can this leave zombies? foreground(job, 1); + job->caller = runner, runner = job; // XXX: can this leave zombies? } void @@ -493,6 +538,7 @@ xboot(int argc, char *argv[]) bootstrap[i].i = 0; run(bootstrap, 1, nil, 0); + runner->pid = runner->pgid = shell.pid; pushlist(); // prime bootstrap argv argv0 = strdup(argv[0]); @@ -516,54 +562,6 @@ Xmark(void) } void -Xerror(char *msg) -{ - print(shell.err, "rc: %s", msg); - flush(shell.err); - while(!runner->flag.i) - Xreturn(); -} - -void -Xreturn(void) -{ - Thread *run = runner; - - switch(run->wait.status){ - /* - * If our job is still running we must: - * 1. move program one step back to rerun Xreturn upon recall - * 2. return to our calling thread - * 3. don't free! - */ - case Prun: case Pstop: - run->code.i--; - runner = run->link; - return; - /* - * If our job has finished: - * 1. remove from our list - * 2. continue to clean up its memory - */ - case Pdone: - deljob(run); - /* fallthrough */ - default: - ; - } - - while(run->args) - poplist(); - freecode(run->code.exe); - efree(run->wait.on); - - runner = run->link; - efree(run); - if(!runner) - exit(0); -} - -void Xword(void) { pushword(runner->code.exe[runner->code.i++].s); @@ -703,21 +701,18 @@ Xasync(void) Xerror("fork failed: try again"); break; - case 0: // child - clearwait(runner); + case 0: // child in background + initchild(runner,0); pushredir(Ropen, null, 0); - if(shell.interactive){ // NOTE: this needs to read off its caller's interactivity - setpid(getpid()); - defaultsignal(); - } - run(runner->code.exe, runner->code.i+1, runner->local, 1); - runner->link = nil; + + run(runner->code.exe, runner->code.i+1, runner->local, 0); + runner->caller = nil; + runner->flag.user = 0; break; - default: // parent + default: // parent in foreground + initparent(runner,pid,1); close(null); - setpid(pid); - addwait(runner, pid); runner->code.i = runner->code.exe[runner->code.i].i; /* jump to end of async command */ /* don't wait: continue running */ @@ -727,33 +722,80 @@ Xasync(void) void Xsubshell(void) { - int pid; + int pid, user; + user = runner->flag.user; switch(pid=fork()){ case -1: Xerror("fork failed: try again"); break; case 0: // child - clearwait(runner); - if(shell.interactive){ // NOTE: this needs to read off its caller's interactivity - setpid(getpid()); - tcsetpgrp(0, runner->pgid); - defaultsignal(); - } + initchild(runner, 1); run(runner->code.exe, runner->code.i+1, runner->local, 1); - runner->link = nil; + runner->caller = nil; break; default: // parent - setpid(pid); - addwait(runner, pid); - waitfor(runner, pid); // wait until child finishes + initparent(runner, pid, 0); // relinquish control + waitfor(runner, pid); // wait until child finishes + if(user){ + tcsetpgrp(0, shell.pid); + runner->flag.user = 1; // take control + } + runner->code.i = runner->code.exe[runner->code.i].i; // jump to end of subshell command and continue execution } } +void +Xpipewait(void) +{ + foreground(runner, 0); +} + +void +Xpipe(void) +{ + Thread *orig; + int pc, pid, lfd, rfd, pfd[2]; + + orig = runner; + pc = orig->code.i; + lfd = orig->code.exe[pc++].i; + rfd = orig->code.exe[pc++].i; + + if(pipe(pfd)<0){ + Xerror("can't get pipe\n"); + return; + } + + switch(pid=fork()){ + case -1: + Xerror("try again"); + break; + case 0: // child + initchild(runner,1); + + /* child 0 (writer) forked process */ + run(runner->code.exe, pc+2, runner->local, 0); + runner->caller = nil; + close(pfd[0]); + pushredir(Ropen, pfd[1], lfd); + break; + + default: // parent + initparent(runner,pid,0); + + /* child 1 (reader) subprocess*/ + run(runner->code.exe, runner->code.exe[pc].i, runner->local, 0); + + close(pfd[1]); + pushredir(Ropen, pfd[0], rfd); + break; + } +} void Xbasic(void) @@ -783,6 +825,7 @@ Xbasic(void) } /* if we are here then it's an external command */ + // TODO: check for if we will exit, don't need to fork, just exec // run the external command if((pid = xforkx()) < 0) { @@ -790,9 +833,6 @@ Xbasic(void) return; } - if(!shell.interactive) - waitall(runner); - foreground(runner, 0); // waits for child poplist(); } @@ -865,7 +905,78 @@ Xbang(void) } void +Xpopredir(void) +{ + Redir *r = runner->redir.end; + if(!r) + fatal("attempted to pop a nil redir\n"); + + runner->redir.end = runner->redir.end->link; + if(r->type==Ropen) + close(r->from); + + efree(r); +} + +void +Xreturn(void) +{ + Thread *curr = runner; + + switch(curr->wait.status){ + /* + * If our job is still running or suspended we must: + * 1. move program one step back to rerun Xreturn upon recall + * 2. return to our calling thread + * 3. don't free! + */ + case Prun: + report(curr, 0); + curr->flag.user = 0; + case Pstop: + curr->code.i--; + runner = curr->caller; + curr->caller = nil; // detach job + return; + /* + * If our job has finished: + * 1. remove from our list + * 2. continue to clean up its memory + */ + case Pdone: + deljob(curr); + /* fallthrough */ + default: + ; + } + + undoredirs(); + + while(curr->args) + poplist(); + freecode(curr->code.exe); + efree(curr->wait.on); + + runner = curr->caller; + efree(curr); + if(!runner) + exit(0); +} + + + +void Xexit(void) { exit(runner->status); } + +void +Xerror(char *msg) +{ + print(shell.err, "rc: %s", msg); + flush(shell.err); + while(!runner->flag.user) + Xreturn(); +} + diff --git a/sys/cmd/rc/exec.h b/sys/cmd/rc/exec.h index 9ad0f3d..f85c699 100644 --- a/sys/cmd/rc/exec.h +++ b/sys/cmd/rc/exec.h @@ -22,6 +22,9 @@ void Xsubshell(void); void Xword(void); void Xcount(void); void Xflat(void); +void Xpipe(void); +void Xpipewait(void); +void Xpopredir(void); void Xerror(char*); diff --git a/sys/cmd/rc/job.c b/sys/cmd/rc/job.c index a8747e9..1587951 100644 --- a/sys/cmd/rc/job.c +++ b/sys/cmd/rc/job.c @@ -11,7 +11,7 @@ getjob(int pid, int *index) { int i; Thread *job; - for(i=0,job=shell.jobs; job && job->pid != pid; i++, job=job->next) + for(i=0,job=shell.jobs; job && job->pid != pid; i++, job=job->link) ; return job; @@ -39,34 +39,42 @@ report(Thread *job, int index) } void -wakeup(Thread *t) +wakeup(Thread *job) { int i; - t->wait.status = Prun; - for(i=0; i < t->wait.len; i++){ - if(t->wait.on[i].status == Pstop) - t->wait.on[i].status = Prun; + job->wait.status = Prun; + for(i=0; i < job->wait.len; i++){ + if(job->wait.on[i].status == Pstop) + job->wait.on[i].status = Prun; } + + tcsetpgrp(0, job->pgid); } void -foreground(Thread *job, int signal) +foreground(Thread *job, int now) { - tcsetpgrp(0, job->pgid); - if(signal){ + Thread *caller = job->caller; + if(now){ if(kill(-job->pgid, SIGCONT) < 0) perror("kill[SIGCONT]"); } waitall(job); - - tcsetpgrp(0, shell.pid); + /* + * reset state if we have a caller + * otherwise we will exit anyways + */ + if(caller && caller->flag.user){ + tcsetpgrp(0, caller->pid); + job->flag.user = 1; + } } void addjob(Thread *job) { - job->next = shell.jobs; + job->link = shell.jobs; shell.jobs = job; job->wait.status = Prun; } @@ -76,8 +84,8 @@ deljob(Thread *job) { Thread **jp; - for(jp = &shell.jobs; *jp && *jp != job; jp = &(*jp)->next) + for(jp = &shell.jobs; *jp && *jp != job; jp = &(*jp)->link) ; - *jp = job->next; + *jp = job->link; } diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c index 4325882..373edd5 100644 --- a/sys/cmd/rc/lex.c +++ b/sys/cmd/rc/lex.c @@ -187,10 +187,6 @@ yylex(void) put3('E','O','F'); return EOF; - case '&': - put1('&'); - return '&'; - case '@': put1('@'); return Tsubshell; @@ -199,6 +195,99 @@ yylex(void) put1('!'); return Tbang; + case '&': + put1('&'); + return '&'; + + case '|': + if(nextis('|')){ + put2('|','|'); + return Toror; + } + node = maketree(); + *w++ = '|'; + + node->type = Tpipe; + node->redir.fd[0] = 1; + node->redir.fd[1] = 1; + goto redir; + + case '>': + node = maketree(); + *w++ = '>'; + node->type = Tredir; + + if(nextis('>')){ + node->redir.type = Rappend; + *w++ = '>'; + }else + node->redir.type = Rwrite; + node->redir.fd[0] = 1; + goto redir; + + case '<': + node = maketree(); + *w++ = '<'; + node->type = Tredir; + + if(nextis('<')){ + node->redir.type = Rhere; + *w++ = '<'; + }else if(nextis('>')){ + node->redir.type = Rrdwr; + *w++ = '>'; + }else{ + node->redir.type = Rread; + } + node->redir.fd[0] = 0; + /* fallthrough */ + redir: + if(nextis('[')){ + *w++='['; + c = advance(); + *w++ = c; + if(c < '0' || '9' < c){ + badredir: + *w = 0; + yyerror(node->type == Tpipe ? "pipe syntax" : "redirection syntax"); + return EOF; + } + node->redir.fd[0] = 0; + do{ + node->redir.fd[0] = 10*node->redir.fd[0]+(c-'0'); + *w++ = c; + c = advance(); + }while('0'<=c && c<='9'); + + if(c == '='){ + *w++ = '='; + if(node->type==Tredir) + node->type = Tdup; + c = advance(); + } + if(c < '0' || '9' < c){ + if(node->type == Tpipe) + goto badredir; + node->redir.type = Rclose; + }else{ + node->redir.type = Rdup; + node->redir.fd[1] = node->redir.fd[0]; + node->redir.fd[0] = 0; + do{ + node->redir.fd[0] = 10*node->redir.fd[0]+(c-'0'); + *w++ = c; + c = advance(); + }while('0'<=c && c<='9'); + } + if(c != ']' || (node->type == Tdup && (node->redir.type = Rhere || node->redir.type == Rappend))) + goto badredir; + *w++ = ']'; + } + *w++ = 0; + yylval.tree = node; + + return node->type; + case '$': if(nextis('#')){ put2('$','#'); diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c index 557030a..cb927e9 100644 --- a/sys/cmd/rc/main.c +++ b/sys/cmd/rc/main.c @@ -42,7 +42,7 @@ initshell(void) if(setpgid(shell.pid, shell.pid)<0) fatal("could not put shell in its own process group"); - tcsetpgrp(0, shell.pid); + tcsetpgrp(shell.pid, shell.pid); } } @@ -52,10 +52,6 @@ initshell(void) int main(int argc, char *argv[]) { - int i; - Code bootstrap[32]; - char num[12]; - shell.err = openfd(2); initenv(); diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c index c53f514..edc1006 100644 --- a/sys/cmd/rc/parse.c +++ b/sys/cmd/rc/parse.c @@ -111,43 +111,51 @@ enum yysymbol_kind_t YYSYMBOL_Telse = 6, /* Telse */ YYSYMBOL_Tbang = 7, /* Tbang */ YYSYMBOL_Tsubshell = 8, /* Tsubshell */ - YYSYMBOL_Targs = 9, /* Targs */ - YYSYMBOL_Tindex = 10, /* Tindex */ - YYSYMBOL_Tbasic = 11, /* Tbasic */ - YYSYMBOL_Tparen = 12, /* Tparen */ - YYSYMBOL_Tblock = 13, /* Tblock */ - YYSYMBOL_Twhile = 14, /* Twhile */ - YYSYMBOL_15_n_ = 15, /* '\n' */ - YYSYMBOL_16_ = 16, /* '$' */ - YYSYMBOL_Tcount = 17, /* Tcount */ - YYSYMBOL_Tflat = 18, /* Tflat */ - YYSYMBOL_19_ = 19, /* '(' */ - YYSYMBOL_20_ = 20, /* ')' */ - YYSYMBOL_21_ = 21, /* '{' */ - YYSYMBOL_22_ = 22, /* '}' */ - YYSYMBOL_23_ = 23, /* ';' */ - YYSYMBOL_24_ = 24, /* '&' */ - YYSYMBOL_25_ = 25, /* '=' */ - YYSYMBOL_26_ = 26, /* '^' */ - YYSYMBOL_YYACCEPT = 27, /* $accept */ - YYSYMBOL_rc = 28, /* rc */ - YYSYMBOL_line = 29, /* line */ - YYSYMBOL_body = 30, /* body */ - YYSYMBOL_paren = 31, /* paren */ - YYSYMBOL_block = 32, /* block */ - YYSYMBOL_cmds = 33, /* cmds */ - YYSYMBOL_cmdsln = 34, /* cmdsln */ - YYSYMBOL_ifbody = 35, /* ifbody */ - YYSYMBOL_assign = 36, /* assign */ - YYSYMBOL_cmd = 37, /* cmd */ - YYSYMBOL_basic = 38, /* basic */ - YYSYMBOL_atom = 39, /* atom */ - YYSYMBOL_word = 40, /* word */ - YYSYMBOL_executable = 41, /* executable */ - YYSYMBOL_nonkeyword = 42, /* nonkeyword */ - YYSYMBOL_keyword = 43, /* keyword */ - YYSYMBOL_wordsnl = 44, /* wordsnl */ - YYSYMBOL_nl = 45 /* nl */ + YYSYMBOL_Toror = 9, /* Toror */ + YYSYMBOL_Tandand = 10, /* Tandand */ + YYSYMBOL_There = 11, /* There */ + YYSYMBOL_Tredir = 12, /* Tredir */ + YYSYMBOL_Tpipe = 13, /* Tpipe */ + YYSYMBOL_Tdup = 14, /* Tdup */ + YYSYMBOL_Tbasic = 15, /* Tbasic */ + YYSYMBOL_Tparen = 16, /* Tparen */ + YYSYMBOL_Tblock = 17, /* Tblock */ + YYSYMBOL_Targs = 18, /* Targs */ + YYSYMBOL_Tindex = 19, /* Tindex */ + YYSYMBOL_Twhile = 20, /* Twhile */ + YYSYMBOL_21_n_ = 21, /* '\n' */ + YYSYMBOL_22_ = 22, /* '$' */ + YYSYMBOL_Tcount = 23, /* Tcount */ + YYSYMBOL_Tflat = 24, /* Tflat */ + YYSYMBOL_25_ = 25, /* '(' */ + YYSYMBOL_26_ = 26, /* ')' */ + YYSYMBOL_27_ = 27, /* '{' */ + YYSYMBOL_28_ = 28, /* '}' */ + YYSYMBOL_29_ = 29, /* ';' */ + YYSYMBOL_30_ = 30, /* '&' */ + YYSYMBOL_31_ = 31, /* '=' */ + YYSYMBOL_32_ = 32, /* '^' */ + YYSYMBOL_YYACCEPT = 33, /* $accept */ + YYSYMBOL_rc = 34, /* rc */ + YYSYMBOL_line = 35, /* line */ + YYSYMBOL_body = 36, /* body */ + YYSYMBOL_paren = 37, /* paren */ + YYSYMBOL_block = 38, /* block */ + YYSYMBOL_cmds = 39, /* cmds */ + YYSYMBOL_cmdsln = 40, /* cmdsln */ + YYSYMBOL_ifbody = 41, /* ifbody */ + YYSYMBOL_assign = 42, /* assign */ + YYSYMBOL_redir = 43, /* redir */ + YYSYMBOL_epilog = 44, /* epilog */ + YYSYMBOL_cmd = 45, /* cmd */ + YYSYMBOL_basic = 46, /* basic */ + YYSYMBOL_atom = 47, /* atom */ + YYSYMBOL_word = 48, /* word */ + YYSYMBOL_executable = 49, /* executable */ + YYSYMBOL_nonkeyword = 50, /* nonkeyword */ + YYSYMBOL_keyword = 51, /* keyword */ + YYSYMBOL_wordsnl = 52, /* wordsnl */ + YYSYMBOL_nl = 53 /* nl */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; @@ -473,21 +481,21 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 37 +#define YYFINAL 42 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 97 +#define YYLAST 158 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 27 +#define YYNTOKENS 33 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 19 +#define YYNNTS 21 /* YYNRULES -- Number of rules. */ -#define YYNRULES 45 +#define YYNRULES 52 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 67 +#define YYNSTATES 79 /* YYMAXUTOK -- Last valid token kind. */ -#define YYMAXUTOK 271 +#define YYMAXUTOK 277 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM @@ -502,18 +510,18 @@ union yyalloc static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 16, 2, 24, 2, - 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, - 2, 25, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 22, 2, 30, 2, + 25, 26, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 29, + 2, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 21, 2, 22, 2, 2, 2, 2, + 2, 2, 2, 27, 2, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -528,18 +536,19 @@ static const yytype_int8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 17, 18 + 15, 16, 17, 18, 19, 20, 23, 24 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int8 yyrline[] = { - 0, 36, 36, 37, 40, 41, 44, 45, 48, 51, - 54, 55, 58, 59, 62, 63, 66, 69, 70, 71, - 72, 73, 74, 75, 78, 79, 88, 89, 92, 93, - 96, 97, 100, 101, 102, 103, 104, 108, 108, 108, - 108, 115, 116, 117, 119, 121 + 0, 37, 37, 38, 41, 42, 45, 46, 49, 52, + 55, 56, 59, 60, 63, 64, 67, 70, 71, 74, + 75, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 89, 90, 91, 94, 95, 98, 99, 102, 103, 106, + 107, 108, 109, 110, 114, 114, 114, 114, 121, 122, + 123, 125, 127 }; #endif @@ -556,12 +565,13 @@ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "Tword", "Twords", - "Tif", "Telse", "Tbang", "Tsubshell", "Targs", "Tindex", "Tbasic", - "Tparen", "Tblock", "Twhile", "'\\n'", "'$'", "Tcount", "Tflat", "'('", - "')'", "'{'", "'}'", "';'", "'&'", "'='", "'^'", "$accept", "rc", "line", - "body", "paren", "block", "cmds", "cmdsln", "ifbody", "assign", "cmd", - "basic", "atom", "word", "executable", "nonkeyword", "keyword", - "wordsnl", "nl", YY_NULLPTR + "Tif", "Telse", "Tbang", "Tsubshell", "Toror", "Tandand", "There", + "Tredir", "Tpipe", "Tdup", "Tbasic", "Tparen", "Tblock", "Targs", + "Tindex", "Twhile", "'\\n'", "'$'", "Tcount", "Tflat", "'('", "')'", + "'{'", "'}'", "';'", "'&'", "'='", "'^'", "$accept", "rc", "line", + "body", "paren", "block", "cmds", "cmdsln", "ifbody", "assign", "redir", + "epilog", "cmd", "basic", "atom", "word", "executable", "nonkeyword", + "keyword", "wordsnl", "nl", YY_NULLPTR }; static const char * @@ -571,7 +581,7 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #endif -#define YYPACT_NINF (-19) +#define YYPACT_NINF (-42) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) @@ -583,15 +593,16 @@ yysymbol_name (yysymbol_kind_t yysymbol) /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -static const yytype_int8 yypact[] = +static const yytype_int16 yypact[] = { - 18, -19, -18, 24, 24, 78, 78, 78, -19, 24, - 5, 7, -19, 24, 24, -4, 78, 41, -19, 24, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, 72, -6, -19, 24, 29, -19, -19, -19, - -19, -19, -19, -19, -2, 78, 78, 10, 55, -19, - -19, -2, -19, -19, -19, 78, -2, -19, -19, -19, - 43, -19, -19, -19, -19, 55, -19 + 22, -42, -23, 89, 89, 133, -42, 133, 133, 133, + -42, 89, 18, 7, -5, 89, 89, 89, 24, 123, + 20, -42, 89, -42, 25, 25, -42, -42, -42, -42, + -42, 23, -42, -42, -42, -42, -42, 99, 15, -42, + 89, 35, -42, -42, -5, -42, -42, 25, 25, -42, + -42, -42, -42, 23, 133, 133, 36, 66, 133, -42, + -42, 23, -42, -42, -42, -42, 66, 23, -42, -42, + -42, 27, -42, 25, -42, -42, -42, 66, 25 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -599,27 +610,30 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_int8 yydefact[] = { - 17, 32, 0, 17, 17, 0, 0, 0, 41, 17, - 0, 0, 19, 17, 17, 4, 18, 24, 30, 17, - 44, 22, 23, 37, 38, 39, 40, 33, 26, 27, - 35, 36, 0, 0, 12, 17, 6, 1, 3, 5, - 20, 10, 11, 28, 25, 0, 0, 0, 17, 42, - 34, 43, 9, 7, 13, 0, 16, 31, 8, 45, - 19, 21, 14, 29, 44, 17, 15 + 21, 39, 0, 21, 21, 0, 17, 0, 0, 0, + 48, 21, 0, 0, 19, 21, 21, 21, 4, 22, + 30, 37, 21, 51, 28, 29, 44, 45, 46, 47, + 35, 18, 33, 34, 40, 42, 43, 0, 0, 12, + 21, 6, 1, 3, 19, 23, 5, 26, 25, 51, + 10, 11, 32, 31, 0, 0, 0, 21, 0, 49, + 41, 50, 9, 7, 13, 20, 21, 16, 38, 8, + 52, 19, 27, 14, 36, 24, 51, 21, 15 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -19, -19, 42, -7, -19, 9, 2, -19, -19, -19, - 0, -19, 4, 6, -19, 1, -19, -19, -10 + -42, -42, 46, 10, -42, 19, 11, -42, -42, -42, + -13, 28, 0, -42, 12, -14, -42, 5, -42, -42, + -41 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - 0, 10, 11, 33, 20, 12, 34, 35, 61, 14, - 36, 16, 43, 44, 17, 18, 29, 32, 48 + 0, 12, 13, 38, 23, 14, 39, 40, 72, 16, + 17, 45, 41, 19, 30, 31, 20, 21, 33, 37, + 57 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -627,63 +641,78 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { - 15, 19, 13, 21, 22, 37, 28, 28, 28, 27, - 30, 31, 47, 15, 40, 13, 52, 28, -2, 41, - 42, 1, 38, 2, 55, 3, 4, 1, 53, 2, - 58, 3, 4, 28, 5, 6, 7, 8, 51, 9, - 5, 6, 7, 8, 54, 9, 28, 28, 62, 64, - 57, 56, 41, 42, 65, 39, 28, 60, 1, 63, - 2, 0, 3, 4, 0, 66, 45, 46, 0, 0, - 59, 5, 6, 7, 8, 1, 9, 23, 24, 25, - 26, 1, 0, 23, 24, 25, 26, 49, 5, 6, - 7, 8, 50, 0, 5, 6, 7, 8 + 18, 44, 22, 24, 25, 53, 52, 5, 66, 6, + 32, 15, 32, 32, 32, 18, 47, 48, 42, 34, + 35, 36, -2, 61, 32, 1, 15, 2, 43, 3, + 4, 44, 56, 76, 5, 77, 6, 49, 49, 5, + 67, 6, 32, 62, 7, 8, 9, 10, 49, 11, + 63, 54, 55, 50, 51, 58, 64, 73, 44, 32, + 32, 46, 69, 32, 50, 51, 75, 68, 0, 1, + 74, 2, 65, 3, 4, 0, 71, 78, 5, 0, + 6, 0, 0, 0, 0, 0, 0, 70, 7, 8, + 9, 10, 1, 11, 2, 0, 3, 4, 0, 0, + 0, 5, 1, 6, 26, 27, 28, 29, 0, 0, + 0, 7, 8, 9, 10, 0, 11, 0, 0, 0, + 59, 7, 8, 9, 10, 60, 1, 0, 26, 27, + 28, 29, 0, 0, 0, 5, 1, 6, 26, 27, + 28, 29, 0, 0, 0, 7, 8, 9, 10, 0, + 0, 0, 0, 0, 0, 7, 8, 9, 10 }; static const yytype_int8 yycheck[] = { - 0, 19, 0, 3, 4, 0, 5, 6, 7, 5, - 6, 7, 19, 13, 14, 13, 22, 16, 0, 23, - 24, 3, 15, 5, 26, 7, 8, 3, 35, 5, - 20, 7, 8, 32, 16, 17, 18, 19, 32, 21, - 16, 17, 18, 19, 15, 21, 45, 46, 48, 6, - 46, 45, 23, 24, 64, 13, 55, 48, 3, 55, - 5, -1, 7, 8, -1, 65, 25, 26, -1, -1, - 15, 16, 17, 18, 19, 3, 21, 5, 6, 7, - 8, 3, -1, 5, 6, 7, 8, 15, 16, 17, - 18, 19, 20, -1, 16, 17, 18, 19 + 0, 14, 25, 3, 4, 19, 19, 12, 49, 14, + 5, 0, 7, 8, 9, 15, 16, 17, 0, 7, + 8, 9, 0, 37, 19, 3, 15, 5, 21, 7, + 8, 44, 22, 6, 12, 76, 14, 13, 13, 12, + 54, 14, 37, 28, 22, 23, 24, 25, 13, 27, + 40, 31, 32, 29, 30, 32, 21, 57, 71, 54, + 55, 15, 26, 58, 29, 30, 66, 55, -1, 3, + 58, 5, 44, 7, 8, -1, 57, 77, 12, -1, + 14, -1, -1, -1, -1, -1, -1, 21, 22, 23, + 24, 25, 3, 27, 5, -1, 7, 8, -1, -1, + -1, 12, 3, 14, 5, 6, 7, 8, -1, -1, + -1, 22, 23, 24, 25, -1, 27, -1, -1, -1, + 21, 22, 23, 24, 25, 26, 3, -1, 5, 6, + 7, 8, -1, -1, -1, 12, 3, 14, 5, 6, + 7, 8, -1, -1, -1, 22, 23, 24, 25, -1, + -1, -1, -1, -1, -1, 22, 23, 24, 25 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { - 0, 3, 5, 7, 8, 16, 17, 18, 19, 21, - 28, 29, 32, 33, 36, 37, 38, 41, 42, 19, - 31, 37, 37, 5, 6, 7, 8, 39, 42, 43, - 39, 39, 44, 30, 33, 34, 37, 0, 15, 29, - 37, 23, 24, 39, 40, 25, 26, 30, 45, 15, - 20, 40, 22, 30, 15, 26, 40, 39, 20, 15, - 32, 35, 37, 39, 6, 45, 37 + 0, 3, 5, 7, 8, 12, 14, 22, 23, 24, + 25, 27, 34, 35, 38, 39, 42, 43, 45, 46, + 49, 50, 25, 37, 45, 45, 5, 6, 7, 8, + 47, 48, 50, 51, 47, 47, 47, 52, 36, 39, + 40, 45, 0, 21, 43, 44, 35, 45, 45, 13, + 29, 30, 43, 48, 31, 32, 36, 53, 32, 21, + 26, 48, 28, 36, 21, 44, 53, 48, 47, 26, + 21, 38, 41, 45, 47, 45, 6, 53, 45 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { - 0, 27, 28, 28, 29, 29, 30, 30, 31, 32, - 33, 33, 34, 34, 35, 35, 36, 37, 37, 37, - 37, 37, 37, 37, 38, 38, 39, 39, 40, 40, - 41, 41, 42, 42, 42, 42, 42, 43, 43, 43, - 43, 44, 44, 44, 45, 45 + 0, 33, 34, 34, 35, 35, 36, 36, 37, 38, + 39, 39, 40, 40, 41, 41, 42, 43, 43, 44, + 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 46, 46, 46, 47, 47, 48, 48, 49, 49, 50, + 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, + 52, 53, 53 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 1, 2, 1, 2, 3, 3, - 2, 2, 1, 2, 1, 4, 3, 0, 1, 1, - 2, 4, 2, 2, 1, 2, 1, 1, 1, 3, - 1, 3, 1, 2, 3, 2, 2, 1, 1, 1, - 1, 0, 2, 2, 0, 2 + 2, 2, 1, 2, 1, 4, 3, 1, 2, 0, + 2, 0, 1, 2, 4, 2, 2, 4, 2, 2, + 1, 2, 2, 1, 1, 1, 3, 1, 3, 1, + 2, 3, 2, 2, 1, 1, 1, 1, 0, 2, + 2, 0, 2 }; @@ -1417,163 +1446,205 @@ yyreduce: switch (yyn) { case 2: /* rc: %empty */ -#line 36 "sys/cmd/rc/syntax.y" +#line 37 "sys/cmd/rc/syntax.y" { return 0; } -#line 1423 "sys/cmd/rc/parse.c" +#line 1452 "sys/cmd/rc/parse.c" break; case 3: /* rc: line '\n' */ -#line 37 "sys/cmd/rc/syntax.y" +#line 38 "sys/cmd/rc/syntax.y" { return compile((yyvsp[-1].tree)); } -#line 1429 "sys/cmd/rc/parse.c" +#line 1458 "sys/cmd/rc/parse.c" break; case 5: /* line: cmds line */ -#line 41 "sys/cmd/rc/syntax.y" +#line 42 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); } -#line 1435 "sys/cmd/rc/parse.c" +#line 1464 "sys/cmd/rc/parse.c" break; case 7: /* body: cmdsln body */ -#line 45 "sys/cmd/rc/syntax.y" +#line 46 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); } -#line 1441 "sys/cmd/rc/parse.c" +#line 1470 "sys/cmd/rc/parse.c" break; case 8: /* paren: '(' body ')' */ -#line 48 "sys/cmd/rc/syntax.y" +#line 49 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tparen, (yyvsp[-1].tree)); } -#line 1447 "sys/cmd/rc/parse.c" +#line 1476 "sys/cmd/rc/parse.c" break; case 9: /* block: '{' body '}' */ -#line 51 "sys/cmd/rc/syntax.y" +#line 52 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tblock, (yyvsp[-1].tree)); } -#line 1453 "sys/cmd/rc/parse.c" +#line 1482 "sys/cmd/rc/parse.c" break; case 11: /* cmds: cmd '&' */ -#line 55 "sys/cmd/rc/syntax.y" +#line 56 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1('&', (yyvsp[-1].tree)); } -#line 1459 "sys/cmd/rc/parse.c" +#line 1488 "sys/cmd/rc/parse.c" break; case 14: /* ifbody: cmd */ -#line 62 "sys/cmd/rc/syntax.y" +#line 63 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(Tif, nil, (yyvsp[0].tree)); } -#line 1465 "sys/cmd/rc/parse.c" +#line 1494 "sys/cmd/rc/parse.c" break; case 15: /* ifbody: block Telse nl cmd */ -#line 63 "sys/cmd/rc/syntax.y" +#line 64 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree3(Tif, nil, (yyvsp[-3].tree), (yyvsp[-2].tree)); } -#line 1471 "sys/cmd/rc/parse.c" +#line 1500 "sys/cmd/rc/parse.c" break; case 16: /* assign: executable '=' word */ -#line 66 "sys/cmd/rc/syntax.y" +#line 67 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2('=', (yyvsp[-2].tree), (yyvsp[0].tree)); } -#line 1477 "sys/cmd/rc/parse.c" +#line 1506 "sys/cmd/rc/parse.c" break; - case 17: /* cmd: %empty */ -#line 69 "sys/cmd/rc/syntax.y" + case 18: /* redir: Tredir word */ +#line 71 "sys/cmd/rc/syntax.y" + { (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 0); } +#line 1512 "sys/cmd/rc/parse.c" + break; + + case 19: /* epilog: %empty */ +#line 74 "sys/cmd/rc/syntax.y" + { (yyval.tree) = nil; } +#line 1518 "sys/cmd/rc/parse.c" + break; + + case 20: /* epilog: redir epilog */ +#line 75 "sys/cmd/rc/syntax.y" + { (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 1); } +#line 1524 "sys/cmd/rc/parse.c" + break; + + case 21: /* cmd: %empty */ +#line 78 "sys/cmd/rc/syntax.y" { (yyval.tree) = nil; } -#line 1483 "sys/cmd/rc/parse.c" +#line 1530 "sys/cmd/rc/parse.c" break; - case 18: /* cmd: basic */ -#line 70 "sys/cmd/rc/syntax.y" + case 22: /* cmd: basic */ +#line 79 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tbasic, (yyvsp[0].tree)); } -#line 1489 "sys/cmd/rc/parse.c" +#line 1536 "sys/cmd/rc/parse.c" break; - case 20: /* cmd: assign cmd */ -#line 72 "sys/cmd/rc/syntax.y" + case 23: /* cmd: block epilog */ +#line 80 "sys/cmd/rc/syntax.y" + { (yyval.tree) = hangepilog((yyvsp[-1].tree), (yyvsp[0].tree)); } +#line 1542 "sys/cmd/rc/parse.c" + break; + + case 24: /* cmd: cmd Tpipe nl cmd */ +#line 81 "sys/cmd/rc/syntax.y" + { (yyval.tree) = hangchild2((yyvsp[-2].tree), (yyvsp[-3].tree), 0, (yyvsp[0].tree), 1); } +#line 1548 "sys/cmd/rc/parse.c" + break; + + case 25: /* cmd: redir cmd */ +#line 82 "sys/cmd/rc/syntax.y" + { (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 1); } +#line 1554 "sys/cmd/rc/parse.c" + break; + + case 26: /* cmd: assign cmd */ +#line 83 "sys/cmd/rc/syntax.y" { (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 2); } -#line 1495 "sys/cmd/rc/parse.c" +#line 1560 "sys/cmd/rc/parse.c" break; - case 21: /* cmd: Tif paren nl ifbody */ -#line 73 "sys/cmd/rc/syntax.y" + case 27: /* cmd: Tif paren nl ifbody */ +#line 84 "sys/cmd/rc/syntax.y" { (yyval.tree) = hangchild1((yyvsp[-2].tree), (yyvsp[-3].tree), 0); } -#line 1501 "sys/cmd/rc/parse.c" +#line 1566 "sys/cmd/rc/parse.c" break; - case 22: /* cmd: Tbang cmd */ -#line 74 "sys/cmd/rc/syntax.y" + case 28: /* cmd: Tbang cmd */ +#line 85 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tbang, (yyvsp[0].tree)); } -#line 1507 "sys/cmd/rc/parse.c" +#line 1572 "sys/cmd/rc/parse.c" break; - case 23: /* cmd: Tsubshell cmd */ -#line 75 "sys/cmd/rc/syntax.y" + case 29: /* cmd: Tsubshell cmd */ +#line 86 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tsubshell, (yyvsp[0].tree)); } -#line 1513 "sys/cmd/rc/parse.c" +#line 1578 "sys/cmd/rc/parse.c" break; - case 25: /* basic: basic word */ -#line 79 "sys/cmd/rc/syntax.y" - { (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); } -#line 1519 "sys/cmd/rc/parse.c" + case 31: /* basic: basic word */ +#line 90 "sys/cmd/rc/syntax.y" + { (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); } +#line 1584 "sys/cmd/rc/parse.c" + break; + + case 32: /* basic: basic redir */ +#line 91 "sys/cmd/rc/syntax.y" + { (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); } +#line 1590 "sys/cmd/rc/parse.c" break; - case 27: /* atom: keyword */ -#line 89 "sys/cmd/rc/syntax.y" + case 34: /* atom: keyword */ +#line 95 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tword, (yyvsp[0].tree)); } -#line 1525 "sys/cmd/rc/parse.c" +#line 1596 "sys/cmd/rc/parse.c" break; - case 29: /* word: word '^' atom */ -#line 93 "sys/cmd/rc/syntax.y" + case 36: /* word: word '^' atom */ +#line 99 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); } -#line 1531 "sys/cmd/rc/parse.c" +#line 1602 "sys/cmd/rc/parse.c" break; - case 31: /* executable: executable '^' atom */ -#line 97 "sys/cmd/rc/syntax.y" + case 38: /* executable: executable '^' atom */ +#line 103 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); } -#line 1537 "sys/cmd/rc/parse.c" +#line 1608 "sys/cmd/rc/parse.c" break; - case 33: /* nonkeyword: '$' atom */ -#line 101 "sys/cmd/rc/syntax.y" + case 40: /* nonkeyword: '$' atom */ +#line 107 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1('$', (yyvsp[0].tree)); } -#line 1543 "sys/cmd/rc/parse.c" +#line 1614 "sys/cmd/rc/parse.c" break; - case 34: /* nonkeyword: '(' wordsnl ')' */ -#line 102 "sys/cmd/rc/syntax.y" + case 41: /* nonkeyword: '(' wordsnl ')' */ +#line 108 "sys/cmd/rc/syntax.y" { (yyval.tree) = (yyvsp[-1].tree); } -#line 1549 "sys/cmd/rc/parse.c" +#line 1620 "sys/cmd/rc/parse.c" break; - case 35: /* nonkeyword: Tcount atom */ -#line 103 "sys/cmd/rc/syntax.y" + case 42: /* nonkeyword: Tcount atom */ +#line 109 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tcount, (yyvsp[0].tree)); } -#line 1555 "sys/cmd/rc/parse.c" +#line 1626 "sys/cmd/rc/parse.c" break; - case 36: /* nonkeyword: Tflat atom */ -#line 104 "sys/cmd/rc/syntax.y" + case 43: /* nonkeyword: Tflat atom */ +#line 110 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tflat, (yyvsp[0].tree)); } -#line 1561 "sys/cmd/rc/parse.c" +#line 1632 "sys/cmd/rc/parse.c" break; - case 41: /* wordsnl: %empty */ -#line 115 "sys/cmd/rc/syntax.y" + case 48: /* wordsnl: %empty */ +#line 121 "sys/cmd/rc/syntax.y" { (yyval.tree) = nil; } -#line 1567 "sys/cmd/rc/parse.c" +#line 1638 "sys/cmd/rc/parse.c" break; - case 43: /* wordsnl: wordsnl word */ -#line 117 "sys/cmd/rc/syntax.y" + case 50: /* wordsnl: wordsnl word */ +#line 123 "sys/cmd/rc/syntax.y" {(yyval.tree) = (!(yyvsp[-1].tree)) ? ((!(yyvsp[0].tree)) ? nil : (yyvsp[0].tree)) : ((!(yyvsp[0].tree)) ? (yyvsp[-1].tree) : maketree2(Twords, (yyvsp[-1].tree), (yyvsp[0].tree))); } -#line 1573 "sys/cmd/rc/parse.c" +#line 1644 "sys/cmd/rc/parse.c" break; -#line 1577 "sys/cmd/rc/parse.c" +#line 1648 "sys/cmd/rc/parse.c" default: break; } @@ -1797,5 +1868,5 @@ yyreturnlab: return yyresult; } -#line 122 "sys/cmd/rc/syntax.y" +#line 128 "sys/cmd/rc/syntax.y" diff --git a/sys/cmd/rc/parse.h b/sys/cmd/rc/parse.h index b42cc2b..c30606d 100644 --- a/sys/cmd/rc/parse.h +++ b/sys/cmd/rc/parse.h @@ -60,14 +60,20 @@ extern int yydebug; Telse = 261, /* Telse */ Tbang = 262, /* Tbang */ Tsubshell = 263, /* Tsubshell */ - Targs = 264, /* Targs */ - Tindex = 265, /* Tindex */ - Tbasic = 266, /* Tbasic */ - Tparen = 267, /* Tparen */ - Tblock = 268, /* Tblock */ - Twhile = 269, /* Twhile */ - Tcount = 270, /* Tcount */ - Tflat = 271 /* Tflat */ + Toror = 264, /* Toror */ + Tandand = 265, /* Tandand */ + There = 266, /* There */ + Tredir = 267, /* Tredir */ + Tpipe = 268, /* Tpipe */ + Tdup = 269, /* Tdup */ + Tbasic = 270, /* Tbasic */ + Tparen = 271, /* Tparen */ + Tblock = 272, /* Tblock */ + Targs = 273, /* Targs */ + Tindex = 274, /* Tindex */ + Twhile = 275, /* Twhile */ + Tcount = 276, /* Tcount */ + Tflat = 277 /* Tflat */ }; typedef enum yytokentype yytoken_kind_t; #endif @@ -82,24 +88,30 @@ extern int yydebug; #define Telse 261 #define Tbang 262 #define Tsubshell 263 -#define Targs 264 -#define Tindex 265 -#define Tbasic 266 -#define Tparen 267 -#define Tblock 268 -#define Twhile 269 -#define Tcount 270 -#define Tflat 271 +#define Toror 264 +#define Tandand 265 +#define There 266 +#define Tredir 267 +#define Tpipe 268 +#define Tdup 269 +#define Tbasic 270 +#define Tparen 271 +#define Tblock 272 +#define Targs 273 +#define Tindex 274 +#define Twhile 275 +#define Tcount 276 +#define Tflat 277 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { -#line 22 "sys/cmd/rc/syntax.y" +#line 23 "sys/cmd/rc/syntax.y" struct Tree *tree; -#line 103 "sys/cmd/rc/parse.h" +#line 115 "sys/cmd/rc/parse.h" }; typedef union YYSTYPE YYSTYPE; diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h index 606ca7b..d3fc7bf 100644 --- a/sys/cmd/rc/rc.h +++ b/sys/cmd/rc/rc.h @@ -3,19 +3,6 @@ #include <u.h> #include <libn.h> -/* - * A thread functions much like a GNU job -> it's just a simple execution stack - * We just need to modify the following datastructures: - * - * 1. Need to store the list of all "active" and "foreground" threads - * - Right now we just have Thread *proc which is the running process. - * - Need to move this to a linked list (how does this interact with the link?) - * - Linked list stores the independent roots of each individual process tree - * 2. Child pids are stored inside waitpid right now. Need to associate this more explictly with a thread. - * 3. Wait needs to be generalized to act on threads. - * 4. our "start" function is equivalent to the launch_job function - * 5. running the interpreter runs the launch_process implicitly (with forks called as interpreter functions) - */ // ----------------------------------------------------------------------- // types @@ -36,10 +23,28 @@ struct Io char *b, *e, buf[]; }; +enum +{ + Rappend, + Rwrite, + Rread, + Rhere, + Rdup, + Ropen, + Rclose, + Rrdwr +}; + struct Tree { int type; - char *str; + union{ + char *str; // Tword + struct { + ushort type; // Tpipe, Tredir, Tdup + int fd[2]; + } redir; + }; Tree *child[3]; Tree *link; }; @@ -79,13 +84,6 @@ struct Var Var *link; }; -enum -{ - Rclose, - Rdup, - Ropen, -}; - struct Redir { char type; /* what to do */ @@ -122,11 +120,14 @@ struct Thread List *args; // argument stack Var *local; // local variables - Redir *redir; // list of redirections + struct { + Redir *start; + Redir *end; + } redir; // list of redirections struct { - ushort i : 1; - ushort eof : 1; + ushort user : 1; + ushort eof : 1; } flag; struct { @@ -138,8 +139,8 @@ struct Thread int pid, pgid, status; long line; - Thread *link; // process we return to - Thread *next; // next job + Thread *caller; // process we return to + Thread *link; // next job }; struct Shell @@ -197,12 +198,15 @@ Tree *maketree2(int, Tree*, Tree*); Tree *maketree3(int, Tree*, Tree*, Tree*); Tree *token(int, char *); -Tree *hangchild1(Tree *, Tree *, int at); +Tree *hangchild1(Tree *, Tree *, int); +Tree *hangchild2(Tree *, Tree *, int, Tree *, int); +Tree *hangepilog(Tree *, Tree*); void freeparsetree(void); /* sys.c */ void initenv(void); +void redirect(struct Redir *); void execute(Word *, Word*); /* wait.c */ diff --git a/sys/cmd/rc/syntax.y b/sys/cmd/rc/syntax.y index 6334819..cb4a174 100644 --- a/sys/cmd/rc/syntax.y +++ b/sys/cmd/rc/syntax.y @@ -1,6 +1,6 @@ %token Tword Twords Tif Telse Tbang Tsubshell -%token Targs Tindex -%token Tbasic Tparen Tblock +%token Toror Tandand There Tredir Tpipe Tdup +%token Tbasic Tparen Tblock Targs Tindex %define parse.error verbose @@ -12,20 +12,21 @@ %} /* operator precendence: lowest first */ -%left Twhile Telse -%left '\n' -%left Tbang Tsubshell +%left Twhile Telse +%left '\n' +%left Tbang Tsubshell +%left Tpipe; %right '$' Tcount Tflat -%right Tindex +%left Tindex /* semantic types */ %union{ struct Tree *tree; } -%type<tree> line cmds cmdsln body paren block ifbody assign; -%type<tree> cmd basic executable nonkeyword keyword word words wordsnl atom arg args; -%type<tree> Tbang Tsubshell Tindex; -%type<tree> Tword Tif Telse; +%type<tree> line cmds cmdsln body paren block ifbody assign epilog redir; +%type<tree> cmd basic executable nonkeyword keyword word words wordsnl atom; +%type<tree> Tbang Tsubshell Tif Telse; +%type<tree> Tword Tredir Tpipe; /* grammar */ @@ -65,10 +66,20 @@ ifbody: assign: executable '=' word { $$ = maketree2('=', $1, $3); } +redir: + Tdup +| Tredir word { $$ = hangchild1($1, $2, 0); } + +epilog: +/* empty */ { $$ = nil; } +| redir epilog { $$ = hangchild1($1, $2, 1); } + cmd: /* empty */ %prec Twhile { $$ = nil; } | basic { $$ = maketree1(Tbasic, $1); } -| block +| block epilog { $$ = hangepilog($1, $2); } +| cmd Tpipe nl cmd { $$ = hangchild2($2, $1, 0, $4, 1); } +| redir cmd %prec Tbang { $$ = hangchild1($1, $2, 1); } | assign cmd %prec Tbang { $$ = hangchild1($1, $2, 2); } | Tif paren nl ifbody { $$ = hangchild1($2, $1, 0); } | Tbang cmd { $$ = maketree1(Tbang, $2); } @@ -76,13 +87,8 @@ cmd: basic: executable -| basic word { $$ = maketree2(Targs, $1, $2); } - -arg: word - -args: - arg -| args arg { $$ = maketree2(Targs, $1, $2); } +| basic word { $$ = maketree2(Targs, $1, $2); } +| basic redir { $$ = maketree2(Targs, $1, $2); } atom: nonkeyword diff --git a/sys/cmd/rc/sys.c b/sys/cmd/rc/sys.c index d286c88..496c2e6 100644 --- a/sys/cmd/rc/sys.c +++ b/sys/cmd/rc/sys.c @@ -90,3 +90,46 @@ execute(Word *cmd, Word *path) efree(argv); fatal("could not execute command: %s\n", path->str); } + +void +redirect(Redir *r) +{ + if(r){ + redirect(r->link); + switch(r->type){ + case Ropen: + if(r->from != r->to){ + } + break; + case Rdup: + dup2(r->from, r->to); // TODO: error checking + break; + case Rclose: + close(r->from); + break; + default: + fatal("unrecognized redirection type %d\n", r->type); + } + } +} + +int +mapfd(int fd) +{ + Redir *r; + for(r = runner->redir.end; r; r = r->link){ + switch(r->type){ + case Rclose: + if(r->from == fd) + fd = -1; + break; + case Rdup: + case Ropen: + if(r->to == fd) + fd = r->from; + break; + } + } + + return fd; +} diff --git a/sys/cmd/rc/tree.c b/sys/cmd/rc/tree.c index 0e2146f..0f7378f 100644 --- a/sys/cmd/rc/tree.c +++ b/sys/cmd/rc/tree.c @@ -19,7 +19,7 @@ freeparsetree(void) Tree *t, *nt; for(t = nodes; t; t = nt) { nt = t->link; - if(t->str) + if(t->type == Tword && t->str) efree(t->str); efree(t); } @@ -60,6 +60,28 @@ hangchild1(Tree *node, Tree *c, int i) } Tree* +hangchild2(Tree *node, Tree *c1, int i1, Tree *c2, int i2) +{ + node->child[i1] = c1; + node->child[i2] = c2; + + return node; +} + +Tree* +hangepilog(Tree *cmd, Tree *epi) +{ + Tree *p; + if(!epi) + return cmd; + for(p = epi; p->child[1]; p = p->child[1]) + ; + + p->child[1] = cmd; + return epi; +} + +Tree* token(int type, char *s) { Tree *node = maketree(); diff --git a/sys/cmd/rc/wait.c b/sys/cmd/rc/wait.c index 6a8d859..4d45e4b 100644 --- a/sys/cmd/rc/wait.c +++ b/sys/cmd/rc/wait.c @@ -51,7 +51,7 @@ await(int pid4, int opt, struct WaitMsg *msg) msg->time[0] = u; msg->time[1] = s; msg->time[2] = u+s; - msg->status = WCOREDUMP(status); + msg->status = WTERMSIG(status); msg->type = Psig; return 1; |