# line 2 "evvexpr.y" include include include include include .help evvexpr .nf -------------------------------------------------------------------------- EVVEXPR.GY -- Generic XYacc source for a general vector expression evaluator. o = evvexpr (expr, getop, getop_data, ufcn, ufcn_data, flags) evvfree (o) Client callbacks: getop (client_data, opname, out) ufcn (client_data, fcn, args, nargs, out) here "out" is the output operand returned to EVVEXPR. Client_data is any arbitrary integer or pointer value passed in to EVVEXPR when by the client when the callback was registered. "args" is an array of operand structs, the arguments for the user function being called. If the operand or function call cannot be completed normally an error exit may be made (call error) or an invalid operand may be returned (O_TYPE set to 0). The client should not free the "args" input operands, this will be handled by EVVEXPR. Operand struct (lib$evvexpr.h): struct operand { int O_TYPE # operand type (bcsilrd) int O_LEN # operand length (0=scalar) int O_FLAGS # O_FREEVAL, O_FREEOP union { char* O_VALC # string short O_VALS int O_VALI # int or bool long O_VALL real O_VALR double O_VALD pointer O_VALP # vector data } } The macro O_VALC references the string value of a TY_CHAR operand. The flags are O_FREEVAL and O_FREEOP, which tell EVVEXPR and EVVFREE whether or not to free any vector operand array or the operand struct when the operand is freed. The client should set these flags on operands returned to EVVEXPR if it wants EVVEXPR to free any operand storage. Supported types are bool, char (string), and SILRD. Bool is indicated as TY_BOOL in the O_TYPE field of the operand struct, but is stored internally as an integer and the value field of a boolean operand is given by O_VALI. Operands may be either scalars or vectors. A vector is indicated by a O_LEN value greater than zero. For vector operands O_VALP points to the data array. A special case is TY_CHAR (string), in which case O_LEN is the allocated length of the EOS-terminated string. A string is logically a scalar value even though it is physically stored in the operand as a character vector. The trig functions operate upon angles in units of radians. The intrinsic functions RAD and DEG are available for converting between radians and degrees. A string can be coerced to a binary value and vice versa, using the INT, STR, etc. intrinsic functions. This is a generalization of the older EVEXPR routine, adding additional datatypes, support for vector operands, and numerous minor enhancements. .endhelp --------------------------------------------------------------------- define YYMAXDEPTH 64 # parser stack length define MAX_ARGS 17 # max args in a function call define yyparse xvv_parse # Arglist structure. define LEN_ARGSTRUCT (1+MAX_ARGS+(MAX_ARGS*LEN_OPERAND)) define A_NARGS Memi[$1] # number of arguments define A_ARGP Memi[$1+$2] # array of pointers to operand structs define A_OPS ($1+MAX_ARGS+1) # offset to operand storage area # Intrinsic functions. define LEN_STAB 300 # for symbol table define LEN_SBUF 256 define LEN_INDEX 97 define LEN_SYM 1 # symbol data define SYM_CODE Memi[$1] define KEYWORDS "|abs|acos|asin|atan|atan2|bool|cos|cosh|deg|double|\ |exp|hiv|int|len|log|log10|long|lov|max|mean|median|\ |min|mod|nint|rad|real|repl|stddev|shift|short|sin|\ |sinh|sort|sqrt|str|sum|tan|tanh|" define F_ABS 01 # function codes define F_ACOS 02 define F_ASIN 03 define F_ATAN 04 define F_ATAN2 05 define F_BOOL 06 define F_COS 07 define F_COSH 08 define F_DEG 09 # radians to degrees define F_DOUBLE 10 # newline 11 define F_EXP 12 define F_HIV 13 # high value define F_INT 14 define F_LEN 15 # vector length define F_LOG 16 define F_LOG10 17 define F_LONG 18 define F_LOV 19 # low value define F_MAX 20 define F_MEAN 21 define F_MEDIAN 22 # newline 23 define F_MIN 24 define F_MOD 25 define F_NINT 26 define F_RAD 27 # degrees to radians define F_REAL 28 define F_REPL 29 # replicate define F_STDDEV 30 # standard deviation define F_SHIFT 31 define F_SHORT 32 define F_SIN 33 # newline 34 define F_SINH 35 define F_SORT 36 # sort define F_SQRT 37 # square root define F_STR 38 define F_SUM 39 define F_TAN 40 define F_TANH 41 define T_B TY_BOOL define T_C TY_CHAR define T_S TY_SHORT define T_I TY_INT define T_L TY_LONG define T_R TY_REAL define T_D TY_DOUBLE # EVVEXPR -- Evaluate a general mixed type vector expression. Input consists # of the expression to be evaluated (a string) and, optionally, user # procedures for fetching external operands and executing external functions. # Output is a pointer to an operand structure containing the computed value of # the expression. The output operand structure is dynamically allocated by # EVVEXPR and must be freed by the user. # # NOTE: this is not intended to be an especially efficient procedure. Rather, # this is a high level, easy to use procedure, intended to provide greater # flexibility in the parameterization of applications programs. The main # inefficiency is that, since compilation and execution are not broken out as # separate steps, when the routine is repeatedly called to evaluate the same # expression with different data, all the compile time computation (parsing # etc.) has to be repeated. pointer procedure evvexpr (expr, getop, getop_data, ufcn, ufcn_data, flags) char expr[ARB] #I expression to be evaluated int getop #I user supplied get operand procedure int getop_data #I client data for above function int ufcn #I user supplied function call procedure int ufcn_data #I client data for above function int flags #I flag bits int junk pointer sp, ip bool debug, first_time int strlen(), xvv_parse() pointer xvv_loadsymbols() extern xvv_gettok() errchk xvv_parse, calloc include "evvexpr.com" data debug /false/ data first_time /true/ begin call smark (sp) if (first_time) { # This creates data which remains for the life of the process. ev_st = xvv_loadsymbols (KEYWORDS) first_time = false } # Set user function entry point addresses. ev_getop = getop ev_getop_data = getop_data ev_ufcn = ufcn ev_ufcn_data = ufcn_data ev_flags = flags # Allocate an operand struct for the expression value. call calloc (ev_oval, LEN_OPERAND, TY_STRUCT) # Make a local copy of the input string. call salloc (ip, strlen(expr), TY_CHAR) call strcpy (expr, Memc[ip], ARB) # Evaluate the expression. The expression value is copied into the # output operand structure by XVV_PARSE, given the operand pointer # passed in common. A common must be used since the standard parser # subroutine has a fixed calling sequence. junk = xvv_parse (ip, debug, xvv_gettok) O_FLAGS(ev_oval) = or (O_FLAGS(ev_oval), O_FREEOP) call sfree (sp) return (ev_oval) end # EVVFREE -- Free an operand struct such as is returned by EVVEXPR. procedure evvfree (o) pointer o # operand struct begin call xvv_freeop (o) end define CONSTANT 257 define IDENTIFIER 258 define NEWLINE 259 define YYEOS 260 define PLUS 261 define MINUS 262 define STAR 263 define SLASH 264 define EXPON 265 define CONCAT 266 define QUEST 267 define COLON 268 define LT 269 define GT 270 define LE 271 define EQ 272 define NE 273 define SE 274 define LAND 275 define LOR 276 define LNOT 277 define BAND 278 define BOR 279 define BXOR 280 define BNOT 281 define AT 282 define GE 283 define UMINUS 284 define yyclearin yychar = -1 define yyerrok yyerrflag = 0 define YYMOVE call amovi (Memi[$1], Memi[$2], YYOPLEN) define YYERRCODE 256 # End generic preprocessor escape. # XVV_UNOP -- Unary operation. Perform the indicated unary operation on the # input operand, returning the result as the output operand. procedure xvv_unop (opcode, in, out) int opcode #I operation to be performed pointer in #I input operand pointer out #I output operand short val_s long val_l int val_i, nelem errchk xvv_error, xvv_initop string s_badswitch "unop: bad switch" begin nelem = O_LEN(in) switch (opcode) { case MINUS: # Unary negation. call xvv_initop (out, nelem, O_TYPE(in)) switch (O_TYPE(in)) { case TY_BOOL, TY_CHAR: call xvv_error ("negation of a nonarithmetic operand") case TY_SHORT: if (nelem > 0) call anegs (Mems[O_VALP(in)], Mems[O_VALP(out)], nelem) else O_VALS(out) = -O_VALS(in) case TY_INT: if (nelem > 0) call anegi (Memi[O_VALP(in)], Memi[O_VALP(out)], nelem) else O_VALI(out) = -O_VALI(in) case TY_LONG: if (nelem > 0) call anegl (Meml[O_VALP(in)], Meml[O_VALP(out)], nelem) else O_VALL(out) = -O_VALL(in) case TY_REAL: if (nelem > 0) call anegr (Memr[O_VALP(in)], Memr[O_VALP(out)], nelem) else O_VALR(out) = -O_VALR(in) case TY_DOUBLE: if (nelem > 0) call anegd (Memd[O_VALP(in)], Memd[O_VALP(out)], nelem) else O_VALD(out) = -O_VALD(in) default: call xvv_error (s_badswitch) } case LNOT: # Logical NOT. call xvv_initop (out, nelem, TY_BOOL) switch (O_TYPE(in)) { case TY_BOOL: if (nelem > 0) call abeqki (Memi[O_VALP(in)], NO, Memi[O_VALP(out)], nelem) else { if (O_VALI(in) == NO) O_VALI(out) = YES else O_VALI(out) = NO } case TY_SHORT: if (nelem > 0) { val_s = NO call abeqks (Mems[O_VALP(in)], val_s, Memi[O_VALP(out)], nelem) } else { if (O_VALS(in) == NO) O_VALS(out) = YES else O_VALS(out) = NO } case TY_INT: if (nelem > 0) { val_i = NO call abeqki (Memi[O_VALP(in)], val_i, Memi[O_VALP(out)], nelem) } else { if (O_VALI(in) == NO) O_VALI(out) = YES else O_VALI(out) = NO } case TY_LONG: if (nelem > 0) { val_l = NO call abeqkl (Meml[O_VALP(in)], val_l, Memi[O_VALP(out)], nelem) } else { if (O_VALL(in) == NO) O_VALL(out) = YES else O_VALL(out) = NO } case TY_CHAR, TY_REAL, TY_DOUBLE: call xvv_error ("not of a nonlogical") default: call xvv_error (s_badswitch) } case BNOT: # Bitwise boolean NOT. call xvv_initop (out, nelem, O_TYPE(in)) switch (O_TYPE(in)) { case TY_BOOL, TY_CHAR, TY_REAL, TY_DOUBLE: call xvv_error ("boolean not of a noninteger operand") case TY_SHORT: if (nelem > 0) call anots (Mems[O_VALP(in)], Mems[O_VALP(out)], nelem) else O_VALS(out) = not(O_VALS(in)) case TY_INT: if (nelem > 0) call anoti (Memi[O_VALP(in)], Memi[O_VALP(out)], nelem) else O_VALI(out) = not(O_VALI(in)) case TY_LONG: if (nelem > 0) call anotl (Meml[O_VALP(in)], Meml[O_VALP(out)], nelem) else O_VALL(out) = not(O_VALL(in)) default: call xvv_error (s_badswitch) } default: call xvv_error (s_badswitch) } call xvv_freeop (in) end # XVV_BINOP -- Binary operation. Perform the indicated arithmetic binary # operation on the two input operands, returning the result as the output # operand. procedure xvv_binop (opcode, in1, in2, out) int opcode #I operation to be performed pointer in1, in2 #I input operands pointer out #I output operand short v_s short xvv_nulls() extern xvv_nulls() int v_i int xvv_nulli() extern xvv_nulli() long v_l long xvv_nulll() extern xvv_nulll() real v_r real xvv_nullr() extern xvv_nullr() double v_d double xvv_nulld() extern xvv_nulld() pointer sp, otemp, p1, p2, po int dtype, nelem, len1, len2 include "evvexpr.com" int xvv_newtype(), strlen() errchk xvv_newtype, xvv_initop, xvv_chtype, xvv_error string s_badswitch "binop: bad case in switch" string s_boolop "binop: bitwise boolean operands must be an integer type" define done_ 91 begin # Set the datatype of the output operand, taking an error action if # the operands have incompatible datatypes. dtype = xvv_newtype (O_TYPE(in1), O_TYPE(in2)) # Compute the size of the output operand. If both input operands are # vectors the length of the output vector is the shorter of the two. switch (dtype) { case TY_BOOL: call xvv_error ("binop: operation illegal for boolean operands") case TY_CHAR: nelem = strlen (O_VALC(in1)) + strlen (O_VALC(in2)) default: if (opcode == CONCAT) nelem = max (1, O_LEN(in1)) + max (1, O_LEN(in2)) else { if (O_LEN(in1) > 0 && O_LEN(in2) > 0) nelem = min (O_LEN(in1), O_LEN(in2)) else if (O_LEN(in1) > 0) nelem = O_LEN(in1) else if (O_LEN(in2) > 0) nelem = O_LEN(in2) else nelem = 0 } } # Convert input operands to desired type. if (O_TYPE(in1) != dtype) call xvv_chtype (in1, in1, dtype) if (O_TYPE(in2) != dtype) call xvv_chtype (in2, in2, dtype) # If this is a scalar/vector operation make sure the vector is the # first operand. len1 = O_LEN(in1) len2 = O_LEN(in2) if (len1 == 0 && len2 > 0) { switch (opcode) { case PLUS: # Swap operands. call smark (sp) call salloc (otemp, LEN_OPERAND, TY_STRUCT) YYMOVE (in1, otemp) YYMOVE (in2, in1) YYMOVE (otemp, in2) call sfree (sp) case CONCAT: ; # Do nothing default: # Promote operand to a constant vector. Inefficient, but # better than aborting. switch (dtype) { case TY_SHORT: v_s = O_VALS(in1) call xvv_initop (in1, nelem, dtype) call amovks (v_s, Mems[O_VALP(in1)], nelem) case TY_INT: v_i = O_VALI(in1) call xvv_initop (in1, nelem, dtype) call amovki (v_i, Memi[O_VALP(in1)], nelem) case TY_LONG: v_l = O_VALL(in1) call xvv_initop (in1, nelem, dtype) call amovkl (v_l, Meml[O_VALP(in1)], nelem) case TY_REAL: v_r = O_VALR(in1) call xvv_initop (in1, nelem, dtype) call amovkr (v_r, Memr[O_VALP(in1)], nelem) case TY_DOUBLE: v_d = O_VALD(in1) call xvv_initop (in1, nelem, dtype) call amovkd (v_d, Memd[O_VALP(in1)], nelem) } } len1 = O_LEN(in1) len2 = O_LEN(in2) } # Initialize the output operand. call xvv_initop (out, nelem, dtype) p1 = O_VALP(in1) p2 = O_VALP(in2) po = O_VALP(out) # The bitwise boolean binary operators a special case since only the # integer datatypes are permitted. Otherwise the bitwise booleans # are just like arithmetic booleans. if (opcode == BAND || opcode == BOR || opcode == BXOR) { switch (dtype) { case TY_SHORT: switch (opcode) { case BAND: if (len1 <= 0) { O_VALS(out) = and (O_VALS(in1), O_VALS(in2)) } else if (len2 <= 0) { call aandks (Mems[p1], O_VALS(in2), Mems[po], nelem) } else { call aands (Mems[p1], Mems[p2], Mems[po], nelem) } case BOR: if (len1 <= 0) { O_VALS(out) = or (O_VALS(in1), O_VALS(in2)) } else if (len2 <= 0) { call aborks (Mems[p1], O_VALS(in2), Mems[po], nelem) } else { call abors (Mems[p1], Mems[p2], Mems[po], nelem) } case BXOR: if (len1 <= 0) { O_VALS(out) = xor (O_VALS(in1), O_VALS(in2)) } else if (len2 <= 0) { call axorks (Mems[p1], O_VALS(in2), Mems[po], nelem) } else { call axors (Mems[p1], Mems[p2], Mems[po], nelem) } } case TY_INT: switch (opcode) { case BAND: if (len1 <= 0) { O_VALI(out) = and (O_VALI(in1), O_VALI(in2)) } else if (len2 <= 0) { call aandki (Memi[p1], O_VALI(in2), Memi[po], nelem) } else { call aandi (Memi[p1], Memi[p2], Memi[po], nelem) } case BOR: if (len1 <= 0) { O_VALI(out) = or (O_VALI(in1), O_VALI(in2)) } else if (len2 <= 0) { call aborki (Memi[p1], O_VALI(in2), Memi[po], nelem) } else { call abori (Memi[p1], Memi[p2], Memi[po], nelem) } case BXOR: if (len1 <= 0) { O_VALI(out) = xor (O_VALI(in1), O_VALI(in2)) } else if (len2 <= 0) { call axorki (Memi[p1], O_VALI(in2), Memi[po], nelem) } else { call axori (Memi[p1], Memi[p2], Memi[po], nelem) } } case TY_LONG: switch (opcode) { case BAND: if (len1 <= 0) { O_VALL(out) = and (O_VALL(in1), O_VALL(in2)) } else if (len2 <= 0) { call aandkl (Meml[p1], O_VALL(in2), Meml[po], nelem) } else { call aandl (Meml[p1], Meml[p2], Meml[po], nelem) } case BOR: if (len1 <= 0) { O_VALL(out) = or (O_VALL(in1), O_VALL(in2)) } else if (len2 <= 0) { call aborkl (Meml[p1], O_VALL(in2), Meml[po], nelem) } else { call aborl (Meml[p1], Meml[p2], Meml[po], nelem) } case BXOR: if (len1 <= 0) { O_VALL(out) = xor (O_VALL(in1), O_VALL(in2)) } else if (len2 <= 0) { call axorkl (Meml[p1], O_VALL(in2), Meml[po], nelem) } else { call axorl (Meml[p1], Meml[p2], Meml[po], nelem) } } default: call xvv_error (s_boolop) } goto done_ } # Perform an arithmetic binary operation. switch (dtype) { case TY_CHAR: switch (opcode) { case CONCAT: call strcpy (O_VALC(in1), O_VALC(out), ARB) call strcat (O_VALC(in2), O_VALC(out), ARB) default: call xvv_error ("binop: operation illegal for string operands") } case TY_SHORT: switch (opcode) { case PLUS: if (len1 <= 0) { O_VALS(out) = O_VALS(in1) + O_VALS(in2) } else if (len2 <= 0) { call aaddks (Mems[p1], O_VALS(in2), Mems[po], nelem) } else { call aadds (Mems[p1], Mems[p2], Mems[po], nelem) } case MINUS: if (len1 <= 0) O_VALS(out) = O_VALS(in1) - O_VALS(in2) else if (len2 <= 0) call asubks (Mems[p1], O_VALS(in2), Mems[po], nelem) else call asubs (Mems[p1], Mems[p2], Mems[po], nelem) case STAR: if (len1 <= 0) O_VALS(out) = O_VALS(in1) * O_VALS(in2) else if (len2 <= 0) call amulks (Mems[p1], O_VALS(in2), Mems[po], nelem) else call amuls (Mems[p1], Mems[p2], Mems[po], nelem) case SLASH: if (and (ev_flags, EV_RNGCHK) == 0) { # No range checking. if (len1 <= 0) O_VALS(out) = O_VALS(in1) / O_VALS(in2) else if (len2 <= 0) call adivks (Mems[p1], O_VALS(in2), Mems[po], nelem) else call adivs (Mems[p1], Mems[p2], Mems[po], nelem) } else { # Check for divide by zero. if (len1 <= 0) { if (O_VALS(in2) == 0) O_VALS(out) = xvv_nulls(0) else O_VALS(out) = O_VALS(in1) / O_VALS(in2) } else if (len2 <= 0) { if (O_VALS(in2) == 0) call amovks (xvv_nulls(0), Mems[po], nelem) else { call adivks (Mems[p1], O_VALS(in2), Mems[po], nelem) } } else { call advzs (Mems[p1], Mems[p2], Mems[po], nelem, xvv_nulls) } } case EXPON: if (len1 <= 0) O_VALS(out) = O_VALS(in1) ** O_VALS(in2) else if (len2 <= 0) call aexpks (Mems[p1], O_VALS(in2), Mems[po], nelem) else call aexps (Mems[p1], Mems[p2], Mems[po], nelem) case CONCAT: # Concatenate two numeric operands. if (len1 <= 0) { Mems[po] = O_VALS(in1) po = po + 1 } else { call amovs (Mems[p1], Mems[po], len1) po = po + len1 } if (len2 <= 0) Mems[po] = O_VALS(in2) else call amovs (Mems[p2], Mems[po], len2) default: call xvv_error (s_badswitch) } case TY_INT: switch (opcode) { case PLUS: if (len1 <= 0) { O_VALI(out) = O_VALI(in1) + O_VALI(in2) } else if (len2 <= 0) { call aaddki (Memi[p1], O_VALI(in2), Memi[po], nelem) } else { call aaddi (Memi[p1], Memi[p2], Memi[po], nelem) } case MINUS: if (len1 <= 0) O_VALI(out) = O_VALI(in1) - O_VALI(in2) else if (len2 <= 0) call asubki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call asubi (Memi[p1], Memi[p2], Memi[po], nelem) case STAR: if (len1 <= 0) O_VALI(out) = O_VALI(in1) * O_VALI(in2) else if (len2 <= 0) call amulki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call amuli (Memi[p1], Memi[p2], Memi[po], nelem) case SLASH: if (and (ev_flags, EV_RNGCHK) == 0) { # No range checking. if (len1 <= 0) O_VALI(out) = O_VALI(in1) / O_VALI(in2) else if (len2 <= 0) call adivki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call adivi (Memi[p1], Memi[p2], Memi[po], nelem) } else { # Check for divide by zero. if (len1 <= 0) { if (O_VALI(in2) == 0) O_VALI(out) = xvv_nulli(0) else O_VALI(out) = O_VALI(in1) / O_VALI(in2) } else if (len2 <= 0) { if (O_VALI(in2) == 0) call amovki (xvv_nulli(0), Memi[po], nelem) else { call adivki (Memi[p1], O_VALI(in2), Memi[po], nelem) } } else { call advzi (Memi[p1], Memi[p2], Memi[po], nelem, xvv_nulli) } } case EXPON: if (len1 <= 0) O_VALI(out) = O_VALI(in1) ** O_VALI(in2) else if (len2 <= 0) call aexpki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call aexpi (Memi[p1], Memi[p2], Memi[po], nelem) case CONCAT: # Concatenate two numeric operands. if (len1 <= 0) { Memi[po] = O_VALI(in1) po = po + 1 } else { call amovi (Memi[p1], Memi[po], len1) po = po + len1 } if (len2 <= 0) Memi[po] = O_VALI(in2) else call amovi (Memi[p2], Memi[po], len2) default: call xvv_error (s_badswitch) } case TY_LONG: switch (opcode) { case PLUS: if (len1 <= 0) { O_VALL(out) = O_VALL(in1) + O_VALL(in2) } else if (len2 <= 0) { call aaddkl (Meml[p1], O_VALL(in2), Meml[po], nelem) } else { call aaddl (Meml[p1], Meml[p2], Meml[po], nelem) } case MINUS: if (len1 <= 0) O_VALL(out) = O_VALL(in1) - O_VALL(in2) else if (len2 <= 0) call asubkl (Meml[p1], O_VALL(in2), Meml[po], nelem) else call asubl (Meml[p1], Meml[p2], Meml[po], nelem) case STAR: if (len1 <= 0) O_VALL(out) = O_VALL(in1) * O_VALL(in2) else if (len2 <= 0) call amulkl (Meml[p1], O_VALL(in2), Meml[po], nelem) else call amull (Meml[p1], Meml[p2], Meml[po], nelem) case SLASH: if (and (ev_flags, EV_RNGCHK) == 0) { # No range checking. if (len1 <= 0) O_VALL(out) = O_VALL(in1) / O_VALL(in2) else if (len2 <= 0) call adivkl (Meml[p1], O_VALL(in2), Meml[po], nelem) else call adivl (Meml[p1], Meml[p2], Meml[po], nelem) } else { # Check for divide by zero. if (len1 <= 0) { if (O_VALL(in2) == 0) O_VALL(out) = xvv_nulll(0) else O_VALL(out) = O_VALL(in1) / O_VALL(in2) } else if (len2 <= 0) { if (O_VALL(in2) == 0) call amovkl (xvv_nulll(0), Meml[po], nelem) else { call adivkl (Meml[p1], O_VALL(in2), Meml[po], nelem) } } else { call advzl (Meml[p1], Meml[p2], Meml[po], nelem, xvv_nulll) } } case EXPON: if (len1 <= 0) O_VALL(out) = O_VALL(in1) ** O_VALL(in2) else if (len2 <= 0) call aexpkl (Meml[p1], O_VALL(in2), Meml[po], nelem) else call aexpl (Meml[p1], Meml[p2], Meml[po], nelem) case CONCAT: # Concatenate two numeric operands. if (len1 <= 0) { Meml[po] = O_VALL(in1) po = po + 1 } else { call amovl (Meml[p1], Meml[po], len1) po = po + len1 } if (len2 <= 0) Meml[po] = O_VALL(in2) else call amovl (Meml[p2], Meml[po], len2) default: call xvv_error (s_badswitch) } case TY_REAL: switch (opcode) { case PLUS: if (len1 <= 0) { O_VALR(out) = O_VALR(in1) + O_VALR(in2) } else if (len2 <= 0) { call aaddkr (Memr[p1], O_VALR(in2), Memr[po], nelem) } else { call aaddr (Memr[p1], Memr[p2], Memr[po], nelem) } case MINUS: if (len1 <= 0) O_VALR(out) = O_VALR(in1) - O_VALR(in2) else if (len2 <= 0) call asubkr (Memr[p1], O_VALR(in2), Memr[po], nelem) else call asubr (Memr[p1], Memr[p2], Memr[po], nelem) case STAR: if (len1 <= 0) O_VALR(out) = O_VALR(in1) * O_VALR(in2) else if (len2 <= 0) call amulkr (Memr[p1], O_VALR(in2), Memr[po], nelem) else call amulr (Memr[p1], Memr[p2], Memr[po], nelem) case SLASH: if (and (ev_flags, EV_RNGCHK) == 0) { # No range checking. if (len1 <= 0) O_VALR(out) = O_VALR(in1) / O_VALR(in2) else if (len2 <= 0) call adivkr (Memr[p1], O_VALR(in2), Memr[po], nelem) else call adivr (Memr[p1], Memr[p2], Memr[po], nelem) } else { # Check for divide by zero. if (len1 <= 0) { if (O_VALR(in2) == 0.0) O_VALR(out) = xvv_nullr(0.0) else O_VALR(out) = O_VALR(in1) / O_VALR(in2) } else if (len2 <= 0) { if (O_VALR(in2) == 0.0) call amovkr (xvv_nullr(0.0), Memr[po], nelem) else { call adivkr (Memr[p1], O_VALR(in2), Memr[po], nelem) } } else { call advzr (Memr[p1], Memr[p2], Memr[po], nelem, xvv_nullr) } } case EXPON: if (len1 <= 0) O_VALR(out) = O_VALR(in1) ** O_VALR(in2) else if (len2 <= 0) call aexpkr (Memr[p1], O_VALR(in2), Memr[po], nelem) else call aexpr (Memr[p1], Memr[p2], Memr[po], nelem) case CONCAT: # Concatenate two numeric operands. if (len1 <= 0) { Memr[po] = O_VALR(in1) po = po + 1 } else { call amovr (Memr[p1], Memr[po], len1) po = po + len1 } if (len2 <= 0) Memr[po] = O_VALR(in2) else call amovr (Memr[p2], Memr[po], len2) default: call xvv_error (s_badswitch) } case TY_DOUBLE: switch (opcode) { case PLUS: if (len1 <= 0) { O_VALD(out) = O_VALD(in1) + O_VALD(in2) } else if (len2 <= 0) { call aaddkd (Memd[p1], O_VALD(in2), Memd[po], nelem) } else { call aaddd (Memd[p1], Memd[p2], Memd[po], nelem) } case MINUS: if (len1 <= 0) O_VALD(out) = O_VALD(in1) - O_VALD(in2) else if (len2 <= 0) call asubkd (Memd[p1], O_VALD(in2), Memd[po], nelem) else call asubd (Memd[p1], Memd[p2], Memd[po], nelem) case STAR: if (len1 <= 0) O_VALD(out) = O_VALD(in1) * O_VALD(in2) else if (len2 <= 0) call amulkd (Memd[p1], O_VALD(in2), Memd[po], nelem) else call amuld (Memd[p1], Memd[p2], Memd[po], nelem) case SLASH: if (and (ev_flags, EV_RNGCHK) == 0) { # No range checking. if (len1 <= 0) O_VALD(out) = O_VALD(in1) / O_VALD(in2) else if (len2 <= 0) call adivkd (Memd[p1], O_VALD(in2), Memd[po], nelem) else call adivd (Memd[p1], Memd[p2], Memd[po], nelem) } else { # Check for divide by zero. if (len1 <= 0) { if (O_VALD(in2) == 0.0D0) O_VALD(out) = xvv_nulld(0.0D0) else O_VALD(out) = O_VALD(in1) / O_VALD(in2) } else if (len2 <= 0) { if (O_VALD(in2) == 0.0D0) call amovkd (xvv_nulld(0.0D0), Memd[po], nelem) else { call adivkd (Memd[p1], O_VALD(in2), Memd[po], nelem) } } else { call advzd (Memd[p1], Memd[p2], Memd[po], nelem, xvv_nulld) } } case EXPON: if (len1 <= 0) O_VALD(out) = O_VALD(in1) ** O_VALD(in2) else if (len2 <= 0) call aexpkd (Memd[p1], O_VALD(in2), Memd[po], nelem) else call aexpd (Memd[p1], Memd[p2], Memd[po], nelem) case CONCAT: # Concatenate two numeric operands. if (len1 <= 0) { Memd[po] = O_VALD(in1) po = po + 1 } else { call amovd (Memd[p1], Memd[po], len1) po = po + len1 } if (len2 <= 0) Memd[po] = O_VALD(in2) else call amovd (Memd[p2], Memd[po], len2) default: call xvv_error (s_badswitch) } default: call xvv_error (s_badswitch) } done_ # Free any storage in input operands. call xvv_freeop (in1) call xvv_freeop (in2) end # XVV_BOOLOP -- Boolean (actually logical) binary operations. Perform the # indicated logical operation on the two input operands, returning the result # as the output operand. The opcodes implemented by this routine are # characterized by the fact that they all return a logical result (YES or NO # physically expressed as an integer). procedure xvv_boolop (opcode, in1, in2, out) int opcode #I operation to be performed pointer in1, in2 #I input operands pointer out #I output operand short v_s int v_i long v_l real v_r double v_d pointer sp, otemp, p1, p2, po int dtype, nelem, len1, len2 int xvv_newtype(), xvv_patmatch(), strncmp(), btoi() errchk xvv_newtype, xvv_initop, xvv_chtype, xvv_error string s_badop "boolop: illegal operation" string s_badswitch "boolop: illegal switch" begin # Boolean operands are treated as integer within this routine. if (O_TYPE(in1) == TY_BOOL) O_TYPE(in1) = TY_INT if (O_TYPE(in2) == TY_BOOL) O_TYPE(in2) = TY_INT # Determine the computation type for the operation, i.e., the type # both input operands must have. This is not the same as the type # of the output operand, which is always boolean for the operations # implemented by this routine. dtype = xvv_newtype (O_TYPE(in1), O_TYPE(in2)) # Compute the size of the output operand. If both input operands are # vectors the length of the output vector is the shorter of the two. if (dtype == TY_CHAR) nelem = 0 else { if (O_LEN(in1) > 0 && O_LEN(in2) > 0) nelem = min (O_LEN(in1), O_LEN(in2)) else if (O_LEN(in1) > 0) nelem = O_LEN(in1) else if (O_LEN(in2) > 0) nelem = O_LEN(in2) else nelem = 0 } # Convert input operands to desired computation type. if (O_TYPE(in1) != dtype) call xvv_chtype (in1, in1, dtype) if (O_TYPE(in2) != dtype) call xvv_chtype (in2, in2, dtype) # If this is a scalar/vector operation make sure the vector is the # first operand. len1 = O_LEN(in1) len2 = O_LEN(in2) if (len1 == 0 && len2 > 0) { switch (opcode) { case EQ, NE: call smark (sp) call salloc (otemp, LEN_OPERAND, TY_STRUCT) YYMOVE (in1, otemp) YYMOVE (in2, in1) YYMOVE (otemp, in2) call sfree (sp) default: # Promote operand to a constant vector. Inefficient, but # better than aborting. switch (dtype) { case TY_SHORT: v_s = O_VALS(in1) call xvv_initop (in1, nelem, dtype) call amovks (v_s, Mems[O_VALP(in1)], nelem) case TY_INT: v_i = O_VALI(in1) call xvv_initop (in1, nelem, dtype) call amovki (v_i, Memi[O_VALP(in1)], nelem) case TY_LONG: v_l = O_VALL(in1) call xvv_initop (in1, nelem, dtype) call amovkl (v_l, Meml[O_VALP(in1)], nelem) case TY_REAL: v_r = O_VALR(in1) call xvv_initop (in1, nelem, dtype) call amovkr (v_r, Memr[O_VALP(in1)], nelem) case TY_DOUBLE: v_d = O_VALD(in1) call xvv_initop (in1, nelem, dtype) call amovkd (v_d, Memd[O_VALP(in1)], nelem) } } len1 = O_LEN(in1) len2 = O_LEN(in2) } # Initialize the output operand. call xvv_initop (out, nelem, TY_BOOL) p1 = O_VALP(in1) p2 = O_VALP(in2) po = O_VALP(out) # Perform the operation. if (dtype == TY_CHAR) { # Character data is a special case. switch (opcode) { case SE: O_VALI(out) = btoi(xvv_patmatch (O_VALC(in1), O_VALC(in2)) > 0) case LT: O_VALI(out) = btoi(strncmp (O_VALC(in1), O_VALC(in2), ARB) < 0) case LE: O_VALI(out) = btoi(strncmp (O_VALC(in1), O_VALC(in2), ARB) <= 0) case GT: O_VALI(out) = btoi(strncmp (O_VALC(in1), O_VALC(in2), ARB) > 0) case GE: O_VALI(out) = btoi(strncmp (O_VALC(in1), O_VALC(in2), ARB) >= 0) case EQ: O_VALI(out) = btoi(strncmp (O_VALC(in1), O_VALC(in2), ARB) == 0) case NE: O_VALI(out) = btoi(strncmp (O_VALC(in1), O_VALC(in2), ARB) != 0) default: call xvv_error (s_badop) } } else if (opcode == LAND || opcode == LOR) { # Operations supporting only the integer types. switch (dtype) { case TY_SHORT: switch (opcode) { case LAND: if (len1 <= 0) { O_VALI(out) = btoi (O_VALS(in1) != 0 && O_VALS(in2) != 0) } else if (len2 <= 0) { call alanks (Mems[p1], O_VALS(in2), Memi[po], nelem) } else call alans (Mems[p1], Mems[p2], Memi[po], nelem) case LOR: if (len1 <= 0) { O_VALI(out) = btoi (O_VALS(in1) != 0 || O_VALS(in2) != 0) } else if (len2 <= 0) { call alorks (Mems[p1], O_VALS(in2), Memi[po], nelem) } else call alors (Mems[p1], Mems[p2], Memi[po], nelem) default: call xvv_error (s_badop) } case TY_INT: switch (opcode) { case LAND: if (len1 <= 0) { O_VALI(out) = btoi (O_VALI(in1) != 0 && O_VALI(in2) != 0) } else if (len2 <= 0) { call alanki (Memi[p1], O_VALI(in2), Memi[po], nelem) } else call alani (Memi[p1], Memi[p2], Memi[po], nelem) case LOR: if (len1 <= 0) { O_VALI(out) = btoi (O_VALI(in1) != 0 || O_VALI(in2) != 0) } else if (len2 <= 0) { call alorki (Memi[p1], O_VALI(in2), Memi[po], nelem) } else call alori (Memi[p1], Memi[p2], Memi[po], nelem) default: call xvv_error (s_badop) } case TY_LONG: switch (opcode) { case LAND: if (len1 <= 0) { O_VALI(out) = btoi (O_VALL(in1) != 0 && O_VALL(in2) != 0) } else if (len2 <= 0) { call alankl (Meml[p1], O_VALL(in2), Memi[po], nelem) } else call alanl (Meml[p1], Meml[p2], Memi[po], nelem) case LOR: if (len1 <= 0) { O_VALI(out) = btoi (O_VALL(in1) != 0 || O_VALL(in2) != 0) } else if (len2 <= 0) { call alorkl (Meml[p1], O_VALL(in2), Memi[po], nelem) } else call alorl (Meml[p1], Meml[p2], Memi[po], nelem) default: call xvv_error (s_badop) } default: call xvv_error (s_badswitch) } } else { # Operations supporting any arithmetic type. switch (dtype) { case TY_SHORT: switch (opcode) { case LT: if (len1 <= 0) O_VALI(out) = btoi (O_VALS(in1) < O_VALS(in2)) else if (len2 <= 0) call abltks (Mems[p1], O_VALS(in2), Memi[po], nelem) else call ablts (Mems[p1], Mems[p2], Memi[po], nelem) case LE: if (len1 <= 0) O_VALI(out) = btoi (O_VALS(in1) <= O_VALS(in2)) else if (len2 <= 0) call ableks (Mems[p1], O_VALS(in2), Memi[po], nelem) else call ables (Mems[p1], Mems[p2], Memi[po], nelem) case GT: if (len1 <= 0) O_VALI(out) = btoi (O_VALS(in1) > O_VALS(in2)) else if (len2 <= 0) call abgtks (Mems[p1], O_VALS(in2), Memi[po], nelem) else call abgts (Mems[p1], Mems[p2], Memi[po], nelem) case GE: if (len1 <= 0) O_VALI(out) = btoi (O_VALS(in1) >= O_VALS(in2)) else if (len2 <= 0) call abgeks (Mems[p1], O_VALS(in2), Memi[po], nelem) else call abges (Mems[p1], Mems[p2], Memi[po], nelem) case EQ: if (len1 <= 0) O_VALI(out) = btoi (O_VALS(in1) == O_VALS(in2)) else if (len2 <= 0) call abeqks (Mems[p1], O_VALS(in2), Memi[po], nelem) else call abeqs (Mems[p1], Mems[p2], Memi[po], nelem) case NE: if (len1 <= 0) O_VALI(out) = btoi (O_VALS(in1) != O_VALS(in2)) else if (len2 <= 0) call abneks (Mems[p1], O_VALS(in2), Memi[po], nelem) else call abnes (Mems[p1], Mems[p2], Memi[po], nelem) default: call xvv_error (s_badop) } case TY_INT: switch (opcode) { case LT: if (len1 <= 0) O_VALI(out) = btoi (O_VALI(in1) < O_VALI(in2)) else if (len2 <= 0) call abltki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call ablti (Memi[p1], Memi[p2], Memi[po], nelem) case LE: if (len1 <= 0) O_VALI(out) = btoi (O_VALI(in1) <= O_VALI(in2)) else if (len2 <= 0) call ableki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call ablei (Memi[p1], Memi[p2], Memi[po], nelem) case GT: if (len1 <= 0) O_VALI(out) = btoi (O_VALI(in1) > O_VALI(in2)) else if (len2 <= 0) call abgtki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call abgti (Memi[p1], Memi[p2], Memi[po], nelem) case GE: if (len1 <= 0) O_VALI(out) = btoi (O_VALI(in1) >= O_VALI(in2)) else if (len2 <= 0) call abgeki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call abgei (Memi[p1], Memi[p2], Memi[po], nelem) case EQ: if (len1 <= 0) O_VALI(out) = btoi (O_VALI(in1) == O_VALI(in2)) else if (len2 <= 0) call abeqki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call abeqi (Memi[p1], Memi[p2], Memi[po], nelem) case NE: if (len1 <= 0) O_VALI(out) = btoi (O_VALI(in1) != O_VALI(in2)) else if (len2 <= 0) call abneki (Memi[p1], O_VALI(in2), Memi[po], nelem) else call abnei (Memi[p1], Memi[p2], Memi[po], nelem) default: call xvv_error (s_badop) } case TY_LONG: switch (opcode) { case LT: if (len1 <= 0) O_VALI(out) = btoi (O_VALL(in1) < O_VALL(in2)) else if (len2 <= 0) call abltkl (Meml[p1], O_VALL(in2), Memi[po], nelem) else call abltl (Meml[p1], Meml[p2], Memi[po], nelem) case LE: if (len1 <= 0) O_VALI(out) = btoi (O_VALL(in1) <= O_VALL(in2)) else if (len2 <= 0) call ablekl (Meml[p1], O_VALL(in2), Memi[po], nelem) else call ablel (Meml[p1], Meml[p2], Memi[po], nelem) case GT: if (len1 <= 0) O_VALI(out) = btoi (O_VALL(in1) > O_VALL(in2)) else if (len2 <= 0) call abgtkl (Meml[p1], O_VALL(in2), Memi[po], nelem) else call abgtl (Meml[p1], Meml[p2], Memi[po], nelem) case GE: if (len1 <= 0) O_VALI(out) = btoi (O_VALL(in1) >= O_VALL(in2)) else if (len2 <= 0) call abgekl (Meml[p1], O_VALL(in2), Memi[po], nelem) else call abgel (Meml[p1], Meml[p2], Memi[po], nelem) case EQ: if (len1 <= 0) O_VALI(out) = btoi (O_VALL(in1) == O_VALL(in2)) else if (len2 <= 0) call abeqkl (Meml[p1], O_VALL(in2), Memi[po], nelem) else call abeql (Meml[p1], Meml[p2], Memi[po], nelem) case NE: if (len1 <= 0) O_VALI(out) = btoi (O_VALL(in1) != O_VALL(in2)) else if (len2 <= 0) call abnekl (Meml[p1], O_VALL(in2), Memi[po], nelem) else call abnel (Meml[p1], Meml[p2], Memi[po], nelem) default: call xvv_error (s_badop) } case TY_REAL: switch (opcode) { case LT: if (len1 <= 0) O_VALI(out) = btoi (O_VALR(in1) < O_VALR(in2)) else if (len2 <= 0) call abltkr (Memr[p1], O_VALR(in2), Memi[po], nelem) else call abltr (Memr[p1], Memr[p2], Memi[po], nelem) case LE: if (len1 <= 0) O_VALI(out) = btoi (O_VALR(in1) <= O_VALR(in2)) else if (len2 <= 0) call ablekr (Memr[p1], O_VALR(in2), Memi[po], nelem) else call abler (Memr[p1], Memr[p2], Memi[po], nelem) case GT: if (len1 <= 0) O_VALI(out) = btoi (O_VALR(in1) > O_VALR(in2)) else if (len2 <= 0) call abgtkr (Memr[p1], O_VALR(in2), Memi[po], nelem) else call abgtr (Memr[p1], Memr[p2], Memi[po], nelem) case GE: if (len1 <= 0) O_VALI(out) = btoi (O_VALR(in1) >= O_VALR(in2)) else if (len2 <= 0) call abgekr (Memr[p1], O_VALR(in2), Memi[po], nelem) else call abger (Memr[p1], Memr[p2], Memi[po], nelem) case EQ: if (len1 <= 0) O_VALI(out) = btoi (O_VALR(in1) == O_VALR(in2)) else if (len2 <= 0) call abeqkr (Memr[p1], O_VALR(in2), Memi[po], nelem) else call abeqr (Memr[p1], Memr[p2], Memi[po], nelem) case NE: if (len1 <= 0) O_VALI(out) = btoi (O_VALR(in1) != O_VALR(in2)) else if (len2 <= 0) call abnekr (Memr[p1], O_VALR(in2), Memi[po], nelem) else call abner (Memr[p1], Memr[p2], Memi[po], nelem) default: call xvv_error (s_badop) } case TY_DOUBLE: switch (opcode) { case LT: if (len1 <= 0) O_VALI(out) = btoi (O_VALD(in1) < O_VALD(in2)) else if (len2 <= 0) call abltkd (Memd[p1], O_VALD(in2), Memi[po], nelem) else call abltd (Memd[p1], Memd[p2], Memi[po], nelem) case LE: if (len1 <= 0) O_VALI(out) = btoi (O_VALD(in1) <= O_VALD(in2)) else if (len2 <= 0) call ablekd (Memd[p1], O_VALD(in2), Memi[po], nelem) else call abled (Memd[p1], Memd[p2], Memi[po], nelem) case GT: if (len1 <= 0) O_VALI(out) = btoi (O_VALD(in1) > O_VALD(in2)) else if (len2 <= 0) call abgtkd (Memd[p1], O_VALD(in2), Memi[po], nelem) else call abgtd (Memd[p1], Memd[p2], Memi[po], nelem) case GE: if (len1 <= 0) O_VALI(out) = btoi (O_VALD(in1) >= O_VALD(in2)) else if (len2 <= 0) call abgekd (Memd[p1], O_VALD(in2), Memi[po], nelem) else call abged (Memd[p1], Memd[p2], Memi[po], nelem) case EQ: if (len1 <= 0) O_VALI(out) = btoi (O_VALD(in1) == O_VALD(in2)) else if (len2 <= 0) call abeqkd (Memd[p1], O_VALD(in2), Memi[po], nelem) else call abeqd (Memd[p1], Memd[p2], Memi[po], nelem) case NE: if (len1 <= 0) O_VALI(out) = btoi (O_VALD(in1) != O_VALD(in2)) else if (len2 <= 0) call abnekd (Memd[p1], O_VALD(in2), Memi[po], nelem) else call abned (Memd[p1], Memd[p2], Memi[po], nelem) default: call xvv_error (s_badop) } default: call xvv_error (s_badswitch) } } # Free any storage in input operands. call xvv_freeop (in1) call xvv_freeop (in2) end # XVV_PATMATCH -- Match a string against a pattern, returning the patmatch # index if the string matches. The pattern may contain any of the conventional # pattern matching metacharacters. Closure (i.e., "*") is mapped to "?*". int procedure xvv_patmatch (str, pat) char str[ARB] #I operand string char pat[ARB] #I pattern int junk, ip, index pointer sp, patstr, patbuf, op int patmake(), patmatch() begin call smark (sp) call salloc (patstr, SZ_FNAME, TY_CHAR) call salloc (patbuf, SZ_LINE, TY_CHAR) call aclrc (Memc[patstr], SZ_FNAME) call aclrc (Memc[patbuf], SZ_LINE) # Map pattern, changing '*' into '?*'. op = patstr for (ip=1; pat[ip] != EOS; ip=ip+1) { if (pat[ip] == '*') { Memc[op] = '?' op = op + 1 } Memc[op] = pat[ip] op = op + 1 } # Encode pattern. junk = patmake (Memc[patstr], Memc[patbuf], SZ_LINE) # Perform the pattern matching operation. index = patmatch (str, Memc[patbuf]) call sfree (sp) return (index) end # XVV_NEWTYPE -- Get the datatype of a binary operation, given the datatypes # of the two input operands. An error action is taken if the datatypes are # incompatible, e.g., boolean and anything else or string and anything else. int procedure xvv_newtype (type1, type2) int type1 #I datatype of first operand int type2 #I datatype of second operand int newtype, p, q, i int tyindex[NTYPES], ttbl[NTYPES*NTYPES] data tyindex /T_B, T_C, T_S, T_I, T_L, T_R, T_D/ data (ttbl(i),i= 1, 7) /T_B, 0, 0, 0, 0, 0, 0/ data (ttbl(i),i= 8,14) / 0, T_C, 0, 0, 0, 0, 0/ data (ttbl(i),i=15,21) / 0, 0, T_S, T_I, T_L, T_R, T_D/ data (ttbl(i),i=22,28) / 0, 0, T_I, T_I, T_L, T_R, T_D/ data (ttbl(i),i=29,35) / 0, 0, T_L, T_L, T_L, T_R, T_D/ data (ttbl(i),i=36,42) / 0, 0, T_R, T_R, T_R, T_R, T_D/ data (ttbl(i),i=43,49) / 0, 0, T_D, T_D, T_D, T_D, T_D/ begin do i = 1, NTYPES { if (tyindex[i] == type1) p = i if (tyindex[i] == type2) q = i } newtype = ttbl[(p-1)*NTYPES+q] if (newtype == 0) call xvv_error ("operands have incompatible types") else return (newtype) end # XVV_QUEST -- Conditional expression. If the condition operand is true # return the first (true) operand, else return the second (false) operand. procedure xvv_quest (cond, in1, in2, out) pointer cond #I pointer to condition operand pointer in1, in2 #I pointer to true,false operands pointer out #I pointer to output operand int dtype, nelem, i pointer sp, otemp, ip1, ip2, op, sel errchk xvv_error, xvv_newtype, xvv_initop, xvv_chtype int xvv_newtype(), btoi() begin switch (O_TYPE(cond)) { case TY_BOOL, TY_INT: ; case TY_SHORT, TY_LONG: call xvv_chtype (cond, cond, TY_BOOL) default: call xvv_error ("evvexpr: nonboolean condition operand") } if (O_LEN(cond) <= 0 && (O_LEN(in1) <= 0 || O_TYPE(in1) == TY_CHAR) && (O_LEN(in2) <= 0 || O_TYPE(in2) == TY_CHAR)) { # Both operands and the conditional are scalars; the expression # type is the type of the selected operand. if (O_VALI(cond) != 0) { YYMOVE (in1, out) call xvv_freeop (in2) } else { YYMOVE (in2, out) call xvv_freeop (in1) } } else if (O_TYPE(in1) == TY_CHAR || O_TYPE(in2) == TY_CHAR) { # This combination is not legal. call xvv_error ("evvexpr: character and vector in cond expr") } else { # Vector/scalar or vector/vector operation. Both operands must # be of the same type. dtype = xvv_newtype (O_TYPE(in1), O_TYPE(in2)) # Compute the size of the output operand. If both input operands # are vectors the length of the output vector is the shorter of # the two. The condition operand contributes to the dimension of # the expression result, although not to the datatype. nelem = 0 if (O_LEN(in1) > 0 && O_LEN(in2) > 0) nelem = min (O_LEN(in1), O_LEN(in2)) else if (O_LEN(in1) > 0) nelem = O_LEN(in1) else if (O_LEN(in2) > 0) nelem = O_LEN(in2) if (O_LEN(cond) > 0 && nelem > 0) nelem = min (O_LEN(cond), nelem) else if (O_LEN(cond) > 0) nelem = O_LEN(cond) # If this is a scalar/vector operation make sure the vector is the # first operand. if (O_LEN(in1) == 0 && O_LEN(in2) > 0) { call smark (sp) call salloc (otemp, LEN_OPERAND, TY_STRUCT) YYMOVE (in1, otemp) YYMOVE (in2, in1) YYMOVE (otemp, in2) call sfree (sp) # Since we are swapping arguments we need to negate the cond. if (O_LEN(cond) <= 0) O_VALI(cond) = btoi (O_VALI(cond) == 0) else { call abeqki (Memi[O_VALP(cond)], NO, Memi[O_VALP(cond)], nelem) } } # Initialize the output operand. call xvv_initop (out, nelem, dtype) # Convert input operands to desired computation type. if (O_TYPE(in1) != dtype) call xvv_chtype (in1, in1, dtype) if (O_TYPE(in2) != dtype) call xvv_chtype (in2, in2, dtype) ip1 = O_VALP(in1) ip2 = O_VALP(in2) op = O_VALP(out) sel = O_VALP(cond) # Perform the operation. switch (dtype) { case TY_SHORT: if (O_LEN(in1) <= 0 && O_LEN(in2) <= 0) { # Vector conditional, both operands are scalars. do i = 1, nelem if (Memi[sel+i-1] != 0) Mems[op+i-1] = O_VALS(in1) else Mems[op+i-1] = O_VALS(in2) } else if (O_LEN(in2) <= 0) { # Operand 1 is a vector, operand 2 is a scalar. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovs (Mems[ip1], Mems[op], nelem) else call amovks (O_VALS(in2), Mems[op], nelem) } else { # Conditional is a vector. call aselks (Mems[ip1], O_VALS(in2), Mems[op], Memi[sel], nelem) } } else { # Both operands are vectors. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovs (Mems[ip1], Mems[op], nelem) else call amovs (Mems[ip2], Mems[op], nelem) } else { # Conditional is a vector. call asels (Mems[ip1], Mems[ip2], Mems[op], Memi[sel], nelem) } } case TY_INT: if (O_LEN(in1) <= 0 && O_LEN(in2) <= 0) { # Vector conditional, both operands are scalars. do i = 1, nelem if (Memi[sel+i-1] != 0) Memi[op+i-1] = O_VALI(in1) else Memi[op+i-1] = O_VALI(in2) } else if (O_LEN(in2) <= 0) { # Operand 1 is a vector, operand 2 is a scalar. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovi (Memi[ip1], Memi[op], nelem) else call amovki (O_VALI(in2), Memi[op], nelem) } else { # Conditional is a vector. call aselki (Memi[ip1], O_VALI(in2), Memi[op], Memi[sel], nelem) } } else { # Both operands are vectors. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovi (Memi[ip1], Memi[op], nelem) else call amovi (Memi[ip2], Memi[op], nelem) } else { # Conditional is a vector. call aseli (Memi[ip1], Memi[ip2], Memi[op], Memi[sel], nelem) } } case TY_LONG: if (O_LEN(in1) <= 0 && O_LEN(in2) <= 0) { # Vector conditional, both operands are scalars. do i = 1, nelem if (Memi[sel+i-1] != 0) Meml[op+i-1] = O_VALL(in1) else Meml[op+i-1] = O_VALL(in2) } else if (O_LEN(in2) <= 0) { # Operand 1 is a vector, operand 2 is a scalar. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovl (Meml[ip1], Meml[op], nelem) else call amovkl (O_VALL(in2), Meml[op], nelem) } else { # Conditional is a vector. call aselkl (Meml[ip1], O_VALL(in2), Meml[op], Memi[sel], nelem) } } else { # Both operands are vectors. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovl (Meml[ip1], Meml[op], nelem) else call amovl (Meml[ip2], Meml[op], nelem) } else { # Conditional is a vector. call asell (Meml[ip1], Meml[ip2], Meml[op], Memi[sel], nelem) } } case TY_REAL: if (O_LEN(in1) <= 0 && O_LEN(in2) <= 0) { # Vector conditional, both operands are scalars. do i = 1, nelem if (Memi[sel+i-1] != 0) Memr[op+i-1] = O_VALR(in1) else Memr[op+i-1] = O_VALR(in2) } else if (O_LEN(in2) <= 0) { # Operand 1 is a vector, operand 2 is a scalar. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovr (Memr[ip1], Memr[op], nelem) else call amovkr (O_VALR(in2), Memr[op], nelem) } else { # Conditional is a vector. call aselkr (Memr[ip1], O_VALR(in2), Memr[op], Memi[sel], nelem) } } else { # Both operands are vectors. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovr (Memr[ip1], Memr[op], nelem) else call amovr (Memr[ip2], Memr[op], nelem) } else { # Conditional is a vector. call aselr (Memr[ip1], Memr[ip2], Memr[op], Memi[sel], nelem) } } case TY_DOUBLE: if (O_LEN(in1) <= 0 && O_LEN(in2) <= 0) { # Vector conditional, both operands are scalars. do i = 1, nelem if (Memi[sel+i-1] != 0) Memd[op+i-1] = O_VALD(in1) else Memd[op+i-1] = O_VALD(in2) } else if (O_LEN(in2) <= 0) { # Operand 1 is a vector, operand 2 is a scalar. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovd (Memd[ip1], Memd[op], nelem) else call amovkd (O_VALD(in2), Memd[op], nelem) } else { # Conditional is a vector. call aselkd (Memd[ip1], O_VALD(in2), Memd[op], Memi[sel], nelem) } } else { # Both operands are vectors. if (O_LEN(cond) <= 0) { # Conditional is a scalar. if (O_VALI(cond) != 0) call amovd (Memd[ip1], Memd[op], nelem) else call amovd (Memd[ip2], Memd[op], nelem) } else { # Conditional is a vector. call aseld (Memd[ip1], Memd[ip2], Memd[op], Memi[sel], nelem) } } default: call xvv_error ("evvexpr: bad datatype in cond expr") } call xvv_freeop (in1) call xvv_freeop (in2) } call xvv_freeop (cond) end # XVV_CALLFCN -- Call an intrinsic function. If the function named is not # one of the standard intrinsic functions, call an external user function # if a function call procedure was supplied. procedure xvv_callfcn (fcn, args, nargs, out) char fcn[ARB] #I function to be called pointer args[ARB] #I pointer to arglist descriptor int nargs #I number of arguments pointer out #I output operand (function value) short v_s short ahivs(), alovs() short ameds() int aravs() int v_i int ahivi(), alovi() int amedi() int aravi() long v_l long ahivl(), alovl() long amedl() int aravl() real v_r real ahivr(), alovr() real amedr() int aravr() double v_d double ahivd(), alovd() double amedd() int aravd() real mean_r, sigma_r double mean_d, sigma_d real asums(), asumi(), asumr() double asuml(), asumd() bool rangecheck int optype, opcode int chunk, repl, nelem, v_nargs, ch, shift, i, j pointer sp, sym, buf, ap, ip, op, in1, in2 include "evvexpr.com" pointer stfind() int xvv_newtype(), strlen(), gctod(), btoi() errchk xvv_chtype, xvv_initop, xvv_newtype, xvv_error1, xvv_error2 errchk zcall5, malloc string s_badtype "%s: illegal operand type" define free_ 91 begin call smark (sp) call salloc (buf, SZ_FNAME, TY_CHAR) # Lookup the function name in the symbol table. sym = stfind (ev_st, fcn) if (sym != NULL) opcode = SYM_CODE(sym) else opcode = 0 # If the function named is not a standard one and the user has supplied # the entry point of an external function evaluation procedure, call # the user procedure to evaluate the function, otherwise abort. if (opcode <= 0) if (ev_ufcn != NULL) { call zcall5 (ev_ufcn, ev_ufcn_data, fcn, args, nargs, out) if (O_TYPE(out) <= 0) call xvv_error1 ("unrecognized macro or function `%s'", fcn) goto free_ } else call xvv_error1 ("unknown function `%s' called", fcn) # Range checking on functions that need it? rangecheck = (and (ev_flags, EV_RNGCHK) != 0) # Verify correct number of arguments. switch (opcode) { case F_MOD, F_REPL, F_SHIFT: v_nargs = 2 case F_MAX, F_MIN, F_ATAN, F_ATAN2, F_MEAN, F_STDDEV, F_MEDIAN: v_nargs = -1 default: v_nargs = 1 } if (v_nargs > 0 && nargs != v_nargs) call xvv_error2 ("function `%s' requires %d arguments", fcn, v_nargs) else if (v_nargs < 0 && nargs < abs(v_nargs)) call xvv_error2 ("function `%s' requires at least %d arguments", fcn, abs(v_nargs)) # Some functions require that the input operand be a certain type, # e.g. floating. Handle the simple cases, converting input operands # to the desired type. switch (opcode) { case F_ACOS, F_ASIN, F_ATAN, F_ATAN2, F_COS, F_COSH, F_DEG, F_EXP, F_LOG, F_LOG10, F_RAD, F_SIN, F_SINH, F_SQRT, F_TAN, F_TANH: # These functions want a floating point input operand. optype = TY_REAL do i = 1, nargs { if (O_TYPE(args[i]) == TY_DOUBLE || O_TYPE(args[i]) == TY_LONG) optype = TY_DOUBLE } do i = 1, nargs { if (O_TYPE(args[i]) != optype) call xvv_chtype (args[i], args[i], optype) } call xvv_initop (out, O_LEN(args[1]), optype) case F_MOD, F_MIN, F_MAX, F_MEDIAN: # These functions may have multiple arguments, all of which # should be the same type. optype = O_TYPE(args[1]) nelem = O_LEN(args[1]) do i = 2, nargs { optype = xvv_newtype (optype, O_TYPE(args[i])) if (O_LEN(args[i]) > 0) if (nelem > 0) nelem = min (nelem, O_LEN(args[i])) else if (nelem == 0) nelem = O_LEN(args[i]) } do i = 1, nargs if (O_TYPE(args[i]) != optype) call xvv_chtype (args[i], args[i], optype) if (nargs == 1 && opcode == F_MEDIAN) nelem = 0 call xvv_initop (out, nelem, optype) case F_LEN: # This function always returns an integer scalar value. nelem = 0 optype = TY_INT call xvv_initop (out, nelem, optype) case F_HIV, F_LOV: # These functions return a scalar value. nelem = 0 optype = O_TYPE(args[1]) if (optype == TY_BOOL) optype = TY_INT call xvv_initop (out, nelem, optype) case F_SUM, F_MEAN, F_STDDEV: # These functions require a vector argument and return a scalar # value. nelem = 0 optype = O_TYPE(args[1]) if (optype == TY_BOOL) optype = TY_INT if (optype == TY_DOUBLE) call xvv_initop (out, nelem, TY_DOUBLE) else call xvv_initop (out, nelem, TY_REAL) case F_SORT, F_SHIFT: # Vector to vector, no type conversions. nelem = O_LEN(args[1]) optype = O_TYPE(args[1]) call xvv_initop (out, nelem, optype) default: optype = 0 } # Evaluate the function. ap = args[1] switch (opcode) { case F_ABS: call xvv_initop (out, O_LEN(ap), O_TYPE(ap)) switch (O_TYPE(ap)) { case TY_SHORT: if (O_LEN(ap) > 0) { call aabss (Mems[O_VALP(ap)], Mems[O_VALP(out)], O_LEN(ap)) } else O_VALS(out) = abs(O_VALS(ap)) case TY_INT: if (O_LEN(ap) > 0) { call aabsi (Memi[O_VALP(ap)], Memi[O_VALP(out)], O_LEN(ap)) } else O_VALI(out) = abs(O_VALI(ap)) case TY_LONG: if (O_LEN(ap) > 0) { call aabsl (Meml[O_VALP(ap)], Meml[O_VALP(out)], O_LEN(ap)) } else O_VALL(out) = abs(O_VALL(ap)) case TY_REAL: if (O_LEN(ap) > 0) { call aabsr (Memr[O_VALP(ap)], Memr[O_VALP(out)], O_LEN(ap)) } else O_VALR(out) = abs(O_VALR(ap)) case TY_DOUBLE: if (O_LEN(ap) > 0) { call aabsd (Memd[O_VALP(ap)], Memd[O_VALP(out)], O_LEN(ap)) } else O_VALD(out) = abs(O_VALD(ap)) default: call xvv_error1 (s_badtype, fcn) } case F_ACOS: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = acos (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = acos (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = acos (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = acos (O_VALD(ap)) case F_ASIN: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = asin (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = asin (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = asin (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = asin (O_VALD(ap)) case F_COS: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = cos (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = cos (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = cos (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = cos (O_VALD(ap)) case F_COSH: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = cosh (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = cosh (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = cosh (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = cosh (O_VALD(ap)) case F_DEG: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = RADTODEG(Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = RADTODEG (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = RADTODEG(Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = RADTODEG (O_VALD(ap)) case F_EXP: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = exp (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = exp (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = exp (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = exp (O_VALD(ap)) case F_LOG: if (optype == TY_REAL) if (O_LEN(ap) > 0) { op = O_VALP(out) do i = 1, O_LEN(ap) { v_r = Memr[O_VALP(ap)+i-1] if (rangecheck && v_r <= 0) Memr[op] = 0 else Memr[op] = log (v_r) op = op + 1 } } else { v_r = O_VALR(ap) if (rangecheck && v_r <= 0) O_VALR(out) = 0 else O_VALR(out) = log (v_r) } if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { op = O_VALP(out) do i = 1, O_LEN(ap) { v_d = Memd[O_VALP(ap)+i-1] if (rangecheck && v_d <= 0) Memd[op] = 0 else Memd[op] = log (v_d) op = op + 1 } } else { v_d = O_VALD(ap) if (rangecheck && v_d <= 0) O_VALD(out) = 0 else O_VALD(out) = log (v_d) } case F_LOG10: if (optype == TY_REAL) if (O_LEN(ap) > 0) { op = O_VALP(out) do i = 1, O_LEN(ap) { v_r = Memr[O_VALP(ap)+i-1] if (rangecheck && v_r <= 0) Memr[op] = 0 else Memr[op] = log10 (v_r) op = op + 1 } } else { v_r = O_VALR(ap) if (rangecheck && v_r <= 0) O_VALR(out) = 0 else O_VALR(out) = log10 (v_r) } if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { op = O_VALP(out) do i = 1, O_LEN(ap) { v_d = Memd[O_VALP(ap)+i-1] if (rangecheck && v_d <= 0) Memd[op] = 0 else Memd[op] = log10 (v_d) op = op + 1 } } else { v_d = O_VALD(ap) if (rangecheck && v_d <= 0) O_VALD(out) = 0 else O_VALD(out) = log10 (v_d) } case F_RAD: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = DEGTORAD(Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = DEGTORAD (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = DEGTORAD(Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = DEGTORAD (O_VALD(ap)) case F_SIN: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = sin (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = sin (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = sin (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = sin (O_VALD(ap)) case F_SINH: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = sinh (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = sinh (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = sinh (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = sinh (O_VALD(ap)) case F_SQRT: if (optype == TY_REAL) if (O_LEN(ap) > 0) { op = O_VALP(out) do i = 1, O_LEN(ap) { v_r = Memr[O_VALP(ap)+i-1] if (rangecheck && v_r < 0) Memr[op] = 0 else Memr[op] = sqrt (v_r) op = op + 1 } } else { v_r = O_VALR(ap) if (rangecheck && v_r <= 0) O_VALR(out) = 0 else O_VALR(out) = sqrt (v_r) } if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { op = O_VALP(out) do i = 1, O_LEN(ap) { v_d = Memd[O_VALP(ap)+i-1] if (rangecheck && v_d < 0) Memd[op] = 0 else Memd[op] = sqrt (v_d) op = op + 1 } } else { v_d = O_VALD(ap) if (rangecheck && v_d <= 0) O_VALD(out) = 0 else O_VALD(out) = sqrt (v_d) } case F_TAN: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = tan (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = tan (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = tan (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = tan (O_VALD(ap)) case F_TANH: if (optype == TY_REAL) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = tanh (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = tanh (O_VALR(ap)) if (optype == TY_DOUBLE) if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = tanh (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = tanh (O_VALD(ap)) case F_LEN: # Vector length. O_VALI(out) = O_LEN(ap) case F_HIV: # High value. switch (optype) { case TY_SHORT: if (O_LEN(ap) > 0) O_VALS(out) = ahivs (Mems[O_VALP(ap)], O_LEN(ap)) else O_VALS(out) = O_VALS(ap) case TY_INT: if (O_LEN(ap) > 0) O_VALI(out) = ahivi (Memi[O_VALP(ap)], O_LEN(ap)) else O_VALI(out) = O_VALI(ap) case TY_LONG: if (O_LEN(ap) > 0) O_VALL(out) = ahivl (Meml[O_VALP(ap)], O_LEN(ap)) else O_VALL(out) = O_VALL(ap) case TY_REAL: if (O_LEN(ap) > 0) O_VALR(out) = ahivr (Memr[O_VALP(ap)], O_LEN(ap)) else O_VALR(out) = O_VALR(ap) case TY_DOUBLE: if (O_LEN(ap) > 0) O_VALD(out) = ahivd (Memd[O_VALP(ap)], O_LEN(ap)) else O_VALD(out) = O_VALD(ap) default: call xvv_error1 (s_badtype, fcn) } case F_LOV: # Low value. switch (optype) { case TY_SHORT: if (O_LEN(ap) > 0) O_VALS(out) = alovs (Mems[O_VALP(ap)], O_LEN(ap)) else O_VALS(out) = O_VALS(ap) case TY_INT: if (O_LEN(ap) > 0) O_VALI(out) = alovi (Memi[O_VALP(ap)], O_LEN(ap)) else O_VALI(out) = O_VALI(ap) case TY_LONG: if (O_LEN(ap) > 0) O_VALL(out) = alovl (Meml[O_VALP(ap)], O_LEN(ap)) else O_VALL(out) = O_VALL(ap) case TY_REAL: if (O_LEN(ap) > 0) O_VALR(out) = alovr (Memr[O_VALP(ap)], O_LEN(ap)) else O_VALR(out) = O_VALR(ap) case TY_DOUBLE: if (O_LEN(ap) > 0) O_VALD(out) = alovd (Memd[O_VALP(ap)], O_LEN(ap)) else O_VALD(out) = O_VALD(ap) default: call xvv_error1 (s_badtype, fcn) } case F_SUM: # Vector sum. switch (optype) { case TY_SHORT: if (O_LEN(ap) > 0) v_r = asums (Mems[O_VALP(ap)], O_LEN(ap)) else v_r = O_VALS(ap) case TY_INT: if (O_LEN(ap) > 0) v_r = asumi (Memi[O_VALP(ap)], O_LEN(ap)) else v_r = O_VALI(ap) case TY_LONG: if (O_LEN(ap) > 0) v_r = asuml (Meml[O_VALP(ap)], O_LEN(ap)) else v_r = O_VALL(ap) case TY_REAL: if (O_LEN(ap) > 0) v_r = asumr (Memr[O_VALP(ap)], O_LEN(ap)) else v_r = O_VALR(ap) case TY_DOUBLE: if (O_LEN(ap) > 0) v_d = asumd (Memd[O_VALP(ap)], O_LEN(ap)) else v_d = O_VALD(ap) default: call xvv_error1 (s_badtype, fcn) } if (optype == TY_DOUBLE) O_VALD(out) = v_d else O_VALR(out) = v_r case F_MEAN, F_STDDEV: # Compute the mean or standard deviation of a vector. An optional # second argument may be supplied to compute a K-sigma rejection # mean and sigma. if (nargs == 2) { if (O_LEN(args[2]) > 0) call xvv_error1 ("%s: ksigma arg must be a scalar" , fcn) switch (O_TYPE(args[2])) { case TY_REAL: v_r = O_VALR(args[2]) v_d = v_r case TY_DOUBLE: v_d = O_VALD(args[2]) v_r = v_d default: call xvv_chtype (args[2], args[2], TY_REAL) v_r = O_VALR(args[2]) v_d = v_r } } else { v_r = 0.0 v_d = 0.0 } switch (optype) { case TY_SHORT: v_i = aravs (Mems[O_VALP(ap)], O_LEN(ap), mean_r,sigma_r,v_r) case TY_INT: v_i = aravi (Memi[O_VALP(ap)], O_LEN(ap), mean_r,sigma_r,v_r) case TY_REAL: v_i = aravr (Memr[O_VALP(ap)], O_LEN(ap), mean_r,sigma_r,v_r) case TY_LONG: v_i = aravl (Meml[O_VALP(ap)], O_LEN(ap), mean_d,sigma_d,v_d) case TY_DOUBLE: v_i = aravd (Memd[O_VALP(ap)], O_LEN(ap), mean_d,sigma_d,v_d) default: call xvv_error1 (s_badtype, fcn) } if (opcode == F_MEAN) { if (O_TYPE(out) == TY_REAL) O_VALR(out) = mean_r else O_VALD(out) = mean_d } else { if (O_TYPE(out) == TY_REAL) O_VALR(out) = sigma_r else O_VALD(out) = sigma_d } case F_MEDIAN: # Compute the median value of a vector, or the vector median # of 3 or more vectors. switch (nargs) { case 1: switch (optype) { case TY_SHORT: O_VALS(out) = ameds (Mems[O_VALP(ap)], O_LEN(ap)) case TY_INT: O_VALI(out) = amedi (Memi[O_VALP(ap)], O_LEN(ap)) case TY_LONG: O_VALL(out) = amedl (Meml[O_VALP(ap)], O_LEN(ap)) case TY_REAL: O_VALR(out) = amedr (Memr[O_VALP(ap)], O_LEN(ap)) case TY_DOUBLE: O_VALD(out) = amedd (Memd[O_VALP(ap)], O_LEN(ap)) default: call xvv_error1 (s_badtype, fcn) } case 3: switch (optype) { case TY_SHORT: call amed3s (Mems[O_VALP(args[1])], Mems[O_VALP(args[2])], Mems[O_VALP(args[3])], Mems[O_VALP(out)], nelem) case TY_INT: call amed3i (Memi[O_VALP(args[1])], Memi[O_VALP(args[2])], Memi[O_VALP(args[3])], Memi[O_VALP(out)], nelem) case TY_LONG: call amed3l (Meml[O_VALP(args[1])], Meml[O_VALP(args[2])], Meml[O_VALP(args[3])], Meml[O_VALP(out)], nelem) case TY_REAL: call amed3r (Memr[O_VALP(args[1])], Memr[O_VALP(args[2])], Memr[O_VALP(args[3])], Memr[O_VALP(out)], nelem) case TY_DOUBLE: call amed3d (Memd[O_VALP(args[1])], Memd[O_VALP(args[2])], Memd[O_VALP(args[3])], Memd[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case 4: switch (optype) { case TY_SHORT: call amed4s (Mems[O_VALP(args[1])], Mems[O_VALP(args[2])], Mems[O_VALP(args[3])], Mems[O_VALP(args[4])], Mems[O_VALP(out)], nelem) case TY_INT: call amed4i (Memi[O_VALP(args[1])], Memi[O_VALP(args[2])], Memi[O_VALP(args[3])], Memi[O_VALP(args[4])], Memi[O_VALP(out)], nelem) case TY_LONG: call amed4l (Meml[O_VALP(args[1])], Meml[O_VALP(args[2])], Meml[O_VALP(args[3])], Meml[O_VALP(args[4])], Meml[O_VALP(out)], nelem) case TY_REAL: call amed4r (Memr[O_VALP(args[1])], Memr[O_VALP(args[2])], Memr[O_VALP(args[3])], Memr[O_VALP(args[4])], Memr[O_VALP(out)], nelem) case TY_DOUBLE: call amed4d (Memd[O_VALP(args[1])], Memd[O_VALP(args[2])], Memd[O_VALP(args[3])], Memd[O_VALP(args[4])], Memd[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case 5: switch (optype) { case TY_SHORT: call amed5s (Mems[O_VALP(args[1])], Mems[O_VALP(args[2])], Mems[O_VALP(args[3])], Mems[O_VALP(args[4])], Mems[O_VALP(args[5])], Mems[O_VALP(out)], nelem) case TY_INT: call amed5i (Memi[O_VALP(args[1])], Memi[O_VALP(args[2])], Memi[O_VALP(args[3])], Memi[O_VALP(args[4])], Memi[O_VALP(args[5])], Memi[O_VALP(out)], nelem) case TY_LONG: call amed5l (Meml[O_VALP(args[1])], Meml[O_VALP(args[2])], Meml[O_VALP(args[3])], Meml[O_VALP(args[4])], Meml[O_VALP(args[5])], Meml[O_VALP(out)], nelem) case TY_REAL: call amed5r (Memr[O_VALP(args[1])], Memr[O_VALP(args[2])], Memr[O_VALP(args[3])], Memr[O_VALP(args[4])], Memr[O_VALP(args[5])], Memr[O_VALP(out)], nelem) case TY_DOUBLE: call amed5d (Memd[O_VALP(args[1])], Memd[O_VALP(args[2])], Memd[O_VALP(args[3])], Memd[O_VALP(args[4])], Memd[O_VALP(args[5])], Memd[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } default: call xvv_error1 ("%s: wrong number of arguments", fcn) } case F_REPL: # Replicate an item to make a longer vector. chunk = O_LEN(ap) optype = O_TYPE(ap) if (optype == TY_BOOL) optype = TY_INT if (O_LEN(args[2]) > 0) call xvv_error1 ("%s: replication factor must be a scalar", fcn) if (O_TYPE(args[2]) != TY_INT) call xvv_chtype (args[2], args[2], TY_INT) repl = max (1, O_VALI(args[2])) if (chunk <= 0) nelem = repl else nelem = chunk * repl call xvv_initop (out, nelem, optype) switch (optype) { case TY_SHORT: if (chunk > 0) { ip = O_VALP(ap) op = O_VALP(out) do i = 1, repl { call amovs (Mems[ip], Mems[op], chunk) op = op + chunk } } else call amovks (O_VALS(ap), Mems[O_VALP(out)], nelem) case TY_INT: if (chunk > 0) { ip = O_VALP(ap) op = O_VALP(out) do i = 1, repl { call amovi (Memi[ip], Memi[op], chunk) op = op + chunk } } else call amovki (O_VALI(ap), Memi[O_VALP(out)], nelem) case TY_LONG: if (chunk > 0) { ip = O_VALP(ap) op = O_VALP(out) do i = 1, repl { call amovl (Meml[ip], Meml[op], chunk) op = op + chunk } } else call amovkl (O_VALL(ap), Meml[O_VALP(out)], nelem) case TY_REAL: if (chunk > 0) { ip = O_VALP(ap) op = O_VALP(out) do i = 1, repl { call amovr (Memr[ip], Memr[op], chunk) op = op + chunk } } else call amovkr (O_VALR(ap), Memr[O_VALP(out)], nelem) case TY_DOUBLE: if (chunk > 0) { ip = O_VALP(ap) op = O_VALP(out) do i = 1, repl { call amovd (Memd[ip], Memd[op], chunk) op = op + chunk } } else call amovkd (O_VALD(ap), Memd[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case F_SHIFT: # Vector shift. if (O_LEN(args[2]) > 0) call xvv_error1 ("%s: shift arg must be a scalar" , fcn) if (O_TYPE(args[2]) != TY_INT) call xvv_chtype (args[2], args[2], TY_INT) shift = O_VALI(args[2]) if (abs(shift) > nelem) { if (shift > 0) shift = nelem else shift = -nelem } switch (optype) { case TY_SHORT: if (nelem > 0) { do i = 1, nelem { j = i - shift if (j < 1) j = j + nelem else if (j > nelem) j = j - nelem Mems[O_VALP(out)+i-1] = Mems[O_VALP(ap)+j-1] } } else O_VALS(out) = (O_VALS(ap)) case TY_INT: if (nelem > 0) { do i = 1, nelem { j = i - shift if (j < 1) j = j + nelem else if (j > nelem) j = j - nelem Memi[O_VALP(out)+i-1] = Memi[O_VALP(ap)+j-1] } } else O_VALI(out) = (O_VALI(ap)) case TY_LONG: if (nelem > 0) { do i = 1, nelem { j = i - shift if (j < 1) j = j + nelem else if (j > nelem) j = j - nelem Meml[O_VALP(out)+i-1] = Meml[O_VALP(ap)+j-1] } } else O_VALL(out) = (O_VALL(ap)) case TY_REAL: if (nelem > 0) { do i = 1, nelem { j = i - shift if (j < 1) j = j + nelem else if (j > nelem) j = j - nelem Memr[O_VALP(out)+i-1] = Memr[O_VALP(ap)+j-1] } } else O_VALR(out) = (O_VALR(ap)) case TY_DOUBLE: if (nelem > 0) { do i = 1, nelem { j = i - shift if (j < 1) j = j + nelem else if (j > nelem) j = j - nelem Memd[O_VALP(out)+i-1] = Memd[O_VALP(ap)+j-1] } } else O_VALD(out) = (O_VALD(ap)) default: call xvv_error1 (s_badtype, fcn) } case F_SORT: # Sort a vector. switch (optype) { case TY_SHORT: if (nelem > 0) call asrts (Mems[O_VALP(ap)], Mems[O_VALP(out)], nelem) else O_VALS(out) = (O_VALS(ap)) case TY_INT: if (nelem > 0) call asrti (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) else O_VALI(out) = (O_VALI(ap)) case TY_LONG: if (nelem > 0) call asrtl (Meml[O_VALP(ap)], Meml[O_VALP(out)], nelem) else O_VALL(out) = (O_VALL(ap)) case TY_REAL: if (nelem > 0) call asrtr (Memr[O_VALP(ap)], Memr[O_VALP(out)], nelem) else O_VALR(out) = (O_VALR(ap)) case TY_DOUBLE: if (nelem > 0) call asrtd (Memd[O_VALP(ap)], Memd[O_VALP(out)], nelem) else O_VALD(out) = (O_VALD(ap)) default: call xvv_error1 (s_badtype, fcn) } case F_ATAN, F_ATAN2: if (optype == TY_REAL) { if (nargs == 1) { if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = atan (Memr[O_VALP(ap)+i-1]) } else O_VALR(out) = atan (O_VALR(ap)) } else { if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memr[O_VALP(out)+i-1] = atan2 (Memr[O_VALP(args[1])+i-1], Memr[O_VALP(args[2])+i-1]) } else O_VALR(out) = atan2(O_VALR(args[1]), O_VALR(args[2])) } } if (optype == TY_DOUBLE) { if (nargs == 1) { if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = atan (Memd[O_VALP(ap)+i-1]) } else O_VALD(out) = atan (O_VALD(ap)) } else { if (O_LEN(ap) > 0) { do i = 1, O_LEN(ap) Memd[O_VALP(out)+i-1] = atan2 (Memd[O_VALP(args[1])+i-1], Memd[O_VALP(args[2])+i-1]) } else O_VALD(out) = atan2(O_VALD(args[1]), O_VALD(args[2])) } } case F_MOD: in1 = args[1] in2 = args[2] switch (optype) { case TY_SHORT: if (O_LEN(in1) <= 0) { O_VALS(out) = mod (O_VALS(in1), O_VALS(in2)) } else if (O_LEN(in2) <= 0) { call amodks (Mems[O_VALP(in1)], O_VALS(in2), Mems[O_VALP(out)], nelem) } else { call amods (Mems[O_VALP(in1)], Mems[O_VALP(in2)], Mems[O_VALP(out)], nelem) } case TY_INT: if (O_LEN(in1) <= 0) { O_VALI(out) = mod (O_VALI(in1), O_VALI(in2)) } else if (O_LEN(in2) <= 0) { call amodki (Memi[O_VALP(in1)], O_VALI(in2), Memi[O_VALP(out)], nelem) } else { call amodi (Memi[O_VALP(in1)], Memi[O_VALP(in2)], Memi[O_VALP(out)], nelem) } case TY_LONG: if (O_LEN(in1) <= 0) { O_VALL(out) = mod (O_VALL(in1), O_VALL(in2)) } else if (O_LEN(in2) <= 0) { call amodkl (Meml[O_VALP(in1)], O_VALL(in2), Meml[O_VALP(out)], nelem) } else { call amodl (Meml[O_VALP(in1)], Meml[O_VALP(in2)], Meml[O_VALP(out)], nelem) } case TY_REAL: if (O_LEN(in1) <= 0) { O_VALR(out) = mod (O_VALR(in1), O_VALR(in2)) } else if (O_LEN(in2) <= 0) { call amodkr (Memr[O_VALP(in1)], O_VALR(in2), Memr[O_VALP(out)], nelem) } else { call amodr (Memr[O_VALP(in1)], Memr[O_VALP(in2)], Memr[O_VALP(out)], nelem) } case TY_DOUBLE: if (O_LEN(in1) <= 0) { O_VALD(out) = mod (O_VALD(in1), O_VALD(in2)) } else if (O_LEN(in2) <= 0) { call amodkd (Memd[O_VALP(in1)], O_VALD(in2), Memd[O_VALP(out)], nelem) } else { call amodd (Memd[O_VALP(in1)], Memd[O_VALP(in2)], Memd[O_VALP(out)], nelem) } default: call xvv_error1 (s_badtype, fcn) } case F_MAX: switch (optype) { case TY_SHORT: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovks (O_VALS(ap), Mems[O_VALP(out)], nelem) else O_VALS(out) = O_VALS(ap) } else call amovs (Mems[O_VALP(ap)], Mems[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALS(out) = max (O_VALS(ap), O_VALS(out)) else { call amaxks (Mems[O_VALP(out)], O_VALS(ap), Mems[O_VALP(out)], nelem) } } else { call amaxs (Mems[O_VALP(out)], Mems[O_VALP(ap)], Mems[O_VALP(out)], nelem) } } case TY_INT: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovki (O_VALI(ap), Memi[O_VALP(out)], nelem) else O_VALI(out) = O_VALI(ap) } else call amovi (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALI(out) = max (O_VALI(ap), O_VALI(out)) else { call amaxki (Memi[O_VALP(out)], O_VALI(ap), Memi[O_VALP(out)], nelem) } } else { call amaxi (Memi[O_VALP(out)], Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) } } case TY_LONG: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovkl (O_VALL(ap), Meml[O_VALP(out)], nelem) else O_VALL(out) = O_VALL(ap) } else call amovl (Meml[O_VALP(ap)], Meml[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALL(out) = max (O_VALL(ap), O_VALL(out)) else { call amaxkl (Meml[O_VALP(out)], O_VALL(ap), Meml[O_VALP(out)], nelem) } } else { call amaxl (Meml[O_VALP(out)], Meml[O_VALP(ap)], Meml[O_VALP(out)], nelem) } } case TY_REAL: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovkr (O_VALR(ap), Memr[O_VALP(out)], nelem) else O_VALR(out) = O_VALR(ap) } else call amovr (Memr[O_VALP(ap)], Memr[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALR(out) = max (O_VALR(ap), O_VALR(out)) else { call amaxkr (Memr[O_VALP(out)], O_VALR(ap), Memr[O_VALP(out)], nelem) } } else { call amaxr (Memr[O_VALP(out)], Memr[O_VALP(ap)], Memr[O_VALP(out)], nelem) } } case TY_DOUBLE: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovkd (O_VALD(ap), Memd[O_VALP(out)], nelem) else O_VALD(out) = O_VALD(ap) } else call amovd (Memd[O_VALP(ap)], Memd[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALD(out) = max (O_VALD(ap), O_VALD(out)) else { call amaxkd (Memd[O_VALP(out)], O_VALD(ap), Memd[O_VALP(out)], nelem) } } else { call amaxd (Memd[O_VALP(out)], Memd[O_VALP(ap)], Memd[O_VALP(out)], nelem) } } default: call xvv_error1 (s_badtype, fcn) } case F_MIN: switch (optype) { case TY_SHORT: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovks (O_VALS(ap), Mems[O_VALP(out)], nelem) else O_VALS(out) = O_VALS(ap) } else call amovs (Mems[O_VALP(ap)], Mems[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALS(out) = min (O_VALS(ap), O_VALS(out)) else { call aminks (Mems[O_VALP(out)], O_VALS(ap), Mems[O_VALP(out)], nelem) } } else { call amins (Mems[O_VALP(out)], Mems[O_VALP(ap)], Mems[O_VALP(out)], nelem) } } case TY_INT: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovki (O_VALI(ap), Memi[O_VALP(out)], nelem) else O_VALI(out) = O_VALI(ap) } else call amovi (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALI(out) = min (O_VALI(ap), O_VALI(out)) else { call aminki (Memi[O_VALP(out)], O_VALI(ap), Memi[O_VALP(out)], nelem) } } else { call amini (Memi[O_VALP(out)], Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) } } case TY_LONG: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovkl (O_VALL(ap), Meml[O_VALP(out)], nelem) else O_VALL(out) = O_VALL(ap) } else call amovl (Meml[O_VALP(ap)], Meml[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALL(out) = min (O_VALL(ap), O_VALL(out)) else { call aminkl (Meml[O_VALP(out)], O_VALL(ap), Meml[O_VALP(out)], nelem) } } else { call aminl (Meml[O_VALP(out)], Meml[O_VALP(ap)], Meml[O_VALP(out)], nelem) } } case TY_REAL: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovkr (O_VALR(ap), Memr[O_VALP(out)], nelem) else O_VALR(out) = O_VALR(ap) } else call amovr (Memr[O_VALP(ap)], Memr[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALR(out) = min (O_VALR(ap), O_VALR(out)) else { call aminkr (Memr[O_VALP(out)], O_VALR(ap), Memr[O_VALP(out)], nelem) } } else { call aminr (Memr[O_VALP(out)], Memr[O_VALP(ap)], Memr[O_VALP(out)], nelem) } } case TY_DOUBLE: # Copy the first argument. ap = args[1] if (O_LEN(ap) <= 0) { if (O_LEN(out) > 0) call amovkd (O_VALD(ap), Memd[O_VALP(out)], nelem) else O_VALD(out) = O_VALD(ap) } else call amovd (Memd[O_VALP(ap)], Memd[O_VALP(out)], nelem) # Process the second and remaining arguments. do i = 2, nargs { ap = args[i] if (O_LEN(ap) <= 0) { if (O_LEN(out) <= 0) O_VALD(out) = min (O_VALD(ap), O_VALD(out)) else { call aminkd (Memd[O_VALP(out)], O_VALD(ap), Memd[O_VALP(out)], nelem) } } else { call amind (Memd[O_VALP(out)], Memd[O_VALP(ap)], Memd[O_VALP(out)], nelem) } } default: call xvv_error1 (s_badtype, fcn) } case F_BOOL: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_BOOL) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALI(ap) else call amovi (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_CHAR: ch = O_VALC(ap) O_VALI(out) = btoi (ch == 'y' || ch == 'Y') case TY_SHORT: if (O_LEN(ap) <= 0) O_VALI(out) = btoi (O_VALS(ap) != 0) else { v_s = 0 call abneks (Mems[O_VALP(ap)], v_s, Memi[O_VALP(out)], nelem) } case TY_INT: if (O_LEN(ap) <= 0) O_VALI(out) = btoi (O_VALI(ap) != 0) else { v_i = 0 call abneki (Memi[O_VALP(ap)], v_i, Memi[O_VALP(out)], nelem) } case TY_LONG: if (O_LEN(ap) <= 0) O_VALI(out) = btoi (O_VALL(ap) != 0) else { v_l = 0 call abnekl (Meml[O_VALP(ap)], v_l, Memi[O_VALP(out)], nelem) } case TY_REAL: if (O_LEN(ap) <= 0) O_VALI(out) = btoi (O_VALR(ap) != 0.0) else { v_r = 0.0 call abnekr (Memr[O_VALP(ap)], v_r, Memi[O_VALP(out)], nelem) } case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALI(out) = btoi (O_VALD(ap) != 0.0D0) else { v_d = 0.0D0 call abnekd (Memd[O_VALP(ap)], v_d, Memi[O_VALP(out)], nelem) } default: call xvv_error1 (s_badtype, fcn) } case F_SHORT: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_SHORT) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALS(out) = O_VALI(ap) else call achtis (Memi[O_VALP(ap)], Mems[O_VALP(out)], nelem) case TY_CHAR: ip = O_VALP(ap) if (gctod (Memc, ip, v_d) <= 0) O_VALS(out) = 0 else O_VALS(out) = v_d case TY_SHORT: if (O_LEN(ap) <= 0) O_VALS(out) = O_VALS(ap) else call achtss (Mems[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_INT: if (O_LEN(ap) <= 0) O_VALS(out) = O_VALI(ap) else call achtis (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_LONG: if (O_LEN(ap) <= 0) O_VALS(out) = O_VALL(ap) else call achtls (Meml[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_REAL: if (O_LEN(ap) <= 0) O_VALS(out) = O_VALR(ap) else call achtrs (Memr[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALS(out) = O_VALD(ap) else call achtds (Memd[O_VALP(ap)], Memi[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case F_INT: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_INT) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALI(ap) else call amovi (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_CHAR: ip = O_VALP(ap) if (gctod (Memc, ip, v_d) <= 0) O_VALI(out) = 0 else O_VALI(out) = v_d case TY_SHORT: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALS(ap) else call achtsi (Mems[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_INT: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALI(ap) else call achtii (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_LONG: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALL(ap) else call achtli (Meml[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_REAL: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALR(ap) else call achtri (Memr[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALD(ap) else call achtdi (Memd[O_VALP(ap)], Memi[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case F_LONG: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_LONG) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALL(out) = O_VALI(ap) else call amovi (Memi[O_VALP(ap)], Meml[O_VALP(out)], nelem) case TY_CHAR: ip = O_VALP(ap) if (gctod (Memc, ip, v_d) <= 0) O_VALL(out) = 0 else O_VALL(out) = v_d case TY_SHORT: if (O_LEN(ap) <= 0) O_VALL(out) = O_VALS(ap) else call achtsl (Mems[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_INT: if (O_LEN(ap) <= 0) O_VALL(out) = O_VALI(ap) else call achtil (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_LONG: if (O_LEN(ap) <= 0) O_VALL(out) = O_VALL(ap) else call achtll (Meml[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_REAL: if (O_LEN(ap) <= 0) O_VALL(out) = O_VALR(ap) else call achtrl (Memr[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALL(out) = O_VALD(ap) else call achtdl (Memd[O_VALP(ap)], Memi[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case F_NINT: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_INT) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALI(ap) else call amovi (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_CHAR: ip = O_VALP(ap) if (gctod (Memc, ip, v_d) <= 0) O_VALI(out) = 0 else O_VALI(out) = nint (v_d) case TY_SHORT: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALS(ap) else call achtsi (Mems[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_INT: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALI(ap) else call achtii (Memi[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_LONG: if (O_LEN(ap) <= 0) O_VALI(out) = O_VALL(ap) else call achtli (Meml[O_VALP(ap)], Memi[O_VALP(out)], nelem) case TY_REAL: if (O_LEN(ap) <= 0) O_VALI(out) = nint (O_VALR(ap)) else { do i = 1, nelem Memi[O_VALP(out)+i-1] = nint (Memr[O_VALP(ap)+i-1]) } case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALI(out) = nint (O_VALD(ap)) else { do i = 1, nelem Memi[O_VALP(out)+i-1] = nint (Memd[O_VALP(ap)+i-1]) } default: call xvv_error1 (s_badtype, fcn) } case F_REAL: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_REAL) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALR(out) = O_VALI(ap) else call achtir (Memi[O_VALP(ap)], Memr[O_VALP(out)], nelem) case TY_CHAR: ip = O_VALP(ap) if (gctod (Memc, ip, v_d) <= 0) O_VALR(out) = 0 else O_VALR(out) = v_d case TY_SHORT: if (O_LEN(ap) <= 0) O_VALR(out) = O_VALS(ap) else call achtsr (Mems[O_VALP(ap)], Memr[O_VALP(out)], nelem) case TY_INT: if (O_LEN(ap) <= 0) O_VALR(out) = O_VALI(ap) else call achtir (Memi[O_VALP(ap)], Memr[O_VALP(out)], nelem) case TY_LONG: if (O_LEN(ap) <= 0) O_VALR(out) = O_VALL(ap) else call achtlr (Meml[O_VALP(ap)], Memr[O_VALP(out)], nelem) case TY_REAL: if (O_LEN(ap) <= 0) O_VALR(out) = O_VALR(ap) else call achtrr (Memr[O_VALP(ap)], Memr[O_VALP(out)], nelem) case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALR(out) = O_VALD(ap) else call achtdr (Memd[O_VALP(ap)], Memr[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case F_DOUBLE: nelem = 0 if (O_LEN(ap) > 0 && O_TYPE(ap) != TY_CHAR) nelem = O_LEN(ap) call xvv_initop (out, nelem, TY_DOUBLE) switch (O_TYPE(ap)) { case TY_BOOL: if (O_LEN(ap) <= 0) O_VALD(out) = O_VALI(ap) else call achtid (Memi[O_VALP(ap)], Memd[O_VALP(out)], nelem) case TY_CHAR: ip = O_VALP(ap) if (gctod (Memc, ip, v_d) <= 0) O_VALD(out) = 0 else O_VALD(out) = v_d case TY_SHORT: if (O_LEN(ap) <= 0) O_VALD(out) = O_VALS(ap) else call achtsd (Mems[O_VALP(ap)], Memd[O_VALP(out)], nelem) case TY_INT: if (O_LEN(ap) <= 0) O_VALD(out) = O_VALI(ap) else call achtid (Memi[O_VALP(ap)], Memd[O_VALP(out)], nelem) case TY_LONG: if (O_LEN(ap) <= 0) O_VALD(out) = O_VALL(ap) else call achtld (Meml[O_VALP(ap)], Memd[O_VALP(out)], nelem) case TY_REAL: if (O_LEN(ap) <= 0) O_VALD(out) = O_VALR(ap) else call achtrd (Memr[O_VALP(ap)], Memd[O_VALP(out)], nelem) case TY_DOUBLE: if (O_LEN(ap) <= 0) O_VALD(out) = O_VALD(ap) else call achtdd (Memd[O_VALP(ap)], Memd[O_VALP(out)], nelem) default: call xvv_error1 (s_badtype, fcn) } case F_STR: optype = TY_CHAR if (O_TYPE(ap) == TY_CHAR) nelem = strlen (O_VALC(ap)) else nelem = MAX_DIGITS call xvv_initop (out, nelem, TY_CHAR) switch (O_TYPE(ap)) { case TY_BOOL: call sprintf (O_VALC(out), nelem, "%b") call pargi (O_VALI(ap)) case TY_CHAR: call sprintf (O_VALC(out), nelem, "%s") call pargstr (O_VALC(ap)) case TY_SHORT: call sprintf (O_VALC(out), nelem, "%d") call pargs (O_VALS(ap)) case TY_INT: call sprintf (O_VALC(out), nelem, "%d") call pargi (O_VALI(ap)) case TY_LONG: call sprintf (O_VALC(out), nelem, "%d") call pargl (O_VALL(ap)) case TY_REAL: call sprintf (O_VALC(out), nelem, "%g") call pargr (O_VALR(ap)) case TY_DOUBLE: call sprintf (O_VALC(out), nelem, "%g") call pargd (O_VALD(ap)) default: call xvv_error1 (s_badtype, fcn) } default: call xvv_error ("callfcn: unknown function type") } free_ # Free any storage used by the argument list operands. do i = 1, nargs call xvv_freeop (args[i]) call sfree (sp) end # XVV_STARTARGLIST -- Allocate an argument list descriptor to receive # arguments as a function call is parsed. We are called with either # zero or one arguments. The argument list descriptor is pointed to by # a ficticious operand. The descriptor itself contains a count of the # number of arguments, an array of pointers to the operand structures, # as well as storage for the operand structures. The operands must be # stored locally since the parser will discard its copy of the operand # structure for each argument as the associated grammar rule is reduced. procedure xvv_startarglist (arg, out) pointer arg #I pointer to first argument, or NULL pointer out #I output operand pointing to arg descriptor pointer ap errchk xvv_initop begin call xvv_initop (out, LEN_ARGSTRUCT, TY_STRUCT) ap = O_VALP(out) if (arg == NULL) A_NARGS(ap) = 0 else { A_NARGS(ap) = 1 A_ARGP(ap,1) = A_OPS(ap) YYMOVE (arg, A_OPS(ap)) } end # XVV_ADDARG -- Add an argument to the argument list for a function call. procedure xvv_addarg (arg, arglist, out) pointer arg #I pointer to argument to be added pointer arglist #I pointer to operand pointing to arglist pointer out #I output operand pointing to arg descriptor pointer ap, o int nargs begin ap = O_VALP(arglist) nargs = A_NARGS(ap) + 1 A_NARGS(ap) = nargs if (nargs > MAX_ARGS) call xvv_error ("too many function arguments") o = A_OPS(ap) + ((nargs - 1) * LEN_OPERAND) A_ARGP(ap,nargs) = o YYMOVE (arg, o) YYMOVE (arglist, out) end # XVV_ERROR1 -- Take an error action, formatting an error message with one # format string plus one string argument. procedure xvv_error1 (fmt, arg) char fmt[ARB] #I printf format string char arg[ARB] #I string argument pointer sp, buf begin call smark (sp) call salloc (buf, SZ_LINE, TY_CHAR) call sprintf (Memc[buf], SZ_LINE, fmt) call pargstr (arg) call xvv_error (Memc[buf]) call sfree (sp) end # XVV_ERROR2 -- Take an error action, formatting an error message with one # format string plus one string argument and one integer argument. procedure xvv_error2 (fmt, arg1, arg2) char fmt[ARB] #I printf format string char arg1[ARB] #I string argument int arg2 #I integer argument pointer sp, buf begin call smark (sp) call salloc (buf, SZ_LINE, TY_CHAR) call sprintf (Memc[buf], SZ_LINE, fmt) call pargstr (arg1) call pargi (arg2) call xvv_error (Memc[buf]) call sfree (sp) end # XVV_ERROR -- Take an error action, given an error message string as the # sole argument. procedure xvv_error (errmsg) char errmsg[ARB] #I error message begin call error (1, errmsg) end # XVV_CHTYPE -- Change the datatype of an operand. The input and output # operands may be the same. procedure xvv_chtype (o1, o2, dtype) pointer o1 #I input operand pointer o2 #I output operand int dtype #I new datatype short v_s int v_i long v_l real v_r double v_d pointer vp, ip, op bool float, freeval int old_type, nelem, ch pointer coerce() int sizeof(), btoi(), gctod() string s_badtype "chtype: invalid operand type" begin old_type = O_TYPE(o1) nelem = O_LEN(o1) # No type conversion needed? if (old_type == dtype) { if (o1 != o2) { if (nelem <= 0) YYMOVE (o1, o2) else { call xvv_initop (o2, nelem, old_type) call amovc (O_VALC(o1), O_VALC(o2), nelem * sizeof(dtype)) } } return } if (nelem <= 0) { # Scalar input operand. O_TYPE(o2) = dtype O_LEN(o2) = 0 float = false # Read the old value into a local variable of type long or double. switch (old_type) { case TY_BOOL: v_l = O_VALI(o1) case TY_CHAR: v_l = 0 # null string? case TY_SHORT: v_l = O_VALS(o1) case TY_INT: v_l = O_VALI(o1) case TY_LONG: v_l = O_VALL(o1) case TY_REAL: v_d = O_VALR(o1) float = true case TY_DOUBLE: v_d = O_VALD(o1) float = true default: call xvv_error (s_badtype) } # Set the value of the output operand. switch (dtype) { case TY_BOOL: if (float) O_VALI(o2) = btoi (v_d != 0) else O_VALI(o2) = btoi (v_l != 0) case TY_CHAR: call xvv_initop (o2, MAX_DIGITS, TY_CHAR) if (float) { call sprintf (O_VALC(o2), MAX_DIGITS, "%g") call pargd (v_d) } else { call sprintf (O_VALC(o2), MAX_DIGITS, "%d") call pargl (v_l) } case TY_SHORT: if (float) O_VALS(o2) = v_d else O_VALS(o2) = v_l case TY_INT: if (float) O_VALI(o2) = v_d else O_VALI(o2) = v_l case TY_LONG: if (float) O_VALL(o2) = v_d else O_VALL(o2) = v_l case TY_REAL: if (float) O_VALR(o2) = v_d else O_VALR(o2) = v_l case TY_DOUBLE: if (float) O_VALD(o2) = v_d else O_VALD(o2) = v_l default: call xvv_error (s_badtype) } } else { # Vector input operand. # Save a pointer to the input operand data vector, to avoid it # getting clobbered if O1 and O2 are the same operand. vp = O_VALP(o1) # If we have a char string input operand the output numeric # operand can only be a scalar. If we have a char string output # operand nelem is the length of the string. if (old_type == TY_CHAR) nelem = 0 else if (dtype == TY_CHAR) nelem = MAX_DIGITS # Initialize the output operand O2. The freeval flag is cleared # cleared to keep the initop from freeing the input operand array, # inherited when the input operand is copied (or when the input # and output operands are the same). We free the old operand # array manually below. if (o1 != o2) YYMOVE (o1, o2) freeval = (and (O_FLAGS(o1), O_FREEVAL) != 0) O_FLAGS(o2) = and (O_FLAGS(o2), not(O_FREEVAL)) call xvv_initop (o2, nelem, dtype) # Write output value. switch (dtype) { case TY_BOOL: if (old_type == TY_CHAR) { ch = Memc[vp] O_VALI(o2) = btoi (ch == 'y' || ch == 'Y') } else { switch (old_type) { case TY_SHORT: v_s = 0 call abneks (Mems[vp], v_s, Memi[O_VALP(o2)], nelem) case TY_INT: v_i = 0 call abneki (Memi[vp], v_i, Memi[O_VALP(o2)], nelem) case TY_LONG: v_l = 0 call abnekl (Meml[vp], v_l, Memi[O_VALP(o2)], nelem) case TY_REAL: v_r = 0.0 call abnekr (Memr[vp], v_r, Memi[O_VALP(o2)], nelem) case TY_DOUBLE: v_d = 0.0D0 call abnekd (Memd[vp], v_d, Memi[O_VALP(o2)], nelem) default: call xvv_error (s_badtype) } } case TY_CHAR: call xvv_error (s_badtype) case TY_SHORT, TY_INT, TY_LONG, TY_REAL, TY_DOUBLE: switch (old_type) { case TY_BOOL: op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR) call achti (Memi[vp], Memc[op], nelem, dtype) case TY_CHAR: ip = vp if (gctod (Memc, ip, v_d) <= 0) v_d = 0 switch (dtype) { case TY_SHORT: O_VALS(o2) = v_d case TY_INT: O_VALI(o2) = v_d case TY_LONG: O_VALL(o2) = v_d case TY_REAL: O_VALR(o2) = v_d case TY_DOUBLE: O_VALD(o2) = v_d } case TY_SHORT: op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR) call achts (Mems[vp], Memc[op], nelem, dtype) case TY_INT: op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR) call achti (Memi[vp], Memc[op], nelem, dtype) case TY_LONG: op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR) call achtl (Meml[vp], Memc[op], nelem, dtype) case TY_REAL: op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR) call achtr (Memr[vp], Memc[op], nelem, dtype) case TY_DOUBLE: op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR) call achtd (Memd[vp], Memc[op], nelem, dtype) default: call xvv_error (s_badtype) } default: call xvv_error (s_badtype) } # Free old operand value. if (freeval) call mfree (vp, old_type) } end # XVV_INITOP -- Initialize an operand, providing storage for an operand value # of the given size and type. procedure xvv_initop (o, o_len, o_type) pointer o #I pointer to operand structure int o_len #I length of operand (zero if scalar) int o_type #I datatype of operand begin O_LEN(o) = 0 call xvv_makeop (o, o_len, o_type) end # XVV_MAKEOP -- Set up the operand structure. If the operand structure has # already been initialized and array storage allocated, free the old array. procedure xvv_makeop (o, o_len, o_type) pointer o #I pointer to operand structure int o_len #I length of operand (zero if scalar) int o_type #I datatype of operand errchk malloc begin # Free old array storage if any. if (O_TYPE(o) != 0 && O_LEN(o) > 0) if (and (O_FLAGS(o), O_FREEVAL) != 0) { if (O_TYPE(o) == TY_BOOL) call mfree (O_VALP(o), TY_INT) else call mfree (O_VALP(o), O_TYPE(o)) O_LEN(o) = 0 } # Set new operand type. O_TYPE(o) = o_type # Allocate array storage if nonscalar operand. if (o_len > 0) { if (o_type == TY_BOOL) call malloc (O_VALP(o), o_len, TY_INT) else call malloc (O_VALP(o), o_len, o_type) O_LEN(o) = o_len } O_FLAGS(o) = O_FREEVAL end # XVV_FREEOP -- Reinitialize an operand structure, i.e., free any associated # array storage and clear the operand datatype field, but do not free the # operand structure itself (which may be only a segment of an array and not # a separately allocated structure). procedure xvv_freeop (o) pointer o #I pointer to operand structure begin # Free old array storage if any. if (O_TYPE(o) != 0 && O_LEN(o) > 0) if (and (O_FLAGS(o), O_FREEVAL) != 0) { if (O_TYPE(o) == TY_BOOL) call mfree (O_VALP(o), TY_INT) else call mfree (O_VALP(o), O_TYPE(o)) O_LEN(o) = 0 } # Either free operand struct or clear the operand type to mark # operand invalid. if (and (O_FLAGS(o), O_FREEOP) != 0) call mfree (o, TY_STRUCT) else O_TYPE(o) = 0 end # XVV_LOADSYMBOLS -- Load a list of symbol names into a symbol table. Each # symbol is tagged with an integer code corresponding to its sequence number # in the symbol list. pointer procedure xvv_loadsymbols (s) char s[ARB] #I symbol list "|sym1|sym2|...|" int delim, symnum, ip pointer sp, symname, st, sym, op pointer stopen(), stenter() begin call smark (sp) call salloc (symname, SZ_FNAME, TY_CHAR) st = stopen ("evvexpr", LEN_INDEX, LEN_STAB, LEN_SBUF) delim = s[1] symnum = 0 for (ip=2; s[ip] != EOS; ip=ip+1) { op = symname while (s[ip] != delim && s[ip] != EOS) { Memc[op] = s[ip] op = op + 1 ip = ip + 1 } Memc[op] = EOS symnum = symnum + 1 if (op > symname && IS_ALPHA(Memc[symname])) { sym = stenter (st, Memc[symname], LEN_SYM) SYM_CODE(sym) = symnum } } call sfree (sp) return (st) end # XVV_NULL -- Return a null value to be used when a computation cannot be # performed and range checking is enabled. Perhaps we should permit a user # specified value here, however this doesn't really work in an expression # evaluator since the value generated may be used in subsequent calculations # and hence may change. If more careful treatment of out of range values # is needed a conditional expression can be used in which case the value # we return here is ignored (but still needed to avoid a hardware exception # when computing a vector). short procedure xvv_nulls (ignore) short ignore #I ignored begin return (0) end int procedure xvv_nulli (ignore) int ignore #I ignored begin return (0) end long procedure xvv_nulll (ignore) long ignore #I ignored begin return (0) end real procedure xvv_nullr (ignore) real ignore #I ignored begin return (0.0) end double procedure xvv_nulld (ignore) double ignore #I ignored begin return (0.0D0) end define YYNPROD 39 define YYLAST 303 # line 1 "/iraf/iraf/lib/yaccpar.x" # Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. # Parser for yacc output, translated to the IRAF SPP language. The contents # of this file form the bulk of the source of the parser produced by Yacc. # Yacc recognizes several macros in the yaccpar input source and replaces # them as follows: # A user suppled "global" definitions and declarations # B parser tables # C user supplied actions (reductions) # The remainder of the yaccpar code is not changed. define yystack_ 10 # statement labels for gotos define yynewstate_ 20 define yydefault_ 30 define yyerrlab_ 40 define yyabort_ 50 define YYFLAG (-1000) # defs used in user actions define YYERROR goto yyerrlab_ define YYACCEPT return (OK) define YYABORT return (ERR) # YYPARSE -- Parse the input stream, returning OK if the source is # syntactically acceptable (i.e., if compilation is successful), # otherwise ERR. The parameters YYMAXDEPTH and YYOPLEN must be # supplied by the caller in the %{ ... %} section of the Yacc source. # The token value stack is a dynamically allocated array of operand # structures, with the length and makeup of the operand structure being # application dependent. int procedure yyparse (fd, yydebug, yylex) int fd # stream to be parsed bool yydebug # print debugging information? int yylex() # user-supplied lexical input function extern yylex() short yys[YYMAXDEPTH] # parser stack -- stacks tokens pointer yyv # pointer to token value stack pointer yyval # value returned by action pointer yylval # value of token int yyps # token stack pointer pointer yypv # value stack pointer int yychar # current input token number int yyerrflag # error recovery flag int yynerrs # number of errors short yyj, yym # internal variables pointer yysp, yypvt short yystate, yyn int yyxi, i errchk salloc, yylex # XVV_PARSE -- SPP/Yacc parser for the evaluation of an expression passed as # a text string. Expression evaluation is carried out as the expression is # parsed, rather than being broken into separate compile and execute stages. # There is only one statement in this grammar, the expression. Our function # is to reduce an expression to a single value of type bool, string, int, # or real. pointer ap bool streq() errchk zcall3, xvv_error1, xvv_unop, xvv_binop, xvv_boolop errchk xvv_quest, xvv_callfcn, xvv_addarg include "evvexpr.com" short yyexca[96] data (yyexca(i),i= 1, 8) / -1, 1, 0, -1, -2, 0, -1, 5/ data (yyexca(i),i= 9, 16) / 40, 33, -2, 5, -1, 6, 40, 32/ data (yyexca(i),i= 17, 24) / -2, 6, -1, 76, 269, 0, 270, 0/ data (yyexca(i),i= 25, 32) / 271, 0, 283, 0, -2, 22, -1, 77/ data (yyexca(i),i= 33, 40) / 269, 0, 270, 0, 271, 0, 283, 0/ data (yyexca(i),i= 41, 48) / -2, 23, -1, 78, 269, 0, 270, 0/ data (yyexca(i),i= 49, 56) / 271, 0, 283, 0, -2, 24, -1, 79/ data (yyexca(i),i= 57, 64) / 269, 0, 270, 0, 271, 0, 283, 0/ data (yyexca(i),i= 65, 72) / -2, 25, -1, 80, 272, 0, 273, 0/ data (yyexca(i),i= 73, 80) / 274, 0, -2, 26, -1, 81, 272, 0/ data (yyexca(i),i= 81, 88) / 273, 0, 274, 0, -2, 27, -1, 82/ data (yyexca(i),i= 89, 96) / 272, 0, 273, 0, 274, 0, -2, 28/ short yyact[303] data (yyact(i),i= 1, 8) / 15, 16, 17, 18, 19, 20, 33, 86/ data (yyact(i),i= 9, 16) / 26, 27, 28, 30, 32, 31, 21, 22/ data (yyact(i),i= 17, 24) / 62, 23, 24, 25, 19, 34, 29, 15/ data (yyact(i),i= 25, 32) / 16, 17, 18, 19, 20, 33, 38, 26/ data (yyact(i),i= 33, 40) / 27, 28, 30, 32, 31, 21, 22, 60/ data (yyact(i),i= 41, 48) / 23, 24, 25, 12, 11, 29, 15, 16/ data (yyact(i),i= 49, 56) / 17, 18, 19, 20, 12, 2, 26, 27/ data (yyact(i),i= 57, 64) / 28, 30, 32, 31, 12, 1, 0, 23/ data (yyact(i),i= 65, 72) / 24, 25, 0, 14, 29, 15, 16, 17/ data (yyact(i),i= 73, 80) / 18, 19, 20, 0, 0, 26, 27, 28/ data (yyact(i),i= 81, 88) / 30, 32, 31, 0, 15, 16, 17, 18/ data (yyact(i),i= 89, 96) / 19, 20, 0, 29, 26, 27, 28, 15/ data (yyact(i),i= 97,104) / 16, 17, 18, 19, 20, 15, 16, 17/ data (yyact(i),i=105,112) / 18, 19, 29, 17, 18, 19, 4, 0/ data (yyact(i),i=113,120) / 84, 0, 40, 85, 0, 0, 0, 35/ data (yyact(i),i=121,128) / 36, 37, 0, 39, 0, 0, 0, 0/ data (yyact(i),i=129,136) / 0, 0, 41, 42, 43, 44, 45, 46/ data (yyact(i),i=137,144) / 47, 48, 49, 50, 51, 52, 53, 54/ data (yyact(i),i=145,152) / 55, 56, 57, 58, 59, 61, 0, 63/ data (yyact(i),i=153,160) / 65, 66, 67, 68, 69, 70, 71, 72/ data (yyact(i),i=161,168) / 73, 74, 75, 76, 77, 78, 79, 80/ data (yyact(i),i=169,176) / 81, 82, 83, 0, 0, 0, 0, 0/ data (yyact(i),i=177,184) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yyact(i),i=185,192) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yyact(i),i=193,200) / 0, 0, 0, 0, 0, 0, 89, 90/ data (yyact(i),i=201,208) / 87, 88, 0, 0, 0, 0, 0, 0/ data (yyact(i),i=209,216) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yyact(i),i=217,224) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yyact(i),i=225,232) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yyact(i),i=233,240) / 0, 0, 0, 0, 15, 16, 17, 18/ data (yyact(i),i=241,248) / 19, 20, 33, 0, 26, 27, 28, 30/ data (yyact(i),i=249,256) / 32, 31, 21, 22, 0, 23, 24, 25/ data (yyact(i),i=257,264) / 0, 0, 29, 0, 5, 6, 64, 0/ data (yyact(i),i=265,272) / 0, 8, 0, 0, 3, 5, 6, 0/ data (yyact(i),i=273,280) / 0, 0, 8, 0, 0, 5, 6, 0/ data (yyact(i),i=281,288) / 9, 0, 8, 13, 10, 7, 0, 0/ data (yyact(i),i=289,296) / 0, 9, 0, 0, 0, 10, 7, 0/ data (yyact(i),i=297,303) / 0, 9, 0, 0, 0, 10, 7/ short yypact[91] data (yypact(i),i= 1, 8) / 12,-1000, 23,-1000,-238,-1000,-1000,-236/ data (yypact(i),i= 9, 16) / 20, 20, 20, -10, 20,-1000,-1000,-1000/ data (yypact(i),i= 17, 24) /-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000/ data (yypact(i),i= 25, 32) /-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000/ data (yypact(i),i= 33, 40) /-1000,-1000,-1000,-245,-245,-245, 20, -25/ data (yypact(i),i= 41, 48) / 3, 3, 3, 3, 3, 3, 3, 3/ data (yypact(i),i= 49, 56) / 3, 3, 3, 3, 3, 3, 3, 3/ data (yypact(i),i= 57, 64) / 3, 3, 3, 3, 71,-238,-1000,-238/ data (yypact(i),i= 65, 72) /-1000,-156,-156,-245,-245,-1000,-160,-215/ data (yypact(i),i= 73, 80) /-215,-192,-192,-192,-166,-166,-166,-166/ data (yypact(i),i= 81, 88) /-177,-177,-177,-261,-1000,-1000,-1000, 3/ data (yypact(i),i= 89, 91) / 3,-238,-238/ short yypgo[7] data (yypgo(i),i= 1, 7) / 0, 61, 53, 110, 114, 44, 39/ short yyr1[39] data (yyr1(i),i= 1, 8) / 0, 1, 1, 2, 2, 3, 3, 3/ data (yyr1(i),i= 9, 16) / 3, 3, 3, 3, 3, 3, 3, 3/ data (yyr1(i),i= 17, 24) / 3, 3, 3, 3, 3, 3, 3, 3/ data (yyr1(i),i= 25, 32) / 3, 3, 3, 3, 3, 3, 3, 3/ data (yyr1(i),i= 33, 39) / 5, 5, 6, 6, 6, 4, 4/ short yyr2[39] data (yyr2(i),i= 1, 8) / 0, 2, 1, 1, 4, 1, 1, 2/ data (yyr2(i),i= 9, 16) / 2, 2, 2, 4, 4, 4, 4, 4/ data (yyr2(i),i= 17, 24) / 4, 4, 4, 4, 4, 4, 4, 4/ data (yyr2(i),i= 25, 32) / 4, 4, 4, 4, 4, 7, 4, 3/ data (yyr2(i),i= 33, 39) / 1, 1, 0, 1, 4, 0, 2/ short yychk[91] data (yychk(i),i= 1, 8) /-1000, -1, -2, 256, -3, 257, 258, 282/ data (yychk(i),i= 9, 16) / 262, 277, 281, -5, 40, 260, 44, 261/ data (yychk(i),i= 17, 24) / 262, 263, 264, 265, 266, 275, 276, 278/ data (yychk(i),i= 25, 32) / 279, 280, 269, 270, 271, 283, 272, 274/ data (yychk(i),i= 33, 40) / 273, 267, 257, -3, -3, -3, 40, -3/ data (yychk(i),i= 41, 48) / -4, -4, -4, -4, -4, -4, -4, -4/ data (yychk(i),i= 49, 56) / -4, -4, -4, -4, -4, -4, -4, -4/ data (yychk(i),i= 57, 64) / -4, -4, -4, -4, -6, -3, 41, -3/ data (yychk(i),i= 65, 72) / 259, -3, -3, -3, -3, -3, -3, -3/ data (yychk(i),i= 73, 80) / -3, -3, -3, -3, -3, -3, -3, -3/ data (yychk(i),i= 81, 88) / -3, -3, -3, -3, 41, 44, 268, -4/ data (yychk(i),i= 89, 91) / -4, -3, -3/ short yydef[91] data (yydef(i),i= 1, 8) / 0, -2, 0, 2, 3, -2, -2, 0/ data (yydef(i),i= 9, 16) / 0, 0, 0, 0, 0, 1, 37, 37/ data (yydef(i),i= 17, 24) / 37, 37, 37, 37, 37, 37, 37, 37/ data (yydef(i),i= 25, 32) / 37, 37, 37, 37, 37, 37, 37, 37/ data (yydef(i),i= 33, 40) / 37, 37, 7, 8, 9, 10, 34, 0/ data (yydef(i),i= 41, 48) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yydef(i),i= 49, 56) / 0, 0, 0, 0, 0, 0, 0, 0/ data (yydef(i),i= 57, 64) / 0, 0, 0, 0, 0, 35, 31, 4/ data (yydef(i),i= 65, 72) / 38, 11, 12, 13, 14, 15, 16, 17/ data (yydef(i),i= 73, 80) / 18, 19, 20, 21, -2, -2, -2, -2/ data (yydef(i),i= 81, 88) / -2, -2, -2, 0, 30, 37, 37, 0/ data (yydef(i),i= 89, 91) / 0, 36, 29/ begin call smark (yysp) call salloc (yyv, (YYMAXDEPTH+2) * YYOPLEN, TY_STRUCT) # Initialization. The first element of the dynamically allocated # token value stack (yyv) is used for yyval, the second for yylval, # and the actual stack starts with the third element. yystate = 0 yychar = -1 yynerrs = 0 yyerrflag = 0 yyps = 0 yyval = yyv yylval = yyv + YYOPLEN yypv = yylval yystack_ # SHIFT -- Put a state and value onto the stack. The token and # value stacks are logically the same stack, implemented as two # separate arrays. if (yydebug) { call printf ("state %d, char 0%o\n") call pargs (yystate) call pargi (yychar) } yyps = yyps + 1 yypv = yypv + YYOPLEN if (yyps > YYMAXDEPTH) { call sfree (yysp) call eprintf ("yacc stack overflow\n") return (ERR) } yys[yyps] = yystate YYMOVE (yyval, yypv) yynewstate_ # Process the new state. yyn = yypact[yystate+1] if (yyn <= YYFLAG) goto yydefault_ # simple state # The variable "yychar" is the lookahead token. if (yychar < 0) { yychar = yylex (fd, yylval) if (yychar < 0) yychar = 0 } yyn = yyn + yychar if (yyn < 0 || yyn >= YYLAST) goto yydefault_ yyn = yyact[yyn+1] if (yychk[yyn+1] == yychar) { # valid shift yychar = -1 YYMOVE (yylval, yyval) yystate = yyn if (yyerrflag > 0) yyerrflag = yyerrflag - 1 goto yystack_ } yydefault_ # Default state action. yyn = yydef[yystate+1] if (yyn == -2) { if (yychar < 0) { yychar = yylex (fd, yylval) if (yychar < 0) yychar = 0 } # Look through exception table. yyxi = 1 while ((yyexca[yyxi] != (-1)) || (yyexca[yyxi+1] != yystate)) yyxi = yyxi + 2 for (yyxi=yyxi+2; yyexca[yyxi] >= 0; yyxi=yyxi+2) { if (yyexca[yyxi] == yychar) break } yyn = yyexca[yyxi+1] if (yyn < 0) { call sfree (yysp) return (OK) # ACCEPT -- all done } } # SYNTAX ERROR -- resume parsing if possible. if (yyn == 0) { switch (yyerrflag) { case 0, 1, 2: if (yyerrflag == 0) { # brand new error call eprintf ("syntax error\n") yyerrlab_ yynerrs = yynerrs + 1 # fall through... } # case 1: # case 2: incompletely recovered error ... try again yyerrflag = 3 # Find a state where "error" is a legal shift action. while (yyps >= 1) { yyn = yypact[yys[yyps]+1] + YYERRCODE if ((yyn >= 0) && (yyn < YYLAST) && (yychk[yyact[yyn+1]+1] == YYERRCODE)) { # Simulate a shift of "error". yystate = yyact[yyn+1] goto yystack_ } yyn = yypact[yys[yyps]+1] # The current yyps has no shift on "error", pop stack. if (yydebug) { call printf ("error recovery pops state %d, ") call pargs (yys[yyps]) call printf ("uncovers %d\n") call pargs (yys[yyps-1]) } yyps = yyps - 1 yypv = yypv - YYOPLEN } # ABORT -- There is no state on the stack with an error shift. yyabort_ call sfree (yysp) return (ERR) case 3: # No shift yet; clobber input char. if (yydebug) { call printf ("error recovery discards char %d\n") call pargi (yychar) } if (yychar == 0) goto yyabort_ # don't discard EOF, quit yychar = -1 goto yynewstate_ # try again in the same state } } # REDUCE -- Reduction by production yyn. if (yydebug) { call printf ("reduce %d\n") call pargs (yyn) } yyps = yyps - yyr2[yyn+1] yypvt = yypv yypv = yypv - yyr2[yyn+1] * YYOPLEN YYMOVE (yypv + YYOPLEN, yyval) yym = yyn # Consult goto table to find next state. yyn = yyr1[yyn+1] yyj = yypgo[yyn+1] + yys[yyps] + 1 if (yyj >= YYLAST) yystate = yyact[yypgo[yyn+1]+1] else { yystate = yyact[yyj+1] if (yychk[yystate+1] != -yyn) yystate = yyact[yypgo[yyn+1]+1] } # Perform action associated with the grammar rule, if any. switch (yym) { case 1: # line 266 "evvexpr.y" { # Normal exit. Move the final expression value operand # into the operand structure pointed to by the global # variable ev_oval. YYMOVE (yypvt-YYOPLEN, ev_oval) call sfree (yysp) return (OK) } case 2: # line 275 "evvexpr.y" { call error (1, "syntax error") } case 3: # line 280 "evvexpr.y" { YYMOVE (yypvt, yyval) } case 4: # line 283 "evvexpr.y" { YYMOVE (yypvt, yyval) call xvv_freeop (yypvt-3*YYOPLEN) } case 5: # line 289 "evvexpr.y" { # Numeric constant. YYMOVE (yypvt, yyval) } case 6: # line 293 "evvexpr.y" { # The boolean constants "yes" and "no" are implemented # as reserved operands. call xvv_initop (yyval, 0, TY_BOOL) if (streq (O_VALC(yypvt), "yes")) { O_VALI(yyval) = YES } else if (streq (O_VALC(yypvt), "no")) { O_VALI(yyval) = NO } else if (ev_getop != NULL) { call zcall3 (ev_getop,ev_getop_data, O_VALC(yypvt), yyval) if (O_TYPE(yyval) <= 0) call xvv_error1 ("unknown operand `%s'", O_VALC(yypvt)) } else call xvv_error1 ("illegal operand `%s'", O_VALC(yypvt)) call xvv_freeop (yypvt) } case 7: # line 311 "evvexpr.y" { # e.g., @"param" if (ev_getop != NULL) { call zcall3 (ev_getop,ev_getop_data, O_VALC(yypvt), yyval) if (O_TYPE(yyval) <= 0) call xvv_error1 ("unknown operand `%s'", O_VALC(yypvt-YYOPLEN)) } else call xvv_error1 ("illegal operand `%s'", O_VALC(yypvt)) call xvv_freeop (yypvt) } case 8: # line 322 "evvexpr.y" { # Unary arithmetic minus. call xvv_unop (MINUS, yypvt, yyval) } case 9: # line 326 "evvexpr.y" { # Logical not. call xvv_unop (LNOT, yypvt, yyval) } case 10: # line 330 "evvexpr.y" { # Boolean not. call xvv_unop (BNOT, yypvt, yyval) } case 11: # line 334 "evvexpr.y" { # Addition. call xvv_binop (PLUS, yypvt-3*YYOPLEN, yypvt, yyval) } case 12: # line 338 "evvexpr.y" { # Subtraction. call xvv_binop (MINUS, yypvt-3*YYOPLEN, yypvt, yyval) } case 13: # line 342 "evvexpr.y" { # Multiplication. call xvv_binop (STAR, yypvt-3*YYOPLEN, yypvt, yyval) } case 14: # line 346 "evvexpr.y" { # Division. call xvv_binop (SLASH, yypvt-3*YYOPLEN, yypvt, yyval) } case 15: # line 350 "evvexpr.y" { # Exponentiation. call xvv_binop (EXPON, yypvt-3*YYOPLEN, yypvt, yyval) } case 16: # line 354 "evvexpr.y" { # Concatenate two operands. call xvv_binop (CONCAT, yypvt-3*YYOPLEN, yypvt, yyval) } case 17: # line 358 "evvexpr.y" { # Logical and. call xvv_boolop (LAND, yypvt-3*YYOPLEN, yypvt, yyval) } case 18: # line 362 "evvexpr.y" { # Logical or. call xvv_boolop (LOR, yypvt-3*YYOPLEN, yypvt, yyval) } case 19: # line 366 "evvexpr.y" { # Boolean and. call xvv_binop (BAND, yypvt-3*YYOPLEN, yypvt, yyval) } case 20: # line 370 "evvexpr.y" { # Boolean or. call xvv_binop (BOR, yypvt-3*YYOPLEN, yypvt, yyval) } case 21: # line 374 "evvexpr.y" { # Boolean xor. call xvv_binop (BXOR, yypvt-3*YYOPLEN, yypvt, yyval) } case 22: # line 378 "evvexpr.y" { # Boolean less than. call xvv_boolop (LT, yypvt-3*YYOPLEN, yypvt, yyval) } case 23: # line 382 "evvexpr.y" { # Boolean greater than. call xvv_boolop (GT, yypvt-3*YYOPLEN, yypvt, yyval) } case 24: # line 386 "evvexpr.y" { # Boolean less than or equal. call xvv_boolop (LE, yypvt-3*YYOPLEN, yypvt, yyval) } case 25: # line 390 "evvexpr.y" { # Boolean greater than or equal. call xvv_boolop (GE, yypvt-3*YYOPLEN, yypvt, yyval) } case 26: # line 394 "evvexpr.y" { # Boolean equal. call xvv_boolop (EQ, yypvt-3*YYOPLEN, yypvt, yyval) } case 27: # line 398 "evvexpr.y" { # String pattern-equal. call xvv_boolop (SE, yypvt-3*YYOPLEN, yypvt, yyval) } case 28: # line 402 "evvexpr.y" { # Boolean not equal. call xvv_boolop (NE, yypvt-3*YYOPLEN, yypvt, yyval) } case 29: # line 406 "evvexpr.y" { # Conditional expression. call xvv_quest (yypvt-6*YYOPLEN, yypvt-3*YYOPLEN, yypvt, yyval) } case 30: # line 410 "evvexpr.y" { # Call an intrinsic or external function. ap = O_VALP(yypvt-YYOPLEN) call xvv_callfcn (O_VALC(yypvt-3*YYOPLEN), A_ARGP(ap,1), A_NARGS(ap), yyval) call xvv_freeop (yypvt-3*YYOPLEN) call xvv_freeop (yypvt-YYOPLEN) } case 31: # line 418 "evvexpr.y" { YYMOVE (yypvt-YYOPLEN, yyval) } case 32: # line 424 "evvexpr.y" { YYMOVE (yypvt, yyval) } case 33: # line 427 "evvexpr.y" { if (O_TYPE(yypvt) != TY_CHAR) call error (1, "illegal function name") YYMOVE (yypvt, yyval) } case 34: # line 435 "evvexpr.y" { # Empty. call xvv_startarglist (NULL, yyval) } case 35: # line 439 "evvexpr.y" { # First arg; start a nonnull list. call xvv_startarglist (yypvt, yyval) } case 36: # line 443 "evvexpr.y" { # Add an argument to an existing list. call xvv_addarg (yypvt, yypvt-3*YYOPLEN, yyval) } } goto yystack_ # stack new state and value end