aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/cmd/rc/code.c30
-rw-r--r--sys/cmd/rc/exec.c331
-rw-r--r--sys/cmd/rc/exec.h3
-rw-r--r--sys/cmd/rc/job.c36
-rw-r--r--sys/cmd/rc/lex.c97
-rw-r--r--sys/cmd/rc/main.c6
-rw-r--r--sys/cmd/rc/parse.c451
-rw-r--r--sys/cmd/rc/parse.h48
-rw-r--r--sys/cmd/rc/rc.h58
-rw-r--r--sys/cmd/rc/syntax.y42
-rw-r--r--sys/cmd/rc/sys.c43
-rw-r--r--sys/cmd/rc/tree.c24
-rw-r--r--sys/cmd/rc/wait.c2
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;