home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / misc / icalc.lzh / icalc / src / complex.y < prev    next >
Text File  |  1992-01-26  |  8KB  |  398 lines

  1. /*
  2. *    icalc - complex-expression parser
  3. *
  4. *    Yacc parser definition for icalc, a complex-number expression
  5. *    parser, featuring arbitrarily named variables, user-defined
  6. *    functions, startup files and special commands to ease certain tasks.
  7. *
  8. *    (C) Martin W Scott, 1991.
  9. */
  10. %{
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include "complex.h"
  14. #include "constant.h"
  15. #include "memory.h"
  16.  
  17. RemKey *remkey;
  18.  
  19. Symbol    *ans;        /* set by init.c */
  20. Symbol    *multi;        /* ditto */
  21. Complex    treeval;    /* what tree evaluates to */
  22. UserFunc *userfunc;    /* symbol for user-function definition */
  23. int    noprompt;    /* if separator a ';', prompt disabled */
  24. int    inparamlist;    /* are we at a functions parameter-list? */
  25. int    indefn;        /* are we in function definition? */
  26. int    silent;        /* should we display results? */
  27. char    *infile;    /* file currently being read */
  28. %}
  29.  
  30. %union {
  31.     double    rval;
  32.     Symbol    *sym;
  33.     Node    *node;
  34.     SymList *slist;
  35.     ArgList *alist;
  36. }
  37. %start    list
  38.  
  39. %token    <rval>    NUMBER
  40. %token    <sym>    VAR CONST C_BLTIN FUNCDEF UFUNC SFUNC COMMAND UNDEF
  41. %token    <sym>    PARAMETER
  42.  
  43. %type    <node>    expr
  44. %type    <sym>    symbol
  45. %type    <slist>    parlist
  46. %type    <alist>    arglist
  47.  
  48. %right    '='            /* assignment */
  49. %left    '+'  '-'        /* standard arithmetic operators */
  50. %left    '*'  '/'
  51. %left    UMINUS            /* unary minus */
  52. %right    '^'            /* exponentation */
  53. %left    '\''            /* conjugate operator z' = conj(z) */
  54. %%
  55.  
  56. list:      /* nothing */
  57.     | list separator    { prompt(); }
  58.     | list FUNCDEF symbol
  59.         {
  60.             if ($3->type == UFUNC)
  61.             {
  62.                 clear_ufunc(&$3->u.ufunc);
  63.             }
  64.             else if ($3->type != UNDEF)
  65.             {
  66.                 execerror($3->name, "already defined");
  67.             }
  68.             inparamlist = 1;
  69.             rem_freeall();
  70.             $3->type = UFUNC;
  71.             userfunc = &$3->u.ufunc;
  72.             init_ufunc(userfunc);
  73.             (void)rem_setkey(&userfunc->remkey);
  74.         }
  75.       '(' parlist ')'
  76.         {
  77.             inparamlist = 0;
  78.             indefn = 1;
  79.             userfunc->params = $6;
  80.         }
  81.       '=' expr separator
  82.         {
  83.             userfunc->tree = $10;
  84.             (void)rem_setkey(&remkey);
  85.             indefn = 0;
  86.             if (!silent)
  87.             {
  88.                 fprintf(stdout, "\tfunction %s defined\n", $3->name);
  89.             }
  90.             prompt();
  91.         }
  92.  
  93.     | list COMMAND separator    { (*($2->u.vptr))(); prompt(); }
  94.     | list expr separator
  95.         {
  96.             treeval = eval_tree($2);
  97.  
  98.             if (!silent)
  99.                 cprin(stdout, "\t", "\n", treeval);
  100.  
  101.             if (ans)    /* allocated successfully */
  102.                 ans->u.val = treeval;/* set 'last answer' const */
  103.  
  104.             /* free all mem associated with this tree */
  105.             rem_freeall();
  106.             prompt();
  107.         }
  108.     | list error separator
  109.         {
  110.             if (indefn)
  111.             {
  112.                 indefn = 0;
  113.                 rem_setkey(&remkey);
  114.             }            
  115.             inparamlist = 0;
  116.             yyerrok;
  117.             prompt();
  118.         }
  119.     ;
  120.  
  121. parlist:    /* none */    { $$ = NULL; }
  122.     | PARAMETER        { $$ = addparam(NULL, $1); }
  123.     | parlist ',' PARAMETER    { $$ = addparam($1, $3); }
  124.     ;
  125.  
  126. arglist:    /* nothing */    { $$ = NULL; }
  127.     | expr            { $$ = addarg(NULL, $1); }
  128.     | arglist ',' expr    { $$ = addarg($1, $3); }
  129.     ;
  130.  
  131. symbol:      VAR
  132.     | UFUNC
  133.     ;
  134.  
  135. separator: '\n'            { noprompt = 0; }
  136.     | ';'            { noprompt = 1; }
  137.     ;
  138.  
  139. expr:      NUMBER        { $$ = n_number($1, 0.0); }
  140.     | NUMBER 'i'        { $$ = n_number(0.0, $1); }
  141.     | 'i'            { $$ = n_number(0.0, 1.0); }
  142.     | CONST            { $$ = n_symbol(CONST, $1); }
  143.     | CONST '=' expr    { execerror("invalid assignment to constant", $1->name); }
  144.     | VAR            { if ($1->type == UNDEF)
  145.                     warning("using zero for undefined symbol", $1->name);
  146.                   $$ = n_symbol(VAR, $1);
  147.                 }
  148.     | PARAMETER        { $$ = n_symbol(PARAMETER, $1); }
  149.     | VAR '=' expr        { $1->type = VAR; $$ = n_asgn($1, $3); }
  150.     | C_BLTIN '(' expr ')'    { $$ = n_func(C_BLTIN, $1, $3); }
  151.     | UFUNC '(' arglist ')' { $$ = n_func(UFUNC, $1, (Node *)$3); }
  152.     | SFUNC '(' arglist ')' { $$ = n_func(SFUNC, $1, (Node *)$3); }
  153.     | expr '+' expr        { $$ = n_binop('+', $1, $3); }
  154.     | expr '-' expr        { $$ = n_binop('-', $1, $3); }
  155.     | expr '*' expr        { $$ = n_binop('*', $1, $3); }
  156.     | expr '/' expr        { $$ = n_binop('/', $1, $3); }
  157.     | expr '^' expr        { $$ = n_binop('^', $1, $3); }
  158.     | expr '\''        { $$ = n_unop('\'', $1); }
  159.     | '(' expr ')'        { $$ = n_unop('(', $2); }
  160.     | '-' expr %prec UMINUS { $$ = n_unop(UMINUS , $2); }
  161.     ;
  162.  
  163. %%
  164.  
  165. #include <signal.h>
  166. #include <setjmp.h>
  167.  
  168. #ifdef AMIGA
  169.  
  170. #include <libraries/dos.h>
  171. #include <workbench/startup.h>
  172. #include <proto/dos.h>
  173.  
  174. #define STARTUP_FILE    "s:icalc.init"
  175.  
  176. extern struct WBStartup *WBenchMsg;
  177. struct WBArg *wbargv;
  178. int wbargc;
  179.  
  180. char *nextarg(void);
  181.  
  182. #endif
  183.  
  184. void processfile(char *name);
  185.  
  186. #define    BANNER    "\033[1micalc v1.1a  (c) Martin W Scott, 1992\033[0m\n"
  187. #define PROMPT    "\033[33micalc> \033[31m"
  188.  
  189. jmp_buf    begin;            /* error start */
  190. int    lineno;            /* current line-number of input file */
  191. FILE    *fin;            /* current input file */
  192.  
  193. yylex()        /* lexical analyser - cumbersome, but does the job (just) */
  194. {
  195.     int    c;
  196.  
  197.     while ((c = getc(fin)) == ' ' || c == '\t')    /* skip blanks */
  198.         ;
  199.  
  200.     if (c == EOF)                /* end of input */
  201.         return 0;
  202.  
  203.     if (c == '.' || isdigit(c))        /* number */
  204.     {
  205.         ungetc(c, fin);
  206.         fscanf(fin, "%lf", &yylval.rval);
  207.         return NUMBER;
  208.     }
  209.     if (c == 'i')                /* possibly imaginary part */
  210.     {
  211.         if (!isalnum(c = getc(fin)) && c != '_')    /* yes, it is */
  212.         {
  213.             ungetc(c, fin);
  214.             return 'i';
  215.         }
  216.         ungetc(c, fin);            /* no, fall through to next */
  217.         c = 'i';            /* restore c to old value */
  218.     }
  219.     if (isalpha(c) || c == '_')        /* constant, var or builtin */
  220.     {
  221.         Symbol *s;
  222.         char sbuf[100], *p = sbuf;
  223.         
  224.         do {
  225.             *p++ = c;
  226.         } while ((c = getc(fin)) != EOF && (isalnum(c) || c == '_'));
  227.         ungetc(c, fin);    
  228.         *p = '\0';
  229.  
  230.         if (inparamlist)
  231.             s = allocsym(sbuf, PARAMETER);
  232.         else
  233.         {
  234.             /* if in function definition, check it's argument
  235.                list for variable references BEFORE symtree      */
  236.             if (indefn && (s = findsym(userfunc->params, sbuf)))
  237.                 ;
  238.             else if (!(s = lookup(sbuf)))
  239.                 s = install(sbuf, UNDEF, zero);
  240.         }
  241.  
  242.         yylval.sym = s;
  243.         
  244.         return s->type == UNDEF ? VAR : s->type;
  245.     }
  246.     if (c == '\\')            /* expression continued on next line */
  247.     {
  248.         while ((c = getc(fin)) != '\n' && c != EOF)
  249.             ;
  250.         if (c == '\n')
  251.         {
  252.             lineno++;
  253.             return yylex();            /* parse next line */
  254.         }
  255.         if (c == EOF)                /* end of input */
  256.             return 0;
  257.     }
  258.     if (c == '#')            /* comment line */
  259.     {
  260.         while ((c = getc(fin)) != '\n' && c != EOF)
  261.             ;
  262.         if (c == EOF)                /* end of input */
  263.             return 0;
  264.     }
  265.     if (c == '\n')
  266.         lineno++;
  267.  
  268.     return c;
  269. }
  270.  
  271. void warning(s, t)    /* print warning messages s and t (t can be NULL) */
  272.     char *s, *t;
  273. {
  274.  
  275.     fprintf(stderr,"icalc: %s", s);
  276.     if (t)
  277.         fprintf(stderr," %s", t);
  278.     if (infile)
  279.     {
  280.         fprintf(stderr," in %s,", infile);
  281.         fprintf(stderr," near line %d\n", lineno);
  282.     }
  283.     fprintf(stderr,"\n");
  284. }
  285.  
  286. void yyerror(s)        /* standard parse error notification */
  287.     char *s;
  288. {
  289.     warning(s, NULL);
  290. }
  291.  
  292. void execerror(s, t)    /* complete evaluation failure; advise, and restart */
  293.     char *s;
  294.     char *t;
  295. {
  296.     warning(s, t);
  297.     longjmp(begin, 0);
  298. }
  299.  
  300.  
  301. void prompt()        /* display a prompt if circumstances are right */
  302. {
  303.     if (!noprompt && !infile && !silent)    /* interactive session */
  304.         fprintf(stderr, PROMPT);
  305. }
  306.  
  307.  
  308. void fpecatch()        /* catch floating-point errors */
  309. {
  310.     execerror("floating point exception", NULL);
  311. }
  312.  
  313.  
  314. void main(argc,argv)    /* main program entry - parse arguments */
  315.     char **argv;
  316. {
  317.     fprintf(stderr,BANNER);            /* hello... */
  318.  
  319.     (void)rem_setkey(&remkey);        /* set 'remember' key */
  320.     init();                    /* build initial symbol tree */
  321.  
  322. #ifdef AMIGA
  323.     if (!access(STARTUP_FILE,0))        /* read startup file */
  324.         processfile(STARTUP_FILE);
  325. #endif
  326.  
  327. #ifdef AMIGA        /* process arguments - the Workbench way... */
  328.  
  329.     if (argc == 0)        /* ran from workbench */
  330.     {
  331.         char *name;
  332.  
  333.         wbargc = WBenchMsg->sm_NumArgs-1;
  334.         wbargv = &(WBenchMsg->sm_ArgList)[1];
  335.  
  336.         while (name = nextarg())
  337.             processfile(name);
  338.     }
  339.     else 
  340. #endif
  341.     if (argc == 1)    /* stdin only - fake argument list */
  342.         processfile("-");
  343.     else
  344.     {
  345.         while (--argc)
  346.             processfile(*++argv);
  347.     }
  348. }
  349.  
  350. void processfile(name)    /* open 'name' and set as curently scanned file */
  351.     char *name;
  352. {
  353.     if (!strcmp(name, "-"))            /* stdin */
  354.     {
  355.         fin = stdin;
  356.         infile = NULL;
  357.     } 
  358.     else if (!(fin = fopen(name, "r")))    /* specified file */
  359.     {
  360.         fprintf(stderr, "icalc: can't open %s\n", name);
  361.         return;
  362.     }
  363.     else infile = name;
  364.  
  365.     lineno = 1;            /* initialise line-count */
  366.  
  367.     setjmp(begin);            /* where to come back to */
  368.     signal(SIGFPE, fpecatch);    /* catch math errors */
  369.     prompt();
  370.     yyparse();            /* start parsing */
  371.  
  372.     if (!infile) fclose(fin);    /* close opened file */
  373. }    
  374.  
  375.  
  376. #ifdef AMIGA
  377.  
  378. char *nextarg()        /* get next selected Workbench argument (icon) */
  379. {
  380.     static BPTR olddir = -1L;
  381.  
  382.     if (wbargc > 0)
  383.     {
  384.         olddir = CurrentDir(wbargv->wa_Lock);
  385.         wbargc--;
  386.         return (wbargv++)->wa_Name;
  387.     }
  388.     else if (wbargc-- == 0)
  389.     {
  390.         if (olddir != (-1L))
  391.             CurrentDir(olddir);
  392.         return "-";
  393.     }
  394.     else return NULL;
  395. }
  396.  
  397. #endif
  398.