eigenmath/userfunc.cpp

279 lines
4.1 KiB
C++
Raw Permalink Normal View History

2008-05-19 03:23:04 +02:00
// Codes for handling user-defined functions
2004-03-03 21:24:06 +01:00
#include "stdafx.h"
#include "defs.h"
2008-05-19 03:23:04 +02:00
/* For f(x)=x^2 we have p1 pointing to the following data structure.
2008-05-19 03:41:00 +02:00
_______ _______ _______
p1----->|CONS |-->|CONS |-------------->|CONS |
|_______| |_______| |_______|
| | |
___v___ ___v___ _______ ___v___ _______ _______
|SETQ | |CONS |-->|CONS | |CONS |-->|CONS |-->|CONS |
|_______| |_______| |_______| |_______| |_______| |_______|
| | | | |
___v___ ___v___ ___v___ ___v___ ___v___
|SYM f | |SYM x | |POWER | |SYM x | |NUM 2 |
|_______| |_______| |_______| |_______| |_______|
2008-05-19 03:23:04 +02:00
(For brevity, cdrs pointing to nil are not shown.)
Hence
2006-10-06 20:28:26 +02:00
2008-05-19 03:23:04 +02:00
caadr(p1) == f
cdadr(p1) == (x)
caddr(p1) == (power x 2)
2006-10-06 20:28:26 +02:00
*/
2004-03-03 21:24:06 +01:00
2008-05-19 03:23:04 +02:00
#define NAME p3
#define ARGS p4
#define BODY p5
2004-03-03 21:24:06 +01:00
void
define_user_function(void)
{
2008-05-19 03:41:00 +02:00
int h;
2007-02-17 04:57:52 +01:00
2004-03-03 21:24:06 +01:00
NAME = caadr(p1);
ARGS = cdadr(p1);
BODY = caddr(p1);
2005-08-06 22:57:37 +02:00
if (!issymbol(NAME))
2008-05-18 20:28:56 +02:00
stop("function name?");
2004-03-03 21:24:06 +01:00
2008-05-18 20:03:22 +02:00
prep_args();
2007-06-29 00:34:34 +02:00
set_binding_and_arglist(NAME, BODY, ARGS);
2004-03-03 21:24:06 +01:00
2007-02-17 04:57:52 +01:00
// do eval, maybe
if (car(BODY) == symbol(EVAL)) {
// remove eval
2007-06-29 00:34:34 +02:00
set_binding_and_arglist(NAME, cadr(BODY), ARGS);
2007-02-17 04:57:52 +01:00
// evaluate the function definition using quoted symbols
2008-05-18 20:28:56 +02:00
h = tos;
2007-02-17 04:57:52 +01:00
push(NAME);
2008-05-19 03:23:04 +02:00
p2 = ARGS;
while (iscons(p2)) {
2007-02-17 04:57:52 +01:00
push_symbol(QUOTE);
2008-05-19 03:23:04 +02:00
push(car(p2));
2007-02-17 04:57:52 +01:00
list(2);
2008-05-19 03:23:04 +02:00
p2 = cdr(p2);
2007-02-17 04:57:52 +01:00
}
2008-05-18 20:28:56 +02:00
list(tos - h);
2007-02-17 04:57:52 +01:00
eval();
// new binding
2008-05-18 20:28:56 +02:00
BODY = pop();
prep_args();
set_binding_and_arglist(NAME, BODY, ARGS);
2007-02-17 04:57:52 +01:00
}
2006-10-06 20:28:26 +02:00
push(symbol(NIL)); // return value
}
2004-03-03 21:24:06 +01:00
2008-05-18 20:03:22 +02:00
// Change formal args to GETARG functions
void
prep_args(void)
{
int n = 0;
2008-05-19 03:23:04 +02:00
p2 = ARGS;
2008-05-18 20:03:22 +02:00
push(BODY);
2008-05-19 03:23:04 +02:00
while (iscons(p2)) {
push(car(p2));
2008-05-18 20:03:22 +02:00
push(symbol(GETARG));
push_integer(n++);
list(2);
subst();
2008-05-19 03:23:04 +02:00
p2 = cdr(p2);
2008-05-18 20:03:22 +02:00
}
BODY = pop();
}
/* For example, this is what p1 points to when the user function wants the 1st
argument...
_______ _______ _______
p1 ---->|CONS |------>|CONS |------>|NIL |
|_______| |_______| |_______|
| |
2008-05-19 03:41:00 +02:00
___v___ ___v___
2008-05-19 03:23:04 +02:00
|GETARG | |NUM 0 |
2008-05-18 20:03:22 +02:00
|_______| |_______|
*/
void
eval_getarg(void)
{
int i, n;
push(cadr(p1));
n = pop_integer();
p1 = args;
for (i = 0; i < n; i++)
2008-05-19 03:23:04 +02:00
p1 = cdr(p1); // ok for all n, cdr(nil) = nil, car(nil) = nil
2008-05-18 20:03:22 +02:00
push(car(p1));
}
2006-10-06 20:28:26 +02:00
/* Example: f(x,y)
2004-03-03 21:24:06 +01:00
2006-10-06 20:28:26 +02:00
p1 -> (f x y)
2004-03-03 21:24:06 +01:00
2006-10-06 20:28:26 +02:00
car(p1) -> f
*/
2004-03-03 21:24:06 +01:00
void
eval_user_function(void)
{
2008-05-18 20:03:22 +02:00
int h;
2004-03-03 21:24:06 +01:00
2008-05-18 20:03:22 +02:00
// Use "derivative" instead of "d" if no user function "d"
2007-05-09 01:43:47 +02:00
2008-05-18 20:03:22 +02:00
if (car(p1) == symbol(SYMBOL_D) && get_arglist(symbol(SYMBOL_D)) == symbol(NIL)) {
2007-05-09 01:43:47 +02:00
eval_derivative();
return;
}
2008-05-18 20:03:22 +02:00
// p2 is the body of the user function
2004-03-03 21:24:06 +01:00
2008-05-18 20:03:22 +02:00
p2 = get_binding(car(p1));
2007-03-21 01:49:40 +01:00
2008-05-18 20:03:22 +02:00
// make p3 the argument list
2007-03-21 01:49:40 +01:00
2008-05-18 20:03:22 +02:00
h = tos;
p3 = cdr(p1);
while (iscons(p3)) {
push(car(p3));
eval();
p3 = cdr(p3);
2007-03-21 01:49:40 +01:00
}
2008-05-18 20:03:22 +02:00
list(tos - h);
p3 = pop();
2007-03-21 01:49:40 +01:00
2008-05-18 20:03:22 +02:00
// undefined function?
2007-03-21 01:49:40 +01:00
2008-05-18 20:03:22 +02:00
if (p2 == car(p1)) {
push(p2);
push(p3);
cons();
return;
2004-03-03 21:24:06 +01:00
}
2008-05-18 20:03:22 +02:00
// eval function body in arg context
push(args);
args = p3;
push(p2);
2004-03-03 21:24:06 +01:00
eval();
2008-05-18 20:03:22 +02:00
swap();
args = pop();
2004-03-03 21:24:06 +01:00
}
2007-05-08 16:57:30 +02:00
#if SELFTEST
2004-03-03 21:24:06 +01:00
static char *s[] = {
2008-05-19 03:41:00 +02:00
// args of generic functions should be evaluated
2004-03-03 21:24:06 +01:00
"f(1+2,3*4)",
"f(3,12)",
2008-05-19 03:42:34 +02:00
// simple func def
2004-03-03 21:24:06 +01:00
"f(x)=x^2",
"",
"f",
"x^2",
2008-05-19 03:41:00 +02:00
// bindings should be restored
2004-03-03 21:24:06 +01:00
"x=123",
"",
"y=345",
"",
"f(x,y)=x^2+y^3",
"",
"f(2,3)",
"31",
"x",
"123",
"y",
"345",
2008-05-19 03:41:00 +02:00
// as above but this time with function bindings
2004-03-03 21:24:06 +01:00
"x(a)=sin(a)",
"",
"y(b)=cos(b)",
"",
"f(x,y)=x^2+y^3",
"",
"f(2,3)",
"31",
"x",
"sin(a)",
"y",
"cos(b)",
2007-02-17 04:57:52 +01:00
2008-05-19 03:41:00 +02:00
// eval func body
2007-02-17 04:57:52 +01:00
"x=quote(x)",
"",
"p(x)=7+4x",
"",
"w(x)=eval(integral(p(x)))",
"",
"w-2*x^2-7*x",
"0",
"w(5)-w(2)",
"63",
2008-05-18 22:06:07 +02:00
// Check that args are quoted in func defn
2007-02-17 04:57:52 +01:00
"x=7",
"",
2008-05-18 22:06:07 +02:00
"y=8",
"",
2007-02-17 04:57:52 +01:00
"p(x,y)=eval(x+y)",
"",
2008-05-18 22:06:07 +02:00
"x=quote(x)",
"",
"y=quote(y)",
"",
2007-02-17 04:57:52 +01:00
"p",
"x+y",
2004-03-03 21:24:06 +01:00
};
void
test_user_func(void)
{
test(__FILE__, s, sizeof s / sizeof (char *));
2004-06-09 04:45:50 +02:00
}
2007-05-08 16:57:30 +02:00
#endif