* Copyright (c) 1994 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
* Opcode execution module
#define QUICKLOCALS 20 /* local vars to handle quickly */
VALUE
*stack
; /* current location of top of stack */
static VALUE stackarray
[MAXSTACK
]; /* storage for stack */
static VALUE oldvalue
; /* previous calculation value */
static char *funcname
; /* function being executed */
static long funcline
; /* function line being executed */
FLAG traceflags
; /* current trace flags */
int tab_ok
= TRUE
; /* FALSE => don't print lading tabs */
static void o_nop(), o_localaddr(), o_globaladdr(), o_paramaddr();
static void o_globalvalue(), o_paramvalue(), o_number(), o_indexaddr();
static void o_assign(), o_add(), o_sub(), o_mul(), o_div();
static void o_mod(), o_save(), o_negate(), o_invert(), o_int(), o_frac();
static void o_numerator(), o_denominator(), o_duplicate(), o_pop();
static void o_jumpeq(), o_jumpne(), o_jump(), o_usercall(), o_getvalue();
static void o_eq(), o_ne(), o_le(), o_ge(), o_lt(), o_gt(), o_preinc();
static void o_postinc(), o_postdec(), o_debug(), o_print(), o_assignpop();
static void o_zero(), o_one(), o_printeol(), o_printspace(), o_printstring();
static void o_oldvalue(), o_quo(), o_power(), o_quit(), o_call(), o_swap();
static void o_dupvalue(), o_getepsilon(), o_and(), o_or(), o_not();
static void o_abs(), o_sgn(), o_isint(), o_condorjump(), o_condandjump();
static void o_square(), o_string(), o_isnum(), o_undef(), o_isnull();
static void o_matcreate(), o_ismat(), o_isstr(), o_getconfig(), o_predec();
static void o_leftshift(), o_rightshift(), o_casejump();
static void o_isodd(), o_iseven(), o_fiaddr(), o_fivalue(), o_argvalue();
static void o_isreal(), o_imaginary(), o_re(), o_im(), o_conjugate();
static void o_objcreate(), o_isobj(), o_norm(), o_elemaddr(), o_elemvalue();
static void o_istype(), o_scale(), o_localvalue(), o_return(), o_islist();
static void o_issimple(), o_cmp(), o_quomod(), o_setconfig(), o_setepsilon();
static void o_printresult(), o_isfile(), o_isassoc(), o_eleminit();
* Types of opcodes (depends on arguments saved after the opcode).
#define OPNUL 1 /* opcode has no arguments */
#define OPONE 2 /* opcode has one integer argument */
#define OPTWO 3 /* opcode has two integer arguments */
#define OPJMP 4 /* opcode is a jump (with one pointer argument) */
#define OPRET 5 /* opcode is a return (with no argument) */
#define OPGLB 6 /* opcode has global symbol pointer argument */
#define OPPAR 7 /* opcode has parameter index argument */
#define OPLOC 8 /* opcode needs local variable pointer (with one arg) */
#define OPSTR 9 /* opcode has a string constant arg */
#define OPARG 10 /* opcode is given number of arguments */
#define OPSTI 11 /* opcode is static initialization */
* Information about each opcode.
void (*o_func
)(); /* routine to call for opcode */
int o_type
; /* type of opcode */
char *o_name
; /* name of opcode */
} opcodes
[MAX_OPCODE
+1] = {
o_nop
, OPNUL
, "NOP", /* no operation */
o_localaddr
, OPLOC
, "LOCALADDR", /* address of local variable */
o_globaladdr
, OPGLB
, "GLOBALADDR", /* address of global variable */
o_paramaddr
, OPPAR
, "PARAMADDR", /* address of paramater variable */
o_localvalue
, OPLOC
, "LOCALVALUE", /* value of local variable */
o_globalvalue
, OPGLB
, "GLOBALVALUE", /* value of global variable */
o_paramvalue
, OPPAR
, "PARAMVALUE", /* value of paramater variable */
o_number
, OPONE
, "NUMBER", /* constant real numeric value */
o_indexaddr
, OPTWO
, "INDEXADDR", /* array index address */
o_printresult
, OPNUL
, "PRINTRESULT", /* print result of top-level expression */
o_assign
, OPNUL
, "ASSIGN", /* assign value to variable */
o_add
, OPNUL
, "ADD", /* add top two values */
o_sub
, OPNUL
, "SUB", /* subtract top two values */
o_mul
, OPNUL
, "MUL", /* multiply top two values */
o_div
, OPNUL
, "DIV", /* divide top two values */
o_mod
, OPNUL
, "MOD", /* take mod of top two values */
o_save
, OPNUL
, "SAVE", /* save value for later use */
o_negate
, OPNUL
, "NEGATE", /* negate top value */
o_invert
, OPNUL
, "INVERT", /* invert top value */
o_int
, OPNUL
, "INT", /* take integer part */
o_frac
, OPNUL
, "FRAC", /* take fraction part */
o_numerator
, OPNUL
, "NUMERATOR", /* take numerator */
o_denominator
, OPNUL
, "DENOMINATOR", /* take denominator */
o_duplicate
, OPNUL
, "DUPLICATE", /* duplicate top value */
o_pop
, OPNUL
, "POP", /* pop top value */
o_return
, OPRET
, "RETURN", /* return value of function */
o_jumpeq
, OPJMP
, "JUMPEQ", /* jump if value zero */
o_jumpne
, OPJMP
, "JUMPNE", /* jump if value nonzero */
o_jump
, OPJMP
, "JUMP", /* jump unconditionally */
o_usercall
, OPTWO
, "USERCALL", /* call a user function */
o_getvalue
, OPNUL
, "GETVALUE", /* convert address to value */
o_eq
, OPNUL
, "EQ", /* test elements for equality */
o_ne
, OPNUL
, "NE", /* test elements for inequality */
o_le
, OPNUL
, "LE", /* test elements for <= */
o_ge
, OPNUL
, "GE", /* test elements for >= */
o_lt
, OPNUL
, "LT", /* test elements for < */
o_gt
, OPNUL
, "GT", /* test elements for > */
o_preinc
, OPNUL
, "PREINC", /* add one to variable (++x) */
o_predec
, OPNUL
, "PREDEC", /* subtract one from variable (--x) */
o_postinc
, OPNUL
, "POSTINC", /* add one to variable (x++) */
o_postdec
, OPNUL
, "POSTDEC", /* subtract one from variable (x--) */
o_debug
, OPONE
, "DEBUG", /* debugging point */
o_print
, OPONE
, "PRINT", /* print value */
o_assignpop
, OPNUL
, "ASSIGNPOP", /* assign to variable and pop it */
o_zero
, OPNUL
, "ZERO", /* put zero on the stack */
o_one
, OPNUL
, "ONE", /* put one on the stack */
o_printeol
, OPNUL
, "PRINTEOL", /* print end of line */
o_printspace
, OPNUL
, "PRINTSPACE", /* print a space */
o_printstring
, OPSTR
, "PRINTSTR", /* print constant string */
o_dupvalue
, OPNUL
, "DUPVALUE", /* duplicate value of top value */
o_oldvalue
, OPNUL
, "OLDVALUE", /* old value from previous calc */
o_quo
, OPNUL
, "QUO", /* integer quotient of top values */
o_power
, OPNUL
, "POWER", /* value raised to a power */
o_quit
, OPSTR
, "QUIT", /* quit program */
o_call
, OPTWO
, "CALL", /* call built-in routine */
o_getepsilon
, OPNUL
, "GETEPSILON", /* get allowed error for calculations */
o_and
, OPNUL
, "AND", /* arithmetic and or top two values */
o_or
, OPNUL
, "OR", /* arithmetic or of top two values */
o_not
, OPNUL
, "NOT", /* logical not or top value */
o_abs
, OPNUL
, "ABS", /* absolute value of top value */
o_sgn
, OPNUL
, "SGN", /* sign of number */
o_isint
, OPNUL
, "ISINT", /* whether number is an integer */
o_condorjump
, OPJMP
, "CONDORJUMP", /* conditional or jump */
o_condandjump
, OPJMP
, "CONDANDJUMP", /* conditional and jump */
o_square
, OPNUL
, "SQUARE", /* square top value */
o_string
, OPSTR
, "STRING", /* string constant value */
o_isnum
, OPNUL
, "ISNUM", /* whether value is a number */
o_undef
, OPNUL
, "UNDEF", /* load undefined value on stack */
o_isnull
, OPNUL
, "ISNULL", /* whether value is the null value */
o_argvalue
, OPARG
, "ARGVALUE", /* load value of arg (parameter) n */
o_matcreate
, OPONE
, "MATCREATE", /* create matrix */
o_ismat
, OPNUL
, "ISMAT", /* whether value is a matrix */
o_isstr
, OPNUL
, "ISSTR", /* whether value is a string */
o_getconfig
, OPNUL
, "GETCONFIG", /* get value of configuration parameter */
o_leftshift
, OPNUL
, "LEFTSHIFT", /* left shift of integer */
o_rightshift
, OPNUL
, "RIGHTSHIFT", /* right shift of integer */
o_casejump
, OPJMP
, "CASEJUMP", /* test case and jump if not matched */
o_isodd
, OPNUL
, "ISODD", /* whether value is odd integer */
o_iseven
, OPNUL
, "ISEVEN", /* whether value is even integer */
o_fiaddr
, OPNUL
, "FIADDR", /* 'fast index' matrix address */
o_fivalue
, OPNUL
, "FIVALUE", /* 'fast index' matrix value */
o_isreal
, OPNUL
, "ISREAL", /* whether value is real number */
o_imaginary
, OPONE
, "IMAGINARY", /* constant imaginary numeric value */
o_re
, OPNUL
, "RE", /* real part of complex number */
o_im
, OPNUL
, "IM", /* imaginary part of complex number */
o_conjugate
, OPNUL
, "CONJUGATE", /* complex conjugate */
o_objcreate
, OPONE
, "OBJCREATE", /* create object */
o_isobj
, OPNUL
, "ISOBJ", /* whether value is an object */
o_norm
, OPNUL
, "NORM", /* norm of value (square of abs) */
o_elemaddr
, OPONE
, "ELEMADDR", /* address of element of object */
o_elemvalue
, OPONE
, "ELEMVALUE", /* value of element of object */
o_istype
, OPNUL
, "ISTYPE", /* whether types are the same */
o_scale
, OPNUL
, "SCALE", /* scale value by a power of two */
o_islist
, OPNUL
, "ISLIST", /* whether value is a list */
o_swap
, OPNUL
, "SWAP", /* swap values of two variables */
o_issimple
, OPNUL
, "ISSIMPLE", /* whether value is simple type */
o_cmp
, OPNUL
, "CMP", /* compare values returning -1, 0, 1 */
o_quomod
, OPNUL
, "QUOMOD", /* calculate quotient and remainder */
o_setconfig
, OPNUL
, "SETCONFIG", /* set configuration parameter */
o_setepsilon
, OPNUL
, "SETEPSILON", /* set allowed error for calculations */
o_isfile
, OPNUL
, "ISFILE", /* whether value is a file */
o_isassoc
, OPNUL
, "ISASSOC", /* whether value is an association */
o_nop
, OPSTI
, "INITSTATIC", /* once only code for static init */
o_eleminit
, OPONE
, "ELEMINIT" /* assign element of matrix or object */
/* on first init, setup the stack array */
for (i
=0; i
< sizeof(stackarray
)/sizeof(stackarray
[0]); ++i
) {
stackarray
[i
].v_type
= V_NULL
;
stackarray
[i
].v_subtype
= V_NOSUBTYPE
;
/* on subsequent inits, free the old stack */
while (stack
> stackarray
) {
* Compute the result of a function by interpreting opcodes.
* Arguments have just been pushed onto the evaluation stack.
register FUNC
*fp
; /* function to calculate */
int argcount
; /* number of arguments called with */
register unsigned long pc
; /* current pc inside function */
register struct opcode
*op
; /* current opcode pointer */
register VALUE
*locals
; /* pointer to local variables */
long oldline
; /* old value of line counter */
unsigned int opnum
; /* current opcode number */
int origargcount
; /* original number of arguments */
int i
; /* loop counter */
BOOL dojump
; /* TRUE if jump is to occur */
char *oldname
; /* old function name being executed */
VALUE
*beginstack
; /* beginning of stack frame */
VALUE
*args
; /* pointer to function arguments */
VALUE retval
; /* function return value */
VALUE localtable
[QUICKLOCALS
]; /* some local variables */
while (argcount
< fp
->f_paramcount
) {
if (fp
->f_localcount
> QUICKLOCALS
) {
locals
= (VALUE
*) malloc(sizeof(VALUE
) * fp
->f_localcount
);
math_error("No memory for local variables");
for (i
= 0; i
< fp
->f_localcount
; i
++) {
locals
[i
].v_num
= qlink(&_qzero_
);
locals
[i
].v_type
= V_NUM
;
locals
[i
].v_subtype
= V_NOSUBTYPE
;
args
= beginstack
- (argcount
- 1);
if (abortlevel
>= ABORT_OPCODE
)
math_error("Calculation aborted in opcode");
if (pc
>= fp
->f_opcodecount
)
math_error("Function pc out of range");
if (stack
> &stackarray
[MAXSTACK
-3])
math_error("Evaluation stack depth exceeded");
opnum
= fp
->f_opcodes
[pc
];
math_error("Function opcode out of range");
if (traceflags
& TRACE_OPCODES
) {
printf("%8s, pc %4ld: ", fp
->f_name
, pc
);
(void)dumpop(&fp
->f_opcodes
[pc
]);
* Now call the opcode routine appropriately.
case OPNUL
: /* no extra arguments */
case OPONE
: /* one extra integer argument */
(*op
->o_func
)(fp
, fp
->f_opcodes
[pc
++]);
case OPTWO
: /* two extra integer arguments */
(*op
->o_func
)(fp
, fp
->f_opcodes
[pc
],
case OPJMP
: /* jump opcodes (one extra pointer arg) */
(*op
->o_func
)(fp
, &dojump
);
case OPGLB
: /* global symbol reference (pointer arg) */
case OPSTR
: /* string constant address */
(*op
->o_func
)(fp
, *((char **) &fp
->f_opcodes
[pc
]));
case OPLOC
: /* local variable reference */
(*op
->o_func
)(fp
, locals
, fp
->f_opcodes
[pc
++]);
case OPPAR
: /* parameter variable reference */
(*op
->o_func
)(fp
, argcount
, args
, fp
->f_opcodes
[pc
++]);
case OPARG
: /* parameter variable reference */
(*op
->o_func
)(fp
, origargcount
, args
);
case OPRET
: /* return from function */
if (stack
->v_type
== V_ADDR
)
copyvalue(stack
->v_addr
, stack
);
for (i
= 0; i
< fp
->f_localcount
; i
++)
if (locals
!= localtable
)
if (stack
!= &beginstack
[1])
math_error("Misaligned stack");
case OPSTI
: /* static initialization code */
fp
->f_opcodes
[pc
++ - 1] = OP_JUMP
;
math_error("Unknown opcode type");
* Dump an opcode at a particular address.
* Returns the size of the opcode so that it can easily be skipped over.
long *pc
; /* location of the opcode */
unsigned long op
; /* opcode number */
printf("%s", opcodes
[op
].o_name
);
case OP_LOCALADDR
: case OP_LOCALVALUE
:
printf(" %s\n", localname(*pc
));
case OP_GLOBALADDR
: case OP_GLOBALVALUE
:
printf(" %s\n", globalname(*((GLOBAL
**) pc
)));
case OP_PARAMADDR
: case OP_PARAMVALUE
:
printf(" %s\n", paramname(*pc
));
case OP_PRINTSTRING
: case OP_STRING
:
printf(" \"%s\"\n", *((char **) pc
));
printf(" \"%s\"\n", *((char **) pc
));
printf(" %ld %ld\n", pc
[0], pc
[1]);
case OP_PRINT
: case OP_JUMPEQ
: case OP_JUMPNE
: case OP_JUMP
:
case OP_CONDORJUMP
: case OP_CONDANDJUMP
: case OP_CASEJUMP
:
case OP_INITSTATIC
: case OP_MATCREATE
: case OP_OBJCREATE
:
case OP_NUMBER
: case OP_IMAGINARY
:
qprintf(" %r\n", constvalue(*pc
));
printf(" line %ld\n", *pc
);
printf(" %s with %ld args\n", builtinname(pc
[0]), pc
[1]);
printf(" %s with %ld args\n", namefunc(pc
[0]), pc
[1]);
o_localaddr(fp
, locals
, index
)
if ((unsigned long)index
>= fp
->f_localcount
)
math_error("Bad local variable index");
math_error("Global variable \"%s\" not initialized", sp
->g_name
);
stack
->v_addr
= &sp
->g_value
;
o_paramaddr(fp
, argcount
, args
, index
)
if ((unsigned long)index
>= argcount
)
math_error("Bad parameter index");
if (args
->v_type
== V_ADDR
)
stack
->v_addr
= args
->v_addr
;
o_localvalue(fp
, locals
, index
)
if ((unsigned long)index
>= fp
->f_localcount
)
math_error("Bad local variable index");
copyvalue(locals
, ++stack
);
GLOBAL
*sp
; /* global symbol */
math_error("Global variable not defined");
copyvalue(&sp
->g_value
, ++stack
);
o_paramvalue(fp
, argcount
, args
, index
)
if ((unsigned long)index
>= argcount
)
math_error("Bad paramaeter index");
if (args
->v_type
== V_ADDR
)
copyvalue(args
, ++stack
);
o_argvalue(fp
, argcount
, args
)
if (vp
->v_type
== V_ADDR
)
if ((vp
->v_type
!= V_NUM
) || qisneg(vp
->v_num
) ||
math_error("Illegal argument for arg function");
if (qiszero(vp
->v_num
)) {
if (stack
->v_type
== V_NUM
)
stack
->v_num
= itoq((long) argcount
);
index
= qtoi(vp
->v_num
) - 1;
if (stack
->v_type
== V_NUM
)
(void) o_paramvalue(fp
, argcount
, args
, index
);
math_error("Numeric constant value not found");
math_error("Numeric constant value not found");
c
->real
= qlink(&_qzero_
);
stack
->v_subtype
= V_STRLITERAL
;
register MATRIX
*mp
; /* matrix being defined */
NUMBER
*num1
; /* first number from stack */
NUMBER
*num2
; /* second number from stack */
VALUE
*vp
; /* value being defined */
long min
[MAXDIM
]; /* minimum range */
long max
[MAXDIM
]; /* maximum range */
long tmp
; /* temporary */
long size
; /* size of matrix */
if ((dim
<= 0) || (dim
> MAXDIM
))
math_error("Bad dimension %ld for matrix", dim
);
if (stack
[-2*dim
].v_type
!= V_ADDR
)
math_error("Attempting to init matrix for non-address");
for (i
= dim
- 1; i
>= 0; i
--) {
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
))
math_error("Non-numeric bounds for matrix");
if (qisfrac(num1
) || qisfrac(num2
))
math_error("Non-integral bounds for matrix");
if (zisbig(num1
->num
) || zisbig(num2
->num
))
math_error("Very large bounds for matrix");
size
*= (max
[i
] - min
[i
] + 1);
math_error("Very large size for matrix");
for (i
= 0; i
< dim
; i
++) {
for (i
= 0; i
< size
; i
++) {
vp
->v_num
= qlink(&_qzero_
);
if (vp
->v_type
== V_ADDR
)
if ((index
< 0) || (index
>= mp
->m_size
))
math_error("Too many initializer values");
oldvp
= &mp
->m_table
[index
];
if ((index
< 0) || (index
>= op
->o_actions
->count
))
math_error("Too many initializer values");
oldvp
= &op
->o_table
[index
];
math_error("Attempt to initialize non matrix or object");
if (vp
->v_type
== V_ADDR
)
o_indexaddr(fp
, dim
, writeflag
)
long dim
; /* dimension of matrix */
long writeflag
; /* nonzero if element will be written */
VALUE indices
[MAXDIM
]; /* index values */
if ((dim
<= 0) || (dim
> MAXDIM
))
math_error("Too many dimensions for indexing");
if (val
->v_type
!= V_ADDR
)
math_error("Non-pointer for index operation");
for (i
= 0; i
< dim
; i
++) {
if (vp
->v_type
== V_ADDR
)
indices
[i
] = vp
->v_addr
[0];
vp
= matindex(val
->v_mat
, flag
, dim
, indices
);
vp
= associndex(val
->v_assoc
, flag
, dim
, indices
);
math_error("Illegal value for indexing");
if (stack
->v_type
!= V_ADDR
)
math_error("Non-pointer for element reference");
if (stack
->v_addr
->v_type
!= V_OBJ
)
math_error("Referencing element of non-object");
index
= objoffset(stack
->v_addr
->v_obj
, index
);
math_error("Element does not exist for object");
stack
->v_addr
= &stack
->v_addr
->v_obj
->o_table
[index
];
if (stack
->v_type
!= V_OBJ
) {
(void) o_elemaddr(fp
, index
);
index
= objoffset(stack
->v_obj
, index
);
math_error("Element does not exist for object");
copyvalue(&stack
->v_obj
->o_table
[index
], stack
);
OBJECT
*op
; /* object being created */
VALUE
*vp
; /* value being defined */
if (stack
->v_type
!= V_ADDR
)
math_error("Attempting to init object for non-address");
VALUE
*var
; /* variable value */
if (var
->v_type
!= V_ADDR
)
math_error("Assignment into non-variable");
if (vp
->v_type
== V_ADDR
) {
VALUE
*var
; /* variable value */
if (var
->v_type
!= V_ADDR
)
math_error("Assignment into non-variable");
if ((vp
->v_type
== V_ADDR
) && (vp
->v_addr
== var
)) {
if (vp
->v_type
== V_ADDR
)
copyvalue(vp
->v_addr
, var
);
VALUE
*v1
, *v2
; /* variables to be swapped */
if ((v1
->v_type
!= V_ADDR
) || (v2
->v_type
!= V_ADDR
))
math_error("Swapping non-variables");
v1
->v_addr
[0] = v2
->v_addr
[0];
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
q
= qadd(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
q
= qsub(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
q
= qmul(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
q
= qdiv(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
q
= qquo(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
q
= qmod(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
VALUE
*v1
, *v2
, *v3
, *v4
;
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v3
->v_type
!= V_ADDR
) || (v4
->v_type
!= V_ADDR
))
math_error("Non-variable for quomod");
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
))
math_error("Non-reals for quomod");
res
= qquomod(v1
->v_num
, v2
->v_num
, &valquo
.v_num
, &valmod
.v_num
);
stack
->v_num
= (res
? qlink(&_qone_
) : qlink(&_qzero_
));
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
))
math_error("Non-numerics for and");
q
= qand(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
))
math_error("Non-numerics for or");
q
= qor(v1
->v_num
, v2
->v_num
);
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
stack
->v_num
= (r
? qlink(&_qzero_
) : qlink(&_qone_
));
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
)) {
scalevalue(v2
, v1
, &tmp
);
math_error("Non-integral scaling factor");
math_error("Very large scaling factor");
q
= qscale(v2
->v_num
, qtoi(q
));
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (qisint(vp
->v_num
) && (stack
->v_type
== V_NUM
))
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_NUM
) || (v2
->v_type
!= V_NUM
) ||
if (stack
->v_type
== V_NUM
)
if ((stack
->v_type
== V_NUM
) && !qisneg(v1
->v_num
))
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
if ((v1
->v_type
!= V_OBJ
) || (v2
->v_type
!= V_OBJ
))
r
= (v1
->v_type
== v2
->v_type
);
r
= (v1
->v_obj
->o_actions
== v2
->v_obj
->o_actions
);
stack
->v_num
= itoq((long) r
);
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
!= V_NUM
) {
stack
->v_num
= qlink(&_qzero_
);
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (stack
->v_type
== V_NUM
)
if (stack
->v_type
== V_COM
)
stack
->v_num
= qlink(&_qzero_
);
stack
->v_num
= qlink(&_qone_
);
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
!= V_MAT
) {
stack
->v_num
= qlink(&_qzero_
);
stack
->v_num
= qlink(&_qone_
);
if (vp
->v_type
== V_ADDR
)
r
= (vp
->v_type
== V_LIST
);
stack
->v_num
= (r
? qlink(&_qone_
) : qlink(&_qzero_
));
if (vp
->v_type
== V_ADDR
)
r
= (vp
->v_type
== V_OBJ
);
stack
->v_num
= (r
? qlink(&_qone_
) : qlink(&_qzero_
));
if (vp
->v_type
== V_ADDR
)
r
= (vp
->v_type
== V_STR
);
stack
->v_num
= (r
? qlink(&_qone_
) : qlink(&_qzero_
));
if (vp
->v_type
== V_ADDR
)
r
= (vp
->v_type
== V_FILE
);
stack
->v_num
= (r
? qlink(&_qone_
) : qlink(&_qzero_
));
if (vp
->v_type
== V_ADDR
)
r
= (vp
->v_type
== V_ASSOC
);
stack
->v_num
= (r
? qlink(&_qone_
) : qlink(&_qzero_
));
if (vp
->v_type
== V_ADDR
)
stack
->v_num
= (r
? qlink(&_qone_
) : qlink(&_qzero_
));
if (vp
->v_type
== V_ADDR
)
if ((vp
->v_type
== V_NUM
) && qisodd(vp
->v_num
)) {
if (stack
->v_type
== V_NUM
)
stack
->v_num
= qlink(&_qone_
);
stack
->v_num
= qlink(&_qzero_
);
if (vp
->v_type
== V_ADDR
)
if ((vp
->v_type
== V_NUM
) && qiseven(vp
->v_num
)) {
if (stack
->v_type
== V_NUM
)
stack
->v_num
= qlink(&_qone_
);
stack
->v_num
= qlink(&_qzero_
);
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
stack
->v_num
= qlink(&_qone_
);
stack
->v_num
= qlink(&_qzero_
);
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
!= V_NULL
) {
stack
->v_num
= qlink(&_qzero_
);
stack
->v_num
= qlink(&_qone_
);
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_ADDR
) {
stack
->v_num
= qlink(vp
->v_num
);
math_error("Taking real part of non-number");
q
= qlink(vp
->v_com
->real
);
if (stack
->v_type
== V_COM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
stack
->v_num
= qlink(&_qzero_
);
math_error("Taking imaginary part of non-number");
q
= qlink(vp
->v_com
->imag
);
if (stack
->v_type
== V_COM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_ADDR
) {
stack
->v_num
= qlink(vp
->v_num
);
register MATRIX
*m
; /* current matrix element */
NUMBER
*q
; /* index value */
LIST
*lp
; /* list header */
ASSOC
*ap
; /* association header */
VALUE
*vp
; /* stack value */
long index
; /* index value as an integer */
if (vp
->v_type
== V_ADDR
)
math_error("Fast indexing by non-number");
math_error("Fast indexing by non-integer");
if (zisbig(q
->num
) || (index
< 0))
math_error("Index out of range for fast indexing");
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
!= V_ADDR
)
math_error("Bad value for fast indexing");
switch (vp
->v_addr
->v_type
) {
if (index
>= vp
->v_addr
->v_obj
->o_actions
->count
)
math_error("Index out of bounds for object");
vp
->v_addr
= vp
->v_addr
->v_obj
->o_table
+ index
;
math_error("Index out of bounds for matrix");
vp
->v_addr
= m
->m_table
+ index
;
vp
->v_addr
= listfindex(lp
, index
);
math_error("Index out of bounds for list");
ap
= vp
->v_addr
->v_assoc
;
vp
->v_addr
= assocfindex(ap
, index
);
math_error("Index out of bounds for association");
math_error("Bad variable type for fast indexing");
if (vp
->v_type
== V_ADDR
)
if (stack
->v_type
== V_NUM
)
val
= objcall(OBJ_SGN
, vp
, NULL_VALUE
, NULL_VALUE
);
math_error("Bad value for sgn");
if (vp
->v_type
== V_ADDR
)
math_error("Numerator of non-number");
if ((stack
->v_type
== V_NUM
) && qisint(vp
->v_num
))
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
math_error("Denominator of non-number");
if (stack
->v_type
== V_NUM
)
copyvalue(stack
, stack
+ 1);
if (stack
->v_type
== V_ADDR
)
copyvalue(stack
->v_addr
, stack
+ 1);
copyvalue(stack
, stack
+ 1);
int i
; /* result of comparison */
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
int i
; /* result of comparison */
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (stack
->v_type
== V_NUM
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (!qiszero(vp
->v_num
)) {
if (stack
->v_type
== V_NUM
)
o_condandjump(fp
, dojump
)
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
== V_NUM
) {
if (qiszero(vp
->v_num
)) {
if (stack
->v_type
== V_NUM
)
* Compare the top two values on the stack for equality and jump if they are
* different, popping off the top element, leaving the first one on the stack.
* If they are equal, pop both values and do not jump.
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
r
= comparevalue(v1
, v2
);
o_usercall(fp
, index
, argcount
)
math_error("Function \"%s\" is undefined", namefunc(index
));
calculate(fp
, (int) argcount
);
o_call(fp
, index
, argcount
)
result
= builtinfunc(index
, (int) argcount
, stack
);
if (stack
->v_type
== V_ADDR
)
copyvalue(stack
->v_addr
, stack
);
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
stack
->v_num
= itoq((long) r
);
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
r
= comparevalue(v1
, v2
);
stack
->v_num
= itoq((long) (r
== 0));
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
r
= comparevalue(v1
, v2
);
stack
->v_num
= itoq((long) (r
!= 0));
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
stack
->v_num
= itoq((long) (r
<= 0));
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
stack
->v_num
= itoq((long) (r
>= 0));
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
stack
->v_num
= itoq((long) (r
< 0));
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
stack
->v_num
= itoq((long) (r
> 0));
if (stack
->v_type
!= V_ADDR
)
math_error("Preincrementing non-variable");
if (stack
->v_addr
->v_type
== V_NUM
) {
np
= &stack
->v_addr
->v_num
;
if (stack
->v_type
!= V_ADDR
)
math_error("Predecrementing non-variable");
if (stack
->v_addr
->v_type
== V_NUM
) {
np
= &stack
->v_addr
->v_num
;
if (stack
->v_type
!= V_ADDR
)
math_error("Postincrementing non-variable");
if (stack
->v_addr
->v_type
== V_NUM
) {
np
= &stack
->v_addr
->v_num
;
if (stack
->v_type
!= V_ADDR
)
math_error("Postdecrementing non-variable");
if (stack
->v_addr
->v_type
== V_NUM
) {
np
= &stack
->v_addr
->v_num
;
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
shiftvalue(v1
, v2
, FALSE
, &tmp
);
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
shiftvalue(v1
, v2
, TRUE
, &tmp
);
if (abortlevel
>= ABORT_STATEMENT
)
math_error("Calculation aborted at statement boundary");
if (vp
->v_type
== V_ADDR
)
if (vp
->v_type
!= V_NULL
) {
printvalue(vp
, PRINT_UNAMBIG
);
if (vp
->v_type
== V_ADDR
)
printvalue(vp
, (int) flags
);
if (traceflags
& TRACE_OPCODES
)
if (traceflags
& TRACE_OPCODES
)
if (traceflags
& TRACE_OPCODES
)
stack
->v_num
= qlink(&_qzero_
);
stack
->v_num
= qlink(&_qone_
);
if (vp
->v_type
== V_ADDR
)
freevalue(&fp
->f_savedvalue
);
copyvalue(vp
, &fp
->f_savedvalue
);
copyvalue(&oldvalue
, ++stack
);
if ((fp
->f_name
[0] == '*') && (fp
->f_name
[1] == '\0')) {
while (stack
> stackarray
) {
math_error("quit statement executed");
stack
->v_num
= qlink(_epsilon_
);
if (vp
->v_type
== V_ADDR
)
math_error("Non-numeric for epsilon");
stack
->v_num
= qlink(_epsilon_
);
if (v1
->v_type
== V_ADDR
)
if (v2
->v_type
== V_ADDR
)
math_error("Non-string for config");
type
= configtype(v1
->v_str
);
math_error("Unknown config name \"%s\"", v1
->v_str
);
if (vp
->v_type
== V_ADDR
)
math_error("Non-string for config");
type
= configtype(vp
->v_str
);
math_error("Unknown config name \"%s\"", vp
->v_str
);
* Set the 'old' value to the last value saved during the calculation.
if (fp
->f_savedvalue
.v_type
== V_NULL
)
oldvalue
= fp
->f_savedvalue
;
fp
->f_savedvalue
.v_type
= V_NULL
;
* Routine called on any runtime error, to complain about it (with possible
* arguments), and then longjump back to the top level command scanner.
# define VA_ALIST fmt, va_alist
# define VA_DCL char *fmt; va_dcl
# if defined(__STDC__) && __STDC__ == 1
# define VA_ALIST char *fmt, ...
# define VA_DCL char *fmt;
if (funcname
&& (*funcname
!= '*'))
fprintf(stderr
, "\"%s\": ", funcname
);
if (funcline
&& ((funcname
&& (*funcname
!= '*')) || !inputisterminal()))
fprintf(stderr
, "line %ld: ", funcline
);
fprintf(stderr
, "%s\n", buf
);