vsl1.c 125 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061
  1. // Visible Lisp A C Norman, August 2012
  2. //
  3. // This is a small Lisp system. It is especially
  4. // intended for use of the Raspberry Pi board, but should build
  5. // on almost any computer with a modern C compiler.
  6. // This code may be used subject to the BSD licence included in the file
  7. // "bsd.txt" that should accompany it.
  8. #ifdef __GNUC__
  9. #define INLINE inline
  10. #define USE_INLINE
  11. #else // __GNUC__
  12. #define INLINE
  13. #endif // __GNUC__
  14. //#ifndef DEBUG
  15. //#define NDEBUG 1
  16. //#endif // DEBUG
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <ctype.h>
  21. #include <time.h>
  22. #include <errno.h>
  23. #include <math.h>
  24. #include <stdint.h>
  25. #include <inttypes.h>
  26. #include <stdarg.h>
  27. #include <assert.h>
  28. #ifndef NO_ZLIB
  29. #include <zlib.h>
  30. #else
  31. typedef FILE *gzFile;
  32. static gzFile gzopen(const char *name, const char *mode)
  33. { return fopen(name, mode);
  34. }
  35. static gzclose(gzFile f)
  36. { fclose(f);
  37. }
  38. static size_t gzread(gzFile f, void *b, size_t n)
  39. { return fread(b, 1, n, f);
  40. }
  41. static void gzwrite(gzFile f, void *b, size_t n)
  42. { fwrite(b, 1, n, f);
  43. }
  44. #endif
  45. char promptstring[1000] = "> ";
  46. #ifndef NO_LIBEDIT
  47. #include <histedit.h>
  48. static EditLine *elx_e;
  49. static History *elx_h;
  50. static HistEvent elx_v;
  51. const char *prompt(EditLine *e)
  52. { return promptstring;
  53. }
  54. const char *elx_line = NULL;
  55. int elx_count = 0;
  56. #endif
  57. #ifdef WIN32
  58. #define popen _popen
  59. #endif
  60. // A Lisp item is represented as an integer and the low 3 bits
  61. // contain tag information that specify how the rest will be used.
  62. typedef intptr_t LispObject;
  63. #define TAGBITS 0x7
  64. #define tagCONS 0 // Traditional Lisp "cons" item.
  65. #define tagSYMBOL 1 // a symbol.
  66. #define tagFIXNUM 2 // An immediate integer value (29 or 61 bits).
  67. #define tagFLOAT 3 // A double-precision number.
  68. #define tagATOM 4 // Something else that will have a header word.
  69. #define tagFORWARD 5 // Used during garbage collection.
  70. #define tagHDR 6 // the header word at the start of an atom .
  71. #define tagSPARE 7 // not used!
  72. // Note that in the above I could have used tagATOM to include the case
  73. // of symbols (aka identifiers) but as an optimisation I choose to make that
  74. // a special case. I still have one spare code (tagSPARE) that could be
  75. // used to extend the system.
  76. // Now I provide macros that test the tag bits. These are all rather obvious!
  77. #define isCONS(x) (((x) & TAGBITS) == tagCONS)
  78. #define isSYMBOL(x) (((x) & TAGBITS) == tagSYMBOL)
  79. #define isFIXNUM(x) (((x) & TAGBITS) == tagFIXNUM)
  80. #define isFLOAT(x) (((x) & TAGBITS) == tagFLOAT)
  81. #define isATOM(x) (((x) & TAGBITS) == tagATOM)
  82. #define isFORWARD(x) (((x) & TAGBITS) == tagFORWARD)
  83. #define isHDR(x) (((x) & TAGBITS) == tagHDR)
  84. // In memory CONS cells and FLOATS exist as just 2-word items with
  85. // all their bits in use. All other sorts of data have a header word
  86. // at their start.
  87. // This contains extra information about the exact form of data present.
  88. #define TYPEBITS 0x78
  89. #define typeSYM 0x00
  90. #define typeGENSYM 0x08
  91. #define typeSTRING 0x10
  92. #define typeVEC 0x18
  93. #define typeBIGNUM 0x20
  94. // 0x28
  95. #define typeEQHASH 0x30
  96. #define typeEQHASHX 0x38
  97. #define typeEQUALHASH 0x40
  98. #define typeEQUALHASHX 0x48
  99. // Codes 0x28, 0x50, 0x58, 0x60, 0x68, 0x70 and 0x78 spare!
  100. #define veclength(h) (((uintptr_t)(h)) >> 7)
  101. #define packlength(n) (((LispObject)(n)) << 7)
  102. #ifdef USE_INLINE
  103. static INLINE LispObject *heapaddr(LispObject x)
  104. {
  105. return (LispObject *)x;
  106. }
  107. #else // USE_INLINE
  108. #define heapaddr(x) ((LispObject *)(x))
  109. #endif // USE_INLINE
  110. // General indirection
  111. #define qind(x) (*((LispObject *)(x)))
  112. // Accessor macros the extract fields from LispObjects ...
  113. #define qcar(x) ((heapaddr(x))[0])
  114. #define qcdr(x) ((heapaddr(x))[1])
  115. // For all other types I must remove the tagging information before I
  116. // can use the item as a pointer.
  117. // An especially important case is that of Symbols. These are the fields that
  118. // they provide.
  119. typedef LispObject SpecialForm(LispObject lits, LispObject a1);
  120. typedef LispObject LispFn(LispObject lits, int nargs, ...);
  121. #define qflags(x) ((heapaddr((x)-tagSYMBOL))[0])
  122. #define qvalue(x) ((heapaddr((x)-tagSYMBOL))[1])
  123. #define qplist(x) ((heapaddr((x)-tagSYMBOL))[2])
  124. #define qpname(x) ((heapaddr((x)-tagSYMBOL))[3])
  125. #define qlits(x) ((heapaddr((x)-tagSYMBOL))[4])
  126. #define qdefn(x) (((void **) (heapaddr((x)-tagSYMBOL)))[5])
  127. #define SYMSIZE 6
  128. // Bits within the flags field of a symbol. Uses explained later on.
  129. #define flagTRACED 0x080
  130. #define flagSPECFORM 0x100
  131. #define flagMACRO 0x200
  132. #define flagGLOBAL 0x400
  133. #define flagFLUID 0x800
  134. // There are LOTS more bits available for flags etc here if needbe!
  135. // Other atoms have a header that gives info about them. Well as a special
  136. // case I will allow that something tagged with tagATOM but with zero as
  137. // its address is a special marker value...
  138. #define NULLATOM (tagATOM + 0)
  139. #define qheader(x) ((heapaddr((x)-tagATOM))[0])
  140. // Fixnums and Floating point numbers are rather easy!
  141. #define qfixnum(x) ((x) >> 3)
  142. #define packfixnum(n) ((((LispObject)(n)) << 3) + tagFIXNUM)
  143. #define MIN_FIXNUM qfixnum(INTPTR_MIN)
  144. #define MAX_FIXNUM qfixnum(INTPTR_MAX)
  145. #define qfloat(x) (((double *)((x)-tagFLOAT))[0])
  146. #define isBIGNUM(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeBIGNUM))
  147. #define qint64(x) (*(int64_t *)((x) - tagATOM + 8))
  148. #define isSTRING(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeSTRING))
  149. #define qstring(x) ((char *)((x) - tagATOM + sizeof(LispObject)))
  150. #define isVEC(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeVEC))
  151. #define isEQHASH(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeEQHASH))
  152. #define isEQHASHX(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeEQHASHX))
  153. #define isEQUALHASH(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeEQUALHASH))
  154. #define isEQUALHASHX(x) (isATOM(x) && ((qheader(x) & TYPEBITS) == typeEQUALHASHX))
  155. // The Lisp heap will have fixed size. Here I make it 256 Mbytes on a
  156. // 32-bit machine and 612M on a 64-bit one.
  157. #ifndef MEM
  158. #define MEM (256*(sizeof(void *)/4))
  159. #endif // MEM
  160. #define BITMAPSIZE ((uintptr_t)MEM*1024*(1024/128))
  161. #define HEAPSIZE (BITMAPSIZE*128)
  162. #define STACKSIZE (128*1024*sizeof(LispObject))
  163. LispObject stackbase, *sp, stacktop;
  164. // I should probably arrange to check for stack overflow here.
  165. #define push(x) { *sp++ = (x); }
  166. #define TOS (sp[-1])
  167. #define pop(x) { (x) = *--sp; }
  168. #define push2(x, y) { push(x); push(y); }
  169. #define pop2(y, x) { pop(y); pop(x); }
  170. #define push3(x, y, z) { push(x); push(y); push(z); }
  171. #define pop3(z, y, x) { pop(z); pop(y); pop(x); }
  172. // This sets the size of the hash table used to store all the symbols
  173. // that Lisp knows about. I note that if I built a serious application
  174. // such as the Reduce algebra system (reduce-algebra.sourceforge.net) I would
  175. // end up with around 7000 symbols in a basic installation! So the size
  176. // table I use here intended to give decent performance out to that scale.
  177. // This is (of course) utterly over the top for the purpose of toy and
  178. // demonstration applications! I make the table size a prime in the hope that
  179. // that will help keep hashed distribution even across it.
  180. #define OBHASH_SIZE 1009
  181. // Some Lisp values that I will use frequently...
  182. #define nil bases[0]
  183. #define undefined bases[1]
  184. #define lisptrue bases[2]
  185. #define lispsystem bases[3]
  186. #define echo bases[4]
  187. #define lambda bases[5]
  188. #define function bases[6]
  189. #define quote bases[7]
  190. #define backquote bases[8]
  191. #define comma bases[9]
  192. #define comma_at bases[10]
  193. #define comma_dot bases[11]
  194. #define eofsym bases[12]
  195. #define cursym bases[13]
  196. #define work1 bases[14]
  197. #define work2 bases[15]
  198. #define restartfn bases[16]
  199. #define expr bases[17]
  200. #define subr bases[18]
  201. #define fexpr bases[19]
  202. #define fsubr bases[20]
  203. #define macro bases[21]
  204. #define input bases[22]
  205. #define output bases[23]
  206. #define pipe bases[24]
  207. #define raise bases[25]
  208. #define lower bases[26]
  209. #define dfprint bases[27]
  210. #define bignum bases[28]
  211. #define charvalue bases[29]
  212. #define toploopeval bases[30]
  213. #define loseflag bases[31]
  214. #define condsymbol bases[32]
  215. #define prognsymbol bases[33]
  216. #define gosymbol bases[34]
  217. #define returnsymbol bases[35]
  218. #ifdef PSL
  219. #define dummyvar bases[36]
  220. #endif
  221. #define BASES_SIZE 37
  222. LispObject bases[BASES_SIZE];
  223. LispObject obhash[OBHASH_SIZE];
  224. // ... and non-LispObject values that need to be saved as part of a
  225. // heap image.
  226. #define headerword nonbases[0]
  227. #define heap1base nonbases[1]
  228. #define heap1top nonbases[2]
  229. #define fringe1 nonbases[3]
  230. #define saveinterp nonbases[4]
  231. #define saveinterpspec nonbases[5]
  232. #define fpfringe1 nonbases[6]
  233. #define NONBASES_SIZE 7
  234. LispObject nonbases[NONBASES_SIZE];
  235. void my_exit(int n)
  236. {
  237. printf("\n+++++ Exit called %d\n", n);
  238. fflush(stdout);
  239. fflush(stderr);
  240. abort();
  241. }
  242. LispObject heap2base, heap2top, fringe2, fpfringe2, bitmap;
  243. // Here there are some memory blocks allocated, each with their
  244. // halfbitmapsize field filled in. Fill in the rest of the entries
  245. // in them.
  246. #define ALIGN8(a) (((a) + 7) & ~(LispObject)7)
  247. void allocateheap(void *pool)
  248. {
  249. heap1base = (LispObject)pool;
  250. heap1base = ALIGN8(heap1base); // ensure alignment
  251. heap1top = heap2base = heap1base + (HEAPSIZE/2);
  252. heap2top = heap2base + (HEAPSIZE/2);
  253. stackbase = heap2top;
  254. stacktop = stackbase + STACKSIZE;
  255. bitmap = stacktop;
  256. sp = (LispObject *)stackbase;
  257. fringe1 = heap1base;
  258. fringe2 = heap2base;
  259. fpfringe1 = heap1top;
  260. fpfringe2 = heap2top;
  261. }
  262. // Now I have enough to let me define various allocation functions.
  263. extern void reclaim();
  264. extern LispObject error1(const char *s, LispObject a);
  265. extern LispObject error2(const char *s, LispObject a, LispObject b);
  266. static INLINE LispObject cons(LispObject a, LispObject b)
  267. {
  268. if (fringe1 + 2*sizeof(LispObject) >= fpfringe1)
  269. { push2(a, b);
  270. reclaim();
  271. pop2(b, a);
  272. }
  273. qcar(fringe1) = a;
  274. qcdr(fringe1) = b;
  275. a = fringe1;
  276. fringe1 += 2*sizeof(LispObject);
  277. return a;
  278. }
  279. static INLINE LispObject list2star(LispObject a, LispObject b, LispObject c)
  280. { // (cons a (cons b c))
  281. if (fringe1 + 4*sizeof(LispObject) >= fpfringe1)
  282. { push3(a, b, c);
  283. reclaim();
  284. pop3(c, b, a);
  285. }
  286. qcar(fringe1) = a;
  287. qcdr(fringe1) = fringe1 + 2*sizeof(LispObject);
  288. a = fringe1;
  289. fringe1 += 2*sizeof(LispObject);
  290. qcar(fringe1) = b;
  291. qcdr(fringe1) = c;
  292. fringe1 += 2*sizeof(LispObject);
  293. return a;
  294. }
  295. static INLINE LispObject acons(LispObject a, LispObject b, LispObject c)
  296. { // (cons (cons a b) c)
  297. if (fringe1 + 4*sizeof(LispObject) >= fpfringe1)
  298. { push3(a, b, c);
  299. reclaim();
  300. pop3(c, b, a);
  301. }
  302. qcar(fringe1) = fringe1 + 2*sizeof(LispObject);
  303. qcdr(fringe1) = c;
  304. c = fringe1;
  305. fringe1 += 2*sizeof(LispObject);
  306. qcar(fringe1) = a;
  307. qcdr(fringe1) = b;
  308. fringe1 += 2*sizeof(LispObject);
  309. return c;
  310. }
  311. static INLINE LispObject boxfloat(double a)
  312. { LispObject r;
  313. if (fringe1 +sizeof(double) >= fpfringe1) reclaim();
  314. fpfringe1 -= sizeof(double);
  315. r = fpfringe1 + tagFLOAT;
  316. qfloat(r) = a;
  317. return r;
  318. }
  319. // The code here does not fill in ANY of the fields within the symbol. That
  320. // needs to be done promptly.
  321. LispObject allocatesymbol()
  322. { LispObject r;
  323. if (fringe1 + 4*sizeof(LispObject) >= fpfringe1) reclaim();
  324. r = fringe1 + tagSYMBOL;
  325. qflags(r) = tagHDR + typeSYM;
  326. fringe1 += 6*sizeof(LispObject);
  327. return r;
  328. }
  329. // This one allocates an atom that is n bytes long (plus its header
  330. // word) and again does not fill in ANY of the fields.
  331. static INLINE LispObject allocateatom(int n)
  332. { LispObject r;
  333. // The actual amount of space allocated must include a word for the
  334. // header and must then be rounded up to be a multiple of 8.
  335. int nn = ALIGN8(sizeof(LispObject) + n);
  336. if (fringe1 + nn >= fpfringe1) reclaim();
  337. r = fringe1 + tagATOM;
  338. // I mark the new vector as being a string so that it is GC safe
  339. qheader(r) = tagHDR + typeSTRING + packlength(n);
  340. fringe1 += nn;
  341. return r;
  342. }
  343. static INLINE LispObject makestring(const char *s, int len)
  344. {
  345. LispObject r = allocateatom(len);
  346. // qheader(r) = tagHDR + typeSTRING + packlength(len); // already done!
  347. memcpy(qstring(r), s, len);
  348. return r;
  349. }
  350. #define elt(v, n) \
  351. (((LispObject *)((v)-tagATOM+sizeof(LispObject)))[n])
  352. static INLINE LispObject makevector(int maxindex)
  353. { int i, len = (maxindex+1)*sizeof(LispObject);
  354. LispObject r = allocateatom(len);
  355. qheader(r) = tagHDR + typeVEC + packlength(len);
  356. for (i=0; i<=maxindex; i++) elt(r, i) = nil;
  357. return r;
  358. }
  359. static INLINE LispObject boxint64(int64_t a)
  360. {
  361. LispObject r = allocateatom(8);
  362. qheader(r) = tagHDR + typeBIGNUM + packlength(8);
  363. qint64(r) = a;
  364. return r;
  365. }
  366. // I will try to have a general macro that will help me with bringing
  367. // everything to consistent numeric types - ie I can start off with a
  368. // mix of fixnums, bignums and floats. The strategy here is that if either
  369. // args is a float then the other is forced to that, and then for all sorts
  370. // of pure integer work everything will be done as int64_t
  371. #define NUMOP(name, a, b) \
  372. if (isFLOAT(a)) \
  373. { if (isFLOAT(b)) return FF(qfloat(a), qfloat(b)); \
  374. else if (isFIXNUM(b)) return FF(qfloat(a), (double)qfixnum(b)); \
  375. else if (isBIGNUM(b)) return FF(qfloat(a), (double)qint64(b)); \
  376. else return error1("Bad argument for " name, b); \
  377. } \
  378. else if (isBIGNUM(a)) \
  379. { if (isFLOAT(b)) return FF((double)qint64(a), qfloat(b)); \
  380. else if (isFIXNUM(b)) return BB(qint64(a), (int64_t)qfixnum(b)); \
  381. else if (isBIGNUM(b)) return BB(qint64(a), qint64(b)); \
  382. else return error1("Bad argument for " name, b); \
  383. } \
  384. else if (isFIXNUM(a)) \
  385. { if (isFLOAT(b)) return FF((double)qfixnum(a), qfloat(b)); \
  386. else if (isFIXNUM(b)) return BB((int64_t)qfixnum(a), \
  387. (int64_t)qfixnum(b)); \
  388. else if (isBIGNUM(b)) return BB((int64_t)qfixnum(a), qint64(b)); \
  389. else return error1("Bad argument for " name, b); \
  390. } \
  391. else return error1("Bad argument for " name, a)
  392. #define UNARYOP(name, a) \
  393. if (isFIXNUM(a)) return BB((int64_t)qfixnum(a)); \
  394. else if (isFLOAT(a)) return FF(qfloat(a)); \
  395. else if (isBIGNUM(a)) return BB(qint64(a)); \
  396. else return error1("Bad argument for " name, a)
  397. // Similar, but only supporting integer (not floating point) values
  398. #define INTOP(name, a, b) \
  399. if (isBIGNUM(a)) \
  400. { if (isFIXNUM(b)) return BB(qint64(a), (int64_t)qfixnum(b)); \
  401. else if (isBIGNUM(b)) return BB(qint64(a), qint64(b)); \
  402. else return error1("Bad argument for " name, b); \
  403. } \
  404. else if (isFIXNUM(a)) \
  405. { if (isFIXNUM(b)) return BB((int64_t)qfixnum(a), \
  406. (int64_t)qfixnum(b)); \
  407. else if (isBIGNUM(b)) return BB((int64_t)qfixnum(a), qint64(b)); \
  408. else return error1("Bad argument for " name, b); \
  409. } \
  410. else return error1("Bad argument for " name, a)
  411. #define UNARYINTOP(name, a) \
  412. if (isFIXNUM(a)) return BB((int64_t)qfixnum(a)); \
  413. else if (isBIGNUM(a)) return BB(qint64(a)); \
  414. else return error1("Bad argument for " name, a)
  415. // This takes an arbitrary 64-bit integer and returns either a fixnum
  416. // or a bignum as necessary.
  417. LispObject makeinteger(int64_t a)
  418. { if (a >= MIN_FIXNUM && a <= MAX_FIXNUM) return packfixnum(a);
  419. else return boxint64(a);
  420. }
  421. #undef FF
  422. #undef BB
  423. #define FF(a) boxfloat(-(a))
  424. #define BB(a) makeinteger(-(a))
  425. LispObject Nminus(LispObject a)
  426. { UNARYOP("minus", a);
  427. }
  428. #undef FF
  429. #undef BB
  430. #define FF(a, b) boxfloat((a) + (b))
  431. #define BB(a, b) makeinteger((a) + (b))
  432. LispObject Nplus2(LispObject a, LispObject b)
  433. { NUMOP("plus", a, b);
  434. }
  435. #undef FF
  436. #undef BB
  437. #define FF(a, b) boxfloat((a) * (b))
  438. #define BB(a, b) makeinteger((a) * (b))
  439. LispObject Ntimes2(LispObject a, LispObject b)
  440. { NUMOP("times", a, b);
  441. }
  442. #undef BB
  443. #define BB(a, b) makeinteger((a) & (b))
  444. LispObject Nlogand2(LispObject a, LispObject b)
  445. { INTOP("logand", a, b);
  446. }
  447. #undef BB
  448. #define BB(a, b) makeinteger((a) | (b))
  449. LispObject Nlogor2(LispObject a, LispObject b)
  450. { INTOP("logor", a, b);
  451. }
  452. #undef BB
  453. #define BB(a, b) makeinteger((a) ^ (b))
  454. LispObject Nlogxor2(LispObject a, LispObject b)
  455. { INTOP("logxor", a, b);
  456. }
  457. #undef FF
  458. #undef BB
  459. #define BOFFO_SIZE 4096
  460. char boffo[BOFFO_SIZE+4];
  461. int boffop;
  462. #define swap(a,b) w = (a); (a) = (b); (b) = w;
  463. static INLINE LispObject copy(LispObject x);
  464. int gccount = 1;
  465. #define allocate_memory(n) malloc(n)
  466. void disaster(int line)
  467. { printf("\nInternal inconsistency detected on line %d\n", line);
  468. printf("Unable to continue. Apologies.\n");
  469. abort();
  470. }
  471. void reclaim()
  472. {
  473. // The strategy here is due to C J Cheyney ("A Nonrecursive List Compacting
  474. // Algorithm". Communications of the ACM 13 (11): 677-678, 1970).
  475. LispObject *s, w;
  476. printf("+++ GC number %d", gccount++);
  477. // I need to clear the part of the bitmap that could be relevant for floating
  478. // point values.
  479. int o = (fpfringe1 - heap1base)/(8*8);
  480. while (o < BITMAPSIZE) ((unsigned char *)bitmap)[o++] = 0;
  481. // Process everything that is on the stack.
  482. for (s=(LispObject *)stackbase; s<sp; s++) *s = copy(*s);
  483. // I should also copy any other list base values here.
  484. for (o=0; o<BASES_SIZE; o++) bases[o] = copy(bases[o]);
  485. for (o=0; o<OBHASH_SIZE; o++)
  486. obhash[o] = copy(obhash[o]);
  487. // Now perform the second part of Cheyney's algorithm, scanning the
  488. // data that has been put in the new heap.
  489. s = (LispObject *)heap2base;
  490. while ((LispObject)s != fringe2)
  491. { LispObject h = *s;
  492. if (!isHDR(h)) // The item to be processed is a simple cons cell
  493. { *s++ = copy(h);
  494. *s = copy(*s);
  495. s++;
  496. }
  497. else // The item is one that uses a header
  498. switch (h & TYPEBITS)
  499. { case typeSYM:
  500. case typeGENSYM:
  501. w = ((LispObject)s) + tagSYMBOL;
  502. // qflags(w) does not need adjusting
  503. qvalue(w) = copy(qvalue(w));
  504. qplist(w) = copy(qplist(w));
  505. qpname(w) = copy(qpname(w));
  506. // qdefn(w) does not need adjusting
  507. qlits(w) = copy(qlits(w));
  508. s += 6;
  509. continue;
  510. case typeSTRING:
  511. case typeBIGNUM:
  512. // These only contain binary information, so none of their content needs
  513. // any more processing.
  514. w = (sizeof(LispObject) + veclength(h) + 7) & ~7;
  515. s += w/sizeof(LispObject);
  516. continue;
  517. case typeVEC:
  518. case typeEQHASH:
  519. case typeEQHASHX:
  520. case typeEQUALHASH:
  521. case typeEQUALHASHX:
  522. // These are to be processed the same way. They contain a bunch of
  523. // reference items.
  524. s++; // Past the header
  525. w = veclength(h);
  526. while (w > 0)
  527. { *s = copy(*s);
  528. s++;
  529. w -= sizeof(LispObject);
  530. }
  531. w = (LispObject)s;
  532. w = (w + 7) & ~7;
  533. s = (LispObject *)w;
  534. continue;
  535. default:
  536. // all the "spare" codes!
  537. disaster(__LINE__);
  538. }
  539. }
  540. // Finally flip the two heaps ready for next time.
  541. swap(heap1base, heap2base);
  542. swap(heap1top, heap2top);
  543. fringe1 = fringe2;
  544. fpfringe1 = fpfringe2;
  545. fringe2 = heap2base;
  546. fpfringe2 = heap2top;
  547. printf(" - collection complete (%" PRIu64 " Kbytes free)\n",
  548. ((uint64_t)(fpfringe1-fringe1))/1024);
  549. if (fpfringe1 - fringe1 < 1000*sizeof(LispObject))
  550. { printf("\nRun out of memory.\n");
  551. exit(1);
  552. }
  553. fflush(stdout);
  554. }
  555. LispObject copy(LispObject x)
  556. { LispObject h;
  557. int o, b;
  558. switch (x & TAGBITS)
  559. { case tagCONS:
  560. if (x == 0) disaster(__LINE__);
  561. h = *((LispObject *)x);
  562. if (isFORWARD(h)) return (h - tagFORWARD);
  563. qcar(fringe2) = h;
  564. qcdr(fringe2) = qcdr(x);
  565. h = fringe2;
  566. qcar(x) = tagFORWARD + h;
  567. fringe2 += 2*sizeof(LispObject);
  568. return h;
  569. case tagSYMBOL:
  570. h = *((LispObject *)(x - tagSYMBOL));
  571. if (isFORWARD(h)) return (h - tagFORWARD + tagSYMBOL);
  572. if (!isHDR(h)) disaster(__LINE__);
  573. h = fringe2 + tagSYMBOL;
  574. qflags(h) = qflags(x);
  575. qvalue(h) = qvalue(x);
  576. qplist(h) = qplist(x);
  577. qpname(h) = qpname(x);
  578. qdefn(h) = qdefn(x);
  579. qlits(h) = qlits(x);
  580. fringe2 += 6*sizeof(LispObject);
  581. qflags(x) = h - tagSYMBOL + tagFORWARD;
  582. return h;
  583. case tagATOM:
  584. if (x == NULLATOM) return x; // special case!
  585. h = qheader(x);
  586. if (isFORWARD(h)) return (h - tagFORWARD + tagATOM);
  587. if (!isHDR(h)) disaster(__LINE__);
  588. switch (h & TYPEBITS)
  589. { case typeEQHASH:
  590. case typeEQUALHASH:
  591. // When a hash table is copied its header is changes to EQHASHX, which
  592. // indicates that it will need rehashing before further use.
  593. qheader(x) ^= (typeEQHASH ^ typeEQHASHX);
  594. case typeEQHASHX:
  595. case typeEQUALHASHX:
  596. case typeSTRING:
  597. case typeVEC:
  598. case typeBIGNUM:
  599. o = (int)veclength(h); // number of bytes excluding the header
  600. *((LispObject *)fringe2) = h; // copy header word across
  601. h = fringe2 + tagATOM;
  602. *((LispObject *)(x - tagATOM)) = fringe2 + tagFORWARD;
  603. fringe2 += sizeof(LispObject);
  604. x = x - tagATOM + sizeof(LispObject);
  605. while (o > 0)
  606. { *((LispObject *)fringe2) = *((LispObject *)x);
  607. fringe2 += sizeof(LispObject);
  608. x += sizeof(LispObject);
  609. o -= sizeof(LispObject);
  610. }
  611. fringe2 = (fringe2 + 7) & ~7;
  612. return h;
  613. default:
  614. //case typeSYM: case typeGENSYM:
  615. // also the spare codes!
  616. disaster(__LINE__);
  617. }
  618. case tagFLOAT:
  619. // every float is 8 bytes wide, regardless of what sort of machine I am on.
  620. h = (x - tagFLOAT - heap1base)/8;
  621. o = h/8;
  622. b = 1 << (h%8);
  623. // now o is an offset and b a bit in the bitmap.
  624. if ((((unsigned char *)bitmap)[o] & b) != 0) // marked already.
  625. return *((LispObject *)(x-tagFLOAT));
  626. else
  627. { ((unsigned char *)bitmap)[o] |= b; // mark it now.
  628. fpfringe2 -= sizeof(double);
  629. h = fpfringe2 + tagFLOAT;
  630. qfloat(h) = qfloat(x); // copy the float.
  631. *((LispObject *)(x-tagFLOAT)) = h; // write in forwarding address.
  632. return h;
  633. }
  634. case tagFIXNUM:
  635. return x;
  636. default:
  637. //case tagFORWARD:
  638. //case tagHDR:
  639. disaster(__LINE__);
  640. return 0; // avoid GCC moans.
  641. }
  642. }
  643. #define printPLAIN 1
  644. #define printESCAPES 2
  645. #define printHEX 4
  646. // I suspect that linelength and linepos need to be maintained
  647. // independently for each output stream. At present that is not
  648. // done.
  649. int linelength = 80, linepos = 0, printflags = printESCAPES;
  650. #define MAX_LISPFILES 30
  651. #ifdef DEBUG
  652. FILE *lispfiles[MAX_LISPFILES], *logfile = NULL;
  653. #else // DEBUG
  654. FILE *lispfiles[MAX_LISPFILES];
  655. #endif // DEBUG
  656. int curchars[MAX_LISPFILES+1];
  657. int symtypes[MAX_LISPFILES+1];
  658. #define curchar curchars[lispin+1]
  659. #define symtype symtypes[lispin+1]
  660. int32_t file_direction = 0, interactive = 0;
  661. int lispin = 0, lispout = 1;
  662. extern LispObject lookup(const char *s, int n, int flags);
  663. void wrch(int c)
  664. {
  665. if (lispout == -1)
  666. { char w[4];
  667. // This bit is for the benefit of explode and explodec.
  668. LispObject r;
  669. w[0] = c; w[1] = 0;
  670. r = lookup(w, 1, 1);
  671. work1 = cons(r, work1);
  672. }
  673. else if (lispout == -2) boffo[boffop++] = c;
  674. else
  675. { putc(c, lispfiles[lispout]);
  676. #ifdef DEBUG
  677. if (logfile != NULL)
  678. { putc(c, logfile);
  679. if (c == '\n')
  680. { fprintf(logfile, "%d]", lispout);
  681. }
  682. }
  683. #endif // DEBUG
  684. if (c == '\n')
  685. { linepos = 0;
  686. fflush(lispfiles[lispout]);
  687. }
  688. else linepos++;
  689. }
  690. }
  691. int my_getc(FILE *f)
  692. {
  693. #ifdef NO_LIBEDIT
  694. // This can help while running under a debugger!
  695. return getc(f);
  696. #else
  697. if (f != stdin) return getc(f);
  698. if (elx_count == 0)
  699. { elx_line = el_gets(elx_e, &elx_count);
  700. if (elx_count <= 0) return EOF;
  701. if (elx_count > 1 || (elx_line[0] != '\n' && elx_line[0] != '\r'))
  702. history(elx_h, &elx_v, H_ENTER, elx_line);
  703. }
  704. elx_count--;
  705. return *elx_line++;
  706. #endif
  707. }
  708. int rdch()
  709. { LispObject w;
  710. if (lispin == -1)
  711. { if (!isCONS(work1)) return EOF;
  712. w = qcar(work1);
  713. work1 = qcdr(work1);
  714. if (isSYMBOL(w)) w = qpname(w);
  715. if (!isSTRING(w)) return EOF;
  716. return *qstring(w);
  717. }
  718. else
  719. { int c = my_getc(lispfiles[lispin]);
  720. #ifdef DEBUG
  721. if (c != EOF /*&& qvalue(echo) != nil*/) wrch(c);
  722. #else // DEBUG
  723. if (c != EOF && qvalue(echo) != nil) wrch(c);
  724. #endif // DEBUG
  725. return c;
  726. }
  727. }
  728. int gensymcounter = 1;
  729. void checkspace(int n)
  730. { if (linepos + n >= linelength && lispout != -1) wrch('\n');
  731. }
  732. char printbuffer[32];
  733. extern LispObject call1(const char *name, LispObject a1);
  734. extern LispObject call2(const char *name, LispObject a1, LispObject a2);
  735. void internalprint(LispObject x)
  736. { int sep = '(', i, esc, len;
  737. char *s;
  738. LispObject pn;
  739. i = 0;
  740. int some = 0;
  741. switch (x & TAGBITS)
  742. { case tagCONS:
  743. if (x == 0) // can only occur in case of bugs here.
  744. { wrch('#');
  745. return;
  746. }
  747. while (isCONS(x))
  748. { i = printflags;
  749. if (qcar(x) == bignum &&
  750. (pn = call1("~big2str", qcdr(x))) != NULLATOM &&
  751. pn != nil)
  752. { printflags = printPLAIN;
  753. internalprint(pn);
  754. printflags = i;
  755. if (some == 0) return;
  756. else break;
  757. }
  758. printflags = i;
  759. checkspace(1);
  760. if (linepos != 0 || sep != ' ' || lispout < 0) wrch(sep);
  761. sep = ' ';
  762. push(x);
  763. internalprint(qcar(x));
  764. pop(x);
  765. some = 1;
  766. x = qcdr(x);
  767. }
  768. if (x != nil)
  769. { checkspace(3);
  770. wrch(' '); wrch('.'); wrch(' ');
  771. internalprint(x);
  772. }
  773. checkspace(1);
  774. wrch(')');
  775. return;
  776. case tagSYMBOL:
  777. pn = qpname(x);
  778. if (pn == nil)
  779. { int len = sprintf(printbuffer, "g%.3d", gensymcounter++);
  780. push(x);
  781. pn = makestring(printbuffer, len);
  782. pop(x);
  783. qpname(x) = pn;
  784. }
  785. len = veclength(qheader(pn));
  786. s = qstring(pn);
  787. if ((printflags & printESCAPES) == 0)
  788. { int i;
  789. checkspace(len);
  790. for (i=0; i<len; i++) wrch(s[i]);
  791. }
  792. else if (len != 0)
  793. { esc = 0;
  794. if (!islower((int)s[0])) esc++;
  795. for (i=1; i<len; i++)
  796. { if (!islower((int)s[i]) &&
  797. !isdigit((int)s[i]) &&
  798. s[i]!='_') esc++;
  799. }
  800. checkspace(len + esc);
  801. if (!islower((int)s[0])) wrch('!');
  802. wrch(s[0]);
  803. for (i=1; i<len; i++)
  804. { if (!islower((int)s[i]) &&
  805. !isdigit((int)s[i]) &&
  806. s[i]!='_')
  807. wrch('!');
  808. wrch(s[i]);
  809. }
  810. }
  811. return;
  812. case tagATOM:
  813. if (x == NULLATOM)
  814. { checkspace(5);
  815. wrch('#'); wrch('n'); wrch('u'); wrch('l'); wrch('l');
  816. return;
  817. }
  818. else switch (qheader(x) & TYPEBITS)
  819. { case typeSTRING:
  820. len = veclength(qheader(x));
  821. push(x);
  822. #define RAWSTRING qstring(TOS)
  823. if ((printflags & printESCAPES) == 0)
  824. { int i;
  825. checkspace(len);
  826. for (i=0; i<len; i++) wrch(RAWSTRING[i]);
  827. }
  828. else
  829. { esc = 2;
  830. for (i=0; i<len; i++)
  831. if (RAWSTRING[i] == '"') esc++;
  832. checkspace(len+esc);
  833. wrch('"');
  834. for (i=0; i<len; i++)
  835. { if (RAWSTRING[i] == '"') wrch('"');
  836. wrch(RAWSTRING[i]);
  837. }
  838. wrch('"');
  839. }
  840. pop(x);
  841. #undef RAWSTRING
  842. return;
  843. case typeBIGNUM:
  844. sprintf(printbuffer, "%" PRId64, qint64(x));
  845. checkspace(len = strlen(printbuffer));
  846. for (i=0; i<len; i++) wrch(printbuffer[i]);
  847. return;
  848. case typeVEC:
  849. i++;
  850. case typeEQUALHASH:
  851. i++;
  852. case typeEQUALHASHX:
  853. i++;
  854. case typeEQHASH:
  855. i++;
  856. case typeEQHASHX:
  857. switch (i)
  858. {
  859. // EQ hash table #h
  860. // EQUALhash table #H
  861. // ditto but in need of rehashing #g or 'G
  862. case 0:
  863. wrch('#'); wrch('g');
  864. break;
  865. case 1:
  866. wrch('#'); wrch('h');
  867. break;
  868. case 2:
  869. wrch('#'); wrch('G');
  870. break;
  871. case 3:
  872. wrch('#'); wrch('H');
  873. break;
  874. case 4:
  875. break;
  876. }
  877. sep = '[';
  878. push(x);
  879. for (i=0; i<veclength(qheader(TOS))/sizeof(LispObject); i++)
  880. { checkspace(1);
  881. wrch(sep);
  882. sep = ' ';
  883. internalprint(elt(TOS, i));
  884. }
  885. pop(x);
  886. checkspace(1);
  887. wrch(']');
  888. return;
  889. default:
  890. //case typeSYM:
  891. // also the spare codes!
  892. assert(0);
  893. }
  894. case tagFLOAT:
  895. { double d = *((double *)(x - tagFLOAT));
  896. if (isnan(d)) strcpy(printbuffer, "NaN");
  897. else if (isfinite(d)) sprintf(printbuffer, "%.14g", d);
  898. else strcpy(printbuffer, "inf");
  899. }
  900. s = printbuffer;
  901. // The C printing of floating point values is not to my taste, so I (slightly)
  902. // asjust the output here...
  903. if (*s == '+' || *s == '-') s++;
  904. while (isdigit((int)*s)) s++;
  905. if (*s == 0 || *s == 'e') // No decimal point present!
  906. { len = strlen(s);
  907. while (len >= 0) // Move existing text up 2 places
  908. { s[len+2] = s[len];
  909. len--;
  910. }
  911. s[0] = '.'; s[1] = '0'; // insert ".0"
  912. }
  913. checkspace(len = strlen(printbuffer));
  914. for (i=0; i<len; i++) wrch(printbuffer[i]);
  915. return;
  916. case tagFIXNUM:
  917. sprintf(printbuffer, "%" PRId64, (int64_t)qfixnum(x));
  918. checkspace(len = strlen(printbuffer));
  919. for (i=0; i<len; i++) wrch(printbuffer[i]);
  920. return;
  921. default:
  922. //case tagFORWARD:
  923. //case tagHDR:
  924. // sprintf(printbuffer, "??%#" PRIxPTR "??\n", x);
  925. // checkspace(len = strlen(printbuffer));
  926. // for (i=0; i<len; i++) wrch(printbuffer[i]);
  927. assert(0);
  928. }
  929. }
  930. LispObject prin(LispObject a)
  931. { printflags = printESCAPES;
  932. push(a);
  933. internalprint(a);
  934. pop(a);
  935. return a;
  936. }
  937. LispObject princ(LispObject a)
  938. { printflags = printPLAIN;
  939. push(a);
  940. internalprint(a);
  941. pop(a);
  942. return a;
  943. }
  944. LispObject prinhex(LispObject a)
  945. { printflags = printESCAPES | printHEX;
  946. push(a);
  947. internalprint(a);
  948. pop(a);
  949. return a;
  950. }
  951. LispObject print(LispObject a)
  952. { printflags = printESCAPES;
  953. push(a);
  954. internalprint(a);
  955. pop(a);
  956. wrch('\n');
  957. return a;
  958. }
  959. void errprint(LispObject a)
  960. { int saveout = lispout, saveflags = printflags;
  961. lispout = 1; printflags = printESCAPES;
  962. push(a);
  963. internalprint(a);
  964. pop(a);
  965. wrch('\n');
  966. lispout = saveout; printflags = saveflags;
  967. }
  968. void errprin(LispObject a)
  969. { int saveout = lispout, saveflags = printflags;
  970. lispout = 1; printflags = printESCAPES;
  971. push(a);
  972. internalprint(a);
  973. pop(a);
  974. lispout = saveout; printflags = saveflags;
  975. }
  976. LispObject printc(LispObject a)
  977. { printflags = printPLAIN;
  978. push(a);
  979. internalprint(a);
  980. pop(a);
  981. wrch('\n');
  982. return a;
  983. }
  984. int hexval(int n)
  985. { if (isdigit(n)) return n - '0';
  986. else if ('a' <= n && n <= 'f') return n - 'a' + 10;
  987. else if ('A' <= n && n <= 'F') return n - 'A' + 10;
  988. else return 0;
  989. }
  990. LispObject token()
  991. { symtype = 'a'; // Default result is an atom.
  992. while (1)
  993. { while (curchar == ' ' ||
  994. curchar == '\t' ||
  995. curchar == '\n') curchar = rdch(); // Skip whitespace
  996. // Discard comments from "%" to end of line.
  997. if (curchar == '%')
  998. { while (curchar != '\n' &&
  999. curchar != EOF) curchar = rdch();
  1000. continue;
  1001. }
  1002. break;
  1003. }
  1004. if (curchar == EOF)
  1005. { symtype = curchar;
  1006. return NULLATOM; // End of file marker.
  1007. }
  1008. if (curchar == '(' || curchar == '.' ||
  1009. curchar == ')' || curchar == '\'' ||
  1010. curchar == '`' || curchar == ',')
  1011. { symtype = curchar; // Lisp special characters.
  1012. curchar = rdch();
  1013. if (symtype == ',' && curchar == '@')
  1014. { symtype = '@';
  1015. curchar = rdch();
  1016. }
  1017. return NULLATOM;
  1018. }
  1019. boffop = 0;
  1020. if (isalpha(curchar) || curchar == '!') // Start a symbol.
  1021. { while (isalpha(curchar) ||
  1022. isdigit(curchar) ||
  1023. curchar == '_' ||
  1024. curchar == '!')
  1025. { if (curchar == '!') curchar = rdch();
  1026. else if (curchar != EOF && qvalue(lower) != nil) curchar = tolower(curchar);
  1027. else if (curchar != EOF && qvalue(raise) != nil) curchar = toupper(curchar);
  1028. if (curchar != EOF)
  1029. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1030. curchar = rdch();
  1031. }
  1032. }
  1033. boffo[boffop] = 0;
  1034. return lookup(boffo, boffop, 1);
  1035. }
  1036. if (curchar == '"') // Start a string
  1037. { curchar = rdch();
  1038. while (1)
  1039. { while (curchar != '"' && curchar != EOF)
  1040. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1041. curchar = rdch();
  1042. }
  1043. // Note that a double-quote can be repeated within a string to denote
  1044. // a string with that character within it. As in
  1045. // "abc""def" is a string with contents abc"def.
  1046. if (curchar != EOF) curchar = rdch();
  1047. if (curchar != '"') break;
  1048. if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1049. curchar = rdch();
  1050. }
  1051. return makestring(boffo, boffop);
  1052. }
  1053. if (curchar == '+' || curchar == '-')
  1054. { boffo[boffop++] = curchar;
  1055. curchar = rdch();
  1056. // + and - are treated specially, since if followed by a digit they
  1057. // introduce a (signed) number, but otherwise they are treated as punctuation.
  1058. if (!isdigit(curchar))
  1059. { boffo[boffop] = 0;
  1060. return lookup(boffo, boffop, 1);
  1061. }
  1062. }
  1063. // Note that in some cases after a + or - I drop through to here.
  1064. if (curchar == '0' && boffop == 0) // "0" without a sign in front
  1065. { boffo[boffop++] = curchar;
  1066. curchar = rdch();
  1067. if (curchar == 'x' || curchar == 'X') // Ahah - hexadecimal input
  1068. { LispObject r;
  1069. boffop = 0;
  1070. curchar = rdch();
  1071. while (isxdigit(curchar))
  1072. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1073. curchar = rdch();
  1074. }
  1075. r = packfixnum(0);
  1076. boffop = 0;
  1077. while (boffo[boffop] != 0)
  1078. { r = call2("plus2", call2("times2", packfixnum(16), r),
  1079. packfixnum(hexval(boffo[boffop++])));
  1080. }
  1081. return r;
  1082. }
  1083. }
  1084. if (isdigit(curchar) || (boffop == 1 && boffo[0] == '0'))
  1085. { while (isdigit(curchar))
  1086. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1087. curchar = rdch();
  1088. }
  1089. // At this point I have a (possibly signed) integer. If it is immediately
  1090. // followed by a "." then a floating point value is indicated.
  1091. if (curchar == '.')
  1092. { symtype = 'f';
  1093. if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1094. curchar = rdch();
  1095. while (isdigit(curchar))
  1096. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1097. curchar = rdch();
  1098. }
  1099. // To make things tidy If I have a "." not followed by any digits I will
  1100. // insert a "0".
  1101. if (!isdigit((int)boffo[boffop-1])) boffo[boffop++] = '0';
  1102. }
  1103. // Whether or not there was a ".", an "e" or "E" introduces an exponent and
  1104. // hence indicates a floating point value.
  1105. if (curchar == 'e' || curchar == 'E')
  1106. { symtype = 'f';
  1107. if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1108. curchar = rdch();
  1109. if (curchar == '+' || curchar == '-')
  1110. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1111. curchar = rdch();
  1112. }
  1113. while (isdigit(curchar))
  1114. { if (boffop < BOFFO_SIZE) boffo[boffop++] = curchar;
  1115. curchar = rdch();
  1116. }
  1117. // If there had been an "e" I force at least one digit in following it.
  1118. if (!isdigit((int)boffo[boffop-1])) boffo[boffop++] = '0';
  1119. }
  1120. boffo[boffop] = 0;
  1121. if (symtype == 'a')
  1122. { int neg = 0;
  1123. LispObject r = packfixnum(0);
  1124. boffop = 0;
  1125. if (boffo[boffop] == '+') boffop++;
  1126. else if (boffo[boffop] == '-') neg=1, boffop++;
  1127. while (boffo[boffop] != 0)
  1128. { r = call2("plus2", call2("times2", packfixnum(10), r),
  1129. packfixnum(boffo[boffop++] - '0'));
  1130. }
  1131. if (neg) r = call1("minus", r);
  1132. return r;
  1133. }
  1134. else
  1135. { double d;
  1136. sscanf(boffo, "%lg", &d);
  1137. return boxfloat(d);
  1138. }
  1139. }
  1140. boffo[boffop++] = curchar;
  1141. curchar = rdch();
  1142. boffo[boffop] = 0;
  1143. symtype = 'a';
  1144. return lookup(boffo, boffop, 1);
  1145. }
  1146. extern LispObject Lget(LispObject lits, int nargs, ...);
  1147. LispObject char_function(LispObject a)
  1148. { if (!isSYMBOL(a)) return nil;
  1149. LispObject pn = qpname(a);
  1150. char *s = qstring(pn);
  1151. if (strlen(s) == 1) return packfixnum(s[0]);
  1152. return Lget(nil, 2, a, charvalue);
  1153. }
  1154. // S ::= name
  1155. // | integer
  1156. // | radix#based-integer
  1157. // | float
  1158. // | string
  1159. // | ' S | ` S | , S | ,@ S | ,. S
  1160. // | #/ char integer code for char
  1161. // | #\ char integer code is char is single character,
  1162. // otherwise NULL, BELL, BACKSPACE, TAB, LF, EOL,
  1163. // FF, CR, EOF, ESC, ESCAPE, SPACE, RUBOUT, RUB,
  1164. // DELETE, DEL, (lower x), (control x), (ctrl x),
  1165. // (meta x). *raise can case-fold x unless ! is used.
  1166. // | #' S
  1167. // | #. S
  1168. // | #+ S S
  1169. // | #- S S
  1170. // | ( T
  1171. // | [ V
  1172. // ;
  1173. //
  1174. // T ::= )
  1175. // | . S )
  1176. // | S T
  1177. // ;
  1178. //
  1179. // V ::= ]
  1180. // | S V
  1181. // ;
  1182. extern LispObject readS();
  1183. extern LispObject readT();
  1184. extern LispObject readV();
  1185. extern LispObject eval(LispObject x);
  1186. LispObject read_hash_macro()
  1187. { LispObject w;
  1188. int c = curchar;
  1189. curchar = rdch();
  1190. switch (c)
  1191. { case '\'': // #'X => (function X)
  1192. cursym = token();
  1193. w = readS();
  1194. return list2star(function, w, nil);
  1195. case '.':
  1196. cursym = token();
  1197. w = readS();
  1198. return eval(w);
  1199. case '+':
  1200. cursym = token();
  1201. w = readS();
  1202. // For now I will suppose that the machine in use is NEVER one of the
  1203. // ones tested fpr. The consequence is that "#+ machine S" always gets
  1204. // ignored.
  1205. (void)readS();
  1206. return readS();
  1207. case '-':
  1208. cursym = token();
  1209. w = readS();
  1210. // To match the behaviour of #+ I just make "#- machine" get ignored so that
  1211. // the S-expression beyond that is the one that is read.
  1212. return readS();
  1213. case '/':
  1214. c = curchar;
  1215. curchar = rdch();
  1216. cursym = token();
  1217. return packfixnum(c & 0xff);
  1218. case '\\':
  1219. cursym = token();
  1220. w = readS();
  1221. return char_function(w);
  1222. default:
  1223. return nil;
  1224. }
  1225. }
  1226. LispObject list_to_vector(LispObject a)
  1227. { int n = 0;
  1228. for (LispObject p=a; p!=nil; p=qcdr(p)) n++;
  1229. LispObject r = makevector(n-1);
  1230. n = 0;
  1231. for (LispObject p=a; p!=nil; p=qcdr(p)) elt(r, n++) = qcar(p);
  1232. return r;
  1233. }
  1234. LispObject readS()
  1235. { LispObject q, w;
  1236. while (1)
  1237. { switch (symtype)
  1238. { case '?':
  1239. cursym = token();
  1240. continue;
  1241. case '(':
  1242. cursym = token();
  1243. return readT();
  1244. case '[':
  1245. cursym = token();
  1246. return list_to_vector(readV());
  1247. case '#':
  1248. return read_hash_macro();
  1249. case '.':
  1250. case ')': // Ignore spurious ")" input
  1251. cursym = token();
  1252. continue;
  1253. case '\'':
  1254. w = quote;
  1255. break;
  1256. case '`':
  1257. w = backquote;
  1258. break;
  1259. case ',':
  1260. w = comma;
  1261. break;
  1262. case '@':
  1263. w = comma_at;
  1264. break;
  1265. case '.'+0x100:
  1266. w = comma_dot;
  1267. break;
  1268. case EOF:
  1269. return eofsym;
  1270. default:
  1271. symtype = '?';
  1272. return cursym;
  1273. }
  1274. push(w);
  1275. cursym = token();
  1276. q = readS();
  1277. pop(w);
  1278. return list2star(w, q, nil);
  1279. }
  1280. }
  1281. LispObject readT()
  1282. { LispObject q, r;
  1283. if (symtype == '?') cursym = token();
  1284. switch (symtype)
  1285. { case EOF:
  1286. return eofsym;
  1287. case '.':
  1288. cursym = token();
  1289. q = readS();
  1290. if (symtype == '?') cursym = token();
  1291. if (symtype == ')') symtype = '?'; // Ignore if not ")".
  1292. return q;
  1293. case ')':
  1294. symtype = '?';
  1295. return nil;
  1296. // case '(': case '\'':
  1297. // case '`': case ',':
  1298. // case '@':
  1299. default:
  1300. q = readS();
  1301. push(q);
  1302. r = readT();
  1303. pop(q);
  1304. return cons(q, r);
  1305. }
  1306. }
  1307. LispObject readV()
  1308. { LispObject q, r;
  1309. if (symtype == '?') cursym = token();
  1310. switch (symtype)
  1311. { case EOF:
  1312. return eofsym;
  1313. case ']':
  1314. symtype = '?';
  1315. return nil;
  1316. default:
  1317. q = readS();
  1318. push(q);
  1319. r = readV();
  1320. pop(q);
  1321. return cons(q, r);
  1322. }
  1323. }
  1324. // createp = -1 for remob
  1325. // = 0 for lookup if exists, but do not create
  1326. // = 1 for create symbol if necessary.
  1327. LispObject lookup(const char *s, int len, int createp)
  1328. { LispObject w, pn;
  1329. int i, hash = 1;
  1330. for (i=0; i<len; i++) hash = 13*hash + s[i];
  1331. hash = (hash & 0x7fffffff) % OBHASH_SIZE;
  1332. LispObject *prev = &obhash[hash];
  1333. w = *prev;
  1334. while (w != tagFIXNUM)
  1335. { LispObject a = qcar(w); // Will be a symbol.
  1336. LispObject n = qpname(a); // Will be a string.
  1337. int l = veclength(qheader(n)); // Length of the name.
  1338. if (l == len &&
  1339. strncmp(s, qstring(n), len) == 0)
  1340. { if (createp == -1) *prev = qcdr(w);
  1341. return a; // Existing symbol found.
  1342. }
  1343. prev = &qcdr(w);
  1344. w = *prev;
  1345. }
  1346. // here the symbol as required was not already present.
  1347. if (createp <= 0) return undefined;
  1348. pn = makestring(s, len);
  1349. push(pn);
  1350. w = allocatesymbol();
  1351. pop(pn);
  1352. qflags(w) = tagHDR + typeSYM;
  1353. qvalue(w) = undefined;
  1354. qplist(w) = nil;
  1355. qpname(w) = pn;
  1356. qdefn(w) = NULL;
  1357. qlits(w) = nil;
  1358. push(w);
  1359. obhash[hash] = cons(w, obhash[hash]);
  1360. pop(w);
  1361. return w;
  1362. }
  1363. #define unwindNONE 0
  1364. #define unwindERROR 1
  1365. #define unwindBACKTRACE 2
  1366. #define unwindGO 4
  1367. #define unwindRETURN 8
  1368. #define unwindPRESERVE 16
  1369. #define unwindRESTART 32
  1370. int unwindflag = unwindNONE;
  1371. int backtraceflag = -1;
  1372. #define backtraceHEADER 1
  1373. #define backtraceTRACE 2
  1374. int forcedMIN=0, forcedMAX=3;
  1375. LispObject error1(const char *msg, LispObject data)
  1376. { if ((backtraceflag & backtraceHEADER) != 0 || forcedMIN > 0)
  1377. { linepos = printf("\n+++ Error: %s: ", msg);
  1378. #ifdef DEBUG
  1379. if (logfile != NULL) fprintf(logfile, "\n+++ Error: %s: ", msg);
  1380. #endif // DEBUG
  1381. errprint(data);
  1382. }
  1383. unwindflag = (backtraceflag & backtraceTRACE) != 0 ||
  1384. forcedMIN > 1 ? unwindBACKTRACE :
  1385. unwindERROR;
  1386. return nil;
  1387. }
  1388. LispObject error2(const char *msg, LispObject data1, LispObject data2)
  1389. { if ((backtraceflag & backtraceHEADER) != 0 || forcedMIN > 0)
  1390. { linepos = printf("\n+++ Error: %s: ", msg);
  1391. #ifdef DEBUG
  1392. if (logfile != NULL) fprintf(logfile, "\n+++ Error: %s: ", msg);
  1393. #endif // DEBUG
  1394. errprint(data1);
  1395. linepos += printf(" ");
  1396. errprint(data2);
  1397. }
  1398. unwindflag = (backtraceflag & backtraceTRACE) != 0 ||
  1399. forcedMIN > 1 ? unwindBACKTRACE : unwindERROR;
  1400. return nil;
  1401. }
  1402. LispObject error1s(const char *msg, const char *data)
  1403. { if ((backtraceflag & backtraceHEADER) != 0 || forcedMIN > 0)
  1404. #ifdef DEBUG
  1405. { printf("\n+++ Error: %s %s\n", msg, data);
  1406. if (logfile != NULL) fprintf(logfile, "\n+++ Error: %s %s\n", msg, data);
  1407. }
  1408. #else // DEBUG
  1409. printf("\n+++ Error: %s %s\n", msg, data);
  1410. #endif // DEBUG
  1411. unwindflag = (backtraceflag & backtraceTRACE) != 0 ||
  1412. forcedMIN > 1 ? unwindBACKTRACE : unwindERROR;
  1413. return nil;
  1414. }
  1415. LispObject applytostack(int n)
  1416. {
  1417. // Apply a function to n arguments.
  1418. // Here the stack has first the function, and then n arguments. The code is
  1419. // grim and basically repetitive, and to avoid it being even worse I will
  1420. // expect that almost all Lisp functions have at most 4 arguments, so
  1421. // if there are more than that I will pass the fifth and beyond all in a list.
  1422. LispObject f, w;
  1423. int traced = (qflags(sp[-n-1]) & flagTRACED) != 0;
  1424. if (traced)
  1425. { int i;
  1426. linepos = printf("Calling: ");
  1427. #ifdef DEBUG
  1428. if (logfile != NULL) fprintf(logfile, "Calling: ");
  1429. #endif // DEBUG
  1430. errprint(sp[-n-1]);
  1431. for (i=1; i<=n; i++)
  1432. { linepos = printf("Arg%d: ", i);
  1433. #ifdef DEBUG
  1434. if (logfile != NULL) fprintf(logfile, "Arg%d: ", i);
  1435. #endif // DEBUG
  1436. errprint(sp[i-n-1]);
  1437. }
  1438. }
  1439. if (n >= 5)
  1440. { push(nil);
  1441. n++;
  1442. while (n > 5)
  1443. { pop(w);
  1444. TOS = cons(TOS, w);
  1445. n--;
  1446. }
  1447. }
  1448. switch (n)
  1449. { case 0:
  1450. f = TOS;
  1451. w = (*(LispFn *)qdefn(f))(qlits(f), 0);
  1452. break;
  1453. case 1:
  1454. { LispObject a1;
  1455. pop(a1);
  1456. f = TOS;
  1457. w = (*(LispFn *)qdefn(f))(qlits(f), 1, a1);
  1458. break;
  1459. }
  1460. case 2:
  1461. { LispObject a1, a2;
  1462. pop(a2)
  1463. pop(a1);
  1464. f = TOS;
  1465. w = (*(LispFn *)qdefn(f))(qlits(f), 2, a1, a2);
  1466. break;
  1467. }
  1468. case 3:
  1469. { LispObject a1, a2, a3;
  1470. pop(a3);
  1471. pop(a2)
  1472. pop(a1);
  1473. f = TOS;
  1474. w = (*(LispFn *)qdefn(f))(qlits(f), 3, a1, a2, a3);
  1475. break;
  1476. }
  1477. case 4:
  1478. { LispObject a1, a2, a3, a4;
  1479. pop(a4);
  1480. pop(a3);
  1481. pop(a2)
  1482. pop(a1);
  1483. f = TOS;
  1484. w = (*(LispFn *)qdefn(f))(qlits(f), 4,
  1485. a1, a2, a3, a4);
  1486. break;
  1487. }
  1488. case 5:
  1489. { LispObject a1, a2, a3, a4, a5andup;
  1490. pop(a5andup);
  1491. pop(a4);
  1492. pop(a3);
  1493. pop(a2)
  1494. pop(a1);
  1495. f = TOS;
  1496. w = (*(LispFn *)qdefn(f))(qlits(f), 5,
  1497. a1, a2, a3, a4, a5andup);
  1498. break;
  1499. }
  1500. default:
  1501. assert(0);
  1502. return nil;
  1503. }
  1504. pop(f);
  1505. if (unwindflag == unwindBACKTRACE)
  1506. { linepos = printf("Calling: ");
  1507. #ifdef DEBUG
  1508. if (logfile != NULL) fprintf(logfile, "Calling: ");
  1509. #endif // DEBUG
  1510. errprint(f);
  1511. }
  1512. else if (traced)
  1513. { push(w);
  1514. prin(f);
  1515. linepos += printf(" = ");
  1516. #ifdef DEBUG
  1517. if (logfile != NULL) fprintf(logfile, " = ");
  1518. #endif // DEBUG
  1519. errprint(w);
  1520. pop(w);
  1521. }
  1522. return w;
  1523. }
  1524. LispObject call1(const char *name, LispObject a1)
  1525. {
  1526. LispObject fn = lookup(name, strlen(name), 0);
  1527. if (fn == undefined || qdefn(fn) == NULL) return NULLATOM;
  1528. push2(fn, a1);
  1529. return applytostack(1);
  1530. }
  1531. LispObject call2(const char *name, LispObject a1, LispObject a2)
  1532. {
  1533. LispObject fn = lookup(name, strlen(name), 0);
  1534. if (fn == undefined || qdefn(fn) == NULL) return NULLATOM;
  1535. push3(fn, a1, a2);
  1536. return applytostack(2);
  1537. }
  1538. LispObject interpret(LispObject def, int nargs, ...);
  1539. LispObject Lgensym(LispObject lits, int nargs, ...);
  1540. LispObject eval(LispObject x)
  1541. { while (isCONS(x) && isSYMBOL(qcar(x)) && (qflags(qcar(x)) & flagMACRO))
  1542. { push2(qcar(x), x);
  1543. x = applytostack(1); // Macroexpand before anything else.
  1544. if (unwindflag != unwindNONE) return nil;
  1545. }
  1546. if (isSYMBOL(x))
  1547. { LispObject v = qvalue(x);
  1548. if (v == undefined) return error1("undefined variable", x);
  1549. else return v;
  1550. }
  1551. else if (!isCONS(x)) return x;
  1552. // Now I have something of the form
  1553. // (f arg1 ... argn)
  1554. // to process.
  1555. { LispObject f = qcar(x);
  1556. if (isSYMBOL(f))
  1557. { LispObject flags = qflags(f), aa, av;
  1558. int i, n = 0;
  1559. if (flags & flagSPECFORM)
  1560. { SpecialForm *fn = (SpecialForm *)qdefn(f);
  1561. return (*fn)(qlits(f), qcdr(x));
  1562. }
  1563. // ... else not a special form...
  1564. if (qdefn(f) == NULL) return error1("undefined function", f);
  1565. aa = qcdr(x);
  1566. while (isCONS(aa))
  1567. { n++; // Count number of args supplied.
  1568. aa = qcdr(aa);
  1569. }
  1570. aa = qcdr(x);
  1571. push(f);
  1572. // Here I will evaluate all the arguments for the function, leaving the
  1573. // evaluated results on the stack.
  1574. for (i=0; i<n; i++)
  1575. { push(aa);
  1576. av = eval(qcar(aa));
  1577. if (unwindflag != unwindNONE)
  1578. { while (i != 0) // Restore the stack if unwinding.
  1579. { pop(aa);
  1580. i--;
  1581. }
  1582. pop2(aa, aa);
  1583. return nil;
  1584. }
  1585. aa = qcdr(TOS);
  1586. TOS = av;
  1587. }
  1588. return applytostack(n);
  1589. }
  1590. else if (isCONS(f) && qcar(f) == lambda)
  1591. { LispObject w;
  1592. push(x);
  1593. w = Lgensym(nil, 0);
  1594. pop(x);
  1595. qdefn(w) = (void *)interpret;
  1596. qlits(w) = qcdr(qcar(x));
  1597. return eval(cons(w, qcdr(x)));
  1598. }
  1599. else return error1("invalid function", f);
  1600. }
  1601. }
  1602. LispObject Lprogn(LispObject lits, LispObject x);
  1603. // The next array is used to help with error recovery, and it does
  1604. // not need to be protected by the garbage collector.
  1605. #define MAX_ARGS 50
  1606. LispObject pushedvars[MAX_ARGS];
  1607. LispObject nreverse(LispObject a)
  1608. { LispObject b = nil, w;
  1609. while (isCONS(a))
  1610. { w = qcdr(a);
  1611. qcdr(a) = b;
  1612. b = a;
  1613. a = w;
  1614. }
  1615. return b;
  1616. }
  1617. LispObject interpret(LispObject def, int nargs, ...)
  1618. {
  1619. // def should be ((a1 a2 ...) e1 e2 ...)
  1620. // where the number of args a1 ... should the same as nargs. Use
  1621. // "shallow binding" to cope with the need for a1 ... to have some
  1622. // sort of local scope.
  1623. va_list aa;
  1624. int i, npushed;
  1625. LispObject arglist, body, w, r = nil;
  1626. if (!isCONS(def)) return error1("bad definition", def);
  1627. va_start(aa, nargs);
  1628. w = arglist = qcar(def);
  1629. body = qcdr(def);
  1630. npushed = 0;
  1631. for (i=0; i<nargs && i<4; i++)
  1632. { LispObject var;
  1633. if (!isCONS(w) || !isSYMBOL(var = qcar(w)))
  1634. { while (npushed != 0) pop(qvalue(pushedvars[--npushed]));
  1635. va_end(aa);
  1636. return error1("excess arguments or invalid variable-name", w);
  1637. }
  1638. push(qvalue(var));
  1639. pushedvars[npushed++] = var;
  1640. qvalue(var) = va_arg(aa, LispObject);
  1641. w = qcdr(w);
  1642. }
  1643. // To make life easier in "eval" where I call functions I will pass up to
  1644. // 4 arguments "naturally", but any beyond that will all be collected as
  1645. // a list. So if nargs==5 then arg5 actually represents a list of the form
  1646. // (arg5 arg6 ...).
  1647. if (nargs == 5)
  1648. { r = va_arg(aa, LispObject);
  1649. while (isCONS(w) && isCONS(r))
  1650. { LispObject var = qcar(w);
  1651. if (!isSYMBOL(var))
  1652. { while (npushed != 0) pop(qvalue(pushedvars[--npushed]));
  1653. va_end(aa);
  1654. return error1("invalid variable-name", var);
  1655. }
  1656. push(qvalue(var));
  1657. pushedvars[npushed++] = var;
  1658. qvalue(var) = qcar(r);
  1659. w = qcdr(w);
  1660. r = qcdr(r);
  1661. }
  1662. }
  1663. va_end(aa);
  1664. if (isCONS(w) || isCONS(r))
  1665. { while (npushed != 0) pop(qvalue(pushedvars[--npushed]));
  1666. return error2("wrong number of args", r, w);
  1667. }
  1668. push(arglist);
  1669. r = Lprogn(nil, body);
  1670. pop(arglist);
  1671. // Now I must restore the bound variables (regardless of whether there
  1672. // has been an error).
  1673. w = nreverse(arglist);
  1674. arglist = nil;
  1675. while (isCONS(w))
  1676. { LispObject x = w;
  1677. w = qcdr(w);
  1678. qcdr(x) = arglist;
  1679. arglist = x;
  1680. pop(qvalue(qcar(arglist)));
  1681. }
  1682. return r;
  1683. }
  1684. LispObject interpretspecform(LispObject lits, LispObject x)
  1685. { // lits should be ((var) body...)
  1686. LispObject v, v_value;
  1687. if (!isCONS(lits)) return nil;
  1688. v = qcar(lits);
  1689. lits = qcdr(lits);
  1690. if (!isCONS(v) || !isSYMBOL(v = qcar(v))) return nil;
  1691. v_value = qvalue(v);
  1692. qvalue(v) = x;
  1693. push2(v, v_value);
  1694. lits = Lprogn(nil, lits);
  1695. pop2(v_value, v);
  1696. qvalue(v) = v_value;
  1697. return lits;
  1698. }
  1699. // Special forms are things that do not have their arguments pre-evaluated.
  1700. LispObject Lquote(LispObject lits, LispObject x)
  1701. { if (isCONS(x)) return qcar(x);
  1702. else return nil;
  1703. }
  1704. LispObject Lcond(LispObject lits, LispObject x)
  1705. {
  1706. // Arg is in form
  1707. // ((predicate1 val1a val1b ...)
  1708. // (predicate2 val2a val2b ...)
  1709. // ...)
  1710. while (isCONS(x))
  1711. { push(x);
  1712. x = qcar(x);
  1713. if (isCONS(x))
  1714. { LispObject p = eval(qcar(x));
  1715. if (unwindflag != unwindNONE)
  1716. { pop(x);
  1717. return nil;
  1718. }
  1719. else if (p != nil)
  1720. { pop(x);
  1721. return Lprogn(nil, qcdr(qcar(x)));
  1722. }
  1723. }
  1724. pop(x);
  1725. x = qcdr(x);
  1726. }
  1727. return nil;
  1728. }
  1729. LispObject Land(LispObject lits, LispObject x)
  1730. { LispObject r = lisptrue;
  1731. while (isCONS(x))
  1732. { push(x);
  1733. r = eval(qcar(x));
  1734. pop(x);
  1735. if (r == nil || unwindflag != unwindNONE) return nil;
  1736. x = qcdr(x);
  1737. }
  1738. return r;
  1739. }
  1740. LispObject Lor(LispObject lits, LispObject x)
  1741. { while (isCONS(x))
  1742. { LispObject r;
  1743. push(x);
  1744. r = eval(qcar(x));
  1745. pop(x);
  1746. if (r != nil || unwindflag != unwindNONE) return r;
  1747. x = qcdr(x);
  1748. }
  1749. return nil;
  1750. }
  1751. // A list of lambda-variables should be a properly nil-terminated list
  1752. // of symbols, not including keywords or anyting declared global.
  1753. int allsymbols(LispObject bvl)
  1754. {
  1755. while (isCONS(bvl))
  1756. { if (!isSYMBOL(qcar(bvl)) ||
  1757. (qflags(qcar(bvl)) & flagGLOBAL) != 0) return 0;
  1758. bvl = qcdr(bvl);
  1759. }
  1760. return (bvl == nil);
  1761. }
  1762. LispObject definer(LispObject x, int flags, void *fn)
  1763. {
  1764. // x should be of the form
  1765. // (name (arg list ...) body)
  1766. //
  1767. // I check for a LOSE flag to give me a way of
  1768. // ignoring definitions that I do not like.
  1769. LispObject name, def;
  1770. if (!isCONS(x) ||
  1771. !isSYMBOL(name = qcar(x)) ||
  1772. !isCONS(def = qcdr(x)))
  1773. return error1("malformed use of de, df or dm", x);
  1774. // For the moment I prohibit redefinition of special forms...
  1775. if ((qflags(name) & flagSPECFORM) != 0)
  1776. return error1("attempt to redefine special form", name);
  1777. if (Lget(nil, 2, name, loseflag) != nil)
  1778. { printf("\n+++ LOSE flag on function, so definition ignored: ");
  1779. errprint(name);
  1780. return name;
  1781. }
  1782. // Now I will <1>try to call macroexpand_list to expand all macros.
  1783. x = lookup("macroexpand_list", 16, 0);
  1784. if (x != undefined && qdefn(x) != NULL)
  1785. { push2(name, def);
  1786. push2(x, qcdr(def));
  1787. x = applytostack(1);
  1788. pop2(def, name);
  1789. if (unwindflag != unwindNONE) return name;
  1790. qlits(name) = cons(qcar(def), x);
  1791. }
  1792. else qlits(name) = def;
  1793. qflags(name) = (qflags(name) & ~(flagSPECFORM|flagMACRO)) | flags;
  1794. qdefn(name) = fn;
  1795. return name;
  1796. }
  1797. LispObject Lde(LispObject lits, LispObject x)
  1798. { return definer(x, 0, (void *)interpret);
  1799. }
  1800. LispObject Ldf(LispObject lits, LispObject x)
  1801. { return definer(x, flagSPECFORM, (void *)interpretspecform);
  1802. }
  1803. LispObject Ldm(LispObject lits, LispObject x)
  1804. { return definer(x, flagMACRO, (void *)interpret);
  1805. }
  1806. LispObject Lsetq(LispObject lits, LispObject x)
  1807. { // (setq var1 val1 var2 val2 ...)
  1808. LispObject w = nil;
  1809. while (isCONS(x) && isCONS(qcdr(x)))
  1810. { if (!isSYMBOL(w=qcar(x)) ||
  1811. w == nil || w == lisptrue)
  1812. return error1("bad variable in setq", x);
  1813. push(x);
  1814. w = eval(qcar(qcdr(x)));
  1815. pop(x);
  1816. if (unwindflag != unwindNONE) return nil;
  1817. qvalue(qcar(x)) = w;
  1818. x = qcdr(qcdr(x));
  1819. }
  1820. return w;
  1821. }
  1822. LispObject Lprogn(LispObject lits, LispObject x)
  1823. { LispObject r = nil;
  1824. while (isCONS(x))
  1825. { push(x);
  1826. r = eval(qcar(x));
  1827. pop(x);
  1828. x = qcdr(x);
  1829. if (unwindflag != unwindNONE) return nil;
  1830. }
  1831. return r;
  1832. }
  1833. // I want to police a constraint that GO and RETURN are only used in
  1834. // "prog context". The following limited number of forms are relevant to
  1835. // this:
  1836. // COND
  1837. // PROGN
  1838. // GO
  1839. // RETURN
  1840. // and (at least for now) I am not going to allow other conditionals, macros
  1841. // or anything else to be transparent to it.
  1842. static LispObject eval_prog_context(LispObject x);
  1843. LispObject progprogn(LispObject x)
  1844. { LispObject r = nil;
  1845. while (isCONS(x))
  1846. { push(x);
  1847. r = eval_prog_context(qcar(x));
  1848. pop(x);
  1849. x = qcdr(x);
  1850. if (unwindflag != unwindNONE) return nil;
  1851. }
  1852. return r;
  1853. }
  1854. LispObject progcond(LispObject x)
  1855. {
  1856. while (isCONS(x))
  1857. { push(x);
  1858. x = qcar(x);
  1859. if (isCONS(x))
  1860. { LispObject p = eval(qcar(x));
  1861. if (unwindflag != unwindNONE)
  1862. { pop(x);
  1863. return nil;
  1864. }
  1865. else if (p != nil)
  1866. { pop(x);
  1867. return progprogn(qcdr(qcar(x)));
  1868. }
  1869. }
  1870. pop(x);
  1871. x = qcdr(x);
  1872. }
  1873. return nil;
  1874. }
  1875. LispObject proggo(LispObject x)
  1876. { if (!isCONS(x) || !isSYMBOL(work1 = qcar(x)))
  1877. return error1("bad go", x);
  1878. work1 = qcar(x);
  1879. unwindflag = unwindGO;
  1880. return nil;
  1881. }
  1882. LispObject progreturn(LispObject args)
  1883. { if (!isCONS(args) || isCONS(qcdr(args)))
  1884. return error1("RETURN need just 1 argument", args);
  1885. args = eval(qcar(args));
  1886. if (unwindflag != unwindNONE) return nil;
  1887. work1 = args;
  1888. unwindflag = unwindRETURN;
  1889. return nil;
  1890. }
  1891. static LispObject eval_prog_context(LispObject x)
  1892. { if (!isCONS(x)) return eval(x);
  1893. else if (qcar(x) == condsymbol) return progcond(qcdr(x));
  1894. else if (qcar(x) == prognsymbol) return progprogn(qcdr(x));
  1895. else if (qcar(x) == gosymbol) return proggo(qcdr(x));
  1896. else if (qcar(x) == returnsymbol) return progreturn(qcdr(x));
  1897. else return eval(x);
  1898. }
  1899. LispObject Lprog(LispObject lits, LispObject x)
  1900. {
  1901. LispObject w, vars;
  1902. if (!isCONS(x)) return nil;
  1903. vars = qcar(x);
  1904. x = qcdr(x);
  1905. w = vars;
  1906. // Now bind all the local variables, giving them the value nil.
  1907. while (isCONS(w))
  1908. { LispObject v = qcar(w);
  1909. w = qcdr(w);
  1910. if (isSYMBOL(v))
  1911. { push(qvalue(v));
  1912. qvalue(v) = nil;
  1913. }
  1914. }
  1915. push(vars); // So that I know what to unbind at the end.
  1916. push(x); // So that "go" can scan the whole block to find a label.
  1917. work1 = nil;
  1918. while (isCONS(x))
  1919. { push(x);
  1920. if (isCONS(qcar(x))) eval_prog_context(qcar(x));
  1921. pop(x);
  1922. x = qcdr(x);
  1923. if (unwindflag == unwindRETURN)
  1924. { unwindflag = unwindNONE;
  1925. break;
  1926. }
  1927. else if (unwindflag == unwindGO)
  1928. { unwindflag = unwindNONE;
  1929. x = TOS;
  1930. while (isCONS(x) && qcar(x) != work1) x = qcdr(x);
  1931. continue;
  1932. }
  1933. if (unwindflag != unwindNONE) break;
  1934. work1 = nil;
  1935. }
  1936. // Now I must unbind all the variables.
  1937. pop(x);
  1938. pop(vars);
  1939. w = nreverse(vars);
  1940. vars = nil;
  1941. while (isCONS(w))
  1942. { LispObject x = w;
  1943. w = qcdr(w);
  1944. qcdr(x) = vars;
  1945. vars = x;
  1946. x = qcar(vars);
  1947. if (isSYMBOL(x)) pop(qvalue(x));
  1948. }
  1949. return work1;
  1950. }
  1951. LispObject Lgo(LispObject lits, LispObject x)
  1952. { return error1("GO not in PROG context", x);
  1953. // if (!isCONS(x) || !isSYMBOL(work1 = qcar(x)))
  1954. // return error1("bad go", x);
  1955. // work1 = qcar(x);
  1956. // unwindflag = unwindGO;
  1957. // return nil;
  1958. }
  1959. #define NARY(x, base, combinefn) \
  1960. LispObject r; \
  1961. if (!isCONS(x)) return base; \
  1962. push(x); \
  1963. r = eval(qcar(x)); \
  1964. pop(x); \
  1965. if (unwindflag != unwindNONE) \
  1966. return nil; \
  1967. x = qcdr(x); \
  1968. while (isCONS(x)) \
  1969. { LispObject a; \
  1970. push2(x, r); \
  1971. a = eval(qcar(x)); \
  1972. pop(r); \
  1973. if (unwindflag != unwindNONE) \
  1974. { pop(x); \
  1975. return nil; \
  1976. } \
  1977. r = combinefn(r, a); \
  1978. pop(x); \
  1979. x = qcdr(x); \
  1980. } \
  1981. return r
  1982. LispObject Lplus(LispObject lits, LispObject x)
  1983. { NARY(x, packfixnum(0), Nplus2);
  1984. }
  1985. LispObject Ltimes(LispObject lits, LispObject x)
  1986. { NARY(x, packfixnum(1), Ntimes2);
  1987. }
  1988. LispObject Llogand(LispObject lits, LispObject x)
  1989. { NARY(x, packfixnum(-1), Nlogand2);
  1990. }
  1991. LispObject Llogor(LispObject lits, LispObject x)
  1992. { NARY(x, packfixnum(0), Nlogor2);
  1993. }
  1994. LispObject Llogxor(LispObject lits, LispObject x)
  1995. { NARY(x, packfixnum(0), Nlogxor2);
  1996. }
  1997. LispObject Llist(LispObject lits, LispObject x)
  1998. { int n = 0;
  1999. LispObject r;
  2000. while (isCONS(x))
  2001. { push(x);
  2002. r = eval(qcar(x));
  2003. if (unwindflag != unwindNONE)
  2004. { while (n != 0)
  2005. { pop(x);
  2006. n--;
  2007. }
  2008. pop(x);
  2009. return nil;
  2010. }
  2011. x = qcdr(TOS);
  2012. TOS = r;
  2013. n++;
  2014. }
  2015. r = nil;
  2016. while (n > 0)
  2017. { pop(x);
  2018. r = cons(x, r);
  2019. n--;
  2020. }
  2021. return r;
  2022. }
  2023. LispObject Lliststar(LispObject lits, LispObject x)
  2024. { int n = 0;
  2025. LispObject r;
  2026. while (isCONS(x))
  2027. { push(x);
  2028. r = eval(qcar(x));
  2029. if (unwindflag != unwindNONE)
  2030. { while (n != 0)
  2031. { pop(x);
  2032. n--;
  2033. }
  2034. pop(x);
  2035. return nil;
  2036. }
  2037. x = qcdr(TOS);
  2038. TOS = r;
  2039. n++;
  2040. }
  2041. if (n == 0) return nil;
  2042. pop(r);
  2043. n--;
  2044. while (n > 0)
  2045. { pop(x);
  2046. r = cons(x, r);
  2047. n--;
  2048. }
  2049. return r;
  2050. }
  2051. // The way that arguments are passed to functions is a little
  2052. // ugly, and uses the C facility for calling functions with variable
  2053. // numbers of arguments. To shorten the code I put much of the mess into
  2054. // macros
  2055. #define ARG0(name) \
  2056. if (nargs != 0) return error1s("wrong number of arguments for", name)
  2057. #define ARG1(name, x) \
  2058. va_list a; \
  2059. LispObject x; \
  2060. if (nargs != 1) return error1s("wrong number of arguments for", name); \
  2061. va_start(a, nargs); \
  2062. x = va_arg(a, LispObject); \
  2063. va_end(a)
  2064. #define ARG2(name, x, y) \
  2065. va_list a; \
  2066. LispObject x, y; \
  2067. if (nargs != 2) return error1s("wrong number of arguments for", name); \
  2068. va_start(a, nargs); \
  2069. x = va_arg(a, LispObject); \
  2070. y = va_arg(a, LispObject); \
  2071. va_end(a)
  2072. #define ARG3(name, x, y, z) \
  2073. va_list a; \
  2074. LispObject x, y, z; \
  2075. if (nargs != 3) return error1s("wrong number of arguments for", name); \
  2076. va_start(a, nargs); \
  2077. x = va_arg(a, LispObject); \
  2078. y = va_arg(a, LispObject); \
  2079. z = va_arg(a, LispObject); \
  2080. va_end(a)
  2081. #define ARG0123(name, x, y, z) \
  2082. va_list a; \
  2083. LispObject x=NULLATOM, y=NULLATOM, z=NULLATOM; \
  2084. if (nargs > 3) return error1s("wrong number of arguments for", name); \
  2085. va_start(a, nargs); \
  2086. if (nargs > 0) x = va_arg(a, LispObject); \
  2087. if (nargs > 1) y = va_arg(a, LispObject); \
  2088. if (nargs > 2) z = va_arg(a, LispObject); \
  2089. va_end(a)
  2090. LispObject Lcar(LispObject lits, int nargs, ...)
  2091. { ARG1("car", x); // Note that this WILL take car of a bignum!
  2092. if (isCONS(x)) return qcar(x);
  2093. else return error1("car of an atom", x);
  2094. }
  2095. LispObject Lcdr(LispObject lits, int nargs, ...)
  2096. { ARG1("cdr", x);
  2097. if (isCONS(x)) return qcdr(x);
  2098. else return error1("cdr of an atom", x);
  2099. }
  2100. LispObject Lrplaca(LispObject lits, int nargs, ...)
  2101. { ARG2("rplaca", x, y);
  2102. if (isCONS(x))
  2103. { qcar(x) = y;
  2104. return x;
  2105. }
  2106. else return error1("rplaca on an atom", x);
  2107. }
  2108. LispObject Lrplacd(LispObject lits, int nargs, ...)
  2109. { ARG2("rplacd", x, y);
  2110. if (isCONS(x))
  2111. { qcdr(x) = y;
  2112. return x;
  2113. }
  2114. else return error1("rplaca on an atom", x);
  2115. }
  2116. LispObject Lreclaim(LispObject lits, int nargs, ...)
  2117. { ARG0("reclaim");
  2118. reclaim();
  2119. return nil;
  2120. }
  2121. LispObject Lcons(LispObject lits, int nargs, ...)
  2122. { ARG2("cons", x, y);
  2123. return cons(x, y);
  2124. }
  2125. LispObject Latom(LispObject lits, int nargs, ...)
  2126. { ARG1("atom", x); // Observe treatment of bignums!
  2127. return (isCONS(x) && qcar(x) != bignum ? nil : lisptrue);
  2128. }
  2129. LispObject Lbignump(LispObject lits, int nargs, ...)
  2130. { ARG1("bignump", x);
  2131. return (isCONS(x) && qcar(x) == bignum ? lisptrue : nil);
  2132. }
  2133. LispObject Lsymbolp(LispObject lits, int nargs, ...)
  2134. { ARG1("symbolp", x);
  2135. return (isSYMBOL(x) ? lisptrue : nil);
  2136. }
  2137. LispObject Lstringp(LispObject lits, int nargs, ...)
  2138. { ARG1("stringp", x);
  2139. return (isSTRING(x) ? lisptrue : nil);
  2140. }
  2141. LispObject Lvectorp(LispObject lits, int nargs, ...)
  2142. { ARG1("vectorp", x);
  2143. return (isVEC(x) ? lisptrue : nil);
  2144. }
  2145. LispObject Lprog1(LispObject lits, int nargs, ...)
  2146. { ARG2("prog1", x, y);
  2147. y = y;
  2148. return x;
  2149. }
  2150. LispObject Lprog2(LispObject lits, int nargs, ...)
  2151. { ARG2("prog2", x, y);
  2152. x = x;
  2153. return y;
  2154. }
  2155. LispObject Lnumberp(LispObject lits, int nargs, ...)
  2156. { ARG1("numberp", x);
  2157. return (isFIXNUM(x) || isBIGNUM(x) || isFLOAT(x) ? lisptrue : nil);
  2158. }
  2159. LispObject Lfixp(LispObject lits, int nargs, ...)
  2160. { ARG1("fixp", x);
  2161. return (isFIXNUM(x) || isBIGNUM(x) ? lisptrue : nil);
  2162. }
  2163. LispObject Lfloatp(LispObject lits, int nargs, ...)
  2164. { ARG1("floatp", x);
  2165. return (isFLOAT(x) ? lisptrue : nil);
  2166. }
  2167. LispObject Lfix(LispObject lits, int nargs, ...)
  2168. { ARG1("fix", x);
  2169. return (isFIXNUM(x) || isBIGNUM(x) ? x :
  2170. isFLOAT(x) ? boxint64((int64_t)qfloat(x)) :
  2171. error1("arg for fix", x));
  2172. }
  2173. LispObject Lfloor(LispObject lits, int nargs, ...)
  2174. { ARG1("floor", x);
  2175. return (isFIXNUM(x) || isBIGNUM(x) ? x :
  2176. isFLOAT(x) ? boxint64((int64_t)floor(qfloat(x))) :
  2177. error1("arg for floor", x));
  2178. }
  2179. LispObject Lceiling(LispObject lits, int nargs, ...)
  2180. { ARG1("ceiling", x);
  2181. return (isFIXNUM(x) || isBIGNUM(x) ? x :
  2182. isFLOAT(x) ? boxint64((int64_t)ceil(qfloat(x))) :
  2183. error1("arg for ceiling", x));
  2184. }
  2185. LispObject Lfloat(LispObject lits, int nargs, ...)
  2186. { ARG1("float", x);
  2187. return (isFLOAT(x) ? x :
  2188. isFIXNUM(x) ? boxfloat((double)qfixnum(x)) :
  2189. isBIGNUM(x) ? boxfloat((double)qint64(x)) :
  2190. error1("arg for float", x));
  2191. }
  2192. #define floatval(x) \
  2193. isFLOAT(x) ? qfloat(x) : \
  2194. isFIXNUM(x) ? (double)qfixnum(x) : \
  2195. isBIGNUM(x) ? (double)qint64(x) : \
  2196. 0.0
  2197. LispObject Lcos(LispObject lits, int nargs, ...)
  2198. { ARG1("cos", x);
  2199. return boxfloat(cos(floatval(x)));
  2200. }
  2201. LispObject Lsin(LispObject lits, int nargs, ...)
  2202. { ARG1("sin", x);
  2203. return boxfloat(sin(floatval(x)));
  2204. }
  2205. LispObject Lsqrt(LispObject lits, int nargs, ...)
  2206. { ARG1("sqrt", x);
  2207. return boxfloat(sqrt(floatval(x)));
  2208. }
  2209. LispObject Llog(LispObject lits, int nargs, ...)
  2210. { ARG1("log", x);
  2211. return boxfloat(log(floatval(x)));
  2212. }
  2213. LispObject Lexp(LispObject lits, int nargs, ...)
  2214. { ARG1("exp", x);
  2215. return boxfloat(exp(floatval(x)));
  2216. }
  2217. LispObject Latan(LispObject lits, int nargs, ...)
  2218. { ARG1("atan", x);
  2219. return boxfloat(atan(floatval(x)));
  2220. }
  2221. LispObject Lnull(LispObject lits, int nargs, ...)
  2222. { ARG1("null", x);
  2223. return (x == nil ? lisptrue : nil);
  2224. }
  2225. LispObject Leq(LispObject lits, int nargs, ...)
  2226. { ARG2("eq", x, y);
  2227. return (x == y ? lisptrue : nil);
  2228. }
  2229. LispObject Lequal(LispObject lits, int nargs, ...)
  2230. { ARG2("equal", x, y);
  2231. while (x != y && isCONS(x) && isCONS(y))
  2232. { if (Lequal(lits, 2, qcar(x), qcar(y)) == nil) return nil;
  2233. x = qcdr(x); y = qcdr(y);
  2234. }
  2235. if (x == y) return lisptrue;
  2236. if ((x & TAGBITS) != (y & TAGBITS)) return nil;
  2237. if (isSYMBOL(x) || isFIXNUM(x)) return nil;
  2238. if (isFLOAT(x)) return (qfloat(x) == qfloat(y) ? lisptrue : nil);
  2239. if (qheader(x) != qheader(y)) return nil;
  2240. switch (qheader(x) & TYPEBITS)
  2241. { case typeVEC: case typeEQHASH: case typeEQHASHX:
  2242. case typeEQUALHASH: case typeEQUALHASHX:
  2243. { int i;
  2244. for (i=0; i<veclength(qheader(x))/sizeof(LispObject); i++)
  2245. if (Lequal(lits, 2, elt(x, i), elt(y, i)) == nil) return nil;
  2246. return lisptrue;
  2247. }
  2248. default: // Treat all other cases as containing binary information.
  2249. { int i;
  2250. const char *xx = qstring(x), *yy = qstring(y);
  2251. for (i=0; i<veclength(qheader(x)); i++)
  2252. if (xx[i] != yy[i]) return nil;
  2253. return lisptrue;
  2254. }
  2255. }
  2256. }
  2257. LispObject Lset(LispObject lits, int nargs, ...)
  2258. { ARG2("set", x, y);
  2259. if (!isSYMBOL(x)) return error1("bad arg for set", x);
  2260. return (qvalue(x) = y);
  2261. }
  2262. LispObject Lboundp(LispObject lits, int nargs, ...)
  2263. { ARG1("boundp", x);
  2264. return (isSYMBOL(x) && qvalue(x)!=undefined) ? lisptrue : nil;
  2265. }
  2266. LispObject Lmakeunbound(LispObject lits, int nargs, ...)
  2267. { ARG1("makeunbound", x);
  2268. if (isSYMBOL(x)) qvalue(x) = undefined;
  2269. return nil;
  2270. }
  2271. LispObject Lgensym(LispObject lits, int nargs, ...)
  2272. { LispObject r;
  2273. ARG0("gensym");
  2274. r = allocatesymbol();
  2275. qflags(r) = tagHDR + typeGENSYM;
  2276. qvalue(r) = undefined;
  2277. qplist(r) = nil;
  2278. qpname(r) = nil; // A nil pname marks this as a not-yet-printed gensym.
  2279. qdefn(r) = NULL;
  2280. qlits(r) = nil;
  2281. return r;
  2282. }
  2283. LispObject Lgensymp(LispObject lits, int nargs, ...)
  2284. { ARG1("gensymp", x);
  2285. if (!isSYMBOL(x)) return nil;
  2286. return (qflags(x) & TYPEBITS) == typeGENSYM ? lisptrue : nil;
  2287. }
  2288. LispObject Lchar(LispObject lits, int nargs, ...)
  2289. { ARG1("char", x);
  2290. return char_function(x);
  2291. }
  2292. LispObject Lcharcode(LispObject lits, int nargs, ...)
  2293. { ARG1("char-code", x);
  2294. if (isFIXNUM(x)) return x;
  2295. if (isSYMBOL(x)) x = qpname(x);
  2296. if (!isSTRING(x)) return error1("bad arg for char-code", x);
  2297. return packfixnum(*qstring(x));
  2298. }
  2299. LispObject Lcodechar(LispObject lits, int nargs, ...)
  2300. { char ch[4];
  2301. ARG1("code-char", x);
  2302. if (!isFIXNUM(x)) return error1("bad arg for code-char", x);
  2303. ch[0] = (char)qfixnum(x); ch[1] = 0;
  2304. return lookup(ch, 1, 1);
  2305. }
  2306. LispObject Ltime(LispObject lits, int nargs, ...)
  2307. { clock_t c = clock();
  2308. ARG0("time"); // I will convert the time to be in milliseconds
  2309. return packfixnum((intptr_t)((1000*(int64_t )c)/CLOCKS_PER_SEC));
  2310. }
  2311. // (date) "14-May-2013"
  2312. // (date!-and!-time) "Tue May 14 09:52:45 2013"
  2313. //
  2314. LispObject Ldate(LispObject lits, int nargs, ...)
  2315. { time_t t = time(NULL);
  2316. char today[32];
  2317. char today1[32];
  2318. strcpy(today, ctime(&t));
  2319. // e.g. "Sun Sep 16 01:03:52 1973\n"
  2320. // 012345678901234567890123
  2321. today[24] = 0; // loses final '\n'
  2322. today1[0] = today[8]==' ' ? '0' : today[8];
  2323. today1[1] = today[9];
  2324. today1[2] = '-';
  2325. today1[3] = today[4];
  2326. today1[4] = today[5];
  2327. today1[5] = today[6];
  2328. today1[6] = '-';
  2329. today1[7] = today[20];
  2330. today1[8] = today[21];
  2331. today1[9] = today[22];
  2332. today1[10] = today[23];
  2333. today1[11] = 0; // Now as in 03-Apr-2009
  2334. return makestring(today1, 11);
  2335. }
  2336. LispObject Ldate_and_time(LispObject lits, int nargs, ...)
  2337. { time_t t = time(NULL);
  2338. char today[32];
  2339. strcpy(today, ctime(&t));
  2340. // e.g. "Sun Sep 16 01:03:52 1973\n"
  2341. today[24] = 0; // loses final '\n'
  2342. return makestring(today, 24);
  2343. }
  2344. LispObject Loblist(LispObject lits, int nargs, ...)
  2345. {
  2346. int i;
  2347. ARG0("oblist");
  2348. work1 = nil;
  2349. for (i=0; i<OBHASH_SIZE; i++)
  2350. for (work2=obhash[i]; isCONS(work2); work2 = qcdr(work2))
  2351. { if (qcar(work2) != undefined)
  2352. work1 = cons(qcar(work2), work1);
  2353. }
  2354. return work1;
  2355. }
  2356. LispObject Leval(LispObject lits, int nargs, ...)
  2357. { ARG1("eval", x);
  2358. return eval(x);
  2359. }
  2360. LispObject Lapply(LispObject lits, int nargs, ...)
  2361. { int n = 0;
  2362. ARG2("apply", x, y);
  2363. if (isCONS(x) && qcar(x) == lambda)
  2364. { LispObject g;
  2365. push2(x, y);
  2366. g = Lgensym(nil, 0);
  2367. pop2(y, x);
  2368. if (unwindflag != unwindNONE) return nil;
  2369. qdefn(g) = (void *)interpret;
  2370. qlits(g) = qcdr(x);
  2371. x = g;
  2372. }
  2373. else if (!isSYMBOL(x)) return error1("bad arg to apply", x);
  2374. push(x);
  2375. while (isCONS(y))
  2376. { push(qcar(y));
  2377. y = qcdr(y);
  2378. n++;
  2379. }
  2380. return applytostack(n);
  2381. }
  2382. LispObject Lplist(LispObject lits, int nargs, ...)
  2383. { ARG1("plist", x);
  2384. if (!isSYMBOL(x)) return nil;
  2385. else return qplist(x);
  2386. }
  2387. LispObject Lpname(LispObject lits, int nargs, ...)
  2388. { ARG1("pname", x);
  2389. if (!isSYMBOL(x)) return nil;
  2390. else return qpname(x);
  2391. }
  2392. LispObject Lput(LispObject lits, int nargs, ...)
  2393. { LispObject w;
  2394. ARG3("put", x, y, z);
  2395. if (!isSYMBOL(x)) return error1("bad arg put", x);
  2396. w = qplist(x);
  2397. while (isCONS(w))
  2398. { LispObject a = qcar(w);
  2399. w = qcdr(w);
  2400. if (isCONS(a) && qcar(a) == y)
  2401. { qcdr(a) = z;
  2402. return z;
  2403. }
  2404. }
  2405. push2(x, z);
  2406. w = acons(y, z, qplist(x));
  2407. pop2(z, x);
  2408. qplist(x) = w;
  2409. return z;
  2410. }
  2411. LispObject Lget(LispObject lits, int nargs, ...)
  2412. { ARG2("get", x, y);
  2413. if (!isSYMBOL(x)) return nil;
  2414. x = qplist(x);
  2415. while (isCONS(x))
  2416. { LispObject a = qcar(x);
  2417. x = qcdr(x);
  2418. if (isCONS(a) && qcar(a) == y) return qcdr(a);
  2419. }
  2420. return nil;
  2421. }
  2422. LispObject Lremprop(LispObject lits, int nargs, ...)
  2423. { LispObject p, r, *prev;
  2424. ARG2("remprop", x, y);
  2425. if (!isSYMBOL(x)) return nil;
  2426. p = *(prev = &qplist(x));
  2427. while (p != nil)
  2428. { if (isCONS(r = qcar(p)) && qcar(qcar(p)) == y)
  2429. { *prev = qcdr(p);
  2430. return r;
  2431. }
  2432. p = *(prev = &qcdr(p));
  2433. }
  2434. return nil;
  2435. }
  2436. LispObject Lmkvect(LispObject lits, int nargs, ...)
  2437. { int n;
  2438. ARG1("mkvect", x);
  2439. if (!isFIXNUM(x)) return error1("bad size in mkvect", x);
  2440. n = (int)qfixnum(x);
  2441. // I put an (arbitrary) limit on the size of the largest vector.
  2442. if (n < 0 || n > 100000) return error1("bad size in mkvect", x);
  2443. return makevector(n);
  2444. }
  2445. LispObject Lupbv(LispObject lits, int nargs, ...)
  2446. { ARG1("upbv", x);
  2447. if (!isVEC(x)) return error1("bad arg to upbv", x);
  2448. return makeinteger(veclength(qheader(x))/sizeof(LispObject)-1);
  2449. }
  2450. LispObject Lputv(LispObject lits, int nargs, ...)
  2451. { int n;
  2452. ARG3("putv", x, y, z);
  2453. if (!isVEC(x) || !isFIXNUM(y))
  2454. return error2("bad arg to putv", x, y);
  2455. n = (int)qfixnum(y);
  2456. if (n < 0 || n >= veclength(qheader(x))/sizeof(LispObject))
  2457. return error1("subscript out of range in putv", y);
  2458. elt(x, n) = z;
  2459. return z;
  2460. }
  2461. LispObject Lgetv(LispObject lits, int nargs, ...)
  2462. { int n;
  2463. ARG2("getv", x, y);
  2464. // As a matter of convenience and generosity I will allow "getv" to
  2465. // access items from hash tables as well as ordinary vectors.
  2466. if ((!isVEC(x) && !isEQHASH(x) && !isEQHASHX(x) &&
  2467. !isEQUALHASH(x) && !isEQUALHASHX(x)) || !isFIXNUM(y))
  2468. return error2("bad arg to getv", x, y);
  2469. n = (int)qfixnum(y);
  2470. if (n < 0 || n >= veclength(qheader(x))/sizeof(LispObject))
  2471. return error1("subscript out of range in getv", y);
  2472. return elt(x, n);
  2473. }
  2474. LispObject Lmkhash(LispObject lits, int nargs, ...)
  2475. { LispObject size = packfixnum(10), r, flavour = packfixnum(0);
  2476. va_list a; // I am going to permit mkhash to have extra arguments.
  2477. va_start(a, nargs); // This is for easier compatibility with Reduce.
  2478. if (nargs >= 1) size = va_arg(a, LispObject);
  2479. if (nargs >= 2) flavour = va_arg(a, LispObject);
  2480. va_end(a);
  2481. if (!isFIXNUM(size)) return error1("bad size in mkhash", size);
  2482. if (!isFIXNUM(flavour)) return error1("bad flavour in mkhash", flavour);
  2483. int n = (int)qfixnum(size);
  2484. int f = (int)qfixnum(flavour);
  2485. // I force hash tables to be of limited size.
  2486. if (n <= 10) n = 11;
  2487. else if (n > 1000) n = 997;
  2488. n |= 1; // Force table-size to be an odd number
  2489. r = makevector(n-1);
  2490. f = (f == 0 ? typeEQHASH : typeEQUALHASH);
  2491. qheader(r) ^= (typeVEC ^ f);
  2492. return r;
  2493. }
  2494. LispObject Lclrhash(LispObject lits, int nargs, ...)
  2495. { ARG1("clrhash", x);
  2496. if (isEQHASHX(x)) qheader(x) ^= (typeEQHASH ^ typeEQHASHX);
  2497. if (isEQUALHASHX(x)) qheader(x) ^= (typeEQUALHASH ^ typeEQUALHASHX);
  2498. if (!isEQHASH(x) && !isEQUALHASH(x))
  2499. return error1("not a hash table in clrhash", x);
  2500. size_t n = veclength(qheader(x))/sizeof(LispObject);
  2501. for (size_t i=0; i<n; i++) elt(x, i) = nil;
  2502. return x;
  2503. }
  2504. uintptr_t hashup(LispObject a, int isEQUAL)
  2505. { if (!isEQUAL) return (uintptr_t)a;
  2506. switch (a & TAGBITS)
  2507. { case tagCONS: // Traditional Lisp "cons" item.
  2508. return 19937*hashup(qcar(a), 1) + hashup(qcdr(a), 1);
  2509. case tagFLOAT: // A double-precision number.
  2510. { union { double d; uintptr_t i;} dd;
  2511. dd.d = qfloat(a);
  2512. return dd.i;
  2513. }
  2514. case tagATOM: // Something else that will have a header word.
  2515. if (isSTRING(a))
  2516. { int len = veclength(qheader(a));
  2517. char *s = qstring(a);
  2518. uintptr_t h = 0;
  2519. for (int i=0; i<len; i++) h = 11213*h + s[i];
  2520. return h;
  2521. }
  2522. return 1; // give up for other atoms!
  2523. default:
  2524. case tagSYMBOL: // a symbol.
  2525. case tagFIXNUM: // An immediate integer value (29 or 61 bits).
  2526. return (uintptr_t)a;
  2527. }
  2528. }
  2529. void rehash(LispObject x)
  2530. { int isEQUAL = isEQUALHASHX(x);
  2531. int n = veclength(qheader(x));
  2532. int i;
  2533. // At the moment that this is invoked it is at least certain that
  2534. // garbage collection is not in progress. Hence the second half-space
  2535. // is all memory available for use! So on a temporary basis I will put
  2536. // a copy of the hash table there.
  2537. LispObject x1 = heap2base + tagATOM;
  2538. memcpy((void *)(x1 - tagATOM), (void *)(x - tagATOM),
  2539. n + sizeof(LispObject));
  2540. n = n/sizeof(LispObject); // Now a count of slots in the table.
  2541. // I will now re-hash from the copy that I made back into the hash table, but
  2542. // now using the new hash values that reflect and changes that have
  2543. // arisen.
  2544. for (i=0; i<n; i++) elt(x, i) = nil;
  2545. for (i=0; i<n; i++)
  2546. { LispObject b = elt(x1, i);
  2547. while (b != nil)
  2548. { LispObject ca = qcar(b), cd = qcdr(b);
  2549. int h = (int)(hashup(qcar(ca), isEQUAL)%((uintptr_t)n)); // New bucket.
  2550. qcdr(b) = elt(x, h);
  2551. elt(x, h) = b; // Re-inserted in table.
  2552. b = cd;
  2553. }
  2554. }
  2555. qheader(x) ^= (typeEQHASH ^ typeEQHASHX);
  2556. }
  2557. int hashsame(LispObject x, LispObject y, int isEQUAL)
  2558. {
  2559. if (isEQUAL) return Lequal(nil, 2, x, y) != nil;
  2560. else return x == y;
  2561. }
  2562. LispObject Lputhash(LispObject lits, int nargs, ...)
  2563. { int n, h;
  2564. LispObject c;
  2565. ARG3("puthash", x, y, z);
  2566. if (isEQHASHX(y) || isEQUALHASHX(y)) rehash(y);
  2567. if (!isEQHASH(y) && !isEQUALHASH(y))
  2568. return error2("not a hash table in puthash", x, y);
  2569. n = veclength(qheader(y))/sizeof(LispObject);
  2570. // I use unsigned types so I get a positive remainder.
  2571. h = (int)(hashup(x, isEQUALHASH(y)) % ((uintptr_t)n));
  2572. c = elt(y, h);
  2573. while (isCONS(c))
  2574. { if (hashsame(qcar(qcar(c)), x, isEQUALHASH(y)))
  2575. { qcdr(qcar(c)) = z;
  2576. return z;
  2577. }
  2578. c = qcdr(c);
  2579. }
  2580. push2(y, z);
  2581. c = acons(x, z, elt(y, h));
  2582. pop2(z, y);
  2583. elt(y, h) = c;
  2584. return z;
  2585. }
  2586. LispObject Lremhash(LispObject lits, int nargs, ...)
  2587. { int n, h;
  2588. LispObject c, *cp;
  2589. ARG2("remhash", x, y);
  2590. if (isEQHASHX(y) || isEQUALHASHX(y)) rehash(y);
  2591. if (!isEQHASH(y) && !isEQUALHASH(y))
  2592. return error2("not a hash table in remhash", x, y);
  2593. n = veclength(qheader(y))/sizeof(LispObject);
  2594. h = (int)(hashup(x, isEQUALHASH(y)) % ((uintptr_t)n));
  2595. c = *(cp = &elt(y, h));
  2596. while (isCONS(c))
  2597. { if (hashsame(qcar(qcar(c)), x, isEQUALHASH(y)))
  2598. { *cp = qcdr(c);
  2599. return qcdr(qcar(c));
  2600. }
  2601. c = *(cp = &qcdr(c));
  2602. }
  2603. return nil;
  2604. }
  2605. LispObject Lgethash(LispObject lits, int nargs, ...)
  2606. { int n, h;
  2607. LispObject c;
  2608. ARG2("gethash", x, y);
  2609. if (isEQHASHX(y) || isEQUALHASHX(y)) rehash(y);
  2610. if (!isEQHASH(y) && !isEQUALHASH(y))
  2611. return error2("not a hash table in gethash", x, y);
  2612. n = veclength(qheader(y))/sizeof(LispObject);
  2613. h = (int)(hashup(x, isEQUALHASH(y)) % ((uintptr_t)n));
  2614. c = elt(y, h);
  2615. while (isCONS(c))
  2616. { if (hashsame(qcar(qcar(c)), x, isEQUALHASH(y))) return qcdr(qcar(c));
  2617. c = qcdr(c);
  2618. }
  2619. return nil;
  2620. }
  2621. LispObject Lgetd(LispObject lits, int nargs, ...)
  2622. { ARG1("getd", x);
  2623. if (!isSYMBOL(x)) return nil;
  2624. if ((qflags(x) & flagSPECFORM) != 0)
  2625. { if (qdefn(x) == (void *)interpretspecform)
  2626. return list2star(fexpr, lambda, qlits(x));
  2627. else return cons(fsubr, x);
  2628. }
  2629. else if (qdefn(x) == NULL) return nil;
  2630. else if (qdefn(x) == (void *)interpret)
  2631. return list2star((qflags(x) & flagMACRO) ? macro : expr,
  2632. lambda, qlits(x));
  2633. else return cons(subr, x);
  2634. }
  2635. LispObject Lreturn(LispObject lits, int nargs, ...)
  2636. { ARG1("return", x);
  2637. return error1("RETURN not in PROG context", x);
  2638. }
  2639. // Now some numeric functions
  2640. #undef FF
  2641. #undef BB
  2642. #define FF(a, b) ((a) > (b) ? lisptrue : nil)
  2643. #define BB(a, b) ((a) > (b) ? lisptrue : nil)
  2644. LispObject Lgreaterp(LispObject lits, int nargs, ...)
  2645. { ARG2("greaterp", x, y);
  2646. NUMOP("greaterp", x, y);
  2647. }
  2648. #undef FF
  2649. #undef BB
  2650. #define FF(a, b) ((a) >= (b) ? lisptrue : nil)
  2651. #define BB(a, b) ((a) >= (b) ? lisptrue : nil)
  2652. LispObject Lgeq(LispObject lits, int nargs, ...)
  2653. { ARG2("geq", x, y);
  2654. NUMOP("geq", x, y);
  2655. }
  2656. #undef FF
  2657. #undef BB
  2658. #define FF(a, b) ((a) < (b) ? lisptrue : nil)
  2659. #define BB(a, b) ((a) < (b) ? lisptrue : nil)
  2660. LispObject Llessp(LispObject lits, int nargs, ...)
  2661. { ARG2("lessp", x, y);
  2662. NUMOP("lessp", x, y);
  2663. }
  2664. #undef FF
  2665. #undef BB
  2666. #define FF(a, b) ((a) <= (b) ? lisptrue : nil)
  2667. #define BB(a, b) ((a) <= (b) ? lisptrue : nil)
  2668. LispObject Lleq(LispObject lits, int nargs, ...)
  2669. { ARG2("leq", x, y);
  2670. NUMOP("leq", x, y);
  2671. }
  2672. LispObject Lminus(LispObject lits, int nargs, ...)
  2673. { ARG1("minus", x);
  2674. return Nminus(x);
  2675. }
  2676. LispObject Lminusp(LispObject lits, int nargs, ...)
  2677. { ARG1("minusp", x);
  2678. // Anything non-numeric will not be negative!
  2679. if ((isFIXNUM(x) && x < 0) ||
  2680. (isFLOAT(x) && qfloat(x) < 0.0) ||
  2681. (isATOM(x) &&
  2682. (qheader(x) & TYPEBITS) == typeBIGNUM &&
  2683. qint64(x) < 0)) return lisptrue;
  2684. else return nil;
  2685. }
  2686. #undef BB
  2687. #define BB(a) makeinteger(~(a))
  2688. LispObject Llognot(LispObject lits, int nargs, ...)
  2689. { ARG1("lognot", x);
  2690. UNARYINTOP("lognot", x);
  2691. }
  2692. LispObject Lzerop(LispObject lits, int nargs, ...)
  2693. { ARG1("zerop", x);
  2694. // Note that a bignum can never be zero! Because that is not "big".
  2695. // This code is generous and anything non-numeric is not zero.
  2696. if (x == packfixnum(0) ||
  2697. (isFLOAT(x) && qfloat(x) == 0.0)) return lisptrue;
  2698. else return nil;
  2699. }
  2700. LispObject Lonep(LispObject lits, int nargs, ...)
  2701. { ARG1("onep", x);
  2702. if (x == packfixnum(1) ||
  2703. (isFLOAT(x) && qfloat(x) == 1.0)) return lisptrue;
  2704. else return nil;
  2705. }
  2706. #undef FF
  2707. #undef BB
  2708. #define FF(a) boxfloat((a) + 1.0)
  2709. #define BB(a) makeinteger((a) + 1)
  2710. LispObject Ladd1(LispObject lits, int nargs, ...)
  2711. { ARG1("add1", x);
  2712. UNARYOP("add1", x);
  2713. }
  2714. #undef FF
  2715. #undef BB
  2716. #define FF(a) boxfloat((a) - 1.0)
  2717. #define BB(a) makeinteger((a) - 1)
  2718. LispObject Lsub1(LispObject lits, int nargs, ...)
  2719. { ARG1("sub1", x);
  2720. UNARYOP("sub1", x);
  2721. }
  2722. #undef FF
  2723. #undef BB
  2724. #define FF(a, b) boxfloat((a) - (b))
  2725. #define BB(a, b) makeinteger((a) - (b))
  2726. LispObject Ldifference(LispObject lits, int nargs, ...)
  2727. { ARG2("difference", x, y);
  2728. NUMOP("difference", x, y);
  2729. }
  2730. #undef FF
  2731. #undef BB
  2732. #define FF(a, b) ((b) == 0.0 ? error1("division by 0.0", nil) : \
  2733. boxfloat((a) / (b)))
  2734. #define BB(a, b) ((b) == 0 ? error1("division by 0", nil) : \
  2735. makeinteger((a) / (b)))
  2736. LispObject Lquotient(LispObject lits, int nargs, ...)
  2737. { ARG2("quotient", x, y);
  2738. NUMOP("quotient", x, y);
  2739. }
  2740. #undef BB
  2741. #define BB(a, b) ((b) == 0 ? error1("remainder by 0", nil) : \
  2742. makeinteger((a) % (b)))
  2743. LispObject Lremainder(LispObject lits, int nargs, ...)
  2744. { ARG2("remainder", x, y);
  2745. INTOP("remainder", x, y);
  2746. }
  2747. #undef BB
  2748. #define BB(a, b) ((b) == 0 ? error1("division by 0", nil) : \
  2749. cons(makeinteger((a) / (b)), makeinteger((a) % (b))))
  2750. LispObject Ldivide(LispObject lits, int nargs, ...)
  2751. { ARG2("divide", x, y);
  2752. INTOP("divide", x, y);
  2753. }
  2754. #undef BB
  2755. #define BB(a) makeinteger((a) << sh)
  2756. LispObject Lleftshift(LispObject lits, int nargs, ...)
  2757. { int sh;
  2758. ARG2("leftshift", x, y);
  2759. if (!isFIXNUM(y)) return error1("Bad argument for leftshift", y);
  2760. sh = (int)qfixnum(y);
  2761. UNARYINTOP("leftshift", x);
  2762. }
  2763. #undef BB
  2764. #define BB(a) makeinteger((a) >> sh)
  2765. LispObject Lrightshift(LispObject lits, int nargs, ...)
  2766. { int sh;
  2767. ARG2("rightshift", x, y);
  2768. if (!isFIXNUM(y)) return error1("Bad argument for rightshift", y);
  2769. sh = (int)qfixnum(y);
  2770. UNARYINTOP("rightshift", x);
  2771. }
  2772. LispObject Lstop(LispObject lits, int nargs, ...)
  2773. { LispObject x = packfixnum(0);
  2774. if (nargs != 0)
  2775. { ARG1("stop", x1);
  2776. x = x1;
  2777. }
  2778. exit(isFIXNUM(x) ? (int)qfixnum(x) : EXIT_SUCCESS);
  2779. return nil;
  2780. }
  2781. LispObject Lposn(LispObject lits, int nargs, ...)
  2782. { ARG0("posn");
  2783. return packfixnum(linepos);
  2784. }
  2785. LispObject Llinelength(LispObject lits, int nargs, ...)
  2786. { ARG1("linelength", n);
  2787. LispObject prev = packfixnum(linelength);
  2788. if (isFIXNUM(n)) linelength = qfixnum(n);
  2789. return prev;
  2790. }
  2791. LispObject Lprinbyte(LispObject lits, int nargs, ...)
  2792. { ARG1("prinbyte", x); // Arg is an integer, send it to output
  2793. // with no messing around.
  2794. putc(qfixnum(x), lispfiles[lispout]);
  2795. return x;
  2796. }
  2797. int coldstart = 0;
  2798. LispObject Lrestart_csl(LispObject lits, int nargs, ...)
  2799. // (restart!-lisp) Cold restart (as for command-line "-z" option)...
  2800. // OR (restart!-lisp nil)Runs standard Read-Eval-Print loop.
  2801. // (restart!-lisp t) Reload current heap image then uses its restart fn.
  2802. // (restart!-lisp f) Reload heap image then invoke (f). (f!=nil, f!=t)
  2803. // (restart!-lisp (m f)) Reload heap, load module m, then call f.
  2804. // (restart!-lisp f a) Reload heap, call (f a). a=nil is NOT special, so
  2805. // this case depends on the number of args passed rather
  2806. // than just using default values.
  2807. // (restart!-list (m f) a) Reload heap, load module m, call (f a).
  2808. { ARG0123("restart-csl", x, y, z);
  2809. if (z != NULLATOM)
  2810. return error1s("wrong number of arguments for", "restart-lisp");
  2811. if (x == NULLATOM) x = nil;
  2812. if (y == NULLATOM) work1 = cons(x, nil);
  2813. else work1 = list2star(x, y, nil);
  2814. if (unwindflag == unwindNONE) unwindflag = unwindRESTART;
  2815. return nil;
  2816. }
  2817. LispObject Lpreserve(LispObject lits, int nargs, ...)
  2818. // (preserve) Dump image, leave restart fn unchanged, exit.
  2819. // (preserve f) Dump image with new restart fn if f!=nil, exit.
  2820. // (preserve f b) As above, but also change banner to b if b!=nil.
  2821. // (preserve f b nil) As above.
  2822. // (preserve f b t) Dump image as before, then do restart that loads
  2823. // the newly created image and uses its restart fn.
  2824. // (preserve f b g) Dump image, readload it but override restart fn
  2825. // to be g just this time.
  2826. // (preserve f b (m g)) Dump image, reload, load-module m, call function g.
  2827. // (preserve f b g a) Reserved to pass a as argument to the restart function.
  2828. // not implemeted yet.
  2829. { ARG0123("preserve", x,y,z);
  2830. if (x == NULLATOM) x = nil;
  2831. if (y == NULLATOM) y = nil; // Ignored for now!
  2832. if (z == NULLATOM) z = nil;
  2833. restartfn = x;
  2834. work1 = cons(z, nil);
  2835. if (unwindflag == unwindNONE)
  2836. { unwindflag = unwindPRESERVE;
  2837. if (z != nil) unwindflag |= unwindRESTART;
  2838. }
  2839. return nil;
  2840. }
  2841. LispObject Lprin(LispObject lits, int nargs, ...)
  2842. { ARG1("prin", x);
  2843. return prin(x);
  2844. }
  2845. LispObject Lprint(LispObject lits, int nargs, ...)
  2846. { ARG1("print", x);
  2847. return print(x);
  2848. }
  2849. LispObject Lprinc(LispObject lits, int nargs, ...)
  2850. { ARG1("princ", x);
  2851. return princ(x);
  2852. }
  2853. LispObject Lprinhex(LispObject lits, int nargs, ...)
  2854. { ARG1("princ", x);
  2855. return prinhex(x);
  2856. }
  2857. LispObject Lprintc(LispObject lits, int nargs, ...)
  2858. { ARG1("printc", x);
  2859. return printc(x);
  2860. }
  2861. LispObject Lterpri(LispObject lits, int nargs, ...)
  2862. { ARG0("terpri");
  2863. wrch('\n');
  2864. return nil;
  2865. }
  2866. LispObject Lnreverse(LispObject lits, int nargs, ...)
  2867. { ARG1("nreverse", x);
  2868. return nreverse(x);
  2869. }
  2870. LispObject Lexplode(LispObject lits, int nargs, ...)
  2871. { int f = lispout;
  2872. ARG1("explode", x);
  2873. lispout = -1;
  2874. work1 = nil;
  2875. prin(x);
  2876. lispout = f;
  2877. return nreverse(work1);
  2878. }
  2879. LispObject Lexplodec(LispObject lits, int nargs, ...)
  2880. { int f = lispout;
  2881. ARG1("explodec", x);
  2882. lispout = -1;
  2883. work1 = nil;
  2884. princ(x);
  2885. lispout = f;
  2886. return nreverse(work1);
  2887. }
  2888. LispObject Lreadbyte(LispObject lits, int nargs, ...)
  2889. { int ch;
  2890. ARG0("readbyte"); // Read byte and return integer.
  2891. ch = curchar;
  2892. curchar = rdch();
  2893. return packfixnum(ch & 0xff);
  2894. }
  2895. LispObject Lreadch(LispObject lits, int nargs, ...)
  2896. { char ch[4];
  2897. ARG0("readch");
  2898. if (curchar == EOF) return eofsym;
  2899. ch[0] = qvalue(lower) != nil ? tolower(curchar) :
  2900. qvalue(raise) != nil ? toupper(curchar) : curchar;
  2901. ch[1] = 0;
  2902. curchar = rdch();
  2903. return lookup(ch, 1, 1);
  2904. }
  2905. LispObject Lreadline(LispObject lits, int nargs, ...)
  2906. { char ch[200];
  2907. int n = 0;
  2908. ARG0("readline");
  2909. if (curchar == '\n') curchar = rdch();
  2910. while (curchar != '\n' && curchar != EOF)
  2911. { if (n < sizeof(ch)-1) ch[n++] = curchar;
  2912. curchar = rdch();
  2913. }
  2914. if (n == 0 && curchar == EOF) return eofsym;
  2915. ch[n] = 0;
  2916. return lookup(ch, n, 1);
  2917. }
  2918. LispObject Lremob(LispObject lits, int nargs, ...)
  2919. { ARG1("remob", x);
  2920. if (!isSYMBOL(x)) return x;
  2921. LispObject pn = qpname(x);
  2922. int len = veclength(qheader(pn));
  2923. const char *s = qstring(pn);
  2924. return lookup(s, len, -1);
  2925. }
  2926. LispObject Lread(LispObject lits, int nargs, ...)
  2927. { ARG0("read");
  2928. return readS();
  2929. }
  2930. LispObject Lcompress(LispObject lits, int nargs, ...)
  2931. { int f = lispin;
  2932. LispObject r;
  2933. ARG1("compress", x);
  2934. lispin = -1;
  2935. symtype = '?';
  2936. curchar = '\n';
  2937. push(cursym);
  2938. work1 = x;
  2939. r = readS();
  2940. lispin = f;
  2941. pop(cursym);
  2942. return r;
  2943. }
  2944. LispObject Lrds(LispObject lits, int nargs, ...)
  2945. { int old = lispin;
  2946. ARG1("rds", x);
  2947. if (x == nil) x = packfixnum(3);
  2948. if (isFIXNUM(x))
  2949. { int n = (int)qfixnum(x);
  2950. if (0 <= n && n < MAX_LISPFILES && lispfiles[n] != NULL &&
  2951. (file_direction & (1<<n)) == 0)
  2952. { lispin = n;
  2953. symtype = '?';
  2954. // If you RDS between two files then curchar (for each) must not be
  2955. // disturbed, but this hack makes EOF get re-checked for...
  2956. if (curchar == EOF) curchar = '\n';
  2957. return packfixnum(old);
  2958. }
  2959. }
  2960. return error1("rds failed", x);
  2961. }
  2962. LispObject Lwrs(LispObject lits, int nargs, ...)
  2963. { int old = lispout;
  2964. ARG1("wrs", x);
  2965. if (x == nil) x = packfixnum(1);
  2966. if (isFIXNUM(x))
  2967. { int n = (int)qfixnum(x);
  2968. if (0 <= n && n < MAX_LISPFILES && lispfiles[n] != NULL &&
  2969. (file_direction & (1<<n)) != 0)
  2970. { lispout = n;
  2971. return packfixnum(old);
  2972. }
  2973. }
  2974. return error1("wrs failed", x);
  2975. }
  2976. #define LONGEST_FILENAME 1000
  2977. char filename[2*LONGEST_FILENAME+50];
  2978. static char imagename[LONGEST_FILENAME];
  2979. static char lispdirectory[LONGEST_FILENAME];
  2980. LispObject Lget_lisp_directory(LispObject lits, int nargs, ...)
  2981. {
  2982. return makestring(lispdirectory, strlen(lispdirectory));
  2983. }
  2984. LispObject Lsystem(LispObject lits, int nargs, ...)
  2985. { ARG1("system", x);
  2986. if (isSYMBOL(x)) x = qpname(x);
  2987. if (!isSTRING(x))
  2988. return error1("bad arg for system", x);
  2989. sprintf(filename, "%.*s", (int)veclength(qheader(x)), qstring(x));
  2990. system(filename);
  2991. return nil;
  2992. }
  2993. LispObject Lsetpchar(LispObject lits, int nargs, ...)
  2994. { ARG1("setpchar", x);
  2995. if (isSYMBOL(x)) x = qpname(x);
  2996. if (!isSTRING(x))
  2997. return error1("bad arg for setpchar", x);
  2998. LispObject r = makestring(promptstring, strlen(promptstring));
  2999. sprintf(promptstring, "%.*s", (int)veclength(qheader(x)), qstring(x));
  3000. return r;
  3001. }
  3002. LispObject Lopen(LispObject lits, int nargs, ...)
  3003. { FILE *f;
  3004. int n, how = 0;
  3005. char *p;
  3006. ARG2("open", x, y);
  3007. if (isSYMBOL(x)) x = qpname(x);
  3008. if (!isSTRING(x) ||
  3009. !((y == input && (how=1)!=0) ||
  3010. (y == output && (how=2)!=0) ||
  3011. (y == pipe && (how=3)!=0)))
  3012. return error2("bad arg for open", x, y);
  3013. if (*qstring(x)=='$' && (p=strchr(qstring(x), '/'))!=NULL)
  3014. { sprintf(filename, "@%.*s", (int)(p-qstring(x))-1, 1+qstring(x));
  3015. lits = qvalue(lookup(filename, strlen(filename), 0));
  3016. if (isSTRING(lits)) sprintf(filename, "%.*s%.*s",
  3017. (int)veclength(qheader(lits)), qstring(lits),
  3018. (int)(veclength(qheader(x)) - (p-qstring(x))), p);
  3019. else sprintf(filename, "%.*s", (int)veclength(qheader(x)), qstring(x));
  3020. }
  3021. else sprintf(filename, "%.*s", (int)veclength(qheader(x)), qstring(x));
  3022. #ifdef __WIN32__
  3023. // while (strchr(filename, '/') != NULL) *strchr(filename, '/') = '\\';
  3024. #endif // __WIN32__
  3025. if (how == 3) f = popen(filename, "w");
  3026. else f = fopen(filename, (how == 1 ? "r" : "w"));
  3027. if (f == NULL) return error1("[open] file could not be opened", x);
  3028. for (n=4; n<MAX_LISPFILES && lispfiles[n]!=NULL; n++);
  3029. if (n<MAX_LISPFILES)
  3030. { lispfiles[n] = f;
  3031. if (y != input) file_direction |= (1 << n);
  3032. return packfixnum(n);
  3033. }
  3034. return error1("too many open files", x);
  3035. }
  3036. LispObject Lopen_module(LispObject lits, int nargs, ...)
  3037. { FILE *f;
  3038. int n, how = 0;
  3039. ARG2("open-module", x, y);
  3040. if (isSYMBOL(x)) x = qpname(x);
  3041. if (!isSTRING(x) ||
  3042. !((y == input && (how=1)!=0) ||
  3043. (y == output && (how=2)!=0)))
  3044. return error2("bad arg for open-module", x, y);
  3045. sprintf(filename, "%s.modules/%.*s.fasl", imagename,
  3046. (int)veclength(qheader(x)), qstring(x));
  3047. f = fopen(filename, (how == 1 ? "r" : "w"));
  3048. if (f == NULL)
  3049. { if (how == 2)
  3050. {
  3051. // The function mkdir() is declared in sys/stat.h and may not be
  3052. // available on all platforms? If I fail to open xxx.img.modules/yyy.fasl
  3053. // I will try makeing certain that the directory exists...
  3054. sprintf(filename, "mkdir %s.modules", imagename);
  3055. system(filename);
  3056. sprintf(filename, "%s.modules/%.*s.fasl", imagename,
  3057. (int)veclength(qheader(x)), qstring(x));
  3058. f = fopen(filename, "w");
  3059. if (f == NULL)
  3060. { printf("+++ module file-name: %s mode=%d\n", filename, how);
  3061. return error1("module could not be opened", x);
  3062. }
  3063. }
  3064. else
  3065. { printf("+++ module file-name: %s mode=%d\n", filename, how);
  3066. return error1("module could not be opened", x);
  3067. }
  3068. }
  3069. for (n=4; n<MAX_LISPFILES && lispfiles[n]!=NULL; n++);
  3070. if (n<MAX_LISPFILES)
  3071. { lispfiles[n] = f;
  3072. if (y != input) file_direction |= (1 << n);
  3073. return packfixnum(n);
  3074. }
  3075. return error1("too many open files", x);
  3076. }
  3077. LispObject Lmodulep(LispObject lits, int nargs, ...)
  3078. { FILE *f;
  3079. ARG1("modulep", x);
  3080. if (isSYMBOL(x)) x = qpname(x);
  3081. if (!isSTRING(x))
  3082. return error1("bad arg for modulep", x);
  3083. sprintf(filename, "%s.modules/%.*s.fasl", imagename,
  3084. (int)veclength(qheader(x)), qstring(x));
  3085. f = fopen(filename, "r");
  3086. if (f == NULL) return nil;
  3087. fclose(f);
  3088. return lisptrue;
  3089. }
  3090. LispObject Lclose(LispObject lits, int nargs, ...)
  3091. { ARG1("close", x);
  3092. if (isFIXNUM(x))
  3093. { int n = (int)qfixnum(x);
  3094. if (n > 3 && n < MAX_LISPFILES)
  3095. { if (lispin == n) lispin = 3;
  3096. if (lispout == n) lispout = 1;
  3097. if (lispfiles[n] != NULL) fclose(lispfiles[n]);
  3098. lispfiles[n] = NULL;
  3099. file_direction &= ~(1<<n);
  3100. }
  3101. }
  3102. return nil;
  3103. }
  3104. void readevalprint(int loadp)
  3105. { while (symtype != EOF)
  3106. { LispObject r;
  3107. push(qvalue(echo));
  3108. unwindflag = unwindNONE;
  3109. if (loadp) qvalue(echo) = nil;
  3110. backtraceflag = backtraceHEADER | backtraceTRACE;
  3111. r = readS();
  3112. pop(qvalue(echo));
  3113. fflush(stdout);
  3114. if (unwindflag != unwindNONE) /* Do nothing */ ;
  3115. else if (loadp || qvalue(dfprint) == nil ||
  3116. (isCONS(r) && (qcar(r) == lookup("rdf", 3, 0) ||
  3117. qcar(r) == lookup("faslend", 7, 0))))
  3118. { r = eval(r);
  3119. if (unwindflag == unwindNONE && !loadp)
  3120. { linepos += printf("Value: ");
  3121. #ifdef DEBUG
  3122. if (logfile != NULL) fprintf(logfile, "Value: ");
  3123. #endif // DEBUG
  3124. print(r);
  3125. fflush(stdout);
  3126. }
  3127. }
  3128. else
  3129. { r = cons(r, nil);
  3130. if (unwindflag == unwindNONE) Lapply(nil, 2, qvalue(dfprint), r);
  3131. }
  3132. if ((unwindflag & (unwindPRESERVE | unwindRESTART)) != 0) return;
  3133. }
  3134. }
  3135. LispObject Lrdf(LispObject lits, int nargs, ...)
  3136. { int f, f1;
  3137. ARG1("rdf", x);
  3138. f1 = Lopen(nil, 2, x, input);
  3139. if (unwindflag != unwindNONE) return nil;
  3140. f = Lrds(nil, 1, f1);
  3141. readevalprint(0);
  3142. Lrds(nil, 1, f);
  3143. Lclose(nil, 1, f1);
  3144. printf("+++ End of rdf\n");
  3145. return nil;
  3146. }
  3147. LispObject Lload_module(LispObject lits, int nargs, ...)
  3148. { int f, f1;
  3149. ARG1("load-module", x);
  3150. f1 = Lopen_module(nil, 2, x, input);
  3151. if (unwindflag != unwindNONE) return nil;
  3152. // I want to save the current input status
  3153. f = Lrds(nil, 1, f1);
  3154. readevalprint(1);
  3155. Lrds(nil, 1, f);
  3156. Lclose(nil, 1, f1);
  3157. return nil;
  3158. }
  3159. LispObject Ltrace(LispObject lits, int nargs, ...)
  3160. { ARG1("trace", x);
  3161. while (isCONS(x))
  3162. { if (isSYMBOL(qcar(x))) qflags(qcar(x)) |= flagTRACED;
  3163. x = qcdr(x);
  3164. }
  3165. return nil;
  3166. }
  3167. LispObject Luntrace(LispObject lits, int nargs, ...)
  3168. { ARG1("untrace", x);
  3169. while (isCONS(x))
  3170. { if (isSYMBOL(qcar(x))) qflags(qcar(x)) &= ~flagTRACED;
  3171. x = qcdr(x);
  3172. }
  3173. return nil;
  3174. }
  3175. LispObject Lerror(LispObject lits, int nargs, ...)
  3176. { ARG2("error", x, y);
  3177. return error2("error function called", x, y);
  3178. }
  3179. LispObject Lenable_errorset(LispObject lits, int nargs, ...)
  3180. { ARG2("enable-errorset", x, y);
  3181. if (isFIXNUM(x))
  3182. { forcedMIN = qfixnum(x);
  3183. if (forcedMIN < 0) forcedMIN = 0;
  3184. else if (forcedMIN > 3) forcedMIN = 3;
  3185. }
  3186. else if (x == nil) forcedMIN = 0;
  3187. else forcedMIN = 3;
  3188. if (isFIXNUM(y))
  3189. { forcedMAX = qfixnum(x);
  3190. if (forcedMAX < 0) forcedMAX = 0;
  3191. else if (forcedMAX > 3) forcedMAX = 3;
  3192. }
  3193. else if (y == nil) forcedMAX = 0;
  3194. else forcedMAX = 3;
  3195. if (forcedMIN > forcedMAX) forcedMAX = forcedMIN;
  3196. if (forcedMIN > 0) backtraceflag |= backtraceHEADER;
  3197. if (forcedMIN > 1) backtraceflag |= backtraceHEADER;
  3198. if (forcedMAX < 1) backtraceflag &= ~backtraceHEADER;
  3199. if (forcedMAX < 2) backtraceflag &= ~backtraceHEADER;
  3200. return nil;
  3201. }
  3202. LispObject Lerrorset(LispObject lits, int nargs, ...)
  3203. { int save = backtraceflag;
  3204. ARG3("errorset", x, y, z);
  3205. backtraceflag = 0;
  3206. if (y != nil) backtraceflag |= backtraceHEADER;
  3207. if (z != nil) backtraceflag |= backtraceTRACE;
  3208. if (forcedMAX < 1) backtraceflag &= ~backtraceHEADER;
  3209. if (forcedMAX < 2) backtraceflag &= ~backtraceHEADER;
  3210. if (forcedMIN > 0) backtraceflag |= backtraceHEADER;
  3211. if (forcedMIN > 1) backtraceflag |= backtraceHEADER;
  3212. x = eval(x);
  3213. if (unwindflag == unwindERROR ||
  3214. unwindflag == unwindBACKTRACE)
  3215. { unwindflag = unwindNONE;
  3216. x = nil;
  3217. }
  3218. else x = cons(x, nil);
  3219. backtraceflag = save;
  3220. return x;
  3221. }
  3222. struct defined_functions
  3223. { const char *name;
  3224. int flags;
  3225. void *entrypoint;
  3226. };
  3227. struct defined_functions fnsetup[] =
  3228. {
  3229. // First the special forms
  3230. {"quote", flagSPECFORM, (void *)Lquote},
  3231. {"cond", flagSPECFORM, (void *)Lcond},
  3232. {"and", flagSPECFORM, (void *)Land},
  3233. {"or", flagSPECFORM, (void *)Lor},
  3234. {"de", flagSPECFORM, (void *)Lde},
  3235. {"df", flagSPECFORM, (void *)Ldf},
  3236. {"dm", flagSPECFORM, (void *)Ldm},
  3237. {"setq", flagSPECFORM, (void *)Lsetq},
  3238. {"progn", flagSPECFORM, (void *)Lprogn},
  3239. {"prog", flagSPECFORM, (void *)Lprog},
  3240. {"go", flagSPECFORM, (void *)Lgo},
  3241. // The following are implemented as special forms here because they
  3242. // take variable or arbitrary numbers of arguments - however they all
  3243. // evaluate all their arguments in a rather simple way, so they
  3244. // could be treated a sorts of "ordinary" function.
  3245. {"list", flagSPECFORM, (void *)Llist},
  3246. {"list*", flagSPECFORM, (void *)Lliststar},
  3247. {"iplus", flagSPECFORM, (void *)Lplus},
  3248. {"itimes", flagSPECFORM, (void *)Ltimes},
  3249. {"ilogand", flagSPECFORM, (void *)Llogand},
  3250. {"ilogor", flagSPECFORM, (void *)Llogor},
  3251. {"ilogxor", flagSPECFORM, (void *)Llogxor},
  3252. // Now ordinary functions.
  3253. {"apply", 0, (void *)Lapply},
  3254. {"atan", 0, (void *)Latan},
  3255. {"atom", 0, (void *)Latom},
  3256. {"bignump", 0, (void *)Lbignump},
  3257. {"boundp", 0, (void *)Lboundp},
  3258. {"car", 0, (void *)Lcar},
  3259. {"cdr", 0, (void *)Lcdr},
  3260. {"char", 0, (void *)Lchar},
  3261. {"char-code", 0, (void *)Lcharcode},
  3262. {"checkpoint", 0, (void *)Lpreserve},
  3263. {"close", 0, (void *)Lclose},
  3264. {"clrhash", 0, (void *)Lclrhash},
  3265. {"code-char", 0, (void *)Lcodechar},
  3266. {"compress", 0, (void *)Lcompress},
  3267. {"cons", 0, (void *)Lcons},
  3268. {"cos", 0, (void *)Lcos},
  3269. {"date", 0, (void *)Ldate},
  3270. {"date-and-time",0, (void *)Ldate_and_time},
  3271. {"eq", 0, (void *)Leq},
  3272. {"equal", 0, (void *)Lequal},
  3273. {"error", 0, (void *)Lerror},
  3274. {"errorset", 0, (void *)Lerrorset},
  3275. {"eval", 0, (void *)Leval},
  3276. {"exp", 0, (void *)Lexp},
  3277. {"explode", 0, (void *)Lexplode},
  3278. {"explodec", 0, (void *)Lexplodec},
  3279. {"floatp", 0, (void *)Lfloatp},
  3280. {"gensym", 0, (void *)Lgensym},
  3281. {"gensymp", 0, (void *)Lgensymp},
  3282. {"get", 0, (void *)Lget},
  3283. {"get-lisp-directory",0, (void *)Lget_lisp_directory},
  3284. {"getd", 0, (void *)Lgetd},
  3285. {"gethash", 0, (void *)Lgethash},
  3286. {"getv", 0, (void *)Lgetv},
  3287. {"iadd1", 0, (void *)Ladd1},
  3288. {"iceiling", 0, (void *)Lceiling},
  3289. {"idifference",0, (void *)Ldifference},
  3290. {"idivide", 0, (void *)Ldivide},
  3291. {"iequal", 0, (void *)Lequal},
  3292. {"ifix", 0, (void *)Lfix},
  3293. {"ifixp", 0, (void *)Lfixp},
  3294. {"ifloat", 0, (void *)Lfloat},
  3295. {"ifloor", 0, (void *)Lfloor},
  3296. {"igeq", 0, (void *)Lgeq},
  3297. {"igreaterp", 0, (void *)Lgreaterp},
  3298. {"ileftshift", 0, (void *)Lleftshift},
  3299. {"ileq", 0, (void *)Lleq},
  3300. {"ilessp", 0, (void *)Llessp},
  3301. {"ilognot", 0, (void *)Llognot},
  3302. {"iminus", 0, (void *)Lminus},
  3303. {"iminusp", 0, (void *)Lminusp},
  3304. {"inumberp", 0, (void *)Lnumberp},
  3305. {"iquotient", 0, (void *)Lquotient},
  3306. {"iremainder", 0, (void *)Lremainder},
  3307. {"irightshift",0, (void *)Lrightshift},
  3308. {"isub1", 0, (void *)Lsub1},
  3309. {"linelength*",0, (void *)Llinelength},
  3310. {"load-module",0, (void *)Lload_module},
  3311. {"log", 0, (void *)Llog},
  3312. {"lposn", 0, (void *)Lposn},
  3313. {"makeunbound",0, (void *)Lmakeunbound},
  3314. {"mkhash", 0, (void *)Lmkhash},
  3315. {"mkvect", 0, (void *)Lmkvect},
  3316. {"modulep", 0, (void *)Lmodulep},
  3317. {"null", 0, (void *)Lnull},
  3318. {"oblist", 0, (void *)Loblist},
  3319. {"onep", 0, (void *)Lonep},
  3320. {"open", 0, (void *)Lopen},
  3321. {"open-module",0, (void *)Lopen_module},
  3322. {"plist", 0, (void *)Lplist},
  3323. {"pname", 0, (void *)Lpname},
  3324. {"posn", 0, (void *)Lposn},
  3325. {"preserve", 0, (void *)Lpreserve},
  3326. {"prin", 0, (void *)Lprin},
  3327. {"prin1", 0, (void *)Lprin},
  3328. {"prin2", 0, (void *)Lprinc},
  3329. {"prinbyte", 0, (void *)Lprinbyte},
  3330. {"princ", 0, (void *)Lprinc},
  3331. {"prinhex", 0, (void *)Lprinhex},
  3332. {"print", 0, (void *)Lprint},
  3333. {"printc", 0, (void *)Lprintc},
  3334. {"prog1", 0, (void *)Lprog1},
  3335. {"prog2", 0, (void *)Lprog2},
  3336. {"put", 0, (void *)Lput},
  3337. {"puthash", 0, (void *)Lputhash},
  3338. {"putv", 0, (void *)Lputv},
  3339. {"rdf", 0, (void *)Lrdf},
  3340. {"rds", 0, (void *)Lrds},
  3341. {"read", 0, (void *)Lread},
  3342. {"readbyte", 0, (void *)Lreadbyte},
  3343. {"readch", 0, (void *)Lreadch},
  3344. {"readline", 0, (void *)Lreadline},
  3345. {"reclaim", 0, (void *)Lreclaim},
  3346. {"remhash", 0, (void *)Lremhash},
  3347. {"remob", 0, (void *)Lremob},
  3348. {"remprop", 0, (void *)Lremprop},
  3349. {"restart-lisp",0, (void *)Lrestart_csl},
  3350. {"restart-csl",0, (void *)Lrestart_csl},
  3351. {"return", 0, (void *)Lreturn},
  3352. {"rplaca", 0, (void *)Lrplaca},
  3353. {"rplacd", 0, (void *)Lrplacd},
  3354. {"set", 0, (void *)Lset},
  3355. {"setpchar*", 0, (void *)Lsetpchar},
  3356. {"sin", 0, (void *)Lsin},
  3357. {"sqrt", 0, (void *)Lsqrt},
  3358. {"stop", 0, (void *)Lstop},
  3359. {"stringp", 0, (void *)Lstringp},
  3360. {"symbol-name",0, (void *)Lpname},
  3361. {"symbolp", 0, (void *)Lsymbolp},
  3362. {"system", 0, (void *)Lsystem},
  3363. {"terpri", 0, (void *)Lterpri},
  3364. {"time", 0, (void *)Ltime},
  3365. {"trace", 0, (void *)Ltrace},
  3366. {"untrace", 0, (void *)Luntrace},
  3367. {"upbv", 0, (void *)Lupbv},
  3368. {"vectorp", 0, (void *)Lvectorp},
  3369. {"wrs", 0, (void *)Lwrs},
  3370. {"zerop", 0, (void *)Lzerop},
  3371. {NULL, 0, NULL}
  3372. };
  3373. void setup()
  3374. {
  3375. // Ensure that initial symbols and functions are in place. Parts of this
  3376. // code are rather rambling and repetitive but this is at least a simple
  3377. // way to do things. I am going to assume that nothing can fail within this
  3378. // setup code, so I can omit all checks for error conditions.
  3379. struct defined_functions *p;
  3380. undefined = lookup("~indefinite-value~", 18, 1);
  3381. qflags(undefined) |= flagGLOBAL;
  3382. qvalue(undefined) = undefined;
  3383. nil = lookup("nil", 3, 1);
  3384. qflags(nil) |= flagGLOBAL;
  3385. qvalue(nil) = nil;
  3386. lisptrue = lookup("t", 1, 1);
  3387. qflags(lisptrue) |= flagGLOBAL;
  3388. qvalue(lisptrue) = lisptrue;
  3389. qvalue(echo = lookup("*echo", 5, 1)) = interactive ? nil : lisptrue;
  3390. qflags(echo) |= flagFLUID;
  3391. qvalue(lispsystem = lookup("lispsystem*", 11, 1)) =
  3392. list2star(lookup("vsl", 3, 1), lookup("csl", 3, 1),
  3393. list2star(lookup("embedded", 8, 1),
  3394. cons(lookup("image", 5, 3),
  3395. makestring(imagename, strlen(imagename))), nil));
  3396. qflags(lispsystem) |= flagGLOBAL;
  3397. quote = lookup("quote", 5, 1);
  3398. function = lookup("function", 8, 1);
  3399. backquote = lookup("`", 1, 1);
  3400. comma = lookup(",", 1, 1);
  3401. comma_at = lookup(",@", 2, 1);
  3402. comma_dot = lookup(",.", 2, 1);
  3403. eofsym = lookup("$eof$", 5, 1);
  3404. qflags(eofsym) |= flagGLOBAL;
  3405. qvalue(eofsym) = eofsym;
  3406. lambda = lookup("lambda", 6, 1);
  3407. expr = lookup("expr", 4, 1);
  3408. subr = lookup("subr", 4, 1);
  3409. fexpr = lookup("fexpr", 5, 1);
  3410. fsubr = lookup("fsubr", 5, 1);
  3411. macro = lookup("macro", 5, 1);
  3412. input = lookup("input", 5, 1);
  3413. output = lookup("output", 6, 1);
  3414. pipe = lookup("pipe", 4, 1);
  3415. qvalue(dfprint = lookup("dfprint*", 6, 1)) = nil;
  3416. qflags(dfprint) |= flagFLUID;
  3417. bignum = lookup("~bignum", 7, 1);
  3418. qvalue(raise = lookup("*raise", 6, 1)) = nil;
  3419. qvalue(lower = lookup("*lower", 6, 1)) = lisptrue;
  3420. qflags(raise) |= flagFLUID;
  3421. qflags(lower) |= flagFLUID;
  3422. toploopeval = lookup("toploopeval*", 12, 1);
  3423. loseflag = lookup("lose", 4, 1);
  3424. bignum = lookup("~bignum", 7, 1);
  3425. condsymbol = lookup("cond", 4, 1);
  3426. prognsymbol = lookup("progn", 5, 1);
  3427. gosymbol = lookup("go", 2, 1);
  3428. returnsymbol = lookup("return", 6, 1);
  3429. #ifdef PSL
  3430. dummyvar = lookup("~dummyvar", 9, 1);
  3431. #endif
  3432. cursym = nil;
  3433. work1 = work2 = nil;
  3434. p = fnsetup;
  3435. while (p->name != NULL)
  3436. { LispObject w = lookup(p->name, strlen(p->name), 1);
  3437. qflags(w) |= p->flags;
  3438. qdefn(w) = p->entrypoint;
  3439. p++;
  3440. }
  3441. }
  3442. void cold_start()
  3443. {
  3444. // version of setup to call when there is no initial heap image at all.
  3445. int i;
  3446. // I make the object-hash-table lists end in a fixnum rather than nil
  3447. // because I want to create the hash table before even the symbol nil
  3448. // exists.
  3449. for (i=0; i<OBHASH_SIZE; i++) obhash[i] = tagFIXNUM;
  3450. for (i=0; i<BASES_SIZE; i++) bases[i] = NULLATOM;
  3451. setup();
  3452. // The following fields could not be set up quite early enough in the
  3453. // cold start case, so I repair them now.
  3454. restartfn = qplist(undefined) = qlits(undefined) =
  3455. qplist(nil) = qlits(nil) = nil;
  3456. }
  3457. LispObject relocate(LispObject a, LispObject change)
  3458. {
  3459. // Used to update a LispObject when reloaded from a saved heap image.
  3460. switch (a & TAGBITS)
  3461. { case tagATOM:
  3462. if (a == NULLATOM) return a;
  3463. case tagCONS:
  3464. case tagSYMBOL:
  3465. case tagFLOAT:
  3466. return a + change;
  3467. default:
  3468. //case tagFIXNUM:
  3469. //case tagFORWARD:
  3470. //case tagHDR:
  3471. return a;
  3472. }
  3473. }
  3474. // A saved image will start with a word that contains the following 32-bit
  3475. // code. This identifies the word-width of the system involved.
  3476. #define FILEID (('v' << 0) | ('s' << 8) | ('l' << 16) | \
  3477. (('0' + sizeof(LispObject)) << 24))
  3478. void warm_start()
  3479. {
  3480. // The idea here is that a file that will already have been
  3481. // created by a previous use of Lisp, and it should be re-loaded.
  3482. gzFile f = gzopen(imagename, "rb");
  3483. int i;
  3484. LispObject currentbase = heap1base, change, s;
  3485. if (f == NULL)
  3486. { printf("Error: unable to open image for reading\n");
  3487. my_exit(EXIT_FAILURE);
  3488. }
  3489. if (gzread(f, nonbases, (unsigned int)sizeof(nonbases)) != sizeof(nonbases) ||
  3490. headerword != FILEID ||
  3491. gzread(f, bases, (unsigned int)sizeof(bases)) != sizeof(bases) ||
  3492. gzread(f, obhash, (unsigned int)sizeof(obhash)) != sizeof(obhash))
  3493. { printf("Error: Image file corrupted or incompatible\n");
  3494. my_exit(EXIT_FAILURE);
  3495. }
  3496. change = currentbase - heap1base;
  3497. // Now I relocate the key addresses to refer to the CURRENT rather than
  3498. // the saved address map.
  3499. heap1base += change;
  3500. heap1top += change;
  3501. fringe1 += change;
  3502. fpfringe1 += change;
  3503. if (gzread(f, (void *)heap1base, (unsigned int)(fringe1-heap1base)) !=
  3504. (int)(fringe1-heap1base) ||
  3505. gzread(f, (void *)fpfringe1, (unsigned int)(heap1top-fpfringe1)) !=
  3506. (int)(heap1top-fpfringe1))
  3507. { printf("Error: Unable to read image file\n");
  3508. my_exit(EXIT_FAILURE);
  3509. }
  3510. gzclose(f);
  3511. if (change != 0)
  3512. { for (i=0; i<BASES_SIZE; i++)
  3513. bases[i] = relocate(bases[i], change);
  3514. for (i=0; i<OBHASH_SIZE; i++)
  3515. obhash[i] = relocate(obhash[i], change);
  3516. // The main heap now needs to be scanned and addresses in it corrected.
  3517. s = heap1base;
  3518. while (s != fringe1)
  3519. { LispObject h, w;
  3520. if (!isHDR(h = qcar(s))) // A simple cons cell
  3521. { qcar(s) = relocate(h, change);
  3522. qcdr(s) = relocate(qcdr(s), change);
  3523. s += 2*sizeof(LispObject);
  3524. }
  3525. else // The item is one that uses a header
  3526. switch (h & TYPEBITS)
  3527. { case typeSYM:
  3528. case typeGENSYM:
  3529. w = s + tagSYMBOL;
  3530. // qflags(w) does not need adjusting
  3531. qvalue(w) = relocate(qvalue(w), change);
  3532. qplist(w) = relocate(qplist(w), change);
  3533. qpname(w) = relocate(qpname(w), change);
  3534. if (qdefn(w) == (void *)saveinterp)
  3535. qdefn(w) = (void *)interpret;
  3536. else if (qdefn(w) == (void *)saveinterpspec)
  3537. qdefn(w) = (void *)interpretspecform;
  3538. qlits(w) = relocate(qlits(w), change);
  3539. s += SYMSIZE*sizeof(LispObject);
  3540. continue;
  3541. case typeSTRING: case typeBIGNUM:
  3542. // These sorts of atom just contain binary data so do not need adjusting,
  3543. // but I have to allow for the length code being in bytes etc.
  3544. s += ALIGN8(sizeof(LispObject) + veclength(h));
  3545. continue;
  3546. case typeEQHASH: case typeEQUALHASH:
  3547. qcar(s) ^= (typeEQHASH ^ typeEQHASHX);
  3548. case typeVEC: case typeEQHASHX: case typeEQUALHASHX:
  3549. s += sizeof(LispObject);
  3550. w = veclength(h);
  3551. while (w > 0)
  3552. { qcar(s) = relocate(qcar(s), change);
  3553. s += sizeof(LispObject);
  3554. w -= sizeof(LispObject);
  3555. }
  3556. s = ALIGN8(s);
  3557. continue;
  3558. default:
  3559. // The spare codes!
  3560. printf("Failure with h = %x\n", (int)h & TYPEBITS);
  3561. assert(0);
  3562. }
  3563. }
  3564. }
  3565. setup(); // resets all built-in functions properly.
  3566. }
  3567. #define VERSION 1002
  3568. int main(int argc, char *argv[])
  3569. {
  3570. for (int i=0; i<MAX_LISPFILES+1; i++)
  3571. { curchars[i] = '\n';
  3572. symtypes[i] = 0;
  3573. }
  3574. #ifndef NO_LIBEDIT
  3575. elx_e = el_init(argv[0], stdin, stdout, stderr);
  3576. el_set(elx_e, EL_PROMPT, prompt);
  3577. el_set(elx_e, EL_EDITOR, "emacs");
  3578. if ((elx_h = history_init()) == 0)
  3579. { fprintf(stderr, "Unable to initialize history\n");
  3580. exit(1);
  3581. }
  3582. history(elx_h, &elx_v, H_SETSIZE, 400);
  3583. el_set(elx_e, EL_HIST, history, elx_h);
  3584. #endif
  3585. int i;
  3586. const char *inputfilename = NULL;
  3587. void *pool;
  3588. pool = (void *)malloc(HEAPSIZE + BITMAPSIZE + STACKSIZE + 16);
  3589. if (pool == NULL)
  3590. { printf("Not enough memory available: Unable to proceed\n");
  3591. my_exit(EXIT_FAILURE);
  3592. }
  3593. memset(pool, 0, HEAPSIZE + BITMAPSIZE + STACKSIZE + 16);
  3594. coldstart = 0;
  3595. interactive = 1;
  3596. #ifdef DEBUG
  3597. logfile = fopen("vsl.log", "w");
  3598. #endif // DEBUG
  3599. #ifdef __WIN32__
  3600. i = strlen(argv[0]);
  3601. if (strcmp(argv[0]+i-4, ".exe") == 0) i -= 4;
  3602. sprintf(imagename, "%.*s.img", i, argv[0]);
  3603. #else // __WIN32__
  3604. sprintf(imagename, "%s.img", argv[0]);
  3605. #endif // __WIN32__
  3606. strcpy(lispdirectory, imagename);
  3607. { char *p = lispdirectory+strlen(lispdirectory)-5;
  3608. while (isalnum((int)*p) && p != &lispdirectory[0]) p--;
  3609. if (*p != '/' && *p != '\\') p++;
  3610. *p = 0;
  3611. }
  3612. for (i=1; i<argc; i++)
  3613. {
  3614. // I have some VERY simple command-line options here.
  3615. // -z do a "cold start".
  3616. // -ifilename use that as image file
  3617. // -i filename ditto
  3618. // filename read from that file rather than from the standard input.
  3619. // -g force all diagnostics
  3620. if (strcmp(argv[i], "-z") == 0) coldstart = 1;
  3621. else if (strcmp(argv[i], "-g") == 0)
  3622. Lenable_errorset(nil, 2, lisptrue, lisptrue);
  3623. else if (strcmp(argv[i], "-i") == 0 && i<argc-1)
  3624. { strcpy(imagename, argv[i+1]);
  3625. i++;
  3626. }
  3627. else if (strncmp(argv[i], "-i", 2) == 0) strcpy(imagename, argv[i]+2);
  3628. else if (argv[i][0] != '-') inputfilename = argv[i], interactive = 0;
  3629. }
  3630. printf("VSL version %d.%.3d\n", VERSION/1000, VERSION%1000); fflush(stdout);
  3631. linepos = 0;
  3632. for (i=0; i<MAX_LISPFILES; i++) lispfiles[i] = 0;
  3633. lispfiles[0] = stdin; lispfiles[1] = stdout;
  3634. lispfiles[2] = stderr; lispfiles[3] = stdin;
  3635. file_direction = (1<<1) | (1<<2); // 1 bits for writable files.
  3636. lispin = 3; lispout = 1;
  3637. if (inputfilename != NULL)
  3638. { FILE *in = fopen(inputfilename, "r");
  3639. if (in == NULL)
  3640. printf("Unable to read from %s, so using standard input\n",
  3641. inputfilename);
  3642. else lispfiles[3] = in;
  3643. }
  3644. boffop = 0;
  3645. for (;;) // This loop is for restart-lisp and preserve.
  3646. { allocateheap(pool);
  3647. // A warm start will read an image file which it expects to have been
  3648. // made by a previous use of vsl.
  3649. if (coldstart) cold_start();
  3650. else warm_start();
  3651. // Any predefined specified on the command-line using -Dxx=yy are
  3652. // instated or re-instated here so they apply even after restart!-lisp.
  3653. for (i=1; i<argc; i++)
  3654. { if (argv[i][0] == '-' && argv[i][1] == 'D')
  3655. { const char *d1 = strchr(argv[i], '=');
  3656. if (d1 == NULL) continue;
  3657. // In general through setup (and I count this as still being setup)
  3658. // I will code on the basis that there will not be any garbage collection
  3659. // so I do not need to think about the effects of data movement during GC.
  3660. qvalue(lookup(argv[i]+2, (d1-argv[i])-2, 1)) =
  3661. makestring(d1+1, strlen(d1+1));
  3662. }
  3663. }
  3664. fflush(stdout);
  3665. curchar = '\n'; symtype = '?'; cursym = nil;
  3666. if (boffop == 0) // Use standard restart function from image.
  3667. { if (restartfn == nil) readevalprint(0);
  3668. else Lapply(nil, 2, restartfn, nil);
  3669. }
  3670. else
  3671. { LispObject x, data = makestring(boffo, boffop);
  3672. data = Lcompress(nil, 1, Lexplodec(nil, 1, data));
  3673. x = qcar(data); // 'fn or '(module fn)
  3674. if (x != nil)
  3675. { if (x == lisptrue) x = restartfn;
  3676. else if (isCONS(x) && isCONS(qcdr(x)))
  3677. { push2(data, qcar(qcdr(x)));
  3678. Lload_module(nil, 1, qcar(x));
  3679. pop2(x, data);
  3680. }
  3681. Lapply(nil, 2, x, qcdr(data));
  3682. }
  3683. }
  3684. if ((unwindflag & unwindPRESERVE) != 0)
  3685. { gzFile f = gzopen(imagename, "wbT");
  3686. if (f == NULL)
  3687. printf("\n+++ Unable to open %s for writing\n", imagename);
  3688. else
  3689. { reclaim(); // To compact memory.
  3690. headerword = FILEID;
  3691. saveinterp = (LispObject)(void *)interpret;
  3692. saveinterpspec = (LispObject)(void *)interpretspecform;
  3693. gzwrite(f, nonbases, (unsigned int)sizeof(nonbases));
  3694. gzwrite(f, bases, (unsigned int)sizeof(bases));
  3695. gzwrite(f, obhash, (unsigned int)sizeof(obhash));
  3696. gzwrite(f, (void *)heap1base, (unsigned int)(fringe1-heap1base));
  3697. gzwrite(f, (void *)fpfringe1, (unsigned int)(heap1top-fpfringe1));
  3698. }
  3699. gzclose(f);
  3700. // A cautious person would have checked for error codes returned by the
  3701. // above calls to write and close. I omit that here to be concise.
  3702. }
  3703. if ((unwindflag & unwindRESTART) == 0) break;
  3704. unwindflag = unwindNONE;
  3705. boffop = 0;
  3706. if (qcar(work1) == nil) coldstart = 1;
  3707. else if (qcar(work1) == lisptrue) coldstart = 0;
  3708. else
  3709. { int save = lispout;
  3710. lispout = -2;
  3711. internalprint(work1);
  3712. wrch(0);
  3713. lispout = save;
  3714. coldstart = 0;
  3715. }
  3716. }
  3717. return 0;
  3718. }
  3719. // end of main source file.