home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Texteditors / XDME / Src / Mod / Math.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-27  |  14.8 KB  |  677 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. *!  integer MATH Functions
  35. *!
  36. ******************************************************************************/
  37.  
  38. /*
  39. **  (C)Copyright 1992 by Bernd Noll for null/zero-soft
  40. **  All Rights Reserved
  41. **
  42. **  RCS Header: $Id: math.c,v 1.66 92/12/02 04:00:49 b_noll Exp $
  43. **
  44. **
  45. */
  46.  
  47. /**************************************
  48.         Includes
  49. **************************************/
  50. #include "defs.h"
  51. #ifdef PATCH_NULL
  52. #include "COM.h"
  53. #include "libs/AUTO.h"
  54. #endif
  55.  
  56. /**************************************
  57.         Globale Exports
  58. **************************************/
  59. Prototype char      MathInfix;
  60. Prototype void      do_unnamedmathfunc(void);
  61. Prototype void      do_namedmathfunc  (void);
  62. Prototype void      do_infixmode        (void);
  63. Prototype void      do_swapV        (void);
  64.  
  65.  
  66. /**************************************
  67.       Interne Defines & Strukturen
  68. **************************************/
  69. /* --- math-function-modi if math_func_helper doesn't use function-parameters */
  70.  
  71. #define MODE_ADD simplehash('a','d')  /* x = x+y (2) */
  72. #define MODE_DEC simplehash('d','e')  /* x = x-1 (1) */
  73. #define MODE_DIV simplehash('d','i')  /* x = x/y (2) */
  74. #define MODE_INC simplehash('i','n')  /* x = x+1 (1) */
  75. #define MODE_MOD simplehash('m','o')  /* x = x%y (2) */
  76. #define MODE_MUL simplehash('m','u')  /* x = x*y (2) */
  77. #define MODE_NEG simplehash('n','e')  /* x = -x  (1) */
  78. #define MODE_NOT simplehash('n','o')  /* x = ~x  (1) */
  79. #define MODE_SUB simplehash('s','u')  /* x = x-y (2) */
  80.  
  81. #ifndef MAXIA
  82. #define MAXIA 5
  83. #endif
  84.  
  85. #define OP_SUB 1  /* the values are used for priorities, too */
  86. #define OP_ADD 2
  87. #define OP_DIV 3
  88. #define OP_MOD 4
  89. #define OP_MUL 5
  90.  
  91. /**************************************
  92.        Interne Prototypes
  93. **************************************/
  94.  
  95.  
  96. /**************************************
  97.        Impementation
  98. **************************************/
  99.  
  100.  
  101. /*
  102. *!
  103. *!  math functions offer the user a simple calculator,
  104. *!  which recognizes +,-,*,/,%,(,);
  105. *!  2 numbers must be separated with one operator,
  106. *!  !!each operator must be surrounded with whitespaces!!
  107. *!  (there are no unique +/- operators allowed, if they are
  108. *!   not part of a number, so "-1" is allowed, "(- 1)" is not!)
  109. *!
  110. *!  so each expression has an inequal number of subexpressions -
  111. *!  x+1 values and x operators with x in N
  112. *!  there should not be more than MAXIA (== 5)
  113. *!  expressions on one level (simply use brackets)
  114. *!  ( that is in fact no problem, as on any evaluation
  115. *!    we try to shorten our results due to operator prorities,
  116. *!    and as long as there are only 4 operators used, we do
  117. *!    normally not run out of space
  118. *!   e.g.:> set abc 0 add abc (1 * 2 + 3 * 4 / 5 - 6) title $abc
  119. *!    => 1      => 1*    => 1*2   => 1*2+   [-> 2+]
  120. *!    => 2+3      => 2+3*  => 2+3*4 => 2+3*4/ [-> 2+12/]
  121. *!    => 2+12/5 => 2+12/5- [-> 2+2-] [-> 4-] => 4-6
  122. *!    == -2
  123. *!
  124. */
  125.  
  126. static
  127. long domathop (long a1, char op, long a2)
  128. {
  129.     switch (op)
  130.     {
  131.     case OP_ADD:
  132.     return (a1 + a2);
  133.     case OP_SUB:
  134.     return (a1 - a2);
  135.     case OP_MUL:
  136.     return (a1 * a2);
  137.     case OP_DIV:
  138.     return (a1 / a2);
  139.     case OP_MOD:
  140.     return (a1 % a2);
  141.     default:
  142.     error  ("undefined mathoperator");
  143.     return (0);
  144.     } /* switch */
  145. } /* domathop */
  146.  
  147.  
  148. static
  149. char getmathop (char * str)
  150. {
  151.     if (!str)
  152.     {
  153.     return(0);
  154.     } /* if */
  155.  
  156.     switch (*str)
  157.     {
  158.     case '+':
  159.     return (OP_ADD);
  160.     case '-':
  161.     return (OP_SUB);
  162.     case '*':
  163.     return (OP_MUL);
  164.     case '/':
  165.     return (OP_DIV);
  166.     case '%':
  167.     return (OP_MOD);
  168.     default:
  169.     error ("unknown operator\n%s", str);
  170.     return(0);
  171.     } /* switch */
  172. } /* getmathop */
  173.  
  174. /* static */
  175. long getmathresult (char* expr)
  176. {
  177.     long   values[MAXIA];
  178.     char   funcs [MAXIA];
  179.     char * str = expr;
  180.     int    i;
  181.     char * checker;
  182.     char * aux2  = NULL;
  183.     char * dummy = NULL;
  184.     char   quote = 0;
  185.  
  186.     /* --------- erstes argument muss immer existieren */
  187.     if (!expr)
  188.     {
  189.     error ("empty expression\n(input NIL)");
  190.     return(0);
  191.     } /* if */
  192.  
  193.     if (is_number(expr))
  194.     {
  195.     return(atoi(expr));
  196.     } /* if */
  197.  
  198.     checker = (UBYTE *)breakout(&str, "e, &aux2);
  199.     if (!checker)
  200.     {
  201. #if 0
  202.     if (aux2) { free (aux2); aux2 = NULL; } /* if */ /* seems senseless */
  203. #endif
  204.     error ("empty expression\n(breakout NIL)");
  205.     return(0);
  206.     } /* if */
  207.  
  208.     /* PATCH_NULL [07 Apr 1993] : BUGFIX >>> */
  209.     /* now we are testing : 1. result word starts w/ alpha, 2. word was NOT multiword (AND is nonnumber), 3. word is NOT quoted (AND is not number)  */
  210.     if (isalpha(checker[0]) || ((str == NULL || *str == 0) && (quote == 0))) { /* should be better : check up to the first space, if there is a non-digit */
  211.     if (aux2)
  212.         free(aux2);
  213.     error ("non-number to math-function");
  214.     return (0);
  215.     } /* if */
  216.     /* PATCH_NULL [07 Apr 1993] : BUGFIX <<< */
  217.  
  218.     values[0] = getmathresult ( checker );
  219.     if (aux2)
  220.     {
  221.     free (aux2);
  222.     aux2 = NULL;
  223.     } /* if */
  224.  
  225.     i = 0;
  226.  
  227.     while (!globalflags.Abortcommand && str && ( 1/* first checking here */ ))
  228.     {
  229.  
  230.     /* --------- operator holen  - better put that line into the while-condition */
  231.     checker = (UBYTE *)breakout(&str, (void*)&dummy, &aux2);
  232.     if (!checker)
  233.     {
  234. #if 0
  235.         if (aux2) { free (aux2); aux2 = NULL; } /* if */ /* seems senseless */
  236. #endif
  237.  
  238.         goto ende;
  239.     } else
  240.     {
  241.  
  242.         funcs[i] = getmathop(checker);
  243.         if (aux2)
  244.         {
  245.         free (aux2);
  246.         aux2 = NULL;
  247.         } /* if */
  248.  
  249.         if (globalflags.Abortcommand)
  250.         {
  251. /* printf ("abort unbekannt\n"); */
  252.         return (0);
  253.         } /* if (aborted) */
  254.  
  255.         /* --------- wenn möglich, verkuerzen */
  256.         while (i>0 && funcs[i-1] >= funcs[i])
  257.         {
  258.         values[i-1] = domathop(values[i-1], funcs[i-1], values[i]);
  259.         funcs[i-1]  = funcs[i];
  260.         i--;
  261.         } /* while */
  262.  
  263.         i++;
  264.         if (i >= MAXIA)
  265.         {
  266.         error ("Expression too complex:\n%s", expr);
  267.         return (0);
  268.         } /* if */
  269.  
  270.         /* --------- naechstes argument holen */
  271.         checker   = (UBYTE *)breakout(&str, (void*)&dummy, &aux2);
  272.  
  273.         values[i] = getmathresult(checker);
  274.         if (aux2)
  275.         {
  276.         free (aux2);
  277.         } /* if */
  278.         if (globalflags.Abortcommand)
  279.         {
  280.         return (0);
  281.         } /* if */
  282.     } /* if ex operator */
  283.     } /* while not end of expr */
  284.  
  285. ende:
  286.  
  287.     while (i > 0)
  288.     {
  289.     values[i-1] = domathop(values[i-1], funcs[i-1], values[i]);
  290.     i--;
  291.     } /* while */
  292.  
  293. /* printf("ok %ld\n", values[0]); */
  294.  
  295.     return (values[0]);
  296. } /* getmathresult */
  297.  
  298.  
  299.  
  300. /*
  301. **  math_hash()
  302. **    Calculate the right math-function defined by a string
  303. **
  304. */
  305.  
  306. static
  307. int math_hash (char * str)
  308. {
  309.     switch (str[1]) { /* PATCH_NULL [04 Aug 1993] : BUGFIX */
  310.     case '=':
  311.         switch (str[0])
  312.         {
  313.         case '+':
  314.             return(MODE_ADD);
  315.         case '-':
  316.             return(MODE_SUB);
  317.         case '*':
  318.             return(MODE_MUL);
  319.         case '/':
  320.             return(MODE_DIV);
  321.         case '%':
  322.             return(MODE_MOD);
  323.         case '~':
  324.         case '^':
  325.             return(MODE_NOT);   /* nun ja minus statt NOT ... */
  326.         } /* switch */
  327.     case '-':
  328.         return(MODE_DEC);
  329.     case '+':
  330.         return(MODE_INC);
  331.     default:
  332.         return(simplehash(str[0],str[1]));
  333.     } /* if */
  334. } /* math_hash */
  335.  
  336.  
  337.  
  338. /*
  339. *!  MATH
  340. *!
  341. *!  math-commands, they are all implemented in do_mathfunc
  342. *!
  343. *!  Very simple syntax:
  344. *!
  345. *!  >[MATH1] NEG / INC / DEC / NOT     <varname>
  346. *!  >[MATH2] ADD / SUB / MUL / DIV / MOD <varname> (<value>)
  347. *!
  348. *!    <value>   is a valid dezimal number
  349. *!    <varname> must be given at each function and must be the name
  350. *!          of an existing variable containing a valid number
  351. *!
  352. *!  (a simple hack to do some increment etc. without arexx)
  353. *!
  354. *!  (due to less feedback, all the math commands are planned
  355. *!  to be replaced with one single command MATH name value)
  356. *!
  357. */
  358.  
  359. static
  360. void do_mathfunc (char* mmode, char* vname, char* mval)
  361. {
  362.     int   mathfunc;
  363.     char  str[16];
  364.     long  l1;
  365.     long  l2;
  366.     char* sstr;
  367.     int   type;
  368.  
  369.     type = VAR_NEX;        /* initialise */
  370.     str[15] = '\0';
  371.     l2 = 0;
  372.     l1 = 0;
  373.  
  374.     /* --- get the right operation mode */
  375.     mathfunc = math_hash(mmode);   /* recognize the mathfunction via mmode */
  376.  
  377.     /* --- if necessary and existing, get the 2nd argument */
  378.     if ((mathfunc != MODE_NOT)&& (mathfunc != MODE_NEG)&&
  379.     (mathfunc != MODE_INC)&& (mathfunc != MODE_DEC))
  380.     {
  381.             /* called with 2 arguments => read a number from slot 2 */
  382.     if (mval != NULL)
  383.     {
  384.         if (is_number(mval))
  385.         {
  386.         l2 = atol(mval);
  387.         } else
  388.         {
  389. /* Abortcommand = 0; */
  390. /* error ("%s:\ninvalid 2nd argument %s", av[0], mval); */
  391.         l2 = getmathresult (mval);
  392.         if (globalflags.Abortcommand)
  393.         {
  394.             return;
  395.         } /* if */
  396. /* abort2(); */
  397.         } /* if */
  398.     } else
  399.     {
  400.         error ("Math:\nMissing 2nd Operand!");
  401.         abort2();
  402.     } /* if */
  403.     } /* if */
  404.  
  405.     /* --- try to get the type and contents of the variable represented by the 1st argument */
  406.     if (vname != NULL) {        /* get the number in the variable whose name is in slot 1 */
  407.     sstr = GetTypedVar(vname,&type);
  408.     if ((type != VAR_NEX) && is_number(sstr))
  409.     {
  410.         l1 = atol(sstr);
  411.         if (sstr)
  412.         free(sstr);
  413.     } else
  414.     {
  415.         if (sstr)
  416.         free(sstr);
  417.         error ("%s:\ninvalid 1st argument %s", av[0], vname);
  418.         abort2();
  419.     } /* if */
  420.     } else
  421.     {
  422.     error ("%s:\nmissing 1st argument %s", av[0], vname);
  423.     abort2();
  424.     } /* if */
  425.  
  426.     /* --- do the specified math operation */
  427.     switch (mathfunc) {         /* apply the math-function to the numbers */
  428.                 /* it would be finer to use a function-variable  - next time perhaps */
  429.     case MODE_NEG:
  430.         l2 = -l1;
  431.         break;
  432.     case MODE_NOT:
  433.         l2 = ~l1;
  434.         break;
  435.     case MODE_INC:
  436.         l2 = l1+1;
  437.         break;
  438.     case MODE_DEC:
  439.         l2 = l1-1;
  440.         break;
  441.     case MODE_ADD:
  442.         l2 = l1+l2;
  443.         break;
  444.     case MODE_SUB:
  445.         l2 = l1-l2;
  446.         break;
  447.     case MODE_MUL:
  448.         l2 = l1*l2;
  449.         break;
  450.     case MODE_DIV:
  451.         if (l2!=0)
  452.         {
  453.         l2 = l1/l2;
  454.         } else
  455.         {
  456.         error ("Math:\nDivision by Zero!");
  457.         abort2();
  458.         } /* if */
  459.         break;
  460.     case MODE_MOD:
  461.         if (l2!=0)
  462.         {
  463.         l2 = l1%l2;
  464.         } else
  465.         {
  466.         error ("Math:\nDivision by Zero!");
  467.         abort2();
  468.         } /* if */
  469.         break;
  470.     default:
  471.         error ("Math:\nUnknown Operator!");
  472.         abort2();
  473.     } /* switch */
  474.  
  475.     if ((type == VAR_TF) || (type == VAR_GF) || (type == VAR_SF) || (type == VAR_PF)) /* if dest is flag change to boolean */
  476.     l2 = (l2 != 0);
  477.  
  478.     /* --- write back the value , if necessary */
  479.     if ((l2 != l1)) {   /* the function has changed a value => put it back to its variable */
  480.     sprintf(str,"%ld",l2);
  481.  
  482.     SetTypedVar(vname, str, type);
  483.     } /* if */
  484.  
  485. } /* do_mathfunc */
  486.  
  487.  
  488.  
  489. /*
  490. *!  SMATH Interface:
  491. *!
  492. *!  consisting of 8 short mathfuncs:
  493. *!
  494. *!  >INC/ DEC/ NEG/ NOT       x
  495. *!  >ADD/ SUB/ MUL/ DIV/ MOD  x y
  496. *!
  497. *!  which expect 1 or 2 arguments
  498. *!  their function is recognized with their name
  499. *!  since they all use the same routines.
  500. *!
  501. *!  (in fact these functions are abbreviations of MATH?)
  502. *!
  503. */
  504.  
  505. void do_namedmathfunc (void)
  506. {
  507.     do_mathfunc(av[0], av[1], av[2]);
  508. } /* do_namedmathfunc */
  509.  
  510.  
  511. /*
  512. *!  LMATH Interface:
  513. *!
  514. *!  2 long math-functions:
  515. *!
  516. *! >MATH1 x y
  517. *! >MATH2 x y z
  518. *!
  519. *!  which expect 2 or 3 arguments
  520. *!
  521. *!  If You use the Toggle INFIX
  522. *!  the second argument defines the mathematical function
  523. *!  else the first arg does
  524. *!
  525. *!
  526. *! >INFIX bool
  527. *!
  528. *!  define the argument order of the MATH? commands
  529. *!  with INFIX OFF we say
  530. *!   % MATH? operator variable [value]
  531. *!  with INFIX ON we use
  532. *!   % MATH? variable operator [value]
  533. *!
  534. */
  535.  
  536. char MathInfix = 0;
  537.  
  538. void do_unnamedmathfunc (void)
  539. {
  540.     if (MathInfix)
  541.     do_mathfunc(av[2], av[1], av[3]); /* infix notation */
  542.     else
  543.     do_mathfunc(av[1], av[2], av[3]); /* prefix notation */
  544. } /* do_unnamedmathfunc */
  545.  
  546.  
  547.  
  548. void do_infixmode (void)
  549. {
  550.     MathInfix = test_arg (av[1], MathInfix);
  551.     if (MathInfix)
  552.     {
  553.     title ("Math Infixmode ON");
  554.     } else
  555.     {
  556.     title ("Math Infixmode OFF");
  557.     } /* if */
  558. } /* do_infixmode */
  559.  
  560.  
  561. /*
  562. *! >SWAP var1 var2
  563. *!
  564. *!  Swap the contents of 2 variables
  565. *!
  566. *!  the command should recognize the type of the 2 variables and
  567. *!  use the appropriate set-funcions
  568. *!
  569. */
  570.  
  571. void do_swapV (void)
  572. {
  573.     char*   value[2];
  574.     int     type[2];
  575.     int     i;
  576.  
  577.     /* --- read values */
  578.     for (i = 0; i < 2; i++)
  579.     {
  580.     if (!(value[i] = GetTypedVar(av[1+i], &type[i])))
  581.     {
  582.         error ("%s:\nUnknown Variable '%s'!", av[0], av[1+i]);
  583.         goto abortion;
  584.     } /* if */
  585.     } /* for */
  586.  
  587. #ifdef N_DEF
  588.     /* --- check compability */
  589.     for (i = 0; i < 2; i++)
  590.     {
  591.     switch (type[i])
  592.     {
  593.         case VAR_TF:
  594.         case VAR_PF:
  595.         case VAR_GF:
  596.         case VAR_SF:
  597.         dummy = toggler(1,value[1-i]);
  598.         break;
  599.         case VAR_NEX:
  600.         error ("%s:\nUnknown Variable '%s'!", av[0], av[1+i]);
  601.         goto abortion;
  602.     } /* switch */
  603.     } /* for */
  604.  
  605.     if (aborted)
  606.     {
  607.     /* error ("%s:\nIncompatible values for\n'%s' and '%s'!", av[0], av[1], av[2]); */
  608.     goto abortion;
  609.     }
  610. #endif /*  */
  611.  
  612.  
  613.     /* --- Write & free values */
  614.     for (i = 0; i < 2; i++)
  615.     {
  616.     SetTypedVar(av[2-i], value[i], type[1-i]);
  617.     free (value[i]);
  618.     } /* for */
  619.  
  620.     return;
  621.  
  622. abortion:
  623.     free(value[0]);
  624.     free(value[1]);
  625.     abort2();
  626. } /* do_swapV */
  627.  
  628.  
  629. #ifdef PATCH_NULL /* PATCH_NULL < 24-06-94 */
  630.  
  631. static const
  632. struct CommandNode MATH_Commands[] =
  633. {
  634.     {ENODE("math1"),         2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unnamedmathfunc  },
  635.     {ENODE("math2"),         3, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unnamedmathfunc  },
  636.     {ENODE("infixmode"),     1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_infixmode        },
  637.     {ENODE("inc"),           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  638.     {ENODE("sub"),           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  639.     {ENODE("add"),           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  640.     {ENODE("dec"),           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  641.     {ENODE("div"),           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  642.     {ENODE("mod"),           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  643.     {ENODE("mul"),           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  644.     {ENODE("not"),           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  645.     {ENODE("neg"),           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc    },
  646. };
  647.  
  648. MK_AUTOINIT(MATH_Init)
  649. {
  650.     int i;
  651.  
  652.     for (i = sizeof (MATH_Commands)/sizeof (struct CommandNode) - 1;i >= 0; --i)
  653.     {
  654.     COM_Add (&MATH_Commands[i]);
  655.     } /* for */
  656. } /* MATH_Init */
  657.  
  658.  
  659.  
  660.  
  661. MK_AUTOEXIT(MATH_Exit)
  662. {
  663.     int  i;
  664.     APTR lock;
  665.  
  666.     for (i = sizeof (MATH_Commands)/sizeof (struct CommandNode) - 1; (i >= 0); DEC(i))
  667.     if (lock = COM_Lock (MATH_Commands[i].cn_Name))
  668.         COM_Remove (lock);
  669. } /* MATH_Exit */
  670. #endif
  671.  
  672.  
  673. /******************************************************************************
  674. *****  ENDE math.c
  675. ******************************************************************************/
  676.  
  677.