home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / formats / ttddd / spec / t3d_doc / igensurf.zoo / src / caldefn.c < prev    next >
C/C++ Source or Header  |  1991-09-28  |  15KB  |  627 lines

  1. /* :ts=8 */
  2. /* Copyright (c) 1991 Regents of the University of California */
  3.  
  4. #include  <stdio.h>
  5. #include  <ctype.h>
  6.  
  7. #include  "calcomp.h"
  8. #include  "calc.h"
  9.  
  10. #ifndef  NHASH
  11. #define  NHASH        521        /* hash size (a prime!) */
  12. #endif
  13.  
  14. #define  New_Node()    (Expression_T *)Ecalloc(1, sizeof(Expression_T))
  15.  
  16. extern char  *Ecalloc(), *savestr();
  17.  
  18. static double  Var_Value1();
  19.  
  20. long  eclock = -1;            /* value storage timer */
  21. int   (*Command_Func)();
  22.  
  23. static Variable_T  *Hash_Table[NHASH];        /* definition list */
  24. static int         Hash_Index;
  25. static Variable_T  *Hash_Pos;
  26.  
  27. Expression_T  *Current_Function;
  28.  
  29. #define  Expr_Name(Expr) ((Expr)->Value.Kid->Node_Type == ET_Symbol ? \
  30.              (Expr)->Value.Kid->Value.Name : \
  31.              (Expr)->Value.Kid->Value.Kid->Value.Name)
  32.  
  33. void File_Compile(File_Name, N_Command_Func)
  34. char  *File_Name;
  35. int   (*N_Command_Func)();
  36. /************************************************************************/
  37. /*                                    */
  38. /* get definitions from a file                         */
  39. /*                                    */
  40. /* Command_Func is the function which should be called when a line    */
  41. /* starting with '#' is found. The function will be called with the    */
  42. /* following arguments :                         */
  43. /*                                    */
  44. /*   Command_Func(char *Line, int Line_Number)                */
  45. /*                                    */
  46. /* Where 'Line' is the contents of the line, and 'Line_Number' is the    */
  47. /* current line number.                            */
  48. /*                                    */
  49. /* Command_Func may be NULL.                        */
  50. /*                                    */
  51. /************************************************************************/
  52. {
  53.     FILE  *fp;
  54.  
  55.     Command_Func = N_Command_Func;
  56.  
  57.     if (File_Name == NULL) {
  58.  
  59.         fp = stdin;
  60.  
  61.     } else if ((fp = fopen(File_Name, "r")) == NULL) {
  62.  
  63.     fprintf(stderr, "%s : cannot open\n", File_Name);
  64.     exit(1);
  65.  
  66.     }
  67.  
  68.     Init_File(fp, File_Name, 0);
  69.  
  70.     while (Next_Char != EOF) Expr_Compile();
  71.  
  72.     if (File_Name != NULL) fclose(fp);
  73.  
  74.     Command_Func = NULL;
  75.  
  76. } /* File_Compile */
  77.  
  78.  
  79. void String_Compile(str, fn, ln, N_Command_Func)
  80. char  *str;
  81. char  *fn;
  82. int  ln;
  83. int   (*N_Command_Func)();
  84. /************************************************************************/
  85. /*                                    */
  86. /* get definitions from a string                     */
  87. /*                                    */
  88. /* Command_Func is the function which should be called when a line    */
  89. /* starting with '#' is found. The function will be called with the    */
  90. /* following arguments :                         */
  91. /*                                    */
  92. /*   Command_Func(char *Line, int Line_Number)                */
  93. /*                                    */
  94. /* Where 'Line' is the contents of the line, and 'Line_Number' is the    */
  95. /* current line number.                            */
  96. /*                                    */
  97. /* Command_Func may be NULL.                        */
  98. /*                                    */
  99. /************************************************************************/
  100. {
  101.  
  102.     Command_Func = N_Command_Func;
  103.     Init_Str(str, fn, ln);
  104.  
  105.     while (Next_Char != EOF) Expr_Compile();
  106.  
  107.     Command_Func = NULL;
  108.  
  109. } /* String_Compile */
  110.  
  111.  
  112. double Var_Value(Name)
  113. char  *Name;
  114. /************************************************************************/
  115. /*                                    */
  116. /* return a variable's value                         */
  117. /*                                    */
  118. /************************************************************************/
  119. {
  120.     return(Var_Value1(Name, Expr_Lookup(Name)));
  121.  
  122. } /* Var_Value */
  123.  
  124.  
  125. double EFunc_Variable(Expr)    
  126. Expression_T  *Expr;
  127. /************************************************************************/
  128. /*                                    */
  129. /* evaluate a variable                             */
  130. /*                                    */
  131. /************************************************************************/
  132. {
  133.     register Variable_T  *dp = Expr->Value.Variable;
  134.  
  135.     return(Var_Value1(dp->Name, dp->Expression));
  136.  
  137. } /* EFunc_Variable */
  138.  
  139.  
  140. void Var_Set(Name, Assignment_Type, Value)
  141. char  *Name;
  142. int  Assignment_Type;
  143. double  Value;
  144. /************************************************************************/
  145. /*                                    */
  146. /* set a variable's value*/
  147. /*                                    */
  148. /************************************************************************/
  149. {
  150.     register Expression_T  *Expr1, *Expr2;
  151.  
  152.                     /* check for quick set */
  153.  
  154.     if ((Expr1 = Expr_Lookup(Name)) != NULL && 
  155.         Expr1->Value.Kid->Node_Type == ET_Symbol) {
  156.  
  157.     Expr2 = Expr1->Value.Kid->Sibling;
  158.  
  159.     if (Expr2->Node_Type == ET_Number) {
  160.  
  161.         Expr2->Value.Number = Value;
  162.         Expr1->Node_Type = Assignment_Type;
  163.         return;
  164.  
  165.     } /* if */
  166.  
  167.     } /* if */
  168.                     /* hand build definition */
  169.     Expr1         = New_Node();
  170.     Expr1->Node_Type     = Assignment_Type;
  171.  
  172.     Expr2         = New_Node();
  173.     Expr2->Node_Type      = ET_Symbol;
  174.     Expr2->Value.Name     = savestr(Name);
  175.  
  176.     Add_Kid(Expr1, Expr2);
  177.  
  178.     Expr2         = New_Node();
  179.     Expr2->Node_Type    = ET_Number;
  180.     Expr2->Value.Number = Value;
  181.  
  182.     Add_Kid(Expr1, Expr2);
  183.  
  184.     Expr_Remove(Name);
  185.  
  186.     Expr_Push(Expr1);
  187.  
  188. } /* Var_Set */
  189.  
  190.  
  191. void Expr_Clear(Name)
  192. char  *Name;
  193. /************************************************************************/
  194. /*                                    */
  195. /* delete variable definitions of name                     */
  196. /*                                    */
  197. /************************************************************************/
  198. {
  199.     register Expression_T  *Expr;
  200.  
  201.     while ((Expr = Expr_Pop(Name)) != NULL) {
  202.  
  203.     if (Expr->Node_Type == ':') {
  204.         Expr_Push(Expr);        /* don't clear constants */
  205.         return;
  206.     } /* if */
  207.  
  208.     Expr_Free(Expr);
  209.  
  210.     } /* while */
  211.  
  212. } /* Expr_Clear */
  213.  
  214.  
  215. void Expr_Remove(Name)
  216. char  *Name;
  217. /************************************************************************/
  218. /*                                    */
  219. /* delete all definitions of name                     */
  220. /*                                    */
  221. /************************************************************************/
  222. {
  223.     register Expression_T  *Expr;
  224.  
  225.     while ((Expr = Expr_Pop(Name)) != NULL) Expr_Free(Expr);
  226.  
  227. } /* Expr_Remove */
  228.  
  229.  
  230. int Var_Defined(Name)
  231. char  *Name;
  232. /************************************************************************/
  233. /*                                    */
  234. /* return non-zero if variable defined                     */
  235. /*                                    */
  236. /************************************************************************/
  237. {
  238.     register Expression_T  *dp;
  239.  
  240.     return((dp = Expr_Lookup(Name)) != NULL && 
  241.            dp->Value.Kid->Node_Type == ET_Symbol);
  242.  
  243. } /* Var_Defined */
  244.  
  245.  
  246. void Expr_Cleanup(Level)
  247. int  Level;
  248. /************************************************************************/
  249. /*                                    */
  250. /* clear definitions (0->vars,1->consts)                 */
  251. /*                                    */
  252. /************************************************************************/
  253. {
  254.     register int         i;
  255.     register Variable_T  *vp;
  256.  
  257.     for (i = 0; i < NHASH; i++) {
  258.  
  259.     for (vp = Hash_Table[i]; vp != NULL; vp = vp->Next) {
  260.  
  261.         if (Level >= 1) Expr_Remove(vp->Name);
  262.         else            Expr_Clear(vp->Name);
  263.  
  264.     } /* for */
  265.  
  266.     } /* for */
  267.  
  268. } /* Expr_Cleanup */
  269.  
  270.  
  271. Expression_T *Expr_Lookup(Name)
  272. char  *Name;
  273. /************************************************************************/
  274. /*                                    */
  275. /* look up a definition                         */
  276. /*                                    */
  277. /************************************************************************/
  278. {
  279.     register Variable_T  *vp;
  280.     
  281.     if ((vp = Var_Lookup(Name)) == NULL) return(NULL);
  282.     return(vp->Expression);
  283.  
  284. } /* Expr_Lookup */
  285.  
  286.  
  287. Variable_T *Var_Lookup(Name)
  288. char  *Name;
  289. /************************************************************************/
  290. /*                                    */
  291. /* look up a variable                             */
  292. /*                                    */
  293. /************************************************************************/
  294. {
  295.     register Variable_T  *vp;
  296.     
  297.     for (vp = Hash_Table[Hash_Value(Name)]; vp != NULL; vp = vp->Next) {
  298.  
  299.         if (!strcmp(vp->Name, Name)) return(vp);
  300.  
  301.     } /* for */
  302.  
  303.     return(NULL);
  304.  
  305. } /* Var_Lookup */
  306.  
  307.  
  308. Variable_T *Var_Insert(Name)
  309. char  *Name;
  310. /************************************************************************/
  311. /*                                    */
  312. /* get a link to a variable                         */
  313. /*                                    */
  314. /************************************************************************/
  315. {
  316.     register Variable_T  *vp;
  317.     int  hv;
  318.     
  319.     hv = Hash_Value(Name);
  320.  
  321.     for (vp = Hash_Table[hv]; vp != NULL; vp = vp->Next) {
  322.  
  323.         if (!strcmp(vp->Name, Name)) {
  324.  
  325.             vp->Number_Links++;
  326.             return(vp);
  327.  
  328.         } /* if */
  329.  
  330.     } /* for */
  331.  
  332.     vp = (Variable_T *)Emalloc(sizeof(Variable_T));
  333.  
  334.     vp->Name = savestr(Name);
  335.     vp->Number_Links = 1;
  336.     vp->Expression = NULL;
  337.     vp->Function = NULL;
  338.     vp->Next = Hash_Table[hv];
  339.  
  340.     Hash_Table[hv] = vp;
  341.  
  342.     return(vp);
  343.  
  344. } /* Var_Insert */
  345.  
  346.  
  347. Var_Free(Variable)
  348. register Variable_T  *Variable;
  349. /************************************************************************/
  350. /*                                    */
  351. /* release link to variable                         */
  352. /*                                    */
  353. /************************************************************************/
  354. {
  355.     register Variable_T  *vp;
  356.     int  hv;
  357.  
  358.     if (--Variable->Number_Links > 0) return;    /* still active */
  359.  
  360.     hv = Hash_Value(Variable->Name);
  361.     vp = Hash_Table[hv];
  362.  
  363.     if (vp == Variable) Hash_Table[hv] = vp->Next;
  364.     else {
  365.  
  366.         while (vp->Next != Variable) vp = vp->Next; /* must be in list */
  367.         vp->Next = Variable->Next;
  368.  
  369.     } 
  370.  
  371.     freestr(Variable->Name);
  372.  
  373.     Efree((char *)Variable);
  374.  
  375. } /* Var_Free */
  376.  
  377.  
  378. Expression_T *Expr_First()
  379. /************************************************************************/
  380. /*                                    */
  381. /* return pointer to first definition                     */
  382. /*                                    */
  383. /************************************************************************/
  384. {
  385.     Hash_Index = 0;
  386.     Hash_Pos = NULL;
  387.  
  388.     return(Expr_Next());
  389.  
  390. } /* Expr_First */
  391.  
  392.  
  393. Expression_T *Expr_Next()
  394. /************************************************************************/
  395. /*                                    */
  396. /* return pointer to next definition                     */
  397. /*                                    */
  398. /************************************************************************/
  399. {
  400.     register Expression_T  *Expr;
  401.  
  402.     while (Hash_Index < NHASH) {
  403.  
  404.         if (Hash_Pos == NULL) Hash_Pos = Hash_Table[Hash_Index++];
  405.  
  406.         while (Hash_Pos != NULL) {
  407.  
  408.             Expr = Hash_Pos->Expression;
  409.             Hash_Pos = Hash_Pos->Next;
  410.  
  411.             if (Expr != NULL) return(Expr);
  412.  
  413.         } /* while */
  414.  
  415.     } /* while */
  416.  
  417.     return(NULL);
  418.  
  419. } /* Expr_Next */
  420.  
  421.  
  422. Expression_T *Expr_Pop(Name)
  423. char  *Name;
  424. /************************************************************************/
  425. /*                                    */
  426. /* pop a definition                             */
  427. /*                                    */
  428. /************************************************************************/
  429. {
  430.     register Variable_T  *vp;
  431.     register Expression_T  *dp;
  432.     
  433.     if ((vp = Var_Lookup(Name)) == NULL || 
  434.                     vp->Expression == NULL) return(NULL);
  435.     dp = vp->Expression;
  436.     vp->Expression = dp->Sibling;
  437.  
  438.     Var_Free(vp);
  439.  
  440.     return(dp);
  441.  
  442. } /* Expr_Pop */
  443.  
  444.  
  445. Expr_Push(Expr)
  446. register Expression_T  *Expr;
  447. /************************************************************************/
  448. /*                                    */
  449. /* push on a definition                         */
  450. /*                                    */
  451. /************************************************************************/
  452. {
  453.     register Variable_T  *vp;
  454.  
  455.     vp = Var_Insert(Expr_Name(Expr));
  456.     Expr->Sibling = vp->Expression;
  457.     vp->Expression = Expr;
  458.  
  459. } /* Expr_Push */
  460.  
  461.  
  462. Expr_Compile()
  463. /************************************************************************/
  464. /*                                    */
  465. /* load next definition                         */
  466. /*                                    */
  467. /************************************************************************/
  468. {
  469.     register Expression_T  *Expr;
  470.  
  471.     if (Next_Char == ';') {        /* empty statement */
  472.  
  473.     Get_Next_Char();
  474.     return;
  475.  
  476.     } /* if */
  477.  
  478.                     /* ordinary definition */
  479.     Expr = Expr_Get();
  480.  
  481.     if (Expr->Node_Type == ':') Expr_Remove(Expr_Name(Expr));
  482.     else             Expr_Clear(Expr_Name(Expr));
  483.  
  484.     Expr_Push(Expr);
  485.  
  486.     if (Next_Char != EOF) {
  487.  
  488.     if (Next_Char != ';') Syntax_Error("';' expected");
  489.     Get_Next_Char();
  490.  
  491.     } /* if */
  492.  
  493. } /* Expr_Compile */
  494.  
  495.  
  496. Expression_T *Expr_Get()
  497. /************************************************************************/
  498. /*                                    */
  499. /* Expr -> ET_Symbol = E1                         */
  500. /*       ET_Symbol : E1                         */
  501. /*         ET_Function(ET_Symbol,..) = E1                 */
  502. /*       ET_Function(ET_Symbol,..) : E1                 */
  503. /*                                    */
  504. /************************************************************************/
  505. {
  506.     register Expression_T  *Expr1, *Expr2;
  507.  
  508.     if (!isalpha(Next_Char)) Syntax_Error("illegal variable name");
  509.  
  510.     Expr1 = New_Node();                /* Get the name        */
  511.     Expr1->Node_Type = ET_Symbol;
  512.     Expr1->Value.Name = savestr(Get_Name());
  513.  
  514.     if (Next_Char == '(') {            /* Function definition     */
  515.  
  516.     Expr2 = New_Node();
  517.     Expr2->Node_Type = ET_Function;
  518.  
  519.     Add_Kid(Expr2, Expr1);
  520.  
  521.     Expr1 = Expr2;
  522.  
  523.     do {                    /* Get arguments    */
  524.  
  525.         Get_Next_Char();        
  526.  
  527.         if (!isalpha(Next_Char)) Syntax_Error("illegal variable name");
  528.  
  529.         Expr2 = New_Node();
  530.         Expr2->Node_Type = ET_Symbol;
  531.         Expr2->Value.Name = savestr(Get_Name());
  532.         Add_Kid(Expr1, Expr2);
  533.  
  534.     } while (Next_Char == ',');
  535.  
  536.     if (Next_Char != ')') Syntax_Error("')' expected");
  537.  
  538.     Get_Next_Char();
  539.  
  540.     Current_Function = Expr1;
  541.  
  542.     } else Current_Function = NULL;
  543.  
  544.     if (Next_Char != '=' && 
  545.         Next_Char != ':') Syntax_Error("'=' or ':' expected");
  546.  
  547.     Expr2 = New_Node();
  548.     Expr2->Node_Type = Next_Char;        /* = or :         */
  549.     Get_Next_Char();
  550.  
  551.     Add_Kid(Expr2, Expr1);            
  552.     Add_Kid(Expr2, Get_E1());             /* Get definition (E1)    */
  553.  
  554.     if (Expr1->Node_Type == ET_Symbol &&
  555.     Expr1->Sibling->Node_Type != ET_Number) {
  556.  
  557.     Expr1 = New_Node();
  558.     Expr1->Node_Type = ET_Timestamp;
  559.     Expr1->Value.Timestamp = -1;
  560.  
  561.     Add_Kid(Expr2, Expr1);
  562.  
  563.     Expr1 = New_Node();
  564.     Expr1->Node_Type = ET_Number;
  565.  
  566.     Add_Kid(Expr2, Expr1);
  567.  
  568.     } /* if */
  569.  
  570.     return(Expr2);
  571.  
  572. } /* Expr_Get */
  573.  
  574.  
  575. static double Var_Value1(Name, Expr)
  576. char            *Name;
  577. Expression_T  *Expr;
  578. /************************************************************************/
  579. /*                                    */
  580. /* evaluate a variable                             */
  581. /*                                    */
  582. /************************************************************************/
  583. {
  584.     register Expression_T  *Expr1, *Expr2;
  585.     
  586.     if (Expr == NULL || Expr->Value.Kid->Node_Type != ET_Symbol) {
  587.  
  588.     fprintf(stderr, "%s : undefined variable\n", Name);
  589.     exit(1);
  590.  
  591.     } /* if */
  592.  
  593.     Expr1 = Expr->Value.Kid->Sibling;        /* get expression */
  594.     if (Expr1->Node_Type == ET_Number) return(Expr1->Value.Number);
  595.  
  596.     Expr2 = Expr1->Sibling;            /* check time */
  597.  
  598.     if (Expr2->Value.Timestamp < 0 || Expr2->Value.Timestamp < eclock) {
  599.  
  600.     Expr2->Value.Timestamp = Expr->Node_Type == ':' ? 1L<<30 : eclock;
  601.     Expr2 = Expr2->Sibling;
  602.  
  603.     Expr2->Value.Number = Expr_Value(Expr1);/* needs new value */
  604.  
  605.     } else Expr2 = Expr2->Sibling;        /* else reuse old value */
  606.  
  607.     return(Expr2->Value.Number);
  608.  
  609. } /* Var_Value1 */
  610.  
  611.  
  612. static int Hash_Value(String)
  613. register char  *String;
  614. /************************************************************************/
  615. /*                                    */
  616. /* hash a string                             */
  617. /*                                    */
  618. /************************************************************************/
  619. {
  620.     register int  rval = 0;
  621.  
  622.     while (*String) rval += *String++;
  623.     
  624.     return(rval % NHASH);
  625.  
  626. } /* Hash_Value */
  627.