aboutsummaryrefslogtreecommitdiff
path: root/sys/fmtio/evvexpr.gy
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /sys/fmtio/evvexpr.gy
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/fmtio/evvexpr.gy')
-rw-r--r--sys/fmtio/evvexpr.gy2680
1 files changed, 2680 insertions, 0 deletions
diff --git a/sys/fmtio/evvexpr.gy b/sys/fmtio/evvexpr.gy
new file mode 100644
index 00000000..32a91153
--- /dev/null
+++ b/sys/fmtio/evvexpr.gy
@@ -0,0 +1,2680 @@
+%{
+include <lexnum.h>
+include <ctype.h>
+include <mach.h>
+include <math.h>
+include <evvexpr.h>
+
+.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
+
+%L
+# 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"
+
+%}
+
+# The $/ following causes the generic preprocessor to pass this block of code
+# through unchanged.
+
+$/
+
+%token CONSTANT IDENTIFIER NEWLINE YYEOS
+%token PLUS MINUS STAR SLASH EXPON CONCAT QUEST COLON
+%token LT GT LE GT EQ NE SE LAND LOR LNOT BAND BOR BXOR BNOT AT
+
+%nonassoc QUEST
+%left LAND LOR
+%left BAND BOR BXOR
+%nonassoc EQ NE SE
+%nonassoc LT GT LE GE
+%left CONCAT
+%left PLUS MINUS
+%left STAR SLASH
+%right UMINUS LNOT BNOT
+%left EXPON
+%right AT
+
+%%
+
+stmt : exprlist YYEOS {
+ # Normal exit. Move the final expression value operand
+ # into the operand structure pointed to by the global
+ # variable ev_oval.
+
+ YYMOVE ($1, ev_oval)
+ call sfree (yysp)
+ return (OK)
+ }
+ | error {
+ call error (1, "syntax error")
+ }
+ ;
+
+exprlist: expr {
+ YYMOVE ($1, $$)
+ }
+ | exprlist ',' opnl expr {
+ YYMOVE ($4, $$)
+ call xvv_freeop ($1)
+ }
+
+
+expr : CONSTANT {
+ # Numeric constant.
+ YYMOVE ($1, $$)
+ }
+ | IDENTIFIER {
+ # The boolean constants "yes" and "no" are implemented
+ # as reserved operands.
+
+ call xvv_initop ($$, 0, TY_BOOL)
+ if (streq (O_VALC($1), "yes")) {
+ O_VALI($$) = YES
+ } else if (streq (O_VALC($1), "no")) {
+ O_VALI($$) = NO
+ } else if (ev_getop != NULL) {
+ call zcall3 (ev_getop,ev_getop_data, O_VALC($1), $$)
+ if (O_TYPE($$) <= 0)
+ call xvv_error1 ("unknown operand `%s'",
+ O_VALC($1))
+ } else
+ call xvv_error1 ("illegal operand `%s'", O_VALC($1))
+ call xvv_freeop ($1)
+ }
+ | AT CONSTANT {
+ # e.g., @"param"
+ if (ev_getop != NULL) {
+ call zcall3 (ev_getop,ev_getop_data, O_VALC($2), $$)
+ if (O_TYPE($$) <= 0)
+ call xvv_error1 ("unknown operand `%s'",
+ O_VALC($1))
+ } else
+ call xvv_error1 ("illegal operand `%s'", O_VALC($2))
+ call xvv_freeop ($2)
+ }
+ | MINUS expr %prec UMINUS {
+ # Unary arithmetic minus.
+ call xvv_unop (MINUS, $2, $$)
+ }
+ | LNOT expr {
+ # Logical not.
+ call xvv_unop (LNOT, $2, $$)
+ }
+ | BNOT expr {
+ # Boolean not.
+ call xvv_unop (BNOT, $2, $$)
+ }
+ | expr PLUS opnl expr {
+ # Addition.
+ call xvv_binop (PLUS, $1, $4, $$)
+ }
+ | expr MINUS opnl expr {
+ # Subtraction.
+ call xvv_binop (MINUS, $1, $4, $$)
+ }
+ | expr STAR opnl expr {
+ # Multiplication.
+ call xvv_binop (STAR, $1, $4, $$)
+ }
+ | expr SLASH opnl expr {
+ # Division.
+ call xvv_binop (SLASH, $1, $4, $$)
+ }
+ | expr EXPON opnl expr {
+ # Exponentiation.
+ call xvv_binop (EXPON, $1, $4, $$)
+ }
+ | expr CONCAT opnl expr {
+ # Concatenate two operands.
+ call xvv_binop (CONCAT, $1, $4, $$)
+ }
+ | expr LAND opnl expr {
+ # Logical and.
+ call xvv_boolop (LAND, $1, $4, $$)
+ }
+ | expr LOR opnl expr {
+ # Logical or.
+ call xvv_boolop (LOR, $1, $4, $$)
+ }
+ | expr BAND opnl expr {
+ # Boolean and.
+ call xvv_binop (BAND, $1, $4, $$)
+ }
+ | expr BOR opnl expr {
+ # Boolean or.
+ call xvv_binop (BOR, $1, $4, $$)
+ }
+ | expr BXOR opnl expr {
+ # Boolean xor.
+ call xvv_binop (BXOR, $1, $4, $$)
+ }
+ | expr LT opnl expr {
+ # Boolean less than.
+ call xvv_boolop (LT, $1, $4, $$)
+ }
+ | expr GT opnl expr {
+ # Boolean greater than.
+ call xvv_boolop (GT, $1, $4, $$)
+ }
+ | expr LE opnl expr {
+ # Boolean less than or equal.
+ call xvv_boolop (LE, $1, $4, $$)
+ }
+ | expr GE opnl expr {
+ # Boolean greater than or equal.
+ call xvv_boolop (GE, $1, $4, $$)
+ }
+ | expr EQ opnl expr {
+ # Boolean equal.
+ call xvv_boolop (EQ, $1, $4, $$)
+ }
+ | expr SE opnl expr {
+ # String pattern-equal.
+ call xvv_boolop (SE, $1, $4, $$)
+ }
+ | expr NE opnl expr {
+ # Boolean not equal.
+ call xvv_boolop (NE, $1, $4, $$)
+ }
+ | expr QUEST opnl expr COLON opnl expr {
+ # Conditional expression.
+ call xvv_quest ($1, $4, $7, $$)
+ }
+ | funct '(' arglist ')' {
+ # Call an intrinsic or external function.
+ ap = O_VALP($3)
+ call xvv_callfcn (O_VALC($1),
+ A_ARGP(ap,1), A_NARGS(ap), $$)
+ call xvv_freeop ($1)
+ call xvv_freeop ($3)
+ }
+ | '(' expr ')' {
+ YYMOVE ($2, $$)
+ }
+ ;
+
+
+funct : IDENTIFIER {
+ YYMOVE ($1, $$)
+ }
+ | CONSTANT {
+ if (O_TYPE($1) != TY_CHAR)
+ call error (1, "illegal function name")
+ YYMOVE ($1, $$)
+ }
+ ;
+
+
+arglist : {
+ # Empty.
+ call xvv_startarglist (NULL, $$)
+ }
+ | expr {
+ # First arg; start a nonnull list.
+ call xvv_startarglist ($1, $$)
+ }
+ | arglist ',' opnl expr {
+ # Add an argument to an existing list.
+ call xvv_addarg ($4, $1, $$)
+ }
+ ;
+
+
+opnl : # Empty.
+ | opnl NEWLINE
+ ;
+
+%%
+
+# 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")
+$for (silrd)
+ case TY_PIXEL:
+ if (nelem > 0)
+ call aneg$t (Mem$t[O_VALP(in)], Mem$t[O_VALP(out)], nelem)
+ else
+ O_VAL$T(out) = -O_VAL$T(in)
+$endfor
+ 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
+ }
+$for (sil)
+ case TY_PIXEL:
+ if (nelem > 0) {
+ val_$t = NO
+ call abeqk$t (Mem$t[O_VALP(in)], val_$t, Memi[O_VALP(out)],
+ nelem)
+ } else {
+ if (O_VAL$T(in) == NO)
+ O_VAL$T(out) = YES
+ else
+ O_VAL$T(out) = NO
+ }
+$endfor
+ 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")
+$for (sil)
+ case TY_PIXEL:
+ if (nelem > 0)
+ call anot$t (Mem$t[O_VALP(in)], Mem$t[O_VALP(out)], nelem)
+ else
+ O_VAL$T(out) = not(O_VAL$T(in))
+$endfor
+ 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
+
+$for (silrd)
+PIXEL v_$t
+PIXEL xvv_null$t()
+extern xvv_null$t()
+$endfor
+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) {
+ $for (silrd)
+ case TY_PIXEL:
+ v_$t = O_VAL$T(in1)
+ call xvv_initop (in1, nelem, dtype)
+ call amovk$t (v_$t, Mem$t[O_VALP(in1)], nelem)
+ $endfor
+ }
+ }
+
+ 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) {
+$for (sil)
+ case TY_PIXEL:
+ switch (opcode) {
+ case BAND:
+ if (len1 <= 0) {
+ O_VAL$T(out) = and (O_VAL$T(in1), O_VAL$T(in2))
+ } else if (len2 <= 0) {
+ call aandk$t (Mem$t[p1], O_VAL$T(in2),
+ Mem$t[po], nelem)
+ } else {
+ call aand$t (Mem$t[p1], Mem$t[p2],
+ Mem$t[po], nelem)
+ }
+ case BOR:
+ if (len1 <= 0) {
+ O_VAL$T(out) = or (O_VAL$T(in1), O_VAL$T(in2))
+ } else if (len2 <= 0) {
+ call abork$t (Mem$t[p1], O_VAL$T(in2),
+ Mem$t[po], nelem)
+ } else {
+ call abor$t (Mem$t[p1], Mem$t[p2],
+ Mem$t[po], nelem)
+ }
+ case BXOR:
+ if (len1 <= 0) {
+ O_VAL$T(out) = xor (O_VAL$T(in1), O_VAL$T(in2))
+ } else if (len2 <= 0) {
+ call axork$t (Mem$t[p1], O_VAL$T(in2),
+ Mem$t[po], nelem)
+ } else {
+ call axor$t (Mem$t[p1], Mem$t[p2],
+ Mem$t[po], nelem)
+ }
+ }
+$endfor
+ 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")
+ }
+$for (silrd)
+ case TY_PIXEL:
+ switch (opcode) {
+ case PLUS:
+ if (len1 <= 0) {
+ O_VAL$T(out) = O_VAL$T(in1) + O_VAL$T(in2)
+ } else if (len2 <= 0) {
+ call aaddk$t (Mem$t[p1], O_VAL$T(in2),
+ Mem$t[po], nelem)
+ } else {
+ call aadd$t (Mem$t[p1], Mem$t[p2],
+ Mem$t[po], nelem)
+ }
+ case MINUS:
+ if (len1 <= 0)
+ O_VAL$T(out) = O_VAL$T(in1) - O_VAL$T(in2)
+ else if (len2 <= 0)
+ call asubk$t (Mem$t[p1], O_VAL$T(in2), Mem$t[po], nelem)
+ else
+ call asub$t (Mem$t[p1], Mem$t[p2], Mem$t[po], nelem)
+
+ case STAR:
+ if (len1 <= 0)
+ O_VAL$T(out) = O_VAL$T(in1) * O_VAL$T(in2)
+ else if (len2 <= 0)
+ call amulk$t (Mem$t[p1], O_VAL$T(in2), Mem$t[po], nelem)
+ else
+ call amul$t (Mem$t[p1], Mem$t[p2], Mem$t[po], nelem)
+
+ case SLASH:
+ if (and (ev_flags, EV_RNGCHK) == 0) {
+ # No range checking.
+ if (len1 <= 0)
+ O_VAL$T(out) = O_VAL$T(in1) / O_VAL$T(in2)
+ else if (len2 <= 0)
+ call adivk$t (Mem$t[p1], O_VAL$T(in2), Mem$t[po], nelem)
+ else
+ call adiv$t (Mem$t[p1], Mem$t[p2], Mem$t[po], nelem)
+ } else {
+ # Check for divide by zero.
+ if (len1 <= 0) {
+ if (O_VAL$T(in2) == 0$f)
+ O_VAL$T(out) = xvv_null$t(0$f)
+ else
+ O_VAL$T(out) = O_VAL$T(in1) / O_VAL$T(in2)
+ } else if (len2 <= 0) {
+ if (O_VAL$T(in2) == 0$f)
+ call amovk$t (xvv_null$t(0$f), Mem$t[po], nelem)
+ else {
+ call adivk$t (Mem$t[p1], O_VAL$T(in2), Mem$t[po],
+ nelem)
+ }
+ } else {
+ call advz$t (Mem$t[p1], Mem$t[p2], Mem$t[po], nelem,
+ xvv_null$t)
+ }
+ }
+ case EXPON:
+ if (len1 <= 0)
+ O_VAL$T(out) = O_VAL$T(in1) ** O_VAL$T(in2)
+ else if (len2 <= 0)
+ call aexpk$t (Mem$t[p1], O_VAL$T(in2), Mem$t[po], nelem)
+ else
+ call aexp$t (Mem$t[p1], Mem$t[p2], Mem$t[po], nelem)
+
+ case CONCAT:
+ # Concatenate two numeric operands.
+ if (len1 <= 0) {
+ Mem$t[po] = O_VAL$T(in1)
+ po = po + 1
+ } else {
+ call amov$t (Mem$t[p1], Mem$t[po], len1)
+ po = po + len1
+ }
+ if (len2 <= 0)
+ Mem$t[po] = O_VAL$T(in2)
+ else
+ call amov$t (Mem$t[p2], Mem$t[po], len2)
+
+ default:
+ call xvv_error (s_badswitch)
+ }
+$endfor
+ 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
+
+$for (silrd)
+PIXEL v_$t
+$endfor
+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) {
+ $for (silrd)
+ case TY_PIXEL:
+ v_$t = O_VAL$T(in1)
+ call xvv_initop (in1, nelem, dtype)
+ call amovk$t (v_$t, Mem$t[O_VALP(in1)], nelem)
+ $endfor
+ }
+ }
+
+ 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) {
+$for (sil)
+ case TY_PIXEL:
+ switch (opcode) {
+ case LAND:
+ if (len1 <= 0) {
+ O_VALI(out) =
+ btoi (O_VAL$T(in1) != 0 && O_VAL$T(in2) != 0)
+ } else if (len2 <= 0) {
+ call alank$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ } else
+ call alan$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+ case LOR:
+ if (len1 <= 0) {
+ O_VALI(out) =
+ btoi (O_VAL$T(in1) != 0 || O_VAL$T(in2) != 0)
+ } else if (len2 <= 0) {
+ call alork$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ } else
+ call alor$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+ default:
+ call xvv_error (s_badop)
+ }
+$endfor
+ default:
+ call xvv_error (s_badswitch)
+ }
+ } else {
+ # Operations supporting any arithmetic type.
+
+ switch (dtype) {
+$for (silrd)
+ case TY_PIXEL:
+ switch (opcode) {
+ case LT:
+ if (len1 <= 0)
+ O_VALI(out) = btoi (O_VAL$T(in1) < O_VAL$T(in2))
+ else if (len2 <= 0)
+ call abltk$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ else
+ call ablt$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+
+ case LE:
+ if (len1 <= 0)
+ O_VALI(out) = btoi (O_VAL$T(in1) <= O_VAL$T(in2))
+ else if (len2 <= 0)
+ call ablek$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ else
+ call able$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+
+ case GT:
+ if (len1 <= 0)
+ O_VALI(out) = btoi (O_VAL$T(in1) > O_VAL$T(in2))
+ else if (len2 <= 0)
+ call abgtk$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ else
+ call abgt$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+
+ case GE:
+ if (len1 <= 0)
+ O_VALI(out) = btoi (O_VAL$T(in1) >= O_VAL$T(in2))
+ else if (len2 <= 0)
+ call abgek$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ else
+ call abge$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+
+ case EQ:
+ if (len1 <= 0)
+ O_VALI(out) = btoi (O_VAL$T(in1) == O_VAL$T(in2))
+ else if (len2 <= 0)
+ call abeqk$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ else
+ call abeq$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+
+ case NE:
+ if (len1 <= 0)
+ O_VALI(out) = btoi (O_VAL$T(in1) != O_VAL$T(in2))
+ else if (len2 <= 0)
+ call abnek$t (Mem$t[p1], O_VAL$T(in2), Memi[po], nelem)
+ else
+ call abne$t (Mem$t[p1], Mem$t[p2], Memi[po], nelem)
+
+ default:
+ call xvv_error (s_badop)
+ }
+$endfor
+ 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) {
+ $for (silrd)
+ case TY_PIXEL:
+ 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)
+ Mem$t[op+i-1] = O_VAL$T(in1)
+ else
+ Mem$t[op+i-1] = O_VAL$T(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 amov$t (Mem$t[ip1], Mem$t[op], nelem)
+ else
+ call amovk$t (O_VAL$T(in2), Mem$t[op], nelem)
+ } else {
+ # Conditional is a vector.
+ call aselk$t (Mem$t[ip1], O_VAL$T(in2), Mem$t[op],
+ Memi[sel], nelem)
+ }
+ } else {
+ # Both operands are vectors.
+ if (O_LEN(cond) <= 0) {
+ # Conditional is a scalar.
+ if (O_VALI(cond) != 0)
+ call amov$t (Mem$t[ip1], Mem$t[op], nelem)
+ else
+ call amov$t (Mem$t[ip2], Mem$t[op], nelem)
+ } else {
+ # Conditional is a vector.
+ call asel$t (Mem$t[ip1], Mem$t[ip2], Mem$t[op],
+ Memi[sel], nelem)
+ }
+ }
+ $endfor
+ 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)
+
+$for (silrd)
+PIXEL v_$t
+PIXEL ahiv$t(), alov$t()
+PIXEL amed$t()
+int arav$t()
+$endfor
+
+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, 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)) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) > 0) {
+ call aabs$t (Mem$t[O_VALP(ap)], Mem$t[O_VALP(out)],
+ O_LEN(ap))
+ } else
+ O_VAL$T(out) = abs(O_VAL$T(ap))
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+
+ case F_ACOS:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = acos (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = acos (O_VAL$T(ap))
+ $endfor
+ case F_ASIN:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = asin (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = asin (O_VAL$T(ap))
+ $endfor
+ case F_COS:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = cos (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = cos (O_VAL$T(ap))
+ $endfor
+ case F_COSH:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = cosh (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = cosh (O_VAL$T(ap))
+ $endfor
+ case F_DEG:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = RADTODEG(Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = RADTODEG (O_VAL$T(ap))
+ $endfor
+ case F_EXP:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = exp (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = exp (O_VAL$T(ap))
+ $endfor
+ case F_LOG:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ op = O_VALP(out)
+ do i = 1, O_LEN(ap) {
+ v_$t = Mem$t[O_VALP(ap)+i-1]
+ if (rangecheck && v_$t <= 0)
+ Mem$t[op] = 0
+ else
+ Mem$t[op] = log (v_$t)
+ op = op + 1
+ }
+ } else {
+ v_$t = O_VAL$T(ap)
+ if (rangecheck && v_$t <= 0)
+ O_VAL$T(out) = 0
+ else
+ O_VAL$T(out) = log (v_$t)
+ }
+ $endfor
+ case F_LOG10:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ op = O_VALP(out)
+ do i = 1, O_LEN(ap) {
+ v_$t = Mem$t[O_VALP(ap)+i-1]
+ if (rangecheck && v_$t <= 0)
+ Mem$t[op] = 0
+ else
+ Mem$t[op] = log10 (v_$t)
+ op = op + 1
+ }
+ } else {
+ v_$t = O_VAL$T(ap)
+ if (rangecheck && v_$t <= 0)
+ O_VAL$T(out) = 0
+ else
+ O_VAL$T(out) = log10 (v_$t)
+ }
+ $endfor
+ case F_RAD:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = DEGTORAD(Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = DEGTORAD (O_VAL$T(ap))
+ $endfor
+ case F_SIN:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = sin (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = sin (O_VAL$T(ap))
+ $endfor
+ case F_SINH:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = sinh (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = sinh (O_VAL$T(ap))
+ $endfor
+ case F_SQRT:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ op = O_VALP(out)
+ do i = 1, O_LEN(ap) {
+ v_$t = Mem$t[O_VALP(ap)+i-1]
+ if (rangecheck && v_$t < 0)
+ Mem$t[op] = 0
+ else
+ Mem$t[op] = sqrt (v_$t)
+ op = op + 1
+ }
+ } else {
+ v_$t = O_VAL$T(ap)
+ if (rangecheck && v_$t <= 0)
+ O_VAL$T(out) = 0
+ else
+ O_VAL$T(out) = sqrt (v_$t)
+ }
+ $endfor
+ case F_TAN:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = tan (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = tan (O_VAL$T(ap))
+ $endfor
+ case F_TANH:
+ $for (rd)
+ if (optype == TY_PIXEL)
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] = tanh (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = tanh (O_VAL$T(ap))
+ $endfor
+
+ case F_LEN:
+ # Vector length.
+ O_VALI(out) = O_LEN(ap)
+
+ case F_HIV:
+ # High value.
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) > 0)
+ O_VAL$T(out) = ahiv$t (Mem$t[O_VALP(ap)], O_LEN(ap))
+ else
+ O_VAL$T(out) = O_VAL$T(ap)
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+ case F_LOV:
+ # Low value.
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) > 0)
+ O_VAL$T(out) = alov$t (Mem$t[O_VALP(ap)], O_LEN(ap))
+ else
+ O_VAL$T(out) = O_VAL$T(ap)
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+
+ case F_SUM:
+ # Vector sum.
+ switch (optype) {
+ $for (silr)
+ case TY_PIXEL:
+ if (O_LEN(ap) > 0)
+ v_r = asum$t (Mem$t[O_VALP(ap)], O_LEN(ap))
+ else
+ v_r = O_VAL$T(ap)
+ $endfor
+ 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) {
+ $for (sir)
+ case TY_PIXEL:
+ v_i = arav$t (Mem$t[O_VALP(ap)], O_LEN(ap), mean_r,sigma_r,v_r)
+ $endfor
+ $for (ld)
+ case TY_PIXEL:
+ v_i = arav$t (Mem$t[O_VALP(ap)], O_LEN(ap), mean_d,sigma_d,v_d)
+ $endfor
+ 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) {
+ $for (silrd)
+ case TY_PIXEL:
+ O_VAL$T(out) = amed$t (Mem$t[O_VALP(ap)], O_LEN(ap))
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+ case 3:
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ call amed3$t (Mem$t[O_VALP(args[1])],
+ Mem$t[O_VALP(args[2])],
+ Mem$t[O_VALP(args[3])],
+ Mem$t[O_VALP(out)], nelem)
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+ case 4:
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ call amed4$t (Mem$t[O_VALP(args[1])],
+ Mem$t[O_VALP(args[2])],
+ Mem$t[O_VALP(args[3])],
+ Mem$t[O_VALP(args[4])],
+ Mem$t[O_VALP(out)], nelem)
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+ case 5:
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ call amed5$t (Mem$t[O_VALP(args[1])],
+ Mem$t[O_VALP(args[2])],
+ Mem$t[O_VALP(args[3])],
+ Mem$t[O_VALP(args[4])],
+ Mem$t[O_VALP(args[5])],
+ Mem$t[O_VALP(out)], nelem)
+ $endfor
+ 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) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (chunk > 0) {
+ ip = O_VALP(ap)
+ op = O_VALP(out)
+ do i = 1, repl {
+ call amov$t (Mem$t[ip], Mem$t[op], chunk)
+ op = op + chunk
+ }
+ } else
+ call amovk$t (O_VAL$T(ap), Mem$t[O_VALP(out)], nelem)
+ $endfor
+ 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) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (nelem > 0) {
+ do i = 1, nelem {
+ j = i - shift
+ if (j < 1)
+ j = j + nelem
+ else if (j > nelem)
+ j = j - nelem
+ Mem$t[O_VALP(out)+i-1] = Mem$t[O_VALP(ap)+j-1]
+ }
+ } else
+ O_VAL$T(out) = (O_VAL$T(ap))
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+
+ case F_SORT:
+ # Sort a vector.
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (nelem > 0)
+ call asrt$t (Mem$t[O_VALP(ap)], Mem$t[O_VALP(out)], nelem)
+ else
+ O_VAL$T(out) = (O_VAL$T(ap))
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+
+ case F_ATAN, F_ATAN2:
+ $for (rd)
+ if (optype == TY_PIXEL) {
+ if (nargs == 1) {
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] =
+ atan (Mem$t[O_VALP(ap)+i-1])
+ } else
+ O_VAL$T(out) = atan (O_VAL$T(ap))
+ } else {
+ if (O_LEN(ap) > 0) {
+ do i = 1, O_LEN(ap)
+ Mem$t[O_VALP(out)+i-1] =
+ atan2 (Mem$t[O_VALP(args[1])+i-1],
+ Mem$t[O_VALP(args[2])+i-1])
+ } else
+ O_VAL$T(out) = atan2(O_VAL$T(args[1]), O_VAL$T(args[2]))
+ }
+ }
+ $endfor
+
+ case F_MOD:
+ in1 = args[1]
+ in2 = args[2]
+
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(in1) <= 0) {
+ O_VAL$T(out) = mod (O_VAL$T(in1), O_VAL$T(in2))
+ } else if (O_LEN(in2) <= 0) {
+ call amodk$t (Mem$t[O_VALP(in1)], O_VAL$T(in2),
+ Mem$t[O_VALP(out)], nelem)
+ } else {
+ call amod$t (Mem$t[O_VALP(in1)], Mem$t[O_VALP(in2)],
+ Mem$t[O_VALP(out)], nelem)
+ }
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+
+ case F_MAX:
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ # Copy the first argument.
+ ap = args[1]
+ if (O_LEN(ap) <= 0) {
+ if (O_LEN(out) > 0)
+ call amovk$t (O_VAL$T(ap), Mem$t[O_VALP(out)], nelem)
+ else
+ O_VAL$T(out) = O_VAL$T(ap)
+ } else
+ call amov$t (Mem$t[O_VALP(ap)], Mem$t[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_VAL$T(out) = max (O_VAL$T(ap), O_VAL$T(out))
+ else {
+ call amaxk$t (Mem$t[O_VALP(out)], O_VAL$T(ap),
+ Mem$t[O_VALP(out)], nelem)
+ }
+ } else {
+ call amax$t (Mem$t[O_VALP(out)], Mem$t[O_VALP(ap)],
+ Mem$t[O_VALP(out)], nelem)
+ }
+ }
+ $endfor
+ default:
+ call xvv_error1 (s_badtype, fcn)
+ }
+
+ case F_MIN:
+ switch (optype) {
+ $for (silrd)
+ case TY_PIXEL:
+ # Copy the first argument.
+ ap = args[1]
+ if (O_LEN(ap) <= 0) {
+ if (O_LEN(out) > 0)
+ call amovk$t (O_VAL$T(ap), Mem$t[O_VALP(out)], nelem)
+ else
+ O_VAL$T(out) = O_VAL$T(ap)
+ } else
+ call amov$t (Mem$t[O_VALP(ap)], Mem$t[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_VAL$T(out) = min (O_VAL$T(ap), O_VAL$T(out))
+ else {
+ call amink$t (Mem$t[O_VALP(out)], O_VAL$T(ap),
+ Mem$t[O_VALP(out)], nelem)
+ }
+ } else {
+ call amin$t (Mem$t[O_VALP(out)], Mem$t[O_VALP(ap)],
+ Mem$t[O_VALP(out)], nelem)
+ }
+ }
+ $endfor
+ 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')
+
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALI(out) = btoi (O_VAL$T(ap) != 0$f)
+ else {
+ v_$t = 0$f
+ call abnek$t (Mem$t[O_VALP(ap)], v_$t, Memi[O_VALP(out)],
+ nelem)
+ }
+ $endfor
+
+ 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
+
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALS(out) = O_VAL$T(ap)
+ else
+ call acht$ts (Mem$t[O_VALP(ap)], Memi[O_VALP(out)], nelem)
+ $endfor
+
+ 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
+
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALI(out) = O_VAL$T(ap)
+ else
+ call acht$ti (Mem$t[O_VALP(ap)], Memi[O_VALP(out)], nelem)
+ $endfor
+
+ 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
+
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALL(out) = O_VAL$T(ap)
+ else
+ call acht$tl (Mem$t[O_VALP(ap)], Memi[O_VALP(out)], nelem)
+ $endfor
+
+ 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)
+
+ $for (sil)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALI(out) = O_VAL$T(ap)
+ else
+ call acht$ti (Mem$t[O_VALP(ap)], Memi[O_VALP(out)], nelem)
+ $endfor
+
+ $for (rd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALI(out) = nint (O_VAL$T(ap))
+ else {
+ do i = 1, nelem
+ Memi[O_VALP(out)+i-1] = nint (Mem$t[O_VALP(ap)+i-1])
+ }
+ $endfor
+
+ 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
+
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALR(out) = O_VAL$T(ap)
+ else
+ call acht$tr (Mem$t[O_VALP(ap)], Memr[O_VALP(out)], nelem)
+ $endfor
+
+ 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
+
+ $for (silrd)
+ case TY_PIXEL:
+ if (O_LEN(ap) <= 0)
+ O_VALD(out) = O_VAL$T(ap)
+ else
+ call acht$td (Mem$t[O_VALP(ap)], Memd[O_VALP(out)], nelem)
+ $endfor
+
+ 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))
+ $for (sil)
+ case TY_PIXEL:
+ call sprintf (O_VALC(out), nelem, "%d")
+ call parg$t (O_VAL$T(ap))
+ $endfor
+ $for (rd)
+ case TY_PIXEL:
+ call sprintf (O_VALC(out), nelem, "%g")
+ call parg$t (O_VAL$T(ap))
+ $endfor
+ 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?
+ $for (sil)
+ case TY_PIXEL:
+ v_l = O_VAL$T(o1)
+ $endfor
+ $for (rd)
+ case TY_PIXEL:
+ v_d = O_VAL$T(o1)
+ float = true
+ $endfor
+ 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)
+ }
+ $for (sil)
+ case TY_PIXEL:
+ if (float)
+ O_VAL$T(o2) = v_d
+ else
+ O_VAL$T(o2) = v_l
+ $endfor
+ $for (rd)
+ case TY_PIXEL:
+ if (float)
+ O_VAL$T(o2) = v_d
+ else
+ O_VAL$T(o2) = v_l
+ $endfor
+ 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) {
+ $for (silrd)
+ case TY_PIXEL:
+ v_$t = 0$f
+ call abnek$t (Mem$t[vp], v_$t, Memi[O_VALP(o2)], nelem)
+ $endfor
+ 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) {
+ $for (silrd)
+ case TY_PIXEL:
+ O_VAL$T(o2) = v_d
+ $endfor
+ }
+ $for (silrd)
+ case TY_PIXEL:
+ op = coerce (O_VALP(o2), O_TYPE(o2), TY_CHAR)
+ call acht$t (Mem$t[vp], Memc[op], nelem, dtype)
+ $endfor
+ 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).
+
+$for (silrd)
+PIXEL procedure xvv_null$t (ignore)
+PIXEL ignore #I ignored
+begin
+ return (0$f)
+end
+$endfor