compiler.red 193 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383
  1. %
  2. % Compiler from Lisp into byte-codes for use with CSL.
  3. % Copyright (C) Codemist Ltd, 1990-1996
  4. %
  5. % Pretty-well all internal functions defined here and all fluid and
  6. % global variables have been written with names of the form s!:xxx. This
  7. % might keep them away from most users. In Common Lisp I may want to put
  8. % them all in a package called "s".
  9. global '(s!:opcodelist);
  10. % The following list of opcodes must be kept in step with the corresponding
  11. % C header file "bytes.h" in the CSL kernel code, and the source file
  12. % "opnames.c".
  13. in "$cslbase/opcodes.red"$
  14. begin
  15. scalar n;
  16. n := 0;
  17. for each v in s!:opcodelist do <<
  18. put(v, 's!:opcode, n);
  19. n := n + 1 >>;
  20. return list(n, 'opcodes, 'allocated)
  21. end;
  22. s!:opcodelist := nil;
  23. symbolic procedure s!:vecof l;
  24. begin
  25. scalar v, n;
  26. v := mkvect sub1 length l;
  27. n := 0;
  28. for each x in l do <<
  29. putv(v, n, x);
  30. n := n+1 >>;
  31. return v
  32. end;
  33. << put('batchp, 's!:builtin0, 0);
  34. put('date, 's!:builtin0, 1);
  35. put('eject, 's!:builtin0, 2);
  36. put('error1, 's!:builtin0, 3);
  37. put('gctime, 's!:builtin0, 4);
  38. % put('gensym, 's!:builtin0, 5);
  39. put('lposn, 's!:builtin0, 6);
  40. % put('next!-random, 's!:builtin0, 7);
  41. put('posn, 's!:builtin0, 8);
  42. put('read, 's!:builtin0, 9);
  43. !#endif
  44. put('readch, 's!:builtin0, 10);
  45. put('terpri, 's!:builtin0, 11);
  46. !#if (not common!-lisp!-mode)
  47. put('time, 's!:builtin0, 12);
  48. !#endif
  49. put('tyi, 's!:builtin0, 13);
  50. % load!-spid is not for use by an ordinary programmer - it is used in the
  51. % compilation of unwind!-protect.
  52. put('load!-spid, 's!:builtin0, 14);
  53. put('abs, 's!:builtin1, 0);
  54. put('add1, 's!:builtin1, 1);
  55. !#if common!-lisp!-mode
  56. put('!1!+, 's!:builtin1, 1);
  57. !#endif
  58. !#if (not common!-lisp!-mode)
  59. put('atan, 's!:builtin1, 2);
  60. !#endif
  61. put('apply0, 's!:builtin1, 3);
  62. put('atom, 's!:builtin1, 4);
  63. put('boundp, 's!:builtin1, 5);
  64. put('char!-code, 's!:builtin1, 6);
  65. put('close, 's!:builtin1, 7);
  66. put('codep, 's!:builtin1, 8);
  67. !#if (not common!-lisp!-mode)
  68. put('compress, 's!:builtin1, 9);
  69. !#endif
  70. put('constantp, 's!:builtin1, 10);
  71. put('digit, 's!:builtin1, 11);
  72. put('endp, 's!:builtin1, 12);
  73. put('eval, 's!:builtin1, 13);
  74. put('evenp, 's!:builtin1, 14);
  75. put('evlis, 's!:builtin1, 15);
  76. put('explode, 's!:builtin1, 16);
  77. put('explode2lc, 's!:builtin1, 17);
  78. put('explode2, 's!:builtin1, 18);
  79. put('explodec, 's!:builtin1, 18);
  80. put('fixp, 's!:builtin1, 19);
  81. !#if (not common!-lisp!-mode)
  82. put('float, 's!:builtin1, 20);
  83. !#endif
  84. put('floatp, 's!:builtin1, 21);
  85. put('symbol!-specialp, 's!:builtin1, 22);
  86. put('gc, 's!:builtin1, 23);
  87. put('gensym1, 's!:builtin1, 24);
  88. put('getenv, 's!:builtin1, 25);
  89. put('symbol!-globalp, 's!:builtin1, 26);
  90. put('iadd1, 's!:builtin1, 27);
  91. put('symbolp, 's!:builtin1, 28);
  92. put('iminus, 's!:builtin1, 29);
  93. put('iminusp, 's!:builtin1, 30);
  94. put('indirect, 's!:builtin1, 31);
  95. put('integerp, 's!:builtin1, 32);
  96. !#if (not common!-lisp!-mode)
  97. put('intern, 's!:builtin1, 33);
  98. !#endif
  99. put('isub1, 's!:builtin1, 34);
  100. put('length, 's!:builtin1, 35);
  101. put('lengthc, 's!:builtin1, 36);
  102. put('linelength, 's!:builtin1, 37);
  103. put('liter, 's!:builtin1, 38);
  104. put('load!-module, 's!:builtin1, 39);
  105. put('lognot, 's!:builtin1, 40);
  106. !#if (not common!-lisp!-mode)
  107. put('macroexpand, 's!:builtin1, 41);
  108. put('macroexpand!-1, 's!:builtin1, 42);
  109. !#endif
  110. put('macro!-function, 's!:builtin1, 43);
  111. put('make!-bps, 's!:builtin1, 44);
  112. put('make!-global, 's!:builtin1, 45);
  113. put('make!-simple!-string, 's!:builtin1, 46);
  114. put('make!-special, 's!:builtin1, 47);
  115. put('minus, 's!:builtin1, 48);
  116. put('minusp, 's!:builtin1, 49);
  117. put('mkvect, 's!:builtin1, 50);
  118. put('modular!-minus, 's!:builtin1, 51);
  119. put('modular!-number, 's!:builtin1, 52);
  120. put('modular!-reciprocal, 's!:builtin1, 53);
  121. put('null, 's!:builtin1, 54);
  122. put('oddp, 's!:builtin1, 55);
  123. put('onep, 's!:builtin1, 56);
  124. put('pagelength, 's!:builtin1, 57);
  125. put('pairp, 's!:builtin1, 58);
  126. put('plist, 's!:builtin1, 59);
  127. put('plusp, 's!:builtin1, 60);
  128. !#if (not common!-lisp!-mode)
  129. put('prin, 's!:builtin1, 61);
  130. put('princ, 's!:builtin1, 62);
  131. put('print, 's!:builtin1, 63);
  132. put('printc, 's!:builtin1, 64);
  133. !#endif
  134. % put('random, 's!:builtin1, 65);
  135. put('rational, 's!:builtin1, 66);
  136. % put('load, 's!:builtin1, 67);
  137. put('rds, 's!:builtin1, 68);
  138. put('remd, 's!:builtin1, 69);
  139. !#if (not common!-lisp!-mode)
  140. put('reverse, 's!:builtin1, 70);
  141. !#endif
  142. put('reversip, 's!:builtin1, 71);
  143. put('seprp, 's!:builtin1, 72);
  144. put('set!-small!-modulus, 's!:builtin1, 73);
  145. put('spaces, 's!:builtin1, 74);
  146. put('xtab, 's!:builtin1, 74); % = spaces?
  147. put('special!-char, 's!:builtin1, 75);
  148. put('special!-form!-p, 's!:builtin1, 76);
  149. put('spool, 's!:builtin1, 77);
  150. put('stop, 's!:builtin1, 78);
  151. !#if (not common!-lisp!-mode)
  152. put('stringp, 's!:builtin1, 79);
  153. !#endif
  154. put('sub1, 's!:builtin1, 80);
  155. !#if common!-lisp!-mode
  156. put('!1!-, 's!:builtin1, 80);
  157. !#endif
  158. put('symbol!-env, 's!:builtin1, 81);
  159. put('symbol!-function, 's!:builtin1, 82);
  160. put('symbol!-name, 's!:builtin1, 83);
  161. put('symbol!-value, 's!:builtin1, 84);
  162. put('system, 's!:builtin1, 85);
  163. !#if (not common!-lisp!-mode)
  164. put('fix, 's!:builtin1, 86);
  165. !#endif
  166. put('ttab, 's!:builtin1, 87);
  167. put('tyo, 's!:builtin1, 88);
  168. !#if (not common!-lisp!-mode)
  169. put('remob, 's!:builtin1, 89);
  170. !#endif
  171. put('unmake!-global, 's!:builtin1, 90);
  172. put('unmake!-special, 's!:builtin1, 91);
  173. put('upbv, 's!:builtin1, 92);
  174. !#if (not common!-lisp!-mode)
  175. put('vectorp, 's!:builtin1, 93);
  176. !#else
  177. put('simple!-vectorp, 's!:builtin1, 93);
  178. !#endif
  179. put('verbos, 's!:builtin1, 94);
  180. put('wrs, 's!:builtin1, 95);
  181. put('zerop, 's!:builtin1, 96);
  182. % car, cdr etc will pretty-well always turn into single byte operations
  183. % rather than the builtin calls listed here. So the next few lines are
  184. % probably redundant.
  185. put('car, 's!:builtin1, 97);
  186. put('cdr, 's!:builtin1, 98);
  187. put('caar, 's!:builtin1, 99);
  188. put('cadr, 's!:builtin1, 100);
  189. put('cdar, 's!:builtin1, 101);
  190. put('cddr, 's!:builtin1, 102);
  191. put('qcar, 's!:builtin1, 103);
  192. put('qcdr, 's!:builtin1, 104);
  193. put('qcaar, 's!:builtin1, 105);
  194. put('qcadr, 's!:builtin1, 106);
  195. put('qcdar, 's!:builtin1, 107);
  196. put('qcddr, 's!:builtin1, 108);
  197. put('ncons, 's!:builtin1, 109);
  198. put('numberp, 's!:builtin1, 110);
  199. % is!-spid and spid!-to!-nil are NOT for direct use by ordinary programmers.
  200. % They are part of the support for &optional arguments.
  201. put('is!-spid, 's!:builtin1, 111);
  202. put('spid!-to!-nil, 's!:builtin1, 112);
  203. !#if common!-lisp!-mode
  204. put('mv!-list!*, 's!:builtin1, 113);
  205. !#endif
  206. put('append, 's!:builtin2, 0);
  207. put('ash, 's!:builtin2, 1);
  208. !#if (not common!-lisp!-mode)
  209. put('assoc, 's!:builtin2, 2);
  210. !#endif
  211. put('assoc!*!*, 's!:builtin2, 2);
  212. put('atsoc, 's!:builtin2, 3);
  213. put('deleq, 's!:builtin2, 4);
  214. !#if (not common!-lisp!-mode)
  215. put('delete, 's!:builtin2, 5);
  216. put('divide, 's!:builtin2, 6);
  217. !#endif
  218. put('eqcar, 's!:builtin2, 7);
  219. put('eql, 's!:builtin2, 8);
  220. !#if (not common!-lisp!-mode)
  221. put('eqn, 's!:builtin2, 9);
  222. !#endif
  223. put('expt, 's!:builtin2, 10);
  224. put('flag, 's!:builtin2, 11);
  225. put('flagpcar, 's!:builtin2, 12);
  226. !#if (not common!-lisp!-mode)
  227. put('gcdn, 's!:builtin2, 13);
  228. !#endif
  229. put('geq, 's!:builtin2, 14);
  230. put('getv, 's!:builtin2, 15);
  231. put('greaterp, 's!:builtin2, 16);
  232. put('idifference, 's!:builtin2, 17);
  233. put('igreaterp, 's!:builtin2, 18);
  234. put('ilessp, 's!:builtin2, 19);
  235. put('imax, 's!:builtin2, 20);
  236. put('imin, 's!:builtin2, 21);
  237. put('iplus2, 's!:builtin2, 22);
  238. put('iquotient, 's!:builtin2, 23);
  239. put('iremainder, 's!:builtin2, 24);
  240. put('irightshift, 's!:builtin2, 25);
  241. put('itimes2, 's!:builtin2, 26);
  242. !#if (not common!-lisp!-mode)
  243. % put('lcm, 's!:builtin2, 27);
  244. !#endif
  245. put('leq, 's!:builtin2, 28);
  246. put('lessp, 's!:builtin2, 29);
  247. % put('make!-random!-state, 's!:builtin2, 30);
  248. put('max2, 's!:builtin2, 31);
  249. !#if (not common!-lisp!-mode)
  250. put('member, 's!:builtin2, 32);
  251. !#endif
  252. put('member!*!*, 's!:builtin2, 32);
  253. put('memq, 's!:builtin2, 33);
  254. put('min2, 's!:builtin2, 34);
  255. put('mod, 's!:builtin2, 35);
  256. put('modular!-difference, 's!:builtin2, 36);
  257. put('modular!-expt, 's!:builtin2, 37);
  258. put('modular!-plus, 's!:builtin2, 38);
  259. put('modular!-quotient, 's!:builtin2, 39);
  260. put('modular!-times, 's!:builtin2, 40);
  261. put('nconc, 's!:builtin2, 41);
  262. put('neq, 's!:builtin2, 42);
  263. put('orderp, 's!:builtin2, 43);
  264. % put('ordp, 's!:builtin2, 43); % alternative name
  265. !#if (not common!-lisp!-mode)
  266. put('quotient, 's!:builtin2, 44);
  267. !#endif
  268. put('remainder, 's!:builtin2, 45);
  269. put('remflag, 's!:builtin2, 46);
  270. put('remprop, 's!:builtin2, 47);
  271. put('rplaca, 's!:builtin2, 48);
  272. put('rplacd, 's!:builtin2, 49);
  273. put('schar, 's!:builtin2, 50);
  274. put('set, 's!:builtin2, 51);
  275. put('smemq, 's!:builtin2, 52);
  276. put('subla, 's!:builtin2, 53);
  277. put('sublis, 's!:builtin2, 54);
  278. put('symbol!-set!-definition, 's!:builtin2, 55);
  279. put('symbol!-set!-env, 's!:builtin2, 56);
  280. put('times2, 's!:builtin2, 57);
  281. put('xcons, 's!:builtin2, 58);
  282. put('equal, 's!:builtin2, 59);
  283. put('eq, 's!:builtin2, 60);
  284. put('cons, 's!:builtin2, 61);
  285. put('list2, 's!:builtin2, 62);
  286. !#if (not common!-lisp!-mode)
  287. put('get, 's!:builtin2, 63);
  288. !#endif
  289. put('qgetv, 's!:builtin2, 64);
  290. put('flagp, 's!:builtin2, 65);
  291. put('apply1, 's!:builtin2, 66);
  292. put('difference, 's!:builtin2, 67);
  293. put('plus2, 's!:builtin2, 68);
  294. put('times2, 's!:builtin2, 69);
  295. put('equalcar, 's!:builtin2, 70);
  296. put('iequal, 's!:builtin2, 71);
  297. put('bps!-putv, 's!:builtin3, 0);
  298. put('errorset, 's!:builtin3, 1);
  299. put('list2!*, 's!:builtin3, 2);
  300. put('list3, 's!:builtin3, 3);
  301. put('putprop, 's!:builtin3, 4);
  302. put('putv, 's!:builtin3, 5);
  303. put('putv!-char, 's!:builtin3, 6);
  304. put('subst, 's!:builtin3, 7);
  305. put('apply2, 's!:builtin3, 8);
  306. put('acons, 's!:builtin3, 9);
  307. nil >>;
  308. % Hex printing, for use when displaying assembly code
  309. symbolic procedure s!:prinhex1 n;
  310. princ schar("0123456789abcdef", logand(n, 15));
  311. symbolic procedure s!:prinhex2 n;
  312. << s!:prinhex1 truncate(n, 16);
  313. s!:prinhex1 n >>;
  314. symbolic procedure s!:prinhex4 n;
  315. << s!:prinhex2 truncate(n, 256);
  316. s!:prinhex2 n >>;
  317. %
  318. % The rather elaborate scheme here is to allow for the possibility that the
  319. % horrid user may have defined one of these variables before loading in
  320. % the compiler - I do not want to clobber the user's settings.
  321. %
  322. flag('(comp plap pgwd pwrds notailcall ord nocompile
  323. carcheckflag savedef carefuleq), 'switch); % for RLISP
  324. if not boundp '!*comp then << % compile automatically on "de"
  325. fluid '(!*comp);
  326. !*comp := t >>;
  327. if not boundp '!*nocompile then << % do not compile when fasling
  328. fluid '(!*nocompile);
  329. !*nocompile := nil >>;
  330. if not boundp '!*plap then << % print generated bytecodes
  331. fluid '(!*plap);
  332. !*plap := nil >>;
  333. if not boundp '!*pgwd then << % equivalent to *plap here
  334. fluid '(!*pgwd);
  335. !*pgwd := nil >>;
  336. if not boundp '!*pwrds then << % display size of generated code
  337. fluid '(!*pwrds);
  338. !*pwrds := t >>;
  339. if not boundp '!*notailcall then << % disable an optimisation
  340. fluid '(!*notailcall);
  341. !*notailcall := nil >>;
  342. if not boundp '!*ord then << % disable an optimisation
  343. fluid '(!*ord);
  344. !*ord := nil >>;
  345. if not boundp '!*savedef then << % keep interpretable definition on p-list
  346. fluid '(!*savedef);
  347. !*savedef := nil >>;
  348. if not boundp '!*carcheckflag then << % safety/speed control
  349. fluid '(!*carcheckflag);
  350. !*carcheckflag := t >>;
  351. if not boundp '!*carefuleq then << % force EQ to be function call
  352. fluid '(!*carefuleq); % to permit checking of (EQ number number)
  353. !*carefuleq := not null member('jlisp, lispsystem!*) >>;
  354. fluid '(s!:current_function s!:current_label s!:current_block s!:current_size
  355. s!:current_procedure s!:other_defs s!:lexical_env s!:has_closure
  356. s!:recent_literals s!:used_lexicals s!:a_reg_values s!:current_count);
  357. %
  358. % s!:current_procedure is a list of basic blocks, with the entry-point
  359. % implicit at the first block (that is to say at the END of the list
  360. % while I am building it).. Each block is represented as a list
  361. % (label exit-condn size . byte-list)
  362. % where the exit-condn can (at various stages during compilation) be
  363. % nil drop through
  364. % (exit) one-byte exit opcodes
  365. % (jump <label>) unconditional jump
  366. % (jumpcond <L1> <L2>) two exits from this block
  367. % ((jumparg ...) <L1> <L2>) two exits, extra data
  368. % (icase <L0> <L1> ... <Ln>) multi-way branch
  369. % furthermore <label> can be either an atom (for a regular label)
  370. % or a list of the form (exit) for an exit condition.
  371. %
  372. % The byte-list is a list of atoms (for genuine bytes in the code
  373. % stream) interleaved with lists that denote comments that appear in
  374. % any assembly listing.
  375. symbolic procedure s!:start_procedure(nargs, nopts, restarg);
  376. << s!:current_procedure := nil;
  377. s!:current_label := gensym();
  378. s!:a_reg_values := nil;
  379. if not zerop nopts or restarg then <<
  380. s!:current_block := list(list('OPTARGS, nopts), nopts,
  381. list('ARGCOUNT, nargs), nargs);
  382. s!:current_size := 2 >>
  383. else if nargs > 3 then <<
  384. s!:current_block := list(list('ARGCOUNT, nargs), nargs);
  385. s!:current_size := 1 >>
  386. else <<
  387. s!:current_block := nil;
  388. s!:current_size := 0 >>
  389. >>;
  390. symbolic procedure s!:set_label x;
  391. << if s!:current_label then begin scalar w;
  392. w := s!:current_size . s!:current_block;
  393. for each x in s!:recent_literals do rplaca(x, w);
  394. s!:recent_literals := nil;
  395. s!:current_procedure :=
  396. (s!:current_label . list('JUMP, x) . w) . s!:current_procedure;
  397. s!:current_block := nil;
  398. s!:current_size := 0 end;
  399. s!:current_label := x;
  400. s!:a_reg_values := nil
  401. >>;
  402. symbolic procedure s!:outjump(op, lab);
  403. begin
  404. scalar g, w;
  405. if not flagp(op, 's!:preserves_a) then s!:a_reg_values := nil;
  406. if null s!:current_label then return nil;
  407. % unconditional jumps set s!:current_label to nil, which denotes
  408. % a state where control can not reach.
  409. if op = 'JUMP then op := list(op, lab)
  410. else if op = 'ICASE then op := op . lab
  411. else op := list(op, lab, g := gensym());
  412. w := s!:current_size . s!:current_block;
  413. for each x in s!:recent_literals do rplaca(x, w);
  414. s!:recent_literals := nil;
  415. s!:current_procedure :=
  416. (s!:current_label . op . w) . s!:current_procedure;
  417. s!:current_block := nil;
  418. s!:current_size := 0;
  419. s!:current_label := g;
  420. return op
  421. end;
  422. symbolic procedure s!:outexit();
  423. begin
  424. scalar w, op;
  425. op := '(EXIT);
  426. if null s!:current_label then return nil;
  427. w := s!:current_size . s!:current_block;
  428. for each x in s!:recent_literals do rplaca(x, w);
  429. s!:recent_literals := nil;
  430. s!:current_procedure :=
  431. (s!:current_label . op . w) . s!:current_procedure;
  432. s!:current_block := nil;
  433. s!:current_size := 0;
  434. s!:current_label := nil
  435. end;
  436. flag('(PUSH PUSHNIL PUSHNIL2 PUSHNIL3 LOSE LOSE2 LOSE3 LOSES
  437. STORELOC STORELOC0 STORELOC1 STORELOC2 STORELOC3
  438. STORELOC4 STORELOC5 STORELOC6 STORELOC7
  439. JUMP JUMPT JUMPNIL
  440. JUMPEQ JUMPEQUAL JUMPNE JUMPNEQUAL
  441. JUMPATOM JUMPNATOM),
  442. 's!:preserves_a);
  443. symbolic procedure s!:outopcode0(op, doc);
  444. begin
  445. if not flagp(op, 's!:preserves_a) then s!:a_reg_values := nil;
  446. if null s!:current_label then return nil;
  447. s!:current_block := op . s!:current_block;
  448. s!:current_size := s!:current_size + 1;
  449. if !*plap or !*pgwd then s!:current_block := doc . s!:current_block;
  450. end;
  451. symbolic procedure s!:outopcode1(op, arg, doc);
  452. % doc is just a single item here.
  453. begin
  454. if not flagp(op, 's!:preserves_a) then s!:a_reg_values := nil;
  455. if null s!:current_label then return nil;
  456. s!:current_block := arg . op . s!:current_block;
  457. s!:current_size := s!:current_size + 2;
  458. if !*plap or !*pgwd then s!:current_block := list(op, doc) . s!:current_block
  459. end;
  460. % Whenever compiled code needs to refer to any Lisp object it does so
  461. % via a literal table - this procedure manages the table. I common up
  462. % literals if they are EQL. In the table that I build here I associate
  463. % each literal with a pair (n . l) where n is the number of times the
  464. % literal is referenced (or some other measure of its importance) and l is
  465. % a list of all the places in the codestream where it is referenced.
  466. deflist(
  467. '((LOADLIT 1)
  468. (LOADFREE 2)
  469. (CALL0 2)
  470. (CALL1 2)
  471. (LITGET 2)
  472. (JUMPLITEQ 2)
  473. (JUMPLITNE 2)
  474. (JUMPLITEQ!* 2)
  475. (JUMPLITNE!* 2)
  476. (JUMPFREET 2)
  477. (JUMPFREENIL 2)),
  478. 's!:short_form_bonus);
  479. % s!:record_literal is called when a literal reference has just been
  480. % pushed onto s!:current_block. It inserts a reference to the literal
  481. % into a hash table so that it can be resolved into an offset into a literal
  482. % vector later on.
  483. symbolic procedure s!:record_literal env;
  484. begin
  485. scalar w, extra;
  486. w := gethash(car s!:current_block, car env);
  487. if null w then w := 0 . nil;
  488. extra := get(cadr s!:current_block, 's!:short_form_bonus);
  489. if null extra then extra := 10 else extra := extra + 10;
  490. s!:recent_literals := (nil . s!:current_block) . s!:recent_literals;
  491. puthash(car s!:current_block, car env,
  492. (car w+extra) . car s!:recent_literals . cdr w);
  493. end;
  494. % record_literal_for_jump is used with x of the form (eg)
  495. % (JUMPLITEQ literal-value <comment>)
  496. % where this list will be used in a jump instruction.
  497. symbolic procedure s!:record_literal_for_jump(x, env, lab);
  498. begin
  499. scalar w, extra;
  500. if null s!:current_label then return nil;
  501. w := gethash(cadr x, car env);
  502. if null w then w := 0 . nil;
  503. extra := get(car x, 's!:short_form_bonus);
  504. if null extra then extra := 10 else extra := extra + 10;
  505. x := s!:outjump(x, lab);
  506. puthash(cadar x, car env, (car w+extra) . (nil . x) . cdr w)
  507. end;
  508. symbolic procedure s!:outopcode1lit(op, arg, env);
  509. begin
  510. if not flagp(op, 's!:preserves_a) then s!:a_reg_values := nil;
  511. if null s!:current_label then return nil;
  512. s!:current_block := arg . op . s!:current_block;
  513. s!:record_literal env;
  514. s!:current_size := s!:current_size + 2;
  515. if !*plap or !*pgwd then s!:current_block := list(op, arg) . s!:current_block
  516. end;
  517. symbolic procedure s!:outopcode2(op, arg1, arg2, doc);
  518. % This is only used for BIGSTACK
  519. begin
  520. if not flagp(op, 's!:preserves_a) then s!:a_reg_values := nil;
  521. if null s!:current_label then return nil;
  522. s!:current_block := arg2 . arg1 . op . s!:current_block;
  523. s!:current_size := s!:current_size + 3;
  524. if !*plap or !*pgwd then s!:current_block := (op . doc) . s!:current_block
  525. end;
  526. symbolic procedure s!:outopcode2lit(op, arg1, arg2, doc, env);
  527. % This is only used for CALLN
  528. begin
  529. if not flagp(op, 's!:preserves_a) then s!:a_reg_values := nil;
  530. if null s!:current_label then return nil;
  531. s!:current_block := arg1 . op . s!:current_block;
  532. s!:record_literal env;
  533. s!:current_block := arg2 . s!:current_block;
  534. s!:current_size := s!:current_size + 3;
  535. if !*plap or !*pgwd then s!:current_block := (op . doc) . s!:current_block
  536. end;
  537. symbolic procedure s!:outlexref(op, arg1, arg2, arg3, doc);
  538. % Only used for LOADLEX and STORELEX
  539. begin
  540. scalar arg4;
  541. if null s!:current_label then return nil;
  542. if arg1 > 255 or arg2 > 255 or arg3 > 255 then <<
  543. if arg1 > 2047 or arg2 > 31 or arg3 > 2047 then
  544. error "stack frame > 2047 or > 31 deep nesting";
  545. doc := list(op, doc);
  546. arg4 := logand(arg3, 255);
  547. arg3 := truncate(arg3,256) + 16*logand(arg1, 15);
  548. if op = 'LOADLEX then op := 192 + arg2
  549. else op := 224 + arg2;
  550. arg2 := truncate(arg1,16);
  551. arg1 := op;
  552. op := 'BIGSTACK >>
  553. else doc := list doc;
  554. s!:current_block := arg3 . arg2 . arg1 . op . s!:current_block;
  555. s!:current_size := s!:current_size + 4;
  556. if arg4 then <<
  557. s!:current_block := arg4 . s!:current_block;
  558. s!:current_size := s!:current_size + 1 >>;
  559. if !*plap or !*pgwd then s!:current_block := (op . doc) . s!:current_block
  560. end;
  561. % Some opcodes that take a byte offset following them have special forms
  562. % that cope with a few very small values of that offset. Here are tables
  563. % that document what is available, and code that optimises the general case
  564. % into the special opcodes when it can.
  565. put('LOADLIT, 's!:shortform, '(1 . 7) .
  566. s!:vecof '(!- LOADLIT1 LOADLIT2 LOADLIT3 LOADLIT4
  567. LOADLIT5 LOADLIT6 LOADLIT7));
  568. put('LOADFREE, 's!:shortform, '(1 . 4) .
  569. s!:vecof '(!- LOADFREE1 LOADFREE2 LOADFREE3 LOADFREE4));
  570. put('STOREFREE, 's!:shortform, '(1 . 3) .
  571. s!:vecof '(!- STOREFREE1 STOREFREE2 STOREFREE3));
  572. put('CALL0, 's!:shortform, '(0 . 3) .
  573. s!:vecof '(CALL0_0 CALL0_1 CALL0_2 CALL0_3));
  574. put('CALL1, 's!:shortform, '(0 . 5) .
  575. s!:vecof '(CALL1_0 CALL1_1 CALL1_2 CALL1_3 CALL1_4 CALL1_5));
  576. put('CALL2, 's!:shortform, '(0 . 4) .
  577. s!:vecof '(CALL2_0 CALL2_1 CALL2_2 CALL2_3 CALL2_4));
  578. put('JUMPFREET, 's!:shortform, '(1 . 4) .
  579. s!:vecof '(!- JUMPFREE1T JUMPFREE2T JUMPFREE3T JUMPFREE4T));
  580. put('JUMPFREENIL, 's!:shortform, '(1 . 4) .
  581. s!:vecof '(!- JUMPFREE1NIL JUMPFREE2NIL JUMPFREE3NIL JUMPFREE4NIL));
  582. put('JUMPLITEQ , 's!:shortform, '(1 . 4) .
  583. s!:vecof '(!- JUMPLIT1EQ JUMPLIT2EQ JUMPLIT3EQ JUMPLIT4EQ));
  584. put('JUMPLITNE , 's!:shortform, '(1 . 4) .
  585. s!:vecof '(!- JUMPLIT1NE JUMPLIT2NE JUMPLIT3NE JUMPLIT4NE));
  586. put('JUMPLITEQ!*, 's!:shortform, get('JUMPLITEQ, 's!:shortform));
  587. put('JUMPLITNE!*, 's!:shortform, get('JUMPLITNE, 's!:shortform));
  588. % These are sub opcodes used with BIGCALL
  589. % The format used with the opcode is as follows:
  590. % BIGCALL (op:4/high:4) (low:8) ?(nargs:8)
  591. % so the upper four bits of the byte after the BIGCALL opcode select what
  592. % operation is actually performed (from the following list). There is a
  593. % 12-bit literal-vector offset with its 4 high bits packed into that byte
  594. % and the next 8 in the byte "low". Then just in the cases CALLN and JCALLN
  595. % a further byte indicates how many arguments are actually being passed.
  596. put('CALL0, 's!:longform, 0); % 0
  597. put('CALL1, 's!:longform, 16); % 1
  598. put('CALL2, 's!:longform, 32); % 2
  599. put('CALL3, 's!:longform, 48); % 3
  600. put('CALLN, 's!:longform, 64); % 4
  601. put('CALL2R, 's!:longform, 80); % 5 (no JCALL version)
  602. put('LOADFREE, 's!:longform, 96);
  603. put('STOREFREE, 's!:longform, 112);
  604. put('JCALL0, 's!:longform, 128);
  605. put('JCALL1, 's!:longform, 144);
  606. put('JCALL2, 's!:longform, 160);
  607. put('JCALL3, 's!:longform, 176);
  608. put('JCALLN, 's!:longform, 192);
  609. put('FREEBIND, 's!:longform, 208);
  610. put('LITGET, 's!:longform, 224);
  611. put('LOADLIT, 's!:longform, 240);
  612. symbolic procedure s!:literal_order(a, b);
  613. if cadr a = cadr b then orderp(car a, car b)
  614. else cadr a > cadr b;
  615. symbolic procedure s!:resolve_literals env;
  616. begin
  617. scalar w, op, opspec, n, litbytes;
  618. w := hashcontents car env;
  619. % I sort the literals used in this function so that the ones that are
  620. % used most often come first, and hence get allocated the smaller
  621. % offsets within the table. Here I need to do something magic if there
  622. % are over 256 literals since the regular opcodes only have that much
  623. % addressability.
  624. w := sort(w, function s!:literal_order);
  625. n := length w;
  626. litbytes := 4*n;
  627. if n > 4096 then w := s!:too_many_literals(w, n);
  628. n := 0;
  629. for each x in w do <<
  630. rplaca(cdr x, n); % Turn priorities into offsets
  631. n := n + 1 >>;
  632. for each x in w do <<
  633. n := cadr x;
  634. for each y in cddr x do <<
  635. if null car y then << % JUMP operation
  636. % If I have a jump that refers to a literal (eg JUMPEQCAR) then I am
  637. % entitled at this stage to leave a 12-bit value in the data structure,
  638. % because as necessary s!:expand_jump will unwind it later to fit in with
  639. % the bytecode restrictions.
  640. op := caadr y;
  641. opspec := get(op, 's!:shortform);
  642. if opspec and caar opspec <= n and n <= cdar opspec then
  643. rplaca(cdr y, getv(cdr opspec, n))
  644. else rplaca(cdadr y, n) >>
  645. else <<
  646. op := caddr y;
  647. if n > 255 then <<
  648. rplaca(car y, caar y + 1); % block is now longer
  649. op := get(op, 's!:longform) + truncate(n,256);
  650. rplaca(cdr y, ilogand(n, 255)); % low byte offset
  651. rplaca(cddr y, 'BIGCALL); % splice in byte and...
  652. rplacd(cdr y, op . cddr y) >> % make a BIGCALL
  653. else if (opspec := get(op, 's!:shortform)) and
  654. caar opspec <= n and
  655. n <= cdar opspec then << % short form available
  656. rplaca(car y, caar y - 1); % block is now shorter
  657. rplaca(cdr y, getv(cdr opspec, n)); % replace opcode
  658. rplacd(cdr y, cdddr y) >> % splice out a byte
  659. else rplaca(cdr y, n) >> >> >>; % OR just fill in offset
  660. for each x in w do rplacd(x, cadr x);
  661. rplaca(env, reversip w . litbytes)
  662. end;
  663. % s!:too_many_literals is called when there are over 4096 literals called for.
  664. % The simple bytecode instruction set can only cope with 256.
  665. % There are two ways I get around this. To consider these it is useful to
  666. % document the opcodes that reference literals:
  667. %
  668. % operations: CALL0, CALL1, CALL2, CALL2R, CALL3, CALLN,
  669. % LOADLIT, LOADFREE, STOREFREE, FREEBIND, LITGET
  670. % and jumps: JUMPLITEQ, JUMPLITNE, JUMPFREENIL, JUMPFREET,
  671. % JUMPEQCAR, JUMPNEQCAR, JUMPFLAGP, JUMPNFLAGP
  672. %
  673. % The jumps involved are all versions that can only support short
  674. % branch offsets, and which s!:expand_jump will elaborate into
  675. % code that uses LOADLIT or LOADFREE as necessary. Eg
  676. %
  677. % JUMPFREENIL var lab => LOADFREE var; JUMPNIL lab
  678. % JUMPEQCAR lit lab => LOADLIT lit; EQCAR; JUMPT lab
  679. %
  680. % Thus I do not have to worry too much about jumps if I can deal with the
  681. % other operations. The bytecode interpreter provides an operation
  682. % called BIGCALL that is followed by two bytes. The first contains a 4-bit
  683. % sub-opcode, while the remaining twelve bits provide for access within the
  684. % first 2048 literals for all the above operations and for the JCALL
  685. % operations corresponding to the CALL ones shown (except CALL2R which does
  686. % not have a coresponding JCALL version). So normally I can just map
  687. % references that need to address literals beyong the 256th onto these
  688. % extended opcodes.
  689. %
  690. % Just to be super-careful I will make at least some allowance for things
  691. % with over 2048 literals. In such cases I will identify excess literals
  692. % that are ONLY referenced using the LOADLIT operation (and that directly,
  693. % not via one of the JUMP combinations shown above). For a suitable number
  694. % of these I migrate the literal values into one or more secondary vectors
  695. % (called v<i> here). These secondary vectors will be stored in the main
  696. % literal vector, and I turn a reference
  697. % LOADLIT x
  698. % into LOADLIT v<i>
  699. % QGETVN n
  700. % for the offset n of the value x in the secondary vector v<i>. Note that
  701. % because v<i> will then probably be referenced very often it will stand
  702. % a good chance of ending up within the first 8 slots in the main
  703. % vector so "LOADLIT v<i>" will end turn into just one byte so the effect
  704. % is as if I have a three byte opcode to load a literal from the extended
  705. % pool. With luck in truly huge procedures there will be a significant
  706. % proportion of literals used in this way and the ones used in more general
  707. % ways will then end up fitting within the first 2048.
  708. %
  709. % In reality the nastiest case I have seen so far has had around 800 literals,
  710. % and that only because of some unduly clumsy compilation and (lack of)
  711. % macro expansion.
  712. symbolic procedure s!:only_loadlit l;
  713. if null l then t
  714. else if null caar l then nil
  715. else if not eqcar(cddar l, 'LOADLIT) then nil
  716. else s!:only_loadlit cdr l;
  717. symbolic procedure s!:too_many_literals(w, n);
  718. begin
  719. scalar k, xvecs, l, r, newrefs, uses, z1;
  720. k := 0; % Number of things in current overflow vector
  721. n := n + 1;
  722. % I must not move the function name down into a sub-vector since it is
  723. % essential (for debugging messages etc) that it ends up in position 0
  724. % in the final literal vector. Hence the test for 10000000 here.
  725. while n > 4096 and not null w do <<
  726. if not (cadar w = 10000000) and s!:only_loadlit cddar w then <<
  727. l := car w . l;
  728. n := n-1;
  729. k := k + 1;
  730. if k = 256 then <<
  731. xvecs := l . xvecs;
  732. l := nil;
  733. k := 0;
  734. n := n+1 >> >>
  735. else r := car w . r;
  736. w := cdr w >>;
  737. % Complain if migrating LOADLIT literals into sub-vectors does not bring me
  738. % down to 12-bit addressability.
  739. if n > 4096 then error "function uses too many literals (4096 is limit)";
  740. xvecs := l . xvecs;
  741. while r do <<
  742. w := car r . w;
  743. r := cdr r >>;
  744. for each v in xvecs do <<
  745. newrefs := nil;
  746. uses := 0;
  747. r := nil;
  748. k := 0;
  749. for each q in v do <<
  750. for each z in cddr q do <<
  751. % Now z is (hdrp . [litval LOADLIT ...]) and I need to rewrite it to
  752. % be +2 in the length and (offset . QGETVN . [<vector> LOADLIT ...])
  753. if car z then rplaca(car z, caar z + 2);
  754. z1 := 'QGETVN . nil . cddr z;
  755. rplaca(cdr z, k);
  756. rplacd(cdr z, z1);
  757. rplacd(z, cdr z1);
  758. newrefs := z . newrefs;
  759. uses := uses + 11 >>;
  760. r := car q . r;
  761. k := k + 1 >>;
  762. newrefs := uses . newrefs;
  763. newrefs := (s!:vecof reversip r) . newrefs;
  764. w := newrefs . w >>;
  765. return sort(w, function s!:literal_order)
  766. end;
  767. % The following variable is a hook that the Lisp to C compiler
  768. % might like to use.
  769. fluid '(s!:into_c);
  770. symbolic procedure s!:endprocedure(name, env);
  771. begin
  772. scalar pc, labelvals, w, vec;
  773. % First I finish off the final basic block by appending an EXIT operation
  774. s!:outexit();
  775. if s!:into_c then return (s!:current_procedure . env);
  776. % Literals have just been collected in an unordered pool so far - now I
  777. % should decide which ones go where in the literal vectors, and insert
  778. % optimised forms of opcodes that can rely on them.
  779. s!:resolve_literals env;
  780. % Tidy up blocks by re-ordering them so as to try to remove chains of
  781. % jumps and similar ugliness.
  782. s!:current_procedure := s!:tidy_flowgraph s!:current_procedure;
  783. % Look for possible tail calls AFTER resolving literals so that I know the
  784. % exact location in the literal vector of the names of the procedures
  785. % chained to. This means that there can be BIGCALL operations present
  786. % as well as regular CALL opcodes. It also means that come calls that
  787. % address the first few items in the literal vector will have been collapsed
  788. % onto one-byte opcodes.
  789. if not !*notailcall and not s!:has_closure then
  790. s!:current_procedure := s!:try_tailcall s!:current_procedure;
  791. % In all cases I can now turn things like (NIL;EXIT) and (LOADLOC 1;EXIT)
  792. % into single-byte instructions, and discard the LOSE from (LOSE;EXIT).
  793. s!:current_procedure := s!:tidy_exits s!:current_procedure;
  794. % JUMP instructions are span-dependent, so I need to iterate to
  795. % cope with that as well as with forward references.
  796. labelvals := s!:resolve_labels();
  797. pc := car labelvals; labelvals := cdr labelvals;
  798. % Allocate space for the compiled code - this is done in
  799. % a separate heap. Maybe soon I will put environment vectors
  800. % in that heap too. The code heap is not subject to garbage
  801. % colection (at present).
  802. vec := make!-bps pc;
  803. pc := 0;
  804. if !*plap or !*pgwd then <<
  805. terpri(); ttab 23; princ "+++ "; prin name; princ " +++"; terpri() >>;
  806. % The final pass assembles all the basic blocks and prints a
  807. % listing (if desired)
  808. for each b in s!:current_procedure do <<
  809. if car b and flagp(car b, 'used_label) and (!*plap or !*pgwd) then <<
  810. ttab 20;
  811. prin car b;
  812. princ ":";
  813. terpri() >>;
  814. pc := s!:plant_basic_block(vec, pc, reverse cdddr b);
  815. b := cadr b; % documentation
  816. if b and
  817. not car b = 'ICASE and
  818. cdr b and
  819. cddr b then b := list(car b, cadr b); % Trim unwanted second label
  820. pc := s!:plant_exit_code(vec, pc, b, labelvals) >>;
  821. % At the end of a procedure I may display a message to record the fact
  822. % that I have compiled it and to show how many bytes were generated
  823. if !*pwrds then <<
  824. if posn() neq 0 then terpri();
  825. princ "+++ "; prin name; princ " compiled, ";
  826. princ pc; princ " + "; princ (cdar env);
  827. princ " bytes"; terpri() >>;
  828. % finally I manufacture a literal vector for use with this code segment
  829. env := caar env;
  830. if null env then w := nil
  831. else <<
  832. w := mkvect cdar env;
  833. while env do <<
  834. putv(w, cdar env, caar env);
  835. env := cdr env >> >>;
  836. return (vec . w);
  837. end;
  838. symbolic procedure s!:add_pending(lab, pend, blocks);
  839. begin
  840. scalar w;
  841. if not atom lab then return
  842. list(gensym(), lab, 0) . pend;
  843. w := atsoc(lab, pend);
  844. if w then return w . deleq(w, pend)
  845. else return atsoc(lab, blocks) . pend
  846. end;
  847. symbolic procedure s!:invent_exit(x, blocks);
  848. begin
  849. scalar w;
  850. w := blocks;
  851. scan:
  852. if null w then go to not_found
  853. else if eqcar(cadar w, x) and caddar w = 0 then return caar w . blocks
  854. else w := cdr w;
  855. go to scan;
  856. not_found:
  857. w := gensym();
  858. return w . list(w, list x, 0) . blocks
  859. end;
  860. symbolic procedure s!:destination_label(lab, blocks);
  861. % lab is a label - first find the associated block. If it is empty
  862. % of executable code and it control leaves it unconditionally (either via
  863. % an unconditional jump or an EXIT) then return a value that reflects
  864. % going directly to that destination. Either an atom for a label or a
  865. % non-atomic EXIT marker. In the case of chains of blocks that end up in
  866. % and EXIT I want to ignore LOSE operations, while in all other cases LOSE
  867. % operations are significant.
  868. begin
  869. scalar n, w, x;
  870. w := atsoc(lab, blocks);
  871. if s!:is_lose_and_exit(w, blocks) then return '(EXIT);
  872. x := cadr w;
  873. n := caddr w;
  874. w := cdddr w;
  875. if n neq 0 then return lab; % is there any code?
  876. if null x or null cdr x then return x % an exit block
  877. else if cadr x = lab then return lab % Very direct loop
  878. else if null cddr x then return s!:destination_label(cadr x, blocks)
  879. else return lab
  880. end;
  881. symbolic procedure s!:remlose b;
  882. % If the instruction stream b has some LOSE opcodes at its tail return
  883. % (q . b') where q is the number of bytes of instructions involved,
  884. % and b' is the instruction sequence with the LOSE opcodes removed.
  885. begin
  886. scalar w;
  887. w := b;
  888. while w and not atom car w do w := cdr w;
  889. if null w then return (0 . b);
  890. if numberp car w and eqcar(cdr w, 'LOSES) then w := (2 . cddr w)
  891. else if car w = 'LOSE or car w = 'LOSE2 or car w = 'LOSE3 then
  892. w := (1 . cdr w)
  893. else return (0 . b);
  894. b := s!:remlose cdr w;
  895. return ((car w + car b) . cdr b);
  896. end;
  897. put('CALL0_0, 's!:shortcall, '(0 . 0));
  898. put('CALL0_1, 's!:shortcall, '(0 . 1));
  899. put('CALL0_2, 's!:shortcall, '(0 . 2));
  900. put('CALL0_3, 's!:shortcall, '(0 . 3));
  901. put('CALL1_0, 's!:shortcall, '(1 . 0));
  902. put('CALL1_1, 's!:shortcall, '(1 . 1));
  903. put('CALL1_2, 's!:shortcall, '(1 . 2));
  904. put('CALL1_3, 's!:shortcall, '(1 . 3));
  905. put('CALL1_4, 's!:shortcall, '(1 . 4));
  906. put('CALL1_5, 's!:shortcall, '(1 . 5));
  907. put('CALL2_0, 's!:shortcall, '(2 . 0));
  908. put('CALL2_1, 's!:shortcall, '(2 . 1));
  909. put('CALL2_2, 's!:shortcall, '(2 . 2));
  910. put('CALL2_3, 's!:shortcall, '(2 . 3));
  911. put('CALL2_4, 's!:shortcall, '(2 . 4));
  912. symbolic procedure s!:remcall b;
  913. % If the instruction stream b has a CALL opcode at its head then
  914. % return (p . q . r . s . b') where p is any comment assocated with
  915. % the call, q is the number of arguments the called function expects,
  916. % r is the literal-vector offset involved, s is the number of bytes
  917. % in the codestream used up and b' is the code stream with the CALL deleted.
  918. % Return NIL if no CALL is found.
  919. begin
  920. scalar w, p, q, r, s;
  921. while b and not atom car b do <<
  922. p := car b; % Strip comments, leaves p=nil if none
  923. b := cdr b >>;
  924. if null b then return nil % Nothing left
  925. % The possible interesting cases here are:
  926. % CALL0_0 .... JCALL2_4 (1 byte opcodes)
  927. % CALL0 n .... CALL3 n (2 bytes)
  928. % CALL2R n (2 bytes, treat as (SWOP;CALL2 n))
  929. % CALLN m n (3 bytes)
  930. % BIGCALL [CALL0..3] n (3 bytes)
  931. % BIGCALL [CALL2R] n (3 bytes, treat as (SWOP;BIGCALL [CALL2] n))
  932. % BIGCALL [CALLN] n m (4 bytes)
  933. else if numberp car b then <<
  934. r := car b;
  935. s := 2;
  936. b := cdr b;
  937. if null b then return nil
  938. else if numberp car b then <<
  939. q := r;
  940. r := car b;
  941. s := 3;
  942. b := cdr b;
  943. if b and numberp (w := car b) and eqcar(cdr b, 'BIGCALL) and
  944. truncate(w, 16) = 4 then <<
  945. r := 256*logand(w, 15) + r;
  946. s := 4;
  947. b := cdr b >>
  948. else if eqcar(b, 'BIGCALL) then <<
  949. w := truncate(r,16);
  950. r := 256*logand(r, 15) + q;
  951. q := w;
  952. if q = 5 then << % BIGCALL [CALL2R]
  953. q := 2;
  954. s := s-1; % fudge for the inserted byte
  955. b := 'BIGCALL . 'SWOP . cdr b >>;
  956. if q > 4 then return nil >>
  957. else if not eqcar(b, 'CALLN) then return nil >>
  958. else if car b = 'CALL0 then q := 0
  959. else if car b = 'CALL1 then q := 1
  960. else if car b = 'CALL2 then q := 2
  961. else if car b = 'CALL2R then <<
  962. q := 2;
  963. s := s-1; % fudge for the inserted byte
  964. b := 'CALL2 . 'SWOP . cdr b >>
  965. else if car b = 'CALL3 then q := 3
  966. else return nil;
  967. b := cdr b >>
  968. else if (q := get(car b, 's!:shortcall)) then <<
  969. r := cdr q;
  970. q := car q;
  971. s := 1;
  972. b := cdr b >>
  973. else return nil;
  974. return (p . q . r . s . b);
  975. end;
  976. symbolic procedure s!:is_lose_and_exit(b, blocks);
  977. % If the block b amounts to just a sequence of LOSE
  978. % operations and then a real exit then return TRUE. Otherwise return NIL.
  979. begin
  980. scalar lab, exit;
  981. lab := car b;
  982. exit := cadr b;
  983. b := cdddr b;
  984. if null exit then return nil;
  985. b := s!:remlose b;
  986. b := cdr b;
  987. while b and not atom car b do b := cdr b;
  988. if b then return nil % something in addition to the LOSEs
  989. else if car exit = 'EXIT then return t
  990. else if car exit = 'JUMP then <<
  991. if cadr exit = lab then nil % very direct loop
  992. else return s!:is_lose_and_exit(atsoc(cadr exit, blocks), blocks) >>
  993. else return nil;
  994. end;
  995. symbolic procedure s!:try_tail_1(b, blocks);
  996. begin
  997. scalar exit, size, body, w, w0, w1, w2, op;
  998. exit := cadr b;
  999. if null exit then return b
  1000. else if not (car exit = 'EXIT) then <<
  1001. if car exit = 'JUMP then <<
  1002. if not s!:is_lose_and_exit(atsoc(cadr exit, blocks), blocks) then
  1003. return b >>
  1004. else return b >>;
  1005. % Here the relevant block either ended with an EXIT, or it ended in an
  1006. % unconditional jump to a block that contained no more than LOSE opcodes
  1007. % before an EXIT.
  1008. size := caddr b;
  1009. body := cdddr b;
  1010. body := s!:remlose body;
  1011. size := size - car body; body := cdr body;
  1012. w := s!:remcall body;
  1013. if null w then return b;
  1014. % w = (comment . nargs . target . bytes . other_bytes)
  1015. w0 := cadr w; % nargs
  1016. w1 := caddr w; % target
  1017. body := cddddr w; % byte-stream tail
  1018. if w0 <= 7 and w1 <= 31 then <<
  1019. % Here I can use a version of JCALL that packs both operands into
  1020. % a single post-byte
  1021. body := 'JCALL . body;
  1022. body := (32*w0 + w1) . body;
  1023. size := size-1 >>
  1024. % For reasonably short calls I can use a generic JCALL where both nargs
  1025. % and the target address use one byte each
  1026. else if w1 < 256 then body := w0 . w1 . 'JCALLN . body
  1027. % When the offset required is over-large I use variants on BIGCALL.
  1028. else <<
  1029. body := 'BIGCALL . body;
  1030. w2 := logand(w1, 255); w1 := truncate(w1,256);
  1031. if w0 < 4 then body := w2 . (w1 + 16*w0 + 128) . body
  1032. else <<
  1033. body := w0 . w2 . (w1 + (16*4 + 128)) . body;
  1034. size := size + 1 >> >>;
  1035. if car w then body := append(car w, list('TAIL)) . body;
  1036. rplaca(cdr b, nil);
  1037. rplaca(cddr b, size-cadddr w+3);
  1038. rplacd(cddr b, body);
  1039. return b
  1040. end;
  1041. symbolic procedure s!:try_tailcall b;
  1042. for each v in b collect s!:try_tail_1(v, b);
  1043. symbolic procedure s!:tidy_exits_1(b, blocks);
  1044. begin
  1045. scalar exit, size, body, comm, w, w0, w1, w2, op;
  1046. exit := cadr b;
  1047. if null exit then return b
  1048. else if not (car exit = 'EXIT) then <<
  1049. if car exit = 'JUMP then <<
  1050. if not s!:is_lose_and_exit(atsoc(cadr exit, blocks), blocks) then
  1051. return b >>
  1052. else return b >>;
  1053. % Here the relevant block either ended with an EXIT, or it ended in an
  1054. % unconditional jump to a block that contained no more than LOSE opcodes
  1055. % before an EXIT.
  1056. size := caddr b;
  1057. body := cdddr b;
  1058. body := s!:remlose body; % chucks away any LOSEs just before the EXIT
  1059. size := size - car body; body := cdr body;
  1060. while body and not atom car body do <<
  1061. comm := car body;
  1062. body := cdr body >>;
  1063. if eqcar(body, 'VNIL) then w := 'NILEXIT
  1064. else if eqcar(body, 'LOADLOC0) then w := 'LOC0EXIT
  1065. else if eqcar(body, 'LOADLOC1) then w := 'LOC1EXIT
  1066. else if eqcar(body, 'LOADLOC2) then w := 'LOC2EXIT
  1067. else w := nil;
  1068. if w then <<
  1069. rplaca(cdr b, list w);
  1070. body := cdr body;
  1071. size := size - 1 >>
  1072. else if comm then body := comm . body;
  1073. rplaca(cddr b, size);
  1074. rplacd(cddr b, body);
  1075. return b
  1076. end;
  1077. symbolic procedure s!:tidy_exits b;
  1078. for each v in b collect s!:tidy_exits_1(v, b);
  1079. symbolic procedure s!:tidy_flowgraph b;
  1080. begin
  1081. scalar r, pending;
  1082. % The blocks are initially built up in reverse order - correct that here
  1083. b := reverse b;
  1084. % The first block is where we enter the procedure, and so it always has to
  1085. % be the first thing emitted.
  1086. pending := list car b;
  1087. while pending do begin
  1088. scalar c, x, l1, l2, done1, done2;
  1089. c := car pending; % next block to emit
  1090. pending := cdr pending;
  1091. flag(list car c, 'coded); % this label has now been set
  1092. x := cadr c; % exit status of current block
  1093. if null x or null cdr x then
  1094. r := c . r
  1095. else if car x = 'ICASE then <<
  1096. % I reverse the list of case labels here so that I add pending blocks in
  1097. % and order that will typically arrange that the cases come out in the
  1098. % generated code in the "natural" order.
  1099. rplacd(x, reversip cdr x);
  1100. for each ll on cdr x do <<
  1101. l1 := s!:destination_label(car ll, b);
  1102. if not atom l1 then <<
  1103. l1 := s!:invent_exit(car l1, b);
  1104. b := cdr l1;
  1105. l1 := cadr l1 >>;
  1106. rplaca(ll, l1);
  1107. done1 := flagp(l1, 'coded);
  1108. flag(list l1, 'used_label);
  1109. if not done1 then pending := s!:add_pending(l1, pending, b) >>;
  1110. rplacd(x, reversip cdr x);
  1111. r := c . r >>
  1112. else if null cddr x then << % unconditional jump
  1113. l1 := s!:destination_label(cadr x, b);
  1114. if not atom l1 then % goto exit turns into exit block
  1115. c := car c . l1 . cddr c
  1116. else if flagp(l1, 'coded) then <<
  1117. flag(list l1, 'used_label);
  1118. c := car c . list(car x, l1) . cddr c >>
  1119. else <<
  1120. c := car c . nil . cddr c;
  1121. pending := s!:add_pending(l1, pending, b) >>;
  1122. r := c . r >>
  1123. else << % conditional jump
  1124. l1 := s!:destination_label(cadr x, b);
  1125. l2 := s!:destination_label(caddr x, b);
  1126. done1 := atom l1 and flagp(l1, 'coded);
  1127. done2 := atom l2 and flagp(l2, 'coded);
  1128. if done1 then <<
  1129. if done2 then <<
  1130. flag(list l1, 'used_label);
  1131. rplaca(cdadr c, l1);
  1132. % Here I synthesize a block to carry the unconditional jump to L2 that I need
  1133. pending := list(gensym(), list('JUMP, l2), 0) . pending >>
  1134. else <<
  1135. flag(list l1, 'used_label);
  1136. rplaca(cdadr c, l1);
  1137. pending := s!:add_pending(l2, pending, b) >> >>
  1138. else <<
  1139. if done2 then <<
  1140. flag(list l2, 'used_label);
  1141. rplaca(cadr c, s!:negate_jump car x);
  1142. rplaca(cdadr c, l2);
  1143. pending := s!:add_pending(l1, pending, b) >>
  1144. else <<
  1145. % neither l1 nor l2 have been done - I make a somewhat random selection
  1146. % as to which I will emit first
  1147. if not atom l1 then << % invent block for exit case
  1148. l1 := s!:invent_exit(car l1, b);
  1149. b := cdr l1;
  1150. l1 := car l1 >>;
  1151. flag(list l1, 'used_label);
  1152. rplaca(cdadr c, l1);
  1153. % it is possible here that l1 was an exit case and s!:invent_exit discovers a
  1154. % previously emitted suitable exit block, in which case l1 is now a reference
  1155. % to an already-set label, so it should not be pushed onto the list of
  1156. % pending blocks
  1157. if not flagp(l1, 'coded) then
  1158. pending := s!:add_pending(l1, pending, b);
  1159. pending := s!:add_pending(l2, pending, b) >> >>;
  1160. r := c . r >>
  1161. end;
  1162. return reverse r
  1163. end;
  1164. deflist('((JUMPNIL JUMPT)
  1165. (JUMPT JUMPNIL)
  1166. (JUMPATOM JUMPNATOM)
  1167. (JUMPNATOM JUMPATOM)
  1168. (JUMPEQ JUMPNE)
  1169. (JUMPNE JUMPEQ)
  1170. (JUMPEQUAL JUMPNEQUAL)
  1171. (JUMPNEQUAL JUMPEQUAL)
  1172. (JUMPL0NIL JUMPL0T)
  1173. (JUMPL0T JUMPL0NIL)
  1174. (JUMPL1NIL JUMPL1T)
  1175. (JUMPL1T JUMPL1NIL)
  1176. (JUMPL2NIL JUMPL2T)
  1177. (JUMPL2T JUMPL2NIL)
  1178. (JUMPL3NIL JUMPL3T)
  1179. (JUMPL3T JUMPL3NIL)
  1180. (JUMPL4NIL JUMPL4T)
  1181. (JUMPL4T JUMPL4NIL)
  1182. (JUMPL0ATOM JUMPL0NATOM)
  1183. (JUMPL0NATOM JUMPL0ATOM)
  1184. (JUMPL1ATOM JUMPL1NATOM)
  1185. (JUMPL1NATOM JUMPL1ATOM)
  1186. (JUMPL2ATOM JUMPL2NATOM)
  1187. (JUMPL2NATOM JUMPL2ATOM)
  1188. (JUMPL3ATOM JUMPL3NATOM)
  1189. (JUMPL3NATOM JUMPL3ATOM)
  1190. (JUMPST0NIL JUMPST0T)
  1191. (JUMPST0T JUMPST0NIL)
  1192. (JUMPST1NIL JUMPST1T)
  1193. (JUMPST1T JUMPST1NIL)
  1194. (JUMPST2NIL JUMPST2T)
  1195. (JUMPST2T JUMPST2NIL)
  1196. (JUMPFREE1NIL JUMPFREE1T)
  1197. (JUMPFREE1T JUMPFREE1NIL)
  1198. (JUMPFREE2NIL JUMPFREE2T)
  1199. (JUMPFREE2T JUMPFREE2NIL)
  1200. (JUMPFREE3NIL JUMPFREE3T)
  1201. (JUMPFREE3T JUMPFREE3NIL)
  1202. (JUMPFREE4NIL JUMPFREE4T)
  1203. (JUMPFREE4T JUMPFREE4NIL)
  1204. (JUMPFREENIL JUMPFREET)
  1205. (JUMPFREET JUMPFREENIL)
  1206. (JUMPLIT1EQ JUMPLIT1NE)
  1207. (JUMPLIT1NE JUMPLIT1EQ)
  1208. (JUMPLIT2EQ JUMPLIT2NE)
  1209. (JUMPLIT2NE JUMPLIT2EQ)
  1210. (JUMPLIT3EQ JUMPLIT3NE)
  1211. (JUMPLIT3NE JUMPLIT3EQ)
  1212. (JUMPLIT4EQ JUMPLIT4NE)
  1213. (JUMPLIT4NE JUMPLIT4EQ)
  1214. (JUMPLITEQ JUMPLITNE)
  1215. (JUMPLITNE JUMPLITEQ)
  1216. (JUMPLITEQ!* JUMPLITNE!*)
  1217. (JUMPLITNE!* JUMPLITEQ!*)
  1218. (JUMPB1NIL JUMPB1T)
  1219. (JUMPB1T JUMPB1NIL)
  1220. (JUMPB2NIL JUMPB2T)
  1221. (JUMPB2T JUMPB2NIL)
  1222. (JUMPFLAGP JUMPNFLAGP)
  1223. (JUMPNFLAGP JUMPFLAGP)
  1224. (JUMPEQCAR JUMPNEQCAR)
  1225. (JUMPNEQCAR JUMPEQCAR)
  1226. ), 'negjump);
  1227. symbolic procedure s!:negate_jump x;
  1228. if atom x then get(x, 'negjump)
  1229. else rplaca(x, get(car x, 'negjump));
  1230. symbolic procedure s!:resolve_labels();
  1231. begin
  1232. scalar w, labelvals, converged, pc, x;
  1233. repeat <<
  1234. converged := t;
  1235. pc := 0;
  1236. for each b in s!:current_procedure do <<
  1237. % Each block has a label at its head - set the label, or
  1238. % on subsequent passes check to see if its value has changed -
  1239. % if anything has happened clear the converged flag so that another
  1240. % pass will be taken
  1241. w := assoc!*!*(car b, labelvals);
  1242. if null w then <<
  1243. converged := nil;
  1244. w := car b . pc;
  1245. labelvals := w . labelvals >>
  1246. else if cdr w neq pc then <<
  1247. rplacd(w, pc);
  1248. converged := nil >>;
  1249. % move on pc by the length of the block excluding any exit code
  1250. pc := pc + caddr b;
  1251. x := cadr b;
  1252. if null x then nil % no EXIT needed
  1253. else if null cdr x then pc := pc + 1 % EXIT operation
  1254. else if car x = 'ICASE then pc := pc + 2*length x
  1255. else <<
  1256. % by this stage I demand that (a) the labels in jump instructions
  1257. % are simple atomic labels (and never (EXIT) psuedo-labels) and (b)
  1258. % there are no longer any 2-way jumps - everything is just (JUMPcond l)
  1259. % where the alternative case is handled by just dropping through.
  1260. % But note that the JUMPcond will sometimes be composite (eg in effect
  1261. % <LOADLOC 2/JUMPT>, eg)
  1262. w := assoc!*!*(cadr x, labelvals);
  1263. if null w then <<
  1264. w := 128; % will be a "short" offset
  1265. converged := nil >>
  1266. else w := cdr w - pc; % the offset
  1267. w := s!:expand_jump(car x, w); % list of bytes to plant
  1268. pc := pc + length w >> >>
  1269. >> until converged;
  1270. return (pc . labelvals)
  1271. end;
  1272. symbolic procedure s!:plant_basic_block(vec, pc, b);
  1273. % For this to give a sensible display the list of bytes must have
  1274. % a comment/annotation after every operation in it. This is ensured by
  1275. % s!:outop.
  1276. begin
  1277. scalar tagged;
  1278. for each i in b do <<
  1279. if atom i then <<
  1280. if symbolp i then i := get(i, 's!:opcode);
  1281. if not tagged and (!*plap or !*pgwd) then <<
  1282. s!:prinhex4 pc; princ ":"; ttab 8; tagged := t >>;
  1283. if not fixp i or i < 0 or i > 255 then error("bad byte to put", i);
  1284. bps!-putv(vec, pc, i);
  1285. if !*plap or !*pgwd then << s!:prinhex2 i; princ " " >>;
  1286. pc := pc + 1 >>
  1287. else if !*plap or !*pgwd then <<
  1288. ttab 23;
  1289. princ car i;
  1290. for each w in cdr i do << princ " "; prin w >>;
  1291. terpri(); tagged := nil >> >>;
  1292. return pc
  1293. end;
  1294. symbolic procedure s!:plant_bytes(vec, pc, bytelist, doc);
  1295. begin
  1296. if !*plap or !*pgwd then << s!:prinhex4 pc; princ ":"; ttab 8 >>;
  1297. for each v in bytelist do <<
  1298. if symbolp v then v := get(v, 's!:opcode);
  1299. if not fixp v or v < 0 or v > 255 then error("bad byte to put", v);
  1300. bps!-putv(vec, pc, v);
  1301. if !*plap or !*pgwd then <<
  1302. if posn() > 50 then << terpri(); ttab 8 >>;
  1303. s!:prinhex2 v; princ " " >>;
  1304. pc := pc + 1 >>;
  1305. if !*plap or !*pgwd then <<
  1306. if posn() > 23 then terpri();
  1307. ttab 23;
  1308. princ car doc;
  1309. for each w in cdr doc do <<
  1310. if posn() > 65 then << terpri(); ttab 23 >>;
  1311. princ " "; prin w >>;
  1312. terpri() >>;
  1313. return pc
  1314. end;
  1315. symbolic procedure s!:plant_exit_code(vec, pc, b, labelvals);
  1316. begin
  1317. scalar w, loc, low, high, r;
  1318. if null b then return pc
  1319. else if null cdr b then % Simple EXIT
  1320. return s!:plant_bytes(vec, pc, list get(car b, 's!:opcode), b)
  1321. else if car b = 'ICASE then <<
  1322. loc := pc + 3;
  1323. for each ll in cdr b do <<
  1324. w := cdr assoc!*!*(ll, labelvals) - loc;
  1325. loc := loc + 2;
  1326. if w < 0 then <<
  1327. w := -w;
  1328. low := ilogand(w, 255);
  1329. high := 128 + truncate(w - low, 256) >>
  1330. else <<
  1331. low := ilogand(w, 255);
  1332. high := truncate(w - low, 256) >>;
  1333. r := low . high . r >>;
  1334. r := get('ICASE, 's!:opcode) . length cddr b . reversip r;
  1335. return s!:plant_bytes(vec, pc, r, b) >>;
  1336. w := cdr assoc!*!*(cadr b, labelvals) - pc;
  1337. w := s!:expand_jump(car b, w); % list of bytes to plant
  1338. return s!:plant_bytes(vec, pc, w, b)
  1339. end;
  1340. deflist('(
  1341. (JUMPL0NIL ((LOADLOC0) JUMPNIL))
  1342. (JUMPL0T ((LOADLOC0) JUMPT))
  1343. (JUMPL1NIL ((LOADLOC1) JUMPNIL))
  1344. (JUMPL1T ((LOADLOC1) JUMPT))
  1345. (JUMPL2NIL ((LOADLOC2) JUMPNIL))
  1346. (JUMPL2T ((LOADLOC2) JUMPT))
  1347. (JUMPL3NIL ((LOADLOC3) JUMPNIL))
  1348. (JUMPL3T ((LOADLOC3) JUMPT))
  1349. (JUMPL4NIL ((LOADLOC4) JUMPNIL))
  1350. (JUMPL4T ((LOADLOC4) JUMPT))
  1351. (JUMPL0ATOM ((LOADLOC0) JUMPATOM))
  1352. (JUMPL0NATOM ((LOADLOC0) JUMPNATOM))
  1353. (JUMPL1ATOM ((LOADLOC1) JUMPATOM))
  1354. (JUMPL1NATOM ((LOADLOC1) JUMPNATOM))
  1355. (JUMPL2ATOM ((LOADLOC2) JUMPATOM))
  1356. (JUMPL2NATOM ((LOADLOC2) JUMPNATOM))
  1357. (JUMPL3ATOM ((LOADLOC3) JUMPATOM))
  1358. (JUMPL3NATOM ((LOADLOC3) JUMPNATOM))
  1359. (JUMPST0NIL ((STORELOC0) JUMPNIL))
  1360. (JUMPST0T ((STORELOC0) JUMPT))
  1361. (JUMPST1NIL ((STORELOC1) JUMPNIL))
  1362. (JUMPST1T ((STORELOC1) JUMPT))
  1363. (JUMPST2NIL ((STORELOC2) JUMPNIL))
  1364. (JUMPST2T ((STORELOC2) JUMPT))
  1365. (JUMPFREE1NIL ((LOADFREE1) JUMPNIL))
  1366. (JUMPFREE1T ((LOADFREE1) JUMPT))
  1367. (JUMPFREE2NIL ((LOADFREE2) JUMPNIL))
  1368. (JUMPFREE2T ((LOADFREE2) JUMPT))
  1369. (JUMPFREE3NIL ((LOADFREE3) JUMPNIL))
  1370. (JUMPFREE3T ((LOADFREE3) JUMPT))
  1371. (JUMPFREE4NIL ((LOADFREE4) JUMPNIL))
  1372. (JUMPFREE4T ((LOADFREE4) JUMPT))
  1373. (JUMPFREENIL ((LOADFREE !*) JUMPNIL))
  1374. (JUMPFREET ((LOADFREE !*) JUMPT))
  1375. (JUMPLIT1EQ ((LOADLIT1) JUMPEQ))
  1376. (JUMPLIT1NE ((LOADLIT1) JUMPNE))
  1377. (JUMPLIT2EQ ((LOADLIT2) JUMPEQ))
  1378. (JUMPLIT2NE ((LOADLIT2) JUMPNE))
  1379. (JUMPLIT3EQ ((LOADLIT3) JUMPEQ))
  1380. (JUMPLIT3NE ((LOADLIT3) JUMPNE))
  1381. (JUMPLIT4EQ ((LOADLIT4) JUMPEQ))
  1382. (JUMPLIT4NE ((LOADLIT4) JUMPNE))
  1383. (JUMPLITEQ ((LOADLIT !*) JUMPEQ))
  1384. (JUMPLITNE ((LOADLIT !*) JUMPNE))
  1385. (JUMPLITEQ!* ((LOADLIT !* SWOP) JUMPEQ))
  1386. (JUMPLITNE!* ((LOADLIT !* SWOP) JUMPNE))
  1387. (JUMPB1NIL ((BUILTIN1 !*) JUMPNIL))
  1388. (JUMPB1T ((BUILTIN1 !*) JUMPT))
  1389. (JUMPB2NIL ((BUILTIN2 !*) JUMPNIL))
  1390. (JUMPB2T ((BUILTIN2 !*) JUMPT))
  1391. (JUMPFLAGP ((LOADLIT !* FLAGP) JUMPT))
  1392. (JUMPNFLAGP ((LOADLIT !* FLAGP) JUMPNIL))
  1393. (JUMPEQCAR ((LOADLIT !* EQCAR) JUMPT))
  1394. (JUMPNEQCAR ((LOADLIT !* EQCAR) JUMPNIL))
  1395. ), 's!:expand_jump);
  1396. fluid '(s!:backwards_jump s!:longer_jump);
  1397. << s!:backwards_jump := make!-simple!-string 256;
  1398. s!:longer_jump := make!-simple!-string 256;
  1399. nil >>;
  1400. for each op in '(
  1401. (JUMP JUMP_B JUMP_L JUMP_BL)
  1402. (JUMPNIL JUMPNIL_B JUMPNIL_L JUMPNIL_BL)
  1403. (JUMPT JUMPT_B JUMPT_L JUMPT_BL)
  1404. (JUMPATOM JUMPATOM_B JUMPATOM_L JUMPATOM_BL)
  1405. (JUMPNATOM JUMPNATOM_B JUMPNATOM_L JUMPNATOM_BL)
  1406. (JUMPEQ JUMPEQ_B JUMPEQ_L JUMPEQ_BL)
  1407. (JUMPNE JUMPNE_B JUMPNE_L JUMPNE_BL)
  1408. (JUMPEQUAL JUMPEQUAL_B JUMPEQUAL_L JUMPEQUAL_BL)
  1409. (JUMPNEQUAL JUMPNEQUAL_B JUMPNEQUAL_L JUMPNEQUAL_BL)
  1410. (CATCH CATCH_B CATCH_L CATCH_BL)) do <<
  1411. putv!-char(s!:backwards_jump,
  1412. get(car op, 's!:opcode), get(cadr op, 's!:opcode));
  1413. putv!-char(s!:backwards_jump,
  1414. get(caddr op, 's!:opcode), get(cadddr op, 's!:opcode));
  1415. putv!-char(s!:longer_jump,
  1416. get(car op, 's!:opcode), get(caddr op, 's!:opcode));
  1417. putv!-char(s!:longer_jump,
  1418. get(cadr op, 's!:opcode), get(cadddr op, 's!:opcode)) >>;
  1419. symbolic procedure s!:expand_jump(op, offset);
  1420. begin
  1421. scalar arg, low, high, opcode, expanded;
  1422. if not atom op then <<
  1423. arg := cadr op;
  1424. op := car op;
  1425. offset := offset - 1 >>;
  1426. expanded := get(op, 's!:expand_jump);
  1427. % The special compact jumps only support forward jumps by up to 255 bytes -
  1428. % they do not allow for backwards or long jumps. I also expand the jumps
  1429. % to a longer form if the argument is 256 or higher (in which case I must
  1430. % have an expansion that uses LOADLIT or LOADFREE and I turn it into one
  1431. % of the longer sequences that can access up to position 2047 in the literal
  1432. % vector.
  1433. if expanded and
  1434. not (2 <= offset and offset < 256+2 and
  1435. (null arg or arg < 256)) then <<
  1436. % Here I need to expand the branch
  1437. op := cadr expanded;
  1438. expanded := car expanded;
  1439. if arg then <<
  1440. if arg > 2047 then
  1441. error("function uses too many literals (2048 limit)")
  1442. else if arg > 255 then begin
  1443. scalar high, low;
  1444. low := ilogand(expanded, 255);
  1445. high := truncate(expanded - low, 256);
  1446. % LOADLIT and LOADFREE are encoded here as sub-types of the BIGCALL opcode.
  1447. expanded := 'BIGCALL .
  1448. get(car expanded, 's!:longform) + high .
  1449. low . cddr expanded end
  1450. else expanded := subst(arg, '!*, expanded);
  1451. offset := offset + 1 >>;
  1452. offset := offset - length expanded;
  1453. arg := nil >>
  1454. else expanded := nil;
  1455. opcode := get(op, 's!:opcode);
  1456. if null opcode then error(0, list(op, offset, "invalid block exit"));
  1457. if -256+2 < offset and offset < 256+2 then offset := offset - 2
  1458. else << high := t; offset := offset - 3 >>;
  1459. if offset < 0 then <<
  1460. opcode := byte!-getv(s!:backwards_jump, opcode);
  1461. offset := -offset >>;
  1462. if high then <<
  1463. low := logand(offset, 255);
  1464. high := truncate(offset - low,256) >>
  1465. else if (low := offset) > 255 then error(0, "Bad offset in expand_jump");
  1466. if arg then return list(opcode, arg, low)
  1467. else if not high then return append(expanded, list(opcode, low))
  1468. else return append(expanded,
  1469. list(byte!-getv(s!:longer_jump, opcode), high, low))
  1470. end;
  1471. %
  1472. % Each expression processed occurs in a context - for CSL we have
  1473. % a strict interpretation of 'program' context - and to allow
  1474. % some optimisations we also distinguish 'top level', 'normal'
  1475. % and 'void'. Contexts are coded numerically, which is a long
  1476. % established hack, but pretty inscrutable - here are the codes..
  1477. % 0 a top-level expression, value is value of current fn
  1478. % 1 an expression whose value is needed, but not at top level
  1479. % 2 an expression whose value is not needed (e.g. in PROGN)
  1480. % 4 value not needed because in PROG context: top level PROG
  1481. % 5 in prog context, PROGs value was needed
  1482. % 6 in prog context, PROG was in void context
  1483. %
  1484. % Note that to support REDUCE I seem to have to allow GO and RETURN
  1485. % to appear anywhere within a progn that is itself in prog context,
  1486. % and not just in the final position. For COMMON Lisp GO and
  1487. % RETURN-FROM statements can appear pretty-well anywhere.
  1488. symbolic procedure s!:comval(x, env, context);
  1489. % s!:comval is the central dispatch procedure in the compiler - calling
  1490. % it will generate code to load the value of x into the A register,
  1491. % pushing down previous value through B.
  1492. begin
  1493. scalar helper;
  1494. x := s!:improve x;
  1495. if atom x then return s!:comatom(x, env, context)
  1496. else if eqcar(car x, 'lambda) then
  1497. return s!:comlambda(cadar x, cddar x, cdr x, env, context)
  1498. else if car x eq s!:current_function then s!:comcall(x, env, context)
  1499. !#if common!-lisp!-mode
  1500. else if helper := s!:local_macro car x then <<
  1501. if atom cdr helper then
  1502. s!:comval('funcall . cdr helper . cdr x, env, context)
  1503. else s!:comval(funcall('lambda . cdr helper, x), env, context) >>
  1504. !#endif
  1505. else if (helper := get(car x, 's!:compilermacro)) and
  1506. (helper := funcall(helper, x, env, context)) then
  1507. return s!:comval(helper, env, context)
  1508. else if (helper := get(car x, 's!:newname)) then
  1509. return s!:comval(helper . cdr x, env, context)
  1510. else if helper := get(car x, 's!:compfn) then
  1511. return funcall(helper, x, env, context)
  1512. else if helper := macro!-function car x then
  1513. return s!:comval(funcall(helper, x), env, context)
  1514. else return s!:comcall(x, env, context)
  1515. end;
  1516. symbolic procedure s!:comspecform(x, env, context);
  1517. error(0, list("special form", x));
  1518. % This establishes a default handler for each special form so that
  1519. % any that I forget to treat more directly will cause a tidy error
  1520. % if found in compiled code. The conditional definition here is to
  1521. % allow me to re-load this file on top of itself during bootstrapping.
  1522. % The list here can be a reminder of ways that this compiler is
  1523. % incomplete.
  1524. if null get('and, 's!:compfn) then <<
  1525. put('compiler!-let, 's!:compfn, function s!:comspecform);
  1526. put('de, 's!:compfn, function s!:comspecform);
  1527. put('defun, 's!:compfn, function s!:comspecform);
  1528. put('eval!-when, 's!:compfn, function s!:comspecform);
  1529. put('flet, 's!:compfn, function s!:comspecform);
  1530. put('labels, 's!:compfn, function s!:comspecform);
  1531. put('macrolet, 's!:compfn, function s!:comspecform);
  1532. !#if (not common!-lisp!-mode)
  1533. % In Common Lisp Mode I support there. In Standard Lisp mode they
  1534. % are not very meaningful so I do not, but I still reserve the names.
  1535. put('multiple!-value!-call, 's!:compfn, function s!:comspecform);
  1536. put('multiple!-value!-prog1, 's!:compfn, function s!:comspecform);
  1537. put('prog!*, 's!:compfn, function s!:comspecform);
  1538. put('progv, 's!:compfn, function s!:comspecform);
  1539. !#endif
  1540. nil >>;
  1541. symbolic procedure s!:improve u;
  1542. begin
  1543. scalar w;
  1544. if atom u then return u
  1545. else if (w := get(car u, 's!:tidy_fn)) then
  1546. return funcall(w, u)
  1547. else if (w := get(car u, 's!:newname)) then
  1548. return s!:improve (w . cdr u)
  1549. else return u
  1550. end;
  1551. symbolic procedure s!:imp_minus u;
  1552. begin
  1553. scalar a;
  1554. a := s!:improve cadr u;
  1555. return if numberp a then -a
  1556. else if eqcar(a, 'minus) or eqcar(a, 'iminus) then cadr a
  1557. else if eqcar(a, 'difference) then
  1558. s!:improve list('difference, caddr a, cadr a)
  1559. else if eqcar(a, 'idifference) then
  1560. s!:improve list('idifference, caddr a, cadr a)
  1561. else list(car u, a)
  1562. end;
  1563. put('minus, 's!:tidy_fn, 's!:imp_minus);
  1564. put('iminus, 's!:tidy_fn, 's!:imp_minus);
  1565. !#if common!-lisp!-mode
  1566. symbolic procedure s!:imp_1!+ u;
  1567. s!:improve ('add1 . cdr u);
  1568. put('!1!+, 's!:tidy_fn, 's!:imp_1!+);
  1569. symbolic procedure s!:imp_1!- u;
  1570. s!:improve ('sub1 . cdr u);
  1571. put('!1!-, 's!:tidy_fn, 's!:imp_1!-);
  1572. !#endif
  1573. symbolic procedure s!:imp_times u;
  1574. begin
  1575. scalar a, b;
  1576. if not (length u = 3) then
  1577. return car u . for each v in cdr u collect s!:improve v;
  1578. a := s!:improve cadr u;
  1579. b := s!:improve caddr u;
  1580. return if a = 1 then b
  1581. else if b = 1 then a
  1582. else if a = -1 then s!:imp_minus list('minus, b)
  1583. else if b = -1 then s!:imp_minus list('minus, a)
  1584. else list(car u, a, b)
  1585. end;
  1586. put('times, 's!:tidy_fn, 's!:imp_times);
  1587. symbolic procedure s!:imp_itimes u;
  1588. begin
  1589. scalar a, b;
  1590. if not (length u = 3) then
  1591. return car u . for each v in cdr u collect s!:improve v;
  1592. a := s!:improve cadr u;
  1593. b := s!:improve caddr u;
  1594. return if a = 1 then b
  1595. else if b = 1 then a
  1596. else if a = -1 then s!:imp_minus list('iminus, b)
  1597. else if b = -1 then s!:imp_minus list('iminus, a)
  1598. else list(car u, a, b)
  1599. end;
  1600. put('itimes, 's!:tidy_fn, 's!:imp_itimes);
  1601. symbolic procedure s!:imp_difference u;
  1602. begin
  1603. scalar a, b;
  1604. a := s!:improve cadr u;
  1605. b := s!:improve caddr u;
  1606. return if a = 0 then s!:imp_minus list('minus, b)
  1607. else if b = 0 then a
  1608. else list(car u, a, b)
  1609. end;
  1610. put('difference, 's!:tidy_fn, 's!:imp_difference);
  1611. symbolic procedure s!:imp_idifference u;
  1612. begin
  1613. scalar a, b;
  1614. a := s!:improve cadr u;
  1615. b := s!:improve caddr u;
  1616. return if a = 0 then s!:imp_minus list('iminus, b)
  1617. else if b = 0 then a
  1618. else list(car u, a, b)
  1619. end;
  1620. put('idifference, 's!:tidy_fn, 's!:imp_idifference);
  1621. % s!:iseasy yields true if the given expression can be loaded without
  1622. % disturbing registers.
  1623. symbolic procedure s!:alwayseasy x;
  1624. t;
  1625. put('quote, 's!:helpeasy, function s!:alwayseasy);
  1626. put('function, 's!:helpeasy, function s!:alwayseasy);
  1627. symbolic procedure s!:easyifarg x;
  1628. null cdr x or (null cddr x and s!:iseasy cadr x);
  1629. put('ncons, 's!:helpeasy, function s!:easyifarg);
  1630. put('car, 's!:helpeasy, function s!:easyifarg);
  1631. put('cdr, 's!:helpeasy, function s!:easyifarg);
  1632. put('caar, 's!:helpeasy, function s!:easyifarg);
  1633. put('cadr, 's!:helpeasy, function s!:easyifarg);
  1634. put('cdar, 's!:helpeasy, function s!:easyifarg);
  1635. put('cddr, 's!:helpeasy, function s!:easyifarg);
  1636. put('caaar, 's!:helpeasy, function s!:easyifarg);
  1637. put('caadr, 's!:helpeasy, function s!:easyifarg);
  1638. put('cadar, 's!:helpeasy, function s!:easyifarg);
  1639. put('caddr, 's!:helpeasy, function s!:easyifarg);
  1640. put('cdaar, 's!:helpeasy, function s!:easyifarg);
  1641. put('cdadr, 's!:helpeasy, function s!:easyifarg);
  1642. put('cddar, 's!:helpeasy, function s!:easyifarg);
  1643. put('cdddr, 's!:helpeasy, function s!:easyifarg);
  1644. put('caaaar, 's!:helpeasy, function s!:easyifarg);
  1645. put('caaadr, 's!:helpeasy, function s!:easyifarg);
  1646. put('caadar, 's!:helpeasy, function s!:easyifarg);
  1647. put('caaddr, 's!:helpeasy, function s!:easyifarg);
  1648. put('cadaar, 's!:helpeasy, function s!:easyifarg);
  1649. put('cadadr, 's!:helpeasy, function s!:easyifarg);
  1650. put('caddar, 's!:helpeasy, function s!:easyifarg);
  1651. put('cadddr, 's!:helpeasy, function s!:easyifarg);
  1652. put('cdaaar, 's!:helpeasy, function s!:easyifarg);
  1653. put('cdaadr, 's!:helpeasy, function s!:easyifarg);
  1654. put('cdadar, 's!:helpeasy, function s!:easyifarg);
  1655. put('cdaddr, 's!:helpeasy, function s!:easyifarg);
  1656. put('cddaar, 's!:helpeasy, function s!:easyifarg);
  1657. put('cddadr, 's!:helpeasy, function s!:easyifarg);
  1658. put('cdddar, 's!:helpeasy, function s!:easyifarg);
  1659. put('cddddr, 's!:helpeasy, function s!:easyifarg);
  1660. %put('ncons, 's!:helpeasy, function s!:easyifarg);
  1661. %put('list, 's!:helpeasy, function s!:easyifarg);
  1662. %put('list!*, 's!:helpeasy, function s!:easyifarg);
  1663. %put('minus, 's!:helpeasy, function s!:easyifarg);
  1664. %put('minusp, 's!:helpeasy, function s!:easyifarg);
  1665. symbolic procedure s!:easygetv x;
  1666. begin
  1667. scalar a2;
  1668. a2 := caddr x;
  1669. if null !*carcheckflag and
  1670. fixp a2 and a2 >= 0 and a2 < 256 then return s!:iseasy cadr x
  1671. else return nil
  1672. end;
  1673. put('getv, 's!:helpeasy, function s!:easygetv);
  1674. !#if common!-lisp!-mode
  1675. put('svref, 's!:heapeasy, function s!:easygetv);
  1676. !#endif
  1677. symbolic procedure s!:easyqgetv x;
  1678. begin
  1679. scalar a2;
  1680. a2 := caddr x;
  1681. if fixp a2 and a2 >= 0 and a2 < 256 then return s!:iseasy cadr x
  1682. else return nil
  1683. end;
  1684. put('qgetv, 's!:helpeasy, function s!:easyqgetv);
  1685. !#if common!-lisp!-mode
  1686. put('qsvref, 's!:heapeasy, function s!:easyqgetv);
  1687. !#endif
  1688. symbolic procedure s!:iseasy x;
  1689. begin
  1690. scalar h;
  1691. if atom x then return t;
  1692. if not atom car x then return nil;
  1693. if h := get(car x, 's!:helpeasy) then return funcall(h, x)
  1694. else return nil
  1695. end;
  1696. symbolic procedure s!:instate_local_decs(v, d, w);
  1697. begin
  1698. scalar fg;
  1699. if fluidp v then return w;
  1700. for each z in d do
  1701. if eqcar(z, 'special) and memq(v, cdr z) then fg := t;
  1702. if fg then <<
  1703. make!-special v;
  1704. w := v . w >>;
  1705. return w
  1706. end;
  1707. symbolic procedure s!:residual_local_decs(d, w);
  1708. begin
  1709. for each z in d do
  1710. if eqcar(z, 'special) then for each v in cdr z do
  1711. if not fluidp v and not globalp v then <<
  1712. make!-special v;
  1713. w := v . w >>;
  1714. return w
  1715. end;
  1716. symbolic procedure s!:cancel_local_decs w;
  1717. unfluid w;
  1718. symbolic procedure s!:find_local_decs body;
  1719. begin
  1720. scalar w, local_decs;
  1721. while body and (eqcar(car body, 'declare) or stringp car body) do <<
  1722. if stringp car body then w := car body . w
  1723. else local_decs := append(local_decs, cdar body);
  1724. body := cdr body >>;
  1725. % I put back any strings since although MAYBE they are documentation also
  1726. % it could be that one was a result.
  1727. while w do << body := car w . body; w := cdr w >>;
  1728. return local_decs . body
  1729. end;
  1730. symbolic procedure s!:comlambda(bvl, body, args, env, context);
  1731. % Handle embedded lambda expressions, which may well be serving as
  1732. % the construct that Common Lisp would write as (let ((x v)) ...)
  1733. % NOTE: I do not support &optional or &rest keywords with embedded
  1734. % lambda expressions. This is maybe just because I think that they would
  1735. % be a gross frivolity! If I find an important piece of code that
  1736. % happens (say because of some macro-expansion) to use them I can
  1737. % process out the keywords here.
  1738. begin
  1739. scalar s, nbvl, fluids, fl1, w, local_decs;
  1740. nbvl := s := cdr env;
  1741. body := s!:find_local_decs body;
  1742. local_decs := car body; body := cdr body;
  1743. if atom body then body := nil
  1744. else if atom cdr body then body := car body
  1745. else body := 'progn . body;
  1746. w := nil;
  1747. for each v in bvl do w := s!:instate_local_decs(v, local_decs, w);
  1748. for each v in bvl do <<
  1749. if fluidp v or globalp v then begin
  1750. scalar g;
  1751. g := gensym();
  1752. nbvl := g . nbvl;
  1753. fl1 := v . fl1;
  1754. fluids := (v . g) . fluids end
  1755. else nbvl := v . nbvl;
  1756. % It would be even better to collect up NILs here and use s!:outstack with
  1757. % larger args (where possible), but at least this is a slight improvement!
  1758. if car args = nil then s!:outstack 1
  1759. else <<
  1760. s!:comval(car args, env, 1);
  1761. s!:outopcode0('PUSH, '(PUSH)) >>;
  1762. rplacd(env, 0 . cdr env);
  1763. args := cdr args >>;
  1764. rplacd(env, nbvl);
  1765. if fluids then <<
  1766. fl1 := s!:vecof fl1;
  1767. s!:outopcode1lit('FREEBIND, fl1, env);
  1768. for each v in nil . fluids do rplacd(env, 0 . cdr env);
  1769. % The number in the environment map where a variable name would more
  1770. % normally be wanted marks a place where free variables are saved. It
  1771. % indicates how many stack locations are used by the free variable save block.
  1772. rplacd(env, (2 + length fluids) . cdr env);
  1773. for each v in fluids do
  1774. s!:comval(list('setq, car v, cdr v), env, 2) >>;
  1775. w := s!:residual_local_decs(local_decs, w);
  1776. % I use a context of 1 here (value needed) regardless of where I am. It avoids
  1777. % program context filtering down into embedded lambdas.
  1778. s!:comval(body, env, 1);
  1779. s!:cancel_local_decs w;
  1780. if fluids then s!:outopcode0('FREERSTR, '(FREERSTR));
  1781. s!:outlose length bvl;
  1782. rplacd(env, s)
  1783. end;
  1784. symbolic procedure s!:loadliteral(x, env);
  1785. if member!*!*(list('quote, x), s!:a_reg_values) then nil
  1786. else <<
  1787. if x = nil then s!:outopcode0('VNIL, '(loadlit nil))
  1788. else s!:outopcode1lit('LOADLIT, x, env);
  1789. s!:a_reg_values := list list('quote, x) >>;
  1790. symbolic procedure s!:comquote(x, env, context);
  1791. if context <= 1 then s!:loadliteral(cadr x, env);
  1792. put('quote, 's!:compfn, function s!:comquote);
  1793. fluid '(s!:current_exitlab s!:current_proglabels s!:local_macros);
  1794. !#if common!-lisp!-mode
  1795. symbolic procedure s!:comval_m(x, env, context, s!:local_macros);
  1796. s!:comval(x, env, context);
  1797. symbolic procedure s!:comflet(x, env, context);
  1798. begin
  1799. scalar w, r, g, save;
  1800. save := cdr env;
  1801. for each d in cadr x do <<
  1802. g := gensym();
  1803. s!:comval(list('function, 'lambda . cdr d), env, context);
  1804. s!:outopcode0('PUSH, '(PUSH));
  1805. rplacd(env, g . cdr env);
  1806. r := (car d . g) . r >>;
  1807. s!:comval_m('progn . cddr x, env, context, append(r, s!:local_macros));
  1808. s!:outlose length cadr x;
  1809. rplacd(env, save)
  1810. end;
  1811. put('flet, 's!:compfn, function s!:comflet);
  1812. symbolic procedure s!:comlabels(x, env, context);
  1813. begin
  1814. scalar w, w1, r, g;
  1815. for each d in cadr x do <<
  1816. g := gensym();
  1817. w := list('setq, g, list('function, 'lambda . cdr d)) . w;
  1818. w1 := list g . w1;
  1819. r := (car d . g) . r >>;
  1820. x := 'let . reverse w1 . append(w, cddr x);
  1821. return s!:comval_m(x, env, context, append(r, s!:local_macros))
  1822. end;
  1823. put('labels, 's!:compfn, function s!:comlabels);
  1824. symbolic procedure s!:commacrolet(x, env, context);
  1825. s!:comval_m('progn . cddr x, env, context,
  1826. append(cadr x, s!:local_macros));
  1827. put('macrolet, 's!:compfn, function s!:commacrolet);
  1828. symbolic procedure s!:local_macro fn;
  1829. begin
  1830. scalar w, y;
  1831. w := list(nil, nil, nil, s!:local_macros) . s!:lexical_env;
  1832. while w do <<
  1833. y := atsoc(fn, cadddr car w);
  1834. if y then w := nil else w := cdr w >>;
  1835. return y
  1836. end;
  1837. !#endif
  1838. symbolic procedure s!:comfunction(x, env, context);
  1839. if context <= 1 then
  1840. << x := cadr x;
  1841. if eqcar(x, 'lambda) then begin
  1842. scalar g, w, s!:used_lexicals;
  1843. s!:has_closure := t;
  1844. % I base the name used on the current date, which probably makes
  1845. % it hard to have clashes.
  1846. g := hashtagged!-name('lambda, cdr x);
  1847. % If I find an expression (FUNCTION (LAMBDA ...)) I will create a lexical
  1848. % closure. In other cases FUNCTION behaves just like QUOTE.
  1849. w := s!:compile1(g, cadr x, cddr x,
  1850. list(cdr env, s!:current_exitlab,
  1851. s!:current_proglabels, s!:local_macros) .
  1852. s!:lexical_env);
  1853. if s!:used_lexicals then
  1854. w := s!:compile1(g, gensym() . cadr x, cddr x,
  1855. list(cdr env, s!:current_exitlab,
  1856. s!:current_proglabels, s!:local_macros) .
  1857. s!:lexical_env);
  1858. s!:other_defs := append(w, s!:other_defs);
  1859. s!:loadliteral(g, env);
  1860. w := length cdr env;
  1861. if s!:used_lexicals then <<
  1862. % If the lambda expression did not use any non-local lexical references
  1863. % then it does not need a closure, so I can load its value slightly more
  1864. % efficiently and also permit tal=il-call optimisation in the function
  1865. % that loads it.
  1866. s!:has_closure := t;
  1867. if w > 4095 then error "stack frame > 4095"
  1868. else if w > 255 then
  1869. s!:outopcode2('BIGSTACK, 128+truncate(w,256), logand(w, 255),
  1870. list('CLOSURE, w))
  1871. else s!:outopcode1('CLOSURE, w, x) >> end
  1872. !#if common!-lisp!-mode
  1873. else if context := s!:local_macro x then <<
  1874. if atom cdr context then s!:comatom(cdr context, env, 1)
  1875. else error(0, "(function <local macro>) is illegal") >>
  1876. !#endif
  1877. else s!:loadliteral(x, env) >>;
  1878. put('function, 's!:compfn, function s!:comfunction);
  1879. symbolic procedure s!:should_be_fluid x;
  1880. if not (fluidp x or globalp x) then <<
  1881. if !*pwrds then << % The !*pwrds flag controls this verbosity too
  1882. if posn() neq 0 then terpri();
  1883. princ "+++ ";
  1884. prin x;
  1885. !#if common!-lisp!-mode
  1886. princ " treated as if locally SPECIAL";
  1887. !#else
  1888. princ " declared fluid";
  1889. !#endif
  1890. terpri() >>;
  1891. !#if (not common!-lisp!-mode)
  1892. fluid list x;
  1893. !#endif
  1894. nil >>;
  1895. symbolic procedure s!:find_lexical(x, lex, n);
  1896. begin
  1897. scalar p;
  1898. if null lex then return nil;
  1899. p := memq(x, caar lex);
  1900. if p then <<
  1901. if not memq(x, s!:used_lexicals) then
  1902. s!:used_lexicals := x . s!:used_lexicals;
  1903. return list(n, length p) >>
  1904. else return s!:find_lexical(x, cdr lex, n+1)
  1905. end;
  1906. global '(s!:loadlocs);
  1907. s!:loadlocs := s!:vecof '(LOADLOC0 LOADLOC1 LOADLOC2 LOADLOC3
  1908. LOADLOC4 LOADLOC5 LOADLOC6 LOADLOC7
  1909. LOADLOC8 LOADLOC9 LOADLOC10 LOADLOC11);
  1910. symbolic procedure s!:comatom(x, env, context);
  1911. begin
  1912. scalar n, w;
  1913. if context > 1 then return nil
  1914. else if null x or not symbolp x then return s!:loadliteral(x, env);
  1915. !#if common!-lisp!-mode
  1916. if keywordp x then return s!:loadliteral(x, env);
  1917. !#endif
  1918. n := 0;
  1919. w := cdr env;
  1920. while w and not eqcar(w, x) do << n := add1 n; w := cdr w >>;
  1921. if w then <<
  1922. w := 'loc . w;
  1923. if member!*!*(w, s!:a_reg_values) then return nil
  1924. else <<
  1925. if n < 12 then s!:outopcode0(getv(s!:loadlocs, n),
  1926. list('LOADLOC, x))
  1927. else if n > 4095 then error "stack frame > 4095"
  1928. else if n > 255 then
  1929. s!:outopcode2('BIGSTACK, truncate(n,256),
  1930. logand(n, 255), list('LOADLOC, x))
  1931. else s!:outopcode1('LOADLOC, n, x);
  1932. s!:a_reg_values := list w;
  1933. return nil >> >>;
  1934. if w := s!:find_lexical(x, s!:lexical_env, 0) then <<
  1935. if member!*!*('lex . w, s!:a_reg_values) then return nil;
  1936. s!:outlexref('LOADLEX, length cdr env, car w, cadr w, x);
  1937. s!:a_reg_values := list('lex . w);
  1938. return nil >>;
  1939. s!:should_be_fluid x;
  1940. if flagp(x, 'constant!?) then return s!:loadliteral(eval x, env);
  1941. w := 'free . x;
  1942. if member!*!*(w, s!:a_reg_values) then return nil;
  1943. s!:outopcode1lit('LOADFREE, x, env);
  1944. s!:a_reg_values := list w
  1945. end;
  1946. flag('(t !$EOL!$ !$EOF!$), 'constant!?);
  1947. symbolic procedure s!:islocal(x, env);
  1948. % Returns a small integer if x is a local variable in the current environment.
  1949. % return 99999 otherwise. Yes I know that 99999 is a silly value to use.
  1950. begin
  1951. scalar n, w;
  1952. if null x or not symbolp x or x eq t then return 99999;
  1953. n := 0;
  1954. w := cdr env;
  1955. while w and not eqcar(w, x) do << n := add1 n; w := cdr w >>;
  1956. if w then return n
  1957. else return 99999
  1958. end;
  1959. symbolic procedure s!:load2(a, b, env);
  1960. % s!:load2(a,b,env) calls s!:comval on a and then on b, so that
  1961. % a end up in the B register and b ends up in the A register(!).
  1962. % If processing b would corrupt the pre-loaded value of a it is
  1963. % necessary to issue PUSH and POP operations.
  1964. % If a final SWOP is needed then this returns T, otherwise NIL
  1965. <<
  1966. if s!:iseasy b then begin
  1967. scalar wa, wb, w;
  1968. wa := s!:islocal(a, env);
  1969. wb := s!:islocal(b, env);
  1970. if wa < 4 and wb < 4 then <<
  1971. if wa = 0 and wb = 1 then w := 'LOC0LOC1
  1972. else if wa = 1 and wb = 2 then w := 'LOC1LOC2
  1973. else if wa = 2 and wb = 3 then w := 'LOC2LOC3
  1974. else if wa = 1 and wb = 0 then w := 'LOC1LOC0
  1975. else if wa = 2 and wb = 1 then w := 'LOC2LOC1
  1976. else if wa = 3 and wb = 2 then w := 'LOC3LOC2;
  1977. if w then <<
  1978. s!:outopcode0(w, list('LOCLOC, a, b));
  1979. return nil >> >>;
  1980. s!:comval(a, env, 1);
  1981. s!:a_reg_values := nil;
  1982. s!:comval(b, env, 1);
  1983. return nil end
  1984. !#if common!-lisp!-mode
  1985. % For Common Lisp it seems that I *must* evaluate args strictly left-to-right.
  1986. % I can violate this rule if the item I move in evaluation order is something
  1987. % which has an utterly constant value.
  1988. else if numberp a or
  1989. stringp a or
  1990. keywordp a or
  1991. eqcar(a, 'quote) then <<
  1992. s!:comval(b, env, 1);
  1993. s!:a_reg_values := nil;
  1994. s!:comval(a, env, 1);
  1995. t >>
  1996. else <<
  1997. s!:comval(a, env, 1);
  1998. s!:outopcode0('PUSH, '(PUSH));
  1999. rplacd(env, 0 . cdr env);
  2000. s!:a_reg_values := nil;
  2001. s!:comval(b, env, 1);
  2002. s!:outopcode0('POP, '(POP));
  2003. rplacd(env, cddr env);
  2004. t >>
  2005. !#else
  2006. % Here, in Standard Lisp mode, I will compile the arguments left to right
  2007. % if !*ord is set. Otherwise in the cases that get down here I can save
  2008. % some generated code (and hence bot time and space) by working right
  2009. % to left.
  2010. else if !*ord then <<
  2011. s!:comval(a, env, 1);
  2012. s!:outopcode0('PUSH, '(PUSH));
  2013. rplacd(env, 0 . cdr env);
  2014. s!:a_reg_values := nil;
  2015. s!:comval(b, env, 1);
  2016. s!:outopcode0('POP, '(POP));
  2017. rplacd(env, cddr env);
  2018. t >>
  2019. else if s!:iseasy a then <<
  2020. s!:comval(b, env, 1);
  2021. s!:a_reg_values := nil;
  2022. s!:comval(a, env, 1);
  2023. t >>
  2024. else <<
  2025. s!:comval(b, env, 1); % b is a complicated expression here
  2026. s!:outopcode0('PUSH, '(PUSH));
  2027. rplacd(env, 0 . cdr env);
  2028. s!:a_reg_values := nil;
  2029. s!:comval(a, env, 1);
  2030. s!:outopcode0('POP, '(POP));
  2031. rplacd(env, cddr env); % this case saves a SWAP afterwards
  2032. nil >>
  2033. !#endif
  2034. >>;
  2035. global '(s!:carlocs s!:cdrlocs s!:caarlocs);
  2036. s!:carlocs := s!:vecof '(CARLOC0 CARLOC1 CARLOC2 CARLOC3
  2037. CARLOC4 CARLOC5 CARLOC6 CARLOC7
  2038. CARLOC8 CARLOC9 CARLOC10 CARLOC11);
  2039. s!:cdrlocs := s!:vecof '(CDRLOC0 CDRLOC1 CDRLOC2 CDRLOC3
  2040. CDRLOC4 CDRLOC5);
  2041. s!:caarlocs := s!:vecof '(CAARLOC0 CAARLOC1 CAARLOC2 CAARLOC3);
  2042. flag('(plus2 times2 eq equal), 's!:symmetric);
  2043. flag('(car cdr caar cadr cdar cddr
  2044. ncons add1 sub1 numberp length), 's!:onearg);
  2045. flag('(cons xcons list2 get flagp plus2 difference times2
  2046. greaterp lessp apply1 eq equal getv qgetv eqcar), 's!:twoarg);
  2047. flag('(apply2 list2!* list3 acons), 's!:threearg);
  2048. % The case of APPLY3 is handled by in-line code rather than a general flag,
  2049. % but I leave the flag statement here as a reminder that it is present as a
  2050. % special case. There is a byte-code allocated for APPLY4, but at present
  2051. % the compiler never generates it and the bytecode interpreter does not
  2052. % implement it. It is reserved in case that sort of use of APPLY/FUNCALL
  2053. % proves sufficiently important.
  2054. % flag('(apply3), 's!:fourarg);
  2055. % flag('(apply4), 's!:fivearg);
  2056. symbolic procedure s!:comcall(x, env, context);
  2057. % generate a procedure call - different CALL instructions
  2058. % and formats are used for different numbers of arguments.
  2059. begin
  2060. scalar fn, args, nargs, op, s, w1, w2, w3, sw;
  2061. fn := car x;
  2062. args := for each v in cdr x collect s!:improve v;
  2063. nargs := length args;
  2064. % Standard Lisp only allows 15 arguments. CSL supports 20 just
  2065. % to be on the safe side, but it tells the programmer when the lower
  2066. % limit is violated. Common Lisp can cope with rather more args, but I
  2067. % will still let people know if I think they have gone over the top.
  2068. if nargs > 15 and !*pwrds then <<
  2069. if posn() neq 0 then terpri();
  2070. princ "+++ ";
  2071. prin fn;
  2072. princ " called with ";
  2073. prin nargs;
  2074. princ " from function ";
  2075. prin s!:current_function;
  2076. terpri() >>;
  2077. s := cdr env;
  2078. if nargs = 0 then
  2079. if (w2 := get(fn, 's!:builtin0)) then s!:outopcode1('BUILTIN0, w2, fn)
  2080. else s!:outopcode1lit('CALL0, fn, env)
  2081. else if nargs = 1 then <<
  2082. if fn = 'car and
  2083. (w2 := s!:islocal(car args, env)) < 12 then
  2084. s!:outopcode0(getv(s!:carlocs, w2), list('carloc, car args))
  2085. else if fn = 'cdr and
  2086. (w2 := s!:islocal(car args, env)) < 6 then
  2087. s!:outopcode0(getv(s!:cdrlocs, w2), list('cdrloc, car args))
  2088. else if fn = 'caar and
  2089. (w2 := s!:islocal(car args, env)) < 4 then
  2090. s!:outopcode0(getv(s!:caarlocs, w2), list('caarloc, car args))
  2091. else <<
  2092. s!:comval(car args, env, 1);
  2093. if flagp(fn, 's!:onearg) then s!:outopcode0(fn, list fn)
  2094. else if (w2 := get(fn, 's!:builtin1)) then
  2095. s!:outopcode1('BUILTIN1, w2, fn)
  2096. else s!:outopcode1lit('CALL1, fn, env) >> >>
  2097. else if nargs = 2 then <<
  2098. sw := s!:load2(car args, cadr args, env);
  2099. if flagp(fn, 's!:symmetric) then sw := nil;
  2100. if flagp(fn, 's!:twoarg) then <<
  2101. if sw then s!:outopcode0('SWOP, '(SWOP));
  2102. s!:outopcode0(fn, list fn) >>
  2103. else <<
  2104. w3 := get(fn, 's!:builtin2);
  2105. if sw then <<
  2106. if w3 then s!:outopcode1('BUILTIN2R, w3, fn)
  2107. else s!:outopcode1lit('CALL2R, fn, env) >>
  2108. else if w3 then s!:outopcode1('BUILTIN2, w3, fn)
  2109. else s!:outopcode1lit('CALL2, fn, env) >> >>
  2110. else if nargs = 3 then <<
  2111. if car args = nil then s!:outstack 1
  2112. else <<
  2113. s!:comval(car args, env, 1);
  2114. s!:outopcode0('PUSH, '(PUSHA3)) >>;
  2115. rplacd(env, 0 . cdr env);
  2116. s!:a_reg_values := nil;
  2117. if s!:load2(cadr args, caddr args, env) then
  2118. s!:outopcode0('SWOP, '(SWOP));
  2119. if flagp(fn, 's!:threearg) then
  2120. s!:outopcode0(if fn = 'list2!* then 'list2star else fn, list fn)
  2121. else if w2 := get(fn, 's!:builtin3) then
  2122. s!:outopcode1('BUILTIN3, w2, fn)
  2123. else s!:outopcode1lit('CALL3, fn, env);
  2124. rplacd(env, cddr env) >>
  2125. else begin
  2126. % Functions with 4 or more arguments are called by pushing all their
  2127. % arguments onto the stack. I expect that this will not be a common case.
  2128. scalar largs;
  2129. largs := reverse args;
  2130. for each a in reverse cddr largs do <<
  2131. if null a then s!:outstack 1
  2132. else <<
  2133. s!:comval(a, env, 1);
  2134. if nargs = 4 then s!:outopcode0('PUSH, '(PUSHA4))
  2135. else s!:outopcode0('PUSH, '(PUSHARG)) >>;
  2136. rplacd(env, 0 . cdr env);
  2137. s!:a_reg_values := nil >>;
  2138. if s!:load2(cadr largs, car largs, env) then
  2139. s!:outopcode0('SWOP, '(SWOP));
  2140. if fn = 'apply3 and nargs = 4 then s!:outopcode0('APPLY3, '(APPLY3))
  2141. % else if fn = 'apply4 and nargs = 5 then % Not yet implemented.
  2142. % s!:outopcode0('APPLY4, '(APPLY4));
  2143. else if nargs > 255 then error("Over 255 args in a function call")
  2144. else s!:outopcode2lit('CALLN, fn, nargs, list(nargs, fn), env);
  2145. rplacd(env, s) end
  2146. end;
  2147. % caaar to cddddr get expanded into compositions of
  2148. % car, cdr, caar, cadr, cdar and cddr - which in turn get
  2149. % compiled into direct bytecodes
  2150. symbolic procedure s!:ad_name l;
  2151. if car l = 'a then
  2152. if cadr l = 'a then 'caar else 'cadr
  2153. else if cadr l = 'a then 'cdar else 'cddr;
  2154. symbolic procedure s!:comcarcdr3(x, env, context);
  2155. begin
  2156. scalar name, outer, c1, c2;
  2157. name := cdr explode2 car x;
  2158. % Turns (eg) (caddr x) into (cadr (cdr x))
  2159. x := list(s!:ad_name name,
  2160. list(if caddr name = 'a then 'car else 'cdr, cadr x));
  2161. return s!:comval(x, env, context)
  2162. end;
  2163. put('caaar, 's!:compfn, function s!:comcarcdr3);
  2164. put('caadr, 's!:compfn, function s!:comcarcdr3);
  2165. put('cadar, 's!:compfn, function s!:comcarcdr3);
  2166. put('caddr, 's!:compfn, function s!:comcarcdr3);
  2167. put('cdaar, 's!:compfn, function s!:comcarcdr3);
  2168. put('cdadr, 's!:compfn, function s!:comcarcdr3);
  2169. put('cddar, 's!:compfn, function s!:comcarcdr3);
  2170. put('cdddr, 's!:compfn, function s!:comcarcdr3);
  2171. symbolic procedure s!:comcarcdr4(x, env, context);
  2172. begin
  2173. scalar name, outer, c1, c2;
  2174. name := cdr explode2 car x;
  2175. x := list(s!:ad_name name, list(s!:ad_name cddr name, cadr x));
  2176. return s!:comval(x, env, context)
  2177. end;
  2178. put('caaaar, 's!:compfn, function s!:comcarcdr4);
  2179. put('caaadr, 's!:compfn, function s!:comcarcdr4);
  2180. put('caadar, 's!:compfn, function s!:comcarcdr4);
  2181. put('caaddr, 's!:compfn, function s!:comcarcdr4);
  2182. put('cadaar, 's!:compfn, function s!:comcarcdr4);
  2183. put('cadadr, 's!:compfn, function s!:comcarcdr4);
  2184. put('caddar, 's!:compfn, function s!:comcarcdr4);
  2185. put('cadddr, 's!:compfn, function s!:comcarcdr4);
  2186. put('cdaaar, 's!:compfn, function s!:comcarcdr4);
  2187. put('cdaadr, 's!:compfn, function s!:comcarcdr4);
  2188. put('cdadar, 's!:compfn, function s!:comcarcdr4);
  2189. put('cdaddr, 's!:compfn, function s!:comcarcdr4);
  2190. put('cddaar, 's!:compfn, function s!:comcarcdr4);
  2191. put('cddadr, 's!:compfn, function s!:comcarcdr4);
  2192. put('cdddar, 's!:compfn, function s!:comcarcdr4);
  2193. put('cddddr, 's!:compfn, function s!:comcarcdr4);
  2194. % The next chunk is commented out - the "carcheck" flag was at one stage
  2195. % there so that *carcheckflag = nil would cause compilation to give
  2196. % unchecked car/cdr access, which ought to be faster. However with the
  2197. % bytecode interpreter model I dedicate plenty of opcodes to regular car and
  2198. % cdr combinations, while unchecked car is supported in a rather simpler
  2199. % way, so the small savings in missing out the check are outweighed by the
  2200. % extra overheads of invoking the unchecked operation!
  2201. % I leave the flag there and cause it to map vector access (getv in Standard
  2202. % lisp and svref in Common Lisp) into a cheaper version that omits checking.
  2203. % This is more profitable becase (a) I do less in the bytecode model to make
  2204. % getv special, and (b) the overheads on array bound checking are greater
  2205. % than those for car/cdr chaining.
  2206. % symbolic procedure s!:comcar(x, env, context);
  2207. % if !*carcheckflag then s!:comcall(x, env, context)
  2208. % else s!:comval('qcar . cdr x, env, context);
  2209. %
  2210. % put('car, 's!:compfn, function s!:comcar);
  2211. %
  2212. % symbolic procedure s!:comcdr(x, env, context);
  2213. % if !*carcheckflag then s!:comcall(x, env, context)
  2214. % else s!:comval('qcdr . cdr x, env, context);
  2215. %
  2216. % put('cdr, 's!:compfn, function s!:comcdr);
  2217. %
  2218. % symbolic procedure s!:comcaar(x, env, context);
  2219. % if !*carcheckflag then s!:comcall(x, env, context)
  2220. % else s!:comval('qcaar . cdr x, env, context);
  2221. %
  2222. % put('caar, 's!:compfn, function s!:comcaar);
  2223. %
  2224. % symbolic procedure s!:comcadr(x, env, context);
  2225. % if !*carcheckflag then s!:comcall(x, env, context)
  2226. % else s!:comval('qcadr . cdr x, env, context);
  2227. %
  2228. % put('cadr, 's!:compfn, function s!:comcadr);
  2229. %
  2230. % symbolic procedure s!:comcdar(x, env, context);
  2231. % if !*carcheckflag then s!:comcall(x, env, context)
  2232. % else s!:comval('qcdar . cdr x, env, context);
  2233. %
  2234. % put('cdar, 's!:compfn, function s!:comcdar);
  2235. %
  2236. % symbolic procedure s!:comcddr(x, env, context);
  2237. % if !*carcheckflag then s!:comcall(x, env, context)
  2238. % else s!:comval('qcddr . cdr x, env, context);
  2239. %
  2240. % put('cddr, 's!:compfn, function s!:comcddr);
  2241. symbolic procedure s!:comgetv(x, env, context);
  2242. if !*carcheckflag then s!:comcall(x, env, context)
  2243. else s!:comval('qgetv . cdr x, env, context);
  2244. put('getv, 's!:compfn, function s!:comgetv);
  2245. symbolic procedure s!:comqgetv(x, env, context);
  2246. if fixp caddr x and caddr x >= 0 and caddr x < 256 then <<
  2247. s!:comval(cadr x, env, 1);
  2248. s!:outopcode1('QGETVN, caddr x, caddr x) >>
  2249. else s!:comcall(x, env, context);
  2250. put('qgetv, 's!:compfn, function s!:comqgetv);
  2251. symbolic procedure s!:comget(x, env, context);
  2252. begin
  2253. scalar a, b, c, w;
  2254. a := cadr x;
  2255. b := caddr x;
  2256. c := cdddr x;
  2257. if eqcar(b, 'quote) then <<
  2258. b := cadr b;
  2259. w := symbol!-make!-fastget(b, nil);
  2260. if c then <<
  2261. if w then <<
  2262. if s!:load2(a, b, env) then
  2263. s!:outopcode0('SWOP, '(SWOP));
  2264. s!:outopcode1('FASTGET, logor(w, 64), b) >>
  2265. else s!:comcall(x, env, context) >>
  2266. else <<
  2267. s!:comval(a, env, 1);
  2268. if w then s!:outopcode1('FASTGET, w, b)
  2269. else s!:outopcode1lit('LITGET, b, env) >> >>
  2270. else s!:comcall(x, env, context)
  2271. end;
  2272. put('get, 's!:compfn, function s!:comget);
  2273. symbolic procedure s!:comflagp(x, env, context);
  2274. begin
  2275. scalar a, b;
  2276. a := cadr x;
  2277. b := caddr x;
  2278. if eqcar(b, 'quote) then <<
  2279. b := cadr b;
  2280. s!:comval(a, env, 1);
  2281. a := symbol!-make!-fastget(b, nil);
  2282. if a then s!:outopcode1('FASTGET, logor(a, 128), b)
  2283. else s!:comcall(x, env, context) >>
  2284. else s!:comcall(x, env, context)
  2285. end;
  2286. put('flagp, 's!:compfn, function s!:comflagp);
  2287. % plus and times (and later on, I guess, logand, logor and a few more)
  2288. % get macroexpanded into calls to two-argument versions of the same
  2289. % operators.
  2290. symbolic procedure s!:complus(x, env, context);
  2291. s!:comval(expand(cdr x, 'plus2), env, context);
  2292. put('plus, 's!:compfn, function s!:complus);
  2293. !#if common!-lisp!-mode
  2294. put('!+, 's!:compfn, function s!:complus);
  2295. !#endif
  2296. symbolic procedure s!:comtimes(x, env, context);
  2297. s!:comval(expand(cdr x, 'times2), env, context);
  2298. put('times, 's!:compfn, function s!:comtimes);
  2299. !#if common!-lisp!-mode
  2300. put('!*, 's!:compfn, function s!:comtimes);
  2301. !#endif
  2302. symbolic procedure s!:comiplus(x, env, context);
  2303. s!:comval(expand(cdr x, 'iplus2), env, context);
  2304. put('iplus, 's!:compfn, function s!:comiplus);
  2305. symbolic procedure s!:comitimes(x, env, context);
  2306. s!:comval(expand(cdr x, 'itimes2), env, context);
  2307. put('itimes, 's!:compfn, function s!:comitimes);
  2308. symbolic procedure s!:complus2(x, env, context);
  2309. begin
  2310. scalar a, b;
  2311. a := s!:improve cadr x;
  2312. b := s!:improve caddr x;
  2313. return if numberp a and numberp b then s!:comval(a+b, env, context)
  2314. else if a = 0 then s!:comval(b, env, context)
  2315. else if a = 1 then s!:comval(list('add1, b), env, context)
  2316. else if b = 0 then s!:comval(a, env, context)
  2317. else if b = 1 then s!:comval(list('add1, a), env, context)
  2318. else if b = -1 then s!:comval(list('sub1, a), env, context)
  2319. else s!:comcall(x, env, context)
  2320. end;
  2321. put('plus2, 's!:compfn, function s!:complus2);
  2322. symbolic procedure s!:comdifference(x, env, context);
  2323. begin
  2324. scalar a, b;
  2325. a := s!:improve cadr x;
  2326. b := s!:improve caddr x;
  2327. return if numberp a and numberp b then s!:comval(a-b, env, context)
  2328. else if a = 0 then s!:comval(list('minus, b), env, context)
  2329. else if b = 0 then s!:comval(a, env, context)
  2330. else if b = 1 then s!:comval(list('sub1, a), env, context)
  2331. else if b = -1 then s!:comval(list('add1, a), env, context)
  2332. else s!:comcall(x, env, context)
  2333. end;
  2334. put('difference, 's!:compfn, function s!:comdifference);
  2335. symbolic procedure s!:comiplus2(x, env, context);
  2336. begin
  2337. scalar a, b;
  2338. a := s!:improve cadr x;
  2339. b := s!:improve caddr x;
  2340. return if numberp a and numberp b then s!:comval(a+b, env, context)
  2341. else if a = 1 then s!:comval(list('iadd1, b), env, context)
  2342. else if b = 1 then s!:comval(list('iadd1, a), env, context)
  2343. else if b = -1 then s!:comval(list('isub1, a), env, context)
  2344. else s!:comcall(x, env, context)
  2345. end;
  2346. put('iplus2, 's!:compfn, function s!:comiplus2);
  2347. symbolic procedure s!:comidifference(x, env, context);
  2348. begin
  2349. scalar a, b;
  2350. a := s!:improve cadr x;
  2351. b := s!:improve caddr x;
  2352. return if numberp a and numberp b then s!:comval(a-b, env, context)
  2353. else if b = 1 then s!:comval(list('isub1, a), env, context)
  2354. else if b = -1 then s!:comval(list('iadd1, a), env, context)
  2355. else s!:comcall(x, env, context)
  2356. end;
  2357. put('idifference, 's!:compfn, function s!:comidifference);
  2358. symbolic procedure s!:comtimes2(x, env, context);
  2359. begin
  2360. scalar a, b;
  2361. a := s!:improve cadr x;
  2362. b := s!:improve caddr x;
  2363. return if numberp a and numberp b then s!:comval(a*b, env, context)
  2364. else if a = 1 then s!:comval(b, env, context)
  2365. else if a = -1 then s!:comval(list('minus, b), env, context)
  2366. else if b = 1 then s!:comval(a, env, context)
  2367. else if b = -1 then s!:comval(list('minus, a), env, context)
  2368. else s!:comcall(x, env, context)
  2369. end;
  2370. put('times2, 's!:compfn, function s!:comtimes2);
  2371. put('itimes2, 's!:compfn, function s!:comtimes2);
  2372. symbolic procedure s!:comminus(x, env, context);
  2373. begin
  2374. scalar a, b;
  2375. a := s!:improve cadr x;
  2376. return if numberp a then s!:comval(-a, env, context)
  2377. else if eqcar(a, 'minus) then s!:comval(cadr a, env, context)
  2378. else s!:comcall(x, env, context)
  2379. end;
  2380. put('minus, 's!:compfn, function s!:comminus);
  2381. symbolic procedure s!:comminusp(x, env, context);
  2382. begin
  2383. scalar a;
  2384. a := s!:improve cadr x;
  2385. if eqcar(a, 'difference) then return
  2386. s!:comval('lessp . cdr a, env, context)
  2387. else return s!:comcall(x, env, context)
  2388. end;
  2389. put('minusp, 's!:compfn, function s!:comminusp);
  2390. symbolic procedure s!:comlessp(x, env, context);
  2391. begin
  2392. scalar a, b;
  2393. a := s!:improve cadr x;
  2394. b := s!:improve caddr x;
  2395. if b = 0 then return
  2396. s!:comval(list('minusp, a), env, context)
  2397. else return s!:comcall(x, env, context)
  2398. end;
  2399. put('lessp, 's!:compfn, function s!:comlessp);
  2400. symbolic procedure s!:comiminusp(x, env, context);
  2401. begin
  2402. scalar a;
  2403. a := s!:improve cadr x;
  2404. if eqcar(a, 'difference) then return
  2405. s!:comval('ilessp . cdr a, env, context)
  2406. else return s!:comcall(x, env, context)
  2407. end;
  2408. put('iminusp, 's!:compfn, function s!:comiminusp);
  2409. symbolic procedure s!:comilessp(x, env, context);
  2410. begin
  2411. scalar a, b;
  2412. a := s!:improve cadr x;
  2413. b := s!:improve caddr x;
  2414. if b = 0 then return
  2415. s!:comval(list('iminusp, a), env, context)
  2416. else return s!:comcall(x, env, context)
  2417. end;
  2418. put('ilessp, 's!:compfn, function s!:comilessp);
  2419. % s!:comprogn is used not only when I see an explicit progn in the
  2420. % code, but to handle the implicit ones in cond and after lambda.
  2421. % it switches evaluation mode to a void context for all but the
  2422. % last expression
  2423. symbolic procedure s!:comprogn(x, env, context);
  2424. << x := cdr x;
  2425. if null x then s!:comval(nil, env, context)
  2426. else begin
  2427. scalar a;
  2428. a := car x;
  2429. while x := cdr x do <<
  2430. s!:comval(a, env, if context >= 4 then context else 2);
  2431. a := car x >>;
  2432. s!:comval(a, env, context)
  2433. end
  2434. >>;
  2435. put('progn, 's!:compfn, function s!:comprogn);
  2436. symbolic procedure s!:comprog1(x, env, context);
  2437. begin
  2438. x := cdr x;
  2439. if null x then return s!:comval(nil, env, context);
  2440. s!:comval(car x, env, context);
  2441. if null (x := cdr x) then return nil;
  2442. s!:outopcode0('PUSH, '(PUSH));
  2443. rplacd(env, 0 . cdr env);
  2444. for each a in x do
  2445. s!:comval(a, env, if context >= 4 then context else 2);
  2446. s!:outopcode0('POP, '(POP));
  2447. rplacd(env, cddr env)
  2448. end;
  2449. put('prog1, 's!:compfn, function s!:comprog1);
  2450. symbolic procedure s!:comprog2(x, env, context);
  2451. begin
  2452. scalar a;
  2453. x := cdr x;
  2454. if null x then return s!:comval(nil, env, context);
  2455. a := car x;
  2456. s!:comval(a, env, if context >= 4 then context else 2);
  2457. s!:comprog1(x, env, context)
  2458. end;
  2459. put('prog2, 's!:compfn, function s!:comprog2);
  2460. !#if common!-lisp!-mode
  2461. % REDUCE seems to introduce a function called IDENTITY that is not quite this
  2462. % one. Shame! hence only do this in Common mode.
  2463. symbolic procedure s!:comidentity(x, env, context);
  2464. s!:comval(cadr x, env, context);
  2465. put('identity, 's!:compfn, function s!:comidentity);
  2466. !#endif
  2467. symbolic procedure s!:outstack n;
  2468. begin
  2469. scalar w, a;
  2470. w := s!:current_block;
  2471. while w and not atom car w do w := cdr w;
  2472. if eqcar(w, 'PUSHNIL) then a := 1
  2473. else if eqcar(w, 'PUSHNIL2) then a := 2
  2474. else if eqcar(w, 'PUSHNIL3) then a := 3
  2475. % If I has a "PUSHNILS 255" already issued it would do no good at all
  2476. % to pick it off here and attempt to consolidate it with a further PUSH.
  2477. % Indeed that would probably lead to disaster.
  2478. else if w and numberp (a := car w) and not (a = 255) and
  2479. eqcar(cdr w, 'PUSHNILS) then <<
  2480. w := cdr w;
  2481. s!:current_size := s!:current_size - 1 >>
  2482. else a := nil;
  2483. if a then <<
  2484. s!:current_block := cdr w;
  2485. s!:current_size := s!:current_size - 1;
  2486. n := n + a >>;
  2487. if n = 1 then s!:outopcode0('PUSHNIL, '(PUSHNIL))
  2488. else if n = 2 then s!:outopcode0('PUSHNIL2, '(PUSHNIL2))
  2489. else if n = 3 then s!:outopcode0('PUSHNIL3, '(PUSHNIL3))
  2490. else if n > 255 then <<
  2491. s!:outopcode1('PUSHNILS, 255, 255);
  2492. s!:outstack(n-255) >>
  2493. else if n > 3 then s!:outopcode1('PUSHNILS, n, n)
  2494. end;
  2495. symbolic procedure s!:outlose n;
  2496. begin
  2497. scalar w, a;
  2498. w := s!:current_block;
  2499. while w and not atom car w do w := cdr w;
  2500. if eqcar(w, 'LOSE) then a := 1
  2501. else if eqcar(w, 'LOSE2) then a := 2
  2502. else if eqcar(w, 'LOSE3) then a := 3
  2503. else if w and numberp (a := car w) and not (a = 255) and
  2504. eqcar(cdr w, 'LOSES) then <<
  2505. w := cdr w;
  2506. s!:current_size := s!:current_size - 1 >>
  2507. else a := nil;
  2508. if a then <<
  2509. s!:current_block := cdr w;
  2510. s!:current_size := s!:current_size - 1;
  2511. n := n + a >>;
  2512. if n = 1 then s!:outopcode0('LOSE, '(LOSE))
  2513. else if n = 2 then s!:outopcode0('LOSE2, '(LOSE2))
  2514. else if n = 3 then s!:outopcode0('LOSE3, '(LOSE3))
  2515. else if n > 255 then <<
  2516. s!:outopcode1('LOSES, 255, 255);
  2517. s!:outlose(n-255) >>
  2518. else if n > 3 then s!:outopcode1('LOSES, n, n)
  2519. end;
  2520. !#if (not common!-lisp!-mode)
  2521. % s!:comprog displays how much fun prog blocks are, in that it has to
  2522. % prepare support for go statements and returns, and it needs to
  2523. % handle fluid bindings. The version here does not handle initialising forms
  2524. % (as required by Common Lisp) but in that case a macro that turns
  2525. % prog into a combination of BLOCK, LET and TAGBODY is used, so there is
  2526. % no serious loss. Similarly PROG* is handled by macroexpansion rather
  2527. % than a variant on this direct support.
  2528. symbolic procedure s!:comprog(x, env, context);
  2529. begin
  2530. scalar labs, s, bvl, fluids, n, body, local_decs, w;
  2531. body := s!:find_local_decs cddr x;
  2532. local_decs := car body; body := cdr body;
  2533. n := 0;
  2534. for each v in cadr x do w := s!:instate_local_decs(v, local_decs, w);
  2535. for each v in cadr x do <<
  2536. if globalp v then <<
  2537. if !*pwrds then <<
  2538. if posn() neq 0 then terpri();
  2539. princ "+++++ global ";
  2540. prin v;
  2541. princ " converted to fluid";
  2542. terpri() >>;
  2543. % convert from global to fluid so that I can proceed
  2544. unglobal list v;
  2545. fluid list v >>;
  2546. if fluidp v then fluids := v . fluids
  2547. else << n := n + 1; bvl := v . bvl >> >>;
  2548. % save the environment that existed outside the prog so I can restore it later
  2549. s := cdr env;
  2550. s!:current_exitlab := (nil . (gensym() . s)) . s!:current_exitlab;
  2551. s!:outstack n;
  2552. rplacd(env, append(bvl, cdr env));
  2553. % bind the fluids
  2554. if fluids then begin
  2555. scalar fl1;
  2556. fl1 := s!:vecof fluids;
  2557. s!:outopcode1lit('FREEBIND, fl1, env);
  2558. for each v in nil . fluids do rplacd(env, 0 . cdr env);
  2559. rplacd(env, (2 + length fluids) . cdr env);
  2560. if context = 0 then context := 1 end;
  2561. % use gensyms as internal names for the labels in this block
  2562. for each a in cddr x do
  2563. if atom a then <<
  2564. if atsoc(a, labs) then <<
  2565. if not null a then <<
  2566. % I do not generate a message if NIL appears several times as a label,
  2567. % since in some generated PROG blocks people may have stuck in NIL thinking
  2568. % of it as a null expression rather than as a label.
  2569. if posn() neq 0 then terpri();
  2570. princ "+++++ label "; prin a;
  2571. princ " multiply defined"; terpri() >> >>
  2572. else labs := (a . ((gensym() . cdr env) . nil)) . labs >>;
  2573. s!:current_proglabels := labs . s!:current_proglabels;
  2574. w := s!:residual_local_decs(local_decs, w);
  2575. % handle the body of the prog
  2576. for each a in cddr x do
  2577. if not atom a then s!:comval(a, env, context+4)
  2578. else begin
  2579. scalar d;
  2580. d := atsoc(a, labs);
  2581. if null cddr d then <<
  2582. rplacd(cdr d, t);
  2583. s!:set_label caadr d >> end;
  2584. s!:cancel_local_decs w;
  2585. % if I drop off the end of a prog block I must return nil, so
  2586. % load it up here
  2587. s!:comval(nil, env, context);
  2588. if fluids then s!:outopcode0('FREERSTR, '(FREERSTR));
  2589. s!:outlose n;
  2590. rplacd(env, s);
  2591. s!:set_label cadar s!:current_exitlab;
  2592. s!:current_exitlab := cdr s!:current_exitlab;
  2593. s!:current_proglabels := cdr s!:current_proglabels
  2594. end;
  2595. put('prog, 's!:compfn, function s!:comprog);
  2596. !#endif
  2597. % s!:comtagbody is put here next to s!:comprog since it is really a subset.
  2598. symbolic procedure s!:comtagbody(x, env, context);
  2599. begin
  2600. scalar labs;
  2601. % use gensyms as internal names for the labels in this block
  2602. for each a in cdr x do
  2603. if atom a then <<
  2604. if atsoc(a, labs) then <<
  2605. if not null a then <<
  2606. % I do not generate a message if NIL appears several times as a label,
  2607. % since in some generated PROG blocks people may have stuck in NIL thinking
  2608. % of it as a null expression rather than as a label.
  2609. if posn() neq 0 then terpri();
  2610. princ "+++++ label "; prin a;
  2611. princ " multiply defined"; terpri() >> >>
  2612. else labs := (a . ((gensym() . cdr env) . nil)) . labs >>;
  2613. s!:current_proglabels := labs . s!:current_proglabels;
  2614. for each a in cdr x do
  2615. if not atom a then s!:comval(a, env, context+4)
  2616. else begin
  2617. scalar d;
  2618. d := atsoc(a, labs);
  2619. if null cddr d then <<
  2620. rplacd(cdr d, t);
  2621. s!:set_label caadr d >> end;
  2622. % if I drop off the end of a prog block I must return nil, so
  2623. % load it up here
  2624. s!:comval(nil, env, context);
  2625. s!:current_proglabels := cdr s!:current_proglabels
  2626. end;
  2627. put('tagbody, 's!:compfn, function s!:comtagbody);
  2628. !#if common!-lisp!-mode
  2629. symbolic procedure s!:comprogv(x, env, context);
  2630. begin
  2631. x := cdr x;
  2632. if s!:load2(car x, cadr x, env) then s!:outopcode0('SWOP, '(SWOP));
  2633. s!:outopcode0('PVBIND, '(PVBIND));
  2634. rplacd(env, '(pvbind) . 0 . cdr env);
  2635. s!:comval('progn . cddr x, env, 1);
  2636. s!:outopcode0('PVRESTORE, '(PVRESTORE));
  2637. rplacd(env, cdddr env)
  2638. end;
  2639. put('progv, 's!:compfn, function s!:comprogv);
  2640. symbolic procedure s!:comprog!*(x, env, context);
  2641. begin
  2642. scalar local_decs;
  2643. local_decs := s!:find_local_decs cddr x;
  2644. % Macroexpand as per CLTL trying to migrate declarations to the right place
  2645. x := list('block, nil,
  2646. list('let!*, cadr x,
  2647. 'declare . car local_decs,
  2648. 'tagbody . cdr local_decs));
  2649. return s!:comval(x, env, context)
  2650. end;
  2651. put('prog!*, 's!:compfn, function s!:comprog!*);
  2652. !#endif
  2653. % s!:comblock is just for RETURN to work with.
  2654. symbolic procedure s!:comblock(x, env, context);
  2655. begin
  2656. s!:current_exitlab := (cadr x . (gensym() . cdr env)) . s!:current_exitlab;
  2657. s!:comval('progn . cddr x, env, context);
  2658. s!:set_label cadar s!:current_exitlab;
  2659. s!:current_exitlab := cdr s!:current_exitlab
  2660. end;
  2661. !#if common!-lisp!-mode
  2662. put('block, 's!:compfn, function s!:comblock);
  2663. !#else
  2664. put('!~block, 's!:compfn, function s!:comblock);
  2665. !#endif
  2666. symbolic procedure s!:comcatch(x, env, context);
  2667. begin
  2668. scalar g;
  2669. g := gensym();
  2670. s!:comval(cadr x, env, 1); % The catch tag
  2671. s!:outjump('CATCH, g); % Jumps to label if a THROW happens
  2672. rplacd(env, '(catch) . 0 . 0 . cdr env);
  2673. s!:comval('progn . cddr x, env, context);
  2674. s!:outopcode0('UNCATCH, '(UNCATCH));
  2675. rplacd(env, cddddr env);
  2676. s!:set_label g
  2677. end;
  2678. put('catch, 's!:compfn, 's!:comcatch);
  2679. symbolic procedure s!:comthrow(x, env, context);
  2680. begin
  2681. s!:comval(cadr x, env, 1); % The tag
  2682. s!:outopcode0('PUSH, '(PUSH));
  2683. rplacd(env, 0 . cdr env);
  2684. s!:comval(caddr x, env, 1); % value to be returned
  2685. s!:outopcode0('THROW, '(THROW)); % tag is on the stack
  2686. rplacd(env, cddr env)
  2687. end;
  2688. put('throw, 's!:compfn, 's!:comthrow);
  2689. symbolic procedure s!:comunwind!-protect(x, env, context);
  2690. begin
  2691. scalar g;
  2692. g := gensym();
  2693. % UNWIND-PROTECT shares an opcode with CATCH by using an otherwise
  2694. % invalid value as a tag. The function LOAD-SPID is not available
  2695. % in interpreted code but in compiled code it just loads such a value.
  2696. s!:comval('(load!-spid), env, 1); % The unwind!-protect tag
  2697. s!:outjump('CATCH, g); % Jumps to label if ANY unwind happens
  2698. rplacd(env, list('unwind!-protect, cddr x) . 0 . 0 . cdr env);
  2699. s!:comval(cadr x, env, context);
  2700. % PROTECT may use the top three stack locations, and must use them to
  2701. % store the current set of values and exit status. It is implicitly done
  2702. % by the forced jump that is taken on a failure...
  2703. s!:outopcode0('PROTECT, '(PROTECT));
  2704. s!:set_label g;
  2705. rplaca(cdr env, 0);
  2706. % A lexical exit here will just pop the stack, discarding the saved
  2707. % information that PROTECT had left behind.
  2708. s!:comval('progn . cddr x, env, context);
  2709. s!:outopcode0('UNPROTECT, '(UNPROTECT));
  2710. rplacd(env, cddddr env)
  2711. end;
  2712. put('unwind!-protect, 's!:compfn, 's!:comunwind!-protect);
  2713. symbolic procedure s!:comdeclare(x, env, context);
  2714. % I print a message if I find DECLARE where I am compiling things.
  2715. % I am supposed to have picked off all valid uses of DECLARE
  2716. % elsewhere, so this is probably an error - but I will make it just
  2717. % a gentle warning message for now.
  2718. begin
  2719. if !*pwrds then <<
  2720. princ "+++ ";
  2721. prin x;
  2722. princ " ignored";
  2723. terpri() >>
  2724. end;
  2725. put('declare, 's!:compfn, function s!:comdeclare);
  2726. symbolic procedure s!:expand_let(vl, b);
  2727. % if null vl then b
  2728. % else if null cdr vl then s!:expand_let!*(vl, b)
  2729. % else
  2730. begin scalar vars, vals;
  2731. for each v in vl do
  2732. if atom v then << vars := v . vars; vals := nil . vals >>
  2733. else if atom cdr v then << vars := car v . vars; vals := nil . vals >>
  2734. else << vars := car v . vars; vals := cadr v . vals >>;
  2735. return list(('lambda . vars . b) . vals)
  2736. end;
  2737. symbolic procedure s!:comlet(x, env, context);
  2738. s!:comval('progn . s!:expand_let(cadr x, cddr x), env, context);
  2739. !#if common!-lisp!-mode
  2740. put('let, 's!:compfn, function s!:comlet);
  2741. !#else
  2742. put('!~let, 's!:compfn, function s!:comlet);
  2743. !#endif
  2744. symbolic procedure s!:expand_let!*(vl, local_decs, b);
  2745. % This has loads of fun because although it basically wants to expand
  2746. % (LET* ((v1 e1) (v2 e2)) b1 b1 b2)
  2747. % into ((LAMBDA (v1) | ) e1)
  2748. % v
  2749. % ((LAMBDA (v2) b1 b2 b3) e2)
  2750. % it also needs to migrate special declarations to the proper levels.
  2751. % I also want the degenerate case (LET* () (DECLARE ...) ...) to arrange to
  2752. % spot and process the DECLARE, so I expand it into a vacuuous LAMBDA.
  2753. begin
  2754. scalar r, var, val;
  2755. r := ('declare . local_decs) . b;
  2756. for each x in reverse vl do <<
  2757. val := nil;
  2758. if atom x then var := x
  2759. else if atom cdr x then var := car x
  2760. else << var := car x; val := cadr x >>;
  2761. for each z in local_decs do
  2762. if eqcar(z, 'special) then
  2763. if memq(var, cdr z) then
  2764. r := list('declare, list('special, var)) . r;
  2765. r := list list('lambda . list var . r, val) >>;
  2766. if eqcar(car r, 'declare) then r := list('lambda . nil . r)
  2767. else r := 'progn . r;
  2768. return r
  2769. end;
  2770. symbolic procedure s!:comlet!*(x, env, context);
  2771. begin
  2772. scalar b;
  2773. b := s!:find_local_decs cddr x;
  2774. return s!:comval(s!:expand_let!*(cadr x, car b, cdr b),
  2775. env, context)
  2776. end;
  2777. put('let!*, 's!:compfn, function s!:comlet!*);
  2778. symbolic procedure s!:restore_stack(e1, e2);
  2779. % This is used when a GO (or a RETURN-FROM) is being compiled to restore
  2780. % the stack to a proper level for the destination of the branch.
  2781. begin
  2782. scalar n;
  2783. n := 0;
  2784. while not (e1 = e2) do <<
  2785. if null e1 then error(0, "bad block nesting with GO or RETURN-FROM");
  2786. if numberp car e1 and car e1 > 2 then <<
  2787. if not zerop n then s!:outlose n;
  2788. n := car e1;
  2789. s!:outopcode0('FREERSTR, '(FREERSTR));
  2790. for i := 1:n do e1 := cdr e1;
  2791. n := 0 >>
  2792. else if car e1 = '(catch) then <<
  2793. if not zerop n then s!:outlose n;
  2794. s!:outopcode0('UNCATCH, '(UNCATCH));
  2795. e1 := cdddr e1;
  2796. n := 0 >>
  2797. else if eqcar(car e1, 'unwind!-protect) then <<
  2798. if not zerop n then s!:outlose n;
  2799. s!:outopcode0('PROTECT, '(PROTECT));
  2800. s!:comval('progn . cadar e1, e1, 2);
  2801. s!:outopcode0('UNPROTECT, '(UNPROTECT));
  2802. e1 := cdddr e1;
  2803. n := 0 >>
  2804. !#if common!-lisp!-mode
  2805. else if car e1 = '(pvbind) then <<
  2806. if not zerop n then s!:outlose n;
  2807. s!:outopcode0('PVRESTORE, '(PVRESTORE));
  2808. e1 := cddr e1;
  2809. n := 0 >>
  2810. !#endif
  2811. else <<
  2812. e1 := cdr e1;
  2813. n := n + 1 >> >>;
  2814. if not zerop n then s!:outlose n
  2815. end;
  2816. symbolic procedure s!:comgo(x, env, context);
  2817. % Even in Common Lisp Mode I do not support (yet) GO statements that
  2818. % escape from one LAMBDA expression into an enclosing one.
  2819. begin
  2820. scalar pl, d;
  2821. !#if (not common!-lisp!-mode)
  2822. if context < 4 then <<
  2823. princ "go not in program context";
  2824. terpri() >>;
  2825. !#endif
  2826. pl := s!:current_proglabels;
  2827. while pl and null d do <<
  2828. d := atsoc(cadr x, car pl);
  2829. if null d then pl := cdr pl >>;
  2830. if null d then <<
  2831. if posn() neq 0 then terpri();
  2832. princ "+++++ label "; prin cadr x; princ " not set"; terpri();
  2833. return >>;
  2834. d := cadr d;
  2835. s!:restore_stack(cdr env, cdr d);
  2836. s!:outjump('JUMP, car d)
  2837. end;
  2838. put('go, 's!:compfn, function s!:comgo);
  2839. symbolic procedure s!:comreturn!-from(x, env, context);
  2840. % Even in Common Lisp Mode I do not support (yet) RETURN statements that
  2841. % escape from one LAMBDA expression into an enclosing one.
  2842. begin
  2843. scalar tag;
  2844. !#if (not common!-lisp!-mode)
  2845. if context < 4 then <<
  2846. princ "+++++ return or return-from not in prog context";
  2847. terpri() >>;
  2848. !#endif
  2849. x := cdr x;
  2850. tag := car x;
  2851. if cdr x then x := cadr x else x := nil;
  2852. !#if common!-lisp!-mode
  2853. s!:comval(x, env, 1);
  2854. !#else
  2855. s!:comval(x, env, context-4);
  2856. !#endif
  2857. x := atsoc(tag, s!:current_exitlab);
  2858. if null x then error(0, list("invalid return-from", tag));
  2859. x := cdr x;
  2860. s!:restore_stack(cdr env, cdr x);
  2861. s!:outjump('JUMP, car x)
  2862. end;
  2863. put('return!-from, 's!:compfn, function s!:comreturn!-from);
  2864. symbolic procedure s!:comreturn(x, env, context);
  2865. s!:comreturn!-from('return!-from . nil . cdr x, env, context);
  2866. put('return, 's!:compfn, function s!:comreturn);
  2867. % conditional code is generated via jumpif, which jumps to label lab
  2868. % if x evaluates to the value of neg
  2869. global '(s!:jumplts s!:jumplnils s!:jumpatoms s!:jumpnatoms);
  2870. s!:jumplts := s!:vecof '(JUMPL0T JUMPL1T JUMPL2T JUMPL3T JUMPL4T);
  2871. s!:jumplnils := s!:vecof '(JUMPL0NIL JUMPL1NIL JUMPL2NIL JUMPL3NIL JUMPL4NIL);
  2872. s!:jumpatoms := s!:vecof '(JUMPL0ATOM JUMPL1ATOM JUMPL2ATOM JUMPL3ATOM);
  2873. s!:jumpnatoms := s!:vecof '(JUMPL0NATOM JUMPL1NATOM JUMPL2NATOM JUMPL3NATOM);
  2874. symbolic procedure s!:jumpif(neg, x, env, lab);
  2875. % There are some special optimised cases for tests on simple atomic
  2876. % values - both local and free variables.
  2877. begin
  2878. scalar w, w1, j;
  2879. top:
  2880. if null x then <<
  2881. if not neg then s!:outjump('JUMP, lab);
  2882. return nil >>
  2883. else if x eq t or (eqcar(x, 'quote) and cadr x) or
  2884. (atom x and not symbolp x) then <<
  2885. if neg then s!:outjump('JUMP, lab);
  2886. return nil >>
  2887. else if (w := s!:islocal(x, env)) < 5 then
  2888. return s!:outjump(getv(if neg then s!:jumplts else s!:jumplnils, w),
  2889. lab)
  2890. else if w = 99999 and symbolp x then <<
  2891. s!:should_be_fluid x;
  2892. w := list(if neg then 'JUMPFREET else 'JUMPFREENIL, x, x);
  2893. return s!:record_literal_for_jump(w, env, lab) >>;
  2894. if not atom x and atom car x and (w := get(car x, 's!:testfn)) then
  2895. return funcall(w, neg, x, env, lab);
  2896. if not atom x then <<
  2897. w := s!:improve x;
  2898. if atom w or not eqcar(x, car w) then << x := w; go to top >>;
  2899. !#if common!-lisp!-mode
  2900. if w1 := s!:local_macro car w then <<
  2901. if atom cdr w1 then x := 'funcall . cdr w1 . cdr w
  2902. else x := funcall('lambda . cdr w1, w);
  2903. go to top >>;
  2904. !#endif
  2905. if (w1 := get(car w, 's!:compilermacro)) and
  2906. (w1 := funcall(w1, w, env, 1)) then <<
  2907. x := w1; go to top >> >>;
  2908. % I only expand ordinary macros here if the expansion leads to something
  2909. % with a TESTFN or COMPILERMACRO property or to an atom.
  2910. remacro:
  2911. if (not atom w) and (w1 := macro!-function car w) then <<
  2912. w := funcall(w1, w);
  2913. if atom w or
  2914. eqcar(w, 'quote) or
  2915. get(car w, 's!:testfn) or
  2916. get(car w, 's!:compilermacro) then << x := w; go to top >>;
  2917. go to remacro >>;
  2918. s!:comval(x, env, 1);
  2919. w := s!:current_block;
  2920. while w and not atom car w do w := cdr w;
  2921. j := '(JUMPNIL . JUMPT);
  2922. if w then <<
  2923. w1 := car w;
  2924. w := cdr w;
  2925. if w1 = 'STORELOC0 then <<
  2926. s!:current_block := w;
  2927. s!:current_size := s!:current_size - 1;
  2928. j := '(JUMPST0NIL . JUMPST0T) >>
  2929. else if w1 = 'STORELOC1 then <<
  2930. s!:current_block := w;
  2931. s!:current_size := s!:current_size - 1;
  2932. j := '(JUMPST1NIL . JUMPST1T) >>
  2933. else if w1 = 'STORELOC2 then <<
  2934. s!:current_block := w;
  2935. s!:current_size := s!:current_size - 1;
  2936. j := '(JUMPST2NIL . JUMPST2T) >>
  2937. else if eqcar(w, 'BUILTIN1) then <<
  2938. s!:current_block := cdr w;
  2939. s!:current_size := s!:current_size - 2;
  2940. j := list('JUMPB1NIL, w1) . list('JUMPB1T, w1) >>
  2941. else if eqcar(w, 'BUILTIN2) then <<
  2942. s!:current_block := cdr w;
  2943. s!:current_size := s!:current_size - 2;
  2944. j := list('JUMPB2NIL, w1) . list('JUMPB2T, w1) >> >>;
  2945. return s!:outjump(if neg then cdr j else car j, lab)
  2946. end;
  2947. symbolic procedure s!:testnot(neg, x, env, lab);
  2948. s!:jumpif(not neg, cadr x, env, lab);
  2949. put('null, 's!:testfn, function s!:testnot);
  2950. put('not, 's!:testfn, function s!:testnot);
  2951. symbolic procedure s!:testatom(neg, x, env, lab);
  2952. begin
  2953. scalar w;
  2954. if (w := s!:islocal(cadr x, env)) < 4 then
  2955. return s!:outjump(getv(if neg then s!:jumpatoms else s!:jumpnatoms, w),
  2956. lab);
  2957. s!:comval(cadr x, env, 1);
  2958. if neg then s!:outjump('JUMPATOM, lab)
  2959. else s!:outjump('JUMPNATOM, lab)
  2960. end;
  2961. put('atom, 's!:testfn, function s!:testatom);
  2962. symbolic procedure s!:testconsp(neg, x, env, lab);
  2963. begin
  2964. scalar w;
  2965. if (w := s!:islocal(cadr x, env)) < 4 then
  2966. return s!:outjump(getv(if neg then s!:jumpnatoms else s!:jumpatoms, w),
  2967. lab);
  2968. s!:comval(cadr x, env, 1);
  2969. if neg then s!:outjump('JUMPNATOM, lab)
  2970. else s!:outjump('JUMPATOM, lab)
  2971. end;
  2972. put('consp, 's!:testfn, function s!:testconsp);
  2973. symbolic procedure s!:comcond(x, env, context);
  2974. begin
  2975. scalar l1, l2, w;
  2976. l1 := gensym();
  2977. while (x := cdr x) do <<
  2978. w := car x;
  2979. if atom cdr w then <<
  2980. s!:comval(car w, env, 1);
  2981. s!:outjump('JUMPT, l1);
  2982. l2 := nil >>
  2983. else <<
  2984. if car w = t then l2 := nil
  2985. else <<
  2986. l2 := gensym();
  2987. s!:jumpif(nil, car w, env, l2) >>;
  2988. w := cdr w;
  2989. if null cdr w then w := car w
  2990. else w := 'progn . w;
  2991. s!:comval(w, env, context);
  2992. if l2 then << s!:outjump('JUMP, l1); s!:set_label l2 >>
  2993. else x := '(nil) >> >>;
  2994. if l2 then s!:comval(nil, env, context);
  2995. s!:set_label l1
  2996. end;
  2997. put('cond, 's!:compfn, function s!:comcond);
  2998. symbolic procedure s!:comif(x, env, context);
  2999. begin
  3000. scalar l1, l2;
  3001. l2 := gensym();
  3002. s!:jumpif(nil, cadr x, env, l2);
  3003. x := cddr x;
  3004. s!:comval(car x, env, context);
  3005. x := cdr x;
  3006. if x or (context < 2 and (x := '(nil))) then <<
  3007. l1 := gensym();
  3008. s!:outjump('JUMP, l1);
  3009. s!:set_label l2;
  3010. s!:comval(car x, env, context);
  3011. s!:set_label l1 >>
  3012. else s!:set_label l2
  3013. end;
  3014. put('if, 's!:compfn, function s!:comif);
  3015. symbolic procedure s!:comwhen(x, env, context);
  3016. begin
  3017. scalar l2;
  3018. l2 := gensym();
  3019. if context < 2 then <<
  3020. s!:comval(cadr x, env, 1);
  3021. s!:outjump('JUMPNIL, l2) >>
  3022. else s!:jumpif(nil, cadr x, env, l2);
  3023. s!:comval('progn . cddr x, env, context);
  3024. s!:set_label l2
  3025. end;
  3026. put('when, 's!:compfn, function s!:comwhen);
  3027. symbolic procedure s!:comunless(x, env, context);
  3028. s!:comwhen(list!*('when, list('not, cadr x), cddr x), env, context);
  3029. put('unless, 's!:compfn, function s!:comunless);
  3030. % The S:ICASE function is not really intended for direct use. It is there
  3031. % to provide Lisp-code with the ability to generate the ICASE byte opcode.
  3032. % The usage is
  3033. % (s!:icase <expression>
  3034. % <default-value>
  3035. % <case 0 value>
  3036. % <case 1 value>
  3037. % <case 2 value>
  3038. % ...
  3039. % <case n value>)
  3040. % and the value if selected on the basis of the expression, which will
  3041. % normally evaluate to an integer in the range 0 to n.
  3042. symbolic procedure s!:comicase(x, env, context);
  3043. begin
  3044. scalar l1, labs, labassoc, w;
  3045. x := cdr x;
  3046. for each v in cdr x do <<
  3047. w := assoc!*!*(v, labassoc);
  3048. % If the same value occurs in several cases then I set just one label
  3049. % and re-use it.
  3050. if w then l1 := cdr w . l1
  3051. else <<
  3052. l1 := gensym();
  3053. labs := l1 . labs;
  3054. labassoc := (v . l1) . labassoc >> >>;
  3055. s!:comval(car x, env, 1);
  3056. s!:outjump('ICASE, reversip labs);
  3057. l1 := gensym();
  3058. for each v in labassoc do <<
  3059. s!:set_label cdr v;
  3060. s!:comval(car v, env, context);
  3061. s!:outjump('JUMP, l1) >>;
  3062. s!:set_label l1
  3063. end;
  3064. put('s!:icase, 's!:compfn, function s!:comicase);
  3065. put('JUMPLITEQ!*, 's!:opcode, get('JUMPLITEQ, 's!:opcode));
  3066. put('JUMPLITNE!*, 's!:opcode, get('JUMPLITNE, 's!:opcode));
  3067. %
  3068. % s!:jumpliteqn jumps to lab is the A register is EQL to val. In
  3069. % all sensible cases an EQ test can be used, but when that will not
  3070. % be possible (mainly floats or bignums) the EQL function itself is
  3071. % invoked. This preserves full generality!
  3072. %
  3073. symbolic procedure s!:jumpliteql(val, lab, env);
  3074. begin
  3075. scalar w;
  3076. if idp val or
  3077. eq!-safe val then <<
  3078. w := list('JUMPLITEQ!*, val, val);
  3079. s!:record_literal_for_jump(w, env, lab) >>
  3080. else <<
  3081. s!:outopcode0('PUSH, '(PUSH));
  3082. s!:loadliteral(val, env);
  3083. s!:outopcode1('BUILTIN2, get('eql, 's!:builtin2), 'eql);
  3084. s!:outjump('JUMPT, lab);
  3085. flag(list lab, 's!:jumpliteql);
  3086. s!:outopcode0('POP, '(POP)) >>
  3087. end;
  3088. symbolic procedure s!:casebranch(sw, env, dflt);
  3089. begin
  3090. scalar size, w, w1, r, g;
  3091. size := 4+truncate(length sw,2);
  3092. % I probably do not need to go as far as making the size of my hash table
  3093. % prime, but the specific case of multiples of 13 is filtered for here
  3094. % since powers of 13 are used in the sxhash/eqlhash calculation.
  3095. while remainder(size, 2)=0 or remainder(size, 3)=0 or
  3096. remainder(size, 5)=0 or remainder(size, 13)=0 do size := size+1;
  3097. for each p in sw do <<
  3098. w := remainder(eqlhash car p, size);
  3099. w1 := assoc!*!*(w, r);
  3100. if w1 then rplacd(cdr w1, p . cddr w1)
  3101. else r := list(w, gensym(), p) . r >>;
  3102. s!:outopcode0('PUSH, '(PUSH));
  3103. rplacd(env, 0 . cdr env);
  3104. s!:outopcode1lit('CALL1, 'eqlhash, env);
  3105. s!:loadliteral(size, env);
  3106. g := gensym();
  3107. s!:outopcode1('BUILTIN2, get('iremainder, 's!:builtin2), 'iremainder);
  3108. s!:outjump('ICASE, g . for i := 0:size-1 collect <<
  3109. w := assoc!*!*(i, r);
  3110. if w then cadr w else g >>);
  3111. for each p in r do <<
  3112. s!:set_label cadr p;
  3113. s!:outopcode0('POP, '(POP));
  3114. for each q in cddr p do s!:jumpliteql(car q, cdr q, env);
  3115. s!:outjump('JUMP, dflt) >>;
  3116. s!:set_label g;
  3117. s!:outopcode0('POP, '(POP));
  3118. s!:outjump('JUMP, dflt);
  3119. rplacd(env, cddr env)
  3120. end;
  3121. symbolic procedure s!:comcase(x, env, context);
  3122. begin
  3123. scalar keyform, blocks, v, w, g, dflt, sw, keys, nonnum;
  3124. x := cdr x;
  3125. keyform := car x;
  3126. for each y on cdr x do <<
  3127. w := assoc!*!*(cdar y, blocks);
  3128. if w then g := cdr w
  3129. else <<
  3130. g := gensym();
  3131. blocks := (cdar y . g) . blocks >>;
  3132. w := caar y;
  3133. if null cdr y and (w = t or w = 'otherwise) then dflt := g
  3134. else <<
  3135. if atom w then w := list w;
  3136. for each n in w do <<
  3137. if idp n or
  3138. !#if common!-lisp!-mode
  3139. characterp n or
  3140. !#endif
  3141. numberp n then <<
  3142. if not fixp n then nonnum := t;
  3143. keys := n . keys;
  3144. sw := (n . g) . sw >>
  3145. % The test made is supposed (in Common Lisp) to be EQL. I take the
  3146. % severe view that I will not accept labels that are lists or vectors
  3147. % or strings or other things where EQL is a nasty sort of test. This is
  3148. % not in accordance with full Common Lisp, and if this really hurts me
  3149. % some time I can degenerate and turn out very clumsy sequences of test-
  3150. % and-branch code in marginal cases.
  3151. else error(0, list("illegal case label", n)) >> >> >>;
  3152. if null dflt then <<
  3153. if (w := assoc!*!*(nil, blocks)) then dflt := cdr w
  3154. else blocks := (nil . (dflt := gensym())) . blocks >>;
  3155. if not nonnum then <<
  3156. keys := sort(keys, function lessp);
  3157. nonnum := car keys;
  3158. g := lastcar keys;
  3159. if g - nonnum < 2*length keys then <<
  3160. % If the keys are a fairly compact block of fixnums I can do an
  3161. % especially good job.
  3162. if not (nonnum = 0) then <<
  3163. keyform := list('xdifference, keyform, nonnum);
  3164. sw := for each y in sw collect (car y - nonnum) . cdr y >>;
  3165. s!:comval(keyform, env, 1);
  3166. w := nil;
  3167. for i := 0:g do
  3168. if (v := assoc!*!*(i, sw)) then w := cdr v . w
  3169. else w := dflt . w;
  3170. w := dflt . reversip w;
  3171. s!:outjump('ICASE, w);
  3172. nonnum := nil >>
  3173. else nonnum := t >>;
  3174. if nonnum then <<
  3175. % If I have only a few cases I do repeated test/branch combinations,
  3176. % but if I have a LOT I will try hashing. The change-over point at 7
  3177. % is pretty much a GUESS for where it should reasonably go.
  3178. s!:comval(keyform, env, 1);
  3179. if length sw < 7 then <<
  3180. % The code here is DELICATE. This is because USUALLY the JUMPLITEQ
  3181. % code preserve the A register, but when expanded to a pair of
  3182. % instructions maybe it does not. To deal with this I use JUMPLITEQ!*
  3183. % which expands slightly differently... Also I have to be prepared to
  3184. % cope with floats or bignums (and I do so in a very ugly way)
  3185. for each y in sw do s!:jumpliteql(car y, cdr y, env);
  3186. s!:outjump('JUMP, dflt) >>
  3187. else s!:casebranch(sw, env, dflt) >>;
  3188. g := gensym();
  3189. for each v in blocks do <<
  3190. s!:set_label cdr v;
  3191. if flagp(cdr v, 's!:jumpliteql) then s!:outlose 1;
  3192. s!:comval('progn . car v, env, context);
  3193. s!:outjump('JUMP, g) >>;
  3194. s!:set_label g
  3195. end;
  3196. put('case, 's!:compfn, function s!:comcase);
  3197. fluid '(!*defn dfprint!* s!:dfprintsave s!:faslmod_name);
  3198. symbolic procedure s!:comeval!-when(x, env, context);
  3199. begin
  3200. scalar y;
  3201. x := cdr x;
  3202. y := car x;
  3203. x := 'progn . cdr x;
  3204. if memq('compile, y) then eval x;
  3205. if memq('load, y) then <<
  3206. if dfprint!* then apply1(dfprint!*, x) >>;
  3207. if memq('eval, y) then s!:comval(x, env, context)
  3208. else s!:comval(nil, env, context)
  3209. end;
  3210. put('eval!-when, 's!:compfn, function s!:comeval!-when);
  3211. % (the <type> <value>) is treated here as just <value>, but in the
  3212. % longer term notice should be taken of the type information.
  3213. symbolic procedure s!:comthe(x, env, context);
  3214. s!:comval(caddr x, env, context);
  3215. put('the, 's!:compfn, function s!:comthe);
  3216. symbolic procedure s!:comand(x, env, context);
  3217. % AND and OR are not transparent to program context, and
  3218. % are always assumed to be used for their value.
  3219. % Is it worth doing something special if all the values tested are
  3220. % known to be regular style predicates? (eg NULL, ATOM, EQ etc calls)
  3221. begin
  3222. scalar l;
  3223. l := gensym();
  3224. x := cdr x;
  3225. s!:comval(car x, env, 1);
  3226. while x := cdr x do <<
  3227. s!:outjump('JUMPNIL, l);
  3228. s!:comval(car x, env, 1) >>;
  3229. s!:set_label l
  3230. end;
  3231. put('and, 's!:compfn, function s!:comand);
  3232. symbolic procedure s!:comor(x, env, context);
  3233. begin
  3234. scalar l;
  3235. l := gensym();
  3236. x := cdr x;
  3237. s!:comval(car x, env, 1);
  3238. while x := cdr x do <<
  3239. s!:outjump('JUMPT, l);
  3240. s!:comval(car x, env, 1) >>;
  3241. s!:set_label l
  3242. end;
  3243. put('or, 's!:compfn, function s!:comor);
  3244. symbolic procedure s!:combool(neg, x, env, lab);
  3245. % Used for AND and OR when they occur in predicates rather
  3246. % than in places where their (full) value is required.
  3247. begin
  3248. scalar fn;
  3249. fn := eqcar(x, 'or);
  3250. if fn eq neg then
  3251. while x := cdr x do
  3252. s!:jumpif(fn, car x, env, lab)
  3253. else <<
  3254. neg := gensym();
  3255. while x := cdr x do
  3256. s!:jumpif(fn, car x, env, neg);
  3257. s!:outjump('JUMP, lab);
  3258. s!:set_label neg >>
  3259. end;
  3260. put('and, 's!:testfn, function s!:combool);
  3261. put('or, 's!:testfn, function s!:combool);
  3262. symbolic procedure s!:testeq(neg, x, env, lab);
  3263. begin
  3264. scalar a, b;
  3265. a := s!:improve cadr x;
  3266. b := s!:improve caddr x;
  3267. if s!:eval_to_eq_unsafe a or s!:eval_to_eq_unsafe b then <<
  3268. if posn() neq 0 then terpri();
  3269. princ "++++ EQ on number upgraded to EQUAL in ";
  3270. prin s!:current_function; princ " : ";
  3271. prin a; princ " "; print b;
  3272. return s!:testequal(neg, 'equal . cdr x, env, lab) >>;
  3273. if !*carefuleq then <<
  3274. s!:comval(x, env, 1);
  3275. s!:outjump(if neg then 'JUMPT else 'JUMPNIL, lab);
  3276. return >>;
  3277. % eq tests against nil can be optimised a bit
  3278. if null a then s!:jumpif(not neg, b, env, lab)
  3279. else if null b then s!:jumpif(not neg, a, env, lab)
  3280. else if eqcar(a, 'quote) or (atom a and not symbolp a) then <<
  3281. s!:comval(b, env, 1);
  3282. if eqcar(a, 'quote) then a := cadr a;
  3283. b := list(if neg then 'JUMPLITEQ else 'JUMPLITNE, a, a);
  3284. s!:record_literal_for_jump(b, env, lab) >>
  3285. else if eqcar(b, 'quote) or (atom b and not symbolp b) then <<
  3286. s!:comval(a, env, 1);
  3287. if eqcar(b, 'quote) then b := cadr b;
  3288. a := list(if neg then 'JUMPLITEQ else 'JUMPLITNE, b, b);
  3289. s!:record_literal_for_jump(a, env, lab) >>
  3290. else <<
  3291. s!:load2(a, b, env);
  3292. if neg then s!:outjump('JUMPEQ, lab)
  3293. else s!:outjump('JUMPNE, lab) >>;
  3294. end;
  3295. symbolic procedure s!:testeq1(neg, x, env, lab);
  3296. begin
  3297. scalar a, b;
  3298. if !*carefuleq then <<
  3299. s!:comval(x, env, 1);
  3300. s!:outjump(if neg then 'JUMPT else 'JUMPNIL, lab);
  3301. return >>;
  3302. a := s!:improve cadr x;
  3303. b := s!:improve caddr x;
  3304. % eq tests against nil can be optimised a bit
  3305. if null a then s!:jumpif(not neg, b, env, lab)
  3306. else if null b then s!:jumpif(not neg, a, env, lab)
  3307. else if eqcar(a, 'quote) or (atom a and not symbolp a) then <<
  3308. s!:comval(b, env, 1);
  3309. if eqcar(a, 'quote) then a := cadr a;
  3310. b := list(if neg then 'JUMPLITEQ else 'JUMPLITNE, a, a);
  3311. s!:record_literal_for_jump(b, env, lab) >>
  3312. else if eqcar(b, 'quote) or (atom b and not symbolp b) then <<
  3313. s!:comval(a, env, 1);
  3314. if eqcar(b, 'quote) then b := cadr b;
  3315. a := list(if neg then 'JUMPLITEQ else 'JUMPLITNE, b, b);
  3316. s!:record_literal_for_jump(a, env, lab) >>
  3317. else <<
  3318. s!:load2(a, b, env);
  3319. if neg then s!:outjump('JUMPEQ, lab)
  3320. else s!:outjump('JUMPNE, lab) >>;
  3321. end;
  3322. put('eq, 's!:testfn, function s!:testeq);
  3323. if eq!-safe 0 then put('iequal, 's!:testfn, function s!:testeq1)
  3324. else put('iequal, 's!:testfn, function s!:testequal);
  3325. symbolic procedure s!:testequal(neg, x, env, lab);
  3326. begin
  3327. scalar a, b;
  3328. a := cadr x;
  3329. b := caddr x;
  3330. % equal tests against nil can be optimised
  3331. if null a then s!:jumpif(not neg, b, env, lab)
  3332. else if null b then s!:jumpif(not neg, a, env, lab)
  3333. % comparisons involving a literal identifier or (in this
  3334. % Lisp implementation) a fixnum can be turned into uses of
  3335. % eq rather than equal, to good effect.
  3336. else if (eqcar(a, 'quote) and (symbolp cadr a or eq!-safe cadr a)) or
  3337. (eqcar(b, 'quote) and (symbolp cadr b or eq!-safe cadr b)) or
  3338. eq!-safe a or eq!-safe b then
  3339. s!:testeq1(neg, 'eq . cdr x, env, lab)
  3340. else <<
  3341. s!:load2(a, b, env); % args commute here if that helps
  3342. if neg then s!:outjump('JUMPEQUAL, lab)
  3343. else s!:outjump('JUMPNEQUAL, lab) >>
  3344. end;
  3345. put('equal, 's!:testfn, function s!:testequal);
  3346. symbolic procedure s!:testneq(neg, x, env, lab);
  3347. s!:testequal(not neg, 'equal . cdr x, env, lab);
  3348. put('neq, 's!:testfn, function s!:testneq);
  3349. symbolic procedure s!:testeqcar(neg, x, env, lab);
  3350. begin
  3351. scalar a, b, sw, promote;
  3352. a := cadr x;
  3353. b := s!:improve caddr x;
  3354. if s!:eval_to_eq_unsafe b then <<
  3355. if posn() neq 0 then terpri();
  3356. princ "++++ EQCAR on number upgraded to EQUALCAR in ";
  3357. prin s!:current_function; princ " : "; print b;
  3358. promote := t >>
  3359. else if !*carefuleq then <<
  3360. s!:comval(x, env, 1);
  3361. s!:outjump(if neg then 'JUMPT else 'JUMPNIL, lab);
  3362. return >>;
  3363. if not promote and eqcar(b, 'quote) then <<
  3364. s!:comval(a, env, 1);
  3365. b := cadr b;
  3366. a := list(if neg then 'JUMPEQCAR else 'JUMPNEQCAR, b, b);
  3367. s!:record_literal_for_jump(a, env, lab) >>
  3368. else <<
  3369. sw := s!:load2(a, b, env);
  3370. if sw then s!:outopcode0('SWOP, '(SWOP));
  3371. if promote then
  3372. s!:outopcode1('BUILTIN2, get('equalcar, 's!:builtin2), 'equalcar)
  3373. else s!:outopcode0('EQCAR, '(EQCAR));
  3374. s!:outjump(if neg then 'JUMPT else 'JUMPNIL, lab) >>
  3375. end;
  3376. put('eqcar, 's!:testfn, function s!:testeqcar);
  3377. symbolic procedure s!:testflagp(neg, x, env, lab);
  3378. begin
  3379. scalar a, b, sw;
  3380. a := cadr x;
  3381. b := caddr x;
  3382. if eqcar(b, 'quote) then <<
  3383. s!:comval(a, env, 1);
  3384. b := cadr b;
  3385. sw := symbol!-make!-fastget(b, nil);
  3386. if sw then <<
  3387. s!:outopcode1('FASTGET, logor(sw, 128), b);
  3388. s!:outjump(if neg then 'JUMPT else 'JUMPNIL, lab) >>
  3389. else <<
  3390. a := list(if neg then 'JUMPFLAGP else 'JUMPNFLAGP, b, b);
  3391. s!:record_literal_for_jump(a, env, lab) >> >>
  3392. else <<
  3393. sw := s!:load2(a, b, env);
  3394. if sw then s!:outopcode0('SWOP, '(SWOP));
  3395. s!:outopcode0('FLAGP, '(FLAGP));
  3396. s!:outjump(if neg then 'JUMPT else 'JUMPNIL, lab) >>
  3397. end;
  3398. put('flagp, 's!:testfn, function s!:testflagp);
  3399. global '(s!:storelocs);
  3400. s!:storelocs := s!:vecof '(STORELOC0 STORELOC1 STORELOC2 STORELOC3
  3401. STORELOC4 STORELOC5 STORELOC6 STORELOC7);
  3402. symbolic procedure s!:comsetq(x, env, context);
  3403. begin
  3404. scalar n, w, var;
  3405. x := cdr x;
  3406. if null x then return;
  3407. if not symbolp car x or null cdr x then
  3408. return error(0, list("bad args for setq", x));
  3409. s!:comval(cadr x, env, 1);
  3410. var := car x;
  3411. n := 0;
  3412. w := cdr env;
  3413. % storing into a lexical variable involves stack access, otherwise
  3414. % I need to update the global value cell
  3415. while w and not eqcar(w, var) do << n := add1 n; w := cdr w >>;
  3416. if w then <<
  3417. if not member!*!*('loc . w, s!:a_reg_values) then
  3418. s!:a_reg_values := ('loc . w) . s!:a_reg_values;
  3419. if n < 8 then s!:outopcode0(getv(s!:storelocs, n),
  3420. list('storeloc, var))
  3421. else if n > 4095 then error "stack frame > 4095"
  3422. else if n > 255 then
  3423. s!:outopcode2('BIGSTACK, 64+truncate(n,256), logand(n, 255),
  3424. list('STORELOC, var))
  3425. else s!:outopcode1('STORELOC, n, var) >>
  3426. else if w := s!:find_lexical(var, s!:lexical_env, 0) then <<
  3427. if not member!*!*('lex . w, s!:a_reg_values) then
  3428. s!:a_reg_values := ('lex . w) . s!:a_reg_values;
  3429. s!:outlexref('STORELEX, length cdr env, car w, cadr w, var) >>
  3430. else <<
  3431. if null var or var eq t then
  3432. error(0, list("bad variable in setq", var))
  3433. else s!:should_be_fluid var;
  3434. w := 'free . var;
  3435. if not member!*!*(w, s!:a_reg_values) then
  3436. s!:a_reg_values := w . s!:a_reg_values;
  3437. s!:outopcode1lit('STOREFREE, var, env) >>;
  3438. % For this very small extra I can support (setq a A b B c C ...)
  3439. if cddr x then return s!:comsetq(cdr x, env, context)
  3440. end;
  3441. put('setq, 's!:compfn, function s!:comsetq);
  3442. put('noisy!-setq, 's!:compfn, function s!:comsetq);
  3443. % cons-related functions seem quite important to Lisp, so I provide
  3444. % a bit of special support - cons has a variant xcons for use when its
  3445. % arguments are most conveniently evaluated in the 'other' order, and
  3446. % list gets specialised into ncons, list2 and list3. Two functions
  3447. % acons and list2!* provide useful combinations of a pair of cons
  3448. % operations - use of them reduces overhead associated with the allocation
  3449. % of freestore.
  3450. symbolic procedure s!:comlist(x, env, context);
  3451. begin
  3452. scalar w;
  3453. if null (x := cdr x) then return s!:comval(nil, env, context);
  3454. s!:a_reg_values := nil;
  3455. if null (w := cdr x) then
  3456. s!:comval(list('ncons, car x), env, context)
  3457. else if null (w := cdr w) then
  3458. s!:comval(list('list2, car x, cadr x), env, context)
  3459. else if null cdr w then
  3460. s!:comval(list('list3, car x, cadr x, car w), env, context)
  3461. else s!:comval(list('list2!*, car x, cadr x, 'list . w), env, context)
  3462. end;
  3463. put('list, 's!:compfn, function s!:comlist);
  3464. symbolic procedure s!:comlist!*(x, env, context);
  3465. begin
  3466. scalar w;
  3467. if null (x := cdr x) then return s!:comval(nil, env, context);
  3468. s!:a_reg_values := nil;
  3469. if null (w := cdr x) then
  3470. s!:comval(car x, env, context)
  3471. else if null (w := cdr w) then
  3472. s!:comval(list('cons, car x, cadr x), env, context)
  3473. else if null cdr w then
  3474. s!:comval(list('list2!*, car x, cadr x, car w), env, context)
  3475. else s!:comval(list('list2!*, car x, cadr x, 'list!* . w), env, context)
  3476. end;
  3477. put('list!*, 's!:compfn, function s!:comlist!*);
  3478. symbolic procedure s!:comcons(x, env, context);
  3479. begin
  3480. scalar a, b;
  3481. a := cadr x;
  3482. b := caddr x;
  3483. if b=nil or b='(quote nil) then
  3484. s!:comval(list('ncons, a), env, context)
  3485. else if eqcar(a, 'cons) then
  3486. s!:comval(list('acons, cadr a, caddr a, b), env, context)
  3487. else if eqcar(b, 'cons) then
  3488. if null caddr b then s!:comval(list('list2, a, cadr b), env, context)
  3489. else s!:comval(list('list2!*, a, cadr b, caddr b), env, context)
  3490. !#if (not common!-lisp!-mode)
  3491. % For Common Lisp it seems that I *must* evaluate args strictly left-to-right.
  3492. else if not !*ord and s!:iseasy a and not s!:iseasy b then
  3493. s!:comval(list('xcons, b, a), env, context)
  3494. !#endif
  3495. else s!:comcall(x, env, context)
  3496. end;
  3497. put('cons, 's!:compfn, function s!:comcons);
  3498. !#if common!-lisp!-mode
  3499. % I must not open-compile VECTOR in Standard Lisp mode because REDUCE
  3500. % has a function of that name that is nothing like the one I support here.
  3501. % But the version here can be useful so that things like
  3502. % (vector e1 e2 ... en)
  3503. % for large n do not generate function calls with excessive numbers of args.
  3504. symbolic procedure s!:vector_compilermacro(x, env, context);
  3505. begin
  3506. scalar args, n, n1, r, w, v, i;
  3507. v := gensym();
  3508. i := gensym();
  3509. args := cdr x;
  3510. n := n1 := length args;
  3511. while n > 12 do <<
  3512. w := nil;
  3513. for j := 1:12 do << w := car args . w; args := cdr args >>;
  3514. r := list('setq, i, ('fill!-vector . v . i . reverse w)) . r;
  3515. n := n - 12 >>;
  3516. if n > 0 then r := ('fill!-vector . v . i . args) . r;
  3517. r := 'let .
  3518. list(list(v, list('mkvect, n1-1)),
  3519. list(i, 0)) .
  3520. reverse (v . r);
  3521. return r
  3522. end;
  3523. put('vector, 's!:compilermacro, function s!:vector_compilermacro);
  3524. symbolic procedure s!:commv!-call(x, env, context);
  3525. begin
  3526. scalar fn, args;
  3527. fn := cadr x;
  3528. args := for each v in cddr x collect list('mv!-list!*, v);
  3529. args := expand(args, 'append);
  3530. if not (fn = '(function list)) then
  3531. args := list('apply, fn, args);
  3532. s!:comval(args, env, context)
  3533. end;
  3534. put('multiple!-value!-call, 's!:compfn, function s!:commv!-call);
  3535. symbolic procedure s!:commv!-prog1(x, env, context);
  3536. begin
  3537. x := cdr x;
  3538. if null x then return s!:comval(nil, env, context)
  3539. else if null cdr x then return s!:comval(car x, env, context);
  3540. s!:comval(list('mv!-list!*, car x), env, context);
  3541. s!:outopcode0('PUSH, '(PUSH));
  3542. rplacd(env, 0 . cdr env);
  3543. for each a in x do
  3544. s!:comval(a, env, if context >= 4 then context else 2);
  3545. s!:outopcode0('POP, '(POP));
  3546. rplacd(env, cddr env);
  3547. s!:loadliteral('values, env);
  3548. s!:outopcode1('BUILTIN2, get('apply1, 's!:builtin2), 'apply1)
  3549. end;
  3550. put('multiple!-value!-prog1, 's!:compfn, function s!:commv!-prog1);
  3551. !#endif
  3552. symbolic procedure s!:comapply(x, env, context);
  3553. begin
  3554. scalar a, b, n;
  3555. a := cadr x; % fn
  3556. b := caddr x; % args
  3557. % I collect the very special idiom
  3558. % (apply xxx (list A B C ...))
  3559. % and map it on to
  3560. % (funcall xxx A B C)
  3561. % but if the list is made up on any other way (eg using a mixture of
  3562. % calls to LIST and CONS) I just let it go through the usual slower route.
  3563. if null cdddr x and eqcar(b, 'list) then <<
  3564. if eqcar(a, 'quote) then return <<
  3565. n := s!:current_function;
  3566. begin
  3567. scalar s!:current_function;
  3568. % the re-binding of current-function is to avoid use of callself
  3569. % in some cases (e.g. the autoloader) when the function I am
  3570. % in has just been redefined.
  3571. s!:current_function := compress
  3572. append(explode n, '!! . '!. . explodec
  3573. (s!:current_count := s!:current_count + 1));
  3574. return s!:comval(cadr a . cdr b, env, context)
  3575. end >>;
  3576. n := length (b := cdr b);
  3577. return s!:comval('funcall . a . b, env, context) >>
  3578. else if null b and null cdddr x then
  3579. return s!:comval(list('funcall, a), env, context)
  3580. else return s!:comcall(x, env, context)
  3581. end;
  3582. put('apply, 's!:compfn, function s!:comapply);
  3583. symbolic procedure s!:imp_funcall u;
  3584. begin
  3585. scalar n;
  3586. u := cdr u;
  3587. if eqcar(car u, 'function) then return s!:improve(cadar u . cdr u);
  3588. n := length cdr u;
  3589. u := if n = 0 then 'apply0 . u
  3590. else if n = 1 then 'apply1 . u
  3591. else if n = 2 then 'apply2 . u
  3592. else if n = 3 then 'apply3 . u
  3593. % else if n = 4 then 'apply4 . u
  3594. else 'funcall!* . u;
  3595. !#if record!-use!-of!-funcall
  3596. % If this flag is set when the compiler is built then every "funcall" in the
  3597. % original source will get logged. If there are too many of them this
  3598. % can be painfully expensive.
  3599. u := list('progn,
  3600. list('s!:record_funcall, mkquote s!:current_function, mkquote u),
  3601. u);
  3602. !#endif
  3603. return u
  3604. end;
  3605. !#if record!-use!-of!-funcall
  3606. global '(all_funcalls);
  3607. symbolic procedure s!:record_funcall(fromfn, call);
  3608. begin
  3609. scalar w;
  3610. if not memq(fromfn, all_funcalls) then
  3611. all_funcalls := fromfn . all_funcalls;
  3612. w := get(fromfn, 'all_funcalls);
  3613. while not atom w and not atom car w and not (caar w = call) do w := cdr w;
  3614. if null w then
  3615. put(fromfn, 'all_funcalls, (call . 1) . get(fromfn, 'all_funcalls))
  3616. else rplacd(car w, cdar w + 1)
  3617. end;
  3618. symbolic procedure display!-funcalls();
  3619. begin
  3620. scalar w;
  3621. w := linelength 500;
  3622. terpri();
  3623. for each fn in all_funcalls do <<
  3624. for each x in get(fn, 'all_funcalls) do <<
  3625. princ cdr x; ttab 10; prin fn; ttab 40; prin car x; terpri() >>;
  3626. remprop(fn, 'all_funcalls) >>;
  3627. all_funcalls := nil;
  3628. terpri();
  3629. linelength w;
  3630. end;
  3631. !#endif
  3632. put('funcall, 's!:tidy_fn, 's!:imp_funcall);
  3633. !#if (not common!-lisp!-mode)
  3634. %
  3635. % The next few cases are concerned with demoting functions that use
  3636. % equal tests into ones that use eq instead
  3637. symbolic procedure s!:eval_to_eq_safe x;
  3638. null x or
  3639. x=t or
  3640. (not symbolp x and eq!-safe x) or
  3641. (not atom x and flagp(car x, 'eq!-safe)) or
  3642. (eqcar(x, 'quote) and (symbolp cadr x or eq!-safe cadr x));
  3643. symbolic procedure s!:eval_to_eq_unsafe x;
  3644. (atom x and not symbolp x and not eq!-safe x) or
  3645. (not atom x and flagp(car x, 'eq!-unsafe)) or
  3646. (eqcar(x, 'quote) and (not atom cadr x or
  3647. (not symbolp cadr x and not eq!-safe cadr x)));
  3648. flag('(eq eqcar null not greaterp lessp geq leq minusp
  3649. atom numberp consp), 'eq!-safe);
  3650. if not eq!-safe 1 then
  3651. flag('(length plus minus difference times quotient
  3652. plus2 times2 expt fix float), 'eq!-unsafe);
  3653. symbolic procedure s!:list_all_eq_safe u;
  3654. atom u or
  3655. ((symbolp car u or eq!-safe car u) and s!:list_all_eq_safe cdr u);
  3656. symbolic procedure s!:eval_to_list_all_eq_safe x;
  3657. null x or
  3658. (eqcar(x, 'quote) and s!:list_all_eq_safe cadr x) or
  3659. (eqcar(x, 'list) and
  3660. (null cdr x or
  3661. (s!:eval_to_eq_safe cadr x and
  3662. s!:eval_to_list_all_eq_safe ('list . cddr x)))) or
  3663. (eqcar(x, 'cons) and
  3664. s!:eval_to_eq_safe cadr x and
  3665. s!:eval_to_list_all_eq_safe caddr x);
  3666. symbolic procedure s!:eval_to_eq_unsafe x;
  3667. (numberp x and not eq!-safe x) or
  3668. stringp x or
  3669. (eqcar(x, 'quote) and
  3670. (not atom cadr x or
  3671. (numberp cadr x and not eq!-safe cadr x) or
  3672. stringp cadr x));
  3673. symbolic procedure s!:list_some_eq_unsafe u;
  3674. not atom u and
  3675. (s!:eval_to_eq_unsafe car u or s!:list_some_eq_unsafe cdr u);
  3676. symbolic procedure s!:eval_to_list_some_eq_unsafe x;
  3677. if atom x then nil
  3678. else if eqcar(x, 'quote) then s!:list_some_eq_unsafe cadr x
  3679. else if eqcar(x, 'list) and cdr x then
  3680. s!:eval_to_eq_unsafe cadr x or s!:eval_to_list_some_eq_unsafe ('list . cddr x)
  3681. else if eqcar(x, 'cons) then
  3682. s!:eval_to_eq_unsafe cadr x or s!:eval_to_list_some_eq_unsafe caddr x
  3683. else nil;
  3684. symbolic procedure s!:eval_to_car_eq_safe x;
  3685. (eqcar(x, 'cons) or eqcar(x, 'list)) and
  3686. not null cdr x and
  3687. s!:eval_to_eq_safe cadr x;
  3688. symbolic procedure s!:eval_to_car_eq_unsafe x;
  3689. (eqcar(x, 'cons) or eqcar(x, 'list)) and
  3690. not null cdr x and
  3691. s!:eval_to_eq_unsafe cadr x;
  3692. symbolic procedure s!:alist_eq_safe u;
  3693. atom u or
  3694. (not atom car u and
  3695. (symbolp caar u or eq!-safe caar u) and
  3696. s!:alist_eq_safe cdr u);
  3697. symbolic procedure s!:eval_to_alist_eq_safe x;
  3698. null x or
  3699. (eqcar(x, 'quote) and s!:alist_eq_safe cadr x) or
  3700. (eqcar(x, 'list) and
  3701. (null cdr x or
  3702. (s!:eval_to_car_eq_safe cadr x and
  3703. s!:eval_to_alist_eq_safe ('list . cddr x)))) or
  3704. (eqcar(x, 'cons) and
  3705. s!:eval_to_car_eq_safe cadr x and
  3706. s!:eval_to_alist_eq_safe caddr x);
  3707. symbolic procedure s!:alist_eq_unsafe u;
  3708. not atom u and
  3709. not atom car u and
  3710. (not atom caar u or
  3711. (not symbolp caar u and not eq!-safe caar u) or
  3712. s!:alist_eq_unsafe cdr u);
  3713. symbolic procedure s!:eval_to_alist_eq_unsafe x;
  3714. if null x then nil
  3715. else if eqcar(x, 'quote) then s!:alist_eq_unsafe cadr x
  3716. else if eqcar(x, 'list) then
  3717. (cdr x and
  3718. (s!:eval_to_car_eq_unsafe cadr x or
  3719. s!:eval_to_alist_eq_unsafe ('list . cddr x)))
  3720. else if eqcar(x, 'cons) then
  3721. s!:eval_to_car_eq_unsafe cadr x or
  3722. s!:eval_to_alist_eq_safe caddr x
  3723. else nil;
  3724. symbolic procedure s!:comequal(x, env, context);
  3725. if s!:eval_to_eq_safe cadr x or
  3726. s!:eval_to_eq_safe caddr x then
  3727. s!:comcall('eq . cdr x, env, context)
  3728. else s!:comcall(x, env, context);
  3729. put('equal, 's!:compfn, function s!:comequal);
  3730. symbolic procedure s!:comeq(x, env, context);
  3731. if s!:eval_to_eq_unsafe cadr x or
  3732. s!:eval_to_eq_unsafe caddr x then <<
  3733. if posn() neq 0 then terpri();
  3734. princ "++++ EQ on number upgraded to EQUAL in ";
  3735. prin s!:current_function; princ " : ";
  3736. prin cadr x; princ " "; print caddr x;
  3737. s!:comcall('equal . cdr x, env, context) >>
  3738. else s!:comcall(x, env, context);
  3739. put('eq, 's!:compfn, function s!:comeq);
  3740. symbolic procedure s!:comeqcar(x, env, context);
  3741. if s!:eval_to_eq_unsafe caddr x then <<
  3742. if posn() neq 0 then terpri();
  3743. princ "++++ EQCAR on number upgraded to EQUALCAR in ";
  3744. prin s!:current_function; princ " : ";
  3745. prin caddr x;
  3746. s!:comcall('equalcar . cdr x, env, context) >>
  3747. else s!:comcall(x, env, context);
  3748. put('eqcar, 's!:compfn, function s!:comeqcar);
  3749. symbolic procedure s!:comsublis(x, env, context);
  3750. if s!:eval_to_alist_eq_safe cadr x then
  3751. s!:comval('subla . cdr x, env, context)
  3752. else s!:comcall(x, env, context);
  3753. put('sublis, 's!:compfn, function s!:comsublis);
  3754. symbolic procedure s!:comsubla(x, env, context);
  3755. if s!:eval_to_alist_eq_unsafe cadr x then <<
  3756. if posn() neq 0 then terpri();
  3757. princ "++++ SUBLA on number upgraded to SUBLIS in ";
  3758. prin s!:current_function; princ " : ";
  3759. print cadr x;
  3760. s!:comval('sublis . cdr x, env, context) >>
  3761. else s!:comcall(x, env, context);
  3762. put('subla, 's!:compfn, function s!:comsubla);
  3763. symbolic procedure s!:comassoc(x, env, context);
  3764. if (s!:eval_to_eq_safe cadr x or s!:eval_to_alist_eq_safe caddr x) and length x = 3 then
  3765. s!:comval('atsoc . cdr x, env, context)
  3766. else if length x = 3 then s!:comcall('assoc!*!* . cdr x, env, context)
  3767. else s!:comcall(x, env, context);
  3768. put('assoc, 's!:compfn, function s!:comassoc);
  3769. put('assoc!*!*, 's!:compfn, function s!:comassoc);
  3770. symbolic procedure s!:comatsoc(x, env, context);
  3771. if (s!:eval_to_eq_unsafe cadr x or
  3772. s!:eval_to_alist_eq_unsafe caddr x) then <<
  3773. if posn() neq 0 then terpri();
  3774. princ "++++ ATSOC on number upgraded to ASSOC in ";
  3775. prin s!:current_function; princ " : ";
  3776. prin cadr x; princ " "; print caddr x;
  3777. s!:comval('assoc . cdr x, env, context) >>
  3778. else s!:comcall(x, env, context);
  3779. put('atsoc, 's!:compfn, function s!:comatsoc);
  3780. symbolic procedure s!:commember(x, env, context);
  3781. if (s!:eval_to_eq_safe cadr x or s!:eval_to_list_all_eq_safe caddr x) and length x = 3 then
  3782. s!:comval('memq . cdr x, env, context)
  3783. else s!:comcall(x, env, context);
  3784. put('member, 's!:compfn, function s!:commember);
  3785. put('member!*!*, 's!:compfn, function s!:commember);
  3786. symbolic procedure s!:commemq(x, env, context);
  3787. if (s!:eval_to_eq_unsafe cadr x or s!:eval_to_list_some_eq_unsafe caddr x) then <<
  3788. if posn() neq 0 then terpri();
  3789. princ "++++ MEMQ on number upgraded to MEMBER in ";
  3790. prin s!:current_function; princ " : ";
  3791. prin cadr x; princ " "; print caddr x;
  3792. s!:comval('member . cdr x, env, context) >>
  3793. else s!:comcall(x, env, context);
  3794. put('memq, 's!:compfn, function s!:commemq);
  3795. !#if (not common!-lisp!-mode)
  3796. symbolic procedure s!:comdelete(x, env, context);
  3797. if (s!:eval_to_eq_safe cadr x or s!:eval_to_list_all_eq_safe caddr x) and length x = 3 then
  3798. s!:comval('deleq . cdr x, env, context)
  3799. else s!:comcall(x, env, context);
  3800. put('delete, 's!:compfn, function s!:comdelete);
  3801. symbolic procedure s!:comdeleq(x, env, context);
  3802. if (s!:eval_to_eq_unsafe cadr x or s!:eval_to_list_some_eq_unsafe caddr x) then <<
  3803. if posn() neq 0 then terpri();
  3804. princ "++++ DELEQ on number upgraded to DELETE in ";
  3805. prin s!:current_function; princ " : ";
  3806. prin cadr x; princ " "; print caddr x;
  3807. s!:comval('delete . cdr x, env, context) >>
  3808. else s!:comcall(x, env, context);
  3809. put('deleq, 's!:compfn, function s!:comdeleq);
  3810. !#endif
  3811. % mapcar etc are compiled specially as a fudge to achieve an effect as
  3812. % if proper environment-capture was implemented for the functional
  3813. % argument (which I do not support at present). Not done (here) for
  3814. % Common Lisp since args to mapcar etc are in the other order.
  3815. symbolic procedure s!:commap(fnargs, env, context);
  3816. begin
  3817. scalar carp, fn, fn1, args, var, avar, moveon, l1, r, s, closed;
  3818. fn := car fnargs;
  3819. % if the value of a mapping function is not needed I demote from mapcar to
  3820. % mapc or from maplist to map.
  3821. if context > 1 then <<
  3822. if fn = 'mapcar then fn := 'mapc
  3823. else if fn = 'maplist then fn := 'map >>;
  3824. if fn = 'mapc or fn = 'mapcar or fn = 'mapcan then carp := t;
  3825. fnargs := cdr fnargs;
  3826. if atom fnargs then error(0,"bad arguments to map function");
  3827. fn1 := cadr fnargs;
  3828. while eqcar(fn1, 'function) or
  3829. (eqcar(fn1, 'quote) and eqcar(cadr fn1, 'lambda)) do <<
  3830. fn1 := cadr fn1;
  3831. closed := t >>;
  3832. % if closed is false I will insert FUNCALL since I am invoking a function
  3833. % stored in a variable - NB this means that the word FUNCTION becomes
  3834. % essential when using mapping operators - this is because I have built
  3835. % a 2-Lisp rather than a 1-Lisp.
  3836. args := car fnargs;
  3837. l1 := gensym();
  3838. r := gensym();
  3839. s := gensym();
  3840. var := gensym();
  3841. avar := var;
  3842. if carp then avar := list('car, avar);
  3843. % Here if closed is true and fn1 is of the form (lambda (w) ... w ...) where
  3844. % the local variable occurs only once in the body, and w is not fluid or
  3845. % global (and there had better be no other bindings to wreck scope) then I
  3846. % might simplify by doing a textual substitution here rather than a real
  3847. % lambda binding. Maybe I should detect such cases in the code that
  3848. % compiles the application of lambda expressions? For now do not bother!
  3849. if closed then fn1 := list(fn1, avar)
  3850. else fn1 := list('funcall, fn1, avar);
  3851. moveon := list('setq, var, list('cdr, var));
  3852. if fn = 'map or fn = 'mapc then fn := sublis(
  3853. list('l1 . l1, 'var . var,
  3854. 'fn . fn1, 'args . args, 'moveon . moveon),
  3855. '(prog (var)
  3856. (setq var args)
  3857. l1 (cond
  3858. ((not var) (return nil)))
  3859. fn
  3860. moveon
  3861. (go l1)))
  3862. else if fn = 'maplist or fn = 'mapcar then fn := sublis(
  3863. list('l1 . l1, 'var . var,
  3864. 'fn . fn1, 'args . args, 'moveon . moveon, 'r . r),
  3865. '(prog (var r)
  3866. (setq var args)
  3867. l1 (cond
  3868. ((not var) (return (reversip r))))
  3869. (setq r (cons fn r))
  3870. moveon
  3871. (go l1)))
  3872. else fn := sublis(
  3873. list('l1 . l1, 'l2 . gensym(), 'var . var,
  3874. 'fn . fn1, 'args . args, 'moveon . moveon,
  3875. 'r . gensym(), 's . gensym()),
  3876. '(prog (var r s)
  3877. (setq var args)
  3878. (setq r (setq s (list nil)))
  3879. l1 (cond
  3880. ((not var) (return (cdr r))))
  3881. (rplacd s fn)
  3882. l2 (cond
  3883. ((not (atom (cdr s))) (setq s (cdr s)) (go l2)))
  3884. moveon
  3885. (go l1)));
  3886. s!:comval(fn, env, context)
  3887. end;
  3888. put('map, 's!:compfn, function s!:commap);
  3889. put('maplist, 's!:compfn, function s!:commap);
  3890. put('mapc, 's!:compfn, function s!:commap);
  3891. put('mapcar, 's!:compfn, function s!:commap);
  3892. put('mapcon, 's!:compfn, function s!:commap);
  3893. put('mapcan, 's!:compfn, function s!:commap);
  3894. !#endif
  3895. !#if common!-lisp!-mode
  3896. % The next few cases are concerned with demoting functions that use
  3897. % equal tests into ones that use eq instead
  3898. symbolic procedure s!:eval_to_eq_safe x;
  3899. null x or x=t or eq!-safe x or
  3900. (eqcar(x, 'quote) and (symbolp cadr x or eq!-safe cadr x));
  3901. symbolic procedure s!:list_all_eq_safe u;
  3902. atom u or
  3903. ((symbolp car u or eq!-safe car u) and s!:list_all_eq_safe cdr u);
  3904. symbolic procedure s!:eval_to_list_some_eq_unsafe x;
  3905. null x or
  3906. (eqcar(x, 'quote) and s!:list_all_eq_safe cadr x) or
  3907. (eqcar(x, 'list) and
  3908. (null cdr x or
  3909. (s!:eval_to_eq_safe cadr x and
  3910. s!:eval_to_list_some_eq_unsafe ('list . cddr x)))) or
  3911. (eqcar(x, 'cons) and
  3912. s!:eval_to_eq_safe cadr x and
  3913. s!:eval_to_list_some_eq_unsafe caddr x);
  3914. symbolic procedure s!:eval_to_car_eq_safe x;
  3915. (eqcar(x, 'cons) or eqcar(x, 'list)) and
  3916. not null cdr x and
  3917. s!:eval_to_eq_safe cadr x;
  3918. symbolic procedure s!:alist_eq_safe u;
  3919. atom u or
  3920. (not atom car u and
  3921. (symbolp caar u or eq!-safe caar u) and
  3922. s!:alist_eq_safe cdr u);
  3923. symbolic procedure s!:eval_to_alist_eq_safe x;
  3924. null x or
  3925. (eqcar(x, 'quote) and s!:alist_eq_safe cadr x) or
  3926. (eqcar(x, 'list) and
  3927. (null cdr x or
  3928. (s!:eval_to_car_eq_safe cadr x and
  3929. s!:eval_to_alist_eq_safe ('list . cddr x)))) or
  3930. (eqcar(x, 'cons) and
  3931. s!:eval_to_car_eq_safe cadr x and
  3932. s!:eval_to_alist_eq_safe caddr x);
  3933. symbolic procedure s!:comsublis(x, env, context);
  3934. if s!:eval_to_alist_eq_safe cadr x then
  3935. s!:comval('subla . cdr x, env, context)
  3936. else s!:comcall(x, env, context);
  3937. put('sublis, 's!:compfn, function s!:comsublis);
  3938. symbolic procedure s!:comassoc(x, env, context);
  3939. if length x = 3 then s!:comcall('atsoc . cdr x, env, context)
  3940. else if length x = 5 and
  3941. cadddr x = '!:test and
  3942. (cadddr cdr x = '(function equal) or
  3943. cadddr cdr x = '(quote equal) or
  3944. cadddr cdr x = 'equal) then
  3945. s!:comval(list('assoc!*!*, cadr x, caddr x), env, context)
  3946. else s!:comcall(x, env, context);
  3947. put('assoc, 's!:compfn, function s!:comassoc);
  3948. symbolic procedure s!:comassoc!*!*(x, env, context);
  3949. if s!:eval_to_eq_safe cadr x or s!:eval_to_alist_eq_safe caddr x then
  3950. s!:comval('atsoc . cdr x, env, context)
  3951. else s!:comcall(x, env, context);
  3952. put('assoc!*!*, 's!:compfn, function s!:comassoc!*!*);
  3953. symbolic procedure s!:commember(x, env, context);
  3954. if length x = 3 then s!:comcall('memq . cdr x, env, context)
  3955. else if length x = 5 and
  3956. cadddr x = '!:test and
  3957. (cadddr cdr x = '(function equal) or
  3958. cadddr cdr x = '(quote equal) or
  3959. cadddr cdr x = 'equal) then
  3960. s!:comval(list('member!*!*, cadr x, caddr x), env, context)
  3961. else if length x = 5 and cadddr x = !:test then begin
  3962. scalar r, g0, g1, g2;
  3963. g0 := gensym(); g1 := gensym(); g2 := gensym();
  3964. r := list('prog, list(g0, g1),
  3965. list('setq, g0, cadr x),
  3966. list('setq, g1, caddr x),
  3967. g2,
  3968. list('cond,
  3969. list(list('null, g1), list('return, nil)),
  3970. list(list('funcall, cadddr cdr x, g0, list('car, g1)),
  3971. list('return, g1))),
  3972. list('setq, g1, list('cdr, g1)),
  3973. list('go, g2));
  3974. return s!:comval(r, env, context) end
  3975. else s!:comcall(x, env, context);
  3976. put('member, 's!:compfn, function s!:commember);
  3977. symbolic procedure s!:commember!*!*(x, env, context);
  3978. if s!:eval_to_eq_safe cadr x or s!:eval_to_list_some_eq_unsafe caddr x then <<
  3979. if posn() neq 0 then terpri();
  3980. princ "++++ MEMQ on number upgraded to MEMBER in ";
  3981. prin s!:current_function; princ " : ";
  3982. prin cadr x; princ " "; print caddr x;
  3983. s!:comval('memq . cdr x, env, context) >>;
  3984. else s!:comcall(x, env, context);
  3985. put('member!*!*, 's!:compfn, function s!:commember!*!*);
  3986. !#endif
  3987. symbolic procedure s!:nilargs use;
  3988. if null use then t
  3989. else if car use = 'nil or car use = '(quote nil) then s!:nilargs cdr use
  3990. else nil;
  3991. symbolic procedure s!:subargs(args, use);
  3992. if null use then t
  3993. else if null args then s!:nilargs use
  3994. else if not (car args = car use) then nil
  3995. else s!:subargs(cdr args, cdr use);
  3996. fluid '(!*where_defined!*);
  3997. symbolic procedure clear_source_database();
  3998. << !*where_defined!* := mkhash(10, 2, 1.5);
  3999. nil >>;
  4000. symbolic procedure load_source_database filename;
  4001. begin
  4002. scalar a, b;
  4003. clear_source_database();
  4004. !#if common!-lisp!-mode
  4005. a := open(filename, !:direction, !:input, !:if!-does!-not!-exist, nil);
  4006. !#else
  4007. a := open(filename, 'input);
  4008. !#endif
  4009. if null a then return nil;
  4010. a := rds a;
  4011. while (b := read()) do
  4012. puthash(car b, !*where_defined!*, cdr b);
  4013. close rds a;
  4014. return nil
  4015. end;
  4016. symbolic procedure save_source_database filename;
  4017. begin
  4018. scalar a;
  4019. !#if common!-lisp!-mode
  4020. a := open(filename, !:direction, !:output);
  4021. !#else
  4022. a := open(filename, 'output);
  4023. !#endif
  4024. if null a then return nil;
  4025. a := wrs a;
  4026. for each z in sort(hashcontents !*where_defined!*, function orderp) do <<
  4027. prin z; terpri() >>;
  4028. princ nil; terpri();
  4029. wrs a;
  4030. !*where_defined!* := nil;
  4031. return nil
  4032. end;
  4033. symbolic procedure display_source_database();
  4034. begin
  4035. scalar w;
  4036. if null !*where_defined!* then return nil;
  4037. w := hashcontents !*where_defined!*;
  4038. w := sort(w, function orderp);
  4039. terpri();
  4040. for each x in w do <<
  4041. princ car x;
  4042. ttab 40;
  4043. prin cdr x;
  4044. terpri() >>
  4045. end;
  4046. % s!:compile1 directs the compilation of a single function, and bind all the
  4047. % major fluids used by the compilation process
  4048. symbolic procedure s!:compile1(name, args, body, s!:lexical_env);
  4049. begin
  4050. scalar w, aargs, oargs, oinit, restarg, svars, nargs, nopts, env, fluids,
  4051. s!:current_function, s!:current_label, s!:current_block,
  4052. s!:current_size, s!:current_procedure, s!:current_exitlab,
  4053. s!:current_proglabels, s!:other_defs, local_decs, s!:has_closure,
  4054. s!:local_macros, s!:recent_literals, s!:a_reg_values, w1, w2,
  4055. s!:current_count;
  4056. s!:current_function := name;
  4057. s!:current_count := 0;
  4058. if !*where_defined!* then <<
  4059. !#if common!-lisp!-mode
  4060. w := symbol!-package name;
  4061. if w then w := list(package!-name w, symbol!-name name);
  4062. !#else
  4063. w := name;
  4064. !#endif
  4065. puthash(w, !*where_defined!*, where!-was!-that()) >>;
  4066. body := s!:find_local_decs body;
  4067. local_decs := car body; body := cdr body;
  4068. if atom body then body := nil
  4069. else if null cdr body then body := car body
  4070. else body := 'progn . body;
  4071. nargs := nopts := 0;
  4072. while args and
  4073. not eqcar(args, '!&optional) and
  4074. not eqcar(args, '!&rest) do <<
  4075. if car args = '!&key or car args = '!&aux then error(0, "&key/&aux");
  4076. aargs := car args . aargs;
  4077. nargs := nargs + 1;
  4078. args := cdr args >>;
  4079. if eqcar(args, '!&optional) then <<
  4080. args := cdr args;
  4081. while args and not eqcar(args, '!&rest) do <<
  4082. if car args = '!&key or car args = '!&aux then error(0, "&key/&aux");
  4083. w := car args;
  4084. % Things that are written as (v) or (v nil) might as well have
  4085. % been treated as just v. I use a WHILE loop so that silly people
  4086. % who write (((((v))))) get their code reduced to just v.
  4087. while not atom w and
  4088. (atom cdr w or cdr w = '(nil)) do w := car w;
  4089. args := cdr args;
  4090. oargs := w . oargs;
  4091. nopts := nopts + 1;
  4092. if atom w then aargs := w . aargs
  4093. else <<
  4094. oinit := t;
  4095. aargs := car w . aargs;
  4096. if not atom cddr w then svars := caddr w . svars >> >> >>;
  4097. if eqcar(args, '!&rest) then <<
  4098. w := cadr args;
  4099. aargs := w . aargs;
  4100. restarg := w;
  4101. args := cddr args;
  4102. if args then error(0, "&rest arg not at end") >>;
  4103. % NB I have not allowed for &aux or &key - I take the view that
  4104. % they will be expanded out by a DEFUN macro.
  4105. args := reverse aargs;
  4106. % The variable args is now a map of how my arguments will actually be
  4107. % presented to me on the stack.
  4108. oargs := reverse oargs; % Optional args, possibly with initforms
  4109. % oinit is true if there are initforms.
  4110. % Now I will TRY to be kind. If any variable mentioned in the argument list
  4111. % is a GLOBAL I will convert it to FLUID, but tell the user that that
  4112. % has happened.
  4113. for each v in append(svars, args) do <<
  4114. if globalp v then <<
  4115. if !*pwrds then <<
  4116. if posn() neq 0 then terpri();
  4117. princ "+++++ global ";
  4118. prin v;
  4119. princ " converted to fluid";
  4120. terpri() >>;
  4121. unglobal list v;
  4122. fluid list v >> >>;
  4123. if oinit then
  4124. return s!:compile2(name, nargs, nopts,
  4125. args, oargs, restarg, body, local_decs);
  4126. w := nil;
  4127. for each v in args do w := s!:instate_local_decs(v, local_decs, w);
  4128. for each v on args do <<
  4129. if fluidp car v then begin
  4130. scalar g;
  4131. g := gensym();
  4132. fluids := (car v . g) . fluids;
  4133. rplaca(v, g) end >>;
  4134. % In the case that the variables a and b are fluid, I map
  4135. % (lambda (a b) X) onto
  4136. % (lambda (g1 g2) (prog (a b) (setq a g1) (setq b g2) (return X)))
  4137. % and then let the compilation of the PROG deal with the fluid bindings.
  4138. % [I worry a bit about adding an extra PROG here, since it can mean that
  4139. % RETURN becomes valid when it used not to...]. Note that since the
  4140. % variable g1, g2 ... are all new gensyms none of them can be locally special
  4141. % so at least I do not have muddle because of that.
  4142. if fluids then <<
  4143. body := list list('return, body);
  4144. for each v in fluids do
  4145. body := list('setq, car v, cdr v) . body;
  4146. body := 'prog .
  4147. (for each v in fluids collect car v) . body >>;
  4148. % If I am compiling in-store I will common up literals only if they are EQL.
  4149. % However if s!:faslmod_name is set then I am compiling to a file, and in
  4150. % that case I will dare common things up if they are EQUAL. The reasoning
  4151. % behind this is that going via a file necesarily loses EQ-ness on some
  4152. % things, so one can afford to do som while for in-store compilation it
  4153. % could make sense to preserve sharing (or not) between literal lists in
  4154. % the code being compiled.
  4155. env := mkhash(10, (if s!:faslmod_name then 2 else 1), 1.5) .
  4156. reverse args;
  4157. puthash(name, car env, 10000000 . nil);
  4158. w := s!:residual_local_decs(local_decs, w);
  4159. s!:start_procedure(nargs, nopts, restarg);
  4160. % Now, so that I will be able to take special action on cases which would
  4161. % compile into nothing more than a tail-call operation, I do a bit of
  4162. % early expansion. If this does not reveal that I have a definition
  4163. % of the form (de f1 (a b c ...) (f2 a b c)) then I ignore what I have done
  4164. % to let comval handle it in the normal way...
  4165. w1 := body;
  4166. more:
  4167. if atom w1 then nil
  4168. else if car w1 = 'block and length w1 = 3 then <<
  4169. w1 := caddr w1; go to more >>
  4170. else if car w1 = 'progn and length w1 = 2 then <<
  4171. w1 := cadr w1; go to more >>
  4172. else if atom (w2 := car w1) and (w2 := get(w2, 's!:newname)) then <<
  4173. w1 := w2 . cdr w1; go to more >>
  4174. else if atom (w2 := car w1) and (w2 := macro!-function w2) then <<
  4175. w1 := funcall(w2, w1); go to more >>;
  4176. if not ((w2 := s!:improve w1) = w1) then << w1 := w2; go to more >>;
  4177. if not atom w1 and atom car w1 and not special!-form!-p car w1 and
  4178. s!:subargs(args, cdr w1) and
  4179. % Just for the moment I will only enable this special case code for
  4180. % instances where the new function has less than 3 args and the one it calls
  4181. % does not need nil-padding.
  4182. nargs <= 3 and nopts = 0 and not restarg and
  4183. length cdr w1 <= nargs then <<
  4184. s!:cancel_local_decs w;
  4185. if restarg then nopts := nopts + 512;
  4186. % The argument count info gets bits added in here to show how many args
  4187. % must be passed on. If this is larger than the number originally provided
  4188. % it means that nils should be padded onto the end.
  4189. nopts := nopts + 1024*length w1;
  4190. nargs := nargs + 256*nopts;
  4191. if !*pwrds then <<
  4192. if posn() neq 0 then terpri();
  4193. princ "+++ "; prin name; princ " compiled as link to ";
  4194. princ car w1; terpri() >>;
  4195. return (name . nargs . nil . car w1) . s!:other_defs >>;
  4196. s!:comval(body, env, 0);
  4197. s!:cancel_local_decs w;
  4198. % This returns a list of values suitable for handing to symbol-set-definition
  4199. if restarg then nopts := nopts + 512;
  4200. nargs := nargs + 256*nopts;
  4201. return (name . nargs . s!:endprocedure(name, env)) . s!:other_defs;
  4202. end;
  4203. symbolic procedure s!:compile2(name, nargs, nopts,
  4204. args, oargs, restarg, body, local_decs);
  4205. % If I have any &optional args that have initforms then I will generate
  4206. % code in a very cautious, slow and pessimistic manner - because I need
  4207. % to be able to evaluate the initforms in an environment where the
  4208. % previously mentioned arguments have all been bound, but subsequent
  4209. % ones have not.
  4210. begin
  4211. scalar fluids, env, penv, g, v, init, atend, w;
  4212. % I start off with an environment that shows how deep my stack is, but
  4213. % which does not give any names to the locations on it.
  4214. for each v in args do <<
  4215. env := 0 . env;
  4216. penv := env . penv >>;
  4217. env := mkhash(10, (if s!:faslmod_name then 2 else 1), 1.5) . env;
  4218. puthash(name, car env, 10000000 . nil);
  4219. penv := reversip penv;
  4220. % I make the list of optional args as long as the complete arg list - with
  4221. % zero entries for things that are not optional.
  4222. if restarg then oargs := append(oargs, '(0));
  4223. for i := 1:nargs do oargs := 0 . oargs;
  4224. s!:start_procedure(nargs, nopts, restarg);
  4225. while args do <<
  4226. v := car args;
  4227. init := car oargs;
  4228. if init = 0 then <<
  4229. w := s!:instate_local_decs(v, local_decs, w);
  4230. if fluidp v then <<
  4231. g := gensym();
  4232. rplaca(car penv, g);
  4233. s!:outopcode1lit('FREEBIND, s!:vecof list v, env);
  4234. rplacd(env, 3 . 0 . 0 . cdr env);
  4235. atend := 'FREERSTR . atend;
  4236. s!:comval(list('setq, v, g), env, 2) >>
  4237. else rplaca(car penv, v) >>
  4238. else begin
  4239. scalar ival, sp, l1, l2;
  4240. if not atom init then <<
  4241. init := cdr init;
  4242. ival := car init;
  4243. if not atom cdr init then sp := cadr init >>;
  4244. l1 := gensym();
  4245. g := gensym();
  4246. rplaca(car penv, g);
  4247. if null ival and null sp then
  4248. s!:comval(list('setq, g, list('spid!-to!-nil, g)), env, 1)
  4249. else <<
  4250. s!:jumpif(nil, list('is!-spid, g), env, l1);
  4251. % Here is code for when an initform must be activated.
  4252. s!:comval(list('setq, g, ival), env, 1);
  4253. if sp then <<
  4254. if fluidp sp then <<
  4255. s!:outopcode1lit('FREEBIND, s!:vecof list sp, env);
  4256. s!:outjump('JUMP, l2 := gensym());
  4257. s!:set_label l1;
  4258. s!:outopcode1lit('FREEBIND, s!:vecof list sp, env);
  4259. rplacd(env, 3 . 0 . 0 . cdr env);
  4260. s!:comval(list('setq, sp, t), env, 1);
  4261. s!:set_label l2;
  4262. atend := 'FREERSTR . atend >>
  4263. else <<
  4264. s!:outopcode0('PUSHNIL, '(PUSHNIL));
  4265. s!:outjump('JUMP, l2 := gensym());
  4266. s!:set_label l1;
  4267. s!:loadliteral(t, env);
  4268. s!:outopcode0('PUSH, '(PUSH));
  4269. s!:set_label l2;
  4270. rplacd(env, sp . cdr env);
  4271. atend := 'LOSE . atend >> >>
  4272. else s!:set_label l1 >>;
  4273. w := s!:instate_local_decs(v, local_decs, w);
  4274. if fluidp v then <<
  4275. s!:outopcode1lit('FREEBIND, s!:vecof list v, env);
  4276. rplacd(env, 3 . 0 . 0 . cdr env);
  4277. s!:comval(list('setq, v, g), env, 1);
  4278. atend := 'FREERSTR . atend >>
  4279. else rplaca(car penv, v)
  4280. end;
  4281. args := cdr args;
  4282. oargs := cdr oargs;
  4283. penv := cdr penv >>;
  4284. w := s!:residual_local_decs(local_decs, w);
  4285. s!:comval(body, env, 0);
  4286. while atend do <<
  4287. s!:outopcode0(car atend, list car atend);
  4288. atend := cdr atend >>;
  4289. s!:cancel_local_decs w;
  4290. nopts := nopts + 256; % Always have complex &optional here
  4291. if restarg then nopts := nopts + 512;
  4292. nargs := nargs + 256*nopts;
  4293. return (name . nargs . s!:endprocedure(name, env)) . s!:other_defs;
  4294. end;
  4295. % compile-all may be invoked at any time to ensure that everything that can be
  4296. % has been compiled
  4297. !#if common!-lisp!-mode
  4298. symbolic procedure compile!-all;
  4299. % Bootstrapping issues mean that I can not easily use do-all-symbols() here
  4300. for each p in list!-all!-packages() do begin
  4301. scalar !*package!*;
  4302. !*package!* := find!-package p;
  4303. for each x in oblist() do
  4304. begin scalar w;
  4305. w := getd x;
  4306. if (eqcar(w, 'expr) or eqcar(w, 'macro)) and
  4307. eqcar(cdr w, 'lambda) then <<
  4308. princ "Compile: "; prin x; terpri();
  4309. errorset(list('compile, mkquote list x), t, t) >> end end;
  4310. !#else
  4311. symbolic procedure compile!-all;
  4312. for each x in oblist() do begin
  4313. scalar w;
  4314. w := getd x;
  4315. if (eqcar(w, 'expr) or eqcar(w, 'macro)) and
  4316. eqcar(cdr w, 'lambda) then <<
  4317. princ "Compile: "; prin x; terpri();
  4318. errorset(list('compile, mkquote list x), t, t) >> end;
  4319. !#endif
  4320. % Support for a FASL mechanism, styled after that which I expect existing
  4321. % Standard Lisp applications to require.
  4322. % The 'eval and 'ignore flags are to help the RLISP interface to the
  4323. % fasl mechanism
  4324. flag('(rds deflist flag fluid global
  4325. remprop remflag unfluid
  4326. unglobal dm defmacro carcheck
  4327. faslend c_end), 'eval);
  4328. flag('(rds), 'ignore);
  4329. fluid '(!*backtrace);
  4330. symbolic procedure s!:fasl_supervisor;
  4331. begin
  4332. scalar u, w, !*echo;
  4333. top:u := errorset('(read), t, !*backtrace);
  4334. if atom u then return; % failed, or maybe EOF
  4335. u := car u;
  4336. if u = !$eof!$ then return; % end of file
  4337. if not atom u then u := macroexpand u; % In case it expands into (DE ...)
  4338. if atom u then go to top
  4339. % the apply('faslend, nil) is here because faslend has a "stat" property
  4340. % and so it will mis-parse if I just write "faslend()". Yuk.
  4341. else if eqcar(u, 'faslend) then return apply('faslend, nil)
  4342. !#if common!-lisp!-mode
  4343. else if eqcar(u, 'load) then << <<
  4344. w := open(u := eval cadr u, !:direction, !:input,
  4345. !:if!-does!-not!-exist, nil);
  4346. !#else
  4347. else if eqcar(u, 'rdf) then <<
  4348. w := open(u := eval cadr u, 'input);
  4349. !#endif
  4350. if w then <<
  4351. terpri();
  4352. princ "Reading file "; prin u; terpri();
  4353. w := rds w;
  4354. s!:fasl_supervisor();
  4355. princ "End of file "; prin u; terpri();
  4356. close rds w >>
  4357. else << princ "Failed to open file "; prin u; terpri() >> >>
  4358. !#if common!-lisp!-mode
  4359. >> where !*package!* = !*package!*
  4360. !#endif
  4361. else s!:fslout0 u;
  4362. go to top
  4363. end;
  4364. symbolic procedure s!:fslout0 u;
  4365. s!:fslout1(u, nil);
  4366. symbolic procedure s!:fslout1(u, loadonly);
  4367. begin
  4368. scalar w;
  4369. if not atom u then u := macroexpand u;
  4370. if atom u then return nil
  4371. else if eqcar(u, 'progn) then <<
  4372. for each v in cdr u do s!:fslout1(v, loadonly);
  4373. return >>
  4374. else if eqcar(u, 'eval!-when) then return begin
  4375. w := cadr u;
  4376. u := 'progn . cddr u;
  4377. if memq('compile, w) and not loadonly then eval u;
  4378. if memq('load, w) then s!:fslout1(u, t);
  4379. return nil end
  4380. % When called from REDUCE the treatment of things flagged as EVAL here
  4381. % will end up leading to them getting evaluated twice. Often this will
  4382. % not matter - a case where I have had to be careful is in (faslend) which
  4383. % can thus be called twice: the second call must be ignored.
  4384. else if flagp(car u, 'eval) or
  4385. % The special treatment here is so that (setq x (carcheck 0)) will get
  4386. % picked up as needing compile-time evaluation.
  4387. (car u = 'setq and not atom caddr u and flagp(caaddr u, 'eval)) then
  4388. if not loadonly then errorset(u, t, !*backtrace);
  4389. !#if common!-lisp!-mode
  4390. if eqcar(u, 'load) then << begin
  4391. w := open(u := eval cadr u, !:direction, !:input,
  4392. !:if!-does!-not!-exist, nil);
  4393. !#else
  4394. if eqcar(u, 'rdf) then begin
  4395. w := open(u := eval cadr u, 'input);
  4396. !#endif
  4397. if w then <<
  4398. princ "Reading file "; prin u; terpri();
  4399. w := rds w;
  4400. s!:fasl_supervisor();
  4401. princ "End of file "; prin u; terpri();
  4402. close rds w
  4403. >>
  4404. else << princ "Failed to open file "; prin u; terpri() >> end
  4405. !#if common!-lisp!-mode
  4406. >> where !*package!* = !*package!*
  4407. !#endif
  4408. else if !*nocompile then << % Funny option not for general use!
  4409. if not eqcar(u, 'faslend) and
  4410. not eqcar(u, 'carcheck) then write!-module u >>
  4411. else if eqcar(u, 'de) or eqcar(u, 'defun) then <<
  4412. u := cdr u;
  4413. if (w := get(car u, 'c!-version)) and
  4414. w = md60 (cadr u . s!:fully_macroexpand_list cddr u) then <<
  4415. princ "+++ "; prin car u;
  4416. printc " not compiled (C version available)";
  4417. write!-module list('restore!-c!-code, mkquote car u) >>
  4418. else if flagp(car u, 'lose) then <<
  4419. princ "+++ "; prin car u;
  4420. printc " not compiled (LOSE flag)" >>
  4421. else for each p in s!:compile1(car u, cadr u, cddr u, nil) do
  4422. s!:fslout2(p, u) >>
  4423. else if eqcar(u, 'dm) or eqcar(u, 'defmacro) then begin
  4424. scalar g;
  4425. g := hashtagged!-name(cadr u, cddr u);
  4426. u := cdr u;
  4427. % At present (and maybe for ever?) macros can not be compiled into C.
  4428. %
  4429. % if (w := get(car u, 'c!-version)) and
  4430. % md60 u = w then <<
  4431. % princ "+++ "; prin car u;
  4432. % printc " not compiled (C version available flag)";
  4433. % return nil >>
  4434. % else
  4435. if flagp(car u, 'lose) then <<
  4436. princ "+++ "; prin car u;
  4437. printc " not compiled (LOSE flag)";
  4438. return nil >>;
  4439. w := cadr u;
  4440. if w and null cdr w then w := car w . '!&optional . gensym() . nil;
  4441. for each p in s!:compile1(g, w, cddr u, nil) do s!:fslout2(p, u);
  4442. write!-module list('dm, car u, '(u !&optional e), list(g, 'u, 'e))
  4443. end
  4444. else if eqcar(u, 'putd) then begin
  4445. % If people put (putd 'name 'expr '(lambda ...)) in their file I will
  4446. % expand it out as if it had been a (de name ...) [similarly for macros].
  4447. scalar a1, a2, a3;
  4448. a1 := cadr u; a2 := caddr u; a3 := cadddr u;
  4449. if eqcar(a1, 'quote) and
  4450. (a2 = '(quote expr) or a2 = '(quote macro)) and
  4451. (eqcar(a3, 'quote) or eqcar(a3, 'function)) and
  4452. eqcar(cadr a3, 'lambda) then <<
  4453. a1 := cadr a1; a2 := cadr a2; a3 := cadr a3;
  4454. u := (if a2 = 'expr then 'de else 'dm) . a1 . cdr a3;
  4455. % More complicated uses of PUTD may defeat the C-version hack...
  4456. s!:fslout1(u, loadonly) >>
  4457. else write!-module u end
  4458. else if not eqcar(u, 'faslend) and
  4459. not eqcar(u, 'carcheck) then write!-module u
  4460. end;
  4461. symbolic procedure s!:fslout2(p, u);
  4462. begin
  4463. scalar name, nargs, code, env, w;
  4464. name := car p;
  4465. nargs := cadr p;
  4466. code := caddr p;
  4467. env := cdddr p;
  4468. if !*savedef and name = car u then <<
  4469. % I associate the saved definition with the top-level function
  4470. % that is being defined, and ignore any embedded lambda expressions
  4471. define!-in!-module(-1); % savedef marker
  4472. write!-module('lambda . cadr u . s!:fully_macroexpand_list cddr u) >>;
  4473. % If the FASL file format tail-call definitions are represented by giving the
  4474. % number of args in the thing to chain to as an integer where otherwise
  4475. % a vector of bytecodes would be provided.
  4476. w := irightshift(nargs, 18);
  4477. nargs := logand(nargs, 262143); % 0x3ffff
  4478. if not (w = 0) then code := w - 1;
  4479. define!-in!-module nargs;
  4480. write!-module name;
  4481. write!-module code;
  4482. write!-module env
  4483. end;
  4484. symbolic procedure faslend;
  4485. begin
  4486. if null s!:faslmod_name then return nil;
  4487. start!-module nil;
  4488. dfprint!* := s!:dfprintsave;
  4489. !*defn := nil;
  4490. !*comp := cdr s!:faslmod_name;
  4491. s!:faslmod_name := nil;
  4492. return nil
  4493. end;
  4494. put('faslend, 'stat, 'endstat);
  4495. symbolic procedure faslout u;
  4496. begin
  4497. terpri();
  4498. princ "FASLOUT ";
  4499. prin u; princ ": IN files; or type in expressions"; terpri();
  4500. princ "When all done, execute FASLEND;"; terpri();
  4501. % I permit the argument to be either a name, or a list of one item
  4502. % that is a name. The idea here is that when called from RLISP it is
  4503. % most convenient for the call to map onto (faslout '(xxx)), while direct
  4504. % use from Lisp favours (faslout 'xxx)
  4505. if not atom u then u := car u;
  4506. if not start!-module u then <<
  4507. if posn() neq 0 then terpri();
  4508. princ "+++ Failed to open FASL output file"; terpri();
  4509. return nil >>;
  4510. s!:faslmod_name := u . !*comp;
  4511. s!:dfprintsave := dfprint!*;
  4512. dfprint!* := 's!:fslout0;
  4513. !*defn := t;
  4514. !*comp := nil;
  4515. if getd 'begin then return nil;
  4516. s!:fasl_supervisor();
  4517. end;
  4518. put('faslout, 'stat, 'rlis);
  4519. symbolic procedure s!:c_supervisor;
  4520. begin
  4521. scalar u, w, !*echo;
  4522. top:u := errorset('(read), t, !*backtrace);
  4523. if atom u then return; % failed, or maybe EOF
  4524. u := car u;
  4525. if u = !$eof!$ then return; % end of file
  4526. if not atom u then u := macroexpand u; % In case it expands into (DE ...)
  4527. if atom u then go to top
  4528. % the apply('c_end, nil) is here because c_end has a "stat" property
  4529. % and so it will mis-parse if I just write "c_end()". Yuk.
  4530. else if eqcar(u, 'c_end) then return apply('c_end, nil)
  4531. !#if common!-lisp!-mode
  4532. else if eqcar(u, 'load) then << <<
  4533. w := open(u := eval cadr u, !:direction, !:input,
  4534. !:if!-does!-not!-exist, nil);
  4535. !#else
  4536. else if eqcar(u, 'rdf) then <<
  4537. w := open(u := eval cadr u, 'input);
  4538. !#endif
  4539. if w then <<
  4540. terpri();
  4541. princ "Reading file "; prin u; terpri();
  4542. w := rds w;
  4543. s!:c_supervisor();
  4544. princ "End of file "; prin u; terpri();
  4545. close rds w
  4546. >>
  4547. else << princ "Failed to open file "; prin u; terpri() >> >>
  4548. !#if common!-lisp!-mode
  4549. >> where !*package!* = !*package!*
  4550. !#endif
  4551. else s!:cout0 u;
  4552. go to top
  4553. end;
  4554. symbolic procedure s!:cout0 u;
  4555. s!:cout1(u, nil);
  4556. symbolic procedure s!:cout1(u, loadonly);
  4557. begin
  4558. scalar s!:into_c;
  4559. s!:into_c := t;
  4560. if not atom u then u := macroexpand u;
  4561. if atom u then return nil
  4562. else if eqcar(u, 'progn) then <<
  4563. for each v in cdr u do s!:cout1(v, loadonly);
  4564. return >>
  4565. else if eqcar(u, 'eval!-when) then return begin
  4566. scalar w;
  4567. w := cadr u;
  4568. u := 'progn . cddr u;
  4569. if memq('compile, w) and not loadonly then eval u;
  4570. if memq('load, w) then s!:cout1(u, t);
  4571. return nil end
  4572. % When called from REDUCE the treatment of things flagged as EVAL here
  4573. % will end up leading to them getting evaluated twice. Often this will
  4574. % not matter - a case where I have had to be careful is in (c_end) which
  4575. % can thus be called twice: the second call must be ignored.
  4576. else if flagp(car u, 'eval) or
  4577. % The special treatment here is so that (setq x (carcheck 0)) will get
  4578. % picked up as needing compile-time evaluation.
  4579. (car u = 'setq and not atom caddr u and flagp(caaddr u, 'eval)) then
  4580. if not loadonly then errorset(u, t, !*backtrace);
  4581. !#if common!-lisp!-mode
  4582. if eqcar(u, 'load) then << begin
  4583. scalar w;
  4584. w := open(u := eval cadr u, !:direction, !:input,
  4585. !:if!-does!-not!-exist, nil);
  4586. !#else
  4587. if eqcar(u, 'rdf) then begin
  4588. scalar w;
  4589. w := open(u := eval cadr u, 'input);
  4590. !#endif
  4591. if w then <<
  4592. princ "Reading file "; prin u; terpri();
  4593. w := rds w;
  4594. s!:c_supervisor();
  4595. princ "End of file "; prin u; terpri();
  4596. close rds w
  4597. >>
  4598. else << princ "Failed to open file "; prin u; terpri() >> end
  4599. !#if common!-lisp!-mode
  4600. >> where !*package!* = !*package!*
  4601. !#endif
  4602. else if eqcar(u, 'de) or eqcar(u, 'defun) then begin
  4603. scalar w;
  4604. u := cdr u;
  4605. w := s!:compile1(car u, cadr u, cddr u, nil);
  4606. for each p in w do s!:cgen(car p, cadr p, caddr p, cdddr p)
  4607. end
  4608. else if eqcar(u, 'dm) or eqcar(u, 'defmacro) then begin
  4609. scalar w, g;
  4610. g := hashtagged!-name(cadr u, cddr u);
  4611. u := cdr u;
  4612. w := cadr u; % List of bound vars. Either (u) or (u &optional e) (?)
  4613. if w and null cdr w then w := car w . '!&optional . gensym() . nil;
  4614. w := s!:compile1(g, w, cddr u, nil);
  4615. for each p in w do s!:cgen(car p, cadr p, caddr p, cdddr p);
  4616. s!:cinit list('dm, car u, '(u !&optional e), list(g, 'u, 'e))
  4617. end
  4618. else if eqcar(u, 'putd) then begin
  4619. % If people put (putd 'name 'expr '(lambda ...)) in their file I will
  4620. % expand it out as if it had been a (de name ...) [similarly for macros].
  4621. % This is done at least once in REDUCE.
  4622. scalar a1, a2, a3;
  4623. a1 := cadr u; a2 := caddr u; a3 := cadddr u;
  4624. if eqcar(a1, 'quote) and
  4625. (a2 = '(quote expr) or a2 = '(quote macro)) and
  4626. (eqcar(a3, 'quote) or eqcar(a3, 'function)) and
  4627. eqcar(cadr a3, 'lambda) then <<
  4628. a1 := cadr a1; a2 := cadr a2; a3 := cadr a3;
  4629. u := (if a2 = 'expr then 'de else 'dm) . a1 . cdr a3;
  4630. s!:cout1(u, loadonly) >>
  4631. else s!:cinit u end
  4632. else if not eqcar(u, 'c_end) and
  4633. not eqcar(u, 'carcheck) then s!:cinit u
  4634. end;
  4635. fluid '(s!:cmod_name);
  4636. symbolic procedure c_end;
  4637. begin
  4638. if null s!:cmod_name then return nil;
  4639. s!:cend();
  4640. dfprint!* := s!:dfprintsave;
  4641. !*defn := nil;
  4642. !*comp := cdr s!:cmod_name;
  4643. s!:cmod_name := nil;
  4644. return nil
  4645. end;
  4646. put('c_end, 'stat, 'endstat);
  4647. symbolic procedure c_out u;
  4648. begin
  4649. terpri();
  4650. princ "C_OUT ";
  4651. prin u; princ ": IN files; or type in expressions"; terpri();
  4652. princ "When all done, execute C_END;"; terpri();
  4653. % I permit the argument to be either a name, or a list of one item
  4654. % that is a name. The idea here is that when called from RLISP it is
  4655. % most convenient for the call to map onto (c_out '(xxx)), while direct
  4656. % use from Lisp favours (c_out 'xxx)
  4657. if not atom u then u := car u;
  4658. if null s!:cstart u then <<
  4659. if posn() neq 0 then terpri();
  4660. princ "+++ Failed to open C output file"; terpri();
  4661. return nil >>;
  4662. s!:cmod_name := u . !*comp;
  4663. s!:dfprintsave := dfprint!*;
  4664. dfprint!* := 's!:cout0;
  4665. !*defn := t;
  4666. !*comp := nil;
  4667. if getd 'begin then return nil;
  4668. s!:c_supervisor();
  4669. end;
  4670. put('c_out, 'stat, 'rlis);
  4671. symbolic procedure s!:compile!-file!*(fromfile,
  4672. !&optional, tofile, verbose, !*pwrds);
  4673. begin
  4674. scalar !*comp, w, save;
  4675. if null tofile then tofile := fromfile;
  4676. if verbose then <<
  4677. if posn() neq 0 then terpri();
  4678. !#if common!-lisp!-mode
  4679. princ ";; Compiling file ";
  4680. !#else
  4681. princ "+++ Compiling file ";
  4682. !#endif
  4683. prin fromfile;
  4684. terpri();
  4685. save := verbos nil;
  4686. verbos ilogand(save, 4) >>;
  4687. if not start!-module tofile then <<
  4688. if posn() neq 0 then terpri();
  4689. princ "+++ Failed to open FASL output file"; terpri();
  4690. if save then verbos save;
  4691. return nil >>;
  4692. !#if common!-lisp!-mode
  4693. << w := open(fromfile, !:direction, !:input,
  4694. !:if!-does!-not!-exist, nil);
  4695. !#else
  4696. w := open(fromfile, 'input);
  4697. !#endif
  4698. if w then <<
  4699. w := rds w;
  4700. s!:fasl_supervisor();
  4701. close rds w >>
  4702. else << princ "Failed to open file "; prin fromfile; terpri() >>
  4703. !#if common!-lisp!-mode
  4704. >> where !*package!* = !*package!*;
  4705. !#else
  4706. ;
  4707. !#endif
  4708. if save then verbos save;
  4709. start!-module nil;
  4710. if verbose then <<
  4711. if posn() neq 0 then terpri();
  4712. !#if common!-lisp!-mode
  4713. princ ";; Compilation complete";
  4714. !#else
  4715. princ "+++ Compilation complete";
  4716. !#endif
  4717. terpri() >>;
  4718. return t
  4719. end;
  4720. % I provide a version that will suffice for Standard Lisp and replace it
  4721. % later on in the Common Lisp case (where keyword args are needed)
  4722. symbolic procedure compile!-file!*(fromfile, !&optional, tofile);
  4723. s!:compile!-file!*(fromfile, tofile, t, t);
  4724. symbolic procedure compd(name, type, defn);
  4725. begin
  4726. scalar g, !*comp;
  4727. !*comp := t;
  4728. if eqcar(defn, 'lambda) then <<
  4729. g := dated!-name type;
  4730. symbol!-set!-definition(g, defn);
  4731. compile list g;
  4732. defn := g >>;
  4733. put(name, type, defn);
  4734. return name
  4735. end;
  4736. symbolic procedure s!:compile0 name;
  4737. begin
  4738. scalar w, args, defn;
  4739. defn := getd name;
  4740. if eqcar(defn, 'macro) and eqcar(cdr defn, 'lambda) then
  4741. begin
  4742. scalar !*comp, lx, vx, bx;
  4743. % If I have a macro definition
  4744. % (dm fff (v) (ggg ...))
  4745. % I will usually map it onto a pair of definitions
  4746. % (dm fff (v) (fff!* v))
  4747. % (de fff!* (v) (ggg ...))
  4748. % and then compile fff!* but not fff itself. If this has been done already
  4749. % or the initial definition of fff was in the required form then I will
  4750. % not perform any transformation and I will not compile fff.
  4751. % I also need to detect the case
  4752. % (dm fff (v &optional e) (fff!* v e))
  4753. lx := cdr defn; % (LAMBDA vx bx)
  4754. if not ((length lx = 3 and
  4755. not atom (bx := caddr lx) and
  4756. cadr lx = cdr bx) or
  4757. (length lx = 3 and
  4758. not atom (bx := caddr lx) and
  4759. not atom cadr lx and eqcar(cdadr lx, '!&optional) and
  4760. not atom (bx := cdr bx) and caadr lx = car bx and
  4761. cddadr lx = cdr bx)) then <<
  4762. w := hashtagged!-name(name, defn);
  4763. symbol!-set!-definition(w, cdr defn);
  4764. s!:compile0 w;
  4765. if 1 = length cadr lx then
  4766. symbol!-set!-env(name, list('(u !&optional env),
  4767. list(w, 'u)))
  4768. else symbol!-set!-env(name, list('(u !&optional env),
  4769. list(w, 'u, 'env))) >>
  4770. end
  4771. else if not eqcar(defn, 'expr) or not eqcar(cdr defn, 'lambda) then <<
  4772. if !*pwrds then <<
  4773. if posn() neq 0 then terpri();
  4774. princ "+++ "; prin name; princ " not compilable"; terpri() >> >>
  4775. else <<
  4776. args := cddr defn;
  4777. defn := cdr args;
  4778. args := car args;
  4779. if stringp args then <<
  4780. if !*pwrds then <<
  4781. if posn() neq 0 then terpri();
  4782. princ "+++ "; prin name; princ " was already compiled";
  4783. terpri() >> >>
  4784. else <<
  4785. if !*savedef then
  4786. put(name, '!*savedef,
  4787. 'lambda . args . s!:fully_macroexpand_list defn);
  4788. w := s!:compile1(name, args, defn, nil);
  4789. for each p in w do
  4790. symbol!-set!-definition(car p, cdr p) >> >>
  4791. end;
  4792. symbolic procedure s!:fully_macroexpand_list l;
  4793. for each u in l collect s!:fully_macroexpand u;
  4794. symbolic procedure s!:fully_macroexpand x;
  4795. % This MUST match the logic in s!:comval, so that there are no oddities
  4796. % about which order expansions are done in.
  4797. begin
  4798. scalar helper;
  4799. if atom x or eqcar(x, 'quote) then return x
  4800. else if eqcar(car x, 'lambda) then return
  4801. ('lambda . cadar x . s!:fully_macroexpand_list cddar x) .
  4802. s!:fully_macroexpand_list cdr x
  4803. !#if common!-lisp!-mode
  4804. else if helper := s!:local_macro car x then <<
  4805. if atom cdr helper then
  4806. s!:fully_macroexpand('funcall . cdr helper . cdr x)
  4807. else s!:fully_macroexpand funcall('lambda . cdr helper, x) >>
  4808. !#endif
  4809. % NB I do not expand compilermacros here. Actually at present "vector"
  4810. % seems to be the only function that has one.
  4811. else if (helper := get(car x, 's!:newname)) then
  4812. return s!:fully_macroexpand (helper . cdr x)
  4813. else if helper := get(car x, 's!:expandfn) then
  4814. return funcall(helper, x)
  4815. else if helper := macro!-function car x then
  4816. return s!:fully_macroexpand funcall(helper, x)
  4817. else return car x . s!:fully_macroexpand_list cdr x
  4818. end;
  4819. symbolic procedure s!:expandfunction u;
  4820. u;
  4821. symbolic procedure s!:expandflet u;
  4822. error("expand", u);
  4823. symbolic procedure s!:expandlabels u;
  4824. error("expand", u);
  4825. symbolic procedure s!:expandmacrolet u;
  4826. error("expand", u);
  4827. symbolic procedure s!:expandprog u;
  4828. car u . cadr u . s!:fully_macroexpand_list cddr u;
  4829. symbolic procedure s!:expandtagbody u;
  4830. s!:fully_macroexpand_list u;
  4831. symbolic procedure s!:expandprogv u;
  4832. car u . cadr u . caddr u . s!:fully_macroexpand_list cadddr u;
  4833. symbolic procedure s!:expandblock u;
  4834. car u . cadr u . s!:fully_macroexpand_list cddr u;
  4835. symbolic procedure s!:expanddeclare u;
  4836. u;
  4837. symbolic procedure s!:expandlet u;
  4838. car u . (for each x in cadr u collect s!:fully_macroexpand_list x) .
  4839. s!:fully_macroexpand_list cddr u;
  4840. symbolic procedure s!:expandlet!* u;
  4841. s!:expandlet u;
  4842. symbolic procedure s!:expandgo u;
  4843. u;
  4844. symbolic procedure s!:expandreturn!-from u;
  4845. car u . cadr u . s!:fully_macroexpand_list cddr u;
  4846. symbolic procedure s!:expandcond u;
  4847. car u . for each x in cdr u collect s!:fully_macroexpand_list x;
  4848. symbolic procedure s!:expandcase u;
  4849. car u . for each x in cdr u collect
  4850. (car x . s!:fully_macroexpand_list cdr x);
  4851. symbolic procedure s!:expandeval!-when u;
  4852. car u . cadr u . s!:fully_macroexpand_list cddr u;
  4853. symbolic procedure s!:expandthe u;
  4854. car u . cadr u . s!:fully_macroexpand_list cddr u;
  4855. symbolic procedure s!:expandmv!-call u;
  4856. car u . cadr u . s!:fully_macroexpand_list cddr u;
  4857. put('function, 's!:expandfn, function s!:expandfunction);
  4858. put('flet, 's!:expandfn, function s!:expandflet);
  4859. put('labels, 's!:expandfn, function s!:expandlabels);
  4860. put('macrolet, 's!:expandfn, function s!:expandmacrolet);
  4861. put('prog, 's!:expandfn, function s!:expandprog);
  4862. put('tagbody, 's!:expandfn, function s!:expandtagbody);
  4863. put('progv, 's!:expandfn, function s!:expandprogv);
  4864. !#if common!-lisp!-mode
  4865. put('block, 's!:expandfn, function s!:expandblock);
  4866. !#else
  4867. put('!~block, 's!:expandfn, function s!:expandblock);
  4868. !#endif
  4869. put('declare, 's!:expandfn, function s!:expanddeclare);
  4870. !#if common!-lisp!-mode
  4871. put('let, 's!:expandfn, function s!:expandlet);
  4872. !#else
  4873. put('!~let, 's!:expandfn, function s!:expandlet);
  4874. !#endif
  4875. put('let!*, 's!:expandfn, function s!:expandlet!*);
  4876. put('go, 's!:expandfn, function s!:expandgo);
  4877. put('return!-from, 's!:expandfn, function s!:expandreturn!-from);
  4878. put('cond, 's!:expandfn, function s!:expandcond);
  4879. put('case, 's!:expandfn, function s!:expandcase);
  4880. put('eval!-when, 's!:expandfn, function s!:expandeval!-when);
  4881. put('the, 's!:expandfn, function s!:expandthe);
  4882. put('multiple!-value!-call, 's!:expandfn, function s!:expandmv!-call);
  4883. % As soon as compile() is defined, !*comp enables automatic compilation
  4884. % when functions are defined - so I must put the definition of compile
  4885. % right at the end of this file so that nothing untoward happens during
  4886. % initial building.
  4887. symbolic procedure compile l;
  4888. begin
  4889. if atom l and not null l then l := list l;
  4890. for each name in l do
  4891. errorset(list('s!:compile0, mkquote name), t, t);
  4892. return l
  4893. end;
  4894. end;
  4895. % End of compiler.red