home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / wp_dtp / xdme1820.lha / XDME / math.c < prev    next >
C/C++ Source or Header  |  1993-03-09  |  12KB  |  582 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     math.c
  5.  
  6.     DESCRIPTION
  7.     Simple Math commands for DME/XDME (integer only)
  8.     Variable swapping    for DME/XDME
  9.  
  10.     NOTES
  11.     -/-
  12.  
  13.     BUGS
  14.     <none known>
  15.  
  16.     TODO
  17.     erweitertes Math-interfaces (flexibler, mehr funktionen)
  18.  
  19.     EXAMPLES
  20.     [ $a == 10 $b == 11 ]
  21.     inc a            [-> $a == 11]
  22.     add b ( 3 * 4 + $b )    [-> $b == 34]
  23.  
  24.     SEE ALSO
  25.     vars.c
  26.  
  27.     INDEX
  28.  
  29.     HISTORY
  30.     <see RCS-File>
  31.  
  32.  
  33. ******************************************************************************/
  34.  
  35. /*
  36. **  (C)Copyright 1992 by Bernd Noll for null/zero-soft
  37. **  All Rights Reserved
  38. **
  39. **  RCS Header: $Id: math.c,v 1.66 92/12/02 04:00:49 b_noll Exp $
  40. **
  41. **
  42. */
  43.  
  44. /**************************************
  45.         Includes
  46. **************************************/
  47. #include "defs.h"
  48.  
  49.  
  50. /**************************************
  51.         Globale Exports
  52. **************************************/
  53. Prototype char      MathInfix;
  54. Prototype void      do_unnamedmathfunc(void);
  55. Prototype void      do_namedmathfunc  (void);
  56. Prototype void      do_infixmode        (void);
  57. Prototype void      do_swapV        (void);
  58.  
  59.  
  60. /**************************************
  61.       Interne Defines & Strukturen
  62. **************************************/
  63. /* --- math-function-modi if math_func_helper doesn't use function-parameters */
  64. #define MODE_NOT simplehash('n','o')
  65. #define MODE_NEG simplehash('n','e')
  66. #define MODE_INC simplehash('i','n')
  67. #define MODE_DEC simplehash('d','e')
  68. #define MODE_ADD simplehash('a','d')
  69. #define MODE_SUB simplehash('s','u')
  70. #define MODE_MUL simplehash('m','u')
  71. #define MODE_DIV simplehash('d','i')
  72. #define MODE_MOD simplehash('m','o')
  73.  
  74. #ifndef MAXIA
  75. #define MAXIA 5
  76. #endif
  77.  
  78. #define OP_SUB 1  /* the values are used for priorities, too */
  79. #define OP_ADD 2
  80. #define OP_DIV 3
  81. #define OP_MUL 4
  82.  
  83. /**************************************
  84.        Interne Prototypes
  85. **************************************/
  86.  
  87.  
  88. /**************************************
  89.        Impementation
  90. **************************************/
  91.  
  92.  
  93. /*
  94. *!  simple calculator:
  95. *!  recognizes +,-,*,/,(,)
  96. *!  2 numbers must be separated with one operator,
  97. *!  !!each operator must be surrounded with whitespaces!!
  98. *!  (there are no unique +/- operators allowed, if they are
  99. *!   not part of a number: "-1" is allowed, "(- 1)" is not!)
  100. *!
  101. *!  so each expression has an inequal number of subexpressions -
  102. *!  x+1 values and x operators with x in N
  103. *!  there should not be more than MAXIA (== 5)
  104. *!  expressions on one level (simply use brackets)
  105. *!  ( that is in fact no problem, as on any evaluation
  106. *!    we try to shorten our results due to operator prorities,
  107. *!    as long as there are only 4 operatores, we can never ever
  108. *!    run out of space
  109. *!   e.g.:>
  110. set abc 0 add abc (1 * 2 + 3 * 4 / 5 - 6) title $abc
  111. *!    => 1      => 1*    => 1*2   => 1*2+   [-> 2+]
  112. *!    => 2+3      => 2+3*  => 2+3*4 => 2+3*4/ [-> 2+12/]
  113. *!    => 2+12/5 => 2+12/5- [-> 2+2-] [-> 4-] => 4-6
  114. *!    == -2
  115. */
  116.  
  117. static
  118. long domathop (long a1, char op, long a2)
  119. {
  120.     switch (op)
  121.     {
  122.     case OP_ADD:
  123.     return (a1 + a2);
  124.     case OP_SUB:
  125.     return (a1 - a2);
  126.     case OP_MUL:
  127.     return (a1 * a2);
  128.     case OP_DIV:
  129.     return (a1 / a2);
  130.     default:
  131.     error  ("undefined mathoperator");
  132.     return (0);
  133.     } /* switch */
  134. } /* domathop */
  135.  
  136.  
  137. static
  138. char getmathop (char * str)
  139. {
  140.     if (!str)
  141.     {
  142.     return(0);
  143.     } /* if */
  144.  
  145.     switch (*str)
  146.     {
  147.     case '+':
  148.     return (OP_ADD);
  149.     case '-':
  150.     return (OP_SUB);
  151.     case '*':
  152.     return (OP_MUL);
  153.     case '/':
  154.     return (OP_DIV);
  155.     default:
  156.     error ("unknown operator\n%s", str);
  157.     return(0);
  158.     } /* switch */
  159. } /* getmathop */
  160.  
  161. /* static */
  162. long getmathresult (char* expr)
  163. {
  164.     long   values[MAXIA];
  165.     char   funcs [MAXIA];
  166.     char * str = expr;
  167.     int    i;
  168.     char * checker;
  169.     char * aux2;
  170.     char * dummy;
  171.  
  172.     /* --------- erstes argument muss immer existieren */
  173.     if (!expr)
  174.     {
  175.     error ("empty expression\n(input NIL)");
  176.     return(0);
  177.     } /* if */
  178.  
  179.     if (is_number(expr))
  180.     {
  181.     return(atoi(expr));
  182.     } /* if */
  183.  
  184.     checker = (ubyte *)breakout(&str, (void*)&dummy, &aux2);
  185.     if (!checker)
  186.     {
  187.     /* if (aux2)
  188.     { free (aux2); aux2 = NULL; } // if */ /* seems senseless */
  189.     error ("empty expression\n(breakout NIL)");
  190.     return(0);
  191.     } /* if */
  192.  
  193.     values[0] = getmathresult ( checker );
  194.     if (aux2)
  195.     {
  196.     free (aux2);
  197.     aux2 = NULL;
  198.     } /* if */
  199.  
  200.     i = 0;
  201.  
  202.     while (!globalflags.Abortcommand && str && ( 1/* first checking here */ ))
  203.     {
  204.  
  205.     /* --------- operator holen  - better put that line into the while-condition */
  206.     checker = (ubyte *)breakout(&str, (void*)&dummy, &aux2);
  207.     if (!checker)
  208.     {
  209.         /* if (aux2)
  210.         { free (aux2); aux2 = NULL; } // if */ /* seems senseless */
  211.  
  212.         goto ende;
  213.     } else
  214.     {
  215.  
  216.         funcs[i] = getmathop(checker);
  217.         if (aux2)
  218.         {
  219.         free (aux2);
  220.         aux2 = NULL;
  221.         } /* if */
  222.  
  223.         if (globalflags.Abortcommand)
  224.         {
  225. /* printf ("abort unbekannt\n"); */
  226.         return (0);
  227.         } /* if (aborted) */
  228.  
  229.         /* --------- wenn möglich, verkuerzen */
  230.         while (i>0 && funcs[i-1] >= funcs[i])
  231.         {
  232.         values[i-1] = domathop(values[i-1], funcs[i-1], values[i]);
  233.         funcs[i-1]  = funcs[i];
  234.         i--;
  235.         } /* while */
  236.  
  237.         i++;
  238.         if (i >= MAXIA)
  239.         {
  240.         error ("Expression too complex:\n%s", expr);
  241.         return (0);
  242.         } /* if */
  243.  
  244.         /* --------- naechstes argument holen */
  245.         checker   = (ubyte *)breakout(&str, (void*)&dummy, &aux2);
  246.  
  247.         values[i] = getmathresult(checker);
  248.         if (aux2)
  249.         {
  250.         free (aux2);
  251.         } /* if */
  252.         if (globalflags.Abortcommand)
  253.         {
  254.         return (0);
  255.         } /* if */
  256.     } /* if ex operator */
  257.     } /* while not end of expr */
  258.  
  259. ende:
  260.  
  261.     while (i > 0)
  262.     {
  263.     values[i-1] = domathop(values[i-1], funcs[i-1], values[i]);
  264.     i--;
  265.     } /* while */
  266.  
  267. /* printf("ok %ld\n", values[0]); */
  268.  
  269.     return (values[0]);
  270. } /* getmathresult */
  271.  
  272.  
  273.  
  274. /*
  275. **  math_hash()
  276. **    Calculate the right math-function defined by a string
  277. **
  278. */
  279.  
  280. static
  281. int math_hash (CHAR * str)
  282. {
  283.     switch (str[1] == '=')
  284.     {
  285.     case '=':
  286.         switch (str[0])
  287.         {
  288.         case '+':
  289.             return(MODE_ADD);
  290.         case '-':
  291.             return(MODE_SUB);
  292.         case '*':
  293.             return(MODE_MUL);
  294.         case '/':
  295.             return(MODE_DIV);
  296.         case '%':
  297.             return(MODE_MOD);
  298.         case '~':
  299.         case '^':
  300.             return(MODE_NOT);   /* nun ja minus statt NOT ... */
  301.         } /* switch */
  302.     case '-':
  303.         return(MODE_DEC);
  304.     case '+':
  305.         return(MODE_INC);
  306.     default:
  307.         return(simplehash(str[0],str[1]));
  308.     } /* if */
  309. } /* math_hash */
  310.  
  311.  
  312.  
  313. /*
  314. *!  PATCH_MATH
  315. *!
  316. *!  math-functions , they are all implemented in do_mathfunc
  317. *!
  318. *!  Very simple syntax:
  319. *!  >[MATH1] NEG / INC / DEC / NOT     <varname>
  320. *!  >[MATH2] ADD / SUB / MUL / DIV / MOD <varname> (<value>)
  321. *!
  322. *!    <value>   is a valid dezimal number
  323. *!    <varname> must be given at each function and must be the name
  324. *!          of an existing variable containing a valid number
  325. *!
  326. *!  (a simple hack to do some increment etc. without arexx)
  327. *!
  328. */
  329.  
  330. static
  331. void do_mathfunc (CHAR* mmode, CHAR* vname, CHAR* mval)
  332. {
  333.     int   mathfunc;
  334.     CHAR  str[16];
  335.     long  l1;
  336.     long  l2;
  337.     CHAR* sstr;
  338.     int   type;
  339.  
  340.     type = VAR_NEX;        /* initialise */
  341.     str[15] = '\0';
  342.     l2 = 0;
  343.     l1 = 0;
  344.  
  345.     /* --- get the right operation mode */
  346.     mathfunc = math_hash(mmode);   /* recognize the mathfunction via mmode */
  347.  
  348.     /* --- if necessary and existing, get the 2nd argument */
  349.     if ((mathfunc != MODE_NOT)&& (mathfunc != MODE_NEG)&&
  350.     (mathfunc != MODE_INC)&& (mathfunc != MODE_DEC))
  351.     {
  352.             /* called with 2 arguments => read a number from slot 2 */
  353.     if (mval != NULL)
  354.     {
  355.         if (is_number(mval))
  356.         {
  357.         l2 = atol(mval);
  358.         } else
  359.         {
  360. /* Abortcommand = 0; */
  361. /* error ("%s:\ninvalid 2nd argument %s", av[0], mval); */
  362.         l2 = getmathresult (mval);
  363.         if (globalflags.Abortcommand)
  364.         {
  365.             return;
  366.         } /* if */
  367. /* abort(); */
  368.         } /* if */
  369.     } else
  370.     {
  371.         abort();
  372.     } /* if */
  373.     } /* if */
  374.  
  375.     /* --- try to get the type and contents of the variable represented by the 1st argument */
  376.     if (vname != NULL)
  377.     {         /* get the number in the variable whose name is in slot 1 */
  378.     sstr = GetTypedVar(vname,&type);
  379.     if ((type != VAR_NEX) && is_number(sstr))
  380.     {
  381.         l1 = atol(sstr);
  382.         if (sstr)
  383.         free(sstr);
  384.     } else
  385.     {
  386.         if (sstr)
  387.         free(sstr);
  388.         error ("%s:\ninvalid 1st argument %s", av[0], vname);
  389.         abort();
  390.     } /* if */
  391.     } else
  392.     {
  393.     error ("%s:\nmissing 1st argument %s", av[0], vname);
  394.     abort();
  395.     } /* if */
  396.  
  397.     /* --- do the specified math operation */
  398.     switch (mathfunc)
  399.     {          /* apply the math-function to the numbers */
  400.                 /* it would be finer to use a function-variable  - next time perhaps */
  401.     case MODE_NEG:
  402.         l2 = -l1;
  403.         break;
  404.     case MODE_NOT:
  405.         l2 = ~l1;
  406.         break;
  407.     case MODE_INC:
  408.         l2 = l1+1;
  409.         break;
  410.     case MODE_DEC:
  411.         l2 = l1-1;
  412.         break;
  413.     case MODE_ADD:
  414.         l2 = l1+l2;
  415.         break;
  416.     case MODE_SUB:
  417.         l2 = l1-l2;
  418.         break;
  419.     case MODE_MUL:
  420.         l2 = l1*l2;
  421.         break;
  422.     case MODE_DIV:
  423.         if (l2!=0)
  424.         {
  425.         l2 = l1/l2;
  426.         } else
  427.         {
  428.         abort();
  429.         } /* if */
  430.         break;
  431.     case MODE_MOD:
  432.         if (l2!=0)
  433.         {
  434.         l2 = l1%l2;
  435.         } else
  436.         {
  437.         abort();
  438.         } /* if */
  439.         break;
  440.     default:
  441.         abort();
  442.     } /* switch */
  443.  
  444.     if ((type == VAR_TF) || (type == VAR_GF) || (type == VAR_SF) || (type == VAR_PF)) /* if dest is flag change to boolean */
  445.     l2 = (l2 != 0);
  446.  
  447.     /* --- write back the value , if necessary */
  448.     if ((l2 != l1))
  449.     {    /* the function has changed a value => put it back to its variable */
  450.     sprintf(str,"%ld",l2);
  451.  
  452.     SetTypedVar(vname, str, type);
  453.     } /* if */
  454.  
  455. } /* do_mathfunc */
  456.  
  457.  
  458.  
  459. /*
  460. *!  PATCH_SMATH:
  461. *!
  462. *!  8 short mathfuncs:
  463. *!   INC, DEC, NEG, NOT       x
  464. *!   ADD, SUB, MUL, DIV, MOD  x y
  465. *!  which expect 1 or 2 arguments
  466. *!  their function is recognized with their name
  467. *!  since they all use the same routines.
  468. *!
  469. */
  470.  
  471. void do_namedmathfunc (void)
  472. {
  473.     do_mathfunc(av[0], av[1], av[2]);
  474. } /* do_namedmathfunc */
  475.  
  476.  
  477. /*
  478. *!  PATCH_LMATH
  479. *!
  480. *!  2 long math-functions:
  481. *!   MATH1 x y
  482. *!   MATH2 x y z
  483. *!  which expect 2 or 3 arguments
  484. *!
  485. *!  If You use the Toggle INFIX
  486. *!  the second argument defines the mathematical function
  487. *!  else the first arg does
  488. *!
  489. */
  490.  
  491. char MathInfix = 0;
  492.  
  493. void do_unnamedmathfunc (void)
  494. {
  495.     if (MathInfix)
  496.     do_mathfunc(av[2], av[1], av[3]); /* infix notation */
  497.     else
  498.     do_mathfunc(av[1], av[2], av[3]); /* prefix notation */
  499. } /* do_unnamedmathfunc */
  500.  
  501.  
  502.  
  503. void do_infixmode (void)
  504. {
  505.     MathInfix = test_arg (av[1], MathInfix);
  506.     if (MathInfix)
  507.     {
  508.     title ("Math Infixmode ON");
  509.     } else
  510.     {
  511.     title ("Math Infixmode OFF");
  512.     } /* if */
  513. } /* do_infixmode */
  514.  
  515.  
  516. /*
  517. *! >SWAP var1 var2
  518. *!
  519. *!  Swap the contents of 2 variables
  520. *!
  521. *!  the command should recognize the type of the 2 variables and
  522. *!  use the appropriate set-funcions
  523. *!
  524. */
  525.  
  526. void do_swapV (void)
  527. {
  528.     CHAR*   value[2];
  529.     int     type[2];
  530.     int     i;
  531.  
  532.     /* --- read values */
  533.     for (i = 0; i < 2; i++)
  534.     {
  535.     if (!value[i] = GetTypedVar(av[1+i], &type[i]))
  536.     {
  537.         goto abortion;
  538.     } /* if */
  539.     } /* for */
  540.  
  541. #ifdef N_DEF
  542.     /* --- check compability */
  543.     for (i = 0; i < 2; i++)
  544.     {
  545.     switch (type[i])
  546.     {
  547.         case VAR_TF:
  548.         case VAR_PF:
  549.         case VAR_GF:
  550.         case VAR_SF:
  551.         dummy = toggler(1,value[1-i]);
  552.         case VAR_NEX:
  553.         goto abortion;
  554.     } /* switch */
  555.     } /* for */
  556.  
  557.     if (aborted)
  558.     goto abortion;
  559. #endif /*  */
  560.  
  561.  
  562.     /* --- Write & free values */
  563.     for (i = 0; i < 2; i++)
  564.     {
  565.     SetTypedVar(av[2-i], value[i], type[1-i]);
  566.     free (value[i]);
  567.     } /* for */
  568.  
  569.     return();
  570.  
  571. abortion:
  572.     free(value[0]);
  573.     free(value[1]);
  574.     abort();
  575. } /* do_swapV */
  576.  
  577.  
  578. /******************************************************************************
  579. *****  ENDE math.c
  580. ******************************************************************************/
  581.  
  582.