An example of creeping featurism
Packard
keith at reed.UUCP
Fri Nov 16 16:56:04 AEST 1984
I couldn't resist, a friend of mine needed a program to wait
for a specified process, berkeley kernels let you do this
by using kill, just kill a process with sig 0, it returns the
error status without actually doing anything. In any case,
as a first cut the program looked like:
#include <errno.h>
extern int errno;
main (argc, argv) char **argv;
{
register int pid;
pid = atoi (argv[1]);
while (kill (pid, 0) != -1 || errno != ESRCH)
sleep (1);
}
Just another example of a quick hack. Well, it got a bit out of
hand, the final version ended up a bit different (oh, I write
compilers for a living by the way):
keith packard
...!tektronix!reed!keith
or
...!tektronix!tekmdp!keithp
/*
* await.c
*
* wait for several processes to terminate
* accepts an expression using the following grammar:
*
* expr : expr -a expr wait for both expressions to become true
* | expr -o expr wait for either expression to become true
* | -n expr wait for expr to become false (why not?)
* | pid wait for process pid to exit
* | ( expr ) used for grouping
* ;
*
* optional characters:
*
* open close and {} are the same as ()
* not, ! or ~ are the same as -n
* and and && are the same as -a
* or and || are the same as -o
*
* example:
* wait either for process 2 and process 3 to terminate or
* for process 4 to terminate:
*
* await 2 and 3 or 4
*
* is this silly or what?
*/
# include <errno.h>
# include <stdio.h>
# define END 1
# define OR 2
# define AND 3
# define NOT 4
# define OP 5
# define CP 6
# define PID 7
extern errno;
struct expr {
struct expr *left;
struct expr *right;
int value;
int op;
};
struct expr *parse(),*e(), *e_e(), *t(), *e_t(), *f(), *allocExpr();
struct expr *expr;
main(argc,argv)
char **argv;
{
expr = parse(argv+1);
for (;;) {
if (test(expr))
exit (0);
sleep (1);
}
}
test (expr)
register struct expr *expr;
{
switch (expr->op) {
case PID:
if (expr->value == -1)
return 1;
if (kill (expr->value, 0) == -1) {
if (errno != ESRCH) {
char buf[14];
perror (itoa (expr->value, buf));
exit (1);
}
expr->value = -1;
return 1;
}
return 0;
case OR:
if (test (expr->left))
return 1;
else
return test (expr->right);
case AND:
if (!test (expr->left))
return 0;
else
return test (expr->right);
case NOT:
return test (expr->left) == 0;
}
}
int token, lvalue;
/*
* grammar
*
* p : e END
* e : t e_e
* e_e : OR e e_e
* | nil
* t : f e_t
* e_t : AND e_t
* | nil
* f : PID
* | NOT f
* | OP e CP
*
*/
struct expr *
parse (a)
char **a;
{
init (a);
token = lex();
return e();
}
struct expr *
e ()
{
register struct expr *et;
switch (token) {
case NOT:
case OP:
case PID:
et = t();
et = e_e(et);
break;
default:
error();
}
return et;
}
struct expr *
e_e (left)
struct expr *left;
{
register struct expr *et;
switch (token) {
case OR:
et = allocExpr ();
et->left = left;
et->op = OR;
token = lex();
et->right = e();
et = e_e(et);
break;
case CP:
case END:
et = left;
break;
default:
error ();
}
return et;
}
struct expr *
t()
{
register struct expr *et;
switch (token) {
case NOT:
case OP:
case PID:
et = f();
et = e_t(et);
break;
default:
error ();
}
return et;
}
struct expr *
e_t(left)
struct expr *left;
{
register struct expr *et;
switch (token) {
case AND:
et = allocExpr ();
et->op = AND;
et->left = left;
token = lex();
et->right = t();
et = e_t(et);
break;
case CP:
case OR:
case END:
et = left;
break;
default:
error ();
}
return et;
}
struct expr *
f()
{
register struct expr *et;
switch (token) {
case PID:
et = allocExpr ();
et->op = PID;
et->value = lvalue;
token = lex();
break;
case NOT:
et = allocExpr ();
et->op = NOT;
token = lex();
et->left = f();
break;
case OP:
token = lex();
et = e();
switch (token) {
case CP:
token = lex();
break;
default:
error ();
}
break;
default:
error ();
}
return et;
}
char **buf;
init(a)
char **a;
{
buf = a;
}
char *
getw ()
{
register char *c, *d;
do {
d = c = *buf;
if (!*buf)
return 0;
for (;;) {
if (!*c) {
++buf;
break;
} else if (*c == ' ' || *c == '\t') {
*c = '\0';
while (*++c == ' ' || *c == '\t')
;
*buf = c;
break;
}
++c;
}
} while (!*d);
return d;
}
struct token {
char *string;
int value;
} tokens [] = {
"or", OR,
"-o", OR,
"||", OR,
"and", AND,
"-a", AND,
"&&", AND,
"not", NOT,
"-n", NOT,
"!", NOT,
"~", NOT,
"open", OP,
"(", OP,
"{", OP,
"close",CP,
")", CP,
"}", CP,
0, 0,
};
lex ()
{
register int i;
register char *s;
register struct token *t;
for (;;) {
if (!(s = getw()))
return END;
for (t = tokens;t->string;++t) {
if (!strcmp (t->string, s))
return t->value;
}
if ('0' <= *s && *s <= '9') {
i = 0;
while ('0' <= *s && *s <= '9')
i = i * 10 + *s++ - '0';
if (!*s) {
lvalue = i;
return PID;
}
}
fprintf (stderr, "lex error on token: %s\n", s);
}
}
error ()
{
fprintf (stderr, "syntax error on %s\n", buf[-1]);
exit (-1);
}
struct expr *
allocExpr ()
{
char *malloc ();
return (struct expr *) malloc (sizeof (struct expr));
}
More information about the Comp.lang.c
mailing list