home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / tcpp / examples / tcalc / tcparser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-10  |  12.0 KB  |  606 lines

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