
Main Program
The main method creates the initial context, fills it up with the
pre-defined names, then handles what the user types. This is
the read-eval-print loop.
//*****************************************************************************
//*** Tom's Lisp Main Program
//***
//*** Tom's lisp is a simple lisp interpreter, neither fast nor standard.
//*** Mostly, the code is reading.
//*****************************************************************************
#include <typeinfo>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
using namespace std;
#include "interrupt.h"
#include "refct.h"
#include "context.h"
#include "evaluable.h"
#include "atoms.h"
#include "builtin.h"
#include "read.h"
// The name of initial file. Can be changed with compile defs.
#ifndef INIT_FILE
#define INIT_FILE "tomsinit.lsp"
#endif
// The name MEM_DEBUG adds memory mgt debuggin code.
// The settings based on the target.
#ifdef WIN32
#define COMP_FOR "Win 32"
// The default search path for all file loads (windows)
#ifndef LSP_PATH
#define LSP_PATH ".;C:\\TOMSLSP;C:\\PROGRAM FILES\\TOMSLSP"
#endif
#else
#define COMP_FOR "Unix/Unix-like"
// The default search path for all file loads.
#ifndef LSP_PATH
#define LSP_PATH ".:/usr/local/lib/tomslsp:/usr/lib/tomslsp"
#endif
#endif
// Also MEM_DEBUG if set adds checks related to debugging the ref count
// memory system.
#define VERSION "0.95"
// Load the file, print an message and exit if the load fails. Used for
// loading the init file and files listed on the command line.
void bload(const char *name, Ptr<Context> c)
{
Ptr<Evaluable> res = load(name, c);
if(res.points_to(typeid(Error))) {
Error::history_off();
cerr << "Error loading " << name << ": ";
res->print(cerr);
cerr << endl;
exit(1);
}
}
int main(int argc, char **argv)
{
// Search path environmet or default.
const char *src;
if(getenv("LSP_PATH")) src = getenv("LSP_PATH");
else src = LSP_PATH;
// Bare mode (parameter). Skips init load.
bool bare = false;
// Do not enter the interactive read-eval-print loop.
bool batch = false;
// Options. The -s can replace search path.
extern char *optarg;
int found;
while((found = getopt(argc, argv, "s:bqBle:S:F:CV")) >= 0) {
switch(found) {
case 's':
src = optarg;
break;
#ifdef MEM_DEBUG
case 'l':
RefCtObj::reporting(atoi(optarg));
break;
#endif
case 'b':
bare = true;
break;
case 'B':
batch = true;
break;
case 'q':
Error::history_off();
break;
case 'e': {
int cnt = atoi(optarg);
int bot = 2*cnt / 3;
Error::toplim(cnt - bot);
Error::botlim(bot); }
break;
case 'S':
Error::toplim(atoi(optarg));
break;
case 'F':
Error::botlim(atoi(optarg));
break;
case 'V':
cout << VERSION << endl;
exit(0);
case 'C':
cout << "Tom's Lisp " << VERSION << " compiled for "
<< COMP_FOR << " systems." << endl;
cout << "Compiled on "
<< __DATE__ << " " << __TIME__ << endl;
#ifdef __VERSION__
cout << "Compiler version: " << __VERSION__ << endl;
#endif
cout << "LSP_PATH = \"" << LSP_PATH << "\"" << endl;
cout << "search path = \"" << src << "\"" << endl;
#ifdef UNBOUND_INTS
cout << "Unbound integer values. ";
#else
cout << "System integer values. ";
#endif
#ifdef MEM_DEBUG
cout << "Memory debug on.";
#endif
cout << endl;
break;
default:
exit(3);
}
}
setsearch(src);
// Set the code values for the built-in error codes.
int enct = set_error_codes();
// Create the main context. This declares the main context object.
Ptr<Context> maincon = Context::alloc();
#ifdef MEM_DEBUG
RefCtObj::rpt("Main context created");
#endif
// This section creates entries in the main context for the standard
// definitions. Most of these are Builtin functions, but there are
// also nil and #t, and Catch is down there a ways.
maincon->set("nil", the_nil);
maincon->set("#t", the_true);
maincon->set("car", Builtin::alloc(bi_car, "car", "p"));
maincon->set("cdr", Builtin::alloc(bi_cdr, "cdr", "p"));
maincon->set("cons", Builtin::alloc(bi_cons, "cons", ".."));
maincon->set("null?", Builtin::alloc(bi_null, "null?", "."));
maincon->set("pair?", Builtin::alloc(bi_ispair, "pair?", "."));
maincon->set("id?", Builtin::alloc(bi_isid, "id?", "."));
maincon->set("int?", Builtin::alloc(bi_isint, "int?", "."));
maincon->set("str?", Builtin::alloc(bi_isstring, "str?", "."));
maincon->set("lambda?", Builtin::alloc(bi_islambda, "lambda?", "."));
maincon->set("macro?", Builtin::alloc(bi_ismacro, "macro?", "."));
maincon->set("builtin?",
Builtin::alloc(bi_isbuiltin, "builtin?", "."));
maincon->set("quote", Builtin::alloc(bi_quote, "quote", ".", false));
maincon->set("eval", Builtin::alloc(bi_eval, "eval", "."));
maincon->set("begin", Builtin::alloc(bi_begin, "begin", "+", false));
maincon->set("cond", Builtin::alloc(bi_cond, "cond", "+", false));
maincon->set("or", Builtin::alloc(bi_or, "or", "+", false));
maincon->set("error", Builtin::alloc(bi_error, "error", "is"));
maincon->set("catch", Catch::alloc());
maincon->set("set", Builtin::alloc(bi_set, "set", "n."));
maincon->set("scope", Builtin::alloc(bi_scope, "scope", "+", false));
maincon->set("macro", Builtin::alloc(bi_macro, "macro", "F.", false));
maincon->set("lambda", Builtin::alloc(bi_lambda, "lambda",
"F.", false));
maincon->set("exit", Builtin::alloc(bi_exit, "exit", "i"));
maincon->set("+", Builtin::alloc(bi_plus, "+", "+i"));
maincon->set("*", Builtin::alloc(bi_times, "*", "+i"));
maincon->set("-", Builtin::alloc(bi_minus, "-", "ii"));
maincon->set("/", Builtin::alloc(bi_div, "/", "ii"));
maincon->set("%", Builtin::alloc(bi_mod, "%", "ii"));
maincon->set("<", Builtin::alloc(bi_lt, "<", "ii"));
maincon->set(">", Builtin::alloc(bi_gt, ">", "ii"));
maincon->set("<=", Builtin::alloc(bi_le, "<=", "ii"));
maincon->set(">=", Builtin::alloc(bi_ge, ">=", "ii"));
maincon->set("=", Builtin::alloc(bi_eq, "=", "ii"));
maincon->set("!=", Builtin::alloc(bi_ne, "!=", "ii"));
maincon->set("eq?", Builtin::alloc(bi_ptreq, "eq?", ".."));
maincon->set("equal?", Builtin::alloc(bi_equal, "equal?", ".."));
maincon->set("strlen", Builtin::alloc(bi_strlen, "strlen", "s"));
maincon->set("shatter", Builtin::alloc(bi_shatter, "shatter", "s"));
maincon->set("collect", Builtin::alloc(bi_collect, "collect", "(+s)"));
maincon->set("chr", Builtin::alloc(bi_chr, "chr", "i"));
maincon->set("ord", Builtin::alloc(bi_ord, "ord", "s"));
maincon->set("load", Builtin::alloc(bi_load, "load", "s"));
maincon->set("print", Builtin::alloc(bi_print, "print", "."));
maincon->set("sprint", Builtin::alloc(bi_sprint, "sprint", "s"));
#ifdef MEM_DEBUG
maincon->set("memrpt", Builtin::alloc(bi_memrpt, "memrpt", ""));
maincon->set("aloc-log", Builtin::alloc(bi_aloc_log, "aloc-log", "i"));
#endif
// Create definitions for the standard error classes.
maincon->set("ERR_UNDEF", Int::alloc(UNDEF));
maincon->set("ERR_BADOP", Int::alloc(BADOP));
maincon->set("ERR_BADARG", Int::alloc(BADARG));
maincon->set("ERR_SHORTARG", Int::alloc(SHORTARG));
maincon->set("ERR_BADTYPE", Int::alloc(BADTYPE));
maincon->set("ERR_LONGARG", Int::alloc(LONGARG));
maincon->set("ERR_RPAREN", Int::alloc(RPAREN));
maincon->set("ERR_SYN", Int::alloc(SYN));
maincon->set("ERR_OPFAIL", Int::alloc(OPFAIL));
maincon->set("ERR_DIVZERO", Int::alloc(DIVZERO));
maincon->set("ERR_INTER", Int::alloc(INTER));
maincon->set("NEXT_ERR", Int::alloc(enct));
// A couple of important environment variables.
if(getenv("USER"))
maincon->set("USER", Str::alloc(getenv("USER")));
if(getenv("HOME"))
maincon->set("HOME", Str::alloc(getenv("HOME")));
// What the heck. Might be useful.
maincon->set("PID", Int::alloc(getpid()));
// Load the standard init file.
if(!bare) bload(INIT_FILE, maincon);
// Load the command line files.
for(argc -= optind, argv += optind; argc--; ++argv)
bload(*argv, maincon);
// For batch mode, we're done.
if(batch) exit(0);
// Main read and print loop. This reads s-expressions from the
// console (standard input), evaluates each, and prints the result.
initsig(); // Init sig handling.
Scanner in(cin, "[standard input]", &cout); // Init tokenizer.
cout << "Welcome to Tom's Lisp " << VERSION << // Welcome msg.
". Recur well." << endl;
#ifdef MEM_DEBUG
RefCtObj::rpt("Before main loop");
#endif
// Read-eval-print loop.
while(in.peek().type != tok_eof) {
// Read.
Ptr<Evaluable> e = read_sexpr(in);
// Reset ^c flag, then evaluate the expression.
signalled = false;
e = e->eval(maincon);
// Print the result.
e->print(cout);
cout << endl;
// Clear the input stream.
in.clear();
}
cout << endl;
#ifdef MEM_DEBUG
// This actually does a bit extra cleanup that we don't bother with
// when we're exiting anyway. But it tests the algorithms.
RefCtObj::rpt("Main loop exit");
maincon->last_rites();
maincon.nullify();
RefCtObj::rpt("Finish");
#endif
}
#ifdef MEM_DEBUG
int RefCtObj::alocnt = 0;
int RefCtObj::alo_rpt = 0;
#endif