home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / tc20 / mcparser.c < prev    next >
Text File  |  1988-10-13  |  12KB  |  602 lines

  1. /* Turbo C - (C) Copyright 1987,1988 by Borland International */
  2.  
  3. #include <string.h>
  4. #include <math.h>
  5. #include <ctype.h>
  6. #include <errno.h>
  7. #include <stdio.h>
  8. #include "mcalc.h"
  9.  
  10. #define PLUS 0
  11. #define MINUS 1
  12. #define TIMES 2
  13. #define DIVIDE 3
  14. #define EXP 4
  15. #define COLON 5
  16. #define OPAREN 6
  17. #define CPAREN 7
  18. #define NUM 8
  19. #define CELL 9
  20. #define FUNC 10
  21. #define EOLN 11
  22. #define BAD 12
  23. #define MAXFUNCNAMELEN 5
  24.  
  25. struct TOKENREC
  26. {
  27.  char state;
  28.  union
  29.  {
  30.   double value;
  31.   struct
  32.   {
  33.    int row, col;
  34.   } c;
  35.   char funcname[MAXFUNCNAMELEN + 1];
  36.  } x;
  37. };
  38.  
  39. static struct TOKENREC stack[PARSERSTACKSIZE], curtoken;
  40. int stacktop, tokentype, error;
  41. char *input, isformula;
  42.  
  43. int matherr(struct exception *e)
  44. {
  45.  e->retval = HUGE_VAL;
  46.  return(1);
  47. } /* matherr */
  48.  
  49. int isfunc(char *s)
  50. /* Returns TRUE if the string is a legal function, FALSE otherwise. */
  51. {
  52.  int len = strlen(s);
  53.  
  54.  if (strncmp(s, input, len) == 0)
  55.  {
  56.   strncpy(curtoken.x.funcname, input, len);
  57.   curtoken.x.funcname[len] = 0;
  58.   input += len;
  59.   return(TRUE);
  60.  }
  61.  return(FALSE);
  62. } /* isfunc */
  63.  
  64. int nexttoken(void)
  65. /* Gets the next token from the input stream */
  66. {
  67.  char *start, numstring[80];
  68.  int decimal, len, numlen;
  69.  
  70.  while (*input == ' ')
  71.   input++;
  72.  if (*input == 0)
  73.   return(EOLN);
  74.  if (strchr("0123456789.", *input))
  75.  {
  76.   start = input;
  77.   len = 0;
  78.   decimal = FALSE;
  79.   while ((isdigit(*input)) ||
  80.    ((*input == '.') && (!decimal)))
  81.   {
  82.    if (*input == '.')
  83.     decimal = TRUE;
  84.    input++;
  85.    len++;
  86.   }
  87.   if ((len == 1) && (start[0] == '.'))
  88.    return(BAD);
  89.   if (*input == 'E')
  90.   {
  91.    input++;
  92.    len++;
  93.    if (strchr("+-", *input) != NULL)
  94.    {
  95.     input++;
  96.     len++;
  97.    }
  98.    numlen = 0;
  99.    while ((isdigit(*input)) && (++numlen <= 3))
  100.    {
  101.     input++;
  102.     len++;
  103.    }
  104.   }
  105.   strncpy(numstring, start, len);
  106.   numstring[len] = 0;
  107.   curtoken.x.value = atof(numstring);
  108.   if (errno == ERANGE)
  109.    return(BAD);
  110.   return(NUM);
  111.  }
  112.  else if (isalpha(*input))
  113.  {
  114.   if
  115.   (isfunc("ABS") ||
  116.    isfunc("ACOS") ||
  117.    isfunc("ASIN") ||
  118.    isfunc("ATAN") ||
  119.    isfunc("COSH") ||
  120.    isfunc("COS") ||
  121.    isfunc("EXP") ||
  122.    isfunc("LOG10") ||
  123.    isfunc("LOG") ||
  124.    isfunc("POW10") ||
  125.    isfunc("ROUND") ||
  126.    isfunc("SINH") ||
  127.    isfunc("SIN") ||
  128.    isfunc("SQRT") ||
  129.    isfunc("SQR") ||
  130.    isfunc("TANH") ||
  131.    isfunc("TAN") ||
  132.    isfunc("TRUNC"))
  133.     return(FUNC);
  134.   if (formulastart(&input, &curtoken.x.c.col, &curtoken.x.c.row))
  135.   {
  136.    isformula = TRUE;
  137.    return(CELL);
  138.   }
  139.   else
  140.    return(BAD);
  141.  }
  142.  else switch(*(input++))
  143.  {
  144.   case '+' : return(PLUS);
  145.   case '-' : return(MINUS);
  146.   case '*' : return(TIMES);
  147.   case '/' : return(DIVIDE);
  148.   case '^' : return(EXP);
  149.   case ':' : return(COLON);
  150.   case '(' : return(OPAREN);
  151.   case ')' : return(CPAREN);
  152.   default  : return(BAD);
  153.  } /* switch */
  154. } /* nexttoken */
  155.  
  156. void push(struct TOKENREC *token)
  157. /* Pushes a new token onto the stack */
  158. {
  159.  if (stacktop == PARSERSTACKSIZE - 1)
  160.  {
  161.   errormsg(MSGSTACKERROR);
  162.   error = TRUE;
  163.  }
  164.  else
  165.   stack[++stacktop] = *token;
  166. } /* push */
  167.  
  168. struct TOKENREC pop(void)
  169. /* Pops the top token off of the stack */
  170. {
  171.  return(stack[stacktop--]);
  172. } /* pop */
  173.  
  174. int gotostate(int production)
  175. /* Finds the new state based on the last production and the top state. */
  176. {
  177.  int state = stack[stacktop].state;
  178.  
  179.  if (production <= 3)
  180.  {
  181.   switch(state)
  182.   {
  183.    case 0 : return(1);
  184.    case 9 : return(19);
  185.    case 20 : return(28);
  186.   } /* switch */
  187.  }
  188.  else if (production <= 6)
  189.  {
  190.   switch(state)
  191.   {
  192.    case 0 :
  193.    case 9 :
  194.    case 20 : return(2);
  195.    case 12 : return(21);
  196.    case 13 : return(22);
  197.   } /* switch */
  198.  }
  199.  else if (production <= 8)
  200.  {
  201.   switch(state)
  202.   {
  203.    case 0 :
  204.    case 9 :
  205.    case 12 :
  206.    case 13 :
  207.    case 20 : return(3);
  208.    case 14 : return(23);
  209.    case 15 : return(24);
  210.    case 16 : return(25);
  211.   } /* switch */
  212.  }
  213.  else if (production <= 10)
  214.  {
  215.   switch(state)
  216.   {
  217.    case 0 :
  218.    case 9 :
  219.    case 12 :
  220.    case 13 :
  221.    case 14 :
  222.    case 15 :
  223.    case 16 :
  224.    case 20 : return(4);
  225.   } /* switch */
  226.  }
  227.  else if (production <= 12)
  228.  {
  229.   switch(state)
  230.   {
  231.    case 0 :
  232.    case 9 :
  233.    case 12 :
  234.    case 13 :
  235.    case 14 :
  236.    case 15 :
  237.    case 16 :
  238.    case 20 : return(6);
  239.    case 5 : return(17);
  240.   } /* switch */
  241.  }
  242.  else
  243.  {
  244.   switch(state)
  245.   {
  246.    case 0 :
  247.    case 5 :
  248.    case 9 :
  249.    case 12 :
  250.    case 13 :
  251.    case 14 :
  252.    case 15 :
  253.    case 16 :
  254.    case 20 : return(8);
  255.   } /* switch */
  256.  }
  257.  return(30);
  258. } /* gotostate */
  259.  
  260. double cellvalue(int col, int row)
  261. /* Finds the value of a particular cell */
  262. {
  263.  if (cell[col][row] == NULL)
  264.   return(0);
  265.  if (cell[col][row]->attrib == TEXT)
  266.   return(HUGE_VAL);
  267.  if (cell[col][row]->attrib == FORMULA)
  268.   return(cell[col][row]->v.f.fvalue);
  269.  return(cell[col][row]->v.value);
  270. } /* cellvalue */
  271.  
  272. void shift(int state)
  273. /* Shifts a token onto the stack */
  274. {
  275.  curtoken.state = state;
  276.  push(&curtoken);
  277.  tokentype = nexttoken();
  278. } /* shift */
  279.  
  280. void reduce(int reduction)
  281. /* Completes a reduction */
  282. {
  283.  struct TOKENREC token1, token2;
  284.  int counter;
  285.  
  286.  switch (reduction)
  287.  {
  288.   case 1 :
  289.    token1 = pop();
  290.    pop();
  291.    token2 = pop();
  292.    curtoken.x.value = token1.x.value + token2.x.value;
  293.    break;
  294.   case 2 :
  295.    token1 = pop();
  296.    pop();
  297.    token2 = pop();
  298.    curtoken.x.value = token2.x.value - token1.x.value;
  299.    break;
  300.   case 4 :
  301.    token1 = pop();
  302.    pop();
  303.    token2 = pop();
  304.    curtoken.x.value = token1.x.value * token2.x.value;
  305.    break;
  306.   case 5 :
  307.    token1 = pop();
  308.    pop();
  309.    token2 = pop();
  310.    if (token1.x.value == 0)
  311.     curtoken.x.value = HUGE_VAL;
  312.    else
  313.     curtoken.x.value = token2.x.value / token1.x.value;
  314.    break;
  315.   case 7 :
  316.    token1 = pop();
  317.    pop();
  318.    token2 = pop();
  319.    curtoken.x.value = pow(token2.x.value, token1.x.value);
  320.    break;
  321.   case 9 :
  322.    token1 = pop();
  323.    pop();
  324.    curtoken.x.value = -token1.x.value;
  325.    break;
  326.   case 11 :
  327.    token1 = pop();
  328.    pop();
  329.    token2 = pop();
  330.    curtoken.x.value = 0;
  331.    if (token1.x.c.row == token2.x.c.row)
  332.    {
  333.     if (token1.x.c.col < token2.x.c.col)
  334.      error = TRUE;
  335.     else
  336.     {
  337.      for (counter = token2.x.c.col; counter <= token1.x.c.col; counter++)
  338.       curtoken.x.value += cellvalue(counter, token1.x.c.row);
  339.     }
  340.    }
  341.    else if (token1.x.c.col == token2.x.c.col)
  342.    {
  343.     if (token1.x.c.row < token2.x.c.row)
  344.      error = TRUE;
  345.     else
  346.     {
  347.      for (counter = token2.x.c.row; counter <= token1.x.c.row; counter++)
  348.       curtoken.x.value += cellvalue(token1.x.c.col, counter);
  349.     }
  350.    }
  351.    else
  352.     error = TRUE;
  353.    break;
  354.   case 13 :
  355.    curtoken = pop();
  356.    curtoken.x.value = cellvalue(curtoken.x.c.col, curtoken.x.c.row);
  357.    break;
  358.   case 14 :
  359.    pop();
  360.    curtoken = pop();
  361.    pop();
  362.    break;
  363.   case 16 :
  364.    pop();
  365.    curtoken = pop();
  366.    pop();
  367.    token1 = pop();
  368.    if (strcmp(token1.x.funcname, "ABS") == 0)
  369.     curtoken.x.value = fabs(curtoken.x.value);
  370.    else if (strcmp(token1.x.funcname, "ACOS") == 0)
  371.     curtoken.x.value = acos(curtoken.x.value);
  372.    else if (strcmp(token1.x.funcname, "ASIN") == 0)
  373.     curtoken.x.value = asin(curtoken.x.value);
  374.    else if (strcmp(token1.x.funcname, "ATAN") == 0)
  375.     curtoken.x.value = atan(curtoken.x.value);
  376.    else if (strcmp(token1.x.funcname, "COSH") == 0)
  377.     curtoken.x.value = cosh(curtoken.x.value);
  378.    else if (strcmp(token1.x.funcname, "COS") == 0)
  379.     curtoken.x.value = cos(curtoken.x.value);
  380.    else if (strcmp(token1.x.funcname, "EXP") == 0)
  381.     curtoken.x.value = exp(curtoken.x.value);
  382.    else if (strcmp(token1.x.funcname, "LOG10") == 0)
  383.     curtoken.x.value = log10(curtoken.x.value);
  384.    else if (strcmp(token1.x.funcname, "LOG") == 0)
  385.     curtoken.x.value = log(curtoken.x.value);
  386.    else if (strcmp(token1.x.funcname, "ROUND") == 0)
  387.     curtoken.x.value = (int)(curtoken.x.value + 0.5);
  388.    else if (strcmp(token1.x.funcname, "POW10") == 0)
  389.     curtoken.x.value = pow10(curtoken.x.value);
  390.    else if (strcmp(token1.x.funcname, "SINH") == 0)
  391.     curtoken.x.value = sinh(curtoken.x.value);
  392.    else if (strcmp(token1.x.funcname, "SIN") == 0)
  393.     curtoken.x.value = sin(curtoken.x.value);
  394.    else if (strcmp(token1.x.funcname, "SQRT") == 0)
  395.     curtoken.x.value = sqrt(curtoken.x.value);
  396.    else if (strcmp(token1.x.funcname, "SQR") == 0)
  397.     curtoken.x.value *= curtoken.x.value;
  398.    else if (strcmp(token1.x.funcname, "TANH") == 0)
  399.     curtoken.x.value = tanh(curtoken.x.value);
  400.    else if (strcmp(token1.x.funcname, "TAN") == 0)
  401.     curtoken.x.value = tan(curtoken.x.value);
  402.    else if (strcmp(token1.x.funcname, "TRUNC") == 0)
  403.     curtoken.x.value = (int)curtoken.x.value;
  404.    break;
  405.   case 3 :
  406.   case 6 :
  407.   case 8 :
  408.   case 10 :
  409.   case 12 :
  410.   case 15 :
  411.    curtoken = pop();
  412.    break;
  413.  } /* switch */
  414.  curtoken.state = gotostate(reduction);
  415.  push(&curtoken);
  416. } /* reduce */
  417.  
  418. double parse(char *s, int *att)
  419. /* Parses the string s - returns the value of the evaluated string, and puts
  420.    the attribute in att: TEXT = 0, CONSTANT = 1, FORMULA = 2.
  421. */
  422. {
  423.  struct TOKENREC firsttoken;
  424.  char accepted = FALSE;
  425.  char copy[80];
  426.  
  427.  error = FALSE;
  428.  isformula = FALSE;
  429.  input = copy;
  430.  strupr(strcpy(copy, s));
  431.  stacktop = -1;
  432.  firsttoken.state = 0;
  433.  firsttoken.x.value = 0;
  434.  push(&firsttoken);
  435.  tokentype = nexttoken();
  436.  do
  437.  {
  438.  switch (stack[stacktop].state)
  439.  {
  440.   case 0 :
  441.   case 9 :
  442.   case 12 :
  443.   case 13 :
  444.   case 14 :
  445.   case 15 :
  446.   case 16 :
  447.   case 20 :
  448.    if (tokentype == NUM)
  449.     shift(10);
  450.    else if (tokentype == CELL)
  451.     shift(7);
  452.    else if (tokentype == FUNC)
  453.     shift(11);
  454.    else if (tokentype == MINUS)
  455.     shift(5);
  456.    else if (tokentype == OPAREN)
  457.     shift(9);
  458.    else
  459.     error = TRUE;
  460.    break;
  461.   case 1 :
  462.    if (tokentype == EOLN)
  463.     accepted = TRUE;
  464.    else if (tokentype == PLUS)
  465.     shift(12);
  466.    else if (tokentype == MINUS)
  467.     shift(13);
  468.    else
  469.     error = TRUE;
  470.    break;
  471.   case 2 :
  472.    if (tokentype == TIMES)
  473.     shift(14);
  474.    else if (tokentype == DIVIDE)
  475.     shift(15);
  476.    else
  477.     reduce(3);
  478.    break;
  479.   case 3 :
  480.    reduce(6);
  481.    break;
  482.   case 4 :
  483.    if (tokentype == EXP)
  484.     shift(16);
  485.    else
  486.     reduce(8);
  487.    break;
  488.   case 5 :
  489.    if (tokentype == NUM)
  490.     shift(10);
  491.    else if (tokentype == CELL)
  492.     shift(7);
  493.    else if (tokentype == FUNC)
  494.     shift(11);
  495.    else if (tokentype == OPAREN)
  496.     shift(9);
  497.    else
  498.     error = TRUE;
  499.    break;
  500.   case 6 :
  501.    reduce(10);
  502.    break;
  503.   case 7 :
  504.    if (tokentype == COLON)
  505.     shift(18);
  506.    else
  507.     reduce(13);
  508.    break;
  509.   case 8 :
  510.    reduce(12);
  511.    break;
  512.   case 10 :
  513.    reduce(15);
  514.    break;
  515.   case 11 :
  516.    if (tokentype == OPAREN)
  517.     shift(20);
  518.    else
  519.     error = TRUE;
  520.    break;
  521.   case 17 :
  522.    reduce(9);
  523.    break;
  524.   case 18 :
  525.    if (tokentype == CELL)
  526.     shift(26);
  527.    else
  528.     error = TRUE;
  529.    break;
  530.   case 19 :
  531.    if (tokentype == PLUS)
  532.     shift(12);
  533.    else if (tokentype == MINUS)
  534.     shift(13);
  535.    else if (tokentype == CPAREN)
  536.     shift(27);
  537.    else
  538.     error = TRUE;
  539.    break;
  540.   case 21 :
  541.    if (tokentype == TIMES)
  542.     shift(14);
  543.    else if (tokentype == DIVIDE)
  544.     shift(15);
  545.    else
  546.     reduce(1);
  547.    break;
  548.   case 22 :
  549.    if (tokentype == TIMES)
  550.     shift(14);
  551.    else if (tokentype == DIVIDE)
  552.     shift(15);
  553.    else
  554.     reduce(2);
  555.    break;
  556.   case 23 :
  557.    reduce(4);
  558.    break;
  559.   case 24 :
  560.    reduce(5);
  561.    break;
  562.   case 25 :
  563.    reduce(7);
  564.    break;
  565.   case 26 :
  566.    reduce(11);
  567.    break;
  568.   case 27 :
  569.    reduce(14);
  570.    break;
  571.   case 28 :
  572.    if (tokentype == PLUS)
  573.     shift(12);
  574.    else if (tokentype == MINUS)
  575.     shift(13);
  576.    else if (tokentype == CPAREN)
  577.     shift(29);
  578.    else
  579.     error = TRUE;
  580.    break;
  581.   case 29 :
  582.    reduce(16);
  583.    break;
  584.   case 30 :
  585.    error = TRUE;
  586.    break;
  587.  } /* switch */
  588.  }
  589.  while ((!accepted) && (!error));
  590.  if (error)
  591.  {
  592.   *att = TEXT;
  593.   return(0);
  594.  }
  595.  if (isformula)
  596.   *att = FORMULA;
  597.  else
  598.   *att = VALUE;
  599.  strcpy(s, copy);
  600.  return(stack[stacktop].x.value);
  601. } /* parse */
  602.