home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
wp_dtp
/
xdme1820.lha
/
XDME
/
math.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-09
|
12KB
|
582 lines
/******************************************************************************
MODUL
math.c
DESCRIPTION
Simple Math commands for DME/XDME (integer only)
Variable swapping for DME/XDME
NOTES
-/-
BUGS
<none known>
TODO
erweitertes Math-interfaces (flexibler, mehr funktionen)
EXAMPLES
[ $a == 10 $b == 11 ]
inc a [-> $a == 11]
add b ( 3 * 4 + $b ) [-> $b == 34]
SEE ALSO
vars.c
INDEX
HISTORY
<see RCS-File>
******************************************************************************/
/*
** (C)Copyright 1992 by Bernd Noll for null/zero-soft
** All Rights Reserved
**
** RCS Header: $Id: math.c,v 1.66 92/12/02 04:00:49 b_noll Exp $
**
**
*/
/**************************************
Includes
**************************************/
#include "defs.h"
/**************************************
Globale Exports
**************************************/
Prototype char MathInfix;
Prototype void do_unnamedmathfunc(void);
Prototype void do_namedmathfunc (void);
Prototype void do_infixmode (void);
Prototype void do_swapV (void);
/**************************************
Interne Defines & Strukturen
**************************************/
/* --- math-function-modi if math_func_helper doesn't use function-parameters */
#define MODE_NOT simplehash('n','o')
#define MODE_NEG simplehash('n','e')
#define MODE_INC simplehash('i','n')
#define MODE_DEC simplehash('d','e')
#define MODE_ADD simplehash('a','d')
#define MODE_SUB simplehash('s','u')
#define MODE_MUL simplehash('m','u')
#define MODE_DIV simplehash('d','i')
#define MODE_MOD simplehash('m','o')
#ifndef MAXIA
#define MAXIA 5
#endif
#define OP_SUB 1 /* the values are used for priorities, too */
#define OP_ADD 2
#define OP_DIV 3
#define OP_MUL 4
/**************************************
Interne Prototypes
**************************************/
/**************************************
Impementation
**************************************/
/*
*! simple calculator:
*! recognizes +,-,*,/,(,)
*! 2 numbers must be separated with one operator,
*! !!each operator must be surrounded with whitespaces!!
*! (there are no unique +/- operators allowed, if they are
*! not part of a number: "-1" is allowed, "(- 1)" is not!)
*!
*! so each expression has an inequal number of subexpressions -
*! x+1 values and x operators with x in N
*! there should not be more than MAXIA (== 5)
*! expressions on one level (simply use brackets)
*! ( that is in fact no problem, as on any evaluation
*! we try to shorten our results due to operator prorities,
*! as long as there are only 4 operatores, we can never ever
*! run out of space
*! e.g.:>
set abc 0 add abc (1 * 2 + 3 * 4 / 5 - 6) title $abc
*! => 1 => 1* => 1*2 => 1*2+ [-> 2+]
*! => 2+3 => 2+3* => 2+3*4 => 2+3*4/ [-> 2+12/]
*! => 2+12/5 => 2+12/5- [-> 2+2-] [-> 4-] => 4-6
*! == -2
*/
static
long domathop (long a1, char op, long a2)
{
switch (op)
{
case OP_ADD:
return (a1 + a2);
case OP_SUB:
return (a1 - a2);
case OP_MUL:
return (a1 * a2);
case OP_DIV:
return (a1 / a2);
default:
error ("undefined mathoperator");
return (0);
} /* switch */
} /* domathop */
static
char getmathop (char * str)
{
if (!str)
{
return(0);
} /* if */
switch (*str)
{
case '+':
return (OP_ADD);
case '-':
return (OP_SUB);
case '*':
return (OP_MUL);
case '/':
return (OP_DIV);
default:
error ("unknown operator\n%s", str);
return(0);
} /* switch */
} /* getmathop */
/* static */
long getmathresult (char* expr)
{
long values[MAXIA];
char funcs [MAXIA];
char * str = expr;
int i;
char * checker;
char * aux2;
char * dummy;
/* --------- erstes argument muss immer existieren */
if (!expr)
{
error ("empty expression\n(input NIL)");
return(0);
} /* if */
if (is_number(expr))
{
return(atoi(expr));
} /* if */
checker = (ubyte *)breakout(&str, (void*)&dummy, &aux2);
if (!checker)
{
/* if (aux2)
{ free (aux2); aux2 = NULL; } // if */ /* seems senseless */
error ("empty expression\n(breakout NIL)");
return(0);
} /* if */
values[0] = getmathresult ( checker );
if (aux2)
{
free (aux2);
aux2 = NULL;
} /* if */
i = 0;
while (!globalflags.Abortcommand && str && ( 1/* first checking here */ ))
{
/* --------- operator holen - better put that line into the while-condition */
checker = (ubyte *)breakout(&str, (void*)&dummy, &aux2);
if (!checker)
{
/* if (aux2)
{ free (aux2); aux2 = NULL; } // if */ /* seems senseless */
goto ende;
} else
{
funcs[i] = getmathop(checker);
if (aux2)
{
free (aux2);
aux2 = NULL;
} /* if */
if (globalflags.Abortcommand)
{
/* printf ("abort unbekannt\n"); */
return (0);
} /* if (aborted) */
/* --------- wenn möglich, verkuerzen */
while (i>0 && funcs[i-1] >= funcs[i])
{
values[i-1] = domathop(values[i-1], funcs[i-1], values[i]);
funcs[i-1] = funcs[i];
i--;
} /* while */
i++;
if (i >= MAXIA)
{
error ("Expression too complex:\n%s", expr);
return (0);
} /* if */
/* --------- naechstes argument holen */
checker = (ubyte *)breakout(&str, (void*)&dummy, &aux2);
values[i] = getmathresult(checker);
if (aux2)
{
free (aux2);
} /* if */
if (globalflags.Abortcommand)
{
return (0);
} /* if */
} /* if ex operator */
} /* while not end of expr */
ende:
while (i > 0)
{
values[i-1] = domathop(values[i-1], funcs[i-1], values[i]);
i--;
} /* while */
/* printf("ok %ld\n", values[0]); */
return (values[0]);
} /* getmathresult */
/*
** math_hash()
** Calculate the right math-function defined by a string
**
*/
static
int math_hash (CHAR * str)
{
switch (str[1] == '=')
{
case '=':
switch (str[0])
{
case '+':
return(MODE_ADD);
case '-':
return(MODE_SUB);
case '*':
return(MODE_MUL);
case '/':
return(MODE_DIV);
case '%':
return(MODE_MOD);
case '~':
case '^':
return(MODE_NOT); /* nun ja minus statt NOT ... */
} /* switch */
case '-':
return(MODE_DEC);
case '+':
return(MODE_INC);
default:
return(simplehash(str[0],str[1]));
} /* if */
} /* math_hash */
/*
*! PATCH_MATH
*!
*! math-functions , they are all implemented in do_mathfunc
*!
*! Very simple syntax:
*! >[MATH1] NEG / INC / DEC / NOT <varname>
*! >[MATH2] ADD / SUB / MUL / DIV / MOD <varname> (<value>)
*!
*! <value> is a valid dezimal number
*! <varname> must be given at each function and must be the name
*! of an existing variable containing a valid number
*!
*! (a simple hack to do some increment etc. without arexx)
*!
*/
static
void do_mathfunc (CHAR* mmode, CHAR* vname, CHAR* mval)
{
int mathfunc;
CHAR str[16];
long l1;
long l2;
CHAR* sstr;
int type;
type = VAR_NEX; /* initialise */
str[15] = '\0';
l2 = 0;
l1 = 0;
/* --- get the right operation mode */
mathfunc = math_hash(mmode); /* recognize the mathfunction via mmode */
/* --- if necessary and existing, get the 2nd argument */
if ((mathfunc != MODE_NOT)&& (mathfunc != MODE_NEG)&&
(mathfunc != MODE_INC)&& (mathfunc != MODE_DEC))
{
/* called with 2 arguments => read a number from slot 2 */
if (mval != NULL)
{
if (is_number(mval))
{
l2 = atol(mval);
} else
{
/* Abortcommand = 0; */
/* error ("%s:\ninvalid 2nd argument %s", av[0], mval); */
l2 = getmathresult (mval);
if (globalflags.Abortcommand)
{
return;
} /* if */
/* abort(); */
} /* if */
} else
{
abort();
} /* if */
} /* if */
/* --- try to get the type and contents of the variable represented by the 1st argument */
if (vname != NULL)
{ /* get the number in the variable whose name is in slot 1 */
sstr = GetTypedVar(vname,&type);
if ((type != VAR_NEX) && is_number(sstr))
{
l1 = atol(sstr);
if (sstr)
free(sstr);
} else
{
if (sstr)
free(sstr);
error ("%s:\ninvalid 1st argument %s", av[0], vname);
abort();
} /* if */
} else
{
error ("%s:\nmissing 1st argument %s", av[0], vname);
abort();
} /* if */
/* --- do the specified math operation */
switch (mathfunc)
{ /* apply the math-function to the numbers */
/* it would be finer to use a function-variable - next time perhaps */
case MODE_NEG:
l2 = -l1;
break;
case MODE_NOT:
l2 = ~l1;
break;
case MODE_INC:
l2 = l1+1;
break;
case MODE_DEC:
l2 = l1-1;
break;
case MODE_ADD:
l2 = l1+l2;
break;
case MODE_SUB:
l2 = l1-l2;
break;
case MODE_MUL:
l2 = l1*l2;
break;
case MODE_DIV:
if (l2!=0)
{
l2 = l1/l2;
} else
{
abort();
} /* if */
break;
case MODE_MOD:
if (l2!=0)
{
l2 = l1%l2;
} else
{
abort();
} /* if */
break;
default:
abort();
} /* switch */
if ((type == VAR_TF) || (type == VAR_GF) || (type == VAR_SF) || (type == VAR_PF)) /* if dest is flag change to boolean */
l2 = (l2 != 0);
/* --- write back the value , if necessary */
if ((l2 != l1))
{ /* the function has changed a value => put it back to its variable */
sprintf(str,"%ld",l2);
SetTypedVar(vname, str, type);
} /* if */
} /* do_mathfunc */
/*
*! PATCH_SMATH:
*!
*! 8 short mathfuncs:
*! INC, DEC, NEG, NOT x
*! ADD, SUB, MUL, DIV, MOD x y
*! which expect 1 or 2 arguments
*! their function is recognized with their name
*! since they all use the same routines.
*!
*/
void do_namedmathfunc (void)
{
do_mathfunc(av[0], av[1], av[2]);
} /* do_namedmathfunc */
/*
*! PATCH_LMATH
*!
*! 2 long math-functions:
*! MATH1 x y
*! MATH2 x y z
*! which expect 2 or 3 arguments
*!
*! If You use the Toggle INFIX
*! the second argument defines the mathematical function
*! else the first arg does
*!
*/
char MathInfix = 0;
void do_unnamedmathfunc (void)
{
if (MathInfix)
do_mathfunc(av[2], av[1], av[3]); /* infix notation */
else
do_mathfunc(av[1], av[2], av[3]); /* prefix notation */
} /* do_unnamedmathfunc */
void do_infixmode (void)
{
MathInfix = test_arg (av[1], MathInfix);
if (MathInfix)
{
title ("Math Infixmode ON");
} else
{
title ("Math Infixmode OFF");
} /* if */
} /* do_infixmode */
/*
*! >SWAP var1 var2
*!
*! Swap the contents of 2 variables
*!
*! the command should recognize the type of the 2 variables and
*! use the appropriate set-funcions
*!
*/
void do_swapV (void)
{
CHAR* value[2];
int type[2];
int i;
/* --- read values */
for (i = 0; i < 2; i++)
{
if (!value[i] = GetTypedVar(av[1+i], &type[i]))
{
goto abortion;
} /* if */
} /* for */
#ifdef N_DEF
/* --- check compability */
for (i = 0; i < 2; i++)
{
switch (type[i])
{
case VAR_TF:
case VAR_PF:
case VAR_GF:
case VAR_SF:
dummy = toggler(1,value[1-i]);
case VAR_NEX:
goto abortion;
} /* switch */
} /* for */
if (aborted)
goto abortion;
#endif /* */
/* --- Write & free values */
for (i = 0; i < 2; i++)
{
SetTypedVar(av[2-i], value[i], type[1-i]);
free (value[i]);
} /* for */
return();
abortion:
free(value[0]);
free(value[1]);
abort();
} /* do_swapV */
/******************************************************************************
***** ENDE math.c
******************************************************************************/