Eigenmath/userfunc.cpp

152 lines
2.3 KiB
C++

// Evaluate a user defined function
#include "stdafx.h"
#include "defs.h"
#define F p3 // F is the function body
#define A p4 // A is the formal argument list
#define B p5 // B is the calling argument list
#define S p6 // S is the argument substitution list
void
eval_user_function(void)
{
int h;
// Use "derivative" instead of "d" if there is no user function "d"
if (car(p1) == symbol(SYMBOL_D) && get_arglist(symbol(SYMBOL_D)) == symbol(NIL)) {
eval_derivative();
return;
}
F = get_binding(car(p1));
A = get_arglist(car(p1));
B = cdr(p1);
// Undefined function?
if (F == car(p1)) {
h = tos;
push(F);
p1 = B;
while (iscons(p1)) {
push(car(p1));
eval();
p1 = cdr(p1);
}
list(tos - h);
return;
}
// Create the argument substitution list S
p1 = A;
p2 = B;
h = tos;
while (iscons(p1) && iscons(p2)) {
push(car(p1));
push(car(p2));
eval();
p1 = cdr(p1);
p2 = cdr(p2);
}
list(tos - h);
S = pop();
// Evaluate the function body
push(F);
if (iscons(S)) {
push(S);
rewrite_args();
}
eval();
}
// Rewrite by expanding symbols that contain args
int
rewrite_args(void)
{
int h, n = 0;
save();
p2 = pop(); // subst. list
p1 = pop(); // expr
if (istensor(p1)) {
n = rewrite_args_tensor();
restore();
return n;
}
if (iscons(p1)) {
h = tos;
push(car(p1)); // Do not rewrite function name
p1 = cdr(p1);
while (iscons(p1)) {
push(car(p1));
push(p2);
n += rewrite_args();
p1 = cdr(p1);
}
list(tos - h);
restore();
return n;
}
// If not a symbol then done
if (!issymbol(p1)) {
push(p1);
restore();
return 0;
}
// Try for an argument substitution first
p3 = p2;
while (iscons(p3)) {
if (p1 == car(p3)) {
push(cadr(p3));
restore();
return 1;
}
p3 = cddr(p3);
}
// Get the symbol's binding, try again
p3 = get_binding(p1);
push(p3);
if (p1 != p3) {
push(p2); // subst. list
n = rewrite_args();
if (n == 0) {
pop();
push(p1); // restore if not rewritten with arg
}
}
restore();
return n;
}
int
rewrite_args_tensor(void)
{
int i, n = 0;
push(p1);
copy_tensor();
p1 = pop();
for (i = 0; i < p1->u.tensor->nelem; i++) {
push(p1->u.tensor->elem[i]);
push(p2);
n += rewrite_args();
p1->u.tensor->elem[i] = pop();
}
push(p1);
return n;
}