2 * obj - object handling primitives
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.2 $
21 * @(#) $Id: obj.c,v 30.2 2013/08/11 08:41:38 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/obj.c,v $
24 * Under source code control: 1990/02/15 01:48:19
25 * File existed as early as: before 1990
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
30 * "Object" handling primitives.
31 * This simply means that user-specified routines are called to perform
32 * the indicated operations.
45 * Types of values returned by calling object routines.
47 #define A_VALUE 0 /* returns arbitrary value */
48 #define A_INT 1 /* returns integer value */
49 #define A_UNDEF 2 /* returns no value */
52 * Error handling actions for when the function is undefined.
54 #define ERR_NONE 0 /* no special action */
55 #define ERR_PRINT 1 /* print element */
56 #define ERR_CMP 2 /* compare two values */
57 #define ERR_TEST 3 /* test value for nonzero */
58 #define ERR_POW 4 /* call generic power routine */
59 #define ERR_ONE 5 /* return number 1 */
60 #define ERR_INC 6 /* increment by one */
61 #define ERR_DEC 7 /* decrement by one */
62 #define ERR_SQUARE 8 /* square value */
63 #define ERR_VALUE 9 /* return value */
64 #define ERR_ASSIGN 10 /* assign value */
67 STATIC
struct objectinfo
{
68 short args
; /* number of arguments */
69 short retval
; /* type of return value */
70 short error
; /* special action on errors */
71 char *name
; /* name of function to call */
72 char *comment
; /* useful comment if any */
74 {1, A_UNDEF
, ERR_PRINT
,
75 "print", "print value, default prints elements"},
77 "one", "multiplicative identity, default is 1"},
79 "test", "logical test (false,true => 0,1), default tests elements"},
80 {2, A_VALUE
, ERR_NONE
,
82 {2, A_VALUE
, ERR_NONE
,
84 {1, A_VALUE
, ERR_NONE
,
86 {2, A_VALUE
, ERR_NONE
,
88 {2, A_VALUE
, ERR_NONE
,
89 "div", "non-integral division"},
90 {1, A_VALUE
, ERR_NONE
,
91 "inv", "multiplicative inverse"},
92 {2, A_VALUE
, ERR_NONE
,
93 "abs", "absolute value within given error"},
94 {1, A_VALUE
, ERR_NONE
,
95 "norm", "square of absolute value"},
96 {1, A_VALUE
, ERR_NONE
,
99 "pow", "integer power, default does multiply, square, inverse"},
100 {1, A_VALUE
, ERR_NONE
,
101 "sgn", "sign of value (-1, 0, 1)"},
103 "cmp", "equality (equal,nonequal => 0,1), default tests elements"},
104 {2, A_VALUE
, ERR_NONE
,
105 "rel", "relative order, positive for >, etc."},
106 {3, A_VALUE
, ERR_NONE
,
107 "quo", "integer quotient"},
108 {3, A_VALUE
, ERR_NONE
,
109 "mod", "remainder of division"},
110 {1, A_VALUE
, ERR_NONE
,
111 "int", "integer part"},
112 {1, A_VALUE
, ERR_NONE
,
113 "frac", "fractional part"},
114 {1, A_VALUE
, ERR_INC
,
115 "inc", "increment, default adds 1"},
116 {1, A_VALUE
, ERR_DEC
,
117 "dec", "decrement, default subtracts 1"},
118 {1, A_VALUE
, ERR_SQUARE
,
119 "square", "default multiplies by itself"},
120 {2, A_VALUE
, ERR_NONE
,
121 "scale", "multiply by power of 2"},
122 {2, A_VALUE
, ERR_NONE
,
123 "shift", "shift left by n bits (right if negative)"},
124 {3, A_VALUE
, ERR_NONE
,
125 "round", "round to given number of decimal places"},
126 {3, A_VALUE
, ERR_NONE
,
127 "bround", "round to given number of binary places"},
128 {3, A_VALUE
, ERR_NONE
,
129 "root", "root of value within given error"},
130 {3, A_VALUE
, ERR_NONE
,
131 "sqrt", "square root within given error"},
132 {2, A_VALUE
, ERR_NONE
,
134 {2, A_VALUE
, ERR_NONE
,
135 "and", "bitwise and"},
136 {1, A_VALUE
, ERR_NONE
,
137 "not", "logical not"},
138 {1, A_VALUE
, ERR_NONE
,
139 "fact", "factorial or postfix !"},
140 {1, A_VALUE
, ERR_VALUE
,
141 "min", "value for min(...)"},
142 {1, A_VALUE
, ERR_VALUE
,
143 "max", "value for max(...)"},
144 {1, A_VALUE
, ERR_VALUE
,
145 "sum", "value for sum(...)"},
146 {2, A_UNDEF
, ERR_ASSIGN
,
147 "assign", "assign, defaults to a = b"},
148 {2, A_VALUE
, ERR_NONE
,
149 "xor", "value for binary ~"},
150 {1, A_VALUE
, ERR_NONE
,
151 "comp", "value for unary ~"},
152 {1, A_VALUE
, ERR_NONE
,
153 "content", "unary hash op"},
154 {2, A_VALUE
, ERR_NONE
,
155 "hashop", "binary hash op"},
156 {1, A_VALUE
, ERR_NONE
,
157 "backslash", "unary backslash op"},
158 {2, A_VALUE
, ERR_NONE
,
159 "setminus", "binary backslash op"},
160 {1, A_VALUE
, ERR_NONE
,
161 "plus", "unary + op"},
167 STATIC STRINGHEAD objectnames
; /* names of objects */
168 STATIC STRINGHEAD elements
; /* element names for parts of objects */
169 STATIC OBJECTACTIONS
**objects
; /* table of actions for objects */
172 STATIC
long maxobjcount
= 0;
174 S_FUNC VALUE
objpowi(VALUE
*vp
, NUMBER
*q
);
175 S_FUNC BOOL
objtest(OBJECT
*op
);
176 S_FUNC BOOL
objcmp(OBJECT
*op1
, OBJECT
*op2
);
177 S_FUNC
void objprint(OBJECT
*op
);
181 * Show all the routine names available for objects.
186 register struct objectinfo
*oip
;
188 printf("\nThe following object routines are definable.\n");
189 printf("Note: xx represents the actual object type name.\n\n");
190 printf("Name Args Comments\n");
191 for (oip
= objectinfo
; oip
->name
; oip
++) {
192 printf("xx_%-8s %d %s\n", oip
->name
, oip
->args
,
193 oip
->comment
? oip
->comment
: "");
200 * Call the appropriate user-defined routine to handle an object action.
201 * Returns the value that the routine returned.
204 objcall(int action
, VALUE
*v1
, VALUE
*v2
, VALUE
*v3
)
206 FUNC
*fp
; /* function to call */
207 STATIC OBJECTACTIONS
*oap
; /* object to call for */
208 struct objectinfo
*oip
; /* information about action */
209 long index
; /* index of function (negative if undefined) */
210 VALUE val
; /* return value */
211 VALUE tmp
; /* temp value */
212 char name
[SYMBOLSIZE
+1+1]; /* full name of user routine to call */
213 size_t namestr_len
; /* length of the namestr() return string */
214 char *namestr_ret
; /* namestr() return string */
215 size_t opi_name_len
; /* length of the oip name */
217 /* initialize VALUEs */
218 val
.v_subtype
= V_NOSUBTYPE
;
219 tmp
.v_subtype
= V_NOSUBTYPE
;
221 if ((unsigned)action
> OBJ_MAXFUNC
) {
222 math_error("Illegal action for object call");
225 oip
= &objectinfo
[action
];
226 if (v1
->v_type
== V_OBJ
) {
227 oap
= v1
->v_obj
->o_actions
;
228 } else if (v2
->v_type
== V_OBJ
) {
229 oap
= v2
->v_obj
->o_actions
;
231 math_error("Object routine called with non-object");
234 index
= oap
->oa_indices
[action
];
236 namestr_ret
= namestr(&objectnames
, oap
->oa_index
);
237 if (namestr_ret
== NULL
) {
238 math_error("namestr returned NULL!!!");
241 namestr_len
= strlen(namestr_ret
);
242 opi_name_len
= strlen(oip
->name
);
243 if (namestr_len
> (size_t)SYMBOLSIZE
-1-opi_name_len
) {
244 math_error("namestr returned a strong too long!!!");
248 strncpy(name
, namestr_ret
, namestr_len
+1);
250 strncat(name
, oip
->name
, opi_name_len
+1);
251 index
= adduserfunc(name
);
252 oap
->oa_indices
[action
] = index
;
256 fp
= findfunc(index
);
258 switch (oip
->error
) {
265 if (v1
->v_type
!= v2
->v_type
) {
269 val
.v_int
= objcmp(v1
->v_obj
, v2
->v_obj
);
273 val
.v_int
= objtest(v1
->v_obj
);
276 if (v2
->v_type
!= V_NUM
) {
277 math_error("Non-real power");
280 val
= objpowi(v1
, v2
->v_num
);
284 val
.v_num
= qlink(&_qone_
);
289 val
= objcall(OBJ_ADD
, v1
, &tmp
, NULL_VALUE
);
294 val
= objcall(OBJ_SUB
, v1
, &tmp
, NULL_VALUE
);
297 val
= objcall(OBJ_MUL
, v1
, v1
, NULL_VALUE
);
304 tmp
.v_subtype
|= v1
->v_subtype
;
310 math_error("Function \"%s\" is undefined",
322 stack
->v_type
= V_ADDR
;
327 stack
->v_type
= V_ADDR
;
330 stack
->v_type
= V_ADDR
;
335 stack
->v_type
= V_ADDR
;
338 stack
->v_type
= V_ADDR
;
341 stack
->v_type
= V_ADDR
;
344 math_error("Bad number of args to calculate");
347 calculate(fp
, oip
->args
);
348 switch (oip
->retval
) {
356 if ((stack
->v_type
!= V_NUM
) || qisfrac(stack
->v_num
)) {
357 math_error("Integer return value required");
360 index
= qtoi(stack
->v_num
);
367 math_error("Bad object return");
375 * Print the elements of an object in short and unambiguous format.
376 * This is the default routine if the user's is not defined.
379 * op object being printed
384 int count
; /* number of elements */
387 count
= op
->o_actions
->oa_count
;
388 math_fmt("obj %s {", namestr(&objectnames
, op
->o_actions
->oa_index
));
389 for (i
= 0; i
< count
; i
++) {
392 printvalue(&op
->o_table
[i
], PRINT_SHORT
| PRINT_UNAMBIG
);
399 * Test an object for being "nonzero".
400 * This is the default routine if the user's is not defined.
401 * Returns TRUE if any of the elements are "nonzero".
406 int i
; /* loop counter */
408 i
= op
->o_actions
->oa_count
;
410 if (testvalue(&op
->o_table
[i
]))
418 * Compare two objects for equality, returning TRUE if they differ.
419 * This is the default routine if the user's is not defined.
420 * For equality, all elements must be equal.
423 objcmp(OBJECT
*op1
, OBJECT
*op2
)
425 int i
; /* loop counter */
427 if (op1
->o_actions
!= op2
->o_actions
)
429 i
= op1
->o_actions
->oa_count
;
431 if (comparevalue(&op1
->o_table
[i
], &op2
->o_table
[i
]))
439 * Raise an object to an integral power.
440 * This is the default routine if the user's is not defined.
441 * Negative powers mean the positive power of the inverse.
442 * Zero means the multiplicative identity.
445 * vp value to be powered
446 * q power to raise number to
449 objpowi(VALUE
*vp
, NUMBER
*q
)
452 long power
; /* power to raise to */
453 FULL bit
; /* current bit value */
456 math_error("Raising object to non-integral power");
459 if (zge31b(q
->num
)) {
460 math_error("Raising object to very large power");
463 power
= ztolong(q
->num
);
467 * Handle some low powers specially
469 if ((power
<= 2) && (power
>= -2)) {
470 switch ((int) power
) {
472 return objcall(OBJ_ONE
, vp
, NULL_VALUE
, NULL_VALUE
);
474 res
.v_obj
= objcopy(vp
->v_obj
);
476 res
.v_subtype
= V_NOSUBTYPE
;
479 return objcall(OBJ_INV
, vp
, NULL_VALUE
, NULL_VALUE
);
481 return objcall(OBJ_SQUARE
, vp
, NULL_VALUE
, NULL_VALUE
);
487 * Compute the power by squaring and multiplying.
488 * This uses the left to right method of power raising.
491 while ((bit
& power
) == 0)
494 res
= objcall(OBJ_SQUARE
, vp
, NULL_VALUE
, NULL_VALUE
);
496 tmp
= objcall(OBJ_MUL
, &res
, vp
, NULL_VALUE
);
502 tmp
= objcall(OBJ_SQUARE
, &res
, NULL_VALUE
, NULL_VALUE
);
506 tmp
= objcall(OBJ_MUL
, &res
, vp
, NULL_VALUE
);
513 tmp
= objcall(OBJ_INV
, &res
, NULL_VALUE
, NULL_VALUE
);
522 * Define a (possibly) new class of objects.
523 * The list of indexes for the element names is also specified here,
524 * and the number of elements defined for the object.
527 * name name of object type
528 * indices table of indices for elements
529 * count number of elements defined for the object
532 defineobject(char *name
, int indices
[], int count
)
534 OBJECTACTIONS
*oap
; /* object definition structure */
536 OBJECTACTIONS
**newobjects
;
540 if (hp
->h_list
== NULL
)
542 index
= findstr(hp
, name
);
545 * Object is already defined. Give an error unless this
546 * new definition is exactly the same as the old one.
548 oap
= objects
[index
];
549 if (oap
->oa_count
== count
) {
550 for (index
= 0; ; index
++) {
553 if (oap
->oa_elements
[index
] != indices
[index
])
560 if (hp
->h_count
>= maxobjcount
) {
561 if (maxobjcount
== 0) {
562 newobjects
= (OBJECTACTIONS
**) malloc(
563 OBJALLOC
* sizeof(OBJECTACTIONS
*));
564 maxobjcount
= OBJALLOC
;
566 maxobjcount
+= OBJALLOC
;
567 newobjects
= (OBJECTACTIONS
**) realloc(objects
,
568 maxobjcount
* sizeof(OBJECTACTIONS
*));
570 if (newobjects
== NULL
) {
571 math_error("Allocation failure for new object type");
574 objects
= newobjects
;
577 oap
= (OBJECTACTIONS
*) malloc(objectactionsize(count
));
578 name
= addstr(hp
, name
);
579 if ((oap
== NULL
) || (name
== NULL
)) {
580 math_error("Cannot allocate object type");
583 oap
->oa_count
= count
;
584 for (index
= OBJ_MAXFUNC
; index
>= 0; index
--)
585 oap
->oa_indices
[index
] = -1;
586 for (index
= 0; index
< count
; index
++)
587 oap
->oa_elements
[index
] = indices
[index
];
588 index
= findstr(hp
, name
);
589 oap
->oa_index
= index
;
590 objects
[index
] = oap
;
596 * Check an object name to see if it is currently defined.
597 * If so, the index for the object type is returned.
598 * If the object name is currently unknown, then -1 is returned.
601 checkobject(char *name
)
606 if (hp
->h_list
== NULL
)
608 return findstr(hp
, name
);
613 * Define a (possibly) new element name for an object.
614 * Returns an index which identifies the element name.
617 addelement(char *name
)
623 if (hp
->h_list
== NULL
)
625 index
= findstr(hp
, name
);
628 if (addstr(hp
, name
) == NULL
) {
629 math_error("Cannot allocate element name");
632 return findstr(hp
, name
);
637 * Return the index which identifies an element name.
638 * Returns minus one if the element name is unknown.
644 findelement(char *name
)
646 if (elements
.h_list
== NULL
)
648 return findstr(&elements
, name
);
653 * Returns the name of object type with specified index
656 objtypename(unsigned long index
)
658 return namestr(&objectnames
, (long)index
);
663 * Return the value table offset to be used for an object element name.
664 * This converts the element index from the element table into an offset
665 * into the object value array. Returns -1 if the element index is unknown.
668 objoffset(OBJECT
*op
, long index
)
670 register OBJECTACTIONS
*oap
;
671 int offset
; /* offset into value array */
674 for (offset
= oap
->oa_count
- 1; offset
>= 0; offset
--) {
675 if (oap
->oa_elements
[offset
] == index
)
683 * Allocate a new object structure with the specified index.
693 if (index
< 0 || index
> maxobjcount
) {
694 math_error("Allocating bad object index");
697 oap
= objects
[index
];
699 math_error("Object type not defined");
703 if (i
< USUAL_ELEMENTS
)
705 if (i
== USUAL_ELEMENTS
)
706 op
= (OBJECT
*) malloc(sizeof(OBJECT
));
708 op
= (OBJECT
*) malloc(objectsize(i
));
710 math_error("Cannot allocate object");
715 for (i
= oap
->oa_count
; i
-- > 0; vp
++) {
716 vp
->v_num
= qlink(&_qzero_
);
718 vp
->v_subtype
= V_NOSUBTYPE
;
725 * Free an object structure.
734 for (i
= op
->o_actions
->oa_count
; i
-- > 0; vp
++) {
735 if (vp
->v_type
== V_NUM
) {
741 if (op
->o_actions
->oa_count
<= USUAL_ELEMENTS
)
749 * Copy an object value
758 i
= op
->o_actions
->oa_count
;
759 if (i
< USUAL_ELEMENTS
)
761 if (i
== USUAL_ELEMENTS
)
762 np
= (OBJECT
*) malloc(sizeof(OBJECT
));
764 np
= (OBJECT
*) malloc(objectsize(i
));
766 math_error("Cannot allocate object");
769 np
->o_actions
= op
->o_actions
;
772 for (i
= op
->o_actions
->oa_count
; i
-- > 0; v1
++, v2
++) {
780 * Show object types that have been defined.
792 if (hp
->h_count
== 0) {
793 printf("No object types defined\n");
796 for (index
= 0; index
< hp
->h_count
; index
++) {
797 oap
= objects
[index
];
798 printf("\t%s\t{", namestr(&objectnames
, index
));
799 for (i
= 0; i
< oap
->oa_count
; i
++) {
801 printf("%s", namestr(ep
, oap
->oa_elements
[i
]));