/* newlisp.c --- enrty point and main functions for newLISP
Copyright (C) 2007 Lutz Mueller
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "newlisp.h"
#include "pcre.h"
#include "protos.h"
#include "primes.h"
#ifdef WIN_32
#include <winsock2.h>
#endif
#ifdef READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#ifdef SUPPORT_UTF8
#include <wctype.h>
#endif
#define freeMemory free
#ifdef WIN_32
#define INIT_FILE "init.lsp"
#define fprintf win32_fprintf
#define fgets win32_fgets
#define fclose win32_fclose
#else
#define INIT_FILE "/usr/local/share/newlisp/init.lsp"
#endif
#ifdef LIBRARY
extern STREAM libStrStream;
#endif
#ifdef LINUX
int opsys = 1;
char ostype[]="Linux";
#endif
#ifdef _BSD
int opsys = 2;
char ostype[]="BSD";
#endif
#ifdef MAC_OSX
int opsys = 3;
char ostype[]="OSX";
#endif
#ifdef SOLARIS
#ifdef TRU64
int opsys = 9;
char ostype[]="Tru64Unix";
#else
int opsys = 4;
char ostype[]="Solaris";
#endif
#endif
#ifdef WIN_32
int opsys = 6;
char ostype[]="Win32";
#endif
#ifdef OS2
int opsys = 7;
char ostype[]="OS/2";
#endif
int version = 9200;
char copyright[]=
"\nnewLISP v.9.2.0 Copyright (c) 2007 Lutz Mueller. All rights reserved.\n\n%s\n\n";
#ifndef NEWLISP64
#ifdef SUPPORT_UTF8
char banner[]=
"newLISP v.9.2.0 on %s UTF-8%s\n\n";
#else
char banner[]=
"newLISP v.9.2.0 on %s%s\n\n";
#endif
#else
#ifdef SUPPORT_UTF8
char banner[]=
"newLISP v.9.2.0 64-bit on %s UTF-8%s\n\n";
#else
char banner[]=
"newLISP v.9.2.0 64-bit on %s%s\n\n";
#endif
#endif
char banner2[]=
", execute 'newlisp -h' for more info.";
char linkOffset[] = "@@@@@@@@";
void printHelpText(void);
/* --------------------- globals -------------------------------------- */
/* interactive command line */
int commandLineFlag = TRUE;
int isTTY = FALSE;
int demonMode = 0;
int noPromptMode = 0;
int forcePromptMode = 0;
int httpMode = 0;
FILE * IOchannel;
int IOport = 0;
char * IOdomain = NULL;
int logTraffic = 0;
#define LOG_LESS 1
#define LOG_MORE 2
/* initialization */
int MAX_CPU_STACK = 0x800;
int MAX_ENV_STACK;
int MAX_RESULT_STACK;
#ifndef NEWLISP64
long MAX_CELL_COUNT = 0x10000000;
#else
long MAX_CELL_COUNT = 0x800000000000000LL;
#endif
CELL * firstFreeCell = NULL;
CELL * nilCell;
CELL * trueCell;
CELL * lastCellCopied;
SYMBOL * nilSymbol;
SYMBOL * trueSymbol;
SYMBOL * starSymbol;
SYMBOL * plusSymbol;
SYMBOL * questionSymbol;
SYMBOL * atSymbol;
SYMBOL * currentFunc;
SYMBOL * argsSymbol;
SYMBOL * mainArgsSymbol;
SYMBOL * dolistIdxSymbol;
SYMBOL * sysSymbol[MAX_REGEX_EXP];
SYMBOL * errorEvent;
SYMBOL * currentContext = NULL;
SYMBOL * mainContext = NULL;
SYMBOL * demonRequest;
SYMBOL * timerEvent;
SYMBOL * symHandler[32];
int currentSignal = 0;
jmp_buf errorJump;
char lc_decimal_point;
/* error and exception handling */
#define EXCEPTION_THROW -1
int errorReg = 0;
CELL * throwResult;
int errnoSave;
/* buffer for read-line */
STREAM readLineStream;
/* compiler */
size_t cellCount = 0;
size_t symbolCount = 0;
int parStackCounter = 0;
/* expression evaluation */
static CELL * (*evalFunc)(CELL *) = NULL;
UINT * envStack = NULL;
UINT * resultStack = NULL;
UINT * lambdaStack = NULL;
int envStackIdx, resultStackIdx, lambdaStackIdx;
int evalSilent = 0;
extern PRIMITIVE primitive[];
int traceFlag = 0;
int evalCatchFlag = 0;
int recursionCount = 0;
int symbolProtectionLevel = 0;
int prettyPrintPars = 0;
int prettyPrintCurrent = 0;
int prettyPrintFlags = 0;
int prettyPrintLength = 0;
char * prettyPrintTab = " ";
#define MAX_PRETTY_PRINT_LENGTH 64
UINT prettyPrintMaxLength = MAX_PRETTY_PRINT_LENGTH;
int stringOutputRaw = TRUE;
#define pushLambda(A) (*(lambdaStack + lambdaStackIdx++) = (UINT)(A))
#define popLambda() ((CELL *)*(lambdaStack + --lambdaStackIdx))
int pushResultFlag = TRUE;
char startupDir[PATH_MAX]; /* start up directory, if defined via -w */
char logFile[PATH_MAX]; /* logFile, is define with -l, -L */
/* ============================== MAIN ================================ */
/*
void setupSignalHandler(int sig, void (* handler)(int))
{
static struct sigaction sig_act;
sig_act.sa_handler = handler;
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if(sigaction(sig, &sig_act, 0) != 0)
printf("Error setting signal:%d handler\n", sig);
}
*/
void setupSignalHandler(int sig, void (* handler)(int))
{
if(signal(sig, handler) == SIG_ERR)
printf("Error setting signal:%d handler\n", sig);
}
#ifdef SOLARIS
void sigpipe_handler(int sig)
{
setupSignalHandler(SIGPIPE, sigpipe_handler);
}
void sigchld_handler(int sig)
{
waitpid(-1, (int *)0, WNOHANG);
}
void ctrlC_handler(int sig)
{
char chr;
setupSignalHandler(SIGINT, ctrlC_handler);
if(commandLineFlag != TRUE) return;
traceFlag |= TRACE_SIGINT;
printErrorMessage(ERR_SIGINT, NULL, 0);
printf("(c)ontinue, e(x)it, (r)eset:");
fflush(NULL);
chr = getchar();
if(chr == 'x') exit(1);
if(chr == 'c') traceFlag &= ~TRACE_SIGINT;
}
void sigalrm_handler(int sig)
{
setupSignalHandler(sig, sigalrm_handler);
/* check if not sitting idle */
if(recursionCount)
traceFlag |= TRACE_TIMER;
else /* if idle */
executeSymbol(timerEvent, NULL);
}
#endif /* solaris */
void setupAllSignals(void)
{
#ifdef SOLARIS
setupSignalHandler(SIGINT,ctrlC_handler);
#else
setupSignalHandler(SIGINT, signal_handler);
#endif
#ifndef WIN_32
#ifdef SOLARIS
setupSignalHandler(SIGALRM, sigalrm_handler);
setupSignalHandler(SIGVTALRM, sigalrm_handler);
setupSignalHandler(SIGPROF, sigalrm_handler);
setupSignalHandler(SIGPIPE, sigpipe_handler);
setupSignalHandler(SIGCHLD, sigchld_handler);
#else
setupSignalHandler(SIGALRM, signal_handler);
setupSignalHandler(SIGVTALRM, signal_handler);
setupSignalHandler(SIGPROF, signal_handler);
setupSignalHandler(SIGPIPE, signal_handler);
setupSignalHandler(SIGCHLD, signal_handler);
#endif
#endif
}
void signal_handler(int sig)
{
#ifndef WIN_32
char chr;
#endif
if(sig > 32 || sig < 1) return;
#ifdef SOLARIS
switch(sig)
{
case SIGALRM:
case SIGVTALRM:
case SIGPROF:
setupSignalHandler(sig, sigalrm_handler);
break;
case SIGPIPE:
setupSignalHandler(SIGPIPE, sigpipe_handler);
break;
case SIGCHLD:
setupSignalHandler(SIGCHLD, sigchld_handler);
break;
}
#else
setupSignalHandler(sig, signal_handler);
#endif
if(symHandler[sig - 1] != nilSymbol)
{
if(recursionCount)
{
currentSignal = sig;
traceFlag |= TRACE_SIGNAL;
return;
}
else
{
executeSymbol(symHandler[sig-1], stuffInteger(sig));
return;
}
}
switch(sig)
{
case SIGINT:
if(commandLineFlag != TRUE) return;
printErrorMessage(ERR_SIGINT, NULL, 0);
#ifdef WIN_32
traceFlag |= TRACE_SIGINT;
#else
printf("\n(c)ontinue, (d)ebug, e(x)it, (r)eset:");
fflush(NULL);
chr = getchar();
if(chr == 'x') exit(1);
if(chr == 'd')
{
traceFlag &= ~TRACE_SIGINT;
openTrace();
}
if(chr == 'r') traceFlag |= TRACE_SIGINT;
break;
case SIGPIPE:
break;
case SIGALRM:
case SIGVTALRM:
case SIGPROF:
/* check if not sitting idle */
if(recursionCount)
traceFlag |= TRACE_TIMER;
else /* if idle */
executeSymbol(timerEvent, NULL);
break;
case SIGCHLD:
waitpid(-1, (int *)0, WNOHANG);
#endif
break;
default:
return;
}
}
void loadStartup(char * name)
{
#ifdef WIN_32
#ifndef LIBRARY
char * ptr;
char EXEName[MAX_LINE];
char initFile[MAX_LINE];
GetModuleFileName(NULL, EXEName, MAX_LINE);
name = EXEName;
#endif
#endif
if(strncmp(linkOffset, "@@@@", 4) == 0)
{
#ifdef WIN_32
#ifndef LIBRARY
ptr = name + strlen(name) - 1;
while(ptr != name)
{
if(*ptr == '/' || *ptr == '\\') break;
ptr--;
}
*ptr = 0;
strncpy(initFile, name, MAX_LINE - 9);
strcat(initFile, "/");
strcat(initFile, INIT_FILE);
loadFile(initFile, 0, 0, mainContext);
#else
loadFile(INIT_FILE, 0, 0, mainContext);
#endif
#else
loadFile(INIT_FILE, 0, 0, mainContext);
#endif
}
else /* load encrypted part at offset */
loadFile(name, *(UINT*)linkOffset, 1, mainContext);
}
#ifdef _BSD
struct lconv *localeconv(void);
char *setlocale(int, const char *);
#endif
void initLocale(void)
{
struct lconv * lc;
char * locale;
#ifndef SUPPORT_UTF8
locale = setlocale(LC_ALL, "C");
#else
locale = setlocale(LC_ALL, "");
#endif
if (locale != NULL)
stringOutputRaw = (strcmp(locale, "C") == 0);
lc = localeconv();
lc_decimal_point = *lc->decimal_point;
}
#ifndef LIBRARY
char * getArg(char * * arg, int argc, int * index)
{
if(strlen(arg[*index]) > 2)
return(arg[*index] + 2);
if(*index >= (argc - 1))
{
printf("missing parameter for %s\n", arg[*index]);
exit(-1);
}
*index = *index + 1;
return(arg[*index]);
}
#ifndef WIN_32
char ** MainArgs;
#endif
CELL * getMainArgs(char * mainArgs[])
{
CELL * argList;
#ifndef LIBRARY
CELL * lastEntry;
int idx = 0;
#endif
#ifndef WIN_32
MainArgs = mainArgs;
#endif
argList = getCell(CELL_EXPRESSION);
#ifndef LIBRARY
lastEntry = NULL;
while(mainArgs[idx] != NULL)
{
if(lastEntry == NULL)
{
lastEntry = stuffString(mainArgs[idx]);
argList->contents = (UINT)lastEntry;
}
else
{
lastEntry->next = stuffString(mainArgs[idx]);
lastEntry = lastEntry->next;
}
idx++;
}
#endif
return(argList);
}
int main(int argc, char * argv[])
{
char command[MAX_LINE];
STREAM cmdStream;
int idx;
#ifdef READLINE
char * cmd;
#endif
#ifdef WIN_32
WSADATA WSAData;
WSAStartup(MAKEWORD(1,1), &WSAData);
#endif
#ifdef SUPPORT_UTF8
opsys += 128;
#endif
memset(&cmdStream, 0, sizeof(STREAM));
initLocale();
IOchannel = stdin;
initialize();
initStacks();
mainArgsSymbol->contents = (UINT)getMainArgs(argv);
if((errorReg = setjmp(errorJump)) != 0)
{
if(errorReg && (errorEvent != nilSymbol) && !isNil((CELL*)errorEvent->contents))
executeSymbol(errorEvent, NULL);
else exit(-1);
goto AFTER_ERROR_ENTRY;
}
setupAllSignals();
loadStartup(argv[0]);
errno = 0;
realpath(".", startupDir);
for(idx = 1; idx < argc; idx++)
{
#ifndef NOCMD
if(strncmp(argv[idx], "-c", 2) == 0)
noPromptMode = TRUE;
if(strncmp(argv[idx], "-C", 2) == 0)
forcePromptMode = TRUE;
if(strncmp(argv[idx], "-http", 5) == 0)
{
noPromptMode = TRUE;
httpMode = TRUE;
}
if(strncmp(argv[idx], "-s", 2) == 0)
{
MAX_CPU_STACK = atoi(getArg(argv, argc, &idx));
if(MAX_CPU_STACK < 1024) MAX_CPU_STACK = 1024;
initStacks();
continue;
}
if(strncmp(argv[idx], "-p", 2) == 0 || strncmp(argv[idx], "-d", 2) == 0 )
{
if(strncmp(argv[idx], "-d", 2) == 0)
demonMode = TRUE;
IOdomain = getArg(argv, argc, &idx);
IOport = atoi(IOdomain);
setupServer(0);
continue;
}
if(strncmp(argv[idx], "-e", 2) == 0)
{
executeCommandLine(getArg(argv, argc, &idx), OUT_CONSOLE, &cmdStream);
exit(0);
}
if(strncmp(argv[idx], "-l", 2) == 0 || strncmp(argv[idx], "-L", 2) == 0)
{
logTraffic = (strncmp(argv[idx], "-L", 2) == 0) ? LOG_MORE : LOG_LESS;
realpath(getArg(argv, argc, &idx), logFile);
continue;
}
if(strncmp(argv[idx], "-m", 2) == 0)
{
#ifndef NEWLISP64
MAX_CELL_COUNT = abs(0x0010000 * atoi(getArg(argv, argc, &idx)));
#else
MAX_CELL_COUNT = abs(0x0008000 * atoi(getArg(argv, argc, &idx)));
#endif
continue;
}
if(strncmp(argv[idx], "-w", 2) == 0)
{
realpath(getArg(argv, argc, &idx), startupDir);
chdir(startupDir);
continue;
}
if(strcmp(argv[idx], "-h") == 0)
{
printHelpText();
exit(0);
}
#endif
loadFile(argv[idx], 0, 0, mainContext);
}
AFTER_ERROR_ENTRY:
if(isatty(fileno(IOchannel)))
{
isTTY = TRUE;
if(!noPromptMode)
varPrintf(OUT_CONSOLE, banner, ostype, banner2);
}
else
{
#ifdef WIN_32
/* its a faked FILE struct, see win32_fdopen() in nl-sock.c */
if(!isSocketStream(IOchannel))
#endif
setbuf(IOchannel,0);
}
errorReg = setjmp(errorJump);
setupAllSignals();
reset();
initStacks();
if(errorReg && !isNil((CELL*)errorEvent->contents) )
executeSymbol(errorEvent, NULL);
while(TRUE)
{
if(commandLineFlag == TRUE)
{
#ifdef READLINE
if(isTTY)
{
errnoSave = errno;
if((cmd = readline(prompt())) == NULL) exit(0);
errno = errnoSave; /* reset errno, set by readline() */
if(strlen(cmd) > 0) add_history(cmd);
executeCommandLine(cmd, OUT_CONSOLE, &cmdStream);
free(cmd);
continue;
}
if(IOchannel != stdin || forcePromptMode)
varPrintf(OUT_CONSOLE, prompt());
#endif
#ifndef READLINE
if(isTTY || IOchannel != stdin || forcePromptMode)
varPrintf(OUT_CONSOLE, prompt());
#endif
if(IOchannel == NULL || fgets(command, MAX_LINE - 1, IOchannel) == NULL)
{
if(!demonMode) exit(1);
if(IOchannel != NULL) fclose(IOchannel);
setupServer(1);
continue;
}
executeCommandLine(command, OUT_CONSOLE, &cmdStream);
}
}
#ifndef WIN_32
return 0;
#endif
}
#endif
void printHelpText(void)
{
varPrintf(OUT_CONSOLE, copyright,
"usage: newlisp [file | url ...] [options ...] [file | url ...]\n\noptions:\n");
varPrintf(OUT_CONSOLE, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s\n\n",
" -h this help",
" -s <stacksize>",
" -m <max-mem-megabyte>",
" -l log connections only",
" -L log all",
" -p <port-number>",
" -d <port-number>",
" -e <quoted lisp expression>",
" -c no prompts, HTTP",
" -C force prompts",
" -http HTTP only",
" -w <working-directory>",
"more information at http://newlisp.org");
}
void setupServer(int reconnect)
{
if((IOchannel = serverFD(IOport, IOdomain, reconnect)) == NULL)
{
printf("newLISP server setup on %s failed.\n", IOdomain);
exit(1);
}
#ifdef WIN_32
if(!isSocketStream(IOchannel))
#endif
setbuf(IOchannel,0);
if(!reconnect && !noPromptMode)
varPrintf(OUT_CONSOLE, banner, ostype, ".");
}
char * prompt(void)
{
char * context;
static char string[32];
if(evalSilent || noPromptMode)
{
evalSilent = 0;
return("");
}
if(currentContext != mainContext)
context = currentContext->name;
else context = "";
if(traceFlag & TRACE_SIGINT)
{
traceFlag &= ~TRACE_SIGINT;
longjmp(errorJump, errorReg);
}
if(traceFlag)
snprintf(string, 31, "%s %d> ", context, recursionCount);
else
snprintf(string, 31, "%s> ", context);
return(string);
}
void reset()
{
recoverEnvironment(0);
collectGarbage();
if(printDevice) close((int)printDevice);
printDevice = recursionCount = resultStackIdx = envStackIdx = lambdaStackIdx = 0;
symbolProtectionLevel = traceFlag = prettyPrintFlags = 0;
evalFunc = NULL;
pushResultFlag = commandLineFlag = TRUE;
currentContext = mainContext;
}
void recoverEnvironment(int index)
{
SYMBOL * symbol;
CELL * cell;
while(envStackIdx > index)
{
symbol = (SYMBOL *)popEnvironment();
cell = (CELL*)popEnvironment();
if(cell != (CELL*)symbol->contents)
{
deleteList((CELL*)symbol->contents);
symbol->contents = (UINT)cell;
if(isProtected(symbol->flags))
symbol->flags &= ~SYMBOL_PROTECTED;
}
}
}
void executeCommandLine(char * command, int outDevice, STREAM * cmdStream)
{
STREAM stream;
char buff[MAX_LINE];
if(strlen(command) == 0 || *command == '\n') return;
if(noPromptMode)
{
if(logTraffic == LOG_MORE)
writeLog(command, 0);
if(strncmp(command, "GET /", 5) == 0)
{
executeHTTPrequest(command + 5, HTTP_GET_URL);
return;
}
else if(strncmp(command, "HEAD /", 6) == 0)
{
executeHTTPrequest(command + 5, HTTP_GET_HEAD);
return;
}
else if(strncmp(command, "PUT /", 5) == 0)
{
executeHTTPrequest(command + 5, HTTP_PUT_URL);
return;
}
else if(strncmp(command, "POST /", 6) == 0)
{
executeHTTPrequest(command + 6, HTTP_POST_URL);
return;
}
else if(strncmp(command, "DELETE /", 8) == 0)
{
executeHTTPrequest(command + 8, HTTP_DELETE_URL);
return;
}
if(httpMode) return;
}
if(*command == '!' && *(command + 1) != ' ' && strlen(command) > 2)
{
system((command + 1));
return;
}
if(cmdStream != NULL && strncmp(command, "[cmd]", 5) == 0)
{
openStrStream(cmdStream, 1024, TRUE);
while(fgets(buff, MAX_LINE - 1, IOchannel) != NULL)
{
if(strncmp(buff, "[/cmd]", 6) == 0)
{
if(logTraffic)
{
writeLog(cmdStream->buffer, 0);
writeLog(buff, 0);
}
/* makeodify stream for evaluation */
makeStreamFromString(&stream, cmdStream->buffer);
evaluateStream(&stream, OUT_CONSOLE, 0);
closeStrStream(cmdStream);
return;
}
writeStreamStr(cmdStream, buff, 0);
}
closeStrStream(cmdStream);
if(!demonMode) exit(1);
if(IOchannel != NULL) fclose(IOchannel);
setupServer(1);
return;
}
if(logTraffic) writeLog(command, TRUE);
prettyPrintLength = 0;
makeStreamFromString(&stream, command);
evaluateStream(&stream, outDevice, 0);
return;
}
CELL * evaluateStream(STREAM * stream, UINT outDevice, int flag)
{
CELL * program;
CELL * eval = nilCell;
int resultIdxSave;
int result;
result = TRUE;
resultIdxSave = resultStackIdx;
while(result)
{
pushResult(program = getCell(CELL_QUOTE));
result = compileExpression(stream, program);
if(result)
{
if(flag && eval != nilCell) deleteList(eval);
eval = evaluateExpression((CELL *)program->contents);
if(outDevice != 0 && !evalSilent)
{
printCell(eval, TRUE, outDevice);
varPrintf(outDevice, "\n");
if(logTraffic == LOG_MORE)
{
printCell(eval, TRUE, OUT_LOG);
writeLog("", TRUE);
}
}
if(flag) eval = copyCell(eval);
}
cleanupResults(resultIdxSave);
}
if(flag) return(eval);
return(NULL);
}
long executeSymbol(SYMBOL * symbol, CELL * params)
{
CELL * program;
CELL * cell;
int resultIdxSave;
if(symbol == nilSymbol || symbol == NULL) return(0);
resultIdxSave = resultStackIdx;
pushResult(program = getCell(CELL_EXPRESSION));
cell = getCell(CELL_SYMBOL);
program->contents = (UINT)cell;
cell->contents = (UINT)symbol;
if(params != NULL) cell->next = params;
cell = evaluateExpression(program);
cleanupResults(resultIdxSave);
return(cell->contents);
}
void initialize()
{
int i;
SYMBOL * symbol;
CELL * pCell;
char symName[8];
/* build true and false cells */
nilCell = getCell(CELL_NIL);
trueCell = getCell(CELL_TRUE);
nilCell->contents = (UINT)nilCell;
trueCell->contents = (UINT)trueCell;
nilCell->next = trueCell->next = nilCell;
/* build first symbol and context MAIN */
mainContext = currentContext = translateCreateSymbol("MAIN", CELL_CONTEXT, NULL, TRUE);
makeContextFromSymbol(mainContext, mainContext);
/* build symbols for primitives */
for(i = 0; primitive[i].name != NULL; i++)
{
pCell = getCell(CELL_PRIMITIVE);
symbol = translateCreateSymbol(
primitive[i].name, CELL_PRIMITIVE, mainContext, TRUE);
symbol->contents = (UINT)pCell;
symbol->flags = primitive[i].prettyPrint | SYMBOL_PROTECTED | SYMBOL_GLOBAL | SYMBOL_BUILTIN;
pCell->contents = (UINT)primitive[i].function;
pCell->aux = (UINT)symbol->name;
}
/* build true, nil, * and ? symbols */
trueSymbol = translateCreateSymbol("true", CELL_TRUE, mainContext, TRUE);
trueSymbol->contents = (UINT)trueCell;
nilSymbol = translateCreateSymbol("nil", CELL_NIL, mainContext, TRUE);
nilSymbol->contents = (UINT)nilCell;
starSymbol = translateCreateSymbol("*", CELL_PRIMITIVE, mainContext, TRUE);
plusSymbol = translateCreateSymbol("+", CELL_PRIMITIVE, mainContext, TRUE);
questionSymbol = translateCreateSymbol("?", CELL_NIL, mainContext, TRUE);
atSymbol = translateCreateSymbol("@", CELL_NIL, mainContext, TRUE);
argsSymbol = translateCreateSymbol("$args", CELL_NIL, mainContext, TRUE);
mainArgsSymbol = translateCreateSymbol("$main-args", CELL_NIL, mainContext, TRUE);
dolistIdxSymbol = translateCreateSymbol("$idx", CELL_NIL, mainContext, TRUE);
for(i = 0; i < MAX_REGEX_EXP; i++)
{
snprintf(symName, 8, "$%d", i);
sysSymbol[i] = translateCreateSymbol(symName, CELL_NIL, mainContext, TRUE);
sysSymbol[i]->flags |= SYMBOL_GLOBAL | SYMBOL_BUILTIN;
}
currentFunc = errorEvent = timerEvent = nilSymbol;
trueSymbol->flags |= SYMBOL_PROTECTED | SYMBOL_GLOBAL;
nilSymbol->flags |= SYMBOL_PROTECTED | SYMBOL_GLOBAL;
questionSymbol->flags |= SYMBOL_PROTECTED | SYMBOL_GLOBAL;
atSymbol->flags |= SYMBOL_GLOBAL | SYMBOL_BUILTIN;
argsSymbol->flags |= SYMBOL_GLOBAL | SYMBOL_BUILTIN | SYMBOL_PROTECTED;
mainArgsSymbol->flags |= SYMBOL_GLOBAL | SYMBOL_BUILTIN | SYMBOL_PROTECTED;
dolistIdxSymbol->flags |= SYMBOL_GLOBAL | SYMBOL_BUILTIN | SYMBOL_PROTECTED;
argsSymbol->contents = (UINT)getCell(CELL_EXPRESSION);
symbol = translateCreateSymbol("ostype", CELL_STRING, mainContext, TRUE);
symbol->contents = (UINT)stuffString(ostype);
symbol->flags |= SYMBOL_GLOBAL | SYMBOL_BUILTIN | SYMBOL_PROTECTED;
/* init signal handlers */
for(i = 0; i < 32; i++)
symHandler[i] = nilSymbol;
/* init readLineStream */
openStrStream(&readLineStream, 16, 0);
}
void initStacks()
{
MAX_ENV_STACK = (MAX_CPU_STACK * 8 * 2);
MAX_RESULT_STACK = (MAX_CPU_STACK * 2);
if(envStack != NULL) freeMemory(envStack);
if(resultStack != NULL) freeMemory(resultStack);
if(lambdaStack != NULL) freeMemory(lambdaStack);
envStack = (UINT *)allocMemory((MAX_ENV_STACK + 16) * sizeof(UINT));
resultStack = (UINT *)allocMemory((MAX_RESULT_STACK + 16) * sizeof(UINT));
lambdaStack = (UINT *)allocMemory((MAX_RESULT_STACK + 16) * sizeof(UINT));
envStackIdx = resultStackIdx = lambdaStackIdx = 0;
}
/* ------------------------- evaluate s-expression --------------------- */
CELL * evaluateExpression(CELL * cell)
{
CELL * result;
CELL * args = NULL;
CELL * pCell = NULL;
SYMBOL * newContext = NULL;
SYMBOL * sPtr;
int resultIdxSave = 0;
if(cell->type & EVAL_SELF_TYPE_MASK) return cell;
switch(cell->type)
{
case CELL_SYMBOL:
case CELL_CONTEXT:
return((CELL*)((SYMBOL *)cell->contents)->contents);
case CELL_QUOTE:
return((CELL *)cell->contents);
case CELL_EXPRESSION:
args = (CELL *)cell->contents;
resultIdxSave = resultStackIdx;
if(++recursionCount > (int)MAX_CPU_STACK)
fatalError(ERR_OUT_OF_CALL_STACK, args, 0);
if(args->type == CELL_SYMBOL) /* precheck for speedup */
pCell = (CELL*)((SYMBOL *)args->contents)->contents;
else
pCell = evaluateExpression(args);
if(traceFlag) traceEntry(cell, pCell, args);
if(pCell->type == CELL_PRIMITIVE)
{
evalFunc = (CELL *(*)(CELL*))pCell->contents;
result = (*evalFunc)(args->next);
evalFunc = NULL;
break;
}
if(pCell->type == CELL_LAMBDA)
{
pushLambda(args);
if(args->type == CELL_SYMBOL)
newContext = ((SYMBOL *)args->contents)->context;
else
newContext = currentContext;
result = evaluateLambda((CELL *)pCell->contents, args->next, newContext);
--lambdaStackIdx;
break;
}
if(pCell->type == CELL_MACRO)
{
if(args->type == CELL_SYMBOL)
newContext = ((SYMBOL *)args->contents)->context;
else
newContext = currentContext;
result = evaluateMacro((CELL *)pCell->contents, args->next, newContext);
break;
}
if(pCell->type == CELL_IMPORT_CDECL
#ifdef WIN_32
|| pCell->type == CELL_IMPORT_DLL
#endif
)
{
result = executeLibfunction(pCell, args->next);
break;
}
/* check for 'default' functor
* allow function call with context name, i.e: (ctx)
* assumes that a ctx:ctx contains a function
*/
if(pCell->type == CELL_CONTEXT)
{
newContext = (SYMBOL *)pCell->contents;
sPtr= translateCreateSymbol(newContext->name, CELL_NIL, newContext, TRUE);
pCell = (CELL *)sPtr->contents;
if(pCell->type == CELL_PRIMITIVE)
{
evalFunc = (CELL *(*)(CELL*))pCell->contents;
result = (*evalFunc)(args->next);
evalFunc = NULL;
break;
}
else if(pCell->type == CELL_LAMBDA)
{
pushLambda(args);
result = evaluateLambda((CELL *)pCell->contents, args->next, newContext);
--lambdaStackIdx;
break;
}
else if(pCell->type == CELL_MACRO)
{
result = evaluateMacro((CELL *)pCell->contents, args->next, newContext);
break;
}
}
/* allow 'implicit indexing' if pCell is a list, array, string or number:
(pCell idx1 idx2 ...)
*/
if(args->next != nilCell)
{
if(pCell->type == CELL_EXPRESSION)
result = copyCell(implicitIndexList(pCell, args->next));
else if(pCell->type == CELL_ARRAY)
result = copyCell(implicitIndexArray(pCell, args->next));
else if(pCell->type == CELL_STRING)
result = implicitIndexString(pCell, args->next);
else if(isNumber(pCell->type))
result = implicitNrestSlice(pCell, args->next);
else result = errorProcExt(ERR_INVALID_FUNCTION, cell);
}
else
result = errorProcExt(ERR_INVALID_FUNCTION, cell);
break;
case CELL_DYN_SYMBOL:
return((CELL*)(getDynamicSymbol(cell))->contents);
default:
result = nilCell;
}
while(resultStackIdx > resultIdxSave)
deleteList(popResult());
if(pushResultFlag)
{
if(resultStackIdx > MAX_RESULT_STACK)
fatalError(ERR_OUT_OF_CALL_STACK, pCell, 0);
pushResult(result);
}
else pushResultFlag = TRUE;
if(traceFlag) traceExit(result, cell, pCell, args);
--recursionCount;
return(result);
}
CELL * evaluateExpressionSafe(CELL * cell, int * errNo)
{
jmp_buf errorJumpSave;
CELL * result;
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
if((*errNo = setjmp(errorJump)) != 0)
{
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
return(NULL);
}
result = evaluateExpression(cell);
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
return(result);
}
/* a symbol belonging to a dynamic context */
/* the parent context symbol points to the real context */
/* cell->contents -> name str of this symbol */
/* cell->aux -> symbol var which holds context (dynamic) */
/* ((SYMBOL*)cell->aux)->contents -> context cell */
SYMBOL * getDynamicSymbol(CELL * cell)
{
CELL * contextCell;
contextCell = (CELL *)((SYMBOL *)cell->aux)->contents;
if(contextCell->type != CELL_CONTEXT)
fatalError(ERR_CONTEXT_EXPECTED, stuffSymbol((SYMBOL*)cell->aux), TRUE);
return(translateCreateSymbol(
(char*)cell->contents, /* name of dyn symbol */
CELL_NIL,
(SYMBOL*)contextCell->contents, /* contextPtr */
TRUE));
}
CELL * evalCheckProtected(CELL * cell, CELL * * flagPtr)
{
CELL * result;
SYMBOL * sPtr;
if(isSymbol(cell->type))
{
if(cell->type == CELL_SYMBOL)
sPtr = (SYMBOL *)cell->contents;
else
sPtr = getDynamicSymbol(cell);
if(isProtected(sPtr->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, cell));
return((CELL *)sPtr->contents);
}
symbolProtectionLevel = recursionCount;
result = evaluateExpression(cell);
if(symbolProtectionLevel == 0xFFFFFFFF)
{
if(flagPtr == NULL)
return(errorProcExt(ERR_SYMBOL_PROTECTED, cell));
else *flagPtr = cell;
}
symbolProtectionLevel = 0;
return(result);
}
/* -------------------- evaluate lambda function ----------------------- */
CELL * evaluateLambda(CELL * localLst, CELL * arg, SYMBOL * newContext)
{
CELL * local;
CELL * result = nilCell;
CELL * cell;
SYMBOL * symbol;
SYMBOL * contextSave;
int localCount = 0;
if(envStackIdx > (UINT)MAX_ENV_STACK)
return(errorProc(ERR_OUT_OF_ENV_STACK));
if(localLst->type != CELL_EXPRESSION)
return(errorProcExt(ERR_INVALID_LAMBDA, localLst));
/* evaluate arguments */
if(arg != nilCell)
{
/* this symbol precheck does 10% speed improvment on lambdas */
if(arg->type == CELL_SYMBOL)
cell = result = copyCell((CELL*)((SYMBOL *)arg->contents)->contents);
else
cell = result = copyCell(evaluateExpression(arg));
while((arg = arg->next) != nilCell)
{
if(arg->type == CELL_SYMBOL)
cell->next = copyCell((CELL*)((SYMBOL *)arg->contents)->contents);
else
cell->next = copyCell(evaluateExpression(arg));
cell = cell->next;
}
}
/* change to new context */
contextSave = currentContext;
currentContext = newContext;
/* save environment and get parameters */
local = (CELL*)localLst->contents;
GET_LOCAL:
{
if(local->type == CELL_SYMBOL)
symbol = (SYMBOL *)local->contents;
/* get default parameters */
else if(local->type == CELL_EXPRESSION)
{
if(((CELL*)local->contents)->type == CELL_SYMBOL)
{
cell = (CELL *)local->contents;
if(cell->type == CELL_SYMBOL)
{
symbol = (SYMBOL *)cell->contents;
if(result == nilCell)
result = copyCell(evaluateExpression(cell->next));
}
else goto GOT_LOCALS;
}
else goto GOT_LOCALS;
}
else goto GOT_LOCALS;
if(isProtected(symbol->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, local));
/* save symbol environment */
pushEnvironment(symbol->contents);
pushEnvironment((UINT)symbol);
/* fill local symbols */
symbol->contents = (UINT)result;
cell = result;
result = result->next;
/* unlink list */
cell->next = nilCell;
local = local->next;
localCount++;
}
goto GET_LOCAL;
GOT_LOCALS:
/* put unassigned args in $args */
pushEnvironment(argsSymbol->contents);
pushEnvironment((UINT)argsSymbol);
argsSymbol->contents = (UINT)getCell(CELL_EXPRESSION);
if(result != nilCell)
((CELL*)argsSymbol->contents)->contents = (UINT)result;
++localCount;
/* evaluate body expressions */
cell = localLst->next;
result = nilCell;
while(cell != nilCell)
{
result = evaluateExpression(cell);
cell = cell->next;
}
result = copyCell(result);
/* recover environment of local symbols */
while(localCount--)
{
symbol = (SYMBOL *)popEnvironment();
if(isProtected(symbol->flags) && (symbol != argsSymbol))
symbol->flags &= ~SYMBOL_PROTECTED;
deleteList((CELL *)symbol->contents);
symbol->contents = popEnvironment();
}
currentContext = contextSave;
return(result);
}
CELL * evaluateMacro(CELL * localLst, CELL * arg, SYMBOL * newContext)
{
CELL * local;
CELL * result;
CELL * cell;
SYMBOL * symbol;
SYMBOL * contextSave;
int localCount;
if(envStackIdx > (UINT)MAX_ENV_STACK)
return(errorProc(ERR_OUT_OF_ENV_STACK));
if(localLst->type != CELL_EXPRESSION)
return(errorProcExt(ERR_INVALID_MACRO, localLst));
local = (CELL *)localLst->contents;
contextSave = currentContext;
currentContext = newContext;
/* save environment and get parameters */
localCount = 0;
GET_ARGS:
{
if(local->type == CELL_SYMBOL)
symbol = (SYMBOL *)local->contents;
/* get default parameters */
else if(local->type == CELL_EXPRESSION)
{
if(((CELL*)local->contents)->type == CELL_SYMBOL)
{
cell = (CELL *)local->contents;
if(cell->type == CELL_SYMBOL)
{
symbol = (SYMBOL *)cell->contents;
if(arg == nilCell)
arg = evaluateExpression(cell->next);
}
else goto GOT_ARGS;
}
else goto GOT_ARGS;
}
else goto GOT_ARGS;
if(isProtected(symbol->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, local));
pushEnvironment(symbol->contents);
pushEnvironment((UINT)symbol);
symbol->contents = (UINT)copyCell(arg);
local = local->next;
arg = arg->next;
localCount++;
}
goto GET_ARGS;
GOT_ARGS:
pushEnvironment(argsSymbol->contents);
pushEnvironment((UINT)argsSymbol);
argsSymbol->contents = (UINT)getCell(CELL_EXPRESSION);
if(arg != nilCell)
((CELL*)argsSymbol->contents)->contents = (UINT)copyList(arg);
++localCount;
arg = localLst->next;
result = nilCell;
while(arg != nilCell)
{
result = evaluateExpression(arg);
arg = arg->next;
}
result = copyCell(result);
while(localCount--)
{
symbol = (SYMBOL *)popEnvironment();
if(isProtected(symbol->flags) && (symbol != argsSymbol))
symbol->flags &= ~SYMBOL_PROTECTED;
deleteList((CELL *)symbol->contents);
symbol->contents = popEnvironment();
}
currentContext = contextSave;
return(result);
}
/* -------------- list/cell creation/deletion routines ---------------- */
CELL * stuffInteger(UINT contents)
{
CELL * cell;
cell = getCell(CELL_LONG);
cell->contents = (UINT) contents;
return(cell);
}
#ifndef NEWLISP64
CELL * stuffInteger64(INT64 contents)
{
CELL * cell;
cell = getCell(CELL_INT64);
*(INT64 *)&cell->aux = contents;
return(cell);
}
#endif
CELL * stuffIntegerList(int argc, ...)
{
CELL * cell;
CELL * list;
va_list ap;
va_start(ap, argc);
list = getCell(CELL_EXPRESSION);
list->contents = (UINT)stuffInteger(va_arg(ap, UINT));
cell = (CELL *)list->contents;
while(--argc)
{
cell->next = stuffInteger(va_arg(ap, UINT));
cell = cell->next;
}
va_end(ap);
return(list);
}
CELL * stuffString(char * string)
{
CELL * cell;
cell = getCell(CELL_STRING);
cell->aux = strlen(string) + 1;
cell->contents = (UINT)allocMemory((UINT)cell->aux);
memcpy((void *)cell->contents, string, (UINT)cell->aux);
return(cell);
}
CELL * stuffStringN(char * string, int len)
{
CELL * cell;
cell = getCell(CELL_STRING);
cell->aux = len + 1;
cell->contents = (UINT)allocMemory((UINT)cell->aux);
memcpy((void *)cell->contents, string, len);
*(char*)(cell->contents + len) = 0;
return(cell);
}
CELL * stuffFloat(double * floatPtr)
{
CELL * cell;
cell = getCell(CELL_FLOAT);
#ifndef NEWLISP64
*(double *)&cell->aux = *floatPtr;
#else
*(double *)&cell->contents = *floatPtr;
#endif
return(cell);
}
CELL * stuffSymbol(SYMBOL * sPtr)
{
CELL * cell;
cell = getCell(CELL_SYMBOL);
cell->contents = (UINT)sPtr;
return(cell);
}
ssize_t convertNegativeOffset(ssize_t offset, CELL * list)
{
int len=0;
while(list != nilCell)
{
++len;
list = list->next;
}
offset = len + offset;
if(offset < 0) offset = 0;
return(offset);
}
/* ------------------------ creating and freeing cells ------------------- */
CELL * getCell(int type)
{
CELL * cell;
if(firstFreeCell == NULL) allocBlock();
cell = firstFreeCell;
firstFreeCell = cell->next;
++cellCount;
cell->type = type;
cell->next = nilCell;
cell->aux = (UINT)nilCell;
cell->contents = (UINT)nilCell;
return(cell);
}
CELL * copyCell(CELL * cell)
{
CELL * newCell;
UINT len;
if(firstFreeCell == NULL) allocBlock();
newCell = firstFreeCell;
firstFreeCell = newCell->next;
++cellCount;
newCell->type = cell->type;
newCell->next = nilCell;
newCell->aux = cell->aux;
newCell->contents = cell->contents;
if(isEnvelope(cell->type))
{
if(cell->type == CELL_ARRAY)
newCell->contents = (UINT)copyArray(cell);
else
{
newCell->contents = (UINT)copyList((CELL *)cell->contents);
newCell->aux = (UINT)lastCellCopied;
}
}
else if(cell->type == CELL_STRING)
{
newCell->contents = (UINT)allocMemory((UINT)cell->aux);
memcpy((void *)newCell->contents,
(void*)cell->contents, (UINT)cell->aux);
}
else if(cell->type == CELL_DYN_SYMBOL)
{
len = strlen((char *)cell->contents);
newCell->contents = (UINT)allocMemory(len + 1);
memcpy((char *)newCell->contents, (char *)cell->contents, len + 1);
}
return(newCell);
}
/* this routine must be called with the list head
if copying with envelope call copyCell() instead */
CELL * copyList(CELL * cell)
{
CELL * firstCell;
CELL * newCell;
if(cell == nilCell || cell == trueCell) return(lastCellCopied = cell);
firstCell = newCell = copyCell(cell);
while((cell = cell->next) != nilCell)
{
newCell->next = copyCell(cell);
newCell = newCell->next;
}
lastCellCopied = newCell;
return(firstCell);
}
/* for deleting lists _and_ cells */
void deleteList(CELL * cell)
{
CELL * next;
while(cell != nilCell)
{
if(isEnvelope(cell->type))
{
if(cell->type == CELL_ARRAY)
deleteArray(cell);
else
deleteList((CELL *)cell->contents);
}
else if(cell->type == CELL_STRING || cell->type == CELL_DYN_SYMBOL)
freeMemory( (void *)cell->contents);
next = cell->next;
/* free cell */
if(cell == trueCell)
{
cell = next;
continue;
}
cell->type = CELL_FREE;
cell->next = firstFreeCell;
firstFreeCell = cell;
--cellCount;
cell = next;
}
}
/* --------------- cell / memory allocation and deallocation ------------- */
CELL * cellMemory = NULL;
CELL * cellBlock = NULL;
void allocBlock()
{
int i;
if(cellCount > MAX_CELL_COUNT) fatalError(ERR_NOT_ENOUGH_MEMORY, NULL, 0);
if(cellMemory == NULL)
{
cellMemory = (CELL *)allocMemory((MAX_BLOCK + 1) * sizeof(CELL));
cellBlock = cellMemory;
}
else
{
(cellBlock + MAX_BLOCK)->next =
(CELL *)allocMemory((MAX_BLOCK + 1) * sizeof(CELL));
cellBlock = (cellBlock + MAX_BLOCK)->next;
}
for(i = 0; i < MAX_BLOCK; i++)
{
(cellBlock + i)->type = CELL_FREE;
(cellBlock + i)->next = (cellBlock + i + 1);
}
(cellBlock + MAX_BLOCK - 1)->next = NULL;
(cellBlock + MAX_BLOCK)->next = NULL;
firstFreeCell = cellBlock;
}
void * allocMemory(size_t nbytes)
{
void * ptr;
if( (ptr = (void *)malloc(nbytes)) == NULL)
fatalError(ERR_NOT_ENOUGH_MEMORY, NULL, 0);
return(ptr);
}
void * callocMemory(size_t nbytes)
{
void * ptr;
if( (ptr = (void *)calloc(nbytes, 1)) == NULL)
fatalError(ERR_NOT_ENOUGH_MEMORY, NULL, 0);
return(ptr);
}
void * reallocMemory(void * prevPtr, UINT size)
{
void * ptr;
if( (ptr = realloc(prevPtr, size)) == NULL)
fatalError(ERR_NOT_ENOUGH_MEMORY, NULL, 0);
return(ptr);
}
/* ----------- garbage collection , only required on error --------------- */
void markReferences(SYMBOL * sPtr);
void markList(CELL * cell);
void sweepGarbage(void);
void relinkCells(void);
void collectGarbage()
{
resultStackIdx = 0;
nilCell->type |= (UINT)0x00008000;
markReferences((SYMBOL *)((CELL *)mainContext->contents)->aux);
sweepGarbage();
relinkCells();
}
void markReferences(SYMBOL * sPtr)
{
CELL * content;
if(sPtr != NIL_SYM && sPtr != NULL)
{
markReferences(sPtr->left);
markList((CELL *)sPtr->contents);
if((symbolType(sPtr) & 0xFF) == CELL_CONTEXT && sPtr != mainContext)
{
content = (CELL *)sPtr->contents;
if((SYMBOL*)content->contents != mainContext && (SYMBOL*)content->contents == sPtr)
markReferences((SYMBOL *)content->aux);
}
markReferences(sPtr->right);
}
}
void markList(CELL * cell)
{
while(cell != nilCell)
{
cell->type |= (UINT)0x00008000;
if(isEnvelope(cell->type & RAW_TYPE_MASK))
{
if((RAW_TYPE_MASK & cell->type) == CELL_ARRAY)
markArray(cell);
else
markList((CELL *)cell->contents);
}
cell = cell->next;
}
}
void sweepGarbage()
{
CELL * blockPtr;
CELL * lastBlockPtr;
CELL * memPtr;
int i, freed;
lastBlockPtr = blockPtr = cellMemory;
while(blockPtr != NULL)
{
for(i = freed = 0; i < MAX_BLOCK; i++)
{
if(*(UINT *)blockPtr != CELL_FREE)
{
if( *(UINT *)blockPtr & (UINT)0x00008000)
*(UINT *)blockPtr &= (UINT)0x00007FFF;
else
{
blockPtr->type = CELL_FREE;
--cellCount;
freed++;
}
}
else freed++;
blockPtr++;
}
if(freed == MAX_BLOCK)
{
memPtr = blockPtr->next;
freeMemory(lastBlockPtr->next);
lastBlockPtr->next = memPtr;
blockPtr = memPtr;
}
else
{
lastBlockPtr = blockPtr;
blockPtr = blockPtr->next;
}
}
}
void relinkCells(void)
{
CELL * blockPtr;
CELL * lastFreeCell = NULL;
int i;
cellBlock = blockPtr = cellMemory;
firstFreeCell = NULL;
while(blockPtr != NULL)
{
cellBlock = blockPtr;
for(i = 0; i < MAX_BLOCK; i++)
{
if(*(UINT *)blockPtr == CELL_FREE)
{
if(firstFreeCell == NULL)
firstFreeCell = lastFreeCell = blockPtr;
else
{
lastFreeCell->next = blockPtr;
lastFreeCell = blockPtr;
}
}
++blockPtr;
}
blockPtr = blockPtr->next;
}
lastFreeCell->next = NULL;
}
void cleanupResults(int from)
{
while(resultStackIdx > from)
deleteList(popResult());
}
/* -------------------------- I/O routines ------------------------------ */
UINT printDevice;
STREAM errorStream;
void prettyPrint(UINT device);
void varPrintf(UINT device, char * format, ...)
{
char * buffer;
va_list argptr;
va_start(argptr,format);
/* new in 7201 , defined in nl-filesys.c if not in libc */
vasprintf(&buffer, format, argptr);
prettyPrintLength += strlen(buffer);
switch(device)
{
case OUT_NULL:
return;
case OUT_DEVICE:
if(printDevice != 0)
{
write(printDevice, buffer, strlen(buffer));
break;
}
case OUT_CONSOLE:
#ifdef LIBRARY
writeStreamStr(&libStrStream, buffer, 0);
return;
#else
if(IOchannel == stdin)
{
printf("%s", buffer);
if(!isTTY) fflush(NULL);
}
else
{
if(IOchannel != NULL)
#ifndef WIN_32
fprintf(IOchannel, "%s", buffer);
#else
fprintf(IOchannel, buffer);
#endif
}
break;
#endif
case OUT_LOG:
writeLog(buffer, 0);
break;
default:
writeStreamStr((STREAM *)device, buffer, 0);
break;
}
freeMemory(buffer);
va_end(argptr);
}
int printCell(CELL * cell, UINT printFlag, UINT device)
{
SYMBOL * sPtr;
SYMBOL * sp;
switch(cell->type)
{
case CELL_NIL:
varPrintf(device, "nil"); break;
case CELL_TRUE:
varPrintf(device, "true"); break;
case CELL_LONG:
varPrintf(device,"%ld", cell->contents); break;
#ifndef NEWLISP64
case CELL_INT64:
#ifdef TRU64
varPrintf(device,"%ld", *(INT64 *)&cell->aux); break;
#else
#ifdef WIN_32
varPrintf(device,"%I64d", *(INT64 *)&cell->aux); break;
#else
varPrintf(device,"%lld", *(INT64 *)&cell->aux); break;
#endif
#endif
#endif
case CELL_FLOAT:
#ifndef NEWLISP64
varPrintf(device,"%1.10g",*(double *)&cell->aux);
#else
varPrintf(device,"%1.10g",*(double *)&cell->contents);
#endif
break;
case CELL_STRING:
if(printFlag)
printString((char *)cell->contents, device, cell->aux - 1);
else
varPrintf(device,"%s",cell->contents);
break;
case CELL_SYMBOL:
case CELL_CONTEXT:
sPtr = (SYMBOL *)cell->contents;
if(sPtr->context != currentContext
/* if not global or global overwritten in current context */
&& (!(sPtr->flags & SYMBOL_GLOBAL) || (lookupSymbol(sPtr->name, currentContext)))
&& (symbolType(sPtr) != CELL_CONTEXT ||
(SYMBOL *)((CELL*)sPtr->contents)->contents != sPtr)) /* context var */
{
varPrintf(device,"%s:%s", (char*)((SYMBOL*)sPtr->context)->name, sPtr->name);
break;
}
/* overwriting global in MAIN */
if(sPtr->context == currentContext
&& currentContext != mainContext
&& ((sp = lookupSymbol(sPtr->name, mainContext)) != NULL)
&& (sp->flags & SYMBOL_GLOBAL) )
{
varPrintf(device,"%s:%s", currentContext->name, sPtr->name);
break;
}
varPrintf(device,"%s",sPtr->name);
break;
case CELL_PRIMITIVE:
case CELL_IMPORT_CDECL:
#ifdef WIN_32
case CELL_IMPORT_DLL:
#endif
varPrintf(device,"%s <%lX>", (char *)cell->aux,
cell->contents);
break;
case CELL_QUOTE:
varPrintf(device, "'");
prettyPrintFlags |= PRETTYPRINT_DOUBLE;
printCell((CELL *)cell->contents, printFlag, device);
break;
case CELL_EXPRESSION:
case CELL_LAMBDA:
case CELL_MACRO:
printExpression(cell, device);
break;
case CELL_DYN_SYMBOL:
varPrintf(device, "%s:%s", ((SYMBOL*)cell->aux)->name, (char*)cell->contents);
break;
case CELL_ARRAY:
printArray(cell, device);
break;
default:
varPrintf(device,"?");
}
prettyPrintFlags &= ~PRETTYPRINT_DOUBLE;
return(1);
}
void printString(char * str, UINT device, int size)
{
char chr;
if(size >= MAX_STRING)
{
varPrintf(device, "[text]");
while(size--) varPrintf(device, "%c", *str++);
varPrintf(device, "[/text]");
return;
}
varPrintf(device,"\"");
while(size--)
{
switch(chr = *str++)
{
case '\n': varPrintf(device,"\\n"); break;
case '\r': varPrintf(device,"\\r"); break;
case '\t': varPrintf(device,"\\t"); break;
case '\\': varPrintf(device,"\\\\"); break;
case '"': varPrintf(device,"\\%c",'"'); break;
default:
if((unsigned char)chr < 32 || (stringOutputRaw && (unsigned char)chr > 126))
varPrintf(device,"\\%03u", (unsigned char)chr);
else
varPrintf(device,"%c",chr); break;
}
}
varPrintf(device,"\"");
}
int printExpression(CELL * cell, UINT device)
{
CELL * item;
int i, pFlags;
item = (CELL *)cell->contents;
if(prettyPrintPars <= prettyPrintCurrent ||
prettyPrintLength > prettyPrintMaxLength)
prettyPrint(device);
if(cell->type == CELL_LAMBDA)
{
varPrintf(device, "(lambda ");
++prettyPrintPars;
}
else if(cell->type == CELL_MACRO)
{
varPrintf(device, "(lambda-macro ");
++prettyPrintPars;
}
else
{
if(isSymbol(item->type))
{
if(item->type == CELL_SYMBOL)
pFlags = ((SYMBOL *)item->contents)->flags;
else
pFlags = 0;
if((pFlags & PRINT_TYPE_MASK) != 0)
{
prettyPrint(device);
varPrintf(device, "(");
++prettyPrintPars;
for(i = 0; i < (pFlags & PRINT_TYPE_MASK); i++)
{
if(item == nilCell)
{prettyPrintFlags |= PRETTYPRINT_DOUBLE; break;}
printCell(item, TRUE, device);
item = item->next;
if(item != nilCell) varPrintf(device," ");
else prettyPrintFlags |= PRETTYPRINT_DOUBLE;
}
prettyPrint(device);
}
else
{
varPrintf(device, "(");
++prettyPrintPars;
}
}
else
{
varPrintf(device, "(");
++prettyPrintPars;
}
}
while(item != nilCell)
{
if(prettyPrintLength > prettyPrintMaxLength) prettyPrint(device);
if(printCell(item, TRUE, device) == 0) return(0);
item = item->next;
if(item != nilCell) varPrintf(device," ");
}
varPrintf(device,")");
--prettyPrintPars;
return(TRUE);
}
void prettyPrint(UINT device)
{
int i;
if(prettyPrintFlags) return;
if(prettyPrintPars > 0)
varPrintf(device, LINE_FEED);
/* varPrintf(device, LINE_FEED); before 7106 */
for(i = 0; i < prettyPrintPars; i++)
varPrintf(device, prettyPrintTab);
prettyPrintLength = prettyPrintCurrent = prettyPrintPars;
prettyPrintFlags |= PRETTYPRINT_DOUBLE;
}
void printSymbol(SYMBOL * sPtr, UINT device)
{
CELL * cell;
CELL * list = NULL;
char * setStr;
prettyPrintCurrent = prettyPrintPars = 1;
prettyPrintLength = 0;
prettyPrintFlags &= !PRETTYPRINT_DOUBLE;
if(sPtr->flags & SYMBOL_PROTECTED)
setStr = "(constant ";
else
setStr = "(set ";
switch(symbolType(sPtr))
{
case CELL_PRIMITIVE:
case CELL_IMPORT_CDECL:
#ifdef WIN_32
case CELL_IMPORT_DLL:
#endif
break;
case CELL_SYMBOL:
case CELL_DYN_SYMBOL:
varPrintf(device, setStr);
printSymbolNameExt(device, sPtr);
varPrintf(device,"'");
printCell((CELL *)sPtr->contents, TRUE, device);
varPrintf(device, ")");
break;
case CELL_ARRAY:
case CELL_EXPRESSION:
varPrintf(device, setStr);
printSymbolNameExt(device, sPtr);
cell = (CELL *)sPtr->contents;
if(symbolType(sPtr) == CELL_ARRAY)
{
varPrintf(device, "(array ");
printArrayDimensions(cell, device);
varPrintf(device, "(flat ");
list = cell = arrayList(cell);
}
cell = (CELL *)cell->contents;
varPrintf(device,"'(");
prettyPrintPars = 2;
if(cell->type == CELL_EXPRESSION) prettyPrint(device);
while(cell != nilCell)
{
if(prettyPrintLength > prettyPrintMaxLength)
prettyPrint(device);
printCell(cell, TRUE, device);
cell = cell->next;
if(cell != nilCell) varPrintf(device, " ");
}
varPrintf(device, "))");
if(symbolType(sPtr) == CELL_ARRAY)
{
deleteList(list);
varPrintf(device ,"))");
}
break;
case CELL_LAMBDA:
case CELL_MACRO:
if(isProtected(sPtr->flags))
{
varPrintf(device, "%s%s%s", LINE_FEED, LINE_FEED, setStr);
printSymbolNameExt(device, sPtr);
printExpression((CELL *)sPtr->contents, device);
varPrintf(device, ")");
}
else if (isGlobal(sPtr->flags))
{
printLambda(sPtr, device);
varPrintf(device, "%s%s", LINE_FEED, LINE_FEED);
printSymbolNameExt(device, sPtr);
}
else printLambda(sPtr, device);
break;
default:
varPrintf(device, setStr);
printSymbolNameExt(device, sPtr);
printCell((CELL *)sPtr->contents, TRUE, device);
varPrintf(device, ")");
break;
}
varPrintf(device, "%s%s", LINE_FEED, LINE_FEED);
prettyPrintLength = prettyPrintPars = 0;
}
void printLambda(SYMBOL * sPtr, UINT device)
{
CELL * lambda;
CELL * cell;
lambda = (CELL *)sPtr->contents;
cell = (CELL *)lambda->contents;
if(cell->type == CELL_EXPRESSION)
cell = (CELL *)cell->contents;
if(!isLegalSymbol(sPtr->name))
{
varPrintf(device, "(set (sym ");
printString(sPtr->name, device, strlen(sPtr->name));
varPrintf(device, " %s) ", ((SYMBOL*)sPtr->context)->name);
printExpression((CELL *)sPtr->contents, device);
varPrintf(device, ")");
return;
}
if(symbolType(sPtr) == CELL_LAMBDA)
varPrintf(device, "(define (");
else
varPrintf(device, "(define-macro (");
prettyPrintPars += 2;
printSymbolName(device, sPtr);
varPrintf(device, " ");
while(cell != nilCell)
{
printCell(cell, TRUE, device);
cell = cell->next;
if(cell != nilCell) varPrintf(device, " ");
}
varPrintf(device, ")");
--prettyPrintPars;
prettyPrint(device);
cell = (CELL *)lambda->contents;
while((cell = cell->next) != nilCell)
{
if(prettyPrintLength > prettyPrintMaxLength) prettyPrint(device);
printCell(cell, TRUE, device);
if(!(cell->type & ENVELOPE_TYPE_MASK) && cell->next != nilCell) varPrintf(device, " ");
}
varPrintf(device, ")");
--prettyPrintPars;
}
void printSymbolName(UINT device, SYMBOL * sPtr)
{
SYMBOL * sp;
if(sPtr->context == currentContext)
{
if(*sPtr->name == *currentContext->name && strcmp(sPtr->name, currentContext->name) == 0)
varPrintf(device, "%s:%s", sPtr->name, sPtr->name);
else if(currentContext != mainContext
&& ((sp = lookupSymbol(sPtr->name, mainContext)) != NULL)
&& (sp->flags & SYMBOL_GLOBAL) )
varPrintf(device, "%s:%s", currentContext->name, sPtr->name);
else
varPrintf(device,"%s", sPtr->name);
}
else
varPrintf(device,"%s:%s",
(char *)((SYMBOL*)sPtr->context)->name, sPtr->name);
}
void printSymbolNameExt(UINT device, SYMBOL * sPtr)
{
if(isGlobal(sPtr->flags))
{
varPrintf(device, "(global '");
printSymbolName(device, sPtr);
if(symbolType(sPtr) == CELL_LAMBDA || symbolType(sPtr) == CELL_MACRO)
varPrintf(device, ")");
else varPrintf(device, ") ");
}
else
{
if(!isLegalSymbol(sPtr->name))
{
varPrintf(device, " (sym ");
printString(sPtr->name, device, strlen(sPtr->name));
varPrintf(device, " %s) ", ((SYMBOL*)sPtr->context)->name);
}
else
{
varPrintf(device, "'");
printSymbolName(device, sPtr);
}
varPrintf(device, " ");
}
}
CELL * p_prettyPrint(CELL * params)
{
CELL * result;
char * str;
size_t len;
if(params != nilCell)
params = getInteger(params, &prettyPrintMaxLength);
if(params != nilCell)
{
getStringSize(params, &str, &len, TRUE);
prettyPrintTab = allocMemory(len + 1);
memcpy(prettyPrintTab, str, len + 1);
}
result = getCell(CELL_EXPRESSION);
result->contents = (UINT)stuffInteger(prettyPrintMaxLength);
((CELL *)result->contents)->next = stuffString(prettyPrintTab);
return(result);
}
/* -------------------------- error handling --------------------------- */
char * errorMessage[] =
{
"", /* 0 */
"not enough memory", /* 1 */
"environment stack overflow", /* 2 */
"call stack overflow", /* 3 */
"problem accessing file", /* 4 */
"not an expression", /* 5 */
"missing parenthesis", /* 6 */
"string token too long", /* 7 */
"missing argument", /* 8 */
"number or string expected", /* 9 */
"value expected", /* 10 */
"string expected", /* 11 */
"symbol expected", /* 12 */
"context expected", /* 13 */
"symbol or context expected", /* 14 */
"list expected", /* 15 */
"list or symbol expected", /* 16 */
"list or string expected", /* 17 */
"list or number expected", /* 18 */
"array expected", /* 19 */
"array, list or string expected", /* 20 */
"lambda expected", /* 21 */
"lambda-macro expected", /* 22 */
"invalid function", /* 23 */
"invalid lambda expression", /* 24 */
"invalid macro expression", /* 25 */
"invalid let parameter list", /* 26 */
"problem saving file", /* 27 */
"division by zero", /* 28 */
"matrix expected", /* 29 */
"wrong dimensions", /* 30 */
"matrix is singular", /* 31 */
"syntax in regular expression", /* 32 */
"throw without catch", /* 33 */
"problem loading library", /* 34 */
"import function not found", /* 35 */
"symbol is protected", /* 36 */
"number out of range", /* 37 */
"regular expression", /* 38 */
"missing end of text [/text]", /* 39 */
"mismatch in number of arguments", /* 40 */
"problem in format string", /* 41 */
"data type and format don't match", /* 42 */
"invalid parameter", /* 43 */
"invalid parameter: 0.0", /* 44 */
"invalid parameter: NaN", /* 45 */
"illegal parameter type", /* 46 */
"symbol not in MAIN context", /* 47 */
"symbol not in current context", /* 48 */
"target cannot be MAIN", /* 49 */
"array index out of bounds", /* 50 */
"nesting level to deep", /* 51 */
"user error", /* 52 */
"user reset -", /* 53 */
"received SIGINT -", /* 54 */
"function is not reentrant" /* 55 */
};
void errorMissingPar(STREAM * stream)
{
char str[64];
snprintf(str, 40, "...%-40s", ((char *)((stream->ptr - stream->buffer) > 40 ? stream->ptr - 40 : stream->buffer)));
errorProcExt2(ERR_MISSING_PAR, stuffString(str));
}
CELL * errorProcAll(int errorNumber, CELL * expr, int deleteFlag)
{
if(!traceFlag) fatalError(errorNumber, expr, deleteFlag);
printErrorMessage(errorNumber, expr, deleteFlag);
openTrace();
return(nilCell);
}
CELL * errorProc(int errorNumber)
{
return(errorProcAll(errorNumber, NULL, 0));
}
/* extended error info in expr */
CELL * errorProcExt(int errorNumber, CELL * expr)
{
return(errorProcAll(errorNumber, expr, 0));
}
/* extended error info in expr, which has to be discarded after printing */
CELL * errorProcExt2(int errorNumber, CELL * expr)
{
return(errorProcAll(errorNumber, expr, 1));
}
CELL * errorProcArgs(int errorNumber, CELL * expr)
{
if(expr == nilCell)
return(errorProcExt(ERR_MISSING_ARGUMENT, NULL));
return(errorProcExt(errorNumber, expr));
}
void fatalError(int errorNumber, CELL * expr, int deleteFlag)
{
printErrorMessage(errorNumber, expr, deleteFlag);
closeTrace();
longjmp(errorJump, errorReg);
}
void printErrorMessage(UINT errorNumber, CELL * expr, int deleteFlag)
{
CELL * lambdaFunc;
UINT lambdaStackIdxSave;
SYMBOL * context;
int i;
if(errorNumber == EXCEPTION_THROW)
errorNumber = ERR_THROW_WO_CATCH;
errorReg = errorNumber;
if(!errorNumber) return;
openStrStream(&errorStream, MAX_STRING, 1);
if(traceFlag & ~TRACE_SIGINT) writeStreamStr(&errorStream, "ERR:", 4);
writeStreamStr(&errorStream, errorMessage[errorReg], 0);
for(i = 0; primitive[i].name != NULL; i++)
{
if(evalFunc == primitive[i].function)
{
writeStreamStr(&errorStream, " in function ", 0);
writeStreamStr(&errorStream, primitive[i].name, 0);
break;
}
}
if(expr != NULL)
{
writeStreamStr(&errorStream, " : ", 3);
printCell(expr, (errorNumber != ERR_USER_ERROR), (UINT)&errorStream);
if(deleteFlag) deleteList(expr);
}
lambdaStackIdxSave = lambdaStackIdx;
while(lambdaStackIdx)
{
lambdaFunc = popLambda();
if(lambdaFunc->type == CELL_SYMBOL)
{
writeStreamStr(&errorStream, LINE_FEED, 0);
writeStreamStr(&errorStream, "called from user defined function ", 0);
context = ((SYMBOL *)lambdaFunc->contents)->context;
if(context != mainContext)
{
writeStreamStr(&errorStream, context->name, 0);
writeStreamStr(&errorStream, ":", 0);
}
writeStreamStr(&errorStream, ((SYMBOL *)lambdaFunc->contents)->name, 0);
}
}
lambdaStackIdx = lambdaStackIdxSave;
if(!(traceFlag & TRACE_SIGINT)) evalFunc = NULL;
parStackCounter = prettyPrintPars = 0;
if(evalCatchFlag && !(traceFlag & TRACE_SIGINT)) return;
if(errorEvent == nilSymbol)
{
if(errorNumber == ERR_SIGINT)
printf(errorStream.buffer);
else
varPrintf(OUT_CONSOLE, "\n%.1024s\n", errorStream.buffer);
}
}
/* --------------------------- load source file ------------------------- */
CELL * loadFile(char * fileName, UINT offset, int encryptFlag, SYMBOL * context)
{
CELL * result;
STREAM stream;
int errNo, dataLen;
jmp_buf errorJumpSave;
SYMBOL * contextSave;
char key[16];
#ifdef LOAD_DEBUG
int i;
#endif
contextSave = currentContext;
currentContext = context;
if(encryptFlag)
{
dataLen = *((int *) (linkOffset + 4));
snprintf( key, 15, "%d", dataLen);
}
else dataLen = MAX_FILE_BUFFER;
if(my_strnicmp(fileName, "http://", 7) == 0)
{
result = getPutPostDeleteUrl(fileName, nilCell, HTTP_GET_URL, 60000);
pushResult(result);
if(memcmp((char *)result->contents, "ERR:", 4) == 0)
return(errorProcExt2(ERR_ACCESSING_FILE, stuffString((char *)result->contents)));
return(copyCell(sysEvalString((char *)result->contents, nilCell, context)));
}
if(my_strnicmp(fileName, "file://", 7) == 0)
fileName = fileName + 7;
if(makeStreamFromFile(&stream, fileName, dataLen + 4 * MAX_STRING, offset) == 0)
return(NULL);
if(encryptFlag)
encryptPad(stream.buffer, stream.buffer, key, dataLen, strlen(key));
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
if((errNo = setjmp(errorJump)) != 0)
{
closeStrStream(&stream);
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
currentContext = contextSave;
longjmp(errorJump, errNo);
}
#ifdef LOAD_DEBUG
for(i = 0; i<recursionCount; i++) printf(" ");
printf("load: %s\n", fileName);
#endif
result = evaluateStream(&stream, 0, TRUE);
currentContext = contextSave;
#ifdef LOAD_DEBUG
for(i = 0; i<recursionCount; i++) printf(" ");
printf("finish load: %s\n", fileName);
#endif
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
closeStrStream(&stream);
return(result);
}
/* -------------------------- parse / compile ----------------------------- */
int compileExpression(STREAM * stream, CELL * cell)
{
char token[MAX_STRING + 4];
double floatNumber;
CELL * newCell;
CELL * contextCell;
SYMBOL * contextPtr;
int listFlag, tklen;
char * lastPtr;
#if experimental
SYMBOL * saveContext;
int defaultSymbolLevel = 0;
saveContext = currentContext;
#endif
listFlag = TRUE; /* assumes we just entered from an envelope cell ! */
GETNEXT:
lastPtr = stream->ptr;
switch(getToken(stream, token, &tklen))
{
case TKN_ERROR:
errorProcExt2(ERR_EXPRESSION, stuffStringN(lastPtr,
(strlen(lastPtr) < 60) ? strlen(lastPtr) : 60));
return(0);
case TKN_EMPTY:
if(parStackCounter != 0) errorMissingPar(stream);
return(0);
case TKN_CHARACTER:
newCell = stuffInteger((UINT)token[0]);
break;
case TKN_HEX:
#ifndef NEWLISP64
newCell = stuffInteger64((INT64)strtoull(token,NULL,0));
#else
newCell = stuffInteger(strtoull(token,NULL,0));
#endif
break;
case TKN_DECIMAL:
#ifndef NEWLISP64
newCell = stuffInteger64(strtoll(token,NULL,0));
#else
newCell = stuffInteger(strtoll(token,NULL,0));
#endif
break;
case TKN_FLOAT:
floatNumber = (double)atof(token);
newCell = stuffFloat(&floatNumber);
break;
case TKN_STRING:
newCell = stuffStringN(token, tklen);
break;
case TKN_SYMBOL:
if(strcmp(token, "lambda") == 0 || strcmp(token, "fn") == 0)
{
if(cell->type != CELL_EXPRESSION)
{
errorProcExt2(ERR_INVALID_LAMBDA, stuffString(lastPtr));
return(0);
}
cell->type = CELL_LAMBDA;
cell->aux = (UINT)nilCell;
goto GETNEXT;
}
else if(strcmp(token, "lambda-macro") == 0 || strcmp(token, "fn-macro") == 0)
{
if(cell->type != CELL_EXPRESSION)
{
errorProcExt2(ERR_INVALID_LAMBDA, stuffString(lastPtr));
return(0);
}
cell->type = CELL_MACRO;
cell->aux = (UINT)nilCell;
goto GETNEXT;
}
else if(strncmp(token, "[text]", 6) == 0)
{
newCell = getCell(CELL_STRING);
newCell->contents = (UINT)readStreamText(stream, "[/text]");
if(newCell->contents == 0)
{
deleteList(newCell);
errorProc(ERR_MISSING_TEXT_END);
}
newCell->aux = strlen((char *)newCell->contents) + 1;
newCell->type = CELL_STRING;
break;
}
newCell = getCell(CELL_SYMBOL);
if(*token == '$')
newCell->contents = (UINT)translateCreateSymbol(
token, CELL_NIL, mainContext, TRUE);
else
newCell->contents = (UINT)translateCreateSymbol(
token, CELL_NIL, currentContext, 0);
break;
case TKN_CONTEXT:
contextPtr = NULL; /* since 7.5.1 dyna vars inside contexts */
if(currentContext != mainContext)
{
if(strcmp(currentContext->name, token) == 0)
contextPtr = currentContext;
else
contextPtr = lookupSymbol(token, currentContext);
}
if(contextPtr == NULL)
contextPtr = translateCreateSymbol(
token, CELL_CONTEXT, mainContext, TRUE);
contextCell = (CELL *)contextPtr->contents;
if(getToken(stream, token, &tklen) != TKN_SYMBOL)
errorProcExt2(ERR_SYMBOL_EXPECTED, stuffString(lastPtr));
/* context does not exist */
if(contextCell->type != CELL_CONTEXT
|| contextPtr != (SYMBOL*)contextCell->contents)
{
newCell = getCell(CELL_DYN_SYMBOL);
newCell->aux = (UINT)contextPtr;
newCell->contents = (UINT)allocMemory(tklen + 1);
strncpy((char *)newCell->contents, token, tklen + 1);
break;
}
/* context exists make a symbol for it */
newCell = getCell(CELL_SYMBOL);
newCell->contents = (UINT)translateCreateSymbol(
token, CELL_NIL, contextPtr, TRUE);
break;
case TKN_QUOTE:
newCell = getCell(CELL_QUOTE);
linkCell(cell, newCell, listFlag);
compileExpression(stream, newCell);
break;
case TKN_LEFT_PAR:
++parStackCounter;
newCell = getCell(CELL_EXPRESSION);
linkCell(cell, newCell, listFlag);
compileExpression(stream, newCell);
break;
case TKN_RIGHT_PAR:
if(parStackCounter == 0) errorMissingPar(stream);
--parStackCounter;
cell->next = nilCell;
return(TRUE);
default:
errorProcExt2(ERR_EXPRESSION, stuffString(lastPtr));
return(0);
}
linkCell(cell, newCell, listFlag);
if(cell->type == CELL_QUOTE && listFlag == TRUE)
return(TRUE);
listFlag = 0;
cell = newCell;
if(parStackCounter != 0)
{
if(*(stream->ptr) != 0) goto GETNEXT;
else errorMissingPar(stream);
}
return(0);
}
void linkCell(CELL * left, CELL * right, int linkFlag)
{
if(linkFlag == 0)
left->next = right;
else left->contents = (UINT)right;
}
int getToken(STREAM * stream, char * token, int * ptr_len)
{
char *tkn;
char chr;
int tknLen;
int floatFlag;
int bracketBalance;
char buff[4];
tkn = token;
tknLen = floatFlag = 0;
*tkn = 0;
STRIP:
if(stream->ptr > (stream->buffer + stream->size - 4 * MAX_STRING))
{
if(stream->handle == 0)
{
/* coming from commmand line or p_evalString */
stream->buffer = stream->ptr;
}
else
{
stream->position += (stream->ptr - stream->buffer);
lseek((int)stream->handle, stream->position, SEEK_SET);
memset(stream->buffer, 0, stream->size + 1);
if(read(stream->handle, stream->buffer, stream->size) > 0)
stream->ptr = stream->buffer;
else
{
*stream->ptr = 0;
return(TKN_EMPTY);
}
}
}
while((unsigned char)*stream->ptr <= ' ' && (unsigned char)*stream->ptr != 0)
++stream->ptr;
if(*stream->ptr == 0) return(TKN_EMPTY);
/* check for comments */
if(*stream->ptr == ';' || *stream->ptr == '#')
{
stream->ptr++;
for(;;)
{
if(*stream->ptr == 0) return(TKN_EMPTY);
if(*stream->ptr == '\n' || *stream->ptr == '\r')
break;
stream->ptr++;
}
stream->ptr++;
goto STRIP;
}
if( *stream->ptr == '-' || *stream->ptr == '+')
{
if(isDigit((unsigned char)*(stream->ptr + 1)) )
*(tkn++) = *(stream->ptr++), tknLen++;
}
if(isDigit((unsigned char)*stream->ptr) ||
(*stream->ptr == lc_decimal_point &&
isDigit((unsigned char)*(stream->ptr + 1))))
{
if(*stream->ptr == '0' && isDigit((unsigned char)*(stream->ptr + 1)))
{
*(tkn++) = *(stream->ptr++), tknLen++;
while(*stream->ptr < '8' && *stream->ptr >= '0' && *stream->ptr != 0)
*(tkn++) = *(stream->ptr++), tknLen++;
*tkn = 0;
return(TKN_DECIMAL);
}
while(isDigit((unsigned char)*stream->ptr) && tknLen < MAX_SYMBOL)
*(tkn++) = *(stream->ptr++), tknLen++;
if(toupper(*stream->ptr) == 'X' && token[0] == '0')
{
*(tkn++) = *(stream->ptr++), tknLen++;
while(isxdigit((unsigned char)*stream->ptr) && tknLen < MAX_SYMBOL)
*(tkn++) = *(stream->ptr++), tknLen++;
*tkn = 0;
return(TKN_HEX);
}
if(*stream->ptr == lc_decimal_point)
{
*(tkn++) = *(stream->ptr++), tknLen++;
while(isDigit((unsigned char)*stream->ptr) && tknLen < MAX_SYMBOL)
*(tkn++) = *(stream->ptr++), tknLen++;
floatFlag = TRUE;
}
else if(toupper(*stream->ptr) != 'E')
{
*tkn = 0;
return(TKN_DECIMAL);
}
if(toupper(*stream->ptr) == 'E')
{
if(isDigit((unsigned char)*(stream->ptr+2))
&& ( *(stream->ptr+1) == '-' || *(stream->ptr+1) == '+') )
*(tkn++) = *(stream->ptr++), tknLen++;
if(isDigit((unsigned char)*(stream->ptr+1)))
{
*(tkn++) = *(stream->ptr++), tknLen++;
while(isDigit((unsigned char)*stream->ptr) && tknLen < MAX_SYMBOL)
*(tkn++) = *(stream->ptr++), tknLen++;
}
else
{
*tkn = 0;
if(floatFlag == TRUE) return(TKN_FLOAT);
else return(TKN_DECIMAL);
}
}
*tkn = 0;
return(TKN_FLOAT);
}
else
{
chr = *stream->ptr;
*(tkn++) = *(stream->ptr++), tknLen++;
switch(chr)
{
case '"':
--tkn; --tknLen;
while(*stream->ptr != '"' && *stream->ptr != 0
&& tknLen < MAX_STRING)
{
if(*stream->ptr == '\\')
{
stream->ptr++;
if(isDigit((unsigned char)*stream->ptr) &&
isDigit((unsigned char)*(stream->ptr+1)) &&
isDigit((unsigned char)*(stream->ptr+2)))
{
memcpy(buff, stream->ptr, 3);
buff[3] = 0;
*(tkn++) = atoi(buff);
tknLen++;
stream->ptr += 3;
continue;
}
switch(*stream->ptr)
{
case 0:
*tkn = 0;
errorProcExt2(ERR_STRING_TOO_LONG, stuffString(token));
break;
case 'n':
*(tkn++) = '\n'; break;
case '\\':
*(tkn++) = '\\'; break;
case 'r':
*(tkn++) = '\r'; break;
case 't':
*(tkn++) = '\t'; break;
case '"':
*(tkn++) = '"'; break;
case 'x':
if(isxdigit((unsigned char)*(stream->ptr + 1)) &&
isxdigit((unsigned char)*(stream->ptr + 2)))
{
buff[0] = '0';
buff[1] = (unsigned char)*(stream->ptr + 1);
buff[2] = (unsigned char)*(stream->ptr + 2);
buff[3] = 0;
*(tkn++) = strtol(buff, NULL, 16);
stream->ptr += 2;
break;
}
default:
*(tkn++) = *stream->ptr;
}
stream->ptr++;
tknLen++;
}
else *(tkn++) = *(stream->ptr++), tknLen++;
}
if(*stream->ptr == '\"')
{
*tkn = 0;
stream->ptr++;
*ptr_len = tknLen;
return(TKN_STRING);
}
else
{
*tkn = 0;
errorProcExt2(ERR_STRING_TOO_LONG,
stuffStringN(token, strlen(token) < 40 ? strlen(token) : 40));
}
break;
case '\'':
case '(':
case ')':
*tkn = 0;
return(chr);
case '{':
--tkn; --tknLen;
bracketBalance = 1;
while(*stream->ptr != 0 && tknLen < MAX_STRING)
{
if(*stream->ptr == '{') ++bracketBalance;
if(*stream->ptr == '}') --bracketBalance;
if(bracketBalance == 0) break;
*(tkn++) = *(stream->ptr++), tknLen++;
}
if(*stream->ptr == '}')
{
*tkn = 0;
stream->ptr++;
*ptr_len = tknLen;
return(TKN_STRING);
}
else
{
*tkn = 0;
errorProcExt2(ERR_STRING_TOO_LONG, stuffStringN(token, 40));
}
break;
case ',':
case ':':
*tkn = 0;
return(TKN_SYMBOL);
case '[':
while( tknLen < MAX_SYMBOL && *stream->ptr != 0 && *stream->ptr != ']')
*(tkn++) = *(stream->ptr++), tknLen++;
*tkn++ = ']';
*tkn = 0;
stream->ptr++;
return(TKN_SYMBOL);
default:
while( tknLen < MAX_SYMBOL
&& (unsigned char)*stream->ptr > ' '
&& *stream->ptr != '"' && *stream->ptr != '\''
&& *stream->ptr != '(' && *stream->ptr != ')'
&& *stream->ptr != ':' && *stream->ptr != ','
&& *stream->ptr != 0)
*(tkn++) = *(stream->ptr++), tknLen++;
*tkn = 0;
*ptr_len = tknLen;
if(*stream->ptr == ':')
{
stream->ptr++;
return(TKN_CONTEXT);
}
return(TKN_SYMBOL);
}
}
*tkn=0;
return(TKN_ERROR);
}
/* -------------------------- utilities ------------------------------------ */
size_t listlen(CELL * listHead)
{
size_t len = 0;
while(listHead != nilCell)
{
len++;
listHead = listHead->next;
}
return(len);
}
/* -------------------------- functions to get parameters ------------------ */
void collectSymbols(SYMBOL * sPtr);
int getFlag(CELL * params)
{
params = evaluateExpression(params);
return(!isNil(params));
}
CELL * getInteger(CELL * params, UINT * number)
{
CELL * cell;
cell = evaluateExpression(params);
#ifndef NEWLISP64
if(cell->type == CELL_INT64)
{
if(*(INT64 *)&cell->aux > 0xFFFFFFFF) *number = 0xFFFFFFFF;
else if(*(INT64 *)&cell->aux < INT32_MIN_AS_INT64) *number = 0x80000000;
else *number = *(INT64 *)&cell->aux;
}
else if(cell->type == CELL_LONG)
*number = cell->contents;
else if(cell->type == CELL_FLOAT)
{
#ifdef WIN_32
if(isnan(*(double *)&cell->aux) || !_finite(*(double *)&cell->aux)) *number = 0;
#else
if(isnan(*(double *)&cell->aux)) *number = 0;
#endif
else if(*(double *)&cell->aux > 4294967295.0) *number = 0xFFFFFFFF;
else if(*(double *)&cell->aux < -2147483648.0) *number = 0x80000000;
else *number = *(double *)&cell->aux;
}
#else
if(cell->type == CELL_LONG)
*number = cell->contents;
else if(cell->type == CELL_FLOAT)
{
if(isnan(*(double *)&cell->contents)) *number = 0;
else if(*(double *)&cell->contents > 9223372036854775807.0) *number = 0x7FFFFFFFFFFFFFFFLL;
else if(*(double *)&cell->contents < -9223372036854775808.0) *number = 0x8000000000000000LL;
else *number = *(double *)&cell->contents;
}
#endif
else
{
*number = 0;
return(errorProcArgs(ERR_NUMBER_EXPECTED, params));
}
return(params->next);
}
#ifndef NEWLISP64
CELL * getInteger64(CELL * params, INT64 * number)
{
CELL * cell;
cell = evaluateExpression(params);
if(cell->type == CELL_INT64)
*number = *(INT64 *)&cell->aux;
else if(cell->type == CELL_LONG)
*number = (int)cell->contents;
else if(cell->type == CELL_FLOAT)
{
#ifdef WIN_32
if(isnan(*(double *)&cell->aux) || !_finite(*(double *)&cell->aux)) *number = 0;
#else
if(isnan(*(double *)&cell->aux)) *number = 0;
#endif
else if(*(double *)&cell->aux > 9223372036854775807.0) *number = 0x7FFFFFFFFFFFFFFFLL;
else if(*(double *)&cell->aux < -9223372036854775808.0) *number = 0x8000000000000000LL;
else *number = *(double *)&cell->aux;
}
else
{
*number = 0;
return(errorProcArgs(ERR_NUMBER_EXPECTED, params));
}
return(params->next);
}
#else
CELL * getInteger64(CELL * params, INT64 * number)
{
CELL * cell;
cell = evaluateExpression(params);
if(cell->type == CELL_LONG)
*number = cell->contents;
else if(cell->type == CELL_FLOAT)
{
if(isnan(*(double *)&cell->contents)) *number = 0;
else if(*(double *)&cell->contents > 9223372036854775807.0) *number = 0x7FFFFFFFFFFFFFFFLL;
else if(*(double *)&cell->contents < -9223372036854775808.0) *number = 0x8000000000000000LL;
else *number = *(double *)&cell->contents;
}
else
{
*number = 0;
return(errorProcArgs(ERR_NUMBER_EXPECTED, params));
}
return(params->next);
}
#endif
CELL * getIntegerExt(CELL * params, UINT * number, int evalFlag)
{
CELL * cell;
if(evalFlag)
cell = evaluateExpression(params);
else cell = params;
#ifndef NEWLISP64
if(cell->type == CELL_INT64)
{
if(*(INT64 *)&cell->aux > 0xFFFFFFFF) *number = 0xFFFFFFFF;
else if(*(INT64 *)&cell->aux < INT32_MIN_AS_INT64) *number = 0x80000000;
else *number = *(INT64 *)&cell->aux;
}
else if(cell->type == CELL_LONG)
*number = cell->contents;
else if(cell->type == CELL_FLOAT)
{
#ifdef WIN_32
if(isnan(*(double *)&cell->aux) || !_finite(*(double *)&cell->aux)) *number = 0;
#else
if(isnan(*(double *)&cell->aux)) *number = 0;
#endif
else if(*(double *)&cell->aux > 4294967295.0) *number = 0xFFFFFFFF;
else if(*(double *)&cell->aux < -2147483648.0) *number = 0x80000000;
else *number = *(double *)&cell->aux;
}
#else
if(cell->type == CELL_LONG)
*number = cell->contents;
else if(cell->type == CELL_FLOAT)
{
if(isnan(*(double *)&cell->contents)) *number = 0;
else if(*(double *)&cell->contents > 9223372036854775807.0) *number = 0x7FFFFFFFFFFFFFFFLL;
else if(*(double *)&cell->contents < -9223372036854775808.0) *number = 0x8000000000000000LL;
else *number = *(double *)&cell->contents;
}
#endif
else
{
*number = 0;
return(errorProcArgs(ERR_NUMBER_EXPECTED, params));
}
return(params->next);
}
CELL * getFloat(CELL * params, double * floatNumber)
{
CELL * cell;
cell = evaluateExpression(params);
#ifndef NEWLISP64
if(cell->type == CELL_FLOAT)
*floatNumber = *(double *)&cell->aux;
else if(cell->type == CELL_INT64)
*floatNumber = *(INT64 *)&cell->aux;
#else
if(cell->type == CELL_FLOAT)
*floatNumber = *(double *)&cell->contents;
#endif
else if(cell->type == CELL_LONG)
*floatNumber = (long)cell->contents;
else
{
*floatNumber = 0.0;
return(errorProcArgs(ERR_NUMBER_EXPECTED, params));
}
return(params->next);
}
CELL * getString(CELL * params, char * * stringPtr)
{
CELL * cell;
cell = evaluateExpression(params);
if(cell->type != CELL_STRING)
{
*stringPtr = "";
return(errorProcArgs(ERR_STRING_EXPECTED, params));
}
*stringPtr = (char *)cell->contents;
return(params->next);
}
CELL * getStringSize(CELL * params, char * * stringPtr, size_t * size, int evalFlag)
{
CELL * cell;
if(params == nilCell)
return(errorProc(ERR_MISSING_ARGUMENT));
if(evalFlag)
cell = evaluateExpression(params);
else cell = params;
if(cell->type != CELL_STRING)
{
*stringPtr = "";
return(errorProcArgs(ERR_STRING_EXPECTED, params));
}
*stringPtr = (char *)cell->contents;
if(size) *size = cell->aux - 1;
return(params->next);
}
CELL * getSymbol(CELL * params, SYMBOL * * symbol)
{
CELL * cell;
cell = evaluateExpression(params);
if(cell->type != CELL_SYMBOL)
{
if(cell->type == CELL_DYN_SYMBOL)
{
*symbol = getDynamicSymbol(cell);
return(params->next);
}
*symbol = nilSymbol;
return(errorProcArgs(ERR_SYMBOL_EXPECTED, params));
}
*symbol = (SYMBOL *)cell->contents;
return(params->next);
}
/* only used for internal syms: $timer, $error-event and $signal-1-> $signal-32 */
CELL * getCreateSymbol(CELL * params, SYMBOL * * symbol, char * name)
{
CELL * cell;
cell = evaluateExpression(params);
if(cell->type != CELL_SYMBOL)
{
if(cell->type == CELL_DYN_SYMBOL)
{
*symbol = getDynamicSymbol(cell);
return(params->next);
}
*symbol = translateCreateSymbol(name, CELL_NIL, mainContext, TRUE);
(*symbol)->flags |= SYMBOL_PROTECTED | SYMBOL_GLOBAL;
(*symbol)->contents = (UINT)copyCell(cell);
}
else
*symbol = (SYMBOL *)cell->contents;
return(params->next);
}
CELL * getContext(CELL * params, SYMBOL * * context)
{
CELL * cell;
cell = evaluateExpression(params);
if(cell->type == CELL_CONTEXT || cell->type == CELL_SYMBOL)
*context = (SYMBOL *)cell->contents;
else
{
*context = NULL;
return(errorProcArgs(ERR_CONTEXT_EXPECTED, params));
}
if(symbolType(*context) != CELL_CONTEXT)
return(errorProcExt(ERR_CONTEXT_EXPECTED, params));
return(params->next);
}
CELL * getListHead(CELL * params, CELL * * list)
{
CELL * cell;
cell = evaluateExpression(params);
if(!isList(cell->type))
{
*list = copyCell(nilCell);
return(errorProcArgs(ERR_LIST_EXPECTED, params));
}
*list = (CELL *)cell->contents;
return(params->next);
}
/* ------------------------------- core predicates ------------------------ */
CELL * p_setlocale(CELL * params)
{
struct lconv * lc;
char * locale;
UINT category;
if(params != nilCell)
params = getString(params, &locale);
else locale = NULL;
if(params != nilCell)
getInteger(params, &category);
else category = LC_ALL;
locale = setlocale(category, locale);
if(locale == NULL)
return(nilCell);
stringOutputRaw = (strcmp(locale, "C") == 0);
lc = localeconv();
lc_decimal_point = *lc->decimal_point;
return(stuffString(locale));
}
CELL * p_commandLine(CELL * params)
{
commandLineFlag = getFlag(params);
return((commandLineFlag == FALSE ? nilCell : trueCell));
}
CELL * p_quote(CELL * params)
{
return(copyCell(params));
}
CELL * p_eval(CELL * params)
{
if(params->type == CELL_SYMBOL)
params = (CELL*)((SYMBOL *)params->contents)->contents;
else
params = evaluateExpression(params);
if(params->type == CELL_SYMBOL)
{
if(symbolProtectionLevel && symbolProtectionLevel == (recursionCount - 1))
{
if(isProtected(((SYMBOL *)params->contents)->flags))
symbolProtectionLevel = 0xFFFFFFFF;
}
/* eval returns original symbol contents for usage in macros */
pushResultFlag = 0;
return(evaluateExpression(params));
}
return(copyCell(evaluateExpression(params)));
}
CELL * p_catch(CELL * params)
{
jmp_buf errorJumpSave;
int envStackIdxSave;
int lambdaStackIdxSave;
int recursionCountSave;
int value;
CELL * expr;
CELL * result;
SYMBOL * symbol = NULL;
SYMBOL * contextSave;
expr = params;
if(params->next != nilCell)
{
getSymbol(params->next, &symbol);
if(isProtected(symbol->flags))
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbol)));
}
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
envStackIdxSave = envStackIdx;
recursionCountSave = recursionCount;
lambdaStackIdxSave = lambdaStackIdx;
contextSave = currentContext;
if((value = setjmp(errorJump)) != 0)
{
memcpy(errorJump, errorJumpSave, (sizeof(jmp_buf)));
recoverEnvironment(envStackIdxSave);
recursionCount = recursionCountSave;
lambdaStackIdx = lambdaStackIdxSave;
currentContext = contextSave;
evalCatchFlag--;
if(value == EXCEPTION_THROW)
{
if(symbol == NULL) return(throwResult);
deleteList((CELL*)symbol->contents);
symbol->contents = (UINT)throwResult;
return(trueCell);
}
if(errorStream.buffer != NULL)
{
if(symbol == NULL)
{
if(errorEvent == nilSymbol && evalCatchFlag == 0)
varPrintf(OUT_CONSOLE, "\n%.1024s\n", errorStream.buffer);
longjmp(errorJump, value);
}
deleteList((CELL*)symbol->contents);
symbol->contents = (UINT)stuffString(errorStream.buffer);
}
return(nilCell);
}
evalCatchFlag++;
result = copyCell(evaluateExpression(expr));
evalCatchFlag--;
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
if(symbol == NULL) return(result);
deleteList((CELL*)symbol->contents);
symbol->contents = (UINT)result;
return(trueCell);
}
CELL * p_throw(CELL * params)
{
if(evalCatchFlag == 0)
return(errorProc(ERR_THROW_WO_CATCH));
throwResult = copyCell(evaluateExpression(params));
longjmp(errorJump, EXCEPTION_THROW);
return(trueCell);
}
CELL * p_throwError(CELL * params)
{
evalFunc = NULL;
errorProcExt(ERR_USER_ERROR, evaluateExpression(params));
return(nilCell);
}
CELL * p_evalString(CELL * params)
{
SYMBOL * context = currentContext;
char * evalString;
params = getString(params, &evalString);
if(params->next != nilCell)
{
if((context = getCreateContext(params->next, TRUE)) == NULL)
return(errorProcExt(ERR_SYMBOL_OR_CONTEXT_EXPECTED, params->next));
}
return(copyCell(sysEvalString(evalString, params, context)));
}
CELL * sysEvalString(char * evalString, CELL * proc, SYMBOL * context)
{
CELL * program;
STREAM stream;
CELL * resultCell = nilCell;
jmp_buf errorJumpSave;
int recursionCountSave;
int envStackIdxSave;
int resultIdxSave;
SYMBOL * contextSave = NULL;
makeStreamFromString(&stream, evalString);
recursionCountSave = recursionCount;
envStackIdxSave = envStackIdx;
resultIdxSave = resultStackIdx;
contextSave = currentContext;
currentContext = context;
if(proc != nilCell)
{
evalCatchFlag++;
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
if(setjmp(errorJump) != 0)
{
memcpy(errorJump, errorJumpSave, (sizeof(jmp_buf)));
recoverEnvironment(envStackIdxSave);
evalCatchFlag--;
recursionCount = recursionCountSave;
currentContext = contextSave;
return(evaluateExpression(proc));
}
}
while(TRUE)
{
pushResult(program = getCell(CELL_QUOTE));
if(compileExpression(&stream, program) == 0) break;
resultCell = evaluateExpression((CELL *)program->contents);
if(resultStackIdx > (MAX_RESULT_STACK - 256))
{
program = popResult();
cleanupResults(resultIdxSave);
pushResult(program);
}
}
if(proc != nilCell)
{
memcpy(errorJump, errorJumpSave, (sizeof(jmp_buf)));
evalCatchFlag--;
}
currentContext = contextSave;
return(resultCell);
}
CELL * p_curry(CELL * params)
{
CELL * lambda;
CELL * cell;
SYMBOL * xPtr;
xPtr = translateCreateSymbol("_x", CELL_NIL, currentContext, TRUE);
lambda = getCell(CELL_LAMBDA);
cell = getCell(CELL_EXPRESSION);
lambda->contents = (UINT)cell;
cell->contents = (UINT)stuffSymbol(xPtr);
cell->next = getCell(CELL_EXPRESSION);
cell = cell->next;
cell->contents = (UINT)copyCell(params);
cell = (CELL *)cell->contents;
cell->next = copyCell(params->next);
cell = cell->next;
cell->next = stuffSymbol(xPtr);
return(lambda);
}
CELL * p_apply(CELL * params)
{
CELL * expr;
CELL * args;
CELL * cell;
CELL * result;
CELL * func;
ssize_t count, cnt;
int resultIdxSave;
func = evaluateExpression(params);
cell = copyCell(func);
expr = getCell(CELL_EXPRESSION);
expr->contents = (UINT)cell;
params = params->next;
args = evaluateExpression(params);
if(params->next != nilCell)
getInteger(params->next, (UINT *)&count);
else count = 0x7FFFFFFF;
if(count < 2) count = 2;
resultIdxSave = resultStackIdx + 2;
if(args->type == CELL_EXPRESSION)
{
args = (CELL *)args->contents;
cnt = count;
REDUCE:
while(args != nilCell && cnt-- > 0)
{
if(isSelfEval(args->type))
{
cell->next = copyCell(args);
cell = cell->next;
}
else
{
cell->next = getCell(CELL_QUOTE);
cell = cell->next;
cell->contents = (UINT)copyCell(args);
}
args = args->next;
}
pushResult(expr);
result = copyCell(evaluateExpression(expr));
if(args == nilCell) return(result);
cell = copyCell(func);
expr = getCell(CELL_EXPRESSION);
expr->contents = (UINT)cell;
cell->next = getCell(CELL_QUOTE);
cell = cell->next;
cell->contents = (UINT)result;
cnt = count - 1;
cleanupResults(resultIdxSave);
goto REDUCE;
}
pushResult(expr);
return(copyCell(evaluateExpression(expr)));
}
CELL * p_args(CELL * params)
{
if(params != nilCell)
return(copyCell(implicitIndexList((CELL*)argsSymbol->contents, params)));
return(copyCell((CELL*)argsSymbol->contents));
}
/* in-place expansion, if symbol==NULL all uppercase, nil vars are expanded */
CELL * expand(CELL * expr, SYMBOL * symbol)
{
CELL * cell = nilCell;
SYMBOL * sPtr;
int enable = 1;
CELL * cont, * rep;
#ifdef SUPPORT_UTF8
int wchar;
#endif
if(expr->type == CELL_SYMBOL)
return(expr);
/*
return(copyCell(expr));
*/
if(isEnvelope(expr->type))
cell = (CELL*)expr->contents;
while(cell != nilCell)
{
if(cell->type == CELL_SYMBOL && (cell->contents == (UINT)symbol || symbol == NULL) )
{
sPtr = (SYMBOL *)cell->contents;
if(symbol == NULL)
{
#ifndef SUPPORT_UTF8
enable = (toupper(*sPtr->name) == *sPtr->name);
#else
utf8_wchar(sPtr->name, &wchar);
enable = (towupper(wchar) == wchar);
#endif
cont = (CELL*)sPtr->contents;
enable = (enable && cont->contents != (UINT)nilCell
&& cont->contents != (UINT)nilSymbol);
}
if(symbol || enable)
{
rep = copyCell((CELL*)sPtr->contents);
cell->type = rep->type;
cell->aux = rep->aux;
cell->contents = rep->contents;
rep->type = CELL_LONG;
rep->aux = 0;
rep->contents = 0;
deleteList(rep);
}
}
else if(isEnvelope(cell->type)) expand(cell, symbol);
cell = cell->next;
}
return(expr);
}
CELL * blockExpand(CELL * block, SYMBOL * symbol)
{
CELL * expanded = nilCell;
CELL * next = nilCell;
while(block != nilCell)
{
if(expanded == nilCell)
{
next = expand(copyCell(block), symbol);
expanded = next;
}
else
{
next->next = expand(copyCell(block), symbol);
next = next->next;
}
block = block->next;
}
return(expanded);
}
CELL * p_expand(CELL * params)
{
SYMBOL * symbol;
CELL * expr;
CELL * next;
CELL * list;
CELL * cell;
expr = evaluateExpression(params);
if(!isList(expr->type) && expr->type != CELL_QUOTE)
return(errorProcExt(ERR_LIST_EXPECTED, expr));
params = next = params->next;
if(params == nilCell)
return(expand(copyCell(expr), NULL));
while((params = next) != nilCell)
{
next = params->next;
params = evaluateExpression(params);
if(params->type == CELL_SYMBOL)
symbol = (SYMBOL*)params->contents;
else if(params->type == CELL_DYN_SYMBOL)
symbol = getDynamicSymbol(params);
else if(params->type == CELL_EXPRESSION)
{
list = (CELL*)params->contents;
while(list != nilCell)
{
if(list->type != CELL_EXPRESSION)
return(errorProcExt(ERR_LIST_EXPECTED, list));
cell = (CELL *)list->contents;
if(cell->type != CELL_SYMBOL)
return(errorProcExt(ERR_SYMBOL_EXPECTED, cell));
symbol = (SYMBOL*)cell->contents;
pushEnvironment(symbol->contents);
pushEnvironment(symbol);
symbol->contents = (UINT)cell->next;
expr = expand(copyCell(expr), symbol);
symbol = (SYMBOL*)popEnvironment();
symbol->contents = popEnvironment();
pushResult(expr);
list = list->next;
continue;
}
break;
}
else
return(errorProcExt(ERR_LIST_OR_SYMBOL_EXPECTED, params));
expr = expand(copyCell(expr), symbol);
pushResult(expr);
}
return(copyCell(expr));
}
CELL * defineOrMacro(CELL * params, UINT cellType)
{
SYMBOL * symbol;
CELL * argsPtr;
CELL * args;
CELL * lambda;
if(params->type != CELL_EXPRESSION)
return(errorProcExt(ERR_LIST_OR_SYMBOL_EXPECTED, params));
/* symbol to be defined */
argsPtr = (CELL *)params->contents;
if(argsPtr->type != CELL_SYMBOL)
{
if(argsPtr->type == CELL_DYN_SYMBOL)
symbol = getDynamicSymbol(argsPtr);
else
return(errorProcExt(ERR_SYMBOL_EXPECTED, params));
}
else symbol = (SYMBOL *)argsPtr->contents;
if(isProtected(symbol->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, params));
/* local symbols */
argsPtr = copyList(argsPtr->next);
lambda = getCell(cellType);
lambda->aux = (UINT)nilCell;
args = getCell(CELL_EXPRESSION);
args->contents = (UINT)argsPtr;
/* body expressions */
args->next = copyList(params->next);
lambda->contents = (UINT)args;
deleteList((CELL *)symbol->contents);
symbol->contents = (UINT)lambda;
pushResultFlag = FALSE;
return(lambda);
}
#define TYPE_SET 1
#define TYPE_CONSTANT 2
#define TYPE_DEFINE 3
CELL * p_define(CELL * params)
{
if(params->type != CELL_SYMBOL)
{
if(params->type != CELL_DYN_SYMBOL)
return(defineOrMacro(params, CELL_LAMBDA));
return(setDefine(getDynamicSymbol(params), params->next, TYPE_SET));
}
return(setDefine((SYMBOL *)params->contents, params->next, TYPE_SET));
}
CELL * p_defineMacro(CELL * params)
{
return(defineOrMacro(params, CELL_MACRO));
}
CELL * p_setq(CELL * params)
{
SYMBOL * symbol;
CELL * next;
for(;;)
{
if(params->type != CELL_SYMBOL)
{
if(params->type == CELL_DYN_SYMBOL)
symbol = getDynamicSymbol(params);
else
return(errorProcExt(ERR_SYMBOL_EXPECTED, params));
}
else
symbol = (SYMBOL *)params->contents;
params = params->next;
next = params->next;
if(params == nilCell)
return(copyCell((CELL*)symbol->contents));
if(next == nilCell) return(setDefine(symbol, params, TYPE_SET));
setDefine(symbol, params, TYPE_SET);
params = next;
}
}
CELL * p_set(CELL *params)
{
SYMBOL * symbol;
CELL * next;
for(;;)
{
params = getSymbol(params, &symbol);
next = params->next;
if(params == nilCell)
return(copyCell((CELL*)symbol->contents));
if(next == nilCell) return(setDefine(symbol, params, TYPE_SET));
setDefine(symbol, params, TYPE_SET);
params = next;
}
}
CELL * p_constant(CELL *params)
{
SYMBOL * symbol;
CELL * next;
for(;;)
{
params = getSymbol(params, &symbol);
/* protect contexts from being set, but not vars holding contexts */
if(symbolType(symbol) == CELL_CONTEXT && (SYMBOL *)((CELL *)symbol->contents)->contents == symbol)
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbol)));
next = params->next;
if(symbol->context != currentContext)
return(errorProcExt2(ERR_NOT_CURRENT_CONTEXT, stuffSymbol(symbol)));
symbol->flags |= SYMBOL_PROTECTED;
if(params == nilCell)
return(copyCell((CELL*)symbol->contents));
if(next == nilCell) return(setDefine(symbol, params, TYPE_CONSTANT));
setDefine(symbol, params, TYPE_CONSTANT);
params = next;
}
}
CELL * setDefine(SYMBOL * symbol, CELL * params, int type)
{
CELL * cell;
if(isProtected(symbol->flags))
{
if(type == TYPE_CONSTANT)
{
if(symbol == nilSymbol || symbol == trueSymbol)
return(errorProcExt2(ERR_SYMBOL_EXPECTED, stuffSymbol(symbol)));
}
else
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbol)));
}
cell = copyCell(evaluateExpression(params));
deleteList((CELL *)symbol->contents);
symbol->contents = (UINT)(cell);
pushResultFlag = FALSE;
return(cell);
}
CELL * p_global(CELL * params)
{
SYMBOL * sPtr;
do
{
params = getSymbol(params, &sPtr);
if(sPtr->context != mainContext || currentContext != mainContext)
return(errorProcExt2(ERR_NOT_IN_MAIN, stuffSymbol(sPtr)));
else
sPtr->flags |= SYMBOL_GLOBAL;
} while (params != nilCell);
return(stuffSymbol(sPtr));
}
#define LET_STD 0
#define LET_NEST 1
#define LET_EXPAND 2
#define LET_LOCAL 3
CELL * let(CELL * params, int type);
CELL * p_let(CELL * params) { return(let(params, LET_STD)); }
CELL * p_letn(CELL * params) { return(let(params, LET_NEST)); }
CELL * p_letExpand(CELL * params) { return(let(params, LET_EXPAND)); }
CELL * p_local(CELL * params) { return(let(params, LET_LOCAL)); }
CELL * let(CELL * params, int type)
{
CELL * inits;
CELL * cell;
CELL * result = nilCell;
CELL * args = NULL, * list = NULL;
CELL * body;
SYMBOL * symbol;
int localCount = 0;
if(params->type != CELL_EXPRESSION)
return(errorProcExt(ERR_INVALID_LET, params));
/* evaluate symbol assignments in parameter list
handle double syntax classic: (let ((v1 e1) (v2 e2) ...) ...)
and: (let (v1 e1 v2 e2 ...) ...)
*/
inits = (CELL*)params->contents;
body = params->next;
if(type == LET_LOCAL)
{
while(inits != nilCell)
{
if(inits->type != CELL_SYMBOL)
return(errorProcExt(ERR_SYMBOL_EXPECTED, inits));
symbol = (SYMBOL *)inits->contents;
if(isProtected(symbol->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, inits));
pushEnvironment(symbol->contents);
pushEnvironment(symbol);
symbol->contents = (UINT)nilCell;
localCount++;
inits = inits->next;
}
goto EVAL_LET_BODY;
}
while(inits != nilCell)
{
if(inits->type != CELL_EXPRESSION)
{
if(inits->type != CELL_SYMBOL)
return(errorProcExt(ERR_INVALID_LET, inits));
cell = inits;
inits = ((CELL*)cell->next)->next;
}
else
{
cell = (CELL *)inits->contents;
if(cell->type != CELL_SYMBOL)
return(errorProcExt(ERR_SYMBOL_EXPECTED, inits));
inits = inits->next;
}
if(type == LET_STD || type == LET_EXPAND)
{
if(localCount == 0)
list = args = copyCell(evaluateExpression(cell->next));
else
{
args->next = copyCell(evaluateExpression(cell->next));
args = args->next;
}
}
else /* LET_NEST */
{
symbol = (SYMBOL *)cell->contents;
if(isProtected(symbol->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, cell));
args = copyCell(evaluateExpression(cell->next));
pushEnvironment((CELL *)symbol->contents);
pushEnvironment((UINT)symbol);
symbol->contents = (UINT)args;
}
localCount++;
}
/* save symbols and get new bindings */
if(type == LET_STD || type == LET_EXPAND)
{
inits = (CELL*)params->contents;
while(inits != nilCell)
{
if(inits->type == CELL_EXPRESSION)
{
cell = (CELL *)inits->contents;
inits = inits->next;
}
else
{
cell = inits;
inits = ((CELL*)cell->next)->next;
}
symbol = (SYMBOL *)cell->contents;
if(isProtected(symbol->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, cell));
pushEnvironment((CELL *)symbol->contents);
pushEnvironment((UINT)symbol);
symbol->contents = (UINT)list;
args = list;
list = list->next;
args->next = nilCell; /* decouple */
/* hook in LET_EXPAND mode here */
if(type == LET_EXPAND)
{
body = blockExpand(body, symbol);
pushResult(body);
}
}
}
EVAL_LET_BODY:
/* evaluate body expressions */
while(body != nilCell)
{
if(result != nilCell) deleteList(result);
result = copyCell(evaluateExpression(body));
body = body->next;
}
/* restore environment */
while(localCount--)
{
symbol = (SYMBOL *)popEnvironment();
if(isProtected(symbol->flags) && (symbol != argsSymbol))
symbol->flags &= ~SYMBOL_PROTECTED;
deleteList((CELL *)symbol->contents);
symbol->contents = popEnvironment();
}
return(result);
}
CELL * p_first(CELL * params)
{
char str[2];
CELL * cell;
cell = evaluateExpression(params);
if(cell->type == CELL_STRING)
{
if((str[0] = *(char *)cell->contents) == 0)
return(stuffString(""));
#ifndef SUPPORT_UTF8
str[1] = 0;
return(stuffString(str));
#else
return(stuffStringN((char*)cell->contents, utf8_1st_len((char*)cell->contents)));
#endif
}
else if(isList(cell->type))
return(copyCell((CELL *)cell->contents));
else if(cell->type == CELL_ARRAY)
return(copyCell(*(CELL * *)cell->contents));
return(errorProcExt(ERR_ARRAY_LIST_OR_STRING_EXPECTED, params));
}
CELL * p_rest(CELL * params)
{
CELL * cell;
CELL * tail;
cell = evaluateExpression(params);
if(cell->type == CELL_STRING)
{
if(*(char *)cell->contents == 0)
return(stuffString(""));
#ifndef SUPPORT_UTF8
return(stuffString((char *)(cell->contents + 1)));
#else
return(stuffString((char *)(cell->contents + utf8_1st_len((char *)cell->contents))));
#endif
}
else if(isList(cell->type))
{
tail = getCell(CELL_EXPRESSION);
tail->contents = (UINT)copyList(((CELL*)cell->contents)->next);
return(tail);
}
else if(cell->type == CELL_ARRAY)
return(subarray(cell, 1, MAX_LONG));
return(errorProcExt(ERR_ARRAY_LIST_OR_STRING_EXPECTED, params));
}
CELL * implicitNrestSlice(CELL * num, CELL * params)
{
CELL * list;
CELL * rest;
ssize_t n, len;
getIntegerExt(num, (UINT *)&n, FALSE);
list = evaluateExpression(params);
if(list->type == CELL_CONTEXT)
list = (CELL *)(translateCreateSymbol(
((SYMBOL*)list->contents)->name,
CELL_NIL,
(SYMBOL*)list->contents,
TRUE))->contents;
/* slice */
if(isNumber(list->type))
{
getIntegerExt(list, (UINT*)&len, FALSE);
list = evaluateExpression(params->next);
if(list->type == CELL_CONTEXT)
list = (CELL *)(translateCreateSymbol(
((SYMBOL*)list->contents)->name,
CELL_NIL,
(SYMBOL*)list->contents,
TRUE))->contents;
if(isList(list->type))
return(sublist((CELL *)list->contents, n, len));
else if(list->type == CELL_STRING)
return(substring((char *)list->contents, list->aux-1, n, len));
else if(list->type == CELL_ARRAY)
return(subarray(list, n, len));
}
/* nrest lists */
else if(isList(list->type))
{
list = (CELL *)list->contents;
if(n < 0) n = convertNegativeOffset(n, list);
while(n-- && list != nilCell)
list = list->next;
rest = getCell(CELL_EXPRESSION);
rest->contents = (UINT)copyList(list);
return(rest);
}
/* nrest strings
this was UTF-8 sensitive before 9.1.11, but only the
explicit first/last/rest should be UTF8-sensitive
*/
else if(list->type == CELL_STRING)
return(substring((char *)list->contents, list->aux - 1, n, MAX_LONG));
else if(list->type == CELL_ARRAY)
return(subarray(list, n, MAX_LONG));
return(errorProcExt(ERR_ILLEGAL_TYPE, params));
}
CELL * p_cons(CELL * params)
{
CELL * cons;
CELL * head;
CELL * tail;
if(params == nilCell)
return(getCell(CELL_EXPRESSION));
head = copyCell(evaluateExpression(params));
cons = getCell(CELL_EXPRESSION);
cons->contents = (UINT)head;
params = params->next;
if(params != nilCell)
{
tail = evaluateExpression(params);
if(isList(tail->type))
{
if(params->next != nilCell)
{
if(((CELL*)params->next)->contents == -1)
{
cons->contents = (UINT)copyList((CELL *)tail->contents);
tail = (CELL*)cons->contents;
while(tail->next != nilCell)
tail = tail->next;
tail->next = head;
return(cons);
}
}
head->next = copyList((CELL *)tail->contents);
cons->type = tail->type;
}
else
head->next = copyCell(tail);
}
return(cons);
}
CELL * p_list(CELL * params)
{
CELL * list;
CELL * lastCopy;
CELL * copy;
CELL * cell;
int resultIdxSave;
list = getCell(CELL_EXPRESSION);
lastCopy = NULL;
resultIdxSave = resultStackIdx;
while(params != nilCell)
{
cell = evaluateExpression(params);
if(cell->type == CELL_ARRAY)
copy = arrayList(cell);
else
copy = copyCell(cell);
if(copy != nilCell)
{
if(lastCopy == NULL)
list->contents = (UINT)copy;
else lastCopy->next = copy;
}
params = params->next;
lastCopy = copy;
cleanupResults(resultIdxSave);
}
return(list);
}
CELL * p_last(CELL * params)
{
CELL * list;
char * str;
#ifdef SUPPORT_UTF8
char * ptr;
int len;
#endif
list = evaluateExpression(params);
if(list->type == CELL_STRING)
{
str = (char *)list->contents;
#ifndef SUPPORT_UTF8
return(stuffString(str + list->aux - 2));
#else
ptr = str;
while((len = utf8_1st_len(str)) != 0)
{
ptr = str;
str += len;
}
return(stuffStringN(ptr, utf8_1st_len(ptr)));
#endif
}
else if(isList(list->type))
{
list = (CELL *)list->contents;
while(list->next != nilCell) list = list->next;
return(copyCell(list));
}
else if(list->type == CELL_ARRAY)
return(copyCell(*((CELL * *)list->contents + (list->aux - 1) / sizeof(UINT) - 1)));
return(errorProcExt(ERR_ARRAY_LIST_OR_STRING_EXPECTED, params));
}
/* -------------------------- program flow and logical ------------------ */
CELL * evaluateBlock(CELL * cell)
{
CELL * result;
result = nilCell;
while(cell != nilCell)
{
result = evaluateExpression(cell);
cell = cell->next;
}
return(result);
}
CELL * p_if(CELL * params)
{
CELL * cell;
cell = evaluateExpression(params);
while(isNil(cell) || isEmpty(cell))
{
params = params->next;
if(params->next == nilCell)
return(copyCell(cell));
params = params->next;
cell = evaluateExpression(params);
}
if(params->next == nilCell) return(copyCell(cell));
return((copyCell(evaluateExpression(params->next))));
}
CELL * p_unless(CELL * params)
{
CELL * cell;
cell = evaluateExpression(params);
if(!isNil(cell) && !isEmpty(cell))
params = params->next;
return((copyCell(evaluateExpression(params->next))));
}
CELL * p_condition(CELL * params)
{
CELL * condition;
CELL * eval = nilCell;
while(params != nilCell)
{
if(params->type == CELL_EXPRESSION)
{
condition = (CELL *)params->contents;
eval = evaluateExpression(condition);
if(!isNil(eval) && !isEmpty(eval))
{
if(condition->next != nilCell)
return(copyCell(evaluateBlock(condition->next)));
return(copyCell(eval));
}
params = params->next;
}
else return(errorProc(ERR_LIST_EXPECTED));
}
return(copyCell(eval));
}
CELL * p_case(CELL * params)
{
CELL * cases;
CELL * cond;
cases = params->next;
params = evaluateExpression(params);
while(cases != nilCell)
{
if(cases->type == CELL_EXPRESSION)
{
cond = (CELL *)cases->contents;
if(compareCells(params, cond) == 0
|| (cond->type == CELL_SYMBOL && symbolType((SYMBOL *)cond->contents) == CELL_TRUE)
|| cond->type == CELL_TRUE)
return(copyCell(evaluateBlock(cond->next)));
}
cases = cases->next;
}
return(nilCell);
}
#define REPEAT_WHILE 0
#define REPEAT_DOWHILE 1
#define REPEAT_UNTIL 2
#define REPEAT_DOUNTIL 3
CELL * p_while(CELL * params) { return(repeat(params, REPEAT_WHILE)); }
CELL * p_doWhile(CELL * params) { return(repeat(params, REPEAT_DOWHILE)); }
CELL * p_until(CELL * params) { return(repeat(params, REPEAT_UNTIL)); }
CELL * p_doUntil(CELL * params) { return(repeat(params, REPEAT_DOUNTIL)); }
/* in 9.0.11 back to 8.8.3 behaviour, speed impact too big on some
algorithms
*/
#define OLD
#ifdef OLD
CELL * repeat(CELL * params, int type)
{
CELL * result;
CELL * cell;
int resultIdxSave;
resultIdxSave = resultStackIdx;
result = nilCell;
while(TRUE)
{
switch(type)
{
case REPEAT_WHILE:
cell = evaluateExpression(params);
if(isNil(cell) || isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
result = evaluateBlock(params->next);
continue;
case REPEAT_DOWHILE:
result = evaluateBlock(params->next);
cell = evaluateExpression(params);
if(isNil(cell) || isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
continue;
case REPEAT_UNTIL:
cell = evaluateExpression(params);
if(!isNil(cell) && !isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
result = evaluateBlock(params->next);
continue;
case REPEAT_DOUNTIL:
result = evaluateBlock(params->next);
cell = evaluateExpression(params);
if(!isNil(cell) && !isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
continue;
default:
break;
}
}
END_REPEAT:
return(copyCell(result));
}
#endif
#ifdef POST_8_8_3
CELL * repeat(CELL * params, int type)
{
CELL * result;
CELL * cell;
int resultIdxSave;
resultIdxSave = resultStackIdx;
result = nilCell;
while(TRUE)
{
switch(type)
{
case REPEAT_WHILE:
cell = evaluateExpression(params);
if(isNil(cell) || isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
deleteList(result);
result = copyCell(evaluateBlock(params->next));
continue;
case REPEAT_DOWHILE:
deleteList(result);
result = copyCell(evaluateBlock(params->next));
cell = evaluateExpression(params);
if(isNil(cell) || isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
continue;
case REPEAT_UNTIL:
cell = evaluateExpression(params);
if(!isNil(cell) && !isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
deleteList(result);
result = copyCell(evaluateBlock(params->next));
continue;
case REPEAT_DOUNTIL:
deleteList(result);
result = copyCell(evaluateBlock(params->next));
cell = evaluateExpression(params);
if(!isNil(cell) && !isEmpty(cell)) goto END_REPEAT;
cleanupResults(resultIdxSave);
continue;
default:
break;
}
}
END_REPEAT:
return(result);
}
#endif
CELL * getPushSymbolParam(CELL * params, SYMBOL * * sym)
{
SYMBOL * symbol;
CELL * cell;
if(params->type != CELL_EXPRESSION)
return(errorProcExt(ERR_LIST_EXPECTED, params));
cell = (CELL *)params->contents;
if(cell->type != CELL_SYMBOL)
return(errorProcExt(ERR_SYMBOL_EXPECTED, cell));
*sym = symbol = (SYMBOL *)cell->contents;
if(isProtected(symbol->flags))
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbol)));
pushEnvironment((CELL *)symbol->contents);
pushEnvironment((UINT)symbol);
symbol->contents = (UINT)nilCell;
return(cell->next);
}
CELL * loop(CELL * params, int forFlag)
{
CELL * cell;
CELL * cond = nilCell;
CELL * block;
SYMBOL * symbol;
double fromFlt, toFlt, interval, step, cntFlt;
INT64 stepCnt, i;
INT64 fromInt64, toInt64;
int intFlag;
int resultIdxSave;
cell = getPushSymbolParam(params, &symbol);
/* integer loops for dotimes and (for (i from to) ...) */
if((intFlag = ((CELL *)cell->next)->next == nilCell))
{
if(forFlag)
{
cell = getInteger64(cell, &fromInt64);
getInteger64(cell, &toInt64);
stepCnt = (toInt64 > fromInt64) ? toInt64 - fromInt64 : fromInt64 - toInt64;
}
else /* dotimes */
{
fromInt64 = toInt64 = 0;
cond = getInteger64(cell, &stepCnt);
}
}
else /* float (for (i from to step) ...) */
{
cell = getFloat(cell, &fromFlt);
cell = getFloat(cell, &toFlt);
cond = getFloat(cell, &step);
if(isnan(fromFlt) || isnan(toFlt) || isnan(step))
return(errorProc(ERR_INVALID_PARAMETER_NAN));
if(step < 0) step = -step;
if(fromFlt > toFlt) step = -step;
cntFlt = (fromFlt < toFlt) ? (toFlt - fromFlt)/step : (fromFlt - toFlt)/step;
stepCnt = (cntFlt > 0.0) ? floor(cntFlt + 0.0000000001) : floor(-cntFlt + 0.0000000001);
}
block = params->next;
resultIdxSave = resultStackIdx;
cell = nilCell;
for(i = 0; i <= stepCnt; i++)
{
if(!forFlag && i == stepCnt) break;
deleteList((CELL *)symbol->contents);
if(intFlag)
{
symbol->contents =
(UINT)stuffInteger64((fromInt64 > toInt64) ? fromInt64 - i:
fromInt64 + i);
}
else
{
interval = fromFlt + i * step;
symbol->contents = (UINT)stuffFloat(&interval);
}
cleanupResults(resultIdxSave);
if(cond != nilCell)
{
cell = evaluateExpression(cond);
if(!isNil(cell)) break;
}
cell = evaluateBlock(block);
}
cell = copyCell(cell);
deleteList((CELL *)symbol->contents);
symbol = (SYMBOL*)popEnvironment();
symbol->flags &= ~SYMBOL_PROTECTED;
symbol->contents = (UINT)popEnvironment();
return(cell);
}
CELL * p_dotimes(CELL * params)
{
return(loop(params, 0));
}
CELL * p_for(CELL * params)
{
return(loop(params, 1));
}
CELL * p_dolist(CELL * params)
{
return(dolist(params, 0));
}
CELL * p_doargs(CELL * params)
{
return(dolist(params, 1));
}
CELL * dolist(CELL * params, int argsFlag)
{
CELL * cell;
CELL * list;
CELL * cond;
SYMBOL * symbol;
CELL * cellIdx;
CELL * result;
int resultIdxSave;
cell = getPushSymbolParam(params, &symbol);
pushEnvironment(dolistIdxSymbol->contents);
pushEnvironment(dolistIdxSymbol);
cellIdx = stuffInteger(0);
dolistIdxSymbol->contents = (UINT)cellIdx;
/* back to pre 8.3.2 behaviour, copying the list,
but now list destruction on result stack to be
safe for throw */
if(argsFlag)
{
list = copyCell((CELL *)argsSymbol->contents);
cond = cell;
}
else
{
list = copyCell(evaluateExpression(cell));
if(!isList(list->type))
return(errorProcExt(ERR_LIST_EXPECTED, cell));
cond = cell->next;
}
/* make sure worklist gets destroyed */
pushResult(list);
list = (CELL *)list->contents;
resultIdxSave = resultStackIdx;
cell = nilCell;
while(list!= nilCell)
{
cleanupResults(resultIdxSave);
deleteList((CELL *)symbol->contents);
symbol->contents = (UINT)copyCell(list);
if(cond != nilCell)
{
cell = evaluateExpression(cond);
if(!isNil(cell)) break;
}
cell = evaluateBlock(params->next);
cellIdx->contents += 1;
list = list->next;
}
result = copyCell(cell);
deleteList(cellIdx);
dolistIdxSymbol = (SYMBOL*)popEnvironment();
dolistIdxSymbol->contents = (UINT)popEnvironment();
deleteList((CELL *)symbol->contents);
symbol = (SYMBOL*)popEnvironment();
symbol->contents = (UINT)popEnvironment();
return(result);
}
CELL * p_evalBlock(CELL * params)
{
return(copyCell(evaluateBlock(params)));
}
CELL * p_silent(CELL * params)
{
evalSilent = TRUE;
return(copyCell(evaluateBlock(params)));
}
CELL * p_and(CELL * params)
{
CELL * result = nilCell;
while(params != nilCell)
{
result = evaluateExpression(params);
if(isNil(result) || isEmpty(result)) return(copyCell(result));
params = params->next;
}
return(copyCell(result));
}
CELL * p_or(CELL * params)
{
CELL * result = nilCell;
while(params != nilCell)
{
result = evaluateExpression(params);
if(!isNil(result) && !isEmpty(result))
return(copyCell(result));
params = params->next;
}
return(copyCell(result));
}
CELL * p_not(CELL * params)
{
CELL * eval;
eval = evaluateExpression(params);
if(isNil(eval) || isEmpty(eval))
return(trueCell);
return(nilCell);
}
/* ------------------------------ I / O --------------------------------- */
CELL * p_print(CELL * params)
{
return println(params, FALSE);
}
CELL * p_println(CELL * params)
{
return println(params, TRUE);
}
CELL * println(CELL * params, int lineFeed)
{
CELL * result;
result = nilCell;
while(params != nilCell)
{
result = evaluateExpression(params);
if(printCell(result, 0, OUT_DEVICE) == 0)
return(nilCell);
params = params->next;
}
if(lineFeed) varPrintf(OUT_DEVICE, LINE_FEED);
return(copyCell(result));
}
CELL * p_device(CELL * params)
{
if(params != nilCell)
getInteger(params, &printDevice);
return(stuffInteger(printDevice));
}
CELL * p_load(CELL * params)
{
char * fileName;
CELL * result = nilCell;
CELL * next;
SYMBOL * context;
int count = 0;
/* get last parameter */
if((next = params) == nilCell)
errorProc(ERR_MISSING_ARGUMENT);
while(next->next != nilCell)
{
count++;
next = next->next;
}
next = evaluateExpression(next);
if(next->type == CELL_STRING)
{
count++;
context = mainContext;
}
else
{
if(count == 0)
errorProcExt(ERR_STRING_EXPECTED, next);
if((context = getCreateContext(next, FALSE)) == NULL)
errorProcExt(ERR_SYMBOL_OR_CONTEXT_EXPECTED, next);
next = NULL;
}
while(count--)
{
/* if last arg was a string, avoid double evaluation */
if(count == 0 && next != NULL)
getStringSize(next, &fileName, NULL, FALSE);
else
params = getString(params, &fileName);
result = loadFile(fileName, 0, 0, context);
if(result == NULL)
return(errorProcExt2(ERR_ACCESSING_FILE, stuffString(fileName)));
}
return(result);
}
void saveContext(SYMBOL * sPtr, UINT device)
{
SYMBOL * contextSave;
contextSave = currentContext;
currentContext = sPtr;
if(sPtr != mainContext)
varPrintf(device, "%s(context '%s)%s%s",
LINE_FEED, sPtr->name, LINE_FEED, LINE_FEED);
saveSymbols((SYMBOL *)((CELL*)sPtr->contents)->aux, device);
if(sPtr != mainContext)
varPrintf(device, "%s(context 'MAIN)%s%s",
LINE_FEED, LINE_FEED, LINE_FEED);
currentContext = contextSave;
}
void saveSymbols(SYMBOL * sPtr, UINT device)
{
int type;
if(sPtr != NIL_SYM && sPtr != NULL)
{
saveSymbols(sPtr->left, device);
type = symbolType(sPtr);
if(type == CELL_CONTEXT)
{
if(sPtr == (SYMBOL *)((CELL *)sPtr->contents)->contents)
{
if(sPtr != currentContext) saveContext(sPtr, device);
}
else printSymbol(sPtr, device);
}
else if(type != CELL_PRIMITIVE && type != CELL_NIL
&& sPtr != trueSymbol && type != CELL_IMPORT_CDECL
&& sPtr != argsSymbol
#ifdef WIN_32
&& type != CELL_IMPORT_DLL
#endif
)
if(*sPtr->name != '$') printSymbol(sPtr, device);
saveSymbols(sPtr->right, device);
}
}
CELL * p_save(CELL * params)
{
char * fileName;
STREAM strStream;
UINT printDeviceSave;
CELL * result;
SYMBOL * contextSave;
CELL * dataCell;
contextSave = currentContext;
currentContext = mainContext;
printDeviceSave = printDevice;
params = getString(params, &fileName);
/* check for URL format */
if(my_strnicmp(fileName, "http://", 7) == 0)
{
openStrStream(&strStream, MAX_STRING, 0);
serializeSymbols(params, (UINT)&strStream);
dataCell = stuffString(strStream.buffer);
result = getPutPostDeleteUrl(fileName, dataCell, HTTP_PUT_URL, 60000);
closeStrStream(&strStream);
deleteList(dataCell);
return(result);
}
else
{
if(my_strnicmp(fileName, "file://", 7) == 0)
fileName = fileName + 7;
if( (printDevice = (UINT)openFile(fileName, "write", NULL)) == (UINT)-1)
return(errorProcExt2(ERR_SAVING_FILE, stuffString(fileName)));
serializeSymbols(params, OUT_DEVICE);
close((int)printDevice);
}
currentContext = contextSave;
printDevice = printDeviceSave;
return(trueCell);
}
void serializeSymbols(CELL * params, UINT device)
{
SYMBOL * sPtr;
if(params->type == CELL_NIL)
saveSymbols((SYMBOL *)((CELL*)currentContext->contents)->aux, device);
else
while(params != nilCell)
{
params = getSymbol(params, &sPtr);
if(symbolType(sPtr) == CELL_CONTEXT)
saveContext((SYMBOL*)((CELL *)sPtr->contents)->contents, device);
else
printSymbol(sPtr, device);
}
}
/* ----------------------- copy a context with 'new' -------------- */
static SYMBOL * fromContext;
static SYMBOL * newContext;
static int overWriteFlag;
CELL * copyContextList(CELL * cell);
UINT * copyContextArray(CELL * array);
CELL * copyContextCell(CELL * cell)
{
CELL * newCell;
SYMBOL * sPtr;
SYMBOL * newSptr;
if(firstFreeCell == NULL) allocBlock();
newCell = firstFreeCell;
firstFreeCell = newCell->next;
++cellCount;
newCell->type = cell->type;
newCell->next = nilCell;
newCell->aux = cell->aux;
newCell->contents = cell->contents;
if(cell->type == CELL_DYN_SYMBOL)
{
sPtr = (SYMBOL*)cell->aux;
if(sPtr->context == fromContext)
newCell->aux =
(UINT)translateCreateSymbol(sPtr->name, 0, newContext, TRUE);
newCell->contents = (UINT)allocMemory(strlen((char *)cell->contents) + 1);
memcpy((void *)newCell->contents,
(void*)cell->contents, strlen((char *)cell->contents) + 1);
}
if(cell->type == CELL_SYMBOL)
{
/* if the cell copied itself contains a symbol copy it recursevely,
if new, if not done here it might not been seen as new later and left
without contents */
sPtr = (SYMBOL *)cell->contents;
if(sPtr->context == fromContext && !(sPtr->flags & SYMBOL_BUILTIN))
{
if((newSptr = lookupSymbol(sPtr->name, newContext)) == NULL)
{
newSptr = translateCreateSymbol(sPtr->name, symbolType(sPtr), newContext, TRUE);
newSptr->contents = (UINT)copyContextCell((CELL*)sPtr->contents);
}
newCell->contents = (UINT)newSptr;
}
}
if(isEnvelope(cell->type))
{
if(cell->type == CELL_ARRAY)
newCell->contents = (UINT)copyContextArray(cell);
else
newCell->contents = (UINT)copyContextList((CELL *)cell->contents);
}
else if(cell->type == CELL_STRING)
{
newCell->contents = (UINT)allocMemory((UINT)cell->aux);
memcpy((void *)newCell->contents,
(void*)cell->contents, (UINT)cell->aux);
}
return(newCell);
}
CELL * copyContextList(CELL * cell)
{
CELL * firstCell;
CELL * newCell;
if(cell == nilCell || cell == trueCell) return(cell);
firstCell = newCell = copyContextCell(cell);
while((cell = cell->next) != nilCell)
{
newCell->next = copyContextCell(cell);
newCell = newCell->next;
}
return(firstCell);
}
UINT * copyContextArray(CELL * array)
{
CELL * * newAddr;
CELL * * orgAddr;
CELL * * addr;
size_t size;
addr = newAddr = (CELL * *)callocMemory(array->aux);
size = (array->aux - 1) / sizeof(UINT);
orgAddr = (CELL * *)array->contents;
while(size--)
*(newAddr++) = copyContextCell(*(orgAddr++));
return((UINT*)addr);
}
void iterateSymbols(SYMBOL * sPtr)
{
int type, newFlag = FALSE;
SYMBOL * newPtr;
if(sPtr != NIL_SYM && sPtr != NULL && !(sPtr->flags & SYMBOL_BUILTIN))
{
iterateSymbols(sPtr->left);
type = symbolType(sPtr);
/* check for default symbol */
if(*sPtr->name == *fromContext->name && strcmp(sPtr->name, fromContext->name) == 0)
{
if((newPtr = lookupSymbol(newContext->name, newContext)) == NULL)
{
newPtr = translateCreateSymbol(newContext->name, type, newContext, TRUE);
newFlag = TRUE;
}
}
else
{
if((newPtr = lookupSymbol(sPtr->name, newContext)) == NULL)
{
newPtr = translateCreateSymbol(sPtr->name, type, newContext, TRUE);
newFlag = TRUE;
}
}
if(overWriteFlag == TRUE || newFlag == TRUE)
{
deleteList((CELL *)newPtr->contents);
newPtr->contents = (UINT)copyContextCell((CELL*)sPtr->contents);
}
iterateSymbols(sPtr->right);
}
}
CELL * p_new(CELL * params)
{
CELL * next;
overWriteFlag = FALSE;
params = getContext(params, &fromContext);
if(!fromContext) return(nilCell); /* for debug mode */
next = params->next;
if(params == nilCell)
newContext = currentContext;
else
{
params = evaluateExpression(params);
if(params->type == CELL_CONTEXT || params->type == CELL_SYMBOL)
newContext = (SYMBOL *)params->contents;
else
return(errorProcExt(ERR_CONTEXT_EXPECTED, params));
overWriteFlag = (evaluateExpression(next)->type != CELL_NIL);
/* allow symbols to be converted to contexts */
if(symbolType(newContext) != CELL_CONTEXT)
{
if(isProtected(newContext->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, params));
if(newContext->context != mainContext)
return(errorProcExt2(ERR_NOT_IN_MAIN, stuffSymbol(newContext)));
deleteList((CELL *)newContext->contents);
makeContextFromSymbol(newContext, NULL);
}
}
if(newContext == mainContext)
return(errorProc(ERR_TARGET_NO_MAIN));
iterateSymbols((SYMBOL *)((CELL*)fromContext->contents)->aux);
return(copyCell((CELL*)newContext->contents));
}
CELL * p_defineNew(CELL * params)
{
SYMBOL * sourcePtr;
SYMBOL * targetPtr;
char * name;
params = getSymbol(params, &sourcePtr);
if(params != nilCell)
{
params = getSymbol(params, &targetPtr);
name = targetPtr->name;
newContext = targetPtr->context;
}
else
{
name = sourcePtr->name;
newContext = currentContext;
}
if(newContext == mainContext)
return(errorProc(ERR_TARGET_NO_MAIN));
fromContext = sourcePtr->context;
targetPtr = translateCreateSymbol(name, symbolType(sourcePtr), newContext, TRUE);
deleteList((CELL *)targetPtr->contents);
targetPtr->contents = (UINT)copyContextCell((CELL*)sourcePtr->contents);
return(stuffSymbol(targetPtr));
}
/* ------------------------------ system ------------------------------ */
CELL * isType(CELL *, int);
CELL * p_isNil(CELL * params)
{
if(isNil(evaluateExpression(params)))
return(trueCell);
return(nilCell);
}
CELL * p_isEmpty(CELL * params)
{
return(isEmptyFunc(evaluateExpression(params)));
}
CELL * isEmptyFunc(CELL * cell)
{
if(cell->type == CELL_STRING)
{
if(*(char*)cell->contents == 0)
return(trueCell);
else return(nilCell);
}
if(!isList(cell->type))
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, cell));
if(cell->contents == (UINT)nilCell)
return(trueCell);
return(nilCell);
}
CELL * isZero(CELL * cell)
{
#ifndef NEWLISP64
if(cell->type == CELL_INT64)
{
if(*(INT64 *)&cell->aux == 0)
return(trueCell);
else
return(nilCell);
}
#endif
if(cell->type == CELL_FLOAT)
{
#ifndef NEWLISP64
if(*(double *)&cell->aux == 0.0)
#else
if(*(double *)&cell->contents == 0.0)
#endif
return(trueCell);
else
return(nilCell);
}
if(cell->type == CELL_LONG)
{
if(cell->contents == 0)
return(trueCell);
}
return(nilCell);
}
CELL * p_isNull(CELL * params)
{
CELL * cell;
cell = evaluateExpression(params);
if(isNil(cell))
return(trueCell);
if( (cell->type == CELL_STRING || isList(cell->type)))
return(isEmptyFunc(cell));
#ifndef NEWLISP64
if(cell->type == CELL_FLOAT && (isnan(*(double *)&cell->aux)) )
#else
if(cell->type == CELL_FLOAT && (isnan(*(double *)&cell->contents)))
#endif
return(trueCell);
return(isZero(cell));
}
CELL * p_isZero(CELL * params)
{
params = evaluateExpression(params);
return(isZero(params));
}
CELL * p_isTrue(CELL * params)
{
params = evaluateExpression(params);
if(!isNil(params) && !isEmpty(params))
return(trueCell);
return(nilCell);
}
CELL * p_isInteger(CELL * params)
{
params = evaluateExpression(params);
if((params->type & COMPARE_TYPE_MASK) == CELL_INT)
return(trueCell);
return(nilCell);
}
CELL * p_isFloat(CELL * params)
{ return(isType(params, CELL_FLOAT)); }
CELL * p_isNumber(CELL * params)
{
params = evaluateExpression(params);
if(isNumber(params->type)) return(trueCell);
return(nilCell);
}
CELL * p_isString(CELL * params)
{ return(isType(params, CELL_STRING)); }
CELL * p_isSymbol(CELL * params)
{ return(isType(params, CELL_SYMBOL)); }
CELL * p_isContext(CELL * params)
{
char * symStr;
SYMBOL * ctx;
/* check type */
if(params->next == nilCell)
return(isType(params, CELL_CONTEXT));
/* check for existense of symbol */
params = getContext(params, &ctx);
if(!ctx) return(nilCell); /* for debug mode */
getString(params, &symStr);
return (lookupSymbol(symStr, ctx) ? trueCell : nilCell);
}
CELL * p_isPrimitive(CELL * params)
{ return(isType(params, CELL_PRIMITIVE)); }
CELL * p_isGlobal(CELL * params)
{
params = evaluateExpression(params);
if(isSymbol(params->type) && isGlobal(((SYMBOL *)params->contents)->flags))
return(trueCell);
return(nilCell);
}
CELL * p_isProtected(CELL * params)
{
params = evaluateExpression(params);
if(isSymbol(params->type) && isProtected(((SYMBOL *)params->contents)->flags))
return(trueCell);
return(nilCell);
}
CELL * p_isAtom(CELL * params)
{
if(params == nilCell)
return(errorProc(ERR_MISSING_ARGUMENT));
params = evaluateExpression(params);
if(params->type & ENVELOPE_TYPE_MASK) return(nilCell);
return(trueCell);
}
CELL * p_isQuote(CELL *params)
{ return(isType(params, CELL_QUOTE)); }
CELL * p_isList(CELL * params)
{ return(isType(params, CELL_EXPRESSION)); }
CELL * p_isLambda(CELL * params)
{ return(isType(params, CELL_LAMBDA)); }
CELL * p_isMacro(CELL * params)
{ return(isType(params, CELL_MACRO)); }
CELL * p_isArray(CELL * params)
{ return(isType(params, CELL_ARRAY)); }
CELL * isType(CELL * params, int operand)
{
CELL * contextCell;
if(params == nilCell)
return(errorProc(ERR_MISSING_ARGUMENT));
params = evaluateExpression(params);
if((UINT)operand == params->type) return(trueCell);
switch(operand)
{
case CELL_PRIMITIVE:
if(params->type == CELL_IMPORT_CDECL
#ifdef WIN_32
|| params->type == CELL_IMPORT_DLL
#endif
)
return(trueCell);
break;
case CELL_EXPRESSION:
if(isList(params->type)) return(trueCell);
break;
case CELL_SYMBOL:
if(params->type == CELL_DYN_SYMBOL) /* check if already created */
{
contextCell = (CELL *)((SYMBOL *)params->aux)->contents;
if(contextCell->type != CELL_CONTEXT)
fatalError(ERR_CONTEXT_EXPECTED,
stuffSymbol((SYMBOL*)params->aux), TRUE);
if(lookupSymbol((char *)params->contents, (SYMBOL*)contextCell->contents))
return(trueCell);
}
break;
default:
break;
}
return(nilCell);
}
CELL * p_isLegal(CELL * params)
{
char * symStr;
getString(params, &symStr);
if(isLegalSymbol(symStr)) return(trueCell);
return(nilCell);
}
int isLegalSymbol(char * source)
{
STREAM stream;
char token[MAX_SYMBOL + 1];
int tklen;
if(*source == (char)'"' || *source == (char)'{' || *source == (char)'['
|| (unsigned char)*source <= (unsigned char)' ' || *source == (char)';' || *source == (char)'#')
return(0);
makeStreamFromString(&stream, source);
return( (getToken(&stream, token, &tklen) == TKN_SYMBOL) && tklen == strlen(source));
}
CELL * p_exit(CELL * params)
{
UINT result;
if(demonMode)
{
fclose(IOchannel);
#ifndef WIN_32
IOchannel = NULL;
#endif
longjmp(errorJump, ERR_USER_RESET);
}
if(params != nilCell) getInteger(params, (UINT*)&result);
else result = 0;
exit(result);
return(trueCell);
}
CELL * p_reset(CELL * params)
{
#ifndef LIBRARY
#ifndef WIN_32
if (getFlag(params))
execv(MainArgs[0], MainArgs);
#endif
#endif
longjmp(errorJump, ERR_USER_RESET);
return(nilCell);
}
CELL * p_errorEvent(CELL * params)
{
CELL * symCell;
if(params != nilCell) getCreateSymbol(params, &errorEvent, "$error-event");
symCell = getCell(CELL_SYMBOL);
symCell->contents = (UINT)errorEvent;
return(symCell);
}
#ifndef WIN_32
CELL * p_timerEvent(CELL * params)
{
CELL * symCell;
double seconds;
UINT timerOption = 0;
struct itimerval timerVal;
struct itimerval outVal;
static double duration;
if(params != nilCell)
{
params = getCreateSymbol(params, &timerEvent, "$timer");
if(params != nilCell)
{
params = getFloat(params, &seconds);
duration = seconds;
if(params != nilCell)
getInteger(params, (UINT*)&timerOption);
memset(&timerVal, 0, sizeof(timerVal));
timerVal.it_value.tv_sec = seconds;
timerVal.it_value.tv_usec = (seconds - timerVal.it_value.tv_sec) * 1000000;
if(setitimer((int)timerOption, &timerVal, &outVal) == -1)
return(nilCell);
return(stuffInteger(0));
}
else
getitimer(timerOption, &outVal);
seconds = duration - (outVal.it_value.tv_sec + outVal.it_value.tv_usec / 1000000.0);
return(stuffFloat(&seconds));
}
symCell = getCell(CELL_SYMBOL);
symCell->contents = (UINT)timerEvent;
return(symCell);
}
#endif
CELL * p_signal(CELL * params)
{
CELL * symCell;
SYMBOL * signalEvent;
UINT sig;
char sigStr[12];
params = getInteger(params, (UINT *)&sig);
if(sig > 32 || sig < 1) return(nilCell);
if(params != nilCell)
{
if(params->contents == (UINT)nilSymbol)
signalEvent = nilSymbol;
else
{
snprintf(sigStr, 11, "$signal-%ld", sig);
getCreateSymbol(params, &signalEvent, sigStr);
}
symHandler[sig - 1] = signalEvent;
if(signal(sig, signal_handler) == SIG_ERR)
return(nilCell);
}
symCell = getCell(CELL_SYMBOL);
symCell->contents = (UINT)symHandler[sig - 1];
return(symCell);
}
CELL * p_errorNumber(CELL * params)
{
return(stuffInteger((UINT)errorReg));
}
CELL * p_errorText(CELL * params)
{
UINT errorNumber = errorReg;
if(params == nilCell)
{
if(errorStream.buffer != NULL)
return(stuffString(errorStream.buffer));
}
else
getInteger(params, &errorNumber);
if(errorNumber > MAX_ERROR_NUMBER)
errorNumber = ERR_NUMBER_OUT_OF_RANGE;
return(stuffString(errorMessage[errorNumber]));
}
CELL * p_dump(CELL * params)
{
CELL * blockPtr;
int i;
CELL * cell;
if(params != nilCell)
{
cell = evaluateExpression(params);
return(stuffIntegerList
(5, cell, cell->type, cell->next, cell->aux, cell->contents));
}
blockPtr = cellMemory;
while(blockPtr != NULL)
{
for(i = 0; i < MAX_BLOCK; i++)
{
if(*(UINT *)blockPtr != CELL_FREE)
{
varPrintf(OUT_DEVICE, "address=%lX type=%d contents=", blockPtr, blockPtr->type);
printCell(blockPtr, TRUE, OUT_DEVICE);
varPrintf(OUT_DEVICE,LINE_FEED);
}
++blockPtr;
}
blockPtr = blockPtr->next;
}
return(trueCell);
}
CELL * p_mainArgs(CELL * params)
{
CELL * cell;
ssize_t idx;
cell = (CELL*)mainArgsSymbol->contents;
if(params != nilCell)
{
getInteger(params, (UINT *)&idx);
cell = (CELL *)cell->contents;
if(idx < 0) idx = convertNegativeOffset(idx, (CELL *)cell);
while(idx--) cell = cell->next;
}
pushResultFlag = FALSE;
return(cell);
}
CELL * p_context(CELL * params)
{
SYMBOL * sPtr;
SYMBOL * cPtr;
char * newSymStr;
if(params->type == CELL_NIL)
return(copyCell((CELL *)currentContext->contents));
if((cPtr = getCreateContext(params, TRUE)) == NULL)
return(errorProcExt(ERR_SYMBOL_OR_CONTEXT_EXPECTED, params));
if(params->next == nilCell)
{
currentContext = cPtr;
return(copyCell( (CELL *)currentContext->contents));
}
/* create symbol from string contents for context */
params = getString(params->next, &newSymStr);
sPtr = translateCreateSymbol(newSymStr, CELL_NIL, cPtr, TRUE);
if(params == nilCell)
{
pushResultFlag = FALSE;
return(CELL *)sPtr->contents;
}
if(strcmp(cPtr->name, sPtr->name) == 0)
return(nilCell);
return(setDefine(sPtr, params, TYPE_SET));
}
SYMBOL * getCreateContext(CELL * cell, int evaluate)
{
SYMBOL * contextSymbol;
if(evaluate)
cell = evaluateExpression(cell);
if(cell->type == CELL_SYMBOL || cell->type == CELL_CONTEXT)
contextSymbol = (SYMBOL *)cell->contents;
else
return(NULL);
if(symbolType(contextSymbol) != CELL_CONTEXT)
{
if(isProtected(contextSymbol->flags))
return(NULL);
if(contextSymbol->context != mainContext)
{
contextSymbol= translateCreateSymbol(
contextSymbol->name, CELL_CONTEXT, mainContext, 1);
}
if(symbolType(contextSymbol) != CELL_CONTEXT)
{
if(isProtected(contextSymbol->flags))
errorProcExt(ERR_CONTEXT_EXPECTED, stuffSymbol(contextSymbol));
deleteList((CELL *)contextSymbol->contents);
makeContextFromSymbol(contextSymbol, NULL);
}
}
/* if this is a context var retrieve the real context symbol */
return((SYMBOL *)((CELL *)contextSymbol->contents)->contents);
}
CELL * p_default(CELL * params)
{
SYMBOL * contextSymbol;
getContext(params, &contextSymbol);
return(stuffSymbol(translateCreateSymbol(contextSymbol->name, CELL_NIL, contextSymbol, TRUE)));
}
CELL * p_systemSymbol(CELL * params)
{
UINT idx;
getInteger(params, &idx);
if(idx > 15 || idx < 0) return(nilCell);
return(copyCell((CELL*)sysSymbol[idx]->contents));
}
/* end of file */
syntax highlighted by Code2HTML, v. 0.9.1