home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v17n02 / turtle.exe / TEXPR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-03  |  5.4 KB  |  285 lines

  1. /*****************************************************************
  2.  *                                                               *
  3.  * TEXPR.C   Expression evaluator for TURTLE.EXE                 *
  4.  *                                                               *
  5.  * Al Williams                                                   *
  6.  *                                                               *
  7.  *****************************************************************/
  8.  
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <dos.h>
  15. #include "turtle.h"
  16.  
  17. static char *s;
  18.  
  19.  
  20. /* get a numeric value */
  21. int getnum(char *token)
  22.   {
  23.   s=token;
  24.   return _getnum(1);
  25.   }
  26.  
  27.  
  28. /* Internal get numeric value -- set allowneg to 1
  29.    if negative numbers are OK */
  30. int _getnum(int allowneg)
  31.   {
  32.   char *span;
  33.   int n,val;
  34. /* process negative number */
  35.   if (allowneg&&*s=='-')
  36.     {
  37.     s++;
  38.     return -getnum(0);
  39.     }
  40.  
  41. /* is it an internal variable ? */
  42.   if (*s=='%')
  43.     {
  44.     s++;
  45.     return specialvar();
  46.     }
  47.  
  48. /* Is it a user variable (A-Z)? */
  49.   if (isalpha(*s))
  50.     {
  51.     val=(int)appdata.vars[toupper(*s)-'A'];
  52.     s++;
  53.     return val;
  54.     }
  55.  
  56. /* Is it a hex number (0x...)? */
  57.   if (*s=='0'&&(*(s+1)=='x'||*(s+1)=='X'))
  58.     {
  59.     span="0123456789ABCDEFabcdef";
  60.     sscanf(s+=2,"%x",&val);
  61.     }
  62.   else
  63.     {
  64. /* normal number */
  65.     val=atoi(s);
  66.     span="0123456789";
  67.     }
  68. /* skip over decimal or hex digits */
  69.   s+=strspn(s,span);
  70.   return val;
  71.   }
  72.  
  73.  
  74. /* process special internal variables */
  75. int specialvar()
  76.   {
  77.   static seeded=0;   /* has random number been seeded? */
  78.   int op=*s++;
  79.   op=toupper(op);
  80.  
  81. /* %i numeric input */
  82.   if (op=='I')
  83.     {
  84.     char inbuf[81];
  85.     fgets(inbuf,sizeof(inbuf),stdin);
  86.     return atoi(inbuf);
  87.     }
  88.  
  89. /* %r random number */
  90.   if (op=='R')
  91.     {
  92.     if (!seeded)
  93.       {
  94.       struct dostime_t dostime;
  95.       seeded=1;
  96.       _dos_gettime(&dostime);
  97.       srand(dostime.hsecond);
  98.       }
  99.     return rand();
  100.     }
  101.  
  102. /* %x X coordinate */
  103.   if (op=='X')
  104.      return appdata.graphxy.xcoord;
  105.  
  106. /* %y Y coordinate */
  107.   if (op=='Y')
  108.      return appdata.graphxy.ycoord;
  109.  
  110. /* %c Color */
  111.   if (op=='C')
  112.      return appdata.color;
  113.  
  114. /* %h Heading */
  115.   if (op=='H')
  116.      return appdata.heading;
  117.  
  118.   return 0;
  119.   }
  120.  
  121.  
  122.  
  123. #define LE 256
  124. #define GE 257
  125.  
  126.  
  127. /* expression error */
  128. eerror()
  129.   {
  130.   printf("Expression error\n");
  131.   return 0;
  132.   }
  133.  
  134.  
  135. /* stack size for expression parse */
  136. #define STKSIZE 100
  137.  
  138. /* stack for values */
  139. int valstack[STKSIZE];
  140. /* top of valstack */
  141. int valstackp=0;
  142.  
  143. /* stack for operators */
  144. int opstack[STKSIZE];
  145. /* top of opstack */
  146. int opstackp=0;
  147.  
  148. /* Push, pop, and get top of stack */
  149. #define push(stk,val) (stk##p<(STKSIZE-1)?stk[stk##p++]=\
  150.                        val:stkerr())
  151. #define pop(stk)      (stk[--stk##p])
  152. #define tos(stk)      (stk[stk##p-1])
  153.  
  154. /* tell user about stack overflow */
  155. stkerr()
  156.   {
  157.   printf("Expression too complex\n");
  158.   return 0;
  159.   }
  160.  
  161.  
  162. /* external interface to evaluate expression in sin */
  163. int evalexpr(char *sin)
  164. {
  165.         int val;
  166.         s=sin;
  167.         val=e_expr();
  168. /* if parser didn't read all of string -- error */
  169.         if (*(s-1)) eerror();
  170.         return val;
  171. }
  172.  
  173.  
  174. /* Expression/subexpression parser */
  175. int e_expr()
  176.   {
  177.   int op='+';
  178.   int value;
  179.   int topstack=opstackp;
  180. /* Initilize stack */
  181.   push(opstack,'+');
  182.   push(valstack,0);
  183.  
  184. /* end at end of string or close paren */
  185.   while (op&&op!=')')
  186.     {
  187. /* If open paren do a recursive call to get value */
  188.     if (*s=='(')
  189.       {
  190.       s++;
  191.       value=e_expr();
  192.       if (*(s-1)!=')') ;  /* error if paren not matched */
  193.       }
  194.     else
  195. /* get a number or variable */
  196.       value=_getnum(1);
  197. /* push it on */
  198.     push(valstack,value);
  199. /* read an operator */
  200.     op=*s++;
  201. /* see if two character (>= or <=) */
  202.     if (op=='>'&&*s=='=') { op=GE; s++; }
  203.     if (op=='<'&&*s=='=') { op=LE; s++; }
  204.  
  205. /* do calculations allowed by precedence */
  206.     while ((opstackp!=topstack)&&prec(tos(opstack))>=prec(op))
  207.       perform(pop(opstack));
  208.  
  209. /* push new operator on stack */
  210.     push(opstack,op);
  211.     }
  212.    pop(opstack);
  213.    return pop(valstack);
  214.    }
  215.  
  216. /* find precedence for given operator */
  217. prec(int op)
  218.   {
  219.   switch (op)
  220.     {
  221.     case 0:
  222.     case ')': return 0;
  223.  
  224.     case '<':
  225.     case '>':
  226.     case LE:
  227.     case GE:
  228.     case '=':
  229.     case '#': return 1;
  230.  
  231.     case '&':
  232.     case '|': return 2;
  233.  
  234.     case '-':
  235.     case '+': return 3;
  236.  
  237.     case '/':
  238.     case '%':
  239.     case '*': return 4;
  240.     }
  241.   }
  242.  
  243. /* carry out operator on two top stack elements */
  244. perform(int op)
  245.   {
  246.   int value,v1,v2;
  247.   v1=pop(valstack);
  248.   v2=pop(valstack);
  249.   switch (op)
  250.     {
  251.     case '+':
  252.               value=v2+v1;
  253.               break;
  254.     case '-': value=v2-v1;
  255.               break;
  256.     case '*': value=v2*v1;
  257.               break;
  258.     case '/': value=v2/v1;
  259.               break;
  260.     case '%': value=v2%v1;
  261.               break;
  262.     case '=': value=v2==v1;
  263.               break;
  264.     case '#': value=v2!=v1;
  265.               break;
  266.     case '<': value=v2<v1;
  267.               break;
  268.     case '>': value=v2>v1;
  269.               break;
  270.     case LE:  value=v2<=v1;
  271.               break;
  272.     case GE:  value=v2>=v1;
  273.               break;
  274.     case '&': value=v2&&v1;
  275.               break;
  276.     case '|': value=v2||v1;
  277.               break;
  278.     }
  279.   push(valstack,value);
  280.   }
  281.  
  282.  
  283.  
  284.  
  285.