📄 obj.c
字号:
/* * obj - object handling primitives * * Copyright (C) 1999-2006 David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is * distributed with calc under the filename COPYING-LGPL. You should have * received a copy with calc; if not, write to Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * @(#) $Revision: 29.8 $ * @(#) $Id: obj.c,v 29.8 2006/05/20 08:43:55 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/obj.c,v $ * * Under source code control: 1990/02/15 01:48:19 * File existed as early as: before 1990 * * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ *//* * "Object" handling primitives. * This simply means that user-specified routines are called to perform * the indicated operations. */#include <stdio.h>#include "calc.h"#include "opcodes.h"#include "func.h"#include "symbol.h"#include "string.h"/* * Types of values returned by calling object routines. */#define A_VALUE 0 /* returns arbitrary value */#define A_INT 1 /* returns integer value */#define A_UNDEF 2 /* returns no value *//* * Error handling actions for when the function is undefined. */#define ERR_NONE 0 /* no special action */#define ERR_PRINT 1 /* print element */#define ERR_CMP 2 /* compare two values */#define ERR_TEST 3 /* test value for nonzero */#define ERR_POW 4 /* call generic power routine */#define ERR_ONE 5 /* return number 1 */#define ERR_INC 6 /* increment by one */#define ERR_DEC 7 /* decrement by one */#define ERR_SQUARE 8 /* square value */#define ERR_VALUE 9 /* return value */#define ERR_ASSIGN 10 /* assign value */static struct objectinfo { short args; /* number of arguments */ short retval; /* type of return value */ short error; /* special action on errors */ char *name; /* name of function to call */ char *comment; /* useful comment if any */} objectinfo[] = { {1, A_UNDEF, ERR_PRINT, "print", "print value, default prints elements"}, {1, A_VALUE, ERR_ONE, "one", "multiplicative identity, default is 1"}, {1, A_INT, ERR_TEST, "test", "logical test (false,true => 0,1), default tests elements"}, {2, A_VALUE, ERR_NONE, "add", NULL}, {2, A_VALUE, ERR_NONE, "sub", NULL}, {1, A_VALUE, ERR_NONE, "neg", "negative"}, {2, A_VALUE, ERR_NONE, "mul", NULL}, {2, A_VALUE, ERR_NONE, "div", "non-integral division"}, {1, A_VALUE, ERR_NONE, "inv", "multiplicative inverse"}, {2, A_VALUE, ERR_NONE, "abs", "absolute value within given error"}, {1, A_VALUE, ERR_NONE, "norm", "square of absolute value"}, {1, A_VALUE, ERR_NONE, "conj", "conjugate"}, {2, A_VALUE, ERR_POW, "pow", "integer power, default does multiply, square, inverse"}, {1, A_VALUE, ERR_NONE, "sgn", "sign of value (-1, 0, 1)"}, {2, A_INT, ERR_CMP, "cmp", "equality (equal,nonequal => 0,1), default tests elements"}, {2, A_VALUE, ERR_NONE, "rel", "relative order, positive for >, etc."}, {3, A_VALUE, ERR_NONE, "quo", "integer quotient"}, {3, A_VALUE, ERR_NONE, "mod", "remainder of division"}, {1, A_VALUE, ERR_NONE, "int", "integer part"}, {1, A_VALUE, ERR_NONE, "frac", "fractional part"}, {1, A_VALUE, ERR_INC, "inc", "increment, default adds 1"}, {1, A_VALUE, ERR_DEC, "dec", "decrement, default subtracts 1"}, {1, A_VALUE, ERR_SQUARE,"square", "default multiplies by itself"}, {2, A_VALUE, ERR_NONE, "scale", "multiply by power of 2"}, {2, A_VALUE, ERR_NONE, "shift", "shift left by n bits (right if negative)"}, {3, A_VALUE, ERR_NONE, "round", "round to given number of decimal places"}, {3, A_VALUE, ERR_NONE, "bround", "round to given number of binary places"}, {3, A_VALUE, ERR_NONE, "root", "root of value within given error"}, {3, A_VALUE, ERR_NONE, "sqrt", "square root within given error"}, {2, A_VALUE, ERR_NONE, "or", "bitwise or"}, {2, A_VALUE, ERR_NONE, "and", "bitwise and"}, {1, A_VALUE, ERR_NONE, "not", "logical not"}, {1, A_VALUE, ERR_NONE, "fact", "factorial or postfix !"}, {1, A_VALUE, ERR_VALUE, "min", "value for min(...)"}, {1, A_VALUE, ERR_VALUE, "max", "value for max(...)"}, {1, A_VALUE, ERR_VALUE, "sum", "value for sum(...)"}, {2, A_UNDEF, ERR_ASSIGN, "assign", "assign, defaults to a = b"}, {2, A_VALUE, ERR_NONE, "xor", "value for binary ~"}, {1, A_VALUE, ERR_NONE, "comp", "value for unary ~"}, {1, A_VALUE, ERR_NONE, "content", "unary hash op"}, {2, A_VALUE, ERR_NONE, "hashop", "binary hash op"}, {1, A_VALUE, ERR_NONE, "backslash", "unary backslash op"}, {2, A_VALUE, ERR_NONE, "setminus", "binary backslash op"}, {1, A_VALUE, ERR_NONE, "plus", "unary + op"}, {0, 0, 0, NULL, NULL}};static STRINGHEAD objectnames; /* names of objects */static STRINGHEAD elements; /* element names for parts of objects */static OBJECTACTIONS **objects; /* table of actions for objects */#define OBJALLOC 16static long maxobjcount = 0;static VALUE objpowi(VALUE *vp, NUMBER *q);static BOOL objtest(OBJECT *op);static BOOL objcmp(OBJECT *op1, OBJECT *op2);static void objprint(OBJECT *op);/* * Show all the routine names available for objects. */voidshowobjfuncs(void){ register struct objectinfo *oip; printf("\nThe following object routines are definable.\n"); printf("Note: xx represents the actual object type name.\n\n"); printf("Name Args Comments\n"); for (oip = objectinfo; oip->name; oip++) { printf("xx_%-8s %d %s\n", oip->name, oip->args, oip->comment ? oip->comment : ""); } printf("\n");}/* * Call the appropriate user-defined routine to handle an object action. * Returns the value that the routine returned. */VALUEobjcall(int action, VALUE *v1, VALUE *v2, VALUE *v3){ FUNC *fp; /* function to call */ static OBJECTACTIONS *oap; /* object to call for */ struct objectinfo *oip; /* information about action */ long index; /* index of function (negative if undefined) */ VALUE val; /* return value */ VALUE tmp; /* temp value */ char name[SYMBOLSIZE+1+1]; /* full name of user routine to call */ size_t namestr_len; /* length of the namestr() return string */ char *namestr_ret; /* namestr() return string */ size_t opi_name_len; /* length of the oip name */ /* initialize VALUEs */ val.v_subtype = V_NOSUBTYPE; tmp.v_subtype = V_NOSUBTYPE; if ((unsigned)action > OBJ_MAXFUNC) { math_error("Illegal action for object call"); /*NOTREACHED*/ } oip = &objectinfo[action]; if (v1->v_type == V_OBJ) { oap = v1->v_obj->o_actions; } else if (v2->v_type == V_OBJ) { oap = v2->v_obj->o_actions; } else { math_error("Object routine called with non-object"); /*NOTREACHED*/ } index = oap->oa_indices[action]; if (index < 0) { namestr_ret = namestr(&objectnames, oap->oa_index); if (namestr_ret == NULL) { math_error("namestr returned NULL!!!"); /*NOTREACHED*/ } namestr_len = strlen(namestr_ret); opi_name_len = strlen(oip->name); if (namestr_len > (size_t)SYMBOLSIZE-1-opi_name_len) { math_error("namestr returned a strong too long!!!"); /*NOTREACHED*/ } name[0] = '\0'; strncpy(name, namestr_ret, namestr_len+1); strcat(name, "_"); strncat(name, oip->name, opi_name_len+1); index = adduserfunc(name); oap->oa_indices[action] = index; } fp = NULL; if (index >= 0) fp = findfunc(index); if (fp == NULL) { switch (oip->error) { case ERR_PRINT: objprint(v1->v_obj); val.v_type = V_NULL; break; case ERR_CMP: val.v_type = V_INT; if (v1->v_type != v2->v_type) { val.v_int = 1; return val; } val.v_int = objcmp(v1->v_obj, v2->v_obj); break; case ERR_TEST: val.v_type = V_INT; val.v_int = objtest(v1->v_obj); break; case ERR_POW: if (v2->v_type != V_NUM) { math_error("Non-real power"); /*NOTREACHED*/ } val = objpowi(v1, v2->v_num); break; case ERR_ONE: val.v_type = V_NUM; val.v_num = qlink(&_qone_); break; case ERR_INC: tmp.v_type = V_NUM; tmp.v_num = &_qone_; val = objcall(OBJ_ADD, v1, &tmp, NULL_VALUE); break; case ERR_DEC: tmp.v_type = V_NUM; tmp.v_num = &_qone_; val = objcall(OBJ_SUB, v1, &tmp, NULL_VALUE); break; case ERR_SQUARE: val = objcall(OBJ_MUL, v1, v1, NULL_VALUE); break; case ERR_VALUE: copyvalue(v1, &val); break; case ERR_ASSIGN: copyvalue(v2, &tmp); tmp.v_subtype |= v1->v_subtype; freevalue(v1); *v1 = tmp; val.v_type = V_NULL; break; default: math_error("Function \"%s\" is undefined", namefunc(index)); /*NOTREACHED*/ } return val; } switch (oip->args) { case 0: break; case 1: ++stack; stack->v_addr = v1; stack->v_type = V_ADDR; break; case 2: ++stack; stack->v_addr = v1; stack->v_type = V_ADDR; ++stack; stack->v_addr = v2; stack->v_type = V_ADDR; break; case 3: ++stack; stack->v_addr = v1; stack->v_type = V_ADDR; ++stack; stack->v_addr = v2; stack->v_type = V_ADDR; ++stack; stack->v_addr = v3; stack->v_type = V_ADDR; break; default: math_error("Bad number of args to calculate"); /*NOTREACHED*/ } calculate(fp, oip->args); switch (oip->retval) { case A_VALUE: return *stack--; case A_UNDEF: freevalue(stack--); val.v_type = V_NULL; break; case A_INT: if ((stack->v_type != V_NUM) || qisfrac(stack->v_num)) { math_error("Integer return value required"); /*NOTREACHED*/ } index = qtoi(stack->v_num); qfree(stack->v_num); stack--; val.v_type = V_INT; val.v_int = index; break; default: math_error("Bad object return"); /*NOTREACHED*/ } return val;}/* * Print the elements of an object in short and unambiguous format. * This is the default routine if the user's is not defined. * * given: * op object being printed */static voidobjprint(OBJECT *op){ int count; /* number of elements */ int i; /* index */ count = op->o_actions->oa_count; math_fmt("obj %s {", namestr(&objectnames, op->o_actions->oa_index)); for (i = 0; i < count; i++) { if (i) math_str(", "); printvalue(&op->o_table[i], PRINT_SHORT | PRINT_UNAMBIG); } math_chr('}');}/* * Test an object for being "nonzero". * This is the default routine if the user's is not defined. * Returns TRUE if any of the elements are "nonzero". */static BOOLobjtest(OBJECT *op){ int i; /* loop counter */ i = op->o_actions->oa_count; while (--i >= 0) { if (testvalue(&op->o_table[i])) return TRUE; } return FALSE;}/* * Compare two objects for equality, returning TRUE if they differ. * This is the default routine if the user's is not defined. * For equality, all elements must be equal. */static BOOLobjcmp(OBJECT *op1, OBJECT *op2){ int i; /* loop counter */ if (op1->o_actions != op2->o_actions) return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -