compiler.red 212 KB

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