vsl.c 119 KB

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