aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-20 13:10:54 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-20 13:10:54 -0700
commit888679027c2e9b43d1485d970df8170ac4fda29f (patch)
treef46c257e6be1f47f4aa69d31a64643c76457a64b
parent6d50d5b97d49a74a8faf587ec2bbf234626adf0c (diff)
Refactored interactivity to track with thread.
Hit a bit of a stopping point. Specifically, the way XAsync runs currently is by forking the execution context and having the child run the async code while the parent runs the remainder. The problem with this architecture is it doesn't interact well with job control. When we fork, we create a new process group. Thus the Xasync fork becomes the new leader. In short, our traversal of the parse tree as to be less "preorder" and more "in order", i.e. from the leaves up. The "left" command of the pipeline should be the "leader" of the process group.
-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;