|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 39193 (0x9919)
Types: TextFile
Names: »dm.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/stat-5.3/eu/stat/src/dm.c«
# line 2 "dm.y"
/* Copyright 1980 Gary Perlman */
#include "stat.h"
PGM(dm,Data Manipulation,5.8,10/14/86)
#define DM_VERSION "5.8 10/14/86"
#ifndef MSDOS
# ifndef PTREE
# define PTREE
# endif PTREE
#endif MSDOS
/*
dm is a data manipulator designed to manipulate files of columns of number and
strings. The major components of this program are:
(1) a parser, built by yacc, called yyparse.
(2) a scanner, yylex, called by yyparse.
(3) a parse tree node function, called by yyparse.
(4) a function, eval, that evaluates the parse trees.
(5) a main that calls I/O routines and the control loop.
The following section is a bunch of global declarations that will be put
literally into the program, y.tab.c by yacc.
*/
#define MAXEXPR 100 /* maximum number of expressions */
#define MAXSTRING 32 /* maximum length of input string */
#define MAXCOL 100 /* maximum number of input columns */
#define MAXCONST 100 /* maximum number of constants */
#define FLOATPTR 0 /* codes for parse tree node types */
#define OPERATOR 1
#define STRINGOP 2
#define STRINGPTR 3
#define PARSERROR 1 /* returned by yyparse on error */
/*
The following few numbers are reserved by dm to signal special conditions by
being returned by various routines. They are hopefully numbers that no
expressions would ever evaluate to.
*/
#define LARGE 9999999999999.0 /* a large number */
#define SUPPRESS -1125899906842624. /* suppress output */
#define STRINGFLAG -8888888888888777.0 /* returned by eval */
#define NIL -998888677484837274. /* cause nil output */
#define EXITFLAG -99999999999999.9 /* cause exit */
char Outpipe = 0; /* true if output is piped */
FILE *Infile; /* data read from here */
char Inputline[BUFSIZ]; /* INPUT read into here */
FILE *Outfile; /* output from dm */
char *Evalstr[MAXCOL+1]; /* ptrs to strings from eval */
char Str[MAXCOL+1][MAXSTRING]; /* columns from each dataline */
char *Expra; /* ptr to each expression */
typedef union
{
int opr; /* if operator or stringop */
double *num; /* if FLOATPTR */
char *str; /* if STRINGOP */
} STUFF;
STUFF Tmp1, Tmp2; /* used in the parser to cast operators */
typedef struct enode /* expression node in tree */
{
int etype; /* type of node */
STUFF contents;
struct enode *lchild;
struct enode *rchild;
} ENODE;
#define ENULL ((ENODE *) NULL)
ENODE *Expr[MAXEXPR+1]; /* ptr to each parse tree */
double Input[MAXCOL+1]; /* input numbers */
#define INLINE (Input[0]) /* input line number stored here */
double Output[MAXEXPR+1]; /* output numbers */
#define OUTLINE (Output[0]) /* output line number stored here */
double Const[MAXCONST]; /* constants stored here */
int Nconst; /* number of constants */
double Nil = NIL; /* flagged by NIL */
double Suppress = SUPPRESS; /* flagged by KILL */
double Stringflag = STRINGFLAG; /* eval returns string */
double Exitflag = EXITFLAG; /* flagged by EXIT */
double Randu; /* uniform rand num */
extern double Maxrand; /* set by initrand */
int Seed; /* random seed sent to initrand */
Boole Userand; /* true if Randu is used */
double N; /* number of input cols */
double Sum; /* sum of input cols */
int Should_output[MAXEXPR+1]; /* used with X */
int Exprno; /* expression number */
int Nexpr; /* number of expressions */
# line 99 "dm.y"
typedef union { /* union of the data types the parser will deal with */
int opr;
char *str;
double *num;
ENODE *ex;
} YYSTYPE;
# define NUMBER 257
# define STRING 258
# define STRINDEX 259
# define IF 260
# define THEN 261
# define ELSE 262
# define NOR 263
# define NAND 264
# define EQ 265
# define NE 266
# define GE 267
# define GT 268
# define LE 269
# define LT 270
# define NOTIN 271
# define C 67
# define UMINUS 272
# define l 108
# define L 76
# define e 101
# define a 97
# define f 102
# define c 99
# define SQRT 273
# define SIN 274
# define COS 275
# define TAN 276
# define ATAN 277
# define ACOS 278
# define ASIN 279
# define NTYPE 280
#define yyclearin yychar = -1
#define yyerrok yyerrflag = 0
extern int yychar;
extern short yyerrflag;
#ifndef YYMAXDEPTH
#define YYMAXDEPTH 150
#endif
YYSTYPE yylval, yyval;
# define YYERRCODE 256
# line 409 "dm.y"
/*
Next is the scanner that will be repeatedly called by yyparse, yylex.
This simple program reads from a global char *Expra, set by main. Variables
are handled by returning NUMBER or STRING, tokens defined in above grammar.
*/
yylex ()
{
extern YYSTYPE yylval;
char *strsave ();
int column;
while (isspace (*Expra) || *Expra == '_')
Expra++;
if (isdigit (*Expra) || *Expra == '.')
{
if (Nconst == MAXCONST)
ERRMSG1 (Maximum number of constants is %d, MAXCONST)
Const[Nconst] = atof (Expra);
yylval.num = &Const[Nconst++];
Expra += skipnumber (Expra, 1);
return (NUMBER);
}
switch (*Expra)
{
case '"':
case '\'':
yylval.str = strsave ();
return (STRING);
case 'a':
if (begins ("atan", Expra))
{Expra += 4; return (ATAN);}
if (begins ("asin", Expra))
{Expra += 4; return (ASIN);}
if (begins ("acos", Expra))
{Expra += 4; return (ACOS);}
if (begins ("abs", Expra))
{Expra += 3; return ('a');}
if (begins ("and", Expra))
{Expra += 3; return ('&');}
break;
case 'A':
if (begins ("AND", Expra))
{ Expra += 3; return ('&'); }
break;
case 'c':
if (begins ("cos", Expra))
{Expra += 3; return (COS);}
if (begins ("ceil", Expra))
{Expra += 4; return ('c');}
break;
case 'f': if (begins ("floor", Expra))
{Expra += 5; return ('f');}
break;
case 'G':
if (begins ("GE", Expra))
{
Expra += 2;
return (GE);
}
if (begins ("GT", Expra))
{
Expra += 2;
return (GT);
}
break;
case 'e': if (begins ("else", Expra))
{Expra += 4; return (ELSE);}
else if (begins ("exp", Expra))
{Expra += 3; return ('e');}
break;
case 'E':
if (begins ("EQ", Expra))
{ Expra += 2; return (EQ); }
if (begins ("ELSE", Expra))
{ Expra += 4; return (ELSE); }
if (begins ("EXIT", Expra))
Expra += 4;
else Expra++;
yylval.num = &Exitflag;
return (NUMBER);
case 'i':
if (begins ("if", Expra))
{Expra += 2; return (IF);}
break;
case 'I':
if (begins ("IF", Expra))
{ Expra += 2; return (IF); }
if (begins ("INLINE", Expra))
{
Expra += 6;
yylval.num = &INLINE;
return (NUMBER);
}
if (begins ("INPUT", Expra))
Expra += 5;
else Expra++;
yylval.str = Inputline;
return (STRING);
case 'K':
if (begins ("KILL", Expra))
Expra += 4;
else Expra++;
yylval.num = &Suppress;
return (NUMBER);
case 'l':
if (begins ("log", Expra))
{Expra += 3; return ('l');}
if (begins ("len", Expra))
{Expra += 3; return ('#');}
break;
case 'L':
if (begins ("LE", Expra))
{ Expra += 2; return (LE); }
if (begins ("LT", Expra))
{ Expra += 2; return (LT); }
if (begins ("Log", Expra))
{Expra += 3; return ('L');}
break;
case 'n':
if (begins ("not", Expra))
{ Expra += 3; return ('!'); }
if (begins ("number", Expra))
{ Expra += 6; return (NTYPE); }
break;
case 'N':
if (begins ("NOT", Expra))
{ Expra += 3; return ('!'); }
if (begins ("NE", Expra) && !begins ("NEXT", Expra))
{ Expra += 2; return (NE); }
if (begins ("NIL", Expra))
{
Expra += 3;
yylval.num = &Nil;
}
else if (begins ("NEXT", Expra))
{
Expra += 4;
yylval.num = &Suppress;
}
else
{
Expra++;
yylval.num = &N;
}
return (NUMBER);
case 'o':
if (begins ("or", Expra))
{ Expra += 2; return ('|'); }
break;
case 'O':
if (begins ("OR", Expra))
{ Expra += 2; return ('|'); }
if (begins ("OUTLINE", Expra))
{
Expra += 7;
yylval.num = &OUTLINE;
return (NUMBER);
}
break;
case 'R':
if (begins ("RAND", Expra))
Expra += 4;
else
Expra++;
Userand = TRUE;
if (isdigit (*Expra))
{
Seed = atoi (Expra);
while (isdigit (*Expra))
Expra++;
}
yylval.num = &Randu;
return (NUMBER);
case 's':
if (begins ("sqrt", Expra))
{
Expra += 4;
return (SQRT);
}
if (begins ("sin", Expra))
{
Expra += 3;
return (SIN);
}
column = atoi (++Expra);
Expra += skipnumber (Expra, 0);
yylval.str = Str[column];
return (STRING);
case 'S':
if (begins ("SKIP", Expra))
{
Expra += 4;
yylval.num = &Suppress;
}
else
{
if (begins ("SUM", Expra))
Expra += 3;
else Expra++;
yylval.num = ∑
}
return (NUMBER);
case 't':
if (begins ("tan", Expra))
{Expra += 3; return (TAN);}
if (begins ("then", Expra))
{Expra += 4; return (THEN);}
break;
case 'T':
if (begins ("THEN", Expra))
{Expra += 4; return (THEN);}
break;
case 'x':
if (Expra[1] == '[')
{
Expra++;
return ('x');
}
column = atoi (++Expra);
Expra += skipnumber (Expra, 0);
yylval.num = &Input[column];
return (NUMBER);
case 'y':
if (Expra[1] == '[')
{
Expra++;
return ('y');
}
column = atoi (++Expra);
Expra += skipnumber (Expra, 0);
yylval.num = &Output[column];
return (NUMBER);
case '=': if (Expra[1] == '=') Expra += 2;
else Expra++;
return (EQ);
case '<': if (Expra[1] == '=')
{
Expra += 2;
return (LE);
}
Expra++;
return (LT);
case '>': if (Expra[1] == '=')
{
Expra += 2;
return (GE);
}
Expra++;
return (GT);
case '!': switch (Expra[1])
{
case '=': Expra += 2; return (NE);
case 'C': Expra += 2; return (NOTIN);
case '&': Expra += 2; return (NAND);
case '|': Expra += 2; return (NOR);
default: Expra++; return ('!');
}
case '&': if (Expra[1] == '&') Expra++; break;
case '|': if (Expra[1] == '|') Expra++; break;
}
return ((int) *Expra++);
}
yyerror (msg)
char *msg;
{
if (msg && *msg)
fprintf (stderr, "\007dm: %s\n", msg);
fprintf (stderr,
"\007dm: Failure occurred with this left in input: (%s)\n", Expra-1);
#ifdef PTREE
ptree (Expr[Exprno]);
putchar ('\n');
#endif
}
char *
strsave ()
{
char buf[BUFSIZ], *bptr = buf;
char quotechar = *Expra++;
while (*Expra && *Expra != quotechar)
*bptr++ = *Expra++;
if (*Expra == quotechar)
Expra++;
*bptr = '\0';
return (strdup (buf));
}
ENODE *
node (datum, dtype, lson, rson)
STUFF *datum; /* string, number, or operator */
int dtype; /* STRINGPTR, FLOATPTR, OPERATOR, STRINGOP */
ENODE *lson;
ENODE *rson;
{
ENODE *newnode;
newnode = myalloc (ENODE, 1);
if (newnode == NULL)
ERRSPACE(expressions)
newnode->etype = dtype;
switch (dtype)
{
case FLOATPTR: newnode->contents.num = datum->num; break;
case STRINGPTR: newnode->contents.str = datum->str; break;
case STRINGOP:
case OPERATOR: newnode->contents.opr = datum->opr; break;
default: fprintf (stderr, "\007dm/enode: unknown data type.\n");
}
newnode->lchild = lson;
newnode->rchild = rson;
return (newnode);
}
main (argc, argv) int argc; char *argv[];
{
ARGV0;
initial (argc, argv);
loop ();
exit (0);
}
/*
initial does the following:
1) inits the random number generator
2) reads in expressions from file, user, or argv[i].
3) parses expressions.
4) opens input and output files.
*/
initial (argc, argv) int argc; char **argv;
{
Boole interactive = FALSE; /* if true, input in interactive mode */
Boole input_by_hand = FALSE; /* true if expressions input by hand */
char exprline[BUFSIZ]; /* expressions read into here */
FILE *exprfile; /* expressions read from here */
FILE *getfile (); /* gets a file open */
argc--;
if (argc)
checkstdin ();
if (argc == 0)
{
interactive = TRUE;
printf ("dm: version %s (Copyright 1980 Gary Perlman)\n", DM_VERSION);
exprfile = getfile ("Expression file? ", "r");
if (exprfile == NULL)
{
input_by_hand = TRUE;
exprfile = stdin;
printf ("Enter ONE expression per line.\n");
printf ("End with an empty line.\n");
}
}
else if (argv[1][0] == 'E') /*Expra file flag */
{
if ((exprfile = fopen (&argv[1][1], "r")) == NULL)
ERROPEN (&argv[1][1])
}
else
exprfile = NULL;
for (;;) /* PARSE expressions until done */
{
readexpr:
if (exprfile == NULL) /*read Expras from argv[i] */
{
if (++Exprno > argc)
break;
Expra = argv[Exprno];
}
else /*read Expras from exprfile */
{
++Exprno;
if (input_by_hand)
printf ("expression[%d]: ", Exprno);
if (getline (exprline, BUFSIZ, exprfile) <= 0)
break;
Expra = exprline;
}
while (isspace (*Expra))
Expra++;
if (*Expra == 'X')
{
Should_output[Exprno] = FALSE;
Expra++;
}
else
Should_output[Exprno] = TRUE;
if (yyparse() == PARSERROR) /* call parser */
{
fprintf (stderr, "\007dm: error in parsing expr[%d].\n", Exprno--);
if (input_by_hand)
goto readexpr;
else
exit (1);
}
#ifdef PTREE
if (interactive)
{
printf ("e%d: ", Exprno);
ptree (Expr[Exprno]);
putchar ('\n');
}
#endif
}
Nexpr = Exprno - 1;
if (Nexpr == 0)
{
Exprno = 0;
fprintf (stderr, "dm: \007No expressions were read in\n");
if (input_by_hand && !feof (stdin))
goto readexpr;
else
exit (1);
}
/* OPEN I/O files */
if (interactive)
{
if ((Infile = getfile ("Input file? ", "r")) == NULL)
Infile = stdin;
if ((Outfile = getfile ("Output file or pipe? ", "w")) == NULL)
Outfile = stdout;
}
else
{
Infile = stdin;
Outfile = stdout;
}
if (Userand)
initrand (Seed);
}
/* loop runs the process on the input to produce the output */
loop ()
{
double eval ();
Boole skip = FALSE;
while (getinput () != EOF)
{
skip = FALSE;
for (Exprno = 1; Exprno <= Nexpr; Exprno++)
if ((Output[Exprno] = eval(Expr[Exprno])) == Suppress)
{skip = TRUE; break;}
else if (Output[Exprno] == Exitflag) exit (0);
if (skip == TRUE) continue;
OUTLINE += 1.0;
for (Exprno = 1; Exprno <= Nexpr; Exprno++)
if (Should_output[Exprno])
{
if (Output[Exprno] == Stringflag)
fprintf (Outfile, "%s", Evalstr[Exprno]);
else if (Output[Exprno] == Nil)
continue;
else
printnum (Outfile, Output[Exprno]);
if (Exprno < Nexpr)
putc ('\t', Outfile);
}
putc ('\n', Outfile);
/* fflush (Outfile); why was this needed? */
}
#ifndef MSDOS /* no popen on MSDOS */
if (Outpipe) VOID pclose (Outfile);
#endif
}
int
getinput ()
{
int ncols;
register int col;
int randval;
if (getline (Inputline, BUFSIZ, Infile) == EOF)
return (EOF);
if (Userand)
{
while ((randval = rand ()) < 0);
Randu = randval/Maxrand;
}
Sum = 0.0;
INLINE += 1.0;
ncols = sstrings (Inputline, Str[1], MAXCOL, MAXSTRING);
for (col = 1; col <= ncols; col++)
if (number (Str[col]))
Sum += (Input[col] = atof(Str[col]));
else
Input[col] = 0.0;
N = ncols;
return (ncols);
}
/*
eval is a recursive function that takes a parse tree of an expression,
and returns its value. The major kludge in this program is how it handles
strings. Since it wants to return a double, it cannot return a string, so
the use of strings is somewhat restricted. When eval evals to a string, it
returns STRINGFLAG after setting a global char *Evalstr[Exprno] to the str
MAIN will look for this flag and switch its output to Evalstr[Exprno] rather
than Output[Exprno].
*/
double
eval (expression) ENODE *expression;
{
int comp; /*for string comparisons*/
int sindex, character; /*for STRINDEX function */
char *string_2b_indexed; /*for STRINDEX function */
double tmp1, tmp2;
int operator;
if (expression == NULL) return (0.0);
if (expression->etype == FLOATPTR)
return (*expression->contents.num);
if (expression->etype == STRINGPTR)
{
Evalstr[Exprno] = expression->contents.str;
return (Stringflag);
}
if (expression->etype == STRINGOP)
{
switch (expression->contents.opr)
{
case '=': /*string compare*/
comp = strcmp (expression->lchild->contents.str,
expression->rchild->contents.str);
return (comp ? 0.0 : 1.0);
case '>': /*string compare*/
comp = strcmp (expression->lchild->contents.str,
expression->rchild->contents.str);
return (comp > 0 ? 1.0 : 0.0);
case '<': /*string compare*/
comp = strcmp (expression->lchild->contents.str,
expression->rchild->contents.str);
return (comp < 0 ? 1.0 : 0.0);
case 'C': /*true is s1 is in s2 */
comp = substr (expression->lchild->contents.str,
expression->rchild->contents.str);
return (comp ? 1.0 : 0.0);
case '#':
return ((double) strlen (expression->rchild->contents.str));
case NTYPE:
return ((double) number (expression->rchild->contents.str));
case '[': /* string index */
sindex = eval (expression->rchild);
string_2b_indexed = expression->lchild->contents.str;
character = string_2b_indexed[sindex-1];
return (1.0 * character);
}
}
operator = expression->contents.opr;
if (operator == ':') return (0.0); /*dummy for conditional */
tmp1 = eval (expression->lchild);
tmp2 = eval (expression->rchild);
switch (operator)
{
case 'x':
sindex = (int) tmp2;
if (sindex < 0 || sindex > N)
ERRMSG1 (computed index for x (%d) is out of range, sindex)
return (Input[sindex]);
case 'y':
sindex = (int) tmp2;
if (sindex >= 0 && sindex <= Nexpr)
return (Output[sindex]);
ERRMSG1 (computed index for y (%d) is out of range, sindex)
case '_': return (-tmp2);
case '!': return (fzero (tmp2) ? 1.0 : 0.0);
case 'l': if (tmp2 <= 0.0)
ERRMSG3 (log undefined for %f on line %.0f expr[%d], tmp2, INLINE,Exprno)
return (log (tmp2));
case 'L': if (tmp2 <= 0.0)
ERRMSG3(Log undefined for %f Input line %.0f expr[%d], tmp2,INLINE,Exprno)
return (log (tmp2) / LOGe10);
case 'e': return (exp (tmp2));
case SQRT:
if (tmp2 < 0.0)
ERRMSG3 (sqrt undefined for %f Input line %.0f expr[%d],
tmp2, INLINE, Exprno)
return (sqrt (tmp2));
case SIN: return (sin (tmp2));
case COS: return (cos (tmp2));
case TAN: return (tan (tmp2));
case ATAN: return (atan (tmp2));
case ACOS: return (acos (tmp2));
case ASIN: return (asin (tmp2));
case 'a': return (fabs (tmp2));
case 'c': return (ceil (tmp2));
case 'f': return (floor (tmp2));
case '+': return (tmp1 + tmp2);
case '-': return (tmp1 - tmp2);
case '*': return (tmp1 * tmp2);
case '%': if (fzero (tmp2))
ERRMSG2 (division by zero. input line %.0f expr[%d], INLINE,Exprno)
return ((double) (((int) tmp1) % ((int) tmp2)));
case '/': if (fzero (tmp2))
ERRMSG2 (division by zero. input line %.0f expr[%d], INLINE,Exprno)
return (tmp1/tmp2);
case '^':
if (tmp1 < 0.0 && (floor (tmp2) != tmp2))
ERRMSG1 (power failure at line %.0f, INLINE)
return (pow (tmp1, tmp2));
case '>': return (tmp1 > tmp2 ? 1.0 : 0.0);
case '<': return (tmp1 < tmp2 ? 1.0 : 0.0);
case '=': return (fzero (tmp1 - tmp2) ? 1.0 : 0.0);
case '&': return ((!fzero (tmp1) && !fzero (tmp2)) ? 1.0 : 0.0);
case '|': return ((!fzero (tmp1) || !fzero (tmp2)) ? 1.0 : 0.0);
case '?': if (!fzero (tmp1))
return (eval (expression->rchild->lchild));
return (eval (expression->rchild->rchild));
default:
ERRMSG3 (Unknown operator '%c' %d \\%3o, operator, operator, operator)
}
return (Exitflag);
}
#ifdef PTREE
ptree (tree) ENODE *tree;
{
if (tree == NULL) return;
if (tree->etype == FLOATPTR)
if (*tree->contents.num < -LARGE)
{
double *nptr = tree->contents.num;
if (nptr == &Suppress)
printf ("KILL");
else if (nptr == &Exitflag)
printf ("EXIT");
else if (nptr == &Nil)
printf ("NIL");
else printf ("CONTROL");
}
else /* regular number */
{
double *dptr = tree->contents.num;
if (dptr > Input && dptr <= &Input[MAXCOL])
printf ("x%d", dptr - Input);
else if (dptr == &INLINE)
printf ("INLINE");
else if (dptr > Output && dptr <= &Output[MAXCOL])
printf ("y%d", dptr - Output);
else if (dptr == &OUTLINE)
printf ("OUTLINE");
else if (dptr == &N)
printf ("N");
else if (dptr == &Sum)
printf ("SUM");
else if (dptr == &Randu)
printf ("RAND");
else
printnum (stdout, *dptr);
}
else if (tree->etype == STRINGPTR)
{
char *sptr = tree->contents.str;
if (sptr == Inputline)
printf ("INPUT");
else if (sptr >= Str[0] && sptr < Str[MAXCOL])
printf ("s%d", (sptr - Str[0])/MAXSTRING);
else printf ("'%s'", sptr);
}
else if (tree->etype == OPERATOR || tree->etype == STRINGOP)
{
int op = tree->contents.opr;
printf ("(");
ptree (tree->lchild);
switch (op)
{
case NTYPE: printf ("number "); break;
case '#': printf ("len "); break;
case 'l': printf ("log "); break;
case 'L': printf ("Log "); break;
case 'e': printf ("exp "); break;
case SQRT: printf ("sqrt "); break;
case SIN: printf ("sin "); break;
case COS: printf ("cos "); break;
case TAN: printf ("tan "); break;
case ATAN: printf ("atan "); break;
case ACOS: printf ("acos "); break;
case ASIN: printf ("asin "); break;
case 'c': printf ("ceil "); break;
case 'f': printf ("floor "); break;
case 'a': printf ("abs "); break;
default:
printf (" %c ", op);
}
ptree (tree->rchild);
printf (")");
}
else printf ("(bad node type %d)", tree->etype);
}
#endif
FILE *
getfile (prompt, mode) char *prompt, *mode;
{
#ifndef MSDOS /* no popen on MSDOS */
FILE *popen ();
#endif
FILE *fopen (), *ioptr;
char filename[BUFSIZ];
char *ptr = filename;
newfile:
printf ("%s", prompt);
if (getline (filename, MAXSTRING, stdin) <= 0) return (NULL);
while (isspace (*ptr)) ptr++;
if (*ptr == NULL) return (NULL);
if (*mode == 'w')
if (*ptr == '|') Outpipe = 1;
else if (!canwrite (filename)) goto newfile;
if (Outpipe)
{
#ifndef MSDOS /* no popen on MSDOS */
if ((ioptr = popen (ptr+1, "w")) == NULL)
#endif
{
fprintf (stderr, "Cannot create pipe.\n");
Outpipe = 0;
goto newfile;
}
}
else if ((ioptr = fopen (filename, mode)) == NULL)
{
printf ("Cannot open '%s'.\n", filename);
goto newfile;
}
return (ioptr);
}
int
getline (string, maxlen, ioptr)
char *string;
int maxlen;
FILE *ioptr;
{
register int inchar;
register int len = 0;
while ((inchar = getc (ioptr)) != EOF)
{
if (inchar == '\n') break;
else if (inchar == '\\')
if ((inchar = getc (ioptr)) == EOF) inchar = '\\';
string[len] = inchar;
if (++len == maxlen) break;
}
string[len] = '\0';
if (len == 0 && feof (ioptr))
return (EOF);
return (len);
}
begins (s1, s2) char *s1, *s2;
{
while (*s1)
if (*s1++ != *s2++)
return (0);
return (1);
/* return (isalpha (*s2) ? 0 : 1); can't be used because of s1 C s2 */
}
substr (s1, s2) char *s1, *s2;
{
while (*s2)
if (begins (s1, s2))
return (1);
else
s2++;
return (0);
}
printnum (ioptr, value)
FILE *ioptr;
double value;
{
char *format = "%g";
if (value >= 0.0 && (fzero (floor (value) - value)))
format = "%.0f";
fprintf (ioptr, format, value);
}
short yyexca[] ={
-1, 1,
0, -1,
-2, 0,
-1, 84,
265, 0,
266, 0,
267, 0,
268, 0,
269, 0,
270, 0,
-2, 15,
-1, 85,
265, 0,
266, 0,
267, 0,
268, 0,
269, 0,
270, 0,
-2, 16,
-1, 86,
265, 0,
266, 0,
267, 0,
268, 0,
269, 0,
270, 0,
-2, 19,
-1, 87,
265, 0,
266, 0,
267, 0,
268, 0,
269, 0,
270, 0,
-2, 20,
-1, 88,
265, 0,
266, 0,
267, 0,
268, 0,
269, 0,
270, 0,
-2, 23,
-1, 89,
265, 0,
266, 0,
267, 0,
268, 0,
269, 0,
270, 0,
-2, 24,
};
# define YYNPROD 54
# define YYLAST 476
short yyact[]={
9, 52, 24, 31, 40, 116, 33, 7, 30, 28,
75, 29, 8, 32, 31, 55, 54, 110, 1, 30,
107, 0, 31, 40, 32, 51, 0, 30, 28, 44,
29, 0, 32, 0, 0, 0, 31, 40, 2, 0,
0, 30, 28, 11, 29, 0, 32, 31, 44, 0,
0, 0, 30, 28, 0, 29, 0, 32, 0, 113,
33, 0, 44, 107, 20, 0, 22, 0, 19, 21,
0, 33, 0, 0, 0, 10, 31, 40, 112, 33,
0, 30, 28, 94, 29, 0, 32, 5, 6, 52,
42, 0, 111, 33, 0, 31, 40, 0, 0, 106,
30, 28, 44, 29, 33, 32, 0, 0, 0, 42,
31, 40, 0, 51, 0, 30, 28, 0, 29, 0,
32, 44, 0, 42, 31, 40, 0, 0, 0, 30,
28, 0, 29, 33, 32, 31, 44, 0, 0, 0,
30, 28, 0, 29, 0, 32, 0, 0, 114, 115,
0, 0, 33, 0, 0, 117, 0, 0, 0, 0,
0, 0, 0, 42, 0, 0, 0, 33, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 33, 42, 0, 0, 0, 0, 0, 0, 0,
0, 0, 33, 0, 0, 0, 0, 42, 0, 45,
46, 48, 47, 50, 49, 53, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 26, 27, 0, 25, 27, 43,
41, 34, 35, 37, 36, 39, 38, 0, 0, 0,
12, 13, 14, 15, 16, 17, 18, 23, 43, 41,
34, 35, 37, 36, 39, 38, 0, 0, 0, 0,
0, 0, 43, 41, 34, 35, 37, 36, 39, 38,
0, 0, 0, 0, 0, 34, 35, 37, 36, 39,
38, 0, 0, 0, 0, 0, 0, 45, 46, 48,
47, 50, 49, 53, 0, 0, 0, 0, 0, 0,
109, 0, 43, 41, 34, 35, 37, 36, 39, 38,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 43, 41, 34, 35, 37, 36, 39, 38, 0,
0, 0, 0, 0, 0, 0, 43, 41, 34, 35,
37, 36, 39, 38, 0, 0, 0, 0, 0, 0,
0, 41, 34, 35, 37, 36, 39, 38, 59, 4,
0, 0, 0, 0, 0, 0, 57, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 74, 76, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 4, 95, 96, 97, 98, 99, 100,
3, 102, 103, 0, 0, 0, 0, 0, 56, 58,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 73, 108, 0, 77, 0, 0, 78,
79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 0, 0, 0, 0, 0,
0, 0, 101, 0, 0, 104, 105, 0, 4, 4,
0, 0, 0, 0, 0, 4 };
short yypact[]={
-33,-1000,-1000, 73, -66, -75, -76, -33, -33, -33,
-33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-33, -33, -33, -30, -30, -33,-1000,-1000, -33, -33,
-33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-33, -33, -33, -33, -33, -30, -30, -30, -30, -30,
-30, -33, -30, -30, -33, -33, 58, 22,-1000, -66,
10,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
-1000,-1000,-1000,-1000,-1000, -30,-1000, 39, -23, -23,
-88, -88, -88, -88, 98, 98, 98, 98, 98, 98,
10, 10, 87, 87, -41,-1000,-1000,-1000,-1000,-1000,
-1000, -1,-1000,-1000, -15, -34,-1000,-1000, -21, -33,
-33,-1000,-1000,-1000,-257,-1000, -33,-1000 };
short yypgo[]={
0, 410, 358, 38, 18 };
short yyr1[]={
0, 4, 3, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2 };
short yyr2[]={
0, 1, 1, 1, 4, 4, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 4, 3, 3, 5,
6, 1, 3, 1 };
short yychk[]={
-1000, -4, -3, -1, -2, 120, 121, 40, 45, 33,
108, 76, 273, 274, 275, 276, 277, 278, 279, 101,
97, 102, 99, 280, 35, 260, 257, 258, 43, 45,
42, 37, 47, 94, 265, 266, 268, 267, 270, 269,
38, 264, 124, 263, 63, 265, 266, 268, 267, 270,
269, 91, 67, 271, 91, 91, -1, -2, -1, -2,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -2, 40, -2, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -3, -2, -2, -2, -2, -2,
-2, -1, -2, -2, -1, -1, 41, 41, -2, 261,
58, 93, 93, 93, -3, -3, 262, -3 };
short yydef[]={
0, -2, 1, 2, 3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 51, 53, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 29, 0,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 0, 45, 0, 7, 8,
9, 10, 11, 12, -2, -2, -2, -2, -2, -2,
25, 26, 27, 28, 0, 13, 14, 17, 18, 21,
22, 0, 47, 48, 0, 0, 6, 52, 0, 0,
0, 46, 4, 5, 0, 49, 0, 50 };
#ifndef lint
static char yaccpar_sccsid[] = "@(#)yaccpar 4.1 (Berkeley) 2/11/83";
#endif not lint
#
# define YYFLAG -1000
# define YYERROR goto yyerrlab
# define YYACCEPT return(0)
# define YYABORT return(1)
/* parser for yacc output */
#ifdef YYDEBUG
int yydebug = 0; /* 1 for debugging */
#endif
YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */
int yychar = -1; /* current input token number */
int yynerrs = 0; /* number of errors */
short yyerrflag = 0; /* error recovery flag */
yyparse() {
short yys[YYMAXDEPTH];
short yyj, yym;
register YYSTYPE *yypvt;
register short yystate, *yyps, yyn;
register YYSTYPE *yypv;
register short *yyxi;
yystate = 0;
yychar = -1;
yynerrs = 0;
yyerrflag = 0;
yyps= &yys[-1];
yypv= &yyv[-1];
yystack: /* put a state and value onto the stack */
#ifdef YYDEBUG
if( yydebug ) printf( "state %d, char 0%o\n", yystate, yychar );
#endif
if( ++yyps> &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); }
*yyps = yystate;
++yypv;
*yypv = yyval;
yynewstate:
yyn = yypact[yystate];
if( yyn<= YYFLAG ) goto yydefault; /* simple state */
if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0;
if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault;
if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */
yychar = -1;
yyval = yylval;
yystate = yyn;
if( yyerrflag > 0 ) --yyerrflag;
goto yystack;
}
yydefault:
/* default state action */
if( (yyn=yydef[yystate]) == -2 ) {
if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0;
/* look through exception table */
for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */
while( *(yyxi+=2) >= 0 ){
if( *yyxi == yychar ) break;
}
if( (yyn = yyxi[1]) < 0 ) return(0); /* accept */
}
if( yyn == 0 ){ /* error */
/* error ... attempt to resume parsing */
switch( yyerrflag ){
case 0: /* brand new error */
yyerror( "syntax error" );
yyerrlab:
++yynerrs;
case 1:
case 2: /* incompletely recovered error ... try again */
yyerrflag = 3;
/* find a state where "error" is a legal shift action */
while ( yyps >= yys ) {
yyn = yypact[*yyps] + YYERRCODE;
if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){
yystate = yyact[yyn]; /* simulate a shift of "error" */
goto yystack;
}
yyn = yypact[*yyps];
/* the current yyps has no shift onn "error", pop stack */
#ifdef YYDEBUG
if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] );
#endif
--yyps;
--yypv;
}
/* there is no state on the stack with an error shift ... abort */
yyabort:
return(1);
case 3: /* no shift yet; clobber input char */
#ifdef YYDEBUG
if( yydebug ) printf( "error recovery discards char %d\n", yychar );
#endif
if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */
yychar = -1;
goto yynewstate; /* try again in the same state */
}
}
/* reduction by production yyn */
#ifdef YYDEBUG
if( yydebug ) printf("reduce %d\n",yyn);
#endif
yyps -= yyr2[yyn];
yypvt = yypv;
yypv -= yyr2[yyn];
yyval = yypv[1];
yym=yyn;
/* consult goto table to find next state */
yyn = yyr1[yyn];
yyj = yypgo[yyn] + *yyps + 1;
if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]];
switch(yym){
case 1:
# line 125 "dm.y"
{
Expr[Exprno] = yypvt[-0].ex;
} break;
case 2:
# line 130 "dm.y"
{
yyval.ex = yypvt[-0].ex;
} break;
case 3:
# line 134 "dm.y"
{
yyval.ex = yypvt[-0].ex;
} break;
case 4:
# line 139 "dm.y"
{
Tmp1.opr = 'x';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-1].ex);
} break;
case 5:
# line 144 "dm.y"
{
Tmp1.opr = 'y';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-1].ex);
} break;
case 6:
# line 149 "dm.y"
{
yyval.ex = yypvt[-1].ex;
} break;
case 7:
# line 153 "dm.y"
{
Tmp1.opr = '+';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 8:
# line 158 "dm.y"
{
Tmp1.opr = '-';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 9:
# line 163 "dm.y"
{
Tmp1.opr = '*';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 10:
# line 168 "dm.y"
{
Tmp1.opr = '%';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 11:
# line 173 "dm.y"
{
Tmp1.opr = '/';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 12:
# line 178 "dm.y"
{
Tmp1.opr = '^';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 13:
# line 183 "dm.y"
{
Tmp1.opr = '=';
yyval.ex = node (&Tmp1, STRINGOP, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 14:
# line 188 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '=';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, STRINGOP, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 15:
# line 195 "dm.y"
{
Tmp1.opr = '=';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 16:
# line 200 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '=';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 17:
# line 207 "dm.y"
{
Tmp1.opr = '>';
yyval.ex = node (&Tmp1, STRINGOP, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 18:
# line 212 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '<';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, STRINGOP, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 19:
# line 219 "dm.y"
{
Tmp1.opr = '>';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 20:
# line 224 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '<';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 21:
# line 231 "dm.y"
{
Tmp1.opr = '<';
yyval.ex = node (&Tmp1, STRINGOP, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 22:
# line 236 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '>';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, STRINGOP, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 23:
# line 243 "dm.y"
{
Tmp1.opr = '<';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 24:
# line 248 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '>';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 25:
# line 255 "dm.y"
{
Tmp1.opr = '&';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 26:
# line 260 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '&';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 27:
# line 267 "dm.y"
{
Tmp1.opr = '|';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 28:
# line 272 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = '|';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 29:
# line 279 "dm.y"
{
Tmp1.opr = '_';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 30:
# line 284 "dm.y"
{
Tmp1.opr = '!';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 31:
# line 289 "dm.y"
{
Tmp1.opr = 'l';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 32:
# line 294 "dm.y"
{
Tmp1.opr = 'L';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 33:
# line 299 "dm.y"
{
Tmp1.opr = SQRT;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 34:
# line 304 "dm.y"
{
Tmp1.opr = SIN;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 35:
# line 309 "dm.y"
{
Tmp1.opr = COS;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 36:
# line 314 "dm.y"
{
Tmp1.opr = TAN;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 37:
# line 319 "dm.y"
{
Tmp1.opr = ATAN;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 38:
# line 324 "dm.y"
{
Tmp1.opr = ACOS;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 39:
# line 329 "dm.y"
{
Tmp1.opr = ASIN;
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 40:
# line 334 "dm.y"
{
Tmp1.opr = 'e';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 41:
# line 339 "dm.y"
{
Tmp1.opr = 'a';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 42:
# line 344 "dm.y"
{
Tmp1.opr = 'f';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 43:
# line 349 "dm.y"
{
Tmp1.opr = 'c';
yyval.ex = node (&Tmp1, OPERATOR, ENULL, yypvt[-0].ex);
} break;
case 44:
# line 354 "dm.y"
{
Tmp1.opr = NTYPE;
yyval.ex = node (&Tmp1, STRINGOP, ENULL, yypvt[-0].ex);
} break;
case 45:
# line 359 "dm.y"
{
Tmp1.opr = '#';
yyval.ex = node (&Tmp1, STRINGOP, ENULL, yypvt[-0].ex);
} break;
case 46:
# line 364 "dm.y"
{
Tmp1.opr = '[';
yyval.ex = node (&Tmp1, STRINGOP, yypvt[-3].ex, yypvt[-1].ex);
} break;
case 47:
# line 369 "dm.y"
{
Tmp1.opr = 'C';
yyval.ex = node (&Tmp1, STRINGOP, yypvt[-2].ex, yypvt[-0].ex);
} break;
case 48:
# line 374 "dm.y"
{
Tmp1.opr = '!';
Tmp2.opr = 'C';
yyval.ex = node (&Tmp1, OPERATOR, ENULL,
node (&Tmp2, STRINGOP, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 49:
# line 381 "dm.y"
{
Tmp1.opr = '?';
Tmp2.opr = ':';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-4].ex,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 50:
# line 388 "dm.y"
{
Tmp1.opr = '?';
Tmp2.opr = ':';
yyval.ex = node (&Tmp1, OPERATOR, yypvt[-4].ex,
node (&Tmp2, OPERATOR, yypvt[-2].ex, yypvt[-0].ex));
} break;
case 51:
# line 395 "dm.y"
{
Tmp1.num = yypvt[-0].num;
yyval.ex = node (&Tmp1, FLOATPTR, ENULL, ENULL);
} break;
case 52:
# line 401 "dm.y"
{
yyval.ex = yypvt[-1].ex;
} break;
case 53:
# line 405 "dm.y"
{
Tmp1.str = yypvt[-0].str;
yyval.ex = node (&Tmp1, STRINGPTR, ENULL, ENULL);
} break;
}
goto yystack; /* stack new state and value */
}