1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-03 17:19:43 +02:00
Leland Lucius 15b9bb96cd Update nyquist to SVN r331 (r3.16+)
------------------------------------------------------------------------
   r331 | rbd | 2020-10-13 12:40:12 -0500 (Tue, 13 Oct 2020) | 2 lines

   Also forgot to install NyquistWords.txt

   ------------------------------------------------------------------------
   r330 | rbd | 2020-10-13 12:34:06 -0500 (Tue, 13 Oct 2020) | 2 lines

   Forgot to move nyquistman.pdf from docsrc/s2h to release

   ------------------------------------------------------------------------
   r329 | rbd | 2020-10-13 11:32:33 -0500 (Tue, 13 Oct 2020) | 2 lines

   Updated some version numbers for 3.16.

   ------------------------------------------------------------------------
   r328 | rbd | 2020-10-13 11:20:52 -0500 (Tue, 13 Oct 2020) | 2 lines

   Fixed NyquistIDE antialiasing for plot text, fix format of message.

   ------------------------------------------------------------------------
   r327 | rbd | 2020-10-12 21:01:53 -0500 (Mon, 12 Oct 2020) | 2 lines

   Fixed a couple of format problems in manual. This version of Nyquist has been tested wtih macOS, Linux, 32&64-bit Windows.

   ------------------------------------------------------------------------
   r326 | rbd | 2020-10-12 20:21:38 -0500 (Mon, 12 Oct 2020) | 1 line

   Modified WIN32 32-bit XLisp to use 64-bit FIXNUMs. This allows XLisp and Nyquist to handle big sounds even on 32-bit machines. Probably at some cost, but inner loops are mostly float and int32, and the Nyquist release is 64-bit anyway. Maybe we'll have to run some benchmarks on Audacity, which is still 32-bit on Windows.
   ------------------------------------------------------------------------
   r325 | rbd | 2020-10-12 13:16:57 -0500 (Mon, 12 Oct 2020) | 1 line

   Win64 passes bigfiletest.lsp now. This version should work on all 64-bit systems now. These changes untested on Linux and macOS.
   ------------------------------------------------------------------------
   r324 | rbd | 2020-10-11 21:31:53 -0500 (Sun, 11 Oct 2020) | 2 lines

   I couldn't free enough space on my linux box, so I adjusted the bigfiletest to write 8-bit ulaw. It's still >4GB and >4G samples. Works on Linux.

   ------------------------------------------------------------------------
   r323 | rbd | 2020-10-11 19:41:25 -0500 (Sun, 11 Oct 2020) | 2 lines

   Missing file from last commit.

   ------------------------------------------------------------------------
   r322 | rbd | 2020-10-11 19:36:08 -0500 (Sun, 11 Oct 2020) | 1 line

   Found another case where WIN64 needs int64_t instead of long for sample count.
   ------------------------------------------------------------------------
   r321 | rbd | 2020-10-11 19:33:25 -0500 (Sun, 11 Oct 2020) | 3 lines

   Fixed s-save to	handle optional	and keyword parameters (which should never have	been mixed in the first	place).	Documentation cleanup - should be final for this version.

   ------------------------------------------------------------------------
   r320 | rbd | 2020-10-11 14:44:37 -0500 (Sun, 11 Oct 2020) | 2 lines

   Fixes to handle IRCAM sound format and tests for big file io working on macOS.

   ------------------------------------------------------------------------
   r319 | rbd | 2020-10-10 21:31:58 -0500 (Sat, 10 Oct 2020) | 2 lines

   Changes for linux and to avoid compiler warnings on linux.

   ------------------------------------------------------------------------
   r318 | rbd | 2020-10-10 20:50:23 -0500 (Sat, 10 Oct 2020) | 1 line

   This is the test used for Win64 version.
   ------------------------------------------------------------------------
   r317 | rbd | 2020-10-10 20:34:34 -0500 (Sat, 10 Oct 2020) | 1 line

   This version works on Win64. Need to test changes on macOS and linux.
   ------------------------------------------------------------------------
   r316 | rbd | 2020-10-10 19:59:15 -0500 (Sat, 10 Oct 2020) | 2 lines

   PWL changes to avoid compiler warning.

   ------------------------------------------------------------------------
   r315 | rbd | 2020-10-10 19:34:04 -0500 (Sat, 10 Oct 2020) | 2 lines

   A few more changes for 64-bit sample counts on Win64

   ------------------------------------------------------------------------
   r314 | rbd | 2020-10-10 13:19:42 -0500 (Sat, 10 Oct 2020) | 2 lines

   Fixed int64_t declaration in gate.alg

   ------------------------------------------------------------------------
   r313 | rbd | 2020-10-10 12:07:40 -0500 (Sat, 10 Oct 2020) | 2 lines

   Fixes to gate for long sounds

   ------------------------------------------------------------------------
   r312 | rbd | 2020-10-10 11:47:29 -0500 (Sat, 10 Oct 2020) | 2 lines

   Fixed sound_save types for intgen

   ------------------------------------------------------------------------
   r311 | rbd | 2020-10-10 11:09:01 -0500 (Sat, 10 Oct 2020) | 2 lines

   Fixed a 64-bit sample count problem in siosc.alg

   ------------------------------------------------------------------------
   r310 | rbd | 2020-10-10 11:03:12 -0500 (Sat, 10 Oct 2020) | 2 lines

   Fixed sndmax to handle 64-bit sample counts.

   ------------------------------------------------------------------------
   r309 | rbd | 2020-10-10 10:57:04 -0500 (Sat, 10 Oct 2020) | 2 lines

   Forgot to re-translate all tran/*.alg files with fix for int64 cast to int32. This version compiles on macOS and ready for test on Win64.

   ------------------------------------------------------------------------
   r308 | rbd | 2020-10-10 10:16:05 -0500 (Sat, 10 Oct 2020) | 2 lines

   Everything seems to compile and run on macOS now. Moving changes to Windows for test.

   ------------------------------------------------------------------------
   r307 | rbd | 2020-10-10 09:23:45 -0500 (Sat, 10 Oct 2020) | 1 line

   Added casts to avoid compiler warnings and to review changes to support 64-bit sample counts on Windows. Still not complete, and waiting to regenerate and compile tran directory code after updates to translation code that will insert more casts.
   ------------------------------------------------------------------------
   r306 | rbd | 2020-10-09 21:55:15 -0500 (Fri, 09 Oct 2020) | 2 lines

   Rebuilt seqfnint.c from header files.

   ------------------------------------------------------------------------
   r305 | rbd | 2020-10-09 21:53:33 -0500 (Fri, 09 Oct 2020) | 1 line

   Changed some FIXNUMS to LONG to avoid compiler warnings in seqfnint.c
   ------------------------------------------------------------------------
   r304 | rbd | 2020-10-09 21:44:03 -0500 (Fri, 09 Oct 2020) | 2 lines

   I discovered forgotten regression-test.lsp and added test that requires 64-bit sample counts to pass. Fixed a few bugs revealed by running the type-checking regression tests.

   ------------------------------------------------------------------------
   r303 | rbd | 2020-10-09 12:28:58 -0500 (Fri, 09 Oct 2020) | 2 lines

   Changes for 64-bit sample counts broke mult-channel s-save. Fixed in the commit for macOS.

   ------------------------------------------------------------------------
   r302 | rbd | 2020-10-09 10:03:39 -0500 (Fri, 09 Oct 2020) | 2 lines

   Changed snd-play to return samples computed and used that to make a test for computing long sounds that would overflow 32-bit length counts.

   ------------------------------------------------------------------------
   r301 | rbd | 2020-10-09 09:11:26 -0500 (Fri, 09 Oct 2020) | 2 lines

   corrected mistake in delaycv.alg and re-translated

   ------------------------------------------------------------------------
   r300 | rbd | 2020-10-09 09:09:06 -0500 (Fri, 09 Oct 2020) | 2 lines

   Fix to delaycv.alg -- "s" changed to "input" to avoid matching "s" in "sample_type".

   ------------------------------------------------------------------------
   r299 | rbd | 2020-10-09 09:03:33 -0500 (Fri, 09 Oct 2020) | 4 lines

   To avoid compiler warnings, XLisp interfaces to C int and long are now
   specified as LONG rather than FIXNUM, and the stubs that call the C
   functions cast FIXNUMs from XLisp into longs before calling C functions.

   ------------------------------------------------------------------------
   r298 | rbd | 2020-10-08 22:20:26 -0500 (Thu, 08 Oct 2020) | 2 lines

   This commit has many more fixes to handle long (64-bit) sounds, including a lot of fixes for warnings by Visual Studio assigning int64_t to long (works on macOS, doesn't work on VS). This was compiled and tested on macOS, and even computed a 27.1-hour sound using OSC, LP, SUM and MULT (haven't tested I/O yet).

   ------------------------------------------------------------------------
   r297 | rbd | 2020-10-07 13:04:02 -0500 (Wed, 07 Oct 2020) | 2 lines

   This is a major cleanup. It started with the goal of changing long to int64_t for sample counts so that on 64-bit windows, where long is only 32-bits, the sample counts would nevertheless be 64-bit allowing long sounds, which was a limitation for long recordings in Audacity. Since I was using compiler warnings to track possible loss-of-precision conversions from 64-bit sample counts, and there were *many* warnings, I started cleaning up *all* the warnings and ended up with a very large set of changes, including "modernizing" C declarations that date back to XLisp and CMU MIDI Toolkit code and were never changed. This version runs all the examples.sal code on macOS, but will surely have problems on Windows and Linux given the number of changes.

   ------------------------------------------------------------------------
   r296 | rbd | 2020-10-06 13:34:20 -0500 (Tue, 06 Oct 2020) | 2 lines

   More changes from long to int64_t for sample counts.

   ------------------------------------------------------------------------
   r295 | rbd | 2020-10-06 11:53:49 -0500 (Tue, 06 Oct 2020) | 2 lines

   More work on using 64-bit sample counts. Changed MAX_STOP from 32-bit to 64-bit limit.

   ------------------------------------------------------------------------
   r294 | rbd | 2020-10-06 11:48:05 -0500 (Tue, 06 Oct 2020) | 2 lines

   Made some changes so that sample counts are int64_t (for windows) instead of long to support sample counts above 31 bits.

   ------------------------------------------------------------------------
   r293 | rbd | 2020-10-04 21:30:55 -0500 (Sun, 04 Oct 2020) | 2 lines

   Fixed a few minor things for Linux and tested on Linux.

   ------------------------------------------------------------------------
   r292 | rbd | 2020-10-04 21:00:28 -0500 (Sun, 04 Oct 2020) | 2 lines

   Update extensions: all are minor changes.

   ------------------------------------------------------------------------
   r291 | rbd | 2020-09-24 13:59:31 -0500 (Thu, 24 Sep 2020) | 2 lines

   New implementation of seq and seqrep, added get-real-time, documented get-real-time, fixed examples.sal and examples.lsp which are now in lib rather than extensions (so they are now back in the basic installation), other cleanup.

   ------------------------------------------------------------------------
   r290 | rbd | 2020-08-16 16:24:52 -0500 (Sun, 16 Aug 2020) | 2 lines

   Fixed bug in snd-gate, revised GATE and NOISE-GATE to handle multi-channel sound. RMS now handles multi-channel input. S-AVG added to take multichannel input (but not used, because RMS could not be written without making SND-SRATE convert multichannel sound to vector of floats. That seems to be going toward a fully vectorized model. Not going there for now.

   ------------------------------------------------------------------------
   r289 | rbd | 2020-07-09 16:27:45 -0500 (Thu, 09 Jul 2020) | 2 lines

   Added GET-REAL-TIME function to XLISP. May not work yet on Windows. Various fixes for compiler warnings. I noticed FLAC doesn't work (I guess it never did) and I cannot figure out how this even links because flac_min seems to be undefined. Something to look at later.
2021-01-27 23:45:25 -06:00

1429 lines
31 KiB
C

/* xlcont - xlisp special forms */
/* Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
/* CHANGE LOG
* --------------------------------------------------------------------
* 28Apr03 dm eliminate some compiler warnings
*/
#include "xlisp.h"
/* external variables */
extern LVAL xlvalue;
extern LVAL s_setf,s_car,s_cdr,s_nth,s_aref,s_get;
extern LVAL s_svalue,s_sfunction,s_splist;
extern LVAL s_lambda,s_macro;
/* forward declarations */
FORWARD LOCAL LVAL bquote1(LVAL expr);
FORWARD LOCAL void placeform(LVAL place, LVAL value);
FORWARD LOCAL LVAL let(int pflag);
FORWARD LOCAL LVAL flet(LVAL type, int letflag);
FORWARD LOCAL LVAL prog(int pflag);
FORWARD LOCAL LVAL progx(int n);
FORWARD LOCAL LVAL doloop(int pflag);
FORWARD LOCAL LVAL evarg(LVAL *pargs);
FORWARD LOCAL LVAL match(int type, LVAL *pargs);
FORWARD LOCAL LVAL evmatch(int type, LVAL *pargs);
FORWARD LOCAL void toofew(LVAL args);
FORWARD LOCAL void toomany(LVAL args);
FORWARD LOCAL void setffunction(LVAL fun, LVAL place, LVAL value);
FORWARD LOCAL int keypresent(LVAL key, LVAL list);
FORWARD LOCAL void dobindings(LVAL list, LVAL env);
FORWARD LOCAL void tagbody(void);
FORWARD LOCAL void doupdates(LVAL list, int pflag);
/* dummy node type for a list */
#define LIST -1
/* xquote - special form 'quote' */
LVAL xquote(void)
{
LVAL val;
val = xlgetarg();
xllastarg();
return (val);
}
/* xfunction - special form 'function' */
LVAL xfunction(void)
{
LVAL val;
/* get the argument */
val = xlgetarg();
xllastarg();
/* create a closure for lambda expressions */
if (consp(val) && car(val) == s_lambda && consp(cdr(val)))
val = xlclose(NIL,s_lambda,car(cdr(val)),cdr(cdr(val)),xlenv,xlfenv);
/* otherwise, get the value of a symbol */
else if (symbolp(val))
val = xlgetfunction(val);
/* otherwise, its an error */
else
xlerror("not a function",val);
/* return the function */
return (val);
}
/* xbquote - back quote special form */
LVAL xbquote(void)
{
LVAL expr;
/* get the expression */
expr = xlgetarg();
xllastarg();
/* fill in the template */
return (bquote1(expr));
}
/* bquote1 - back quote helper function */
LOCAL LVAL bquote1(LVAL expr)
{
LVAL val,list,last,new;
/* handle atoms */
if (atomp(expr))
val = expr;
/* handle (comma <expr>) */
else if (car(expr) == s_comma) {
if (atomp(cdr(expr)))
xlfail("bad comma expression");
val = xleval(car(cdr(expr)));
}
/* handle ((comma-at <expr>) ... ) */
else if (consp(car(expr)) && car(car(expr)) == s_comat) {
xlstkcheck(2);
xlsave(list);
xlsave(val);
if (atomp(cdr(car(expr))))
xlfail("bad comma-at expression");
list = xleval(car(cdr(car(expr))));
for (last = NIL; consp(list); list = cdr(list)) {
new = consa(car(list));
if (last)
rplacd(last,new);
else
val = new;
last = new;
}
if (last)
rplacd(last,bquote1(cdr(expr)));
else
val = bquote1(cdr(expr));
xlpopn(2);
}
/* handle any other list */
else {
xlsave1(val);
val = consa(NIL);
rplaca(val,bquote1(car(expr)));
rplacd(val,bquote1(cdr(expr)));
xlpop();
}
/* return the result */
return (val);
}
/* xlambda - special form 'lambda' */
LVAL xlambda(void)
{
LVAL fargs,arglist,val;
/* get the formal argument list and function body */
xlsave1(arglist);
fargs = xlgalist();
arglist = makearglist(xlargc,xlargv);
/* create a new function definition */
val = xlclose(NIL,s_lambda,fargs,arglist,xlenv,xlfenv);
/* restore the stack and return the closure */
xlpop();
return (val);
}
/* xgetlambda - get the lambda expression associated with a closure */
LVAL xgetlambda(void)
{
LVAL closure;
closure = xlgaclosure();
return (cons(gettype(closure),
cons(getlambda(closure),getbody(closure))));
}
/* xsetq - special form 'setq' */
LVAL xsetq(void)
{
LVAL sym,val;
/* handle each pair of arguments */
for (val = NIL; moreargs(); ) {
sym = xlgasymbol();
val = xleval(nextarg());
xlsetvalue(sym,val);
}
/* return the result value */
return (val);
}
/* xpsetq - special form 'psetq' */
LVAL xpsetq(void)
{
LVAL plist,sym,val;
/* protect some pointers */
xlsave1(plist);
/* handle each pair of arguments */
for (val = NIL; moreargs(); ) {
sym = xlgasymbol();
val = xleval(nextarg());
plist = cons(cons(sym,val),plist);
}
/* do parallel sets */
for (; plist; plist = cdr(plist))
xlsetvalue(car(car(plist)),cdr(car(plist)));
/* restore the stack */
xlpop();
/* return the result value */
return (val);
}
/* xsetf - special form 'setf' */
LVAL xsetf(void)
{
LVAL place,value;
/* protect some pointers */
xlsave1(value);
/* handle each pair of arguments */
while (moreargs()) {
/* get place and value */
place = xlgetarg();
value = xleval(nextarg());
/* expand macros in the place form */
if (consp(place))
place = xlexpandmacros(place);
/* check the place form */
if (symbolp(place))
xlsetvalue(place,value);
else if (consp(place))
placeform(place,value);
else
xlfail("bad place form");
}
/* restore the stack */
xlpop();
/* return the value */
return (value);
}
/* placeform - handle a place form other than a symbol */
LOCAL void placeform(LVAL place, LVAL value)
{
LVAL fun,arg1,arg2;
int i;
/* check the function name */
if ((fun = match(SYMBOL,&place)) == s_get) {
xlstkcheck(2);
xlsave(arg1);
xlsave(arg2);
arg1 = evmatch(SYMBOL,&place);
arg2 = evmatch(SYMBOL,&place);
if (place) toomany(place);
xlputprop(arg1,value,arg2);
xlpopn(2);
}
else if (fun == s_svalue) {
arg1 = evmatch(SYMBOL,&place);
if (place) toomany(place);
setvalue(arg1,value);
}
else if (fun == s_sfunction) {
arg1 = evmatch(SYMBOL,&place);
if (place) toomany(place);
setfunction(arg1,value);
}
else if (fun == s_splist) {
arg1 = evmatch(SYMBOL,&place);
if (place) toomany(place);
setplist(arg1,value);
}
else if (fun == s_car) {
arg1 = evmatch(CONS,&place);
if (place) toomany(place);
rplaca(arg1,value);
}
else if (fun == s_cdr) {
arg1 = evmatch(CONS,&place);
if (place) toomany(place);
rplacd(arg1,value);
}
else if (fun == s_nth) {
xlsave1(arg1);
arg1 = evmatch(FIXNUM,&place);
arg2 = evmatch(LIST,&place);
if (place) toomany(place);
for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i)
arg2 = cdr(arg2);
if (consp(arg2))
rplaca(arg2,value);
xlpop();
}
else if (fun == s_aref) {
xlsave1(arg1);
arg1 = evmatch(VECTOR,&place);
arg2 = evmatch(FIXNUM,&place); i = (int)getfixnum(arg2);
if (place) toomany(place);
if (i < 0 || i >= getsize(arg1))
xlerror("index out of range",arg2);
setelement(arg1,i,value);
xlpop();
}
else if ((fun = xlgetprop(fun,s_setf)))
setffunction(fun,place,value);
else
xlfail("bad place form");
}
/* setffunction - call a user defined setf function */
LOCAL void setffunction(LVAL fun, LVAL place, LVAL value)
{
LVAL *newfp;
int argc;
/* create the new call frame */
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(fun);
pusharg(NIL);
/* push the values of all of the place expressions and the new value */
for (argc = 1; consp(place); place = cdr(place), ++argc)
pusharg(xleval(car(place)));
pusharg(value);
/* insert the argument count and establish the call frame */
newfp[2] = cvfixnum((FIXTYPE)argc);
xlfp = newfp;
/* apply the function */
xlapply(argc);
}
/* xdefun - special form 'defun' */
LVAL xdefun(void)
{
LVAL sym,fargs,arglist;
/* get the function symbol and formal argument list */
xlsave1(arglist);
sym = xlgasymbol();
fargs = xlgalist();
arglist = makearglist(xlargc,xlargv);
/* make the symbol point to a new function definition */
xlsetfunction(sym,xlclose(sym,s_lambda,fargs,arglist,xlenv,xlfenv));
/* restore the stack and return the function symbol */
xlpop();
return (sym);
}
/* xdefmacro - special form 'defmacro' */
LVAL xdefmacro(void)
{
LVAL sym,fargs,arglist;
/* get the function symbol and formal argument list */
xlsave1(arglist);
sym = xlgasymbol();
fargs = xlgalist();
arglist = makearglist(xlargc,xlargv);
/* make the symbol point to a new function definition */
xlsetfunction(sym,xlclose(sym,s_macro,fargs,arglist,NIL,NIL));
/* restore the stack and return the function symbol */
xlpop();
return (sym);
}
/* xcond - special form 'cond' */
LVAL xcond(void)
{
LVAL list,val;
/* find a predicate that is true */
for (val = NIL; moreargs(); ) {
/* get the next conditional */
list = nextarg();
/* evaluate the predicate part */
if (consp(list) && (val = xleval(car(list)))) {
/* evaluate each expression */
for (list = cdr(list); consp(list); list = cdr(list))
val = xleval(car(list));
/* exit the loop */
break;
}
}
/* return the value */
return (val);
}
/* xwhen - special form 'when' */
LVAL xwhen(void)
{
LVAL val;
/* check the test expression */
if ((val = xleval(xlgetarg())))
while (moreargs())
val = xleval(nextarg());
/* return the value */
return (val);
}
/* xunless - special form 'unless' */
LVAL xunless(void)
{
LVAL val=NIL;
/* check the test expression */
if (xleval(xlgetarg()) == NIL)
while (moreargs())
val = xleval(nextarg());
/* return the value */
return (val);
}
/* xcase - special form 'case' */
LVAL xcase(void)
{
LVAL key,list,cases,val;
/* protect some pointers */
xlsave1(key);
/* get the key expression */
key = xleval(nextarg());
/* find a case that matches */
for (val = NIL; moreargs(); ) {
/* get the next case clause */
list = nextarg();
/* make sure this is a valid clause */
if (consp(list)) {
/* compare the key list against the key */
if ((cases = car(list)) == s_true ||
(listp(cases) && keypresent(key,cases)) ||
eql(key,cases)) {
/* evaluate each expression */
for (list = cdr(list); consp(list); list = cdr(list))
val = xleval(car(list));
/* exit the loop */
break;
}
}
else
xlerror("bad case clause",list);
}
/* restore the stack */
xlpop();
/* return the value */
return (val);
}
/* keypresent - check for the presence of a key in a list */
LOCAL int keypresent(LVAL key, LVAL list)
{
for (; consp(list); list = cdr(list))
if (eql(car(list),key))
return (TRUE);
return (FALSE);
}
/* xand - special form 'and' */
LVAL xand(void)
{
LVAL val;
/* evaluate each argument */
for (val = s_true; moreargs(); )
if ((val = xleval(nextarg())) == NIL)
break;
/* return the result value */
return (val);
}
/* x_or - special form 'or' */
/* this was named xor, but that caused problems with c++ under gcc */
LVAL x_or(void)
{
LVAL val;
/* evaluate each argument */
for (val = NIL; moreargs(); )
if ((val = xleval(nextarg())))
break;
/* return the result value */
return (val);
}
/* xif - special form 'if' */
LVAL xif(void)
{
LVAL testexpr,thenexpr,elseexpr;
/* get the test expression, then clause and else clause */
testexpr = xlgetarg();
thenexpr = xlgetarg();
elseexpr = (moreargs() ? xlgetarg() : NIL);
xllastarg();
/* evaluate the appropriate clause */
return (xleval(xleval(testexpr) ? thenexpr : elseexpr));
}
/* xlet - special form 'let' */
LVAL xlet(void)
{
return (let(TRUE));
}
/* xletstar - special form 'let*' */
LVAL xletstar(void)
{
return (let(FALSE));
}
/* let - common let routine */
LOCAL LVAL let(int pflag)
{
LVAL newenv,val;
/* protect some pointers */
xlsave1(newenv);
/* create a new environment frame */
newenv = xlframe(xlenv);
/* get the list of bindings and bind the symbols */
if (!pflag) {
xlenv = newenv;
}
dobindings(xlgalist(),newenv);
if (pflag) {
xlenv = newenv;
}
/* execute the code */
for (val = NIL; moreargs(); )
val = xleval(nextarg());
/* unbind the arguments */
xlenv = cdr(xlenv);
/* restore the stack */
xlpop();
/* return the result */
return (val);
}
/* xflet - built-in function 'flet' */
LVAL xflet(void)
{
return (flet(s_lambda,TRUE));
}
/* xlabels - built-in function 'labels' */
LVAL xlabels(void)
{
return (flet(s_lambda,FALSE));
}
/* xmacrolet - built-in function 'macrolet' */
LVAL xmacrolet(void)
{
return (flet(s_macro,TRUE));
}
/* flet - common flet/labels/macrolet routine */
LOCAL LVAL flet(LVAL type, int letflag)
{
LVAL list,bnd,sym,fargs,val;
/* create a new environment frame */
xlfenv = xlframe(xlfenv);
/* bind each symbol in the list of bindings */
for (list = xlgalist(); consp(list); list = cdr(list)) {
/* get the next binding */
bnd = car(list);
/* get the symbol and the function definition */
sym = match(SYMBOL,&bnd);
fargs = match(LIST,&bnd);
val = xlclose(sym,type,fargs,bnd,xlenv,(letflag?cdr(xlfenv):xlfenv));
/* bind the value to the symbol */
xlfbind(sym,val);
}
/* execute the code */
for (val = NIL; moreargs(); )
val = xleval(nextarg());
/* unbind the arguments */
xlfenv = cdr(xlfenv);
/* return the result */
return (val);
}
/* xprog - special form 'prog' */
LVAL xprog(void)
{
return (prog(TRUE));
}
/* xprogstar - special form 'prog*' */
LVAL xprogstar(void)
{
return (prog(FALSE));
}
/* prog - common prog routine */
LOCAL LVAL prog(int pflag)
{
LVAL newenv,val;
XLCONTEXT cntxt;
/* protect some pointers */
xlsave1(newenv);
/* create a new environment frame */
newenv = xlframe(xlenv);
/* establish a new execution context */
xlbegin(&cntxt,CF_RETURN,NIL);
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
else {
/* get the list of bindings and bind the symbols */
if (!pflag) {
xlenv = newenv;
}
dobindings(xlgalist(),newenv);
if (pflag) {
xlenv = newenv;
}
/* execute the code */
tagbody();
val = NIL;
/* unbind the arguments */
xlenv = cdr(xlenv);
}
xlend(&cntxt);
/* restore the stack */
xlpop();
/* return the result */
return (val);
}
/* 4035 is the "no return value" warning message */
/* xgo, xreturn, xrtnfrom, and xthrow don't return anything */
/* #pragma warning(disable: 4035) */
/* xgo - special form 'go' */
LVAL xgo(void)
{
LVAL label;
/* get the target label */
label = xlgetarg();
xllastarg();
/* transfer to the label */
xlgo(label);
return NIL; /* never happens */
}
/* xreturn - special form 'return' */
LVAL xreturn(void)
{
LVAL val;
/* get the return value */
val = (moreargs() ? xleval(nextarg()) : NIL);
xllastarg();
/* return from the inner most block */
xlreturn(NIL,val);
return NIL; /* never happens */
}
/* xrtnfrom - special form 'return-from' */
LVAL xrtnfrom(void)
{
LVAL name,val;
/* get the return value */
name = xlgasymbol();
val = (moreargs() ? xleval(nextarg()) : NIL);
xllastarg();
/* return from the inner most block */
xlreturn(name,val);
return NIL; /* never happens */
}
/* xprog1 - special form 'prog1' */
LVAL xprog1(void)
{
return (progx(1));
}
/* xprog2 - special form 'prog2' */
LVAL xprog2(void)
{
return (progx(2));
}
/* progx - common progx code */
LOCAL LVAL progx(int n)
{
LVAL val;
/* protect some pointers */
xlsave1(val);
/* evaluate the first n expressions */
while (moreargs() && --n >= 0)
val = xleval(nextarg());
/* evaluate each remaining argument */
while (moreargs())
xleval(nextarg());
/* restore the stack */
xlpop();
/* return the last test expression value */
return (val);
}
/* xprogn - special form 'progn' */
LVAL xprogn(void)
{
LVAL val;
/* evaluate each expression */
for (val = NIL; moreargs(); )
val = xleval(nextarg());
/* return the last test expression value */
return (val);
}
/* xprogv - special form 'progv' */
LVAL xprogv(void)
{
LVAL olddenv,vars,vals,val;
/* protect some pointers */
xlstkcheck(2);
xlsave(vars);
xlsave(vals);
/* get the list of variables and the list of values */
vars = xlgetarg(); vars = xleval(vars);
vals = xlgetarg(); vals = xleval(vals);
/* bind the values to the variables */
for (olddenv = xldenv; consp(vars); vars = cdr(vars)) {
if (!symbolp(car(vars)))
xlerror("expecting a symbol",car(vars));
if (consp(vals)) {
xldbind(car(vars),car(vals));
vals = cdr(vals);
}
else
xldbind(car(vars),s_unbound);
}
/* evaluate each expression */
for (val = NIL; moreargs(); )
val = xleval(nextarg());
/* restore the previous environment and the stack */
xlunbind(olddenv);
xlpopn(2);
/* return the last test expression value */
return (val);
}
/* xloop - special form 'loop' */
LVAL xloop(void)
{
LVAL *argv,arg,val;
XLCONTEXT cntxt;
int argc;
/* protect some pointers */
xlsave1(arg);
/* establish a new execution context */
xlbegin(&cntxt,CF_RETURN,NIL);
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
else
for (argv = xlargv, argc = xlargc; ; xlargv = argv, xlargc = argc)
while (moreargs()) {
arg = nextarg();
if (consp(arg))
xleval(arg);
}
xlend(&cntxt);
/* restore the stack */
xlpop();
/* return the result */
return (val);
}
/* xdo - special form 'do' */
LVAL xdo(void)
{
return (doloop(TRUE));
}
/* xdostar - special form 'do*' */
LVAL xdostar(void)
{
return (doloop(FALSE));
}
/* doloop - common do routine */
LOCAL LVAL doloop(int pflag)
{
LVAL newenv,*argv,blist,clist,test,val;
XLCONTEXT cntxt;
int argc;
/* protect some pointers */
xlsave1(newenv);
/* get the list of bindings, the exit test and the result forms */
blist = xlgalist();
clist = xlgalist();
test = (consp(clist) ? car(clist) : NIL);
argv = xlargv;
argc = xlargc;
/* create a new environment frame */
newenv = xlframe(xlenv);
/* establish a new execution context */
xlbegin(&cntxt,CF_RETURN,NIL);
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
else {
/* bind the symbols */
if (!pflag) {
xlenv = newenv;
}
dobindings(blist,newenv);
if (pflag) {
xlenv = newenv;
}
/* execute the loop as long as the test is false */
for (val = NIL; xleval(test) == NIL; doupdates(blist,pflag)) {
xlargv = argv;
xlargc = argc;
tagbody();
}
/* evaluate the result expression */
if (consp(clist))
for (clist = cdr(clist); consp(clist); clist = cdr(clist))
val = xleval(car(clist));
/* unbind the arguments */
xlenv = cdr(xlenv);
}
xlend(&cntxt);
/* restore the stack */
xlpop();
/* return the result */
return (val);
}
/* xdolist - special form 'dolist' */
LVAL xdolist(void)
{
LVAL list,*argv,clist,sym,val;
XLCONTEXT cntxt;
int argc;
/* protect some pointers */
xlsave1(list);
/* get the control list (sym list result-expr) */
clist = xlgalist();
sym = match(SYMBOL,&clist);
list = evmatch(LIST,&clist);
argv = xlargv;
argc = xlargc;
/* initialize the local environment */
xlenv = xlframe(xlenv);
xlbind(sym,NIL);
/* establish a new execution context */
xlbegin(&cntxt,CF_RETURN,NIL);
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
else {
/* loop through the list */
for (val = NIL; consp(list); list = cdr(list)) {
/* bind the symbol to the next list element */
xlsetvalue(sym,car(list));
/* execute the loop body */
xlargv = argv;
xlargc = argc;
tagbody();
}
/* evaluate the result expression */
xlsetvalue(sym,NIL);
val = (consp(clist) ? xleval(car(clist)) : NIL);
/* unbind the arguments */
xlenv = cdr(xlenv);
}
xlend(&cntxt);
/* restore the stack */
xlpop();
/* return the result */
return (val);
}
/* xdotimes - special form 'dotimes' */
LVAL xdotimes(void)
{
LVAL *argv,clist,sym,cnt,val;
XLCONTEXT cntxt;
int argc,n,i;
/* get the control list (sym list result-expr) */
clist = xlgalist();
sym = match(SYMBOL,&clist);
cnt = evmatch(FIXNUM,&clist); n = (int) getfixnum(cnt);
argv = xlargv;
argc = xlargc;
/* establish a new execution context */
xlbegin(&cntxt,CF_RETURN,NIL);
/* initialize the local environment */
xlenv = xlframe(xlenv);
xlbind(sym,NIL);
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
else {
/* loop through for each value from zero to n-1 */
for (val = NIL, i = 0; i < n; ++i) {
/* bind the symbol to the next list element */
xlsetvalue(sym,cvfixnum((FIXTYPE)i));
/* execute the loop body */
xlargv = argv;
xlargc = argc;
tagbody();
}
/* evaluate the result expression */
xlsetvalue(sym,cnt);
val = (consp(clist) ? xleval(car(clist)) : NIL);
/* unbind the arguments */
xlenv = cdr(xlenv);
}
xlend(&cntxt);
/* return the result */
return (val);
}
/* xblock - special form 'block' */
LVAL xblock(void)
{
LVAL name,val;
XLCONTEXT cntxt;
/* get the block name */
name = xlgetarg();
if (name && !symbolp(name))
xlbadtype(name);
/* execute the block */
xlbegin(&cntxt,CF_RETURN,name);
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
else
for (val = NIL; moreargs(); )
val = xleval(nextarg());
xlend(&cntxt);
/* return the value of the last expression */
return (val);
}
/* xtagbody - special form 'tagbody' */
LVAL xtagbody(void)
{
tagbody();
return (NIL);
}
/* xcatch - special form 'catch' */
LVAL xcatch(void)
{
XLCONTEXT cntxt;
LVAL tag,val;
/* protect some pointers */
xlsave1(tag);
/* get the tag */
tag = xleval(nextarg());
/* establish an execution context */
xlbegin(&cntxt,CF_THROW,tag);
/* check for 'throw' */
if (_setjmp(cntxt.c_jmpbuf))
val = xlvalue;
/* otherwise, evaluate the remainder of the arguments */
else {
for (val = NIL; moreargs(); )
val = xleval(nextarg());
}
xlend(&cntxt);
/* restore the stack */
xlpop();
/* return the result */
return (val);
}
/* xthrow - special form 'throw' */
LVAL xthrow(void)
{
LVAL tag,val;
/* get the tag and value */
tag = xleval(nextarg());
val = (moreargs() ? xleval(nextarg()) : NIL);
xllastarg();
/* throw the tag */
xlthrow(tag,val);
return NIL; /* never happens */
}
/* xunwindprotect - special form 'unwind-protect' */
LVAL xunwindprotect(void)
{
extern XLCONTEXT *xltarget;
extern int xlmask;
XLCONTEXT cntxt;
XLCONTEXT *target = NULL;
int mask = 0;
int sts;
LVAL val;
/* protect some pointers */
xlsave1(val);
/* get the expression to protect */
val = xlgetarg();
/* evaluate the protected expression */
xlbegin(&cntxt,CF_UNWIND,NIL);
if ((sts = _setjmp(cntxt.c_jmpbuf))) {
target = xltarget;
mask = xlmask;
val = xlvalue;
}
else
val = xleval(val);
xlend(&cntxt);
/* evaluate the cleanup expressions */
while (moreargs())
xleval(nextarg());
/* if unwinding, continue unwinding */
if (sts)
xljump(target,mask,val);
/* restore the stack */
xlpop();
/* return the value of the protected expression */
return (val);
}
/* xerrset - special form 'errset' */
LVAL xerrset(void)
{
LVAL expr,flag,val;
XLCONTEXT cntxt;
/* get the expression and the print flag */
expr = xlgetarg();
flag = (moreargs() ? xlgetarg() : s_true);
xllastarg();
/* establish an execution context */
xlbegin(&cntxt,CF_ERROR,flag);
/* check for error */
if (_setjmp(cntxt.c_jmpbuf))
val = NIL;
/* otherwise, evaluate the expression */
else {
expr = xleval(expr);
val = consa(expr);
}
xlend(&cntxt);
/* return the result */
return (val);
}
/* xtrace - special form 'trace' */
LVAL xtrace(void)
{
LVAL sym,fun,this;
/* loop through all of the arguments */
sym = xlenter("*TRACELIST*");
while (moreargs()) {
fun = xlgasymbol();
/* check for the function name already being in the list */
for (this = getvalue(sym); consp(this); this = cdr(this))
if (car(this) == fun)
break;
/* add the function name to the list */
if (null(this))
setvalue(sym,cons(fun,getvalue(sym)));
}
return (getvalue(sym));
}
/* xuntrace - special form 'untrace' */
LVAL xuntrace(void)
{
LVAL sym,fun,this,last;
/* loop through all of the arguments */
sym = xlenter("*TRACELIST*");
while (moreargs()) {
fun = xlgasymbol();
/* remove the function name from the list */
last = NIL;
for (this = getvalue(sym); consp(this); this = cdr(this)) {
if (car(this) == fun) {
if (last)
rplacd(last,cdr(this));
else
setvalue(sym,cdr(this));
break;
}
last = this;
}
}
return (getvalue(sym));
}
/* dobindings - handle bindings for let/let*, prog/prog*, do/do* */
LOCAL void dobindings(LVAL list, LVAL env)
{
LVAL bnd, val;
LVAL sym = NULL;
/* protect some pointers */
xlsave1(val);
/* bind each symbol in the list of bindings */
for (; consp(list); list = cdr(list)) {
/* get the next binding */
bnd = car(list);
/* handle a symbol */
if (symbolp(bnd)) {
sym = bnd;
val = NIL;
}
/* handle a list of the form (symbol expr) */
else if (consp(bnd)) {
sym = match(SYMBOL,&bnd);
val = evarg(&bnd);
}
else
xlfail("bad binding");
/* bind the value to the symbol */
xlpbind(sym,val,env);
}
/* restore the stack */
xlpop();
}
/* doupdates - handle updates for do/do* */
LOCAL void doupdates(LVAL list, int pflag)
{
LVAL plist,bnd,sym,val;
/* protect some pointers */
xlstkcheck(2);
xlsave(plist);
xlsave(val);
/* bind each symbol in the list of bindings */
for (; consp(list); list = cdr(list)) {
/* get the next binding */
bnd = car(list);
/* handle a list of the form (symbol expr) */
if (consp(bnd)) {
sym = match(SYMBOL,&bnd);
bnd = cdr(bnd);
if (bnd) {
val = evarg(&bnd);
if (pflag)
plist = cons(cons(sym,val),plist);
else
xlsetvalue(sym,val);
}
}
}
/* set the values for parallel updates */
for (; plist; plist = cdr(plist))
xlsetvalue(car(car(plist)),cdr(car(plist)));
/* restore the stack */
xlpopn(2);
}
/* tagbody - execute code within a block and tagbody */
LOCAL void tagbody(void)
{
LVAL *argv,arg;
XLCONTEXT cntxt;
int argc;
/* establish an execution context */
xlbegin(&cntxt,CF_GO,NIL);
argc = xlargc;
argv = xlargv;
/* check for a 'go' */
if (_setjmp(cntxt.c_jmpbuf)) {
cntxt.c_xlargc = argc;
cntxt.c_xlargv = argv;
}
/* execute the body */
while (moreargs()) {
arg = nextarg();
if (consp(arg))
xleval(arg);
}
xlend(&cntxt);
}
/* match - get an argument and match its type */
LOCAL LVAL match(int type, LVAL *pargs)
{
LVAL arg;
/* make sure the argument exists */
if (!consp(*pargs))
toofew(*pargs);
/* get the argument value */
arg = car(*pargs);
/* move the argument pointer ahead */
*pargs = cdr(*pargs);
/* check its type */
if (type == LIST) {
if (arg && ntype(arg) != CONS)
xlerror("bad argument type",arg);
}
else {
if (arg == NIL || ntype(arg) != type)
xlerror("bad argument type",arg);
}
/* return the argument */
return (arg);
}
/* evarg - get the next argument and evaluate it */
LOCAL LVAL evarg(LVAL *pargs)
{
LVAL arg;
/* protect some pointers */
xlsave1(arg);
/* make sure the argument exists */
if (!consp(*pargs))
toofew(*pargs);
/* get the argument value */
arg = car(*pargs);
/* move the argument pointer ahead */
*pargs = cdr(*pargs);
/* evaluate the argument */
arg = xleval(arg);
/* restore the stack */
xlpop();
/* return the argument */
return (arg);
}
/* evmatch - get an evaluated argument and match its type */
LOCAL LVAL evmatch(int type, LVAL *pargs)
{
LVAL arg;
/* protect some pointers */
xlsave1(arg);
/* make sure the argument exists */
if (!consp(*pargs))
toofew(*pargs);
/* get the argument value */
arg = car(*pargs);
/* move the argument pointer ahead */
*pargs = cdr(*pargs);
/* evaluate the argument */
arg = xleval(arg);
/* check its type */
if (type == LIST) {
if (arg && ntype(arg) != CONS)
xlerror("bad argument type",arg);
}
else {
if (arg == NIL || ntype(arg) != type)
xlerror("bad argument type",arg);
}
/* restore the stack */
xlpop();
/* return the argument */
return (arg);
}
/* toofew - too few arguments */
LOCAL void toofew(LVAL args)
{
xlerror("too few arguments",args);
}
/* toomany - too many arguments */
LOCAL void toomany(LVAL args)
{
xlerror("too many arguments",args);
}