aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-19 09:35:59 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-19 09:35:59 -0700
commit47e3d475df6244a48b73421cd4210b64c392df8d (patch)
tree5b4459341a6c6a7211749796367f536a09f1faa1
parentead340a66039096c7b4bf12dcd65e189769c6653 (diff)
feat(rc): cleaner process watching for each job
-rw-r--r--sys/cmd/rc/code.c4
-rw-r--r--sys/cmd/rc/exec.c188
-rw-r--r--sys/cmd/rc/input.c10
-rw-r--r--sys/cmd/rc/job.c82
-rw-r--r--sys/cmd/rc/lex.c17
-rw-r--r--sys/cmd/rc/main.c7
-rw-r--r--sys/cmd/rc/parse.c529
-rw-r--r--sys/cmd/rc/parse.h2
-rw-r--r--sys/cmd/rc/prompt.c4
-rw-r--r--sys/cmd/rc/rc.h36
-rw-r--r--sys/cmd/rc/syntax.y5
-rw-r--r--sys/cmd/rc/var.c12
-rw-r--r--sys/cmd/rc/wait.c94
13 files changed, 725 insertions, 265 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index 8dec021..d4dd6e1 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -50,7 +50,7 @@ walk(Tree *node)
switch(node->type){
default:
- print(errio, "bad type %d in interpreter walk\n", node->type);
+ print(shell.err, "bad type %d in interpreter walk\n", node->type);
break;
case '$':
@@ -152,7 +152,7 @@ copycode(Code *c)
int
compile(Tree *node)
{
- flush(errio);
+ flush(shell.err);
//print(errio, "%t\n", node);
interpreter.i = 0;
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index 80cd645..d78cb5d 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -31,10 +31,10 @@ static
void
pushword(char *str)
{
- if(!proc->args)
+ if(!runner->args)
fatal("attempt to push on empty argument stack\n");
- proc->args->word = makeword(str, proc->args->word);
+ runner->args->word = makeword(str, runner->args->word);
}
static
@@ -42,14 +42,14 @@ void
popword(void)
{
Word *w;
- if(!proc->args)
+ if(!runner->args)
fatal("tried to pop word on empty argument stack\n");
- w = proc->args->word;
+ w = runner->args->word;
if(!w)
fatal("tried to pop word but nothing there\n");
- proc->args->word = w->link;
+ runner->args->word = w->link;
efree(w->str);
efree(w);
}
@@ -101,21 +101,21 @@ pushlist(void)
List *stack = emalloc(sizeof(*stack));
stack->word = nil;
- stack->link = proc->args;
+ stack->link = runner->args;
- proc->args = stack;
+ runner->args = stack;
}
static
void
poplist(void)
{
- List *stack = proc->args;
+ List *stack = runner->args;
if(!stack)
fatal("attempted to pop an empty argument stack\n");
freelist(stack->word);
- proc->args = stack->link;
+ runner->args = stack->link;
efree(stack);
}
@@ -140,12 +140,12 @@ void
xx(void)
{
popword(); // "exec"
- if(!proc->args->word){
+ if(!runner->args->word){
Xerror("empty argument list");
return;
}
- execute(proc->args->word, path(proc->args->word->str));
+ execute(runner->args->word, path(runner->args->word->str));
poplist();
}
@@ -160,15 +160,15 @@ xforkx(void)
case -1:
return -1;
case 0: // child
- clearwait(proc);
+ clearwait(runner);
if(shell.interactive){
- proc->pid = getpid();
- if(proc->pgid <= 0)
- proc->pgid = proc->pid;
+ runner->pid = getpid();
+ if(runner->pgid <= 0)
+ runner->pgid = runner->pid;
- setpgid(pid, proc->pgid);
- tcsetpgrp(0, proc->pgid);
+ setpgid(pid, runner->pgid);
+ tcsetpgrp(0, runner->pgid);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
@@ -181,16 +181,16 @@ xforkx(void)
pushword("exec");
xx();
- exit(1); // NOTE: xx does not return!
+ exit(2); // NOTE: xx does not return!
/*unreachable*/
default: // parent
- addwait(proc, pid);
+ addwait(runner, pid);
/* ensure the state matches for parent and child */
- proc->pid = pid;
- if(proc->pgid <= 0)
- proc->pgid = pid;
- setpgid(pid, proc->pgid);
+ runner->pid = pid;
+ if(runner->pgid <= 0)
+ runner->pgid = pid;
+ setpgid(pid, runner->pgid);
return pid;
}
@@ -205,9 +205,9 @@ pushredir(int type, int from, int to)
r->type = type;
r->from = from;
r->to = to;
- r->link = proc->redir;
+ r->link = runner->redir;
- proc->redir = r;
+ runner->redir = r;
}
/* byte code */
@@ -219,17 +219,30 @@ run(Code *c, int pc, Var *local)
new->code.i = pc;
new->code.exe = copycode(c);
- new->args = nil;
- new->local = local;
+
new->cmd.path = nil;
new->cmd.io = nil;
+
+ new->args = nil;
+ new->local = local;
+ new->redir = nil;
+
+ new->flag.i = 0;
new->flag.eof = 0;
- new->line = 1;
- new->link = proc;
+ new->wait.status = 0;
+ new->wait.len = 0;
+ new->wait.cap = 0;
+ new->wait.on = nil;
+
+ new->status = 0;
new->pgid = new->pid = -1;
- proc = new;
+ new->line = 0;
+ new->link = runner;
+ new->next = nil;
+
+ runner = new;
}
// -----------------------------------------------------------------------
@@ -307,12 +320,12 @@ xdot(void)
}
#endif
/* get input file */
- if(!proc->args->word){
+ if(!runner->args->word){
Xerror("usage: . [-i] file [arg ...]\n");
return;
}
- base = strdup(proc->args->word->str);
+ base = strdup(runner->args->word->str);
popword();
for(fd=-1, p=path(base); p; p = p->link){
strcpy(file, p->str);
@@ -326,23 +339,23 @@ xdot(void)
}
if(fd<0){
- print(errio, "%s: ", base);
+ print(shell.err, "%s: ", base);
//setstatus("can't open");
Xerror(".: can't open\n");
return;
}
/* set up for a new command loop */
- old = proc; // store pointer to old code
+ old = runner; // store pointer to old code
run(dotcmd, 1, nil);
/* operations on new command stack */
pushredir(Rclose, fd, 0);
- proc->cmd.path = base;
- proc->cmd.io = openfd(fd);
+ runner->cmd.path = base;
+ runner->cmd.io = openfd(fd);
/* push $* value */
pushlist();
- proc->args->word = old->args->word;
+ runner->args->word = old->args->word;
/* free caller's copy of $* */
argv = old->args;
@@ -361,7 +374,7 @@ xjob(void)
int i;
Thread *job;
- for(i = 0, job = shell.jobs; job; job = job->next)
+ for(i=0, job = shell.jobs; job; job = job->next, i++)
report(job,i);
poplist();
@@ -376,27 +389,23 @@ xfg(void)
popword(); // fg
/* get input job id */
- if(!proc->args->word){
- print(errio, "usage: fg [pid|\%num]\n");
+ if(!runner->args->word){
+ print(shell.err, "usage: fg [pid|\%num]\n");
poplist();
return;
}
- i = atoi(proc->args->word->str);
+ i = atoi(runner->args->word->str);
popword(); // [jobid]
for(job=shell.jobs; i > 0; job=job->next, --i)
;
- assert(!job->flag.done);
-
- addwait(job, job->pid);
- job->flag.stop = 0;
poplist(); // this goes here?
- job->link = proc, proc = job; // XXX: can this leave orphans?
+ wakeup(job);
+ job->link = runner, runner = job; // XXX: can this leave zombies?
foreground(job, 1);
- printf("hi\n");
}
void
@@ -434,8 +443,8 @@ xboot(int argc, char *argv[])
/* main interpreter loop */
for(;;){
- proc->code.i++;
- (*proc->code.exe[proc->code.i-1].f)();
+ runner->code.i++;
+ (*runner->code.exe[runner->code.i-1].f)();
}
}
@@ -451,52 +460,55 @@ Xmark(void)
void
Xerror(char *msg)
{
- print(errio, "rc: %s", msg);
- flush(errio);
- while(!proc->flag.i)
+ print(shell.err, "rc: %s", msg);
+ flush(shell.err);
+ while(!runner->flag.i)
Xreturn();
}
void
Xreturn(void)
{
- Thread *run = proc;
+ 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!
*/
- if(run->flag.stop){
+ case PStop:
run->code.i--;
- proc = run->link;
+ runner = run->link;
return;
- }
-
/*
* If our job has finished:
* 1. remove from our list
- * 2. clean up its memory!
+ * 2. continue to clean up its memory
*/
- if(run->flag.done)
+ case PDone:
deljob(run);
+ /* fallthrough */
+ default:
+ ;
+ }
while(run->args)
poplist();
freecode(run->code.exe);
- efree(run->wait.pid);
+ efree(run->wait.on);
- proc = run->link;
+ runner = run->link;
efree(run);
- if(!proc)
+ if(!runner)
exit(0);
}
void
Xword(void)
{
- pushword(proc->code.exe[proc->code.i++].s);
+ pushword(runner->code.exe[runner->code.i++].s);
}
void
@@ -506,18 +518,18 @@ Xdollar(void)
char *s, *t;
Word *a, *star;
- if(count(proc->args->word)!=1){
+ if(count(runner->args->word)!=1){
Xerror("variable name not singleton!\n");
return;
}
- s = proc->args->word->str;
+ s = runner->args->word->str;
// deglob(s);
n = 0;
for(t = s;'0'<=*t && *t<='9';t++)
n = n*10+*t-'0';
- a = proc->args->link->word;
+ a = runner->args->link->word;
if(n==0 || *t)
a = copywords(var(s)->val, a);
@@ -532,7 +544,7 @@ Xdollar(void)
}
poplist();
- proc->args->word = a;
+ runner->args->word = a;
}
void
@@ -540,22 +552,22 @@ Xassign(void)
{
Var *v;
- if(count(proc->args->word)!=1){
+ if(count(runner->args->word)!=1){
Xerror("variable name not singleton!\n");
return;
}
//deglob(runq->argv->words->word);
- v = var(proc->args->word->str);
+ v = var(runner->args->word->str);
poplist();
//globlist();
freewords(v->val);
- v->val = proc->args->word;
+ v->val = runner->args->word;
v->new = 1;
if(v->update)
v->update(v);
- proc->args->word = nil;
+ runner->args->word = nil;
poplist();
}
@@ -566,8 +578,8 @@ Xreadcmd(void)
Thread *root;
Word *prompt;
- flush(errio);
- root = proc;
+ flush(shell.err);
+ root = runner;
if(yyparse()){
exit(1);
@@ -576,22 +588,22 @@ Xreadcmd(void)
run(compiled, 1, root->local);
}
- // killzombies();
+ killzombies();
freeparsetree();
}
void
Xlocal(void)
{
- if(count(proc->args->word)!=1){
+ if(count(runner->args->word)!=1){
Xerror("variable name must be singleton\n");
return;
}
//deglob(shell->args->word->str);
- proc->local = makevar(strdup(proc->args->word->str), proc->local);
- proc->local->val = copywords(proc->args->link->word, nil);
- proc->local->new = 1;
+ runner->local = makevar(strdup(runner->args->word->str), runner->local);
+ runner->local->val = copywords(runner->args->link->word, nil);
+ runner->local->new = 1;
poplist();
poplist();
@@ -600,13 +612,11 @@ Xlocal(void)
void
Xunlocal(void)
{
- Var *v = proc->local, *hide;
+ Var *v = runner->local, *hide;
if(!v)
fatal("Xunlocal: no locals!\n", 0);
- printf("unlocal\n");
-
- proc->local = v->link;
+ runner->local = v->link;
hide = var(v->name);
hide->new = 1;
@@ -623,19 +633,18 @@ Xbasic(void)
int pid, status;
struct Builtin *b;
- arg = proc->args->word;
+ arg = runner->args->word;
if(!arg){
Xerror("empty argument list\n");
return;
}
- /* print(errio, "recieved arg: %v\n", arg); // for debugging */
- flush(errio);
+ flush(shell.err);
v = var(arg->str);
if(v->func){
- // xfunc(v);
return;
}
+
// see if it matches a builtin
for(b = builtin; b->name; b++){
if(strcmp(b->name, arg->str)==0){
@@ -645,8 +654,7 @@ Xbasic(void)
}
/* if we are here then it's an external command */
- killzombies();
- addjob(proc);
+ addjob(runner);
// run the external command
if((pid = xforkx()) < 0) {
@@ -657,9 +665,9 @@ Xbasic(void)
poplist();
if(!shell.interactive)
- waitall(proc);
+ waitall(runner);
- foreground(proc, 0); // waits for child
+ foreground(runner, 0); // waits for child
}
void
diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c
index 4c6b37f..228b2d8 100644
--- a/sys/cmd/rc/input.c
+++ b/sys/cmd/rc/input.c
@@ -995,7 +995,7 @@ notty(void)
for(;;){
c = fgetc(stdin);
- put(&proc->cmd.io, c);
+ put(&runner->cmd.io, c);
}
}
@@ -1019,17 +1019,17 @@ readline(char *prompt)
int n;
// reset the command buffer
- proc->cmd.io->e = proc->cmd.io->b = proc->cmd.io->buf;
+ runner->cmd.io->e = runner->cmd.io->b = runner->cmd.io->buf;
if(!shell.interactive)
return notty();
- if((n = raw(proc->cmd.io->e, proc->cmd.io->cap-1, prompt)) == -1)
+ if((n = raw(runner->cmd.io->e, runner->cmd.io->cap-1, prompt)) == -1)
return 0;
- proc->cmd.io->e += n;
+ runner->cmd.io->e += n;
/* insert a newline character at the end */
- put(&proc->cmd.io, '\n');
+ put(&runner->cmd.io, '\n');
printf("\n");
return 1;
diff --git a/sys/cmd/rc/job.c b/sys/cmd/rc/job.c
new file mode 100644
index 0000000..779ce6c
--- /dev/null
+++ b/sys/cmd/rc/job.c
@@ -0,0 +1,82 @@
+#include "rc.h"
+
+#include <signal.h>
+#include <termios.h>
+
+// -----------------------------------------------------------------------
+// exports
+
+Thread *
+getjob(int pid, int *index)
+{
+ int i;
+ Thread *job;
+ for(i=0,job=shell.jobs; job && job->pid != pid; i++, job=job->next)
+ ;
+
+ return job;
+}
+
+void
+report(Thread *job, int index)
+{
+ switch(job->wait.status){
+ case PDone:
+ print(shell.err, "job %d [%d]: done\n", index, job->pid);
+ break;
+ case PStop:
+ print(shell.err, "job %d [%d]: suspended\n", index, job->pid);
+ break;
+ case PAgain:
+ print(shell.err, "job %d [%d]: continued\n", index, job->pid);
+ break;
+ case PRun:
+ print(shell.err, "job %d [%d]: running\n", index, job->pid);
+ break;
+ default:
+ fatal("bad wait status: %d\n", job->wait.status);
+ }
+}
+
+void
+wakeup(Thread *t)
+{
+ 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;
+ }
+}
+
+void
+foreground(Thread *job, int signal)
+{
+ tcsetpgrp(0, job->pgid);
+ if(signal){
+ if(kill(-job->pgid, SIGCONT) < 0)
+ perror("kill[SIGCONT]");
+ }
+
+ waitall(job);
+
+ tcsetpgrp(0, shell.pid);
+}
+
+void
+addjob(Thread *job)
+{
+ job->next = shell.jobs;
+ shell.jobs = job;
+}
+
+void
+deljob(Thread *job)
+{
+ Thread **jp;
+
+ for(jp = &shell.jobs; *jp && *jp != job; jp = &(*jp)->next)
+ ;
+
+ *jp = job->next;
+}
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index e7c7d7d..b4a2e8c 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -15,16 +15,17 @@ struct Lexer
static struct Lexer lexer = { .c={0, EOF}, .doprompt=1 };
void
-yyerror(char *msg)
+yyerror(const char *msg)
{
- print(errio, "\nrc: ");
+ print(shell.err, "\nrc:%d: ", runner->line);
if(lexer.buf[0] && lexer.buf[0]!='\n')
- print(errio, "@ %q: ", lexer.buf);
+ print(shell.err, "%q: ", lexer.buf);
- print(errio, "%s\n", msg);
- flush(errio);
+ print(shell.err, "%s\n", msg);
+ flush(shell.err);
+ /* consume remaining tokens */
while(lexer.c[0] !='\n' && lexer.c[0] != EOF)
advance();
}
@@ -40,18 +41,18 @@ readc(void)
peek = EOF;
return c;
}
- if(proc->flag.eof)
+ if(runner->flag.eof)
return EOF;
if(!prompt(&lexer.doprompt))
exit(1); // XXX: hack for signal handling right now...
- c = get(proc->cmd.io);
+ c = get(runner->cmd.io);
lexer.doprompt = lexer.doprompt || c=='\n' || c==EOF;
if(c==EOF)
- proc->flag.eof = 1;
+ runner->flag.eof = 1;
return c;
}
diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c
index d1bbd06..557030a 100644
--- a/sys/cmd/rc/main.c
+++ b/sys/cmd/rc/main.c
@@ -8,9 +8,8 @@
// -----------------------------------------------------------------------
// globals
-Io *errio = nil;
-Thread *proc = nil;
-Shell shell = { 0 };
+Thread *runner = nil;
+Shell shell = { 0 };
// -----------------------------------------------------------------------
// functions
@@ -57,7 +56,7 @@ main(int argc, char *argv[])
Code bootstrap[32];
char num[12];
- errio = openfd(2);
+ shell.err = openfd(2);
initenv();
initpath();
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
index e2e4afa..42834ed 100644
--- a/sys/cmd/rc/parse.c
+++ b/sys/cmd/rc/parse.c
@@ -67,12 +67,12 @@
/* First part of user prologue. */
-#line 5 "sys/cmd/rc/syntax.y"
+#line 7 "sys/cmd/rc/syntax.y"
#include "rc.h"
int yylex(void);
- void yyerror(char *);
+ void yyerror(const char *);
#line 78 "sys/cmd/rc/parse.c"
@@ -133,14 +133,15 @@ enum yysymbol_kind_t
YYSYMBOL_cmds = 28, /* cmds */
YYSYMBOL_cmdsln = 29, /* cmdsln */
YYSYMBOL_ifbody = 30, /* ifbody */
- YYSYMBOL_cmd = 31, /* cmd */
- YYSYMBOL_basic = 32, /* basic */
- YYSYMBOL_atom = 33, /* atom */
- YYSYMBOL_word = 34, /* word */
- YYSYMBOL_executable = 35, /* executable */
- YYSYMBOL_nonkeyword = 36, /* nonkeyword */
- YYSYMBOL_keyword = 37, /* keyword */
- YYSYMBOL_nl = 38 /* nl */
+ YYSYMBOL_assign = 31, /* assign */
+ YYSYMBOL_cmd = 32, /* cmd */
+ YYSYMBOL_basic = 33, /* basic */
+ YYSYMBOL_atom = 34, /* atom */
+ YYSYMBOL_word = 35, /* word */
+ YYSYMBOL_executable = 36, /* executable */
+ YYSYMBOL_nonkeyword = 37, /* nonkeyword */
+ YYSYMBOL_keyword = 38, /* keyword */
+ YYSYMBOL_nl = 39 /* nl */
};
typedef enum yysymbol_kind_t yysymbol_kind_t;
@@ -338,7 +339,7 @@ typedef int yy_state_fast_t;
#define YY_ASSERT(E) ((void) (0 && (E)))
-#if !defined yyoverflow
+#if 1
/* The parser invokes alloca or malloc; define the necessary symbols. */
@@ -403,7 +404,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# endif
-#endif /* !defined yyoverflow */
+#endif /* 1 */
#if (! defined yyoverflow \
&& (! defined __cplusplus \
@@ -466,18 +467,18 @@ union yyalloc
#endif /* !YYCOPY_NEEDED */
/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 24
+#define YYFINAL 25
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 49
+#define YYLAST 53
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 22
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 17
+#define YYNNTS 18
/* YYNRULES -- Number of rules. */
-#define YYNRULES 33
+#define YYNRULES 35
/* YYNSTATES -- Number of states. */
-#define YYNSTATES 48
+#define YYNSTATES 52
/* YYMAXUTOK -- Last valid token kind. */
#define YYMAXUTOK 266
@@ -527,17 +528,17 @@ static const yytype_int8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_int8 yyrline[] =
{
- 0, 34, 34, 35, 38, 39, 42, 43, 46, 49,
- 52, 53, 56, 57, 60, 61, 67, 68, 69, 70,
- 73, 74, 83, 84, 87, 88, 91, 92, 95, 96,
- 99, 99, 101, 103
+ 0, 36, 36, 37, 40, 41, 44, 45, 48, 51,
+ 54, 55, 58, 59, 62, 63, 66, 69, 70, 71,
+ 72, 73, 76, 77, 86, 87, 90, 91, 94, 95,
+ 98, 99, 102, 102, 104, 106
};
#endif
/** Accessing symbol of state STATE. */
#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
-#if YYDEBUG || 0
+#if 1
/* The user-facing name of the symbol whose (internal) number is
YYSYMBOL. No bounds checking. */
static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
@@ -550,8 +551,8 @@ static const char *const yytname[] =
"Telse", "Tbang", "Targs", "Tbasic", "Tparen", "Tblock", "Twhile",
"'\\n'", "'$'", "'('", "')'", "'{'", "'}'", "';'", "'&'", "'='", "'^'",
"$accept", "rc", "line", "body", "paren", "block", "cmds", "cmdsln",
- "ifbody", "cmd", "basic", "atom", "word", "executable", "nonkeyword",
- "keyword", "nl", YY_NULLPTR
+ "ifbody", "assign", "cmd", "basic", "atom", "word", "executable",
+ "nonkeyword", "keyword", "nl", YY_NULLPTR
};
static const char *
@@ -561,7 +562,7 @@ yysymbol_name (yysymbol_kind_t yysymbol)
}
#endif
-#define YYPACT_NINF (-10)
+#define YYPACT_NINF (-14)
#define yypact_value_is_default(Yyn) \
((Yyn) == YYPACT_NINF)
@@ -575,11 +576,12 @@ yysymbol_name (yysymbol_kind_t yysymbol)
STATE-NUM. */
static const yytype_int8 yypact[] =
{
- 3, -10, -2, 21, 7, 15, 9, -10, 7, 22,
- 21, 10, -10, 7, -10, -10, -10, -10, -10, -10,
- 18, -10, 7, 20, -10, -10, -10, -10, -10, -10,
- 23, 21, 27, 1, -10, -10, -10, 21, -10, -10,
- -10, 38, -10, -10, -10, -10, 1, -10
+ 3, -14, -13, 24, 10, 5, 19, -14, 10, 10,
+ 28, 24, -3, -14, 10, -14, -14, -14, -14, -14,
+ -14, -2, -14, 10, 26, -14, -14, -14, -14, -14,
+ -14, -14, 21, 24, 24, 25, 8, -14, -14, -14,
+ 24, 21, -14, -14, -14, 38, -14, -14, -14, -14,
+ 8, -14
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -587,25 +589,26 @@ static const yytype_int8 yypact[] =
means the default is an error. */
static const yytype_int8 yydefact[] =
{
- 16, 28, 0, 0, 16, 0, 0, 18, 16, 4,
- 17, 20, 26, 16, 32, 30, 31, 29, 22, 23,
- 0, 12, 16, 6, 1, 3, 5, 10, 11, 24,
- 21, 0, 0, 16, 9, 7, 13, 0, 27, 8,
- 33, 18, 19, 14, 25, 32, 16, 15
+ 17, 30, 0, 0, 17, 0, 0, 19, 17, 17,
+ 4, 18, 22, 28, 17, 34, 32, 33, 31, 24,
+ 25, 0, 12, 17, 6, 1, 3, 5, 20, 10,
+ 11, 26, 23, 0, 0, 0, 17, 9, 7, 13,
+ 0, 16, 29, 8, 35, 19, 21, 14, 27, 34,
+ 17, 15
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
- -10, -10, 37, 5, -10, 14, 29, -10, -10, 0,
- -10, -9, -10, -10, -1, -10, 4
+ -14, -14, 40, 11, -14, 13, 22, -14, -14, -14,
+ 0, -14, 1, 18, -14, -1, -14, 4
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
- 0, 5, 6, 20, 14, 7, 21, 22, 42, 23,
- 10, 17, 30, 11, 12, 19, 33
+ 0, 5, 6, 21, 15, 7, 22, 23, 46, 9,
+ 24, 11, 31, 32, 12, 13, 20, 36
};
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
@@ -613,20 +616,22 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int8 yytable[] =
{
- 9, 29, 18, -2, 1, 2, 1, 2, 9, 18,
- 1, 2, 13, 40, 3, 24, 3, 4, 32, 4,
- 3, 25, 38, 4, 1, 15, 16, 35, 44, 8,
- 18, 31, 36, 43, 3, 34, 18, 8, 27, 28,
- 27, 28, 39, 45, 37, 26, 47, 41, 0, 46
+ 10, 14, 19, -2, 18, 25, 1, 2, 10, 28,
+ 19, 1, 2, 1, 2, 37, 3, 33, 34, 4,
+ 44, 3, 8, 3, 4, 35, 4, 1, 16, 17,
+ 8, 26, 19, 19, 38, 42, 47, 3, 39, 19,
+ 43, 48, 40, 49, 29, 30, 29, 30, 27, 45,
+ 51, 41, 0, 50
};
static const yytype_int8 yycheck[] =
{
- 0, 10, 3, 0, 3, 4, 3, 4, 8, 10,
- 3, 4, 14, 12, 13, 0, 13, 16, 13, 16,
- 13, 12, 31, 16, 3, 4, 5, 22, 37, 0,
- 31, 21, 12, 33, 13, 17, 37, 8, 18, 19,
- 18, 19, 15, 5, 21, 8, 46, 33, -1, 45
+ 0, 14, 3, 0, 3, 0, 3, 4, 8, 9,
+ 11, 3, 4, 3, 4, 17, 13, 20, 21, 16,
+ 12, 13, 0, 13, 16, 14, 16, 3, 4, 5,
+ 8, 12, 33, 34, 23, 34, 36, 13, 12, 40,
+ 15, 40, 21, 5, 18, 19, 18, 19, 8, 36,
+ 50, 33, -1, 49
};
/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
@@ -634,28 +639,29 @@ static const yytype_int8 yycheck[] =
static const yytype_int8 yystos[] =
{
0, 3, 4, 13, 16, 23, 24, 27, 28, 31,
- 32, 35, 36, 14, 26, 4, 5, 33, 36, 37,
- 25, 28, 29, 31, 0, 12, 24, 18, 19, 33,
- 34, 21, 25, 38, 17, 25, 12, 21, 33, 15,
- 12, 27, 30, 31, 33, 5, 38, 31
+ 32, 33, 36, 37, 14, 26, 4, 5, 34, 37,
+ 38, 25, 28, 29, 32, 0, 12, 24, 32, 18,
+ 19, 34, 35, 20, 21, 25, 39, 17, 25, 12,
+ 21, 35, 34, 15, 12, 27, 30, 32, 34, 5,
+ 39, 32
};
/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */
static const yytype_int8 yyr1[] =
{
0, 22, 23, 23, 24, 24, 25, 25, 26, 27,
- 28, 28, 29, 29, 30, 30, 31, 31, 31, 31,
+ 28, 28, 29, 29, 30, 30, 31, 32, 32, 32,
32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
- 37, 37, 38, 38
+ 37, 37, 38, 38, 39, 39
};
/* 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, 0, 1, 1, 4,
- 1, 2, 1, 1, 1, 3, 1, 3, 1, 2,
- 1, 1, 0, 2
+ 2, 2, 1, 2, 1, 4, 3, 0, 1, 1,
+ 2, 4, 1, 2, 1, 1, 1, 3, 1, 3,
+ 1, 2, 1, 1, 0, 2
};
@@ -838,8 +844,275 @@ int yydebug;
#endif
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
/*-----------------------------------------------.
@@ -908,7 +1181,10 @@ yyparse (void)
action routines. */
YYSTYPE yyval;
-
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
@@ -1119,109 +1395,121 @@ yyreduce:
switch (yyn)
{
case 2: /* rc: %empty */
-#line 34 "sys/cmd/rc/syntax.y"
+#line 36 "sys/cmd/rc/syntax.y"
{ return 0; }
-#line 1125 "sys/cmd/rc/parse.c"
+#line 1401 "sys/cmd/rc/parse.c"
break;
case 3: /* rc: line '\n' */
-#line 35 "sys/cmd/rc/syntax.y"
+#line 37 "sys/cmd/rc/syntax.y"
{ return compile((yyvsp[-1].tree)); }
-#line 1131 "sys/cmd/rc/parse.c"
+#line 1407 "sys/cmd/rc/parse.c"
break;
case 5: /* line: cmds line */
-#line 39 "sys/cmd/rc/syntax.y"
+#line 41 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); }
-#line 1137 "sys/cmd/rc/parse.c"
+#line 1413 "sys/cmd/rc/parse.c"
break;
case 7: /* body: cmdsln body */
-#line 43 "sys/cmd/rc/syntax.y"
+#line 45 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); }
-#line 1143 "sys/cmd/rc/parse.c"
+#line 1419 "sys/cmd/rc/parse.c"
break;
case 8: /* paren: '(' body ')' */
-#line 46 "sys/cmd/rc/syntax.y"
+#line 48 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tparen, (yyvsp[-1].tree)); }
-#line 1149 "sys/cmd/rc/parse.c"
+#line 1425 "sys/cmd/rc/parse.c"
break;
case 9: /* block: '{' body '}' */
-#line 49 "sys/cmd/rc/syntax.y"
+#line 51 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tblock, (yyvsp[-1].tree)); }
-#line 1155 "sys/cmd/rc/parse.c"
+#line 1431 "sys/cmd/rc/parse.c"
break;
case 11: /* cmds: cmd '&' */
-#line 53 "sys/cmd/rc/syntax.y"
+#line 55 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1('&', (yyvsp[-1].tree)); }
-#line 1161 "sys/cmd/rc/parse.c"
+#line 1437 "sys/cmd/rc/parse.c"
break;
case 14: /* ifbody: cmd */
-#line 60 "sys/cmd/rc/syntax.y"
+#line 62 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(Tif, nil, (yyvsp[0].tree)); }
-#line 1167 "sys/cmd/rc/parse.c"
+#line 1443 "sys/cmd/rc/parse.c"
break;
case 15: /* ifbody: block Telse nl cmd */
-#line 61 "sys/cmd/rc/syntax.y"
+#line 63 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree3(Tif, nil, (yyvsp[-3].tree), (yyvsp[-2].tree)); }
-#line 1173 "sys/cmd/rc/parse.c"
+#line 1449 "sys/cmd/rc/parse.c"
+ break;
+
+ case 16: /* assign: executable '=' word */
+#line 66 "sys/cmd/rc/syntax.y"
+ { (yyval.tree) = maketree2('=', (yyvsp[-2].tree), (yyvsp[0].tree)); }
+#line 1455 "sys/cmd/rc/parse.c"
break;
- case 16: /* cmd: %empty */
-#line 67 "sys/cmd/rc/syntax.y"
+ case 17: /* cmd: %empty */
+#line 69 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = nil; }
-#line 1179 "sys/cmd/rc/parse.c"
+#line 1461 "sys/cmd/rc/parse.c"
break;
- case 17: /* cmd: basic */
-#line 68 "sys/cmd/rc/syntax.y"
+ case 18: /* cmd: basic */
+#line 70 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tbasic, (yyvsp[0].tree)); }
-#line 1185 "sys/cmd/rc/parse.c"
+#line 1467 "sys/cmd/rc/parse.c"
break;
- case 19: /* cmd: Tif paren nl ifbody */
-#line 70 "sys/cmd/rc/syntax.y"
+ case 20: /* cmd: assign cmd */
+#line 72 "sys/cmd/rc/syntax.y"
+ { (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 2); }
+#line 1473 "sys/cmd/rc/parse.c"
+ break;
+
+ case 21: /* cmd: Tif paren nl ifbody */
+#line 73 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = hangchild1((yyvsp[-2].tree), (yyvsp[-3].tree), 0); }
-#line 1191 "sys/cmd/rc/parse.c"
+#line 1479 "sys/cmd/rc/parse.c"
break;
- case 21: /* basic: basic word */
-#line 74 "sys/cmd/rc/syntax.y"
+ case 23: /* basic: basic word */
+#line 77 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); }
-#line 1197 "sys/cmd/rc/parse.c"
+#line 1485 "sys/cmd/rc/parse.c"
break;
- case 23: /* atom: keyword */
-#line 84 "sys/cmd/rc/syntax.y"
+ case 25: /* atom: keyword */
+#line 87 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1(Tword, (yyvsp[0].tree)); }
-#line 1203 "sys/cmd/rc/parse.c"
+#line 1491 "sys/cmd/rc/parse.c"
break;
- case 25: /* word: word '^' atom */
-#line 88 "sys/cmd/rc/syntax.y"
+ case 27: /* word: word '^' atom */
+#line 91 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
-#line 1209 "sys/cmd/rc/parse.c"
+#line 1497 "sys/cmd/rc/parse.c"
break;
- case 27: /* executable: executable '^' atom */
-#line 92 "sys/cmd/rc/syntax.y"
+ case 29: /* executable: executable '^' atom */
+#line 95 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); }
-#line 1215 "sys/cmd/rc/parse.c"
+#line 1503 "sys/cmd/rc/parse.c"
break;
- case 29: /* nonkeyword: '$' atom */
-#line 96 "sys/cmd/rc/syntax.y"
+ case 31: /* nonkeyword: '$' atom */
+#line 99 "sys/cmd/rc/syntax.y"
{ (yyval.tree) = maketree1('$', (yyvsp[0].tree)); }
-#line 1221 "sys/cmd/rc/parse.c"
+#line 1509 "sys/cmd/rc/parse.c"
break;
-#line 1225 "sys/cmd/rc/parse.c"
+#line 1513 "sys/cmd/rc/parse.c"
default: break;
}
@@ -1268,7 +1556,37 @@ yyerrlab:
if (!yyerrstatus)
{
++yynerrs;
- yyerror (YY_("syntax error"));
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ YYNOMEM;
+ }
}
if (yyerrstatus == 3)
@@ -1410,9 +1728,10 @@ yyreturnlab:
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
-
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
return yyresult;
}
-#line 104 "sys/cmd/rc/syntax.y"
+#line 107 "sys/cmd/rc/syntax.y"
diff --git a/sys/cmd/rc/parse.h b/sys/cmd/rc/parse.h
index 5328340..8fc661f 100644
--- a/sys/cmd/rc/parse.h
+++ b/sys/cmd/rc/parse.h
@@ -85,7 +85,7 @@ extern int yydebug;
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
-#line 20 "sys/cmd/rc/syntax.y"
+#line 22 "sys/cmd/rc/syntax.y"
struct Tree *tree;
diff --git a/sys/cmd/rc/prompt.c b/sys/cmd/rc/prompt.c
index 21078e8..94022ca 100644
--- a/sys/cmd/rc/prompt.c
+++ b/sys/cmd/rc/prompt.c
@@ -6,11 +6,11 @@ prompt(ushort *flag)
int f = *flag;
if(f){
if(!readline("> ")){
- proc->flag.eof = 1;
+ runner->flag.eof = 1;
return 0;
}
- proc->line++;
+ runner->line++;
*flag = 0;
}
return 1;
diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h
index 9c6307f..ef7c18e 100644
--- a/sys/cmd/rc/rc.h
+++ b/sys/cmd/rc/rc.h
@@ -93,6 +93,22 @@ struct Redir
struct Redir *link; /* what else to do (reverse order) */
};
+enum
+{
+ PNil,
+ PRun,
+ PStop,
+ PSig,
+ PAgain,
+ PDone,
+};
+
+struct WaitItem
+{
+ int pid;
+ ushort status;
+};
+
struct Thread
{
struct {
@@ -109,21 +125,19 @@ struct Thread
Redir *redir; // list of redirections
struct {
- ushort i : 1;
- ushort eof : 1;
- ushort stop : 1;
- ushort done : 1;
- ushort again : 1;
- } flag; // flags for process
+ ushort i : 1;
+ ushort eof : 1;
+ } flag;
struct {
- int len, cap, *pid;
+ ushort status;
+ int len, cap;
+ struct WaitItem *on;
} wait;
int pid, pgid, status;
long line;
- Tree *nodes; // memory allocation
Thread *link; // process we return to
Thread *next; // next job
};
@@ -131,6 +145,7 @@ struct Thread
struct Shell
{
int pid;
+ Io *err;
int status;
int interactive;
Thread *jobs;
@@ -140,9 +155,7 @@ struct Shell
// globals
extern Shell shell;
-
-extern Thread *proc;
-extern Io *errio;
+extern Thread *runner;
extern Code *compiled;
// -----------------------------------------------------------------------
@@ -203,6 +216,7 @@ void killzombies(void);
Thread *getjob(int, int*);
void addjob(Thread *);
void deljob(Thread *);
+void wakeup(Thread *);
void report(Thread *, int);
void foreground(Thread *, int);
diff --git a/sys/cmd/rc/syntax.y b/sys/cmd/rc/syntax.y
index 247cc8a..a580cb0 100644
--- a/sys/cmd/rc/syntax.y
+++ b/sys/cmd/rc/syntax.y
@@ -2,11 +2,13 @@
%token Targs
%token Tbasic Tparen Tblock
+%define parse.error verbose
+
%{
#include "rc.h"
int yylex(void);
- void yyerror(char *);
+ void yyerror(const char *);
%}
/* operator precendence: lowest first */
@@ -67,6 +69,7 @@ cmd:
/* empty */ %prec Twhile { $$ = nil; }
| basic { $$ = maketree1(Tbasic, $1); }
| block
+| assign cmd %prec Tbang { $$ = hangchild1($1, $2, 2); }
| Tif paren nl ifbody { $$ = hangchild1($2, $1, 0); }
basic:
diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c
index 7b5d75a..5e1e90c 100644
--- a/sys/cmd/rc/var.c
+++ b/sys/cmd/rc/var.c
@@ -159,7 +159,7 @@ globalvar(char *name)
h = hash(name, arrlen(globals));
if(strcmp(name,"PATH")==0){
- flush(errio);
+ flush(shell.err);
}
for(v = globals[h]; v; v = v->link){
@@ -175,8 +175,8 @@ Var*
var(char *name)
{
Var *v;
- if(proc){
- for(v = proc->local; v; v=v->link)
+ if(runner){
+ for(v = runner->local; v; v=v->link)
if(strcmp(v->name, name) == 0)
return v;
}
@@ -206,7 +206,7 @@ mkenv(void)
nchr+=strlen(a->str)+1; \
}
- for(v= proc->local; v; v=v->link){
+ for(v= runner->local; v; v=v->link){
BODY
}
for(h=globals; h!=arrend(globals); h++){
@@ -238,7 +238,7 @@ mkenv(void)
*p++='\0'; \
}
- for(v=proc->local; v; v=v->link){
+ for(v=runner->local; v; v=v->link){
BODY
}
for(h=globals; h!=arrend(globals); h++){
@@ -265,7 +265,7 @@ initpath(void)
v = globalvar("PATH");
v->update = bigpath;
- flush(errio);
+ flush(shell.err);
bigpath(v);
}
diff --git a/sys/cmd/rc/wait.c b/sys/cmd/rc/wait.c
index db586cb..44ffb58 100644
--- a/sys/cmd/rc/wait.c
+++ b/sys/cmd/rc/wait.c
@@ -8,13 +8,11 @@
struct WaitMsg
{
int pid;
+ int type;
ulong time[3];
int status;
- int signal;
- int suspend;
};
-
// -----------------------------------------------------------------------
// internal
@@ -30,7 +28,7 @@ await(int pid4, int opt, struct WaitMsg *msg)
for(;;){
if((pid = wait4(pid4, &status, opt, &ru)) <= 0){
msg->pid = 0;
- perror("failed wait");
+ perror("failed wait4");
return 0;
}
@@ -43,8 +41,7 @@ await(int pid4, int opt, struct WaitMsg *msg)
msg->time[1] = s;
msg->time[2] = u+s;
msg->status = WEXITSTATUS(status);
- msg->signal = 0;
- msg->suspend = 0;
+ msg->type = PDone;
return 1;
}
@@ -55,8 +52,7 @@ await(int pid4, int opt, struct WaitMsg *msg)
msg->time[1] = s;
msg->time[2] = u+s;
msg->status = WCOREDUMP(status);
- msg->signal = 1;
- msg->suspend = 0;
+ msg->type = PSig;
return 1;
}
@@ -67,14 +63,27 @@ await(int pid4, int opt, struct WaitMsg *msg)
msg->time[1] = s;
msg->time[2] = u+s;
msg->status = WSTOPSIG(status);
- msg->signal = 0;
- msg->suspend = 1;
+ msg->type = PStop;
return 1;
}
}
}
+static
+int
+shouldwait(Thread *job)
+{
+ int i;
+
+ for(i=0; i<job->wait.len; i++){
+ if(job->wait.on[i].status == PRun)
+ return 1;
+ }
+
+ return 0;
+}
+
// -----------------------------------------------------------------------
// exported
@@ -90,7 +99,7 @@ havewait(Thread *job, int pid)
int i;
for(i=0; i<job->wait.len; i++)
- if(job->wait.pid[i] == pid)
+ if(job->wait.on[i].pid == pid)
return 1;
return 0;
}
@@ -100,9 +109,10 @@ addwait(Thread *job, int pid)
{
if(job->wait.len == job->wait.cap){
job->wait.cap = job->wait.cap + 2;
- job->wait.pid = erealloc(job->wait.pid, job->wait.cap*sizeof(*job->wait.pid));
+ job->wait.on = erealloc(job->wait.on, job->wait.cap*sizeof(*job->wait.on));
}
- job->wait.pid[job->wait.len++] = pid;
+
+ job->wait.on[job->wait.len++] = (struct WaitItem){.pid=pid, .status=PRun};
}
void
@@ -111,8 +121,8 @@ delwait(Thread *job, int pid)
int r, w;
for(r=w=0; r < job->wait.len; r++){
- if(job->wait.pid[r] != pid)
- job->wait.pid[w++] = job->wait.pid[r];
+ if(job->wait.on[r].pid != pid)
+ job->wait.on[w++].pid = job->wait.on[r].pid;
}
job->wait.len = w;
}
@@ -120,36 +130,63 @@ delwait(Thread *job, int pid)
int
waitall(Thread *job)
{
+ int i;
Thread *t;
struct WaitMsg msg;
- while(job->wait.len && await(-job->pgid, WUNTRACED, &msg)){
- if(msg.pid == 0 && errno == ECHILD){
+ while(shouldwait(job) && await(-job->pgid, WUNTRACED, &msg)){
+ if(msg.pid == 0){
perror("wait job");
return 0;
}
+ for(i=0; i < job->wait.len; i++){
+ if(job->wait.on[i].pid == msg.pid){
+ switch(msg.type){
+ case PStop:
+ print(shell.err, "%d: suspended\n", msg.pid);
+ job->wait.status = PStop;
+ job->wait.on[i].status = PStop;
+ break;
+
+ case PSig:
+ print(shell.err, "%d: terminated by signal %d\n", msg.pid, msg.status);
+ /* fallthrough */
+ case PDone:
+ job->wait.on[i].status = PDone;
+ delwait(job, msg.pid);
+ if(!job->wait.len)
+ job->wait.status = PDone;
+ break;
+
+ default:
+ fatal("%d: unrecognized message type %d\n", msg.pid, msg.type);
+ }
+ break;
+ }
+ }
+ }
+#if 0
for(t=job; t; t=t->link){
if(t->pid == msg.pid){
t->status = msg.status;
- t->flag.stop = t->flag.done = t->flag.again = 0;
if(msg.suspend){
t->flag.stop = 1;
}else{
t->flag.done = 1;
if(msg.signal){
- print(errio, "%d: terminated by signal %d\n", msg.pid, msg.status);
+ print(shell.err, "%d: terminated by signal %d\n", msg.pid, msg.status);
}
}
delwait(t, msg.pid);
goto outer;
}
}
-
perror("waitpid");
return 0;
outer:;
}
+#endif
return 1;
}
@@ -161,24 +198,21 @@ killzombies(void)
int index, status, pid;
while((pid=waitpid(-1, &status, WNOHANG))>0){
- print(errio, "pid %d\n", pid);
- flush(errio);
+ print(shell.err, "found zombie pid %d\n", pid);
+ flush(shell.err);
job = getjob(pid, &index);
- if(!job){
+ if(!job)
perror("invalid pid");
- }
-
- job->flag.done = job->flag.stop = job->flag.again = 0;
if(WIFEXITED(status))
- job->flag.done = 1;
+ job->wait.status = PDone;
if(WIFSTOPPED(status))
- job->flag.stop = 1;
+ job->wait.status = PStop;
if(WIFCONTINUED(status))
- job->flag.again = 1;
+ job->wait.status = PAgain;
- if(job->flag.done){
+ if(job->wait.status == PDone){
report(job,index);
deljob(job);
}