!*********************************************************************** !* !* LISP for EMAS !* !* Edinburgh Regional Computing Centre !* !* Updated by R.D. Eager University of Kent MCMLXXXII !* !*********************************************************************** ! ! !*********************************************************************** !* !* Constants !* !*********************************************************************** ! constantinteger no = 0, yes = 1 constantinteger setup = 1,instream = 2,outstream = 3 constantinteger ssdatafiletype = 4; ! Subsystem file type constantinteger marker = m'LISP'; ! Marker at the front of LISP machine files constantinteger default line length = 80 ! For formatting output constantinteger maxlevel = 15 constantinteger long base = 256 constantinteger long tail = 511 constantinteger name base = 512 constantinteger name tail = 2047 constantinteger stack base = 1024 constantinteger stack tail = 2047 constantinteger short base = 2048 constantinteger short tail = 4095 constantinteger list base = 4096 constantinteger list tail = x'7fff' constantinteger atom base = 256 constantinteger char base = 1919 constantinteger zero base = 3072 constantinteger pname max = 8191 constantinteger t = 2003 constantinteger percent = 1956 constantinteger nil = 512 constantinteger quote = 513 constantinteger label = 514 constantinteger lambda = 515 constantinteger apval = 516 constantinteger subr = 517 constantinteger fsubr = 518 constantinteger expr = 519 constantinteger fexpr = 520 constantinteger exit = 521 constantinteger evln = x'8000'!522 constantinteger stars = 523 constantinteger error = 0 constantinteger error1 = 1 constantinteger error2 = 2 constantinteger error3 = 3 constantinteger escape = x'88',eof = x'89' constantbyteintegerarray mask(apval:fexpr) = 3, 4!2, 2, 4!1, 1 constantbyteintegerarray code(0:127) = c x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'80', eof, x'80', x'80', x'80', x'80', x'80', x'80', x'80', x'21', x'22', x'23',escape, x'25', x'26', x'84', x'81', x'83', x'2a', x'2b', x'2c', x'2d', x'82',escape, x'30', x'31', x'32', x'33', x'34', x'35', x'36', x'37', x'38', x'39', x'3a', x'3b', x'3c', x'3d', x'3e', x'3f', x'84', x'41', x'42', x'43', x'44', x'45', x'46', x'47', x'48', x'49', x'4a', x'4b', x'4c', x'4d', x'4e', x'4f', x'50', x'51', x'52', x'53', x'54', x'55', x'56', x'57', x'58', x'59', x'5a', x'85', x'5c', x'87', x'5e', x'5f', x'60', x'61', x'62', x'63', x'64', x'65', x'66', x'67', x'68', x'69', x'6a', x'6b', x'6c', x'6d', x'6e', x'6f', x'70', x'71', x'72', x'73', x'74', x'75', x'76', x'77', x'78', x'79', x'7a', x'7b', x'7c', x'7d', x'7e', x'7f' constantstring(1) snl = " " constantstring(1)array charx(0:7) = c " ", "(", ".", ")", "'", "[", " ", "]" ! ! !*********************************************************************** !* !* Record and array formats !* !*********************************************************************** ! recordformat atom cell(halfinteger bind,prop,func,byteinteger form, stringname pname) recordformat lisp cell(halfinteger car,cdr) recordformat lispinfo(integer dataend,datastart,filesize,filetype, sum,datetime,format,records,marker,const, long head,pname space,pname base,pname head,name, name head,stack,global,list,list head,list count, line length) recordformat rf(integer conad,filetype,datastart,dataend) recordformat stack frame(halfinteger back,bind,link) ! ownintegerarrayformat constf(long base:long tail) ownrecord(stack frame)arrayformat stackf(stack base:stack tail) ownrecord(lisp cell)arrayformat listf(0:list tail) ownrecord(atom cell)arrayformat namef(name base:name tail) ownbyteintegerarrayformat pnamef(0:pname max) ! ! !*********************************************************************** !* !* Subsystem references !* !*********************************************************************** ! systemroutinespec connect(string(31) file,integer mode,hole, prot,record(rf)name r,integername flag) systemroutinespec define(integer chan,string(31) iden, integername afd,flag) systemstringfunctionspec failuremessage(integer mess) systemstringfunctionspec itos(integer n) systemroutinespec outfile(string(31) file,integer size,hole, prot,integername conad,flag) externalroutinespec prompt(string(255) s) systemroutinespec setfname(string(63) s) externalroutinespec set return code(integer i) ! ! !*********************************************************************** !* !* Own variables !* !*********************************************************************** ! owninteger auxp; ! Auxiliary stack pointer owninteger errval,infile,outf owninteger char,reset,front,pname tail,progflag,local,nillist ownintegername list count,list head,long head,pname head,global,name head ownintegername line length ownstring(255) pmpt,plabel,line,clause,pspaces ownintegerarrayname const ownrecord(lispinfo)name lispfile ownrecord(atom cell)arrayname name ownrecord(lisp cell)arrayname list ownrecord(stack frame)arrayname stack ownintegerarray auxs(0:1023); ! Auxiliary stack ownbyteintegerarray blanks(0:255) = ' '(*) ownstring(5) errors = "Error" ! ! !*********************************************************************** !* !* Forward references !* !*********************************************************************** ! integerfunctionspec eval(integer form) integerfunctionspec func(record(atom cell)name atom,integer args) routinespec loop(string(255) pmpt,integer term) ! ! !*********************************************************************** !* !* Miscellaneous routines !* !*********************************************************************** ! integerfunction push(integer index) ! Adds the item 'index' to the auxiliary stack, yielding 'index' as the ! result. auxs(auxp) = index auxp = auxp + 1 result = index end; ! of push ! !----------------------------------------------------------------------- ! integerfunction pop(integer index) ! Removes an item from the auxiliary stack, yielding that item as its ! result. auxp = auxp - 1 result = index end; ! of pop ! !----------------------------------------------------------------------- ! stringfunction pname(integer index) ! Yields the printable form of the atom described by 'index'. if index >= long base then start if index >= name base then start result = itos(index-zero base) if index >= short base result = tostring(index-char base) if index >= char base result = name(index)_p name finish else result = itos(const(index)) finish else result = errors end; ! of pname ! !----------------------------------------------------------------------- ! string(255)function pack(integer index) integer car string(255) packed ! packed = "" while index >= list base cycle; ! cdr down the list car = list(index)_car index = list(index)_cdr if car >= list base then packed <- packed.pack(car) else c packed <- packed.pname(car) repeat packed <- packed.pname(index) unless index = nil result = packed end; ! of pack ! !----------------------------------------------------------------------- ! integerfunction numberp(integername value) ! Performs the LISP function 'numberp', on the item described by ! 'value'. value = const(value) and result = t if long base <= value <= long tail value = value - zero base and result = t if short base <= value <= short tail result = nil end; ! of numberp ! !----------------------------------------------------------------------- ! integerfunction equal(integer arg1,arg2) ! Performs the LISP function 'equal' on the two items described by ! 'arg1' and 'arg2'. if arg1 = arg2 or (numberp(arg1) = t = numberp(arg2) and c arg1 = arg2) or(arg1 >= list base and arg2 >= list base and c equal(list(arg1)_car,list(arg2)_car) = t and c equal(list(arg1)_cdr,list(arg2)_cdr) = t) then result = t result = nil end; ! of equal ! !----------------------------------------------------------------------- ! integerfunction mnumb(integer value) ! Allocates storage for a number (if necessary), and yields its value as ! the result. integer index ! result = value + zero base if -1024 <= value <= 1023 unless long base <= long head <= long tail then start printstring(snl."Atom error: No more room for long constants".snl) result = error finish index = long base while index # long head cycle result = index if const(index) = value index = index + 1 repeat long head = long head + 1 const(index) = value result = index end; ! of mnumb ! !----------------------------------------------------------------------- ! integerfunction matom(string(255) pname) ! Allocates storage for the name 'pname', and yields its index as the ! result. Uses an existing copy if it is already in the name table. integer index record(atom cell)name atom ! if length(pname) = 1 then start result = char base + (charno(pname,1) & x'7f') finish for index = name base,1,name head - 1 cycle result = index if pname = name(index)_pname repeat unless name head < char base and c pname head + length(pname) + 1 < pname tail then start printstring(snl."Atom error: No more space for names".snl) result = error finish atom == name(name head) atom_pname == string(pname head) pname head = pname head + length(pname) + 1 atom_pname = pname index = name head name head = name head + 1 result = index end; ! of matom ! !----------------------------------------------------------------------- ! integerfunction ratom ! Reads and allocates space for an atom, after classifying it. Yields ! the index of the item read. integer type,sign,value,tsign string(255) pname ! type = 0 value = 0 sign = +1 tsign = +1 pname = "" cycle if char & x'80' # 0 then start; ! Separator if pname # "" then start; ! Terminator result = matom(pname) if type < 2 ! Symbolic atom result = mnumb(value); ! Numeric atom finish value = char & x'7f' char = x'80' and result = value if char # x'80' ! Break character finish else start; ! Normal character if 0 <= type <= 2 then start; ! Possibly numeric if '0' <= char <= '9' then start ! Yes for now type = 2 if sign = -1 then start value = -value sign = +1 finish value = value*10 + (char-'0')*tsign finish else start; ! Possibly signed if type = 0 and (char = '+' or char = '-') then start type = 1 if char = '-' then start sign = -1 tsign = -1 finish finish else type = -1; ! Not numeric finish finish pname <- pname.tostring(char); ! Always symbolic finish cycle readch(char); ! Next symbol char = code(char & x'7f') selectinput(0) if char = eof repeat until char # eof readch(char) and type = -1 if char = escape repeat end; ! of ratom ! !----------------------------------------------------------------------- ! routine printchars(string(255) phrase) integer adjustment ! phrase <- plabel.phrase and plabel = "" if plabel # "" if phrase = "" then start if length(line) + length(clause) < line length then start printstring(line.clause.snl) finish else printstring(line.snl.pspaces.clause.snl) line = "" clause = "" finish if length(pspaces)+length(clause)+length(phrase) >= line length then start adjustment = length(pspaces) - length(phrase) if adjustment < 0 then start printstring(line.snl) if line # "" printstring(pspaces.clause.snl) line = "" clause = "" finish else length(pspaces) = adjustment finish clause = clause.phrase; ! Append phrase end; ! of printchars ! !----------------------------------------------------------------------- ! routine print(integer index) integer level,clevel,adjustment,i byteinteger r flag,c count,r count,line 1 integerarray line pos(0:maxlevel) ! ! string(255)function padding integer index,count ! if level < maxlevel + 1 then index = level else index = maxlevel count = line pos(index) - length(plabel) count = line length if count > line length count = 0 if count < 0 blanks(0) = count result = string(addr(blanks(0))) end; ! of padding ! ! routine lparen integer i ! if level <= maxlevel and line pos(level) = 0 then start line pos(level) = length(line) + length(clause) finish c count = 10 if 50 < length(line) > line pos(level) or c length(clause) > 30 or (length(clause) > 20 and length(line) > 20) if r flag > 0 or c count >= 10 then start ! Start of new phrase if length(line) + length(clause) > line length or c length(line) - length(pspaces) > 25 or c count >= 2 then start ! ! Adjust the position of the left parenthesis at this level ! if level > clevel then start adjustment = length(line) - length(pspaces) for i = clevel + 1,1,level cycle line pos(i) = line pos(i) - adjustment repeat finish printstring(line.snl) if line # "" line = pspaces.clause line 1 = 0 finish else line = line.clause c count = r count clause = "" clevel = level pspaces = padding finish level = level + 1 if line 1 = 0 r flag = 0 r count = 0 print chars("(") end; ! of lparen ! ! routine rparen print chars(")") line pos(level) = 0 if 0 < level <= maxlevel level = level - 1 if level > 0 r flag = 1 rcount = rcount + 1 end; ! of rparen ! !----------------------------------------------------------------------- ! routine print sexp(integer index) ! Prints out the S-expression described by 'index'. This may be a list ! cell (and therefore something fairly complex) or it may just be an ! atom. integer car,cdr record(lisp cell)name cell ! if index >= list base then start; ! List cell cell == list(index) car = cell_car cdr = cell_cdr; ! Map onto cell lparen print sexp(car); ! Start of list if cdr >= list base then start cycle; ! Print tail index = cdr cell == list(index) car = cell_car cdr = cell_cdr print chars(" ") if plabel = "" ! Print space exit if cdr < list base; ! End of list if car = nil then start; ! Print empty list lparen print chars(" ") rparen finish else print sexp(car); ! Print car repeat print sexp(car) finish printchars(" . ") and printchars(pname(cdr)) and rflag = 0 if cdr # nil r paren; ! Close list finish else start; ! Atom if r flag = 1 then start r flag = 2 plabel <- pname(index)." " finish else start print chars(pname(index)) r flag = 0 finish finish end; ! of print sexp ! ! line 1 = 1 r flag = 0 c count = 0 r count = 0 pspaces = "" level = 0 clevel = 0 line pos(0) = 4; ! Initial indentation line pos(i) = 0 for i = 1,1,maxlevel print sexp(index) end; ! of print ! !----------------------------------------------------------------------- ! routine mark(integer index) ! Marks the chain of cells headed by 'index', by adding bit x'8000'. ! Used by the garbage collector. halfintegername car ! while index >= list base and list(index)_car >= 0 cycle car == list(index)_car index = list(index)_cdr car <- car!x'8000' mark(car & x'7fff') if car & x'7fff' >= list base repeat end; ! of mark ! !----------------------------------------------------------------------- ! routine garbage collect record(lisp cell)name cell integer i ! mark(name(i)_prop) for i = name base,1,name head - 1 mark(name(i)_prop) for i = char base,1,name tail mark(stack(i)_bind) for i = stack base,1,front mark(stack(i)_bind) for i = global,1,stack tail if auxp > 0 then start mark(auxs(i)) for i = 0,1,auxp - 1 finish list count = 0 list head = 0 for i = list base,1,list tail cycle cell == list(i) if cell_car < 0 then cell_car <- cell_car & x'7fff' else start list count = list count + 1 cell_car = list head list head = i finish repeat end; ! of garbage collect ! !----------------------------------------------------------------------- ! integerfunction cons(integer car,cdr) ! Performs the LISP function 'cons' on the items described by 'car' and ! 'cdr'. Yields the index of the cell constructed. integer index,dummy record(lisp cell)name cell ! if list count <= 100 or list head < list base then start dummy = push(car); ! Ensure these lists are not garbage collected dummy = push(cdr) auxp = auxp + 2 garbage collect auxp = auxp - 2 if list count <= 1000 then start printstring(snl."Lisp note: Less than 1000 free cells remaining - free something".snl) loop("Free:",percent) finish finish if list head < list base then start printstring(snl."Lisp error: No more free space left".snl) result = error finish list count = list count - 1 index = list head cell == list(index) list head = cell_car cell_car = car cell_cdr = cdr result = index end; ! of cons ! !----------------------------------------------------------------------- ! integerfunction reverse(integer curr) integer last record(lisp cell)name cell ! last = nil while curr >= list base cycle cell == list(curr) last = cons(cell_car,last) curr = cell_cdr repeat result = last end; ! of reverse ! !----------------------------------------------------------------------- ! integerfunction read sexp(string(255) pmpt) integerfunctionspec cell(integer car) integerfunctionspec head integerfunctionspec tail integer colapse ! ! integerfunction cell(integer car) integer cdr ! if car >= atom base then start; ! Head not in error auxs(auxp) = car auxp = auxp + 1 cdr = tail auxp = auxp - 1 result = cons(car,cdr) if cdr >= atom base ! Tail not in error finish result = error end; ! of cell ! ! integerfunction head integer temp,res switch sw(0:3) ! temp = ratom result = temp if temp >= atom base; ! Atom -> sw(temp & 3); ! Handle by case ! sw(0): ! "" result = cons(quote,cons(head,nil)) ! sw(1): ! '(' or '[' res = tail colapse = no if temp >= 4; ! '[' result = res ! sw(2): sw(3): ! '.' or ')' printstring(snl."Read error: S-expression begins with a ".charx(temp).snl) result = error end; ! of head ! ! integerfunction tail integer temp,res switch sw(0:3) ! result = nil if colapse = yes; ! Collapse back to '[' temp = ratom; ! Separator result = cell(temp) if temp >= atom base ! Atom -> sw(temp & 3); ! Handle by case ! sw(0): result = cell(cons(quote,cons(head,nil))) ! sw(1): ! '(' or '[' res = tail colapse = no if temp >= 4; ! '[' result = cell(res) ! sw(2): ! '.' temp = head result = temp if tail = nil printstring(snl."Read error: Dotted pair not enclosed in brackets".snl) result = error ! sw(3): ! ')' or ']' colapse = yes if temp >= 4 result = nil end; ! of tail ! ! colapse = no prompt(pmpt) result = head end; ! of read sexp ! !----------------------------------------------------------------------- ! routine loop(string(255) pmpt,integer term) integer value ! cycle reset = 0 value = eval(read sexp(pmpt)) exit if value = term print(value) and print chars("") unless reset # 0 repeat end; ! of loop ! !----------------------------------------------------------------------- ! integerfunction pcons(integer car,cdr) auxp = auxp - 1 result = cons(car,cdr) end; ! of pcons ! !----------------------------------------------------------------------- ! routine xprint(string(255) mess,integer form) string(255) save ! save = line line = mess print(form) print chars("") line = save end; ! of xprint ! !----------------------------------------------------------------------- ! routine bind(integer symb,entry,bind) record(atom cell)name atom record(stack frame)name frame ! unless name base <= symb < list base then start printstring(snl."Bind error: Element of name list not an atom, element = ") xprint("",symb) return finish if name(symb)_form = 3 then start xprint(snl."Bind error: Name list entry has constant binding, name=",symb) return finish unless global > front then start printstring(snl."Bind error: Stack overflow".snl) return finish frame == stack(entry) atom == name(symb) unless bind >= atom base then start printstring(snl."Bind error: Unassigned argument ") xprint("",symb) bind = error finish frame_bind = bind frame_back = symb frame_link = atom_bind atom_bind = entry end; ! of bind ! !----------------------------------------------------------------------- ! routine bindlist(integername names,args) record(lisp cell)name cell,argc ! stack(front)_link = local stack(front)_back = 0 local = front front = front + 1 while names >= list base cycle cell == list(names) argc == list(args) bind(cell_car,front,argc_car) front = front + 1 names = cell_cdr args = argc_cdr repeat end; ! of bindlist ! !----------------------------------------------------------------------- ! integerfunction unbind(integer result) record(stack frame)name frame ! while front > local cycle front = front - 1 frame == stack(front) name(frame_back)_bind = frame_link if frame_back > 0 repeat front = local local = stack(front)_link result = result end; ! of unbind ! !----------------------------------------------------------------------- ! integerfunction prog(integer names,body) integer proglist,result record(lisp cell)name cell ! bindlist(names,nillist) progflag = progflag + 4; ! In prog proglist = body while body >= list base cycle; ! Evaluate body cell == list(body) if cell_car >= list base then start ! Not a plabel result = eval(cell_car); ! So evaluate if progflag & 3 # 0 then start; ! Return or go if progflag & 1 # 0 then start ! Return progflag = progflag & (¬3) - 4 result = unbind(result) finish cell == list(proglist) progflag = progflag & (¬3) while cell_car # result cycle; ! Scan for label if cell_cdr < list base then start progflag = progflag - 4 result = unbind(error); ! Not found finish cell == list(cell_cdr) repeat finish finish body = cell_cdr repeat progflag = progflag - 4 result = unbind(result); ! Fell through end; ! of prog ! !----------------------------------------------------------------------- ! integerfunction evlist(integer args) record(lisp cell)name cell ! result = args unless args >= list base cell == list(args) result = pcons(push(eval(cell_car)),evlist(cell_cdr)) end; ! of evlist ! !----------------------------------------------------------------------- ! integerfunction apply(integer function,args) integer car,cadr,caddr record(lisp cell)name cell ! if function >= list base then start cell == list(function) car = cell_car cell == list(cell_cdr) cadr = cell_car cell == list(cell_cdr) caddr = cell_car if car = label then start bind(cadr,front,caddr) front = front + 1 result = apply(caddr,args) finish if car = lambda then start bindlist(cadr,args) bind(cadr,front,args) and front = front + 1 if cadr # nil result = unbind(eval(caddr)) finish result = apply(eval(function),args) finish if name base <= function <= name tail then start result = func(name(function),args) finish result = error end; ! of apply ! !----------------------------------------------------------------------- ! integerfunction put(integer atom,bind,prop) integer id halfintegername hole record(lisp cell)name prop cell,bind cell ! unless name base <= atom <= name tail and name base <= prop <= name tail then start result = error3 finish hole == name(atom)_prop cycle; ! Search property list hole = cons(prop,cons(bind,nil)) and exit if hole < list base ! Not on list prop cell == list(hole) bind cell == list(prop cell_cdr) bind cell_car = bind and exit if prop cell_car = prop ! Property found hole == bind cell_cdr; ! Try next entry repeat if apval <= prop <= fexpr then start; ! Function definition name(atom)_form = mask(prop) if subr <= prop <= fsubr then start id = bind result = error3 unless numberp(id) = t name(atom)_func = id finish else name(atom)_func = bind finish result = bind end; ! of put ! !----------------------------------------------------------------------- ! integerfunction func(record(atom cell)name atom,integer args) ! Interprets a function call. EXPRs and FEXPRs are interpreted by ! calling 'apply'. SUBRs and FSUBRs are interpreted in the 'func()' ! switch below. integer arg1,arg2,arg3,symb,afd,flag string(80) line halfintegername hole record(lisp cell)name cell record(stack frame)name frame switch type(0:3) switch func(0:86) ! -> type(atom_form & 3) ! type(3): ! Apval type(0): ! No function definition on property list result = error2 unless atom_bind < global ! Nor on alist front = front + 1 args = evlist(args) front = front - 1 result = apply(stack(atom_bind)_bind,args) ! type(1): ! Expr or Fexpr result = apply(atom_func,args) ! type(2): ! Subr or Fsubr cell == list(args); arg1 = cell_car cell == list(cell_cdr); arg2 = cell_car cell == list(cell_cdr); arg3 = cell_car ! -> func(atom_func) ! func(0): ! Quote result = arg1 ! func(1): ! Car result = list(arg1)_car ! func(2): ! Cdr result = list(arg1)_cdr ! func(3): ! Caar result = list(list(arg1)_car)_car ! func(4): ! Cadr result = list(list(arg1)_cdr)_car ! func(5): ! Cdar result = list(list(arg1)_car)_cdr ! func(6): ! Cddr result = list(list(arg1)_cdr)_cdr ! func(7): ! Cons result = cons(arg1,arg2) ! func(8): ! List result = args ! func(9): ! Cond while args >= list base cycle cell == list(list(args)_car) arg1 = eval(cell_car) if arg1 # nil then start while cell_cdr >= list base cycle cell == list(cell_cdr) arg1 = eval(cell_car) repeat result = arg1 finish args = list(args)_cdr repeat result = nil ! func(10): ! And while args >= list base cycle cell == list(args) result = nil unless eval(cell_car) # nil args = cell_cdr repeat result = t ! func(11): ! Or while args >= list base cycle cell == list(args) result = t if eval(cell_car) # nil args = cell_cdr repeat result = nil ! func(12): ! Null if arg1 = nil then result = t else result = nil ! func(13): ! Atom if atom base <= arg1 < list base then result = t else result = nil ! func(14): ! Numberp result = numberp(arg1) ! func(56): ! Evenp if numberp(arg1) = t and (arg1 & 1) = 0 then result = t result = nil ! func(55): ! Onep arg1 = arg1 - 1 ! func(15): ! Zerop if arg1 = zero base then result = t else result = nil ! func(16): ! Eq if arg1 = arg2 then result = t else result = nil ! func(17): ! Equal result = equal(arg1,arg2) ! func(18): ! Lessp if numberp(arg1) = t = numberp(arg2) and arg1 < arg2 then result = t else c result = nil ! func(19): ! Greaterp if numberp(arg1) = t = numberp(arg2) and arg1 > arg2 then result = t else c result = nil ! func(20): ! Memb/Memq while arg2 >= list base cycle cell == list(arg2) result = t if arg1 = cell_car arg2 = cell_cdr repeat result = nil ! func(21): ! Member while arg2 >= list base cycle cell == list(arg2) result = t if equal(arg1,cell_car) = t arg2 = cell_cdr repeat result = nil ! func(22): ! Assoc while arg2 >= list base cycle cell == list(arg2) result = cell_car if equal(arg1,list(cell_car)_car) = t arg2 = cell_cdr repeat result = nil ! func(23): ! Plus arg1 = 0 while args >= list base cycle cell == list(args) arg2 = cell_car if numberp(arg2) = t then arg1 = arg1 + arg2 else result = error3 args = cell_cdr repeat result = mnumb(arg1) ! func(24): ! Difference unless numberp(arg1) = t then result = error3 while args >= list base cycle cell == list(args) arg2 = cell_car if numberp(arg2) = t then arg1 = arg1 - arg2 else result = error3 args = cell_cdr repeat result = mnumb(arg1) ! func(25): ! Times arg1 = 1 while args >= list base cycle cell == list(args) arg2 = cell_car if numberp(arg2) = t then arg1 = arg1 * arg2 else result = error3 args = cell_cdr repeat result = mnumb(arg1) ! func(26): ! Quotient unless numberp(arg1) = t then result = error3 while args >= list base cycle cell == list(args) arg2 = cell_cdr if numberp(arg2) = t then arg1 = arg1//arg2 else result = error3 args = cell_cdr repeat result = mnumb(arg1) ! func(27): ! Add1 if numberp(arg1) = t then result = mnumb(arg1 + 1) result = error3 ! func(28): ! Sub1 if numberp(arg1) = t then result = mnumb(arg1 - 1) result = error3 ! func(29): ! Abs if numberp(arg1) = t then result = mnumb(imod(arg1)) result = error3 ! func(30): ! Selectq arg1 = eval(arg1) args = list(args)_cdr cycle arg3 = args args = list(arg3)_cdr exit if args < list base cell == list(list(arg3)_car) arg2 = cell_car arg3 = cell_cdr while arg2 >= list base cycle cell == list(arg2) -> exit if cell_car = arg1 arg2 = cell_cdr repeat exit if arg2 = arg1 repeat ! exit: while arg3 >= list base cycle cell == list(arg3) arg1 = eval(cell_car) arg3 = cell_cdr repeat result = arg1 ! func(31): ! Put result = put(arg1,arg3,arg2) ! func(32): ! Prop result = error3 unless name base <= arg1 <= name tail result = name(arg1)_prop ! func(33): ! Rem/Remprop result = error3 unless c name base <= arg1 <= name tail and name base <= arg2 <= name tail atom == name(arg1) hole == atom_prop while hole >= list base cycle cell == list(hole) if cell_car = arg2 then start cell == list(cell_cdr) atom_form = 0 if cell_car = atom_func hole = cell_cdr result = t finish hole == list(cell_cdr)_cdr repeat result = nil ! func(34): ! Get result = error3 unless c name base <= arg1 <= name tail and name base <= arg2 <= name tail args = name(arg1)_prop while args >= list base cycle cell == list(args) result = list(cell_cdr)_car if cell_car = arg2 args = list(cell_cdr)_cdr repeat result = nil ! func(35): ! Put/Putprop/Defprop result = put(arg1,arg2,arg3) ! func(36): ! Eval result = eval(arg1) ! func(37): ! Evlis result = evlist(args) ! func(38): ! Apply result = apply(arg1,arg2) ! func(39): ! Errset arg1 = cons(eval(arg1),nil) arg1 = errval and reset = 0 if reset = 2 result = arg1 ! func(40): ! Rplaca result = error3 if arg1 < list base list(arg1)_car = arg2 result = arg2 ! func(41): ! Rplacd result = error3 if arg1 < list base list(arg1)_cdr = arg2 result = arg2 ! func(42): ! Nconc result = arg2 if arg1 = nil result = error3 unless arg1 >= list base args = arg1; ! Remember 'a' arg1 = list(arg1)_cdr while list(arg1)_cdr >= list base ! Cdr down 'a' list(arg1)_cdr = arg2 result = args ! func(43): ! Minusp if numberp(arg1) = t and arg1 < 0 then result = t result = nil ! func(44): ! Setq arg2 = eval(arg2) ! func(45): ! Set result = error3 unless name base <= arg1 <= name tail arg3 = name(arg1)_bind if arg3 < stack tail then start stack(arg3)_bind = arg2 finish else start global = global - 1 bind(arg1,global,arg2) finish result = arg2 ! func(46): ! Explode result = error3 unless atom base <= arg1 < list base line = pname(arg1) arg2 = nil for arg1 = addr(line) + length(line),-1,addr(line) + 1 cycle symb = byteinteger(arg1) if '0' <= symb <= '9' then symb = zero base + symb - '0' else c symb = char base + symb arg2 = cons(symb,arg2) repeat result = arg2 ! func(47): ! Implode result = matom(pack(arg1)) ! func(48): ! Prog2 result = arg2 ! func(49): ! Progn while args >= list base cycle cell == list(args) arg1 = eval(cell_car) args = cell_cdr repeat result = arg1 ! func(50): ! Prog result = prog(arg1,list(args)_cdr) ! func(51): ! Minus if numberp(arg1) = t then result = mnumb(-arg1) result = error3 ! func(52): ! Return progflag = progflag!1 result = arg1 ! func(53): ! Go progflag = progflag!2 result = arg1 ! func(54): ! Reverse result = reverse(arg1) ! func(60): ! Prompt result = error3 unless name base <= arg1 <= name tail pmpt = pname(arg1) result = arg1 ! func(61): ! Readch if atom base <= arg1 < list base then prompt(pname(arg1)) else prompt(pmpt) readch(symb) if '0' <= symb <= '9' then result = mnumb(symb - '0') else c result = matom(tostring(symb)) ! func(62): ! Read result = read sexp(pname(arg1)) if atom base <= arg1 < list base result = read sexp(pmpt) ! func(63): ! Princ print(arg1) result = arg1 ! func(64): ! Print print(arg1) print chars("") result = arg1 ! func(65): ! Terpri print chars("") arg1 = nil unless arg1 >= atom base result = arg1 ! func(66): ! Inunit selectinput(arg1) and result = mnumb(arg1) if numberp(arg1) = t result = error3 ! func(67): ! Outunit selectoutput(arg1) and result = mnumb(arg1) if numberp(arg1) = t result = error3 ! func(68): ! Input result = error3 unless name base <= arg1 <= name tail selectinput(0) closestream(instream) arg2 = infile infile = arg1 define(instream,name(infile)_pname,afd,flag) selectinput(instream) result = arg2 ! func(69): ! Output result = error3 unless name base <= arg1 <= name tail selectoutput(0) closestream(outstream) arg2 = outf outf = arg1 define(outstream,name(outf)_pname,afd,flag) selectoutput(outstream) result = arg2 ! func(70): ! Trace result = error3 unless name base <= arg1 <= name tail atom == name(arg1) atom_form = atom_form!8 result = arg1 ! func(71): ! Untrace result = error3 unless name base <= arg1 <= name tail atom == name(arg1) atom_form = atom_form & (¬8) result = arg1 ! func(72): ! Break result = error3 unless name base <= arg1 <= name tail name(arg1)_form = name(arg1)_form!16 result = arg1 ! func(73): ! Unbreak result = error3 unless name base <= arg1 <= name tail name(arg1)_form = name(arg1)_form & (¬16) result = arg1 ! func(74): ! $Delete result = error3 unless name base <= arg1 <= name tail atom == name(arg1) atom_bind = stack tail atom_prop = nil atom_func = 0 atom_form = 0 result = arg1 ! func(75): ! Peek if numberp(arg1) = t and front - arg1 > stack base then c arg1 = front - arg1 else arg1 = stack base if front # arg1 then start for arg1 = front - 1,-1,arg1 cycle frame == stack(arg1) line <- pname(frame_back & x'fff')." " length(line) = 9 if frame_back & x'8000' # 0 then line = line."* " else line = line."= " xprint(line,frame_bind) repeat finish result = stars ! func(76): ! Linelength result = error3 unless zerobase + 40 <= arg1 <= zerobase + 255 line length = arg1 - zerobase result = arg1 ! func(77): ! Garb garbage collect result = mnumb(list count) ! func(78): ! Reset pmpt = "Read:" reset = 1 errval = nil result = percent ! func(79): ! Err errval = arg1 reset = 2 result = percent ! func(80): ! Oblist arg2 = nil for arg1 = name head - 1,-1,name base cycle arg2 = cons(arg1,arg2) repeat result = arg2 ! func(81): ! Alist arg2 = nil arg3 = nil for arg1 = stack base,1,front - 1 cycle frame == stack(arg1) arg2 = cons(cons(frame_back,frame_bind),arg2) if c name base <= frame_back <= name tail repeat for arg1 = stack tail - 1,-1,global cycle frame == stack(arg1) arg3 = cons(cons(frame_back,frame_bind),arg3) repeat result = cons(arg2,arg3) ! func(82): ! Ascii result = error3 unless numberp(arg1) = t and 0 <= arg1 <= 127 result = matom(tostring(arg1)) ! func(83): ! Max unless numberp(arg1) = t then result = error3 while args >= list base cycle cell == list(args) arg2 = cell_car unless numberp(arg2) = t then result = error3 arg1 = arg2 if arg1 < arg2 args = cell_cdr repeat result = mnumb(arg1) ! func(84): ! Min unless numberp(arg1) = t then result = error3 while args >= list base cycle cell == list(args) arg2 = cell_car unless numberp(arg2) = t then result = error3 arg1 = arg2 if arg2 < arg1 args = cell_cdr repeat result = mnumb(arg1) ! func(85): ! Sqrt unless numberp(arg1) = t then result = error3 result = int(sqrt(arg1)) ! func(86): ! Expt unless numberp(arg1) = t = numberp(arg2) then result = error3 result = mnumb(arg1****arg2) end; ! of func ! !----------------------------------------------------------------------- ! integerfunction trace(string(255) mess,integer form) xprint(mess,form) result = form end; ! of trace ! !----------------------------------------------------------------------- ! integerfunction eval(integer form) integer car,cdr record(lisp cell)name cell record(atom cell)name atom record(stack frame)name frame ! ! integerfunction break(integer result) integer sexp switch error(0:3) ! result = result if result >= atom base or reset # 0 selectinput(0) selectoutput(0) xprint("Eval error: ",form) ! -> error(result) ! error(1): printstring(" Atom is not bound to a value".snl) -> error(0) ! error(2): xprint(" Function not defined: ",car) -> error(0) ! error(3): xprint(" Argument not of the correct form in ",cdr) ! error(0): loop(" %:",percent) result = percent if reset # 0 sexp = read sexp("Eval:") sexp = form if sexp = percent result = eval(sexp) end; ! of break ! ! ** Body of eval ** ! result = percent if reset # 0 frame == stack(front) frame_back <- evln frame_bind = form if form >= list base then start; ! Form is a list cell == list(form) car = cell_car cdr = cell_cdr if name base <= car <= name tail then start atom == name(car) if atom_form & 4 # 0 then start ! Evaluate tail if EXPR or SUBR front = front + 1 cdr = evlist(cdr) front = front - 1 finish form = push(form) frame_back <- car!x'8000' frame_bind = cdr if atom_form & 16 # 0 then start selectinput(0) selectoutput(0) xprint("Lisp Break: ",form) front = front + 1 loop(" %:",percent) front = front - 1 finish if atom_form & 8 # 0 then start ! Name being traced result = pop(break(trace("<--- ".pname(car)." ",func(atom, trace("---> ".pname(car)." ",cdr))))) finish result = pop(break(func(atom,cdr))) ! Form of Apply finish front = front + 1 cdr = evlist(cdr) front = front - 1 result = break(apply(car,cdr)); ! Function is a list finish if name base <= form <= name tail then start atom == name(form) result = atom_func if atom_form & x'7' = 3 ! Apval result = break(stack(atom_bind)_bind) ! Return binding finish result = form; ! Constant end; ! of eval ! !----------------------------------------------------------------------- ! routine initlisp integer i,sexp record(atom cell)name atom record(lisp cell)name cell record(stack frame)name frame ! for i = name base,1,name tail cycle atom == name(i) atom_bind = stack tail atom_prop = nil atom_func = 0 atom_form = 0 atom_pname == errors repeat selectinput(setup) reset = 0 sexp = ratom for i = nil,1,stars; ! Read in known atoms for i = 0,1,list base - 1 cycle cell == list(i) cell_car = error3 cell_cdr = error3 repeat list head = list base list count = list tail - list head list(i)_car = i + 1 for i = list base,1,list tail - 1 list(list tail) = 0 sexp = put(ratom,ratom,ratom) until sexp = nil ! Initialise from INITLISP stack(front)_bind = error frame == stack(global) frame_link = global frame_bind = error1 auxs(auxp) = error sexp = eval(read sexp("")) until sexp = nil selectinput(0) end; ! of initlisp ! ! !*********************************************************************** !* !* L I S P !* !*********************************************************************** ! externalroutine lisp(string(255) parms) integer flag,conad,initmode,i,fixup string(255) work record(rf) rr byteintegerarrayname pname space record(atom cell)name atom ! local = stack base front = stack base auxp = 0 pmpt = "Read:" char = x'80'; ! Arbitrary separator to start ! if parms -> work.("/").parms and work = "" then start if parms = "" then parms = "T#LSPMACH" outfile(parms,196608,0,0,conad,flag) -> err if flag # 0 initmode = yes finish else start initmode = no connect(parms,3,0,0,rr,flag) -> err if flag # 0 conad = rr_conad finish ! <define channels 2 and 3???> ! lispfile == record(conad); ! LISP machine store ! if initmode = yes then start lispfile_dataend = lispfile_filesize lispfile_filetype = ssdatafiletype lispfile_format = 3; ! Un-structured lispfile_marker = marker lispfile_const = x'1000' lispfile_long head = long base lispfile_pname space = lispfile_const + 4*(long tail-long base+1) lispfile_pname base = lispfile_pname space lispfile_pname head = lispfile_pname base lispfile_name = x'4000' lispfile_name head = name base lispfile_stack = x'A000' lispfile_global = stack tail lispfile_list = x'10000' lispfile_line length = default line length finish else start if lispfile_marker # marker then start ! Not a LISP machine file flag = 311; ! Corrupt file setfname(parms) -> err finish finish ! ! Map variables onto machine file ! const == array(conad+lispfile_const,constf) long head == lispfile_long head pname space == array(conad+lispfile_pname space,pnamef) pname head == lispfile_pname head pname tail = addr(pname space(pname max)) name == array(conad+lispfile_name,namef) name head == lispfile_name head global == lispfile_global line length == lispfile_line length ! ! Relocate 'pname' addresses. ! fixup = addr(pname space(0)) - lispfile_pname base lispfile_pname base = lispfile_pname base + fixup lispfile_pname head = lispfile_pname head + fixup for i = name base,1,name head - 1 cycle atom == name(i) atom_pname == string(addr(atom_pname)+fixup) atom_bind = stack tail unless global <= atom_bind <= stack tail repeat ! for i = char base,1,name tail cycle atom == name(i) atom_bind = stack tail unless global <= atom_bind <= stack tail repeat ! list == array(conad+lispfile_list,listf) list head == lispfile_list head list count == lispfile_list count stack == array(conad + lispfile_stack,stackf) ! pspaces = "" plabel = "" line = "" clause = "" progflag = 0 flag = 0 if initmode = yes then initlisp nillist = cons(nil,nil) list(nillist)_cdr = push(nillist) infile = matom(".IN") outf = matom(".OUT") ! loop("Lisp:",exit) set return code(0) stop ! err: selectoutput(0) printstring(snl."LISP fails -".failuremessage(flag)) set return code(flag) stop end; ! of lisp endoffile