1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345 |
- /* eval2.c Copyright (C) 1989-2002 Codemist Ltd */
- /*
- * Interpreter (part 2). apply & some special forms
- */
- /*
- * This code may be used and modified, and redistributed in binary
- * or source form, subject to the "CCL Public License", which should
- * accompany it. This license is a variant on the BSD license, and thus
- * permits use of code derived from this in either open and commercial
- * projects: but it does require that updates to this code be made
- * available back to the originators of the package.
- * Before merging other code in with this or linking this code
- * with other packages or libraries please check that the license terms
- * of the other material are compatible with those of this.
- */
- /* Signature: 274a0849 08-Apr-2002 */
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
- #include "machine.h"
- #include "tags.h"
- #include "cslerror.h"
- #include "externs.h"
- #include "entries.h"
- #ifdef TIMEOUT
- #include "timeout.h"
- #endif
- static Lisp_Object apply_lots(int nargs, n_args *f, Lisp_Object def)
- /*
- * Cases with 8 or more args are lifted out here into a subroutine
- * to make APPLY a bit shorter and because these cases should be
- * uncommon & not worth optimising much. The code that Microsoft C 6.00A
- * produced for this was utterly DREADFUL - maybe other C compilers will
- * make a mess of it too. Anyway I hope it will not be called very often.
- */
- {
- switch(nargs)
- {
- case 9:
- return (*f)(def, 9, stack[-9], stack[-8], stack[-7],
- stack[-6], stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- case 10:
- return (*f)(def, 10, stack[-10], stack[-9], stack[-8],
- stack[-7], stack[-6], stack[-5], stack[-4],
- stack[-3], stack[-2], stack[-1]);
- case 11:
- return (*f)(def, 11, stack[-11], stack[-10],
- stack[-9], stack[-8], stack[-7], stack[-6],
- stack[-5], stack[-4], stack[-3], stack[-2],
- stack[-1]);
- case 12:
- return (*f)(def, 12, stack[-12], stack[-11],
- stack[-10], stack[-9], stack[-8], stack[-7],
- stack[-6], stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- case 13:
- return (*f)(def, 13, stack[-13], stack[-12],
- stack[-11], stack[-10], stack[-9], stack[-8],
- stack[-7], stack[-6], stack[-5], stack[-4],
- stack[-3], stack[-2], stack[-1]);
- case 14:
- return (*f)(def, 14, stack[-14], stack[-13],
- stack[-12], stack[-11], stack[-10], stack[-9],
- stack[-8], stack[-7], stack[-6], stack[-5],
- stack[-4], stack[-3], stack[-2], stack[-1]);
- case 15:
- return (*f)(def, 15, stack[-15], stack[-14],
- stack[-13], stack[-12], stack[-11], stack[-10],
- stack[-9], stack[-8], stack[-7], stack[-6],
- stack[-5], stack[-4], stack[-3], stack[-2],
- stack[-1]);
- case 16:
- return (*f)(def, 16, stack[-16], stack[-15],
- stack[-14], stack[-13], stack[-12], stack[-11],
- stack[-10], stack[-9], stack[-8], stack[-7],
- stack[-6], stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- case 17:
- return (*f)(def, 17, stack[-17], stack[-16],
- stack[-15], stack[-14], stack[-13], stack[-12],
- stack[-11], stack[-10], stack[-9], stack[-8],
- stack[-7], stack[-6], stack[-5], stack[-4],
- stack[-3], stack[-2], stack[-1]);
- case 18:
- return (*f)(def, 18, stack[-18], stack[-17],
- stack[-16], stack[-15], stack[-14], stack[-13],
- stack[-12], stack[-11], stack[-10], stack[-9],
- stack[-8], stack[-7], stack[-6], stack[-5],
- stack[-4], stack[-3], stack[-2], stack[-1]);
- case 19:
- return (*f)(def, 19, stack[-19], stack[-18],
- stack[-17], stack[-16], stack[-15], stack[-14],
- stack[-13], stack[-12], stack[-11], stack[-10],
- stack[-9], stack[-8], stack[-7], stack[-6],
- stack[-5], stack[-4], stack[-3], stack[-2],
- stack[-1]);
- case 20:
- return (*f)(def, 20, stack[-20], stack[-19],
- stack[-18], stack[-17], stack[-16], stack[-15],
- stack[-14], stack[-13], stack[-12], stack[-11],
- stack[-10], stack[-9], stack[-8], stack[-7],
- stack[-6], stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- case 21:
- return (*f)(def, 21, stack[-21], stack[-20],
- stack[-19], stack[-18], stack[-17], stack[-16],
- stack[-15], stack[-14], stack[-13], stack[-12],
- stack[-11], stack[-10], stack[-9], stack[-8],
- stack[-7], stack[-6], stack[-5], stack[-4],
- stack[-3], stack[-2], stack[-1]);
- case 22:
- return (*f)(def, 22, stack[-22], stack[-21],
- stack[-20], stack[-19], stack[-18], stack[-17],
- stack[-16], stack[-15], stack[-14], stack[-13],
- stack[-12], stack[-11], stack[-10], stack[-9],
- stack[-8], stack[-7], stack[-6], stack[-5],
- stack[-4], stack[-3], stack[-2], stack[-1]);
- case 23:
- return (*f)(def, 23, stack[-23], stack[-22],
- stack[-21], stack[-20], stack[-19], stack[-18],
- stack[-17], stack[-16], stack[-15], stack[-14],
- stack[-13], stack[-12], stack[-11], stack[-10],
- stack[-9], stack[-8], stack[-7], stack[-6],
- stack[-5], stack[-4], stack[-3], stack[-2],
- stack[-1]);
- case 24:
- return (*f)(def, 24, stack[-24], stack[-23],
- stack[-22], stack[-21], stack[-20], stack[-19],
- stack[-18], stack[-17], stack[-16], stack[-15],
- stack[-14], stack[-13], stack[-12], stack[-11],
- stack[-10], stack[-9], stack[-8], stack[-7],
- stack[-6], stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- case 25:
- return (*f)(def, 25, stack[-25], stack[-24], stack[-23],
- stack[-22], stack[-21], stack[-20], stack[-19],
- stack[-18], stack[-17], stack[-16], stack[-15],
- stack[-14], stack[-13], stack[-12], stack[-11],
- stack[-10], stack[-9], stack[-8], stack[-7],
- stack[-6], stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- default:
- /*
- * If more than 25 args are going to be passed I will arrange that the
- * final ones are built into a list - as if the 25th arg was specified
- * as a "&rest" one. Why? Because passing VERY large numbers of arguments
- * in C is not a good idea - ANSI C compilers are only obliged to support
- * up to 31 args, and one some machines this limit seems to really matter.
- * But Common Lisp can need more args than that. I will ignore the fact that
- * what I do here is slow. I will HOPE that calls with 25 or more args
- * are very uncommon.
- */
- { int n = nargs;
- Lisp_Object w, *tsp = stack, nil = C_nil;
- #if (ARG_CUT_OFF != 25)
- if (ARG_CUT_OFF != 25)
- { fprintf(stderr, "\n+++ ARG_CUT_OFF incorrectly configured\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- w = ncons(tsp[-1]);
- errexit();
- tsp[-1] = w;
- while (n > ARG_CUT_OFF)
- { w = cons(tsp[-2], tsp[-1]);
- errexit();
- tsp[-2] = w;
- tsp[-1] = tsp[0];
- tsp--;
- n--;
- }
- return (*f)(def, nargs, tsp[-25], tsp[-24], tsp[-23],
- tsp[-22], tsp[-21], tsp[-20], tsp[-19],
- tsp[-18], tsp[-17], tsp[-16], tsp[-15],
- tsp[-14], tsp[-13], tsp[-12], tsp[-11],
- tsp[-10], tsp[-9], tsp[-8], tsp[-7],
- tsp[-6], tsp[-5], tsp[-4], tsp[-3],
- tsp[-2], tsp[-1]);
- }
- }
- }
- void push_args(va_list a, int nargs)
- /*
- * The unpacking here must match "apply_lots" as above. For up to
- * (and including) ARG_CUT_OFF (=25) args things are passed normally.
- * beyond that the first ARG_CUT_OFF-1 args are passed normally, and the
- * rest are in a list as a final actual arg. Note that this list will
- * have at least two elements.
- */
- {
- int i;
- if (nargs <= ARG_CUT_OFF)
- { for (i = 0; i<nargs; i++)
- { Lisp_Object w = va_arg(a, Lisp_Object);
- push(w);
- }
- }
- else
- { Lisp_Object x;
- for (i = 0; i<(ARG_CUT_OFF-1); i++)
- { Lisp_Object w = va_arg(a, Lisp_Object);
- push(w);
- }
- x = va_arg(a, Lisp_Object);
- /*
- * Internal consistency should ensure that the list passed here is long
- * enough for the following unpacking operation. But if (as a result of
- * internal system muddles it is not maybe the fact that qcar(nil) =
- * qcdr(nil) = nil will tend to reduce the damage?
- */
- for (; i<nargs; i++)
- { push(qcar(x));
- x = qcdr(x);
- }
- }
- va_end(a);
- }
- void push_args_1(va_list a, int nargs)
- /*
- * This is very much like push_args(), but is for the (rather small number
- * of) cases where the first argument to a function must NOT be pushed on the
- * stack. See, for instance, "funcall" as an example.
- */
- {
- int i;
- if (nargs <= ARG_CUT_OFF)
- { for (i = 1; i<nargs; i++)
- { Lisp_Object w = va_arg(a, Lisp_Object);
- push(w);
- }
- }
- else
- { Lisp_Object x;
- for (i = 1; i<(ARG_CUT_OFF-1); i++)
- { Lisp_Object w = va_arg(a, Lisp_Object);
- push(w);
- }
- x = va_arg(a, Lisp_Object);
- for (; i<nargs; i++)
- { push(qcar(x));
- x = qcdr(x);
- }
- }
- va_end(a);
- }
- Lisp_Object apply(Lisp_Object fn, int nargs, Lisp_Object env, Lisp_Object name)
- /*
- * There are (nargs) arguments on the Lisp stack, and apply() must use them
- * then pop them off. They were pushed in the order push(arg1); push(arg2),
- * and so on, and the stack grows upwards.
- * If I return with an error I will hand back the value name rather than the
- * junk value normally used in such cases.
- */
- {
- Lisp_Object def, nil = C_nil;
- for (;;)
- { if (symbolp(fn))
- {
- def = qenv(fn); /* this is passed as arg1 to the called code */
- /*
- * apply_lambda() will find arguments on the stack and is responsible for
- * popping them before it exits.
- */
- {
- /*
- * Because there are nargs values pushed on the (upwards growing) stack,
- * &stack[1-nargs] points at the first value pushed, i.e. arg-1. At one stage
- * I had a machine-specific bit of code (called "ncall") to do the following,
- * arguing that maybe in assembly code it would be possible to do much better
- * than the really ugly switch statement shown now. My belief now (especially
- * given that ncall was used in just one place - here) is that the switch will
- * cost no more than the procedure call did, and that in-line code will help
- * speed up the common and critical cases of 0, 1, 2 and 3 args. Also apply
- * is otherwise a reasonably short function, so if this switch is needed
- * anywhere here is not too bad.
- */
- push(name);
- switch (nargs)
- {
- /*
- * The Standard Lisp Report (Marti et al, Utah UUCS-78-101) only
- * requires support for 15 args. Common Lisp requires at least 50.
- * I deal with up to 8 args in-line here (I expect more than that to be
- * amazingly uncommon) so that this function is kept under contol.
- * Calls with more than 8 args go over to apply_lots, and within that
- * function calls with over 25 args have an even more clumsy treatment.
- */
- case 0:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 0);
- break;
- case 1:
- #ifdef DEBUG
- if (qfn1(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfn1(fn))(def, stack[-1]);
- break;
- case 2:
- #ifdef DEBUG
- if (qfn2(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfn2(fn))(def, stack[-2], stack[-1]);
- break;
- case 3:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 3, stack[-3], stack[-2], stack[-1]);
- break;
- case 4:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 4, stack[-4], stack[-3], stack[-2],
- stack[-1]);
- break;
- case 5:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 5, stack[-5], stack[-4], stack[-3],
- stack[-2], stack[-1]);
- break;
- case 6:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 6, stack[-6], stack[-5], stack[-4],
- stack[-3], stack[-2], stack[-1]);
- break;
- case 7:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 7, stack[-7], stack[-6], stack[-5],
- stack[-4], stack[-3], stack[-2], stack[-1]);
- break;
- case 8:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = (*qfnn(fn))(def, 8, stack[-8], stack[-7], stack[-6],
- stack[-5], stack[-4], stack[-3], stack[-2],
- stack[-1]);
- break;
- default:
- #ifdef DEBUG
- if (qfnn(fn) == NULL)
- { term_printf("Illegal APPLY\n");
- my_exit(EXIT_FAILURE);
- }
- #endif
- def = apply_lots(nargs, qfnn(fn), def);
- break;
- }
- /*
- * here I have to pop the stack by hand - note that popv does not
- * corrupt exit_count, which tells me how many results were being handed
- * back.
- */
- pop(name);
- popv(nargs);
- nil = C_nil;
- if (exception_pending()) return name;
- else return def;
- }
- }
- else if (!is_cons(fn))
- { popv(nargs);
- push(name);
- error(1, err_bad_fn, fn);
- pop(name);
- return name;
- }
- /* apply_lambda() will pop the args from the stack when it is done */
- if ((def = qcar(fn)) == lambda)
- return apply_lambda(qcdr(fn), nargs, env, name);
- /*
- * A bytecoded funarg is stored as (cfunarg <actual fn> <env>) and any call
- * to it behaves as if the actual function was called with the environment
- * passed as a forced-in first argument.
- */
- else if (def == cfunarg)
- { int i;
- push(nil);
- def = qcdr(fn);
- fn = qcar(def);
- for (i=0; i<nargs; i++) stack[-i] = stack[-i-1];
- stack[-nargs] = qcdr(def);
- nargs++;
- continue;
- }
- else if (def == funarg)
- { def = qcdr(fn);
- if (consp(def))
- return apply_lambda(qcdr(def), nargs, qcar(def), name);
- }
- break;
- }
- /*
- * Other cases are all errors.
- */
- popv(nargs);
- push(name);
- error(1, err_bad_apply, fn);
- pop(name);
- return name;
- }
- /*
- * Now for implementation of all the special forms...
- */
- static Lisp_Object and_fn(Lisp_Object args, Lisp_Object env)
- /* also needs to be a macro for Common Lisp */
- {
- Lisp_Object nil = C_nil;
- stackcheck2(0, args, env);
- if (!consp(args)) return onevalue(lisp_true);
- for (;;)
- { Lisp_Object v = qcar(args);
- args = qcdr(args);
- if (!consp(args)) return eval(v, env);
- push2(args, env);
- v = eval(v, env);
- pop2(env, args);
- errexit();
- if (v == nil) return onevalue(nil);
- }
- }
- /*
- * This is not used at present, but may be wanted sometime so I will
- * leave it here for now...
- *
- Lisp_Object append(Lisp_Object a, Lisp_Object b)
- {
- Lisp_Object nil = C_nil;
- if (!consp(a)) return b;
- else
- { stackcheck2(0, a, b);
- push(a);
- b = append(qcdr(a), b);
- pop(a);
- errexit();
- return cons(qcar(a), b);
- }
- }
- */
- static Lisp_Object block_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object p, nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- stackcheck2(0, args, env);
- push3(qcar(args), /* my_tag */
- qcdr(args), /* args */
- env);
- #define env stack[0]
- #define args stack[-1]
- #define my_tag stack[-2]
- /*
- * I need to augment the (lexical) environment with the name of my
- * tag in such a way that return-from can throw out to exactly the
- * correct matching level. This is done by pushing (0 . tag) onto
- * the environment - the 0 marks this as a block name.
- */
- my_tag = cons(fixnum_of_int(0), my_tag);
- errexitn(3);
- env = cons(my_tag, env);
- errexitn(3);
- p = nil;
- while (consp(args))
- { p = qcar(args);
- p = eval(p, env);
- /*
- * one of the sorts of exit that may be activated by marking nil is
- * a return_from. Here I need to check to see if that is what
- * is going on.
- */
- nil = C_nil;
- if (exception_pending())
- { flip_exception(); /* Temp restore it */
- qcar(my_tag) = fixnum_of_int(2); /* Invalidate */
- if (exit_reason == UNWIND_RETURN && exit_tag == my_tag)
- { exit_reason = UNWIND_NULL; /* not strictly needed - but tidy */
- popv(3);
- return nvalues(exit_value, exit_count);
- }
- if ((exit_reason & UNWIND_ERROR) != 0)
- { err_printf("\nEvaluating: ");
- loop_print_error(qcar(args));
- ignore_exception();
- }
- flip_exception(); /* re-instate exit condition */
- popv(3);
- return nil;
- }
- args = qcdr(args);
- }
- popv(3);
- return p;
- #undef env
- #undef args
- #undef my_tag
- }
- static Lisp_Object catch_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object tag, nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- stackcheck2(0, args, env);
- push2(args, env);
- tag = qcar(args);
- tag = eval(tag, env);
- errexit();
- tag = catch_tags = cons(tag, catch_tags);
- pop2(env, args);
- errexit();
- push(tag);
- {
- Lisp_Object v = progn_fn(qcdr(args), env);
- pop(tag);
- nil = C_nil;
- if (exception_pending())
- { flip_exception();
- catch_tags = qcdr(tag);
- qcar(tag) = tag;
- qcdr(tag) = nil; /* Invalidate the catch frame */
- if (exit_reason == UNWIND_THROW && exit_tag == tag)
- { exit_reason = UNWIND_NULL;
- return nvalues(exit_value, exit_count);
- }
- flip_exception();
- return nil;
- }
- catch_tags = qcdr(tag);
- qcar(tag) = tag;
- qcdr(tag) = nil; /* Invalidate the catch frame */
- return v;
- }
- }
- #define BODY_LET 0
- #define BODY_COMPILER_LET 1
- #define BODY_PROG 2
- Lisp_Object let_fn_1(Lisp_Object bvl, Lisp_Object body,
- Lisp_Object env, int compilerp)
- /*
- * This will have to look for (declare (special ...)).
- * compiler-let forces all of its bindings to be locally special. In
- * CSL mode I do not support local declarations, which simplifies and
- * speeds things up here.
- */
- {
- Lisp_Object nil = C_nil;
- stackcheck3(0, bvl, body, env);
- push3(bvl, body, env);
- nil = C_nil;
- push5(nil, nil, env, nil, nil);
- #ifdef COMMON
- /*
- * I lose the name (for security) but leave the junk stack location
- * (because doing otherwise seems unduly complicated.
- */
- #define local_decs stack[0]
- #endif
- #define specenv stack[-1]
- #define env1 stack[-2]
- #define p stack[-3]
- #define q stack[-4]
- #define env stack[-5]
- #define body stack[-6]
- #define bvl stack[-7]
- #define Return(v) { popv(8); return (v); }
- #ifdef COMMON
- /*
- * Find local declarations - it is necessary to macro-expand
- * items in the body to see if they turn into declarations.
- */
- for (;;)
- { if (exception_pending() || !consp(body)) break;
- p = macroexpand(qcar(body), env);
- errexitn(8);
- body = qcdr(body);
- if (!consp(p))
- { if (stringp(p) && consp(body)) continue;
- body = cons(p, body);
- nil = C_nil;
- break;
- }
- if (qcar(p) != declare_symbol)
- { body = cons(p, body);
- nil = C_nil;
- break;
- }
- for (p = qcdr(p); consp(p); p = qcdr(p))
- { q = qcar(p);
- if (!consp(q) || qcar(q) != special_symbol) continue;
- /* here q says (special ...) */
- for (q=qcdr(q); consp(q); q = qcdr(q))
- { local_decs = cons(qcar(q), local_decs);
- nil = C_nil;
- if (exception_pending()) break;
- }
- if (exception_pending()) break;
- }
- }
- if (exception_pending()) Return(nil);
- #endif
- for (; consp(bvl); bvl=qcdr(bvl))
- { Lisp_Object z;
- q = qcar(bvl);
- if (consp(q))
- { z = qcdr(q);
- q = qcar(q);
- if (consp(z)) z = qcar(z); else z = nil;
- }
- else z = nil;
- if (!is_symbol(q))
- { Lisp_Object qq = q;
- Return(error(1, err_bad_bvl, qq));
- }
- else
- {
- #ifdef COMMON
- Header h = qheader(q);
- #endif
- if (z != nil)
- { z = eval(z, env);
- errexitn(8);
- }
- z = cons(q, z);
- errexitn(8);
- #ifdef COMMON
- if (compilerp == BODY_COMPILER_LET)
- { specenv = cons(z, specenv);
- errexitn(8);
- q = acons(q, work_symbol, env1);
- errexitn(8);
- env1 = q; /* Locally special */
- }
- else
- #endif
- #ifndef COMMON
- specenv = cons(z, specenv);
- #else
- if (h & SYM_SPECIAL_VAR) specenv = cons(z, specenv);
- else
- {
- Lisp_Object w;
- for (w = local_decs; w!=nil; w = qcdr(w))
- { if (q != qcar(w)) continue;
- qcar(w) = fixnum_of_int(0);
- /* The next few calls to cons() maybe lose w, but that is OK! */
- specenv = cons(z, specenv);
- errexitn(8);
- q = acons(q, work_symbol, env1);
- errexitn(8);
- env1 = q;
- goto bound;
- }
- env1 = cons(z, env1);
- bound: ;
- }
- #endif
- errexitn(8);
- }
- }
- #ifdef COMMON
- while (local_decs!=nil) /* Pervasive special declarations */
- { Lisp_Object q1 = qcar(local_decs);
- local_decs=qcdr(local_decs);
- if (!is_symbol(q1)) continue;
- q1 = acons(q1, work_symbol, env1);
- errexitn(8);
- env1 = q1;
- }
- #endif
- if (specenv == nil)
- { Lisp_Object bodyx = body, env1x = env1;
- /*
- * See expansion of Return() for an explanation of why body and env1 have
- * been moved into new local variables before the call..
- */
- if (compilerp == BODY_PROG)
- { Return(tagbody_fn(bodyx, env1x));
- }
- else
- { Return(progn_fn(bodyx, env1x));
- }
- }
- /*
- * I instate the special bindings after all values to bind have been collected
- */
- for (p = specenv; p != nil; p = qcdr(p))
- { Lisp_Object w = qcar(p), v = qcar(w), z = qcdr(w);
- Lisp_Object old = qvalue(v);
- qvalue(v) = z;
- qcdr(w) = old;
- }
- {
- if (compilerp == BODY_PROG)
- body = tagbody_fn(body, env1);
- else body = progn_fn(body, env1);
- nil = C_nil;
- if (exception_pending())
- { flip_exception();
- for (p = specenv; p != nil; p = qcdr(p))
- { Lisp_Object w = qcar(p), v = qcar(w), z = qcdr(w);
- qvalue(v) = z;
- }
- flip_exception();
- Return(nil);
- }
- else
- { for (p = specenv; p != nil; p = qcdr(p))
- { Lisp_Object w = qcar(p), v = qcar(w), z = qcdr(w);
- qvalue(v) = z;
- }
- { Lisp_Object bodyx = body;
- Return(bodyx);
- }
- }
- }
- #ifdef COMMON
- #undef local_decs
- #endif
- #undef specenv
- #undef env1
- #undef p
- #undef q
- #undef env
- #undef body
- #undef bvl
- #undef Return
- }
- #ifdef COMMON
- static Lisp_Object compiler_let_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- return let_fn_1(qcar(args), qcdr(args), env, BODY_COMPILER_LET);
- }
- #endif
- static Lisp_Object cond_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object nil = C_nil;
- stackcheck2(0, args, env);
- while (consp(args))
- {
- Lisp_Object p = qcar(args);
- if (consp(p))
- { Lisp_Object p1;
- push2(args, env);
- p1 = qcar(p);
- p1 = eval(p1, env);
- pop2(env, args);
- errexit();
- if (p1 != nil)
- { args = qcdr(qcar(args));
- /* Here I support the case "(cond (predicate) ...)" with no consequents */
- if (!consp(args)) return onevalue(p1);
- else return progn_fn(args, env);
- }
- }
- args = qcdr(args);
- }
- return onevalue(nil);
- }
- #ifdef COMMON
- Lisp_Object declare_fn(Lisp_Object args, Lisp_Object env)
- /*
- * declarations can only properly occur at the heads of various
- * special forms, and so may NOT be evaluated in an ordinary manner.
- * Thus I am entitled (just about) to make this a no-op. It would
- * probably be better to arrange that (declare ...) never got evaluated
- * and then I could raise an error if this bit of code got activated.
- * Indeed (declare ...) probably does not ever get evaluated - still
- * a no-op here seems the safest bet.
- */
- {
- Lisp_Object nil = C_nil;
- CSL_IGNORE(env);
- CSL_IGNORE(args);
- return onevalue(nil);
- }
- #endif
- #define flagged_lose(v) \
- ((fv = qfastgets(v)) != nil && elt(fv, 1) != SPID_NOPROP)
- static Lisp_Object defun_fn(Lisp_Object args, Lisp_Object env)
- {
- /*
- * defun is eventually expected (required!) to be a macro rather than (maybe
- * as well as?) a special form. For bootstrap purposes it seems useful to
- * build it in as a special form. Also this special form is quite good enough
- * in CSL mode
- */
- Lisp_Object fname, nil = C_nil;
- CSL_IGNORE(env);
- if (consp(args))
- { fname = qcar(args);
- args = qcdr(args);
- if (is_symbol(fname))
- { Lisp_Object fv;
- if (qheader(fname) & SYM_SPECIAL_FORM)
- return error(1, err_redef_special, fname);
- if ((qheader(fname) & (SYM_C_DEF | SYM_CODEPTR)) ==
- (SYM_C_DEF | SYM_CODEPTR)) return onevalue(fname);
- if (flagged_lose(fname))
- { debug_printf("\n+++ ");
- loop_print_debug(fname);
- debug_printf(" not defined because of LOSE flag\n");
- return onevalue(nil);
- }
- qheader(fname) = qheader(fname) & ~SYM_MACRO;
- if ((qheader(fname) & SYM_C_DEF) != 0) lose_C_def(fname);
- if (qfn1(fname) != undefined1)
- { if (qvalue(redef_msg) != nil)
- { debug_printf("\n+++ ");
- loop_print_debug(fname);
- debug_printf(" redefined\n");
- }
- errexit();
- set_fns(fname, undefined1, undefined2, undefinedn);
- qenv(fname) = fname;
- }
- /*
- * qfn() can contain 'interpreted' for a function defined wrt the null
- * environment, or 'funarged' for one with an environment - in the latter
- * case the definition (in qenv()) is a pair (<def> . <env>)
- */
- qenv(fname) = args; /* Sort of notional lambda present */
- set_fns(fname, interpreted1, interpreted2, interpretedn);
- if (qvalue(comp_symbol) != nil &&
- qfn1(compiler_symbol) != undefined1)
- { push(fname);
- args = ncons(fname);
- nil = C_nil;
- if (!exception_pending())
- (qfn1(compiler_symbol))(qenv(compiler_symbol), args);
- pop(fname);
- }
- return onevalue(fname);
- }
- }
- return aerror("defun");
- }
- static Lisp_Object defmacro_fn(Lisp_Object args, Lisp_Object env)
- {
- /*
- * defmacro is eventually expected (required!) to be a macro rather than (maybe
- * as well as?) a special form. For bootstrap purposes it seems useful to
- * build it in as a special form.
- */
- Lisp_Object fname, nil = C_nil;
- CSL_IGNORE(env);
- if (consp(args))
- { fname = qcar(args);
- args = qcdr(args);
- if (is_symbol(fname))
- {
- if ((qheader(fname) & (SYM_C_DEF | SYM_CODEPTR)) ==
- (SYM_C_DEF | SYM_CODEPTR)) return onevalue(fname);
- qheader(fname) |= SYM_MACRO;
- /*
- * Note that a name can have a definition as a macro and as a special form,
- * and in that case the qfn() cell gives the special form and the qenv()
- * cell the macro definition. Otherwise at present I put 'undefined'
- * in the qfn() cell, but in due course I will want something else as better
- * protection against compiled code improperly attempting to call a macro.
- * Note also that if the symbol was a special form before I do not want
- * to clear the C_DEF flag, since the special form must be re-instated when
- * I reload the system.
- */
- if ((qheader(fname) & SYM_SPECIAL_FORM) == 0)
- { qheader(fname) &= ~SYM_C_DEF;
- if (qfn1(fname) != undefined1 &&
- qvalue(redef_msg) != nil)
- { debug_printf("\n+++ ");
- loop_print_debug(fname);
- debug_printf(" redefined as a macro\n");
- errexit();
- }
- set_fns(fname, undefined1, undefined2, undefinedn);
- }
- qenv(fname) = args; /* Sort of notional lambda present */
- if (qvalue(comp_symbol) != nil &&
- qfn1(compiler_symbol) != undefined1)
- { Lisp_Object t1, t2;
- push(fname);
- if (!(consp(args) &&
- consp(qcdr(args)) &&
- qcdr(qcdr(args)) == nil &&
- (t1 = qcar(args),
- t2 = qcdr(qcar(qcdr(args))),
- equal(t1, t2))))
- { errexitn(1);
- fname = stack[0];
- args = ncons(fname);
- nil = C_nil;
- if (!exception_pending())
- (qfn1(compiler_symbol))(qenv(compiler_symbol), args);
- }
- pop(fname);
- errexit();
- }
- return onevalue(fname);
- }
- }
- return aerror("defmacro");
- }
- static Lisp_Object eval_when_fn(Lisp_Object args, Lisp_Object env)
- /*
- * When interpreted, eval-when just looks for the situation EVAL.
- */
- {
- Lisp_Object situations, nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- situations = qcar(args);
- args = qcdr(args);
- while (consp(situations))
- { if (qcar(situations) == eval_symbol) return progn_fn(args, env);
- situations = qcdr(situations);
- }
- return onevalue(nil);
- }
- #ifdef COMMON
- static Lisp_Object flet_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object my_env, d, nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- stackcheck2(0, args, env);
- my_env = env;
- d = qcar(args); /* The bunch of definitions */
- args = qcdr(args);
- nil = C_nil;
- while (consp(d))
- { Lisp_Object w = qcar(d);
- if (consp(w) && consp(qcdr(w)))
- { Lisp_Object w1;
- push4(args, d, env, w);
- w1 = list2star(funarg, my_env, qcdr(w));
- pop(w);
- nil = C_nil;
- if (!exception_pending()) w1 = cons(w1, qcar(w));
- pop(env);
- nil = C_nil;
- if (!exception_pending()) env = cons(w1, env);
- pop2(d, args);
- errexit();
- }
- d = qcdr(d);
- }
- /*
- * Treat body as (let nil ...) to get (declare ...) recognized.
- */
- return let_fn_1(nil, args, env, BODY_LET);
- }
- #endif
- Lisp_Object function_fn(Lisp_Object args, Lisp_Object env)
- {
- /*
- * For most things this behaves just like (quote xxx), but
- * (function (lambda (x) y)) gets converted to
- * (funarg env (x) y).
- */
- Lisp_Object nil = C_nil;
- if (consp(args) && qcdr(args) == nil)
- { args = qcar(args);
- if (consp(args) && qcar(args) == lambda)
- args = list2star(funarg, env, qcdr(args));
- return onevalue(args);
- }
- return aerror("function");
- }
- static Lisp_Object go_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object p, tag, nil = C_nil;
- CSL_IGNORE(env);
- if (!consp(args)) return aerror("go");
- else tag = qcar(args);
- for(p=env; consp(p); p=qcdr(p))
- { Lisp_Object w = qcar(p), z;
- if (!consp(w)) continue;
- if (qcar(w) == fixnum_of_int(1) &&
- (z = qcar(qcdr(w)), eql(z, tag)))
- { p = w;
- goto tag_found;
- }
- }
- return error(1, err_go_tag, tag);
- tag_found:
- exit_tag = p;
- exit_count = 0;
- exit_reason = UNWIND_GO;
- flip_exception(); /* Exceptional exit active */
- return nil;
- }
- static Lisp_Object if_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object nil = C_nil;
- Lisp_Object p=nil, tr=nil, fs=nil;
- if (!consp(args)) return aerror("if");
- p = qcar(args);
- args = qcdr(args);
- if (!consp(args)) return aerror("if");
- tr = qcar(args);
- args = qcdr(args);
- if (!consp(args)) fs = nil;
- else
- { fs = qcar(args);
- args = qcdr(args);
- if (args != nil) return aerror("if");
- }
- stackcheck4(0, p, env, tr, fs);
- push3(fs, tr, env);
- p = eval(p, env);
- pop3(env, tr, fs);
- errexit();
- if (p == nil)
- return eval(fs, env); /* tail call on result */
- else return eval(tr, env); /* ... passing back values */
- }
- #ifdef COMMON
- static Lisp_Object labels_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object my_env, d, nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- stackcheck2(0, args, env);
- my_env = env;
- d = qcar(args); /* The bunch of definitions */
- while (consp(d))
- { Lisp_Object w = qcar(d);
- if (consp(w) && consp(qcdr(w)))
- { Lisp_Object w1;
- push4(args, d, env, w);
- w1 = list2star(funarg, nil, qcdr(w));
- pop(w);
- nil = C_nil;
- if (!exception_pending()) w1 = cons(w1, qcar(w));
- pop(env);
- nil = C_nil;
- if (!exception_pending()) env = cons(w1, env);
- pop2(d, args);
- errexit();
- }
- d = qcdr(d);
- }
- /*
- * Now patch up the environments stored with the local defs so as to
- * permit mutual recursion between them all.
- */
- for (d=env; d!=my_env; d=qcdr(d))
- qcar(qcdr(qcar(qcar(d)))) = env;
- return let_fn_1(nil, qcdr(args), env, BODY_LET);
- }
- #endif
- static Lisp_Object let_fn(Lisp_Object args, Lisp_Object env)
- {
- Lisp_Object nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- return let_fn_1(qcar(args), qcdr(args), env, BODY_LET);
- }
- static Lisp_Object letstar_fn(Lisp_Object args, Lisp_Object env)
- /*
- * This will have to look for (declare (special ...)), unless
- * I am in CSL mode.
- */
- {
- Lisp_Object nil = C_nil;
- if (!consp(args)) return onevalue(nil);
- stackcheck2(0, args, env);
- push3(qcar(args), qcdr(args), env);
- nil = C_nil;
- push5(nil, nil, /* p, q */
- env, nil, nil); /* env1, specenv, local_decs */
- #ifdef COMMON
- #define local_decs stack[0]
- #endif
- #define specenv stack[-1]
- #define env1 stack[-2]
- #define p stack[-3]
- #define q stack[-4]
- #define env stack[-5]
- #define body stack[-6]
- #define bvl stack[-7]
- #define Return(v) { popv(8); return (v); }
- #ifdef COMMON
- for (;;)
- { if (exception_pending() || !consp(body)) break;
- p = macroexpand(qcar(body), env);
- errexitn(8);
- body = qcdr(body);
- if (!consp(p))
- { if (stringp(p) && consp(body)) continue;
- body = cons(p, body);
- nil = C_nil;
- break;
- }
- if (qcar(p) != declare_symbol)
- { body = cons(p, body);
- nil = C_nil;
- break;
- }
- for (p = qcdr(p); consp(p); p = qcdr(p))
- { q = qcar(p);
- if (!consp(q) || qcar(q) != special_symbol) continue;
- /* here q says (special ...) */
- for (q=qcdr(q); consp(q); q = qcdr(q))
- { local_decs = cons(qcar(q), local_decs);
- nil = C_nil;
- if (exception_pending()) break;
- }
- if (exception_pending()) break;
- }
- }
- if (exception_pending()) Return(nil);
- #endif
- for (; consp(bvl); bvl=qcdr(bvl))
- { Lisp_Object z;
- q = qcar(bvl);
- if (consp(q))
- { z = qcdr(q);
- q = qcar(q);
- if (consp(z)) z = qcar(z); else z = nil;
- }
- else z = nil;
- if (!is_symbol(q))
- { error(1, err_bad_bvl, q);
- goto unwind_special_bindings;
- }
- else
- {
- #ifdef COMMON
- Header h = qheader(q);
- #endif
- if (z != nil)
- { z = eval(z, env);
- nil = C_nil;
- if (exception_pending()) goto unwind_special_bindings;
- }
- #ifndef COMMON
- p = z;
- z = acons(q, qvalue(q), specenv);
- nil = C_nil;
- if (!exception_pending()) specenv = z;
- qvalue(q) = p;
- #else
- if (h & SYM_SPECIAL_VAR)
- {
- p = z;
- z = acons(q, qvalue(q), specenv);
- nil = C_nil;
- if (!exception_pending()) specenv = z;
- qvalue(q) = p;
- }
- else
- {
- for (p = local_decs; p!=nil; p = qcdr(p))
- { Lisp_Object w;
- if (q != qcar(p)) continue;
- qcar(p) = fixnum_of_int(0);
- w = acons(q, qvalue(q), specenv);
- nil = C_nil;
- if (exception_pending()) goto unwind_special_bindings;
- specenv = w;
- w = acons(q, work_symbol, env);
- nil = C_nil;
- if (exception_pending()) goto unwind_special_bindings;
- env = w;
- qvalue(q) = z;
- goto bound;
- }
- q = acons(q, z, env);
- nil = C_nil;
- if (exception_pending()) goto unwind_special_bindings;
- env = q;
- bound: ;
- }
- #endif
- nil = C_nil;
- if (exception_pending()) goto unwind_special_bindings;
- }
- }
- #ifdef COMMON
- while (local_decs!=nil) /* Pervasive special declarations */
- { q = qcar(local_decs);
- local_decs=qcdr(local_decs);
- if (!is_symbol(q)) continue;
- q = acons(q, work_symbol, env);
- nil = C_nil;
- if (!exception_pending()) env = q;
- else goto unwind_special_bindings;
- }
- #endif
- if (specenv == nil)
- { Lisp_Object bodyx = body, envx = env;
- Return(progn_fn(bodyx, envx)); /* beware Return macro! */
- }
- {
- body = progn_fn(body, env);
- nil = C_nil;
- if (exception_pending()) goto unwind_special_bindings;
- for (bvl = specenv; bvl != nil; bvl = qcdr(bvl))
- { Lisp_Object w = qcar(bvl), v = qcar(w), z = qcdr(w);
- qvalue(v) = z;
- }
- { Lisp_Object bodyx = body;
- Return(bodyx);
- }
- }
- unwind_special_bindings:
- flip_exception();
- for (bvl = specenv; bvl != nil; bvl = qcdr(bvl))
- { Lisp_Object w = qcar(bvl), v = qcar(w), z = qcdr(w);
- qvalue(v) = z;
- }
- flip_exception();
- popv(8);
- return nil;
- #ifdef COMMON
- #undef local_decs
- #endif
- #undef specenv
- #undef env1
- #undef p
- #undef q
- #undef env
- #undef body
- #undef bvl
- #undef Return
- }
- setup_type const eval2_setup[] =
- /*
- * A jolly curiosity - "function" and "declare" are ALSO set up in
- * restart.c (because handles are needed on the symbols). I leave
- * the redundant initialisation here too since I find it clearer that
- * way.
- */
- {
- {"and", and_fn, bad_special2, bad_specialn},
- {"catch", catch_fn, bad_special2, bad_specialn},
- {"cond", cond_fn, bad_special2, bad_specialn},
- /*
- * I am not over-enthusiastic about supporting eval-when in CSL, but
- * something of that sort seems needed by some bits of code that I have
- * come across...
- */
- {"eval-when", eval_when_fn, bad_special2, bad_specialn},
- {"function", function_fn, bad_special2, bad_specialn},
- {"go", go_fn, bad_special2, bad_specialn},
- {"if", if_fn, bad_special2, bad_specialn},
- {"let*", letstar_fn, bad_special2, bad_specialn},
- /* DE and DM are used as low level primitives in the Common Lisp bootstrap */
- {"de", defun_fn, bad_special2, bad_specialn},
- {"dm", defmacro_fn, bad_special2, bad_specialn},
- #ifdef COMMON
- {"block", block_fn, bad_special2, bad_specialn},
- {"compiler-let", compiler_let_fn, bad_special2, bad_specialn},
- {"declare", declare_fn, bad_special2, bad_specialn},
- {"flet", flet_fn, bad_special2, bad_specialn},
- {"labels", labels_fn, bad_special2, bad_specialn},
- {"let", let_fn, bad_special2, bad_specialn},
- #else
- {"~block", block_fn, bad_special2, bad_specialn},
- {"~let", let_fn, bad_special2, bad_specialn},
- #endif
- {NULL, 0, 0, 0}};
- /* end of eval2.c */
|