home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / RADIANCE / SRC / COMMON / CALDEFN.C < prev    next >
C/C++ Source or Header  |  1993-10-07  |  15KB  |  684 lines

  1. /* Copyright (c) 1991 Regents of the University of California */
  2.  
  3. #ifndef lint
  4. static char SCCSid[] = "@(#)caldefn.c 2.3 8/10/92 LBL";
  5. #endif
  6.  
  7. /*
  8.  *  Store variable definitions.
  9.  *
  10.  *  7/1/85  Greg Ward
  11.  *
  12.  *  11/11/85  Added conditional compiles (OUTCHAN) for control output.
  13.  *
  14.  *  4/2/86  Added conditional compiles for function definitions (FUNCTION).
  15.  *
  16.  *  1/15/88  Added clock for caching of variable values.
  17.  *
  18.  *  11/16/88  Added VARDEF structure for hard linking.
  19.  *
  20.  *  5/31/90  Added conditional compile (REDEFW) for redefinition warning.
  21.  *
  22.  *  4/23/91  Added ':' assignment for constant expressions
  23.  *
  24.  *  8/7/91  Added optional context path to append to variable names
  25.  */
  26.  
  27. #include  <stdio.h>
  28.  
  29. #include  <ctype.h>
  30.  
  31. #include  "calcomp.h"
  32.  
  33. #ifndef  NHASH
  34. #define  NHASH          521             /* hash size (a prime!) */
  35. #endif
  36.  
  37. #define  newnode()      (EPNODE *)ecalloc(1, sizeof(EPNODE))
  38.  
  39. extern char  *ecalloc(), *emalloc(), *savestr(), *strcpy();
  40.  
  41. static int  hash();
  42.  
  43. static double  dvalue();
  44.  
  45. long  eclock = -1;                      /* value storage timer */
  46.  
  47. static char  context[MAXWORD+1];        /* current context path */
  48.  
  49. static VARDEF  *hashtbl[NHASH];         /* definition list */
  50. static int  htndx;                      /* index for */         
  51. static VARDEF  *htpos;                  /* ...dfirst() and */
  52. #ifdef  OUTCHAN
  53. static EPNODE  *ochpos;                 /* ...dnext */
  54. static EPNODE  *outchan;
  55. #endif
  56.  
  57. #ifdef  FUNCTION
  58. EPNODE  *curfunc;
  59. #define  dname(ep)      ((ep)->v.kid->type == SYM ? \
  60.             (ep)->v.kid->v.name : \
  61.             (ep)->v.kid->v.kid->v.name)
  62. #else
  63. #define  dname(ep)      ((ep)->v.kid->v.name)
  64. #endif
  65.  
  66.  
  67. fcompile(fname)                 /* get definitions from a file */
  68. char  *fname;
  69. {
  70.     FILE  *fp;
  71.  
  72.     if (fname == NULL)
  73.     fp = stdin;
  74.     else if ((fp = fopen(fname, "r")) == NULL) {
  75.     eputs(fname);
  76.     eputs(": cannot open\n");
  77.     quit(1);
  78.     }
  79.     initfile(fp, fname, 0);
  80.     while (nextc != EOF)
  81.     getstatement();
  82.     if (fname != NULL)
  83.     fclose(fp);
  84. }
  85.  
  86.  
  87. scompile(str, fn, ln)           /* get definitions from a string */
  88. char  *str;
  89. char  *fn;
  90. int  ln;
  91. {
  92.     initstr(str, fn, ln);
  93.     while (nextc != EOF)
  94.     getstatement();
  95. }
  96.  
  97.  
  98. double
  99. varvalue(vname)                 /* return a variable's value */
  100. char  *vname;
  101. {
  102.     return(dvalue(vname, dlookup(vname)));
  103. }
  104.  
  105.  
  106. double
  107. evariable(ep)                   /* evaluate a variable */
  108. EPNODE  *ep;
  109. {
  110.     register VARDEF  *dp = ep->v.ln;
  111.  
  112.     return(dvalue(dp->name, dp->def));
  113. }
  114.  
  115.  
  116. varset(vname, assign, val)      /* set a variable's value */
  117. char  *vname;
  118. int  assign;
  119. double  val;
  120. {
  121.     char  *qname;
  122.     register EPNODE  *ep1, *ep2;
  123.                     /* get qualified name */
  124.     qname = qualname(vname, 0);
  125.                     /* check for quick set */
  126.     if ((ep1 = dlookup(qname)) != NULL && ep1->v.kid->type == SYM) {
  127.     ep2 = ep1->v.kid->sibling;
  128.     if (ep2->type == NUM) {
  129.         ep2->v.num = val;
  130.         ep1->type = assign;
  131.         return;
  132.     }
  133.     }
  134.                     /* hand build definition */
  135.     ep1 = newnode();
  136.     ep1->type = assign;
  137.     ep2 = newnode();
  138.     ep2->type = SYM;
  139.     ep2->v.name = savestr(vname);
  140.     addekid(ep1, ep2);
  141.     ep2 = newnode();
  142.     ep2->type = NUM;
  143.     ep2->v.num = val;
  144.     addekid(ep1, ep2);
  145.     dremove(qname);
  146.     dpush(qname, ep1);
  147. }
  148.  
  149.  
  150. dclear(name)                    /* delete variable definitions of name */
  151. char  *name;
  152. {
  153.     register EPNODE  *ep;
  154.  
  155.     while ((ep = dpop(name)) != NULL) {
  156.     if (ep->type == ':') {
  157.         dpush(name, ep);            /* don't clear constants */
  158.         return;
  159.     }
  160.     epfree(ep);
  161.     }
  162. }
  163.  
  164.  
  165. dremove(name)                   /* delete all definitions of name */
  166. char  *name;
  167. {
  168.     register EPNODE  *ep;
  169.  
  170.     while ((ep = dpop(name)) != NULL)
  171.     epfree(ep);
  172. }
  173.  
  174.  
  175. vardefined(name)        /* return non-zero if variable defined */
  176. char  *name;
  177. {
  178.     register EPNODE  *dp;
  179.  
  180.     return((dp = dlookup(name)) != NULL && dp->v.kid->type == SYM);
  181. }
  182.  
  183.  
  184. char *
  185. setcontext(ctx)                 /* set a new context path */
  186. register char  *ctx;
  187. {
  188.     register char  *cpp;
  189.  
  190.     if (ctx == NULL)
  191.     return(context);                /* just asking */
  192.     if (!*ctx) {
  193.     context[0] = '\0';              /* clear context */
  194.     return(context);
  195.     }
  196.     cpp = context;                      /* else copy it (carefully!) */
  197.     if (*ctx != CNTXMARK)
  198.     *cpp++ = CNTXMARK;              /* make sure there's a mark */
  199.     do {
  200.     if (cpp >= context+MAXWORD)
  201.         break;                      /* just copy what we can */
  202.     if (isid(*ctx))
  203.         *cpp++ = *ctx++;
  204.     else {
  205.         *cpp++ = '_'; ctx++;
  206.     }
  207.     } while (*ctx);
  208.     *cpp = '\0';
  209.     return(context);
  210. }
  211.  
  212.  
  213. char *
  214. qualname(nam, lvl)              /* get qualified name */
  215. register char  *nam;
  216. int  lvl;
  217. {
  218.     static char  nambuf[MAXWORD+1];
  219.     register char  *cp = nambuf, *cpp;
  220.                 /* check for explicit local */
  221.     if (*nam == CNTXMARK)
  222.     if (lvl > 0)            /* only action is to refuse search */
  223.         return(NULL);
  224.     else
  225.         nam++;
  226.     else if (nam == nambuf)     /* check for repeat call */
  227.     return(lvl > 0 ? NULL : nam);
  228.                 /* copy name to static buffer */
  229.     while (*nam) {
  230.     if (cp >= nambuf+MAXWORD)
  231.         goto toolong;
  232.     *cp++ = *nam++;
  233.     }
  234.                 /* check for explicit global */
  235.     if (cp > nambuf && cp[-1] == CNTXMARK) {
  236.     if (lvl > 0)
  237.         return(NULL);
  238.     *--cp = '\0';
  239.     return(nambuf);         /* already qualified */
  240.     }
  241.     cpp = context;              /* else skip the requested levels */
  242.     while (lvl-- > 0) {
  243.     if (!*cpp)
  244.         return(NULL);       /* return NULL if past global level */
  245.     while (*++cpp && *cpp != CNTXMARK)
  246.         ;
  247.     }
  248.     while (*cpp) {              /* copy context to static buffer */
  249.     if (cp >= nambuf+MAXWORD)
  250.         goto toolong;
  251.     *cp++ = *cpp++;
  252.     }
  253. toolong:
  254.     *cp = '\0';
  255.     return(nambuf);             /* return qualified name */
  256. }
  257.  
  258.  
  259. incontext(qn)                   /* is qualified name in current context? */
  260. register char  *qn;
  261. {
  262.     while (*qn && *qn != CNTXMARK)      /* find context mark */
  263.     qn++;
  264.     return(!strcmp(qn, context));
  265. }
  266.  
  267.  
  268. #ifdef  OUTCHAN
  269. chanout(cs)                     /* set output channels */
  270. int  (*cs)();
  271. {
  272.     register EPNODE  *ep;
  273.  
  274.     for (ep = outchan; ep != NULL; ep = ep->sibling)
  275.     (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
  276.  
  277. }
  278. #endif
  279.  
  280.  
  281. dcleanup(lvl)           /* clear definitions (0->vars,1->output,2->consts) */
  282. int  lvl;
  283. {
  284.     register int  i;
  285.     register VARDEF  *vp;
  286.     register EPNODE  *ep;
  287.                 /* if context is global, clear all */
  288.     for (i = 0; i < NHASH; i++)
  289.     for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
  290.         if (!context[0] || incontext(vp->name))
  291.         if (lvl >= 2)
  292.             dremove(vp->name);
  293.         else
  294.             dclear(vp->name);
  295. #ifdef  OUTCHAN
  296.     if (lvl >= 1) {
  297.     for (ep = outchan; ep != NULL; ep = ep->sibling)
  298.         epfree(ep);
  299.     outchan = NULL;
  300.     }
  301. #endif
  302. }
  303.  
  304.  
  305. EPNODE *
  306. dlookup(name)                   /* look up a definition */
  307. char  *name;
  308. {
  309.     register VARDEF  *vp;
  310.     
  311.     if ((vp = varlookup(name)) == NULL)
  312.     return(NULL);
  313.     return(vp->def);
  314. }
  315.  
  316.  
  317. VARDEF *
  318. varlookup(name)                 /* look up a variable */
  319. char  *name;
  320. {
  321.     int  lvl = 0;
  322.     register char  *qname;
  323.     register VARDEF  *vp;
  324.                 /* find most qualified match */
  325.     while ((qname = qualname(name, lvl++)) != NULL)
  326.     for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
  327.         if (!strcmp(vp->name, qname))
  328.         return(vp);
  329.     return(NULL);
  330. }
  331.  
  332.  
  333. VARDEF *
  334. varinsert(name)                 /* get a link to a variable */
  335. char  *name;
  336. {
  337.     register VARDEF  *vp;
  338.     int  hv;
  339.     
  340.     if ((vp = varlookup(name)) != NULL) {
  341.     vp->nlinks++;
  342.     return(vp);
  343.     }
  344.     vp = (VARDEF *)emalloc(sizeof(VARDEF));
  345. #ifdef  FUNCTION
  346.     vp->lib = liblookup(name);
  347. #else
  348.     vp->lib = NULL;
  349. #endif
  350.     if (vp->lib == NULL)                /* if name not in library */
  351.     name = qualname(name, 0);       /* use fully qualified version */
  352.     hv = hash(name);
  353.     vp->name = savestr(name);
  354.     vp->nlinks = 1;
  355.     vp->def = NULL;
  356.     vp->next = hashtbl[hv];
  357.     hashtbl[hv] = vp;
  358.     return(vp);
  359. }
  360.  
  361.  
  362. #ifdef  FUNCTION
  363. libupdate(fn)                   /* update library links */
  364. char  *fn;
  365. {
  366.     register int  i;
  367.     register VARDEF  *vp;
  368.                     /* if fn is NULL then relink all */
  369.     for (i = 0; i < NHASH; i++)
  370.     for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
  371.         if (vp->lib != NULL || fn == NULL || !strcmp(fn, vp->name))
  372.         vp->lib = liblookup(vp->name);
  373. }
  374. #endif
  375.  
  376.  
  377. varfree(ln)                             /* release link to variable */
  378. register VARDEF  *ln;
  379. {
  380.     register VARDEF  *vp;
  381.     int  hv;
  382.  
  383.     if (--ln->nlinks > 0)
  384.     return;                         /* still active */
  385.  
  386.     hv = hash(ln->name);
  387.     vp = hashtbl[hv];
  388.     if (vp == ln)
  389.     hashtbl[hv] = vp->next;
  390.     else {
  391.     while (vp->next != ln)          /* must be in list */
  392.         vp = vp->next;
  393.     vp->next = ln->next;
  394.     }
  395.     freestr(ln->name);
  396.     efree((char *)ln);
  397. }
  398.  
  399.  
  400. EPNODE *
  401. dfirst()                        /* return pointer to first definition */
  402. {
  403.     htndx = 0;
  404.     htpos = NULL;
  405. #ifdef  OUTCHAN
  406.     ochpos = outchan;
  407. #endif
  408.     return(dnext());
  409. }
  410.  
  411.  
  412. EPNODE *
  413. dnext()                         /* return pointer to next definition */
  414. {
  415.     register EPNODE  *ep;
  416.     register char  *nm;
  417.  
  418.     while (htndx < NHASH) {
  419.     if (htpos == NULL)
  420.         htpos = hashtbl[htndx++];
  421.     while (htpos != NULL) {
  422.         ep = htpos->def;
  423.         nm = htpos->name;
  424.         htpos = htpos->next;
  425.         if (ep != NULL && incontext(nm))
  426.         return(ep);
  427.     }
  428.     }
  429. #ifdef  OUTCHAN
  430.     if ((ep = ochpos) != NULL)
  431.     ochpos = ep->sibling;
  432.     return(ep);
  433. #else
  434.     return(NULL);
  435. #endif
  436. }
  437.  
  438.  
  439. EPNODE *
  440. dpop(name)                      /* pop a definition */
  441. char  *name;
  442. {
  443.     register VARDEF  *vp;
  444.     register EPNODE  *dp;
  445.     
  446.     if ((vp = varlookup(name)) == NULL || vp->def == NULL)
  447.     return(NULL);
  448.     dp = vp->def;
  449.     vp->def = dp->sibling;
  450.     varfree(vp);
  451.     return(dp);
  452. }
  453.  
  454.  
  455. dpush(nm, ep)                   /* push on a definition */
  456. char  *nm;
  457. register EPNODE  *ep;
  458. {
  459.     register VARDEF  *vp;
  460.  
  461.     vp = varinsert(nm);
  462.     ep->sibling = vp->def;
  463.     vp->def = ep;
  464. }
  465.  
  466.  
  467. #ifdef  OUTCHAN
  468. addchan(sp)                     /* add an output channel assignment */
  469. EPNODE  *sp;
  470. {
  471.     int  ch = sp->v.kid->v.chan;
  472.     register EPNODE  *ep, *epl;
  473.  
  474.     for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
  475.     if (ep->v.kid->v.chan >= ch) {
  476.         if (epl != NULL)
  477.         epl->sibling = sp;
  478.         else
  479.         outchan = sp;
  480.         if (ep->v.kid->v.chan > ch)
  481.         sp->sibling = ep;
  482.         else {
  483.         sp->sibling = ep->sibling;
  484.         epfree(ep);
  485.         }
  486.         return;
  487.     }
  488.     if (epl != NULL)
  489.     epl->sibling = sp;
  490.     else
  491.     outchan = sp;
  492.     sp->sibling = NULL;
  493.  
  494. }
  495. #endif
  496.  
  497.  
  498. getstatement()                  /* get next statement */
  499. {
  500.     register EPNODE  *ep;
  501.     char  *qname;
  502.     register VARDEF  *vdef;
  503.  
  504.     if (nextc == ';') {         /* empty statement */
  505.     scan();
  506.     return;
  507.     }
  508. #ifdef  OUTCHAN
  509.     if (nextc == '$') {         /* channel assignment */
  510.     ep = getchan();
  511.     addchan(ep);
  512.     } else
  513. #endif
  514.     {                           /* ordinary definition */
  515.     ep = getdefn();
  516.     qname = qualname(dname(ep), 0);
  517. #ifdef  REDEFW
  518.     if ((vdef = varlookup(qname)) != NULL)
  519.         if (vdef->def != NULL) {
  520.         wputs(qname);
  521.         if (vdef->def->type == ':')
  522.             wputs(": redefined constant expression\n");
  523.         else
  524.             wputs(": redefined\n");
  525.         }
  526. #ifdef  FUNCTION
  527.         else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
  528.         wputs(qname);
  529.         wputs(": definition hides library function\n");
  530.         }
  531. #endif
  532. #endif
  533.     if (ep->type == ':')
  534.         dremove(qname);
  535.     else
  536.         dclear(qname);
  537.     dpush(qname, ep);
  538.     }
  539.     if (nextc != EOF) {
  540.     if (nextc != ';')
  541.         syntax("';' expected");
  542.     scan();
  543.     }
  544. }
  545.  
  546.  
  547. EPNODE *
  548. getdefn()                       /* A -> SYM = E1 */
  549.                 /*      SYM : E1 */
  550.                 /*      FUNC(SYM,..) = E1 */
  551.                 /*      FUNC(SYM,..) : E1 */
  552. {
  553.     register EPNODE  *ep1, *ep2;
  554.  
  555.     if (!isalpha(nextc) && nextc != CNTXMARK)
  556.     syntax("illegal variable name");
  557.  
  558.     ep1 = newnode();
  559.     ep1->type = SYM;
  560.     ep1->v.name = savestr(getname());
  561.  
  562. #ifdef  FUNCTION
  563.     if (nextc == '(') {
  564.     ep2 = newnode();
  565.     ep2->type = FUNC;
  566.     addekid(ep2, ep1);
  567.     ep1 = ep2;
  568.     do {
  569.         scan();
  570.         if (!isalpha(nextc))
  571.         syntax("illegal variable name");
  572.         ep2 = newnode();
  573.         ep2->type = SYM;
  574.         ep2->v.name = savestr(getname());
  575.         addekid(ep1, ep2);
  576.     } while (nextc == ',');
  577.     if (nextc != ')')
  578.         syntax("')' expected");
  579.     scan();
  580.     curfunc = ep1;
  581.     } else
  582.     curfunc = NULL;
  583. #endif
  584.  
  585.     if (nextc != '=' && nextc != ':')
  586.     syntax("'=' or ':' expected");
  587.  
  588.     ep2 = newnode();
  589.     ep2->type = nextc;
  590.     scan();
  591.     addekid(ep2, ep1);
  592.     addekid(ep2, getE1());
  593.  
  594.     if (
  595. #ifdef  FUNCTION
  596.         ep1->type == SYM &&
  597. #endif
  598.         ep1->sibling->type != NUM) {
  599.     ep1 = newnode();
  600.     ep1->type = TICK;
  601.     ep1->v.tick = -1;
  602.     addekid(ep2, ep1);
  603.     ep1 = newnode();
  604.     ep1->type = NUM;
  605.     addekid(ep2, ep1);
  606.     }
  607.  
  608.     return(ep2);
  609. }
  610.  
  611.  
  612. #ifdef  OUTCHAN
  613. EPNODE *
  614. getchan()                       /* A -> $N = E1 */
  615. {
  616.     register EPNODE  *ep1, *ep2;
  617.  
  618.     if (nextc != '$')
  619.     syntax("missing '$'");
  620.     scan();
  621.  
  622.     ep1 = newnode();
  623.     ep1->type = CHAN;
  624.     ep1->v.chan = getinum();
  625.  
  626.     if (nextc != '=')
  627.     syntax("'=' expected");
  628.     scan();
  629.  
  630.     ep2 = newnode();
  631.     ep2->type = '=';
  632.     addekid(ep2, ep1);
  633.     addekid(ep2, getE1());
  634.  
  635.     return(ep2);
  636. }
  637. #endif
  638.  
  639.  
  640.  
  641. /*
  642.  *  The following routines are for internal use only:
  643.  */
  644.  
  645.  
  646. static double
  647. dvalue(name, d)                 /* evaluate a variable */
  648. char  *name;
  649. EPNODE  *d;
  650. {
  651.     register EPNODE  *ep1, *ep2;
  652.     
  653.     if (d == NULL || d->v.kid->type != SYM) {
  654.     eputs(name);
  655.     eputs(": undefined variable\n");
  656.     quit(1);
  657.     }
  658.     ep1 = d->v.kid->sibling;                    /* get expression */
  659.     if (ep1->type == NUM)
  660.     return(ep1->v.num);                     /* return if number */
  661.     ep2 = ep1->sibling;                         /* check time */
  662.     if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
  663.     ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
  664.     ep2 = ep2->sibling;
  665.     ep2->v.num = evalue(ep1);               /* needs new value */
  666.     } else
  667.     ep2 = ep2->sibling;                     /* else reuse old value */
  668.  
  669.     return(ep2->v.num);
  670. }
  671.  
  672.  
  673. static int
  674. hash(s)                         /* hash a string */
  675. register char  *s;
  676. {
  677.     register int  rval = 0;
  678.  
  679.     while (*s)
  680.     rval += *s++;
  681.     
  682.     return(rval % NHASH);
  683. }
  684.