12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331 |
- /* eval2.c Copyright (C) 1989-96 Codemist Ltd */
- /*
- * Interpreter (part 2). apply & some special forms
- */
- /* Signature: 589bce9e 17-Jan-1999 */
- #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 */
|