lisp:
	proc options(main,stack(4096));
	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/
	%replace
		true   by '1'b,
		false  by '0'b;
	%replace
		expr   by  0,
		fexpr  by  1,
		subr   by  2,
		fsubr  by  3,
		apval  by  4,
		atomic by  5,
		cell   by  6;

	dcl
		m_exp entry returns (ptr);

	dcl
		define_ptr  ptr external,
		label_ptr   ptr external,
		lambda_ptr  ptr external,
		cond_ptr    ptr external,
		quote_ptr   ptr external,
		nil_ptr     ptr external,
		true_ptr    ptr external;

	dcl
		totwds entry returns (fixed(15)),
		maxwds entry returns (fixed(15)),
		allwds entry (fixed(15)) returns (ptr),
		scan entry;

	dcl
		sysprint file,
		f_stack(8) file variable external,
		f_top fixed external,
		new_file bit(1),
		new_name char(16) var;

	dcl
		(lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8) file;

	dcl
		accum char(128) var external,
		hash_table (0:127) ptr external
			init((128)null),
		hash_code fixed(7) external;

	dcl
		1 node based,
		  2 type fixed(7),
		  2 carf  ptr,
		  2 cdrf  ptr;
	%replace
		extra_bytes by 6;

	dcl
		1 atomic_sym based,
		  2 form fixed(7),
		  2 coll ptr,
		  2 p_list ptr,
		  2 symbol char(128) var;

	dcl
		trace fixed static external initial(0);

	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/
	allbytes:
		proc (n) returns (ptr);
		dcl
			n fixed;
		return (allwds(divide(n+1,2,15)));
		end allbytes;

	compute_hash:
		proc external;
		dcl
			c char(1),
			i fixed;
		hash_code = 0;
			do i = 1 to length(accum);
			c = substr(accum,i,1);
			hash_code = hash_code + rank(c);
			end;
		if hash_code < 0 then
			hash_code = abs(hash_code);
		end compute_hash;

	chars:
		proc (p) returns (char(128) var);
		dcl
			p ptr,
			c char(1),
			i fixed;
			do i = 1 to length(p->symbol);
			c = substr(p->symbol,i,1);
			if rank (c) < rank (' ') |
			   rank (c) > rank ('_') then
				return ('?-symbol');
			end;
		return (p->symbol);
		end chars;

	lookup:
		proc returns(ptr) external;
		dcl
			p ptr;
			do p = hash_table(hash_code)
				repeat(p->coll) while(p~=null);
			if accum = chars(p) then
				return (p);
			end;
		return (null);
		end lookup;

	enter:
		proc returns(ptr) external;
		dcl
			i fixed,
			p ptr;
		p = allbytes(length(accum)+extra_bytes);
		p->form = atomic;
		p->coll = hash_table(hash_code);
		p->p_list = nil_ptr;
		p->symbol = accum;
		hash_table(hash_code) = p;
		return (p);
		end enter;

	/*****************************************************
	*                                                    *
	*               Elementary Functions                 *
	*                                                    *
	*****************************************************/
	cons:
		proc (p,q) returns(ptr) external;
		dcl
			(p,q,r) ptr;
		allocate node set (r);
		r->type = cell;
		r->carf = p;
		r->cdrf = q;
		return (r);
		end cons;

	car:
		proc (p) returns (ptr);
		dcl
			p ptr;
		return (p->carf);
		end car;

	cdr:
		proc (p) returns (ptr);
		dcl
			p ptr;
		return (p->cdrf);
		end cdr;

	eq:
		proc (p,q) returns (bit(1));
		dcl
			(p,q) ptr;
		return (p = q);
		end eq;

	atom:
		proc(p) returns(bit(1));
		dcl
			p ptr;
		return (p->type <= atomic);
		end atom;

	equal:
		proc(x,y) returns (bit(1)) recursive;
		dcl
			(x,y) ptr;
		if atom(x) then
			do;
			if atom(y) then
				return(eq(x,y));
			return (false);
			end;
		if equal(car(x),car(y)) then
			return (equal(cdr(x),cdr(y)));
		return (false);
		end equal;

	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/
	cadr:
		proc (p) returns (ptr);
		dcl
			p ptr;
		return (p->cdrf->carf);
		end cadr;

	caddr:
		proc (p) returns (ptr);
		dcl
			p ptr;
		return (p->cdrf->cdrf->carf);
		end caddr;

	caar:
		proc (p) returns (ptr);
		dcl
			p ptr;
		return (p->carf->carf);
		end caar;

	cadar:
		proc (p) returns (ptr);
		dcl
			p ptr;
		return (p->carf->cdrf->carf);
		end cadar;

	replaca:
		proc (p,q);
		dcl
			(p,q) ptr;
		p->carf = q;
		end replaca;

	replacd:
		proc (p,q) external;
		dcl
			(p,q) ptr;
		p->cdrf = q;
		end replacd;

	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/

	deflist:
		proc(p) returns(ptr) recursive;
		dcl
			(p,q,r) ptr;
		q = car(p);
		if atom(q) then
			do;
			r = cons(label_ptr,cons(q,cdr(p)));
			call replacd(q,r);
			q->type = expr;
			end;
		else
			call error('Not Atomic Name',q);
		return (q);
		end deflist;

	define:
		proc(p) returns(ptr) recursive;
		dcl
			p ptr;
		if p = nil_ptr then
			return (nil_ptr);
		return (cons(deflist(car(p)),define(cdr(p))));
		end define;
	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/
	dcl
		i fixed,
		name char(128) var;

	error:
		proc(c,x);
		dcl
			c char(15) var,
			x ptr;
		put skip list('Error:',c);
		call display(x);
		go to error_exit;
		end error;

	evalquote:
		proc (fn,x) returns(ptr);
		dcl
			(fn,x) ptr;
		return(apply(fn,x,nil_ptr));
		end evalquote;

	apply:
		proc ((fn),(x),(a)) returns(ptr) recursive;
		dcl
			(fn,x,a) ptr;
		if atom(fn) then
			if fn->type = expr then
				fn = cdr(fn);
		if trace > 0 then
			do;
			put skip list('Apply:');
			call display(fn);
			call display(x);
			call display(a);
			end;
		if atom(fn) then
			do;
			name = chars(fn);
			/* check for c....r */
			if length(name) >= 3 then
			if substr(name,1,1) = 'C' then
			if substr(name,length(name),1) = 'R' then
			if verify(substr(name,2,length(name)-2),
				'AD') = 0 then
				do;
				if x = nil_ptr then
					return(nil_ptr);
				x = car(x);
					do i = length(name)-1 to 2
						by -1 while(x~=nil_ptr);
					if substr(name,i,1) = 'A' then
						x = car(x);
					else
						x = cdr(x);
					end;
				return (x);
				end;
			if name = 'CONS' then
				return (cons(car(x),cadr(x)));
			if name = 'EQ' then
			if eq(car(x),cadr(x)) then
				return(true_ptr);
			else
				return(nil_ptr);
			if name = 'ATOM' then
			if atom(car(x)) then
				return(true_ptr);
			else
				return(nil_ptr);
			if name = 'DEFINE' then
				return (define(car(x)));
			if name = 'LIB' then
				do;
				new_file = true;
				new_name = chars(car(x));
				return(nil_ptr);
				end;
			if name = 'TRACE' then
				do;
				trace = chars(car(x));
				return (nil_ptr);
				end;
			else
				return(apply(eval(fn,a),x,a));
			end;
		if atom(car(fn)) then
			do;
			name = chars(car(fn));
			if name = 'LAMBDA' then
				return(eval(caddr(fn),
					pairlis(cadr(fn),x,a)));
			if name = 'LABEL' then
				return(apply(caddr(fn),x,
					cons(cons(cadr(fn),caddr(fn)),a)));
			end;
		call error('Undefined',fn);
		end apply;

	eval:
		proc(e,a) returns (ptr) recursive;
		dcl
			(e,a) ptr;
		if trace > 0 then
			do;
			put skip list('Eval:');
			call display(e);
			call display(a);
			end;
		if atom(e) then
			do;
			if e = true_ptr then
				return (true_ptr);
			if e = nil_ptr then
				return (nil_ptr);
			return (cdr(assoc(e,a)));
			end;
		if atom(car(e)) then
			do;
			name = chars(car(e));
			if name = 'quote' then
				return (cadr(e));
			if name = 'cond' then
				return (evcon(cdr(e),a));
			return (apply(car(e),evlis(cdr(e),a),a));
			end;
		return (apply(car(e),evlis(cdr(e),a),a));
		end eval;

	evcon:
		proc(c,a) returns (ptr) recursive;
		dcl
			(c,a) ptr;
		if eval(caar(c),a) = true_ptr then
			return (eval(cadar(c),a));
		return (evcon(cdr(c),a));
		end evcon;

	evlis:
		proc (m,a) returns (ptr) recursive;
		dcl
			(m,a) ptr;
		if m = nil_ptr then
			return (nil_ptr);
		return (cons(eval(car(m),a),evlis(cdr(m),a)));
		end evlis;

	pairlis:
		proc(x,y,a) returns (ptr) recursive;
		dcl
			(x,y,a) ptr;
		if x = nil_ptr then
			return (a);
		if y = nil_ptr then
			call error('Argument Count',x);
		return (cons(cons(car(x),car(y)),
				pairlis(cdr(x),cdr(y),a)));
		end pairlis;

	assoc:
		proc(x,a) returns (ptr) recursive;
		dcl
			(x,a) ptr;
		if a = nil_ptr then
			call error('No Value',x);
		if trace >= 2 then
			do;
			put skip list('assoc:');
			call display(a);
			call display(x);
			end;
		if equal(caar(a),x) then
			return (car(a));
		return (assoc(x,cdr(a)));
		end assoc;
	/*****************************************************
	*                                                    *
	*              List Construction Routines            *
	*                                                    *
	*****************************************************/
	item:
		proc returns (ptr);
		dcl
			p ptr;
		if accum = 'NIL' then
			p = nil_ptr;
		else
			do;
			call compute_hash();
			p = lookup();
			if p = null then
				p = enter();
			end;
		call scan();
		return (p);
		end item;

	tail:
		proc returns(ptr) recursive;
		dcl
			p ptr;
		if accum = ')' then
			do;
			call scan();
			return (nil_ptr);
			end;
		p = cons(list(),nil_ptr);
		if accum = '.' then
			do;
			call scan();
			call replacd(p,list());
			if accum = ')' then
				call scan();
			else
				put skip list('Balance Error');
			end;
		else
			call replacd(p,tail());
		return (p);
		end tail;

	list:
		proc returns(ptr) recursive external;
		if accum = '(' then
			do;
			call scan();
			return (tail());
			end;
		return (item());
		end list;

	/*****************************************************
	*                                                    *
	*              List Display Routines                 *
	*                                                    *
	*****************************************************/
	d_tail:
		proc (p) recursive;
		dcl
			p ptr;
		if p = nil_ptr then
			return;
		if atom(p) then
			do;
			put list('.');
			put list(chars(p));
			end;
		else
			do;
			call d_list(car(p));
			call d_tail(cdr(p));
			end;
		end d_tail;

	d_list:
		proc (p) recursive;
		dcl
			p ptr;
		if atom(p) then
			put list(chars(p));
		else
			do;
			put list('(');
			call d_tail(p);
			put list(')');
			end;
		end d_list;

	display:
		proc (p);
		dcl
			p ptr;
		put skip;
			call d_list(p);
		end display;

	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/

	release:
		proc (p) recursive;
		dcl
			p ptr;
		if p = nil_ptr then
			return;
		if atom(p) then
			return;
		call release(car(p));
		call release(cdr(p));
		free p->node;
		end release;
	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/
	init:
		proc;
		accum = 'DEFINE';
		call compute_hash();
		define_ptr = enter();
		accum = 'LABEL';
		call compute_hash();
		label_ptr = enter();
		accum = 'LAMBDA';
		call compute_hash();
		lambda_ptr = enter();
		accum = 'COND';
		call compute_hash();
		cond_ptr = enter();
		accum = 'QUOTE';
		call compute_hash();
		quote_ptr = enter();
		accum = 'T';
		call compute_hash();
		true_ptr = enter();
		accum = 'LABEL';
		call compute_hash();
		label_ptr = enter();
		accum = 'NIL';
		call compute_hash();
		nil_ptr = enter();
		end init;

	/*****************************************************
	*                                                    *
	*                                                    *
	*****************************************************/

	dcl
		(fn, x, e) ptr,
		prompt char(1) var;
	call init();
	fn = nil_ptr;
	x  = nil_ptr;
	f_stack(1) = lib1;
	f_stack(2) = lib2;
	f_stack(3) = lib3;
	f_stack(4) = lib4;
	f_stack(5) = lib5;
	f_stack(6) = lib6;
	f_stack(7) = lib7;
	f_stack(8) = lib8;
	f_top = 1;
	open file(sysprint) stream output linesize(79)
		print pagesize(0) title('$con');
	open file(lib1) stream title('$con');
	on endfile(lib1)
		stop;
	error_exit:
		do while(true);
		/*
		call release(fn);
		call release(x);
		*/
		prompt = '';
		if f_top = 1 then
			prompt = '>';
		put edit (totwds(),'/',maxwds(),' words',prompt)
			(skip,2(f(5),a),skip,a);
		call scan();
		/*
		fn = list();
			do while (accum = ')');
			call scan();
			end;
		x  = list();
			do while (accum ~= ';');
			call scan();
			end;
		*/
		fn = m_exp();
		if fn ^= nil_ptr then
			do;
			x  = cdr(fn);
			fn = car(fn);
			put list('Evalquote:');
			call display(fn);
			call display(x);
			e = evalquote(fn,x);
			put skip list('Value is:');
			call display(e);
			end;
		if new_file then
			do;
			new_file = false;
			f_top = f_top + 1;
			if f_top > hbound(f_stack,1) then
				do;
				put skip list('Readfile Stack Overflow');
				f_top = 1;
				go to error_exit;
				end;
			on undefinedfile(f_stack(f_top))
				begin;
				put skip list('No File:',new_name);
				f_top = 1;
				go to error_exit;
				end;
			open file(f_stack(f_top)) stream title(new_name);
			revert undefinedfile(f_stack(f_top));
			on endfile(f_stack(f_top))
				begin;
				close file(f_stack(f_top));
				f_top = f_top - 1;
				go to error_exit;
				end;
			end;
		end;
	end lisp;
