home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 521.lha / ICalc_v1.0 / src / complex.y < prev    next >
Encoding:
Text File  |  1991-06-10  |  7.6 KB  |  377 lines

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