home *** CD-ROM | disk | FTP | other *** search
- /*
- * Yacc input for complex-number parser, version 1.
- * Handles only simple arithmetical expressions: +, -, *, /, unary -.
- * Now added: exponentation w^z and conjugate, z'.
- * Arbitrary variable names now...and builtin functions.
- * And comments...constants - lots in fact. These things grow and grow!
- * Coming soon: user-defined functions...
- * Thank God for yacc - these things are a nightmare to hand-code...
- *
- * Martin W.Scott, March 16, 1991.
- */
- %{
- #include <stdio.h>
- #include <ctype.h>
- #include "complex.h"
- #include "memory.h"
-
- extern void cprin(FILE *, char *prefix, char *suffix, Complex z);
- extern int precision;
-
- RemKey *remkey;
-
- const Complex zero = {0.0, 0.0},
- eye = {0.0, 1.0};
-
- Symbol *ans; /* set by init.c */
- Complex treeval; /* what tree evaluates to */
- UserFunc *userfunc; /* symbol for user-function definition */
- int inparamlist; /* are we at a functions parameter-list? */
- int indefn; /* are we in function definition? */
- int silent; /* should we display results? */
- int repeatcnt; /* number of times to repeat expression */
- char *infile; /* file currently being read */
- %}
-
- %union {
- double rval;
- Symbol *sym;
- Node *node;
- }
- %start list
-
- %token <rval> NUMBER
- %token <sym> VAR CONST C_BLTIN R_BLTIN FUNCDEF UFUNC COMMAND UNDEF
- %token <sym> PARAMETER PRECISION REPEAT
-
- %type <node> expr
- %type <sym> parlist symbol
-
- %right '=' /* assignment */
- %left '+' '-' /* standard arithmetic operators */
- %left '*' '/'
- %left UMINUS /* unary minus */
- %right '^' /* exponentation */
- %left '\'' /* conjugate operator z' = conj(z) */
- %%
-
- list: /* nothing */
- | list separator
- | list PRECISION NUMBER separator { precision = (int)($3); }
- | list FUNCDEF symbol
- {
- if ($3->type == UFUNC)
- {
- clear_ufunc(&$3->u.ufunc);
- }
- else if ($3->type != UNDEF)
- {
- execerror($3->name, "already defined");
- }
- inparamlist = 1;
- $3->type = UFUNC;
- userfunc = &$3->u.ufunc;
- rem_freeall();
- userfunc->remkey = NULL;
- (void)rem_setkey(&userfunc->remkey);
- }
- '(' parlist ')'
- {
- inparamlist = 0;
- indefn = 1;
- userfunc->param = $6;
- }
- '=' expr separator
- {
- userfunc->tree = $10;
- (void)rem_setkey(&remkey);
- indefn = 0;
- if (!silent)
- fprintf(stdout, "\t%s(%s) defined\n", $3->name, userfunc->param->name);
- }
-
- | list COMMAND separator { (*($2->u.vptr))(); }
- | list opt_repeat expr separator
- {
- while (repeatcnt)
- {
- --repeatcnt;
- treeval = eval_tree($3);
-
- if (!silent)
- cprin(stdout, "\t", "\n", treeval);
- if (ans) /* allocated successfully */
- ans->u.val = treeval;/* set 'last answer' const */
- }
- /* free all mem associated with this tree */
- rem_freeall();
- }
- | list error '\n'
- {
- if (indefn)
- {
- indefn = 0;
- rem_setkey(&remkey);
- }
- inparamlist = 0;
- yyerrok;
- }
- ;
-
- parlist: PARAMETER
-
- /* | parlist ',' PARAMETER */
-
- symbol: VAR
- | UFUNC
- ;
-
- separator: '\n' /* allows multiple commands/expressions on one line */
- | ';'
- ;
-
- opt_repeat: /* nothing */ { repeatcnt = 1; }
- | REPEAT NUMBER { repeatcnt = (int)($2); }
- ;
-
- expr: NUMBER { $$ = n_number($1, 0.0); }
- | NUMBER 'i' { $$ = n_number(0.0, $1); }
- | 'i' { $$ = n_number(0.0, 1.0); }
- | CONST { $$ = n_symbol(CONST, $1); }
- | CONST '=' expr { execerror("invalid assignment to constant", $1->name); }
- | VAR { if ($1->type == UNDEF)
- warning("using zero for undefined symbol", $1->name);
- $$ = n_symbol(VAR, $1);
- }
- | PARAMETER { $$ = n_symbol(PARAMETER, $1); }
- | VAR '=' expr { $1->type = VAR; $$ = n_asgn($1, $3); }
- | C_BLTIN '(' expr ')' { $$ = n_func(C_BLTIN, $1, $3); }
- | R_BLTIN '(' expr ')' { $$ = n_func(R_BLTIN, $1, $3); }
- | UFUNC '(' expr ')' { $$ = n_func(UFUNC, $1, $3); }
- | expr '+' expr { $$ = n_binop('+', $1, $3); }
- | expr '-' expr { $$ = n_binop('-', $1, $3); }
- | expr '*' expr { $$ = n_binop('*', $1, $3); }
- | expr '/' expr { $$ = n_binop('/', $1, $3); }
- | expr '^' expr { $$ = n_binop('^', $1, $3); }
- | expr '\'' { $$ = n_unop('\'', $1); }
- | '(' expr ')' { $$ = n_unop('(', $2); }
- | '-' expr %prec UMINUS { $$ = n_unop(UMINUS , $2); }
- ;
-
- %%
-
- #include <signal.h>
- #include <setjmp.h>
-
- #ifdef AMIGA
- #include <libraries/dos.h>
- #include <workbench/startup.h>
- #include <proto/dos.h>
- extern struct WBStartup *WBenchMsg;
- int workbench;
- struct WBArg *wbargv;
- char *nextarg(void);
- #endif
-
- #define BANNER "\033[33micalc expression parser v1.0, by mws\033[31m\n"
-
- jmp_buf begin; /* error start */
- int lineno; /* current line-number of input file */
- FILE *fin; /* current input file */
- char **gargv; /* global argument array */
- int gargc; /* global argument count */
-
- yylex()
- {
- int c;
-
- chkabort();
- while ((c = getc(fin)) == ' ' || c == '\t') /* skip blanks */
- ;
-
- if (c == EOF) /* end of input */
- return 0;
-
- if (c == '.' || isdigit(c)) /* number */
- {
- ungetc(c, fin);
- fscanf(fin, "%lf", &yylval.rval);
- return NUMBER;
- }
- if (c == 'i') /* possibly imaginary part */
- {
- if (!isalnum(c = getc(fin))) /* yes, it is */
- {
- ungetc(c, fin);
- return 'i';
- }
- ungetc(c, fin); /* no, fall through to next */
- c = 'i'; /* restore c to proper value */
- }
- if (isalpha(c)) /* constant, var or builtin */
- {
- Symbol *s;
- char sbuf[100], *p = sbuf;
-
- do {
- *p++ = c;
- } while ((c = getc(fin)) != EOF && isalnum(c));
- ungetc(c, fin);
- *p = '\0';
-
- if (inparamlist)
- s = allocsym(sbuf, PARAMETER);
- else
- {
- /* if in function definition, check it's argument
- list for variable references BEFORE symtree */
- if (indefn && !strcmp(sbuf, userfunc->param->name))
- s = userfunc->param;
- else if (!(s = lookup(sbuf)))
- s = install(sbuf, UNDEF, zero);
- }
-
- yylval.sym = s;
-
- return s->type == UNDEF ? VAR : s->type;
- }
- if (c == '#')
- {
- while ((c = getc(fin)) != '\n' && c != EOF)
- ;
- if (c == EOF) /* end of input */
- return 0;
- }
- if (c == '\n')
- lineno++;
-
- return c;
- }
-
- void warning(s, t)
- char *s, *t;
- {
- fprintf(stderr,"icalc: %s", s);
- if (t)
- fprintf(stderr," %s", t);
- if (infile)
- {
- fprintf(stderr," in %s,", infile);
- fprintf(stderr," near line %d\n", lineno);
- }
- fprintf(stderr,"\n");
- }
-
- void yyerror(s)
- char *s;
- {
- warning(s, NULL);
- }
-
- void execerror(s, t)
- char *s;
- char *t;
- {
- warning(s, t);
- longjmp(begin, 0);
- }
-
- void fpecatch()
- {
- execerror("floating point exception", NULL);
- }
-
- void main(argc,argv)
- char **argv;
- {
- fprintf(stderr,BANNER); /* hello... */
-
- #ifdef AMIGA
- if (argc == 0) /* ran from workbench */
- {
- workbench = 1; /* set workbench flag */
- gargc = WBenchMsg->sm_NumArgs-1;
- wbargv = &(WBenchMsg->sm_ArgList)[1];
- }
- else
- #endif
- if (argc == 1) /* stdin only - fake argument list */
- {
- static char *stdinonly[] = { "-" };
-
- gargv = stdinonly;
- gargc = 1;
- }
- else
- {
- gargv = &argv[1];
- gargc = argc-1;
- }
-
- (void)rem_setkey(&remkey); /* set 'remember' key */
- init(); /* build initial symbol tree */
-
- while (moreinput()) /* something to rea */
- {
- setjmp(begin); /* where to come back to */
- signal(SIGFPE, fpecatch); /* catch math errors */
- yyparse(); /* start parsing */
- }
- }
-
- int moreinput()
- {
- #ifdef AMIGA
- if (workbench)
- {
- infile = nextarg();
- if (infile == NULL)
- return 0;
- }
- else {
- #endif
- if (gargc-- <= 0)
- return 0;
- if (fin && fin != stdin)
- fclose(fin);
- infile = *gargv++;
- #ifdef AMIGA
- }
- #endif
- lineno = 1;
- if (!strcmp(infile, "-"))
- {
- fin = stdin;
- infile = NULL;
- fprintf(stderr, "ready\n");
- }
- else if (!(fin = fopen(infile, "r")))
- {
- fprintf(stderr, "icalc: can't open %s\n", infile);
- return moreinput();
- }
- return 1;
- }
-
- #ifdef AMIGA
-
- char *nextarg()
- {
- static BPTR olddir = -1L;
-
- if (gargc > 0)
- {
- olddir = CurrentDir(wbargv->wa_Lock);
- gargc--;
- return (wbargv++)->wa_Name;
- }
- else if (gargc-- == 0)
- {
- if (olddir != (-1L))
- CurrentDir(olddir);
- return "-";
- }
- else return NULL;
- }
-
- #endif