QbeGen.mod 148 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937
  1. IMPLEMENTATION MODULE QbeGen;
  2. IMPORT FileIO, SymTab;
  3. VAR
  4. out : FileIO.File;
  5. opened : BOOLEAN;
  6. inBody : BOOLEAN;
  7. dead : BOOLEAN; (* TRUE past a terminator: next instruction opens
  8. an unreachable block with a fresh label, so
  9. the .ssa stays valid QBE (no dangling temps,
  10. no instruction outside a block). *)
  11. nTemp : CARDINAL;
  12. nLab : CARDINAL;
  13. loopTop : CARDINAL;
  14. loopSt : ARRAY [0 .. 15] OF QVal;
  15. nR : CARDINAL; (* non-zero REAL consts flushed at BeginBody *)
  16. rNames : ARRAY [0 .. 31] OF QVal;
  17. rVals : ARRAY [0 .. 31] OF QVal;
  18. nStr : CARDINAL; (* string-literal data counter *)
  19. strNams : ARRAY [0 .. 4095] OF QVal;
  20. strTexts : ARRAY [0 .. 4095] OF ARRAY [0 .. 255] OF CHAR;
  21. (* UString literals: decoded codepoints, recorded for EndModule. *)
  22. ustrN : CARDINAL;
  23. ustrNams : ARRAY [0 .. 255] OF QVal;
  24. ustrStart : ARRAY [0 .. 255] OF CARDINAL;
  25. ustrCount : ARRAY [0 .. 255] OF CARDINAL;
  26. ustrPool : ARRAY [0 .. 8191] OF INTEGER;
  27. ustrUsed : CARDINAL;
  28. (* array constructors: pooled static descriptors *)
  29. ctorN : CARDINAL;
  30. ctorNam : ARRAY [0 .. 255] OF QVal;
  31. ctorTxt : ARRAY [0 .. 255] OF ARRAY [0 .. 4095] OF CHAR;
  32. ctorUse : ARRAY [0 .. 255] OF BOOLEAN; (* FALSE once inlined as a field *)
  33. ctorTop : CARDINAL;
  34. ctorTyp : ARRAY [0 .. 7] OF INTEGER;
  35. ctorCnt : ARRAY [0 .. 7] OF CARDINAL;
  36. ctorBuf : ARRAY [0 .. 7] OF ARRAY [0 .. 4095] OF CHAR;
  37. ctorEv : ARRAY [0 .. 7] OF ARRAY [0 .. 255] OF QVal;
  38. ctorEk : ARRAY [0 .. 7] OF ARRAY [0 .. 255] OF INTEGER;
  39. (* compile-time set constants: pooled static masks (Lower's PoolSet) *)
  40. setN : CARDINAL;
  41. setNam : ARRAY [0 .. 255] OF QVal; (* "setN" (no $) *)
  42. setW : ARRAY [0 .. 255] OF CARDINAL; (* words per entry *)
  43. setMask : ARRAY [0 .. 255] OF ARRAY [0 .. 15] OF CARDINAL;
  44. withTop : CARDINAL;
  45. withSt : ARRAY [0 .. 7] OF QVal;
  46. noEmit : BOOLEAN; (* TRUE while parsing nested procedures in 4.1:
  47. SymTab tracks, QbeGen suppresses output *)
  48. inFunc : BOOLEAN; (* TRUE inside an emitted function body *)
  49. useStack : BOOLEAN;(* TRUE: NewHeap allocates stack slots *)
  50. funcRes : CHAR; (* current function result class *)
  51. nLoc : CARDINAL; (* function-local name table entries *)
  52. locNames : ARRAY [0 .. 255] OF SymTab.Name;
  53. locTag : ARRAY [0 .. 255] OF INTEGER; (* 0 slot, 1 data, 2 addr *)
  54. locRep : ARRAY [0 .. 255] OF QVal; (* slot temp / mangled / addr *)
  55. locCls : ARRAY [0 .. 255] OF CHAR;
  56. locTyp : ARRAY [0 .. 255] OF INTEGER;
  57. funcDepth : CARDINAL; (* open BeginFuncs; main body = 0 *)
  58. excHas : ARRAY [0 .. 16] OF BOOLEAN;
  59. excBodyL, excHandlerL, excAfterL : ARRAY [0 .. 16] OF QVal;
  60. scopeTop : CARDINAL; (* open procedure scopes *)
  61. scopeBase : ARRAY [0 .. 16] OF CARDINAL;
  62. scopeLink : ARRAY [0 .. 15] OF QVal; (* per-scope link records *)
  63. slTmp : QVal; (* current static-link param temp *)
  64. hdrComma : BOOLEAN;
  65. stkLink : ARRAY [0 .. 15] OF QVal; (* per-call static links *)
  66. stkExt : ARRAY [0 .. 15] OF BOOLEAN; (* per-call external flag *)
  67. stkInd : ARRAY [0 .. 15] OF BOOLEAN; (* per-call indirect flag *)
  68. outSel : CARDINAL; (* 0 = file, else nestBufs[outSel-1] *)
  69. nInit : CARDINAL;
  70. initNames : ARRAY [0 .. 31] OF QVal;
  71. nFini : CARDINAL;
  72. finiNames : ARRAY [0 .. 31] OF QVal;
  73. sessBuf : ARRAY [0 .. 8388607] OF CHAR; (* whole image, buffered (8 MiB:
  74. must hold the compiler's own
  75. image text when self-hosting) *)
  76. sessUsed : CARDINAL;
  77. nestBufs : ARRAY [0 .. 15] OF ARRAY [0 .. 131071] OF CHAR;
  78. nestUsed : ARRAY [0 .. 15] OF CARDINAL;
  79. (* Short-circuit AND/OR: the RHS operand's code is buffered here
  80. (delayTop > 0) and replayed inside the branch. *)
  81. delayBuf : ARRAY [0 .. 15] OF ARRAY [0 .. 8191] OF CHAR;
  82. delayUsed : ARRAY [0 .. 15] OF CARDINAL;
  83. delayTop : CARDINAL;
  84. (* one buffer per nesting depth: each nested function stays
  85. contiguous no matter how deep the parse interleaves *)
  86. nPar : CARDINAL; (* recorded formal params for the header *)
  87. parCls : ARRAY [0 .. 63] OF CHAR;
  88. parTmp : ARRAY [0 .. 63] OF QVal;
  89. parNam : ARRAY [0 .. 63] OF SymTab.Name;
  90. parVar : ARRAY [0 .. 63] OF BOOLEAN;
  91. parTyp : ARRAY [0 .. 63] OF INTEGER;
  92. argBuf : ARRAY [0 .. 4095] OF CHAR; (* accumulated call args *)
  93. hbuf : ARRAY [0 .. 2047] OF CHAR; (* buffered function header *)
  94. nArg : CARDINAL;
  95. recvQ : QVal; (* armed class-method receiver *)
  96. recvArmed : BOOLEAN;
  97. callDepth : CARDINAL; (* nested-call stack *)
  98. stkName : ARRAY [0 .. 15] OF QVal;
  99. stkRes : ARRAY [0 .. 15] OF CHAR;
  100. stkArg : ARRAY [0 .. 15] OF ARRAY [0 .. 1023] OF CHAR;
  101. stkN : ARRAY [0 .. 15] OF CARDINAL;
  102. funcName : QVal; (* current function / call target *)
  103. curModName : SymTab.Name; (* module being compiled (global names) *)
  104. outName : SymTab.Name; (* image-file override (Lower compare) *)
  105. hasOutName : BOOLEAN;
  106. nVal : ARRAY [0 .. 255] OF QVal; (* VAR-actual note keys *)
  107. nAddr : ARRAY [0 .. 255] OF QVal; (* VAR-actual note addresses *)
  108. nn : CARDINAL;
  109. (* Session-state snapshot: Lower runs per unit while the grammar's
  110. suppressed inline emit still mutates these, so Lower saves/restores
  111. its own values around each unit. *)
  112. sav_nTemp, sav_nLab, sav_loopTop, sav_nR, sav_nStr, sav_nLoc,
  113. sav_nPar, sav_nArg, sav_nn, sav_nInit, sav_nFini, sav_sessUsed, sav_delayTop,
  114. sav_ustrN, sav_ustrUsed, sav_ctorN, sav_ctorTop, sav_funcDepth,
  115. sav_scopeTop, sav_callDepth, sav_outSel, sav_withTop,
  116. sav_setN : CARDINAL;
  117. sav_inBody, sav_inFunc, sav_useStack, sav_recvArmed : BOOLEAN;
  118. PROCEDURE SaveSession;
  119. BEGIN
  120. sav_nTemp := nTemp; sav_nLab := nLab; sav_loopTop := loopTop;
  121. sav_nR := nR; sav_nStr := nStr; sav_nLoc := nLoc; sav_nPar := nPar;
  122. sav_nArg := nArg; sav_nn := nn; sav_nInit := nInit;
  123. sav_nFini := nFini;
  124. sav_sessUsed := sessUsed; sav_delayTop := delayTop;
  125. sav_ustrN := ustrN; sav_ustrUsed := ustrUsed;
  126. sav_ctorN := ctorN; sav_ctorTop := ctorTop;
  127. sav_setN := setN;
  128. sav_funcDepth := funcDepth; sav_scopeTop := scopeTop;
  129. sav_callDepth := callDepth; sav_outSel := outSel;
  130. sav_withTop := withTop;
  131. sav_inBody := inBody; sav_inFunc := inFunc;
  132. sav_useStack := useStack; sav_recvArmed := recvArmed
  133. END SaveSession;
  134. PROCEDURE RestoreSession;
  135. VAR i : CARDINAL;
  136. BEGIN
  137. nTemp := sav_nTemp; nLab := sav_nLab; loopTop := sav_loopTop;
  138. nR := sav_nR; nStr := sav_nStr; nLoc := sav_nLoc; nPar := sav_nPar;
  139. nArg := sav_nArg; nInit := sav_nInit; nFini := sav_nFini;
  140. sessUsed := sav_sessUsed; delayTop := sav_delayTop;
  141. ustrN := sav_ustrN; ustrUsed := sav_ustrUsed;
  142. ctorN := sav_ctorN; ctorTop := sav_ctorTop;
  143. setN := sav_setN;
  144. funcDepth := sav_funcDepth; scopeTop := sav_scopeTop;
  145. callDepth := sav_callDepth; outSel := sav_outSel;
  146. withTop := sav_withTop;
  147. inBody := sav_inBody; inFunc := sav_inFunc;
  148. useStack := sav_useStack; recvArmed := sav_recvArmed;
  149. (* Clear the VAR-actual note ring. The grammar's suppressed
  150. parse-time emit never reaches the buffer, but its NoteAddr calls
  151. do fill this ring; AddrOfVal scans the whole ring and the keys
  152. are temps that restart per function, so a stale grammar entry can
  153. false-match Lower's own key. Lower re-notes its own VAR
  154. actuals, so starting from an empty ring is correct. *)
  155. nn := 0;
  156. i := 0;
  157. WHILE i <= HIGH(nVal) DO
  158. nVal[i][0] := CHR(0); nAddr[i][0] := CHR(0); INC(i)
  159. END
  160. END RestoreSession;
  161. (* ---------------- small string utilities ---------------- *)
  162. PROCEDURE Len (s: ARRAY OF CHAR): CARDINAL;
  163. VAR i : CARDINAL;
  164. BEGIN
  165. i := 0;
  166. WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO INC(i) END;
  167. RETURN i
  168. END Len;
  169. PROCEDURE Cpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  170. VAR i : CARDINAL;
  171. BEGIN
  172. i := 0;
  173. WHILE (i <= HIGH(d)) AND (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
  174. d[i] := s[i]; INC(i)
  175. END;
  176. IF i <= HIGH(d) THEN d[i] := CHR(0) END
  177. END Cpy;
  178. PROCEDURE App (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  179. VAR i, j : CARDINAL;
  180. BEGIN
  181. i := 0;
  182. WHILE (i <= HIGH(d)) AND (d[i] # CHR(0)) DO INC(i) END;
  183. j := 0;
  184. WHILE (i <= HIGH(d)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  185. d[i] := s[j]; INC(i); INC(j)
  186. END;
  187. IF i <= HIGH(d) THEN d[i] := CHR(0) END
  188. END App;
  189. PROCEDURE BufApp (VAR buf: ARRAY OF CHAR; VAR used: CARDINAL;
  190. s: ARRAY OF CHAR; eol: BOOLEAN);
  191. VAR j : CARDINAL;
  192. BEGIN
  193. j := 0;
  194. WHILE (used < HIGH(buf)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  195. buf[used] := s[j]; INC(used); INC(j)
  196. END;
  197. IF eol AND (used < HIGH(buf)) THEN
  198. buf[used] := CHR(10); INC(used)
  199. END;
  200. IF used <= HIGH(buf) THEN buf[used] := CHR(0) END
  201. END BufApp;
  202. PROCEDURE WEmit (s: ARRAY OF CHAR; eol: BOOLEAN);
  203. (* Single output sink: the session buffer, or a nesting-depth
  204. buffer for nested functions (QBE rejects definitions inside
  205. functions, so nested bodies hoist until EndModule). *)
  206. VAR b, u, j : CARDINAL;
  207. BEGIN
  208. IF NOT opened OR noEmit THEN RETURN END;
  209. IF delayTop > 0 THEN
  210. b := delayTop - 1;
  211. u := delayUsed[b]; j := 0;
  212. WHILE (u < HIGH(delayBuf[b])) AND (j <= HIGH(s))
  213. AND (s[j] # CHR(0)) DO
  214. delayBuf[b][u] := s[j]; INC(u); INC(j)
  215. END;
  216. IF eol AND (u < HIGH(delayBuf[b])) THEN
  217. delayBuf[b][u] := CHR(10); INC(u)
  218. END;
  219. IF u <= HIGH(delayBuf[b]) THEN delayBuf[b][u] := CHR(0) END;
  220. delayUsed[b] := u;
  221. RETURN
  222. END;
  223. IF outSel = 0 THEN
  224. BufApp(sessBuf, sessUsed, s, eol);
  225. RETURN
  226. END;
  227. b := outSel - 1;
  228. IF b > HIGH(nestBufs) THEN b := HIGH(nestBufs) END;
  229. u := nestUsed[b];
  230. j := 0;
  231. WHILE (u < HIGH(nestBufs[b])) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  232. nestBufs[b][u] := s[j]; INC(u); INC(j)
  233. END;
  234. IF eol AND (u < HIGH(nestBufs[b])) THEN
  235. nestBufs[b][u] := CHR(10); INC(u)
  236. END;
  237. IF u <= HIGH(nestBufs[b]) THEN nestBufs[b][u] := CHR(0) END;
  238. nestUsed[b] := u
  239. END WEmit;
  240. PROCEDURE W (s: ARRAY OF CHAR);
  241. BEGIN
  242. WEmit(s, FALSE)
  243. END W;
  244. PROCEDURE WL (s: ARRAY OF CHAR);
  245. BEGIN
  246. WEmit(s, TRUE)
  247. END WL;
  248. PROCEDURE SetNoEmit (b: BOOLEAN);
  249. BEGIN
  250. noEmit := b
  251. END SetNoEmit;
  252. PROCEDURE DelayBegin;
  253. (* Start buffering output (the RHS operand of a short-circuit AND/OR). *)
  254. BEGIN
  255. IF delayTop <= HIGH(delayBuf) THEN
  256. delayUsed[delayTop] := 0;
  257. delayBuf[delayTop][0] := CHR(0);
  258. INC(delayTop)
  259. END
  260. END DelayBegin;
  261. PROCEDURE DelayEnd;
  262. (* Stop buffering (restore the previous output sink). *)
  263. BEGIN
  264. IF delayTop > 0 THEN DEC(delayTop) END
  265. END DelayEnd;
  266. PROCEDURE DelayFlush;
  267. (* Emit the buffered RHS operand's code into the current sink.
  268. DelayEnd already popped delayTop, so the just-used buffer index is
  269. delayTop itself. *)
  270. VAR b: CARDINAL;
  271. BEGIN
  272. b := delayTop;
  273. IF b <= HIGH(delayBuf) THEN WEmit(delayBuf[b], FALSE) END
  274. END DelayFlush;
  275. PROCEDURE Slot4 (VAR s: QVal);
  276. BEGIN
  277. NewTemp(s);
  278. Revive;
  279. W(" "); W(s); W(" =l alloc4 4"); WL("")
  280. END Slot4;
  281. PROCEDURE StoreW (slot: ARRAY OF CHAR; val: ARRAY OF CHAR);
  282. BEGIN
  283. Revive;
  284. W(" storew "); W(val); W(", "); WL(slot)
  285. END StoreW;
  286. PROCEDURE LoadW (slot: ARRAY OF CHAR; VAR q: QVal);
  287. BEGIN
  288. NewTemp(q);
  289. Revive;
  290. W(" "); W(q); W(" =w loadw "); WL(slot)
  291. END LoadW;
  292. PROCEDURE SetModule (name: ARRAY OF CHAR);
  293. (* Names the module whose globals are being emitted (QBE symbols
  294. become "<mod>_<name>" so separate modules never collide). *)
  295. BEGIN
  296. Cpy(curModName, name)
  297. END SetModule;
  298. PROCEDURE SymRef (name: ARRAY OF CHAR; VAR ref: QVal);
  299. (* "$<mod>_<sym>" for module-level entries (avoids cross-module
  300. collisions); "$<name>" fallback otherwise. *)
  301. VAR g : SymTab.Name;
  302. BEGIN
  303. Cpy(ref, "$");
  304. IF SymTab.GlobalRef(name, g) THEN App(ref, g)
  305. ELSE App(ref, name)
  306. END
  307. END SymRef;
  308. PROCEDURE Wc (c: CHAR);
  309. (* Writes a single class character (w/d/l). *)
  310. VAR s : ARRAY [0 .. 1] OF CHAR;
  311. BEGIN
  312. s[0] := c; s[1] := CHR(0);
  313. W(s)
  314. END Wc;
  315. PROCEDURE AppNum (VAR d: ARRAY OF CHAR; v: CARDINAL);
  316. (* Appends v in decimal to d. *)
  317. VAR buf : ARRAY [0 .. 15] OF CHAR;
  318. n, i, L : CARDINAL;
  319. BEGIN
  320. n := 0;
  321. IF v = 0 THEN buf[0] := "0"; n := 1 END;
  322. WHILE (v > 0) AND (n <= HIGH(buf)) DO
  323. buf[n] := CHR(ORD("0") + v MOD 10); v := v DIV 10; INC(n)
  324. END;
  325. i := n;
  326. WHILE i > 0 DO
  327. DEC(i);
  328. L := Len(d);
  329. IF L < HIGH(d) THEN d[L] := buf[i]; d[L + 1] := CHR(0) END
  330. END
  331. END AppNum;
  332. (* ---------------- exported helpers ---------------- *)
  333. PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  334. BEGIN
  335. Cpy(d, s)
  336. END CopyOp;
  337. PROCEDURE NoteAddr (val: ARRAY OF CHAR; addr: ARRAY OF CHAR);
  338. (* Records value-temp → address mapping for VAR actuals. Ring of
  339. 256: safe because SSA temps are never reused (stale entries can
  340. never false-match, only age out on pathological expressions). *)
  341. BEGIN
  342. Cpy(nVal[nn], val);
  343. Cpy(nAddr[nn], addr);
  344. nn := nn + 1;
  345. IF nn > HIGH(nVal) THEN nn := 0 END
  346. END NoteAddr;
  347. PROCEDURE AddrOfVal (val: ARRAY OF CHAR; VAR addr: QVal): BOOLEAN;
  348. VAR i : CARDINAL;
  349. BEGIN
  350. i := 0;
  351. WHILE i <= HIGH(nVal) DO
  352. IF SymTab.Equal(nVal[i], val) THEN
  353. Cpy(addr, nAddr[i]);
  354. RETURN TRUE
  355. END;
  356. INC(i)
  357. END;
  358. RETURN FALSE
  359. END AddrOfVal;
  360. PROCEDURE AddrOf (name: ARRAY OF CHAR; VAR q: QVal);
  361. VAR idx : INTEGER;
  362. levels : CARDINAL;
  363. BEGIN
  364. IF LocFindUp(name, levels, idx) THEN
  365. IF levels = 0 THEN
  366. IF locTag[idx] = 1 THEN
  367. Cpy(q, "$");
  368. App(q, locRep[idx])
  369. ELSE
  370. Cpy(q, locRep[idx])
  371. END
  372. ELSE
  373. UpAddrOf(idx, levels, q)
  374. END;
  375. RETURN
  376. END;
  377. SymRef(name, q)
  378. END AddrOf;
  379. PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
  380. VAR neg : BOOLEAN;
  381. mag : CARDINAL;
  382. buf : ARRAY [0 .. 15] OF CHAR;
  383. n, i, L : CARDINAL;
  384. t : CHAR;
  385. BEGIN
  386. neg := v < 0;
  387. IF neg THEN mag := VAL(CARDINAL, -v) ELSE mag := VAL(CARDINAL, v) END;
  388. n := 0;
  389. IF mag = 0 THEN buf[0] := "0"; n := 1 END;
  390. WHILE (mag > 0) AND (n < HIGH(buf)) DO
  391. buf[n] := CHR(ORD("0") + mag MOD 10); mag := mag DIV 10; INC(n)
  392. END;
  393. i := 0;
  394. WHILE i < n DIV 2 DO
  395. t := buf[i]; buf[i] := buf[n - 1 - i]; buf[n - 1 - i] := t; INC(i)
  396. END;
  397. s[0] := CHR(0);
  398. IF neg THEN App(s, "-") END;
  399. i := 0;
  400. WHILE i < n DO
  401. L := Len(s);
  402. IF L < HIGH(s) THEN s[L] := buf[i]; s[L + 1] := CHR(0) END;
  403. INC(i)
  404. END
  405. END IntStr;
  406. PROCEDURE HexVal (ch: CHAR): INTEGER;
  407. BEGIN
  408. IF (ch >= "0") AND (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
  409. IF (ch >= "A") AND (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
  410. IF (ch >= "a") AND (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
  411. RETURN 0
  412. END HexVal;
  413. PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
  414. (* "0xFF" -> "255", plain decimals are copied through. *)
  415. VAR n, i : CARDINAL;
  416. v : INTEGER;
  417. BEGIN
  418. n := Len(s);
  419. IF (n > 2) AND (s[0] = "0")
  420. AND ((s[1] = "x") OR (s[1] = "X")) THEN
  421. v := 0; i := 2;
  422. WHILE i < n DO v := v * 16 + HexVal(s[i]); INC(i) END;
  423. IntStr(v, d)
  424. ELSE
  425. Cpy(d, s)
  426. END
  427. END NormInt;
  428. PROCEDURE NormLit (s: ARRAY OF CHAR; VAR d: QVal; VAR isCh: BOOLEAN);
  429. (* Full V3 integer literal: octal B/b, hex H/h and C/c suffixes plus
  430. the 0x/0X prefix; C marks a character constant. The suffix letter
  431. is excluded from the digit run (HexVal would read 'B' as 11).
  432. A 0x/0X prefix takes priority over any trailing B/C/H (C-style
  433. hex digits, so 0xB is 11, never an octal suffix). *)
  434. VAR n, i, hi, base : CARDINAL;
  435. v : INTEGER;
  436. ch : CHAR;
  437. BEGIN
  438. n := Len(s);
  439. isCh := FALSE;
  440. IF n = 0 THEN Cpy(d, "0"); RETURN END;
  441. i := 0;
  442. IF (n >= 3) AND (s[0] = "0") AND ((s[1] = "x") OR (s[1] = "X")) THEN
  443. base := 16; hi := n; i := 2
  444. ELSE
  445. ch := s[n - 1];
  446. IF (ch = "B") OR (ch = "b") THEN
  447. base := 8; hi := n - 1
  448. ELSIF (ch = "H") OR (ch = "h") THEN
  449. base := 16; hi := n - 1
  450. ELSIF (ch = "C") OR (ch = "c") THEN
  451. base := 16; hi := n - 1; isCh := TRUE
  452. ELSE
  453. base := 10; hi := n
  454. END
  455. END;
  456. v := 0;
  457. WHILE i < hi DO
  458. v := v * VAL(INTEGER, base) + HexVal(s[i]); INC(i)
  459. END;
  460. IntStr(v, d)
  461. END NormLit;
  462. PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
  463. (* "3.14" -> "d_3.14" (QBE double immediates carry a d_ prefix). *)
  464. BEGIN
  465. Cpy(d, "d_");
  466. App(d, s)
  467. END NormReal;
  468. PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
  469. BEGIN
  470. IF Len(s) >= 2 THEN RETURN ORD(s[1]) END;
  471. RETURN 0
  472. END CharVal;
  473. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
  474. (* Safe for a and q being the same variable. *)
  475. VAR i, j, L : CARDINAL;
  476. tmp : QVal;
  477. BEGIN
  478. Cpy(tmp, a);
  479. IF Len(tmp) = 0 THEN Cpy(q, "0"); RETURN END;
  480. IF tmp[0] = "-" THEN
  481. i := 1; j := 0;
  482. WHILE (tmp[i] # CHR(0)) AND (j < HIGH(q)) DO
  483. q[j] := tmp[i]; INC(i); INC(j)
  484. END;
  485. IF j <= HIGH(q) THEN q[j] := CHR(0) END
  486. ELSIF (tmp[0] = "d") AND (Len(tmp) > 1) AND (tmp[1] = "_") THEN
  487. Cpy(q, "d_-");
  488. i := 2;
  489. WHILE tmp[i] # CHR(0) DO
  490. L := Len(q);
  491. IF L < HIGH(q) THEN q[L] := tmp[i]; q[L + 1] := CHR(0) END;
  492. INC(i)
  493. END
  494. ELSE
  495. Cpy(q, "-");
  496. App(q, tmp)
  497. END
  498. END NegFold;
  499. PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
  500. BEGIN
  501. IF Len(s) = 0 THEN RETURN FALSE END;
  502. RETURN ((s[0] >= "0") AND (s[0] <= "9")) OR (s[0] = "-")
  503. OR (s[0] = "d")
  504. END IsImm;
  505. PROCEDURE ParseInt (s: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
  506. VAR i, nd, d: CARDINAL;
  507. neg: BOOLEAN;
  508. BEGIN
  509. v := 0; i := 0; neg := FALSE; nd := 0;
  510. IF (i <= HIGH(s)) AND (s[i] = "-") THEN neg := TRUE; INC(i) END;
  511. IF (i > HIGH(s)) OR (s[i] = CHR(0)) THEN RETURN FALSE END;
  512. WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
  513. d := ORD(s[i]);
  514. IF (d < ORD("0")) OR (d > ORD("9")) THEN RETURN FALSE END;
  515. v := v * 10 + VAL(INTEGER, d - ORD("0"));
  516. INC(i); INC(nd)
  517. END;
  518. IF nd = 0 THEN RETURN FALSE END;
  519. IF neg THEN v := -v END;
  520. RETURN TRUE
  521. END ParseInt;
  522. PROCEDURE Fold2 (kind: INTEGER; a, b: ARRAY OF CHAR; VAR r: QVal): BOOLEAN;
  523. VAR x, y, z: INTEGER;
  524. BEGIN
  525. IF NOT ParseInt(a, x) THEN RETURN FALSE END;
  526. IF NOT ParseInt(b, y) THEN RETURN FALSE END;
  527. IF kind = 0 THEN z := x + y
  528. ELSIF kind = 1 THEN z := x - y
  529. ELSIF kind = 2 THEN z := x * y
  530. ELSIF kind = 3 THEN
  531. IF y = 0 THEN RETURN FALSE END;
  532. z := x DIV y
  533. ELSE
  534. IF y = 0 THEN RETURN FALSE END;
  535. z := x MOD y
  536. END;
  537. IntStr(z, r);
  538. RETURN TRUE
  539. END Fold2;
  540. (* ---------------- module / data section ---------------- *)
  541. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  542. VAR i : CARDINAL;
  543. BEGIN
  544. opened := TRUE;
  545. inBody := FALSE;
  546. dead := FALSE;
  547. hasOutName := FALSE;
  548. nTemp := 0; nLab := 0; loopTop := 0; nR := 0; nStr := 0;
  549. withTop := 0;
  550. noEmit := FALSE; inFunc := FALSE; useStack := FALSE;
  551. ctorN := 0; ctorTop := 0;
  552. setN := 0;
  553. nLoc := 0; nPar := 0; nArg := 0; nn := 0; callDepth := 0;
  554. recvArmed := FALSE;
  555. funcDepth := 0; scopeTop := 0; scopeBase[0] := 0;
  556. nInit := 0; nFini := 0;
  557. outSel := 0;
  558. sessUsed := 0; sessBuf[0] := CHR(0);
  559. delayTop := 0;
  560. ustrN := 0; ustrUsed := 0;
  561. i := 0;
  562. WHILE i <= HIGH(nestBufs) DO
  563. nestBufs[i][0] := CHR(0); nestUsed[i] := 0; INC(i)
  564. END;
  565. WL("# QBE IR generated by the V3 step-1 backend");
  566. WL("")
  567. END OpenModule;
  568. PROCEDURE DataLine (name: ARRAY OF CHAR; isReal: BOOLEAN;
  569. init: ARRAY OF CHAR);
  570. BEGIN
  571. IF NOT opened THEN RETURN END;
  572. W("data $"); W(name);
  573. IF isReal THEN W(" = { d ") ELSE W(" = { w ") END;
  574. W(init);
  575. WL(" }")
  576. END DataLine;
  577. PROCEDURE DataLineB (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  578. (* A one-byte global (BYTE/SBYTE). *)
  579. BEGIN
  580. IF NOT opened THEN RETURN END;
  581. W("data $"); W(name);
  582. W(" = { b ");
  583. W(init);
  584. WL(" }")
  585. END DataLineB;
  586. PROCEDURE DataLineH (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  587. (* A 16-bit global (WORD16/INTEGER16). *)
  588. BEGIN
  589. IF NOT opened THEN RETURN END;
  590. W("data $"); W(name);
  591. W(" = { h ");
  592. W(init);
  593. WL(" }")
  594. END DataLineH;
  595. PROCEDURE DataLinePacked (name: ARRAY OF CHAR; t: INTEGER);
  596. (* A PACKEDSET global: 1/2/4 bytes, zero-initialised. *)
  597. VAR nb: CARDINAL;
  598. BEGIN
  599. IF NOT opened THEN RETURN END;
  600. nb := SymTab.SetBytes(t);
  601. W("data $"); W(name);
  602. W(" = { ");
  603. IF nb = 1 THEN W("b 0")
  604. ELSIF nb = 2 THEN W("h 0")
  605. ELSE W("w 0")
  606. END;
  607. WL(" }")
  608. END DataLinePacked;
  609. PROCEDURE DataLineL (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  610. BEGIN
  611. IF NOT opened THEN RETURN END;
  612. W("data $"); W(name);
  613. W(" = { l ");
  614. W(init);
  615. WL(" }")
  616. END DataLineL;
  617. PROCEDURE DeclLocal (name: ARRAY OF CHAR; t: INTEGER);
  618. (* Function-local variable: stack slot + static init, recorded. *)
  619. VAR slot : QVal;
  620. BEGIN
  621. AllocLocal(t, slot);
  622. LocAdd(name, 0, slot, ResClass(t), t)
  623. END DeclLocal;
  624. PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
  625. (* Module-level variable: emitted as data "$<mod>_<name>". *)
  626. VAR g : QVal;
  627. BEGIN
  628. IF inFunc THEN DeclLocal(name, t); RETURN END;
  629. Cpy(g, curModName); App(g, "_"); App(g, name);
  630. IF SymTab.ClassOf(t) = SymTab.ClReal THEN DataLine(g, TRUE, "0")
  631. ELSIF SymTab.IsByteType(t) THEN DataLineB(g, "0")
  632. ELSIF SymTab.IsWord16Type(t) THEN DataLineH(g, "0")
  633. ELSIF SymTab.ClassOf(t) = SymTab.ClArray THEN DeclArr(g, t)
  634. ELSIF SymTab.IsPackedSet(t) THEN DataLinePacked(g, t)
  635. ELSIF SymTab.ClassOf(t) = SymTab.ClSet THEN DeclSet(g, t)
  636. ELSIF (SymTab.ClassOf(t) = SymTab.ClRecord)
  637. OR (SymTab.ClassOf(t) = SymTab.ClClass) THEN
  638. DeclRec(g, t)
  639. ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
  640. OR (SymTab.ClassOf(t) = SymTab.ClLong)
  641. OR (SymTab.ClassOf(t) = SymTab.ClProc) THEN DataLineL(g, "0")
  642. ELSE DataLine(g, FALSE, "0")
  643. END
  644. END DeclVar;
  645. PROCEDURE IsZeroReal (val: ARRAY OF CHAR): BOOLEAN;
  646. (* TRUE when the "d_..." literal denotes zero (checked textually). *)
  647. VAR i : CARDINAL;
  648. seen : BOOLEAN;
  649. ch : CHAR;
  650. BEGIN
  651. i := 0;
  652. IF (Len(val) > 1) AND (val[0] = "d") AND (val[1] = "_") THEN i := 2 END;
  653. IF (Len(val) > i) AND (val[i] = "-") THEN INC(i) END;
  654. seen := FALSE;
  655. WHILE val[i] # CHR(0) DO
  656. ch := val[i];
  657. IF (ch >= "0") AND (ch <= "9") THEN
  658. seen := TRUE;
  659. IF ch # "0" THEN RETURN FALSE END
  660. ELSIF (ch # ".") AND (ch # "E") AND (ch # "e")
  661. AND (ch # "+") AND (ch # "-") THEN
  662. RETURN FALSE
  663. END;
  664. INC(i)
  665. END;
  666. RETURN seen
  667. END IsZeroReal;
  668. PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER);
  669. VAR cls : INTEGER;
  670. mang : QVal;
  671. BEGIN
  672. cls := SymTab.ClassOf(t);
  673. IF inFunc THEN
  674. Cpy(mang, funcName); App(mang, "_"); App(mang, name);
  675. LocAdd(name, 1, mang, ResClass(t), t)
  676. ELSE
  677. Cpy(mang, curModName); App(mang, "_"); App(mang, name)
  678. END;
  679. IF (cls = SymTab.ClStr) OR NOT IsImm(val) THEN
  680. DataLine(mang, FALSE, "0"); RETURN
  681. END;
  682. IF cls = SymTab.ClLong THEN
  683. DataLineL(mang, val)
  684. ELSIF cls = SymTab.ClReal THEN
  685. (* This qbe accepts only integer/zero literals in "data":
  686. non-zero REALs flush at BeginBody. *)
  687. DataLine(mang, TRUE, "0");
  688. IF NOT IsZeroReal(val) AND (nR <= HIGH(rNames)) THEN
  689. Cpy(rNames[nR], mang); Cpy(rVals[nR], val); INC(nR)
  690. END
  691. ELSE DataLine(mang, FALSE, val)
  692. END
  693. END DeclConst;
  694. (* ---------------- function body ---------------- *)
  695. PROCEDURE BeginInit (mod: ARRAY OF CHAR);
  696. (* Module BEGIN body as `<mod>_init`; main calls it at startup. *)
  697. VAR sym : QVal;
  698. BEGIN
  699. IF NOT opened THEN RETURN END;
  700. excHas[0] := FALSE;
  701. Cpy(sym, mod);
  702. App(sym, "_init");
  703. WL("");
  704. W("export function w $"); W(sym); WL("() {");
  705. WL("@start");
  706. IF nInit <= HIGH(initNames) THEN
  707. Cpy(initNames[nInit], sym); INC(nInit)
  708. END
  709. END BeginInit;
  710. PROCEDURE EndInit;
  711. BEGIN
  712. Revive;
  713. WL(" ret 0");
  714. WL("}")
  715. END EndInit;
  716. PROCEDURE BeginFini (mod: ARRAY OF CHAR);
  717. (* Module FINALLY body as `<mod>_fini`; main calls it at termination. *)
  718. VAR sym : QVal;
  719. BEGIN
  720. IF NOT opened THEN RETURN END;
  721. excHas[0] := FALSE;
  722. Cpy(sym, mod);
  723. App(sym, "_fini");
  724. WL("");
  725. W("export function w $"); W(sym); WL("() {");
  726. WL("@start");
  727. IF nFini <= HIGH(finiNames) THEN
  728. Cpy(finiNames[nFini], sym); INC(nFini)
  729. END
  730. END BeginFini;
  731. PROCEDURE EndFini;
  732. BEGIN
  733. Revive;
  734. WL(" ret 0");
  735. WL("}")
  736. END EndFini;
  737. PROCEDURE BeginBody;
  738. VAR i : CARDINAL;
  739. t : QVal;
  740. BEGIN
  741. IF NOT opened OR inBody THEN RETURN END;
  742. WL("");
  743. WL("export function w $main() {");
  744. WL("@start");
  745. excHas[0] := FALSE;
  746. WL(" call $m2_exc_init()");
  747. inBody := TRUE;
  748. i := 0;
  749. WHILE i < nR DO
  750. NewTemp(t);
  751. W(" "); W(t); W(" =d copy "); WL(rVals[i]);
  752. StoreVar(rNames[i], t, TRUE);
  753. INC(i)
  754. END;
  755. i := 0;
  756. WHILE i < nInit DO
  757. W(" call $"); W(initNames[i]); WL("()");
  758. INC(i)
  759. END
  760. END BeginBody;
  761. PROCEDURE FlushSets;
  762. (* Pooled set constants. Declared before EndModule, which calls it. *)
  763. VAR k, i: CARDINAL;
  764. w: CARDINAL;
  765. sv: QVal;
  766. BEGIN
  767. IF NOT opened THEN RETURN END;
  768. k := 0;
  769. WHILE k < setN DO
  770. W("data $"); W(setNam[k]); W(" = { ");
  771. w := setW[k];
  772. IF w = 0 THEN w := 1 END;
  773. i := 0;
  774. WHILE i < w DO
  775. IF i > 0 THEN W(", ") END;
  776. IntStr(VAL(INTEGER, setMask[k][i]), sv);
  777. W("w "); W(sv);
  778. INC(i)
  779. END;
  780. WL(" }");
  781. INC(k)
  782. END
  783. END FlushSets;
  784. PROCEDURE FiniExists (name: ARRAY OF CHAR): BOOLEAN;
  785. VAR i: CARDINAL;
  786. BEGIN
  787. i := 0;
  788. WHILE i < nFini DO
  789. IF SymTab.Equal(finiNames[i], name) THEN RETURN TRUE END;
  790. INC(i)
  791. END;
  792. RETURN FALSE
  793. END FiniExists;
  794. PROCEDURE EmitFiniCalls (prog: ARRAY OF CHAR);
  795. (* Program finalizer first, then imported/local finalizers in reverse
  796. initialization order. *)
  797. VAR i: CARDINAL; p: QVal;
  798. BEGIN
  799. Cpy(p, prog); App(p, "_fini");
  800. IF FiniExists(p) THEN
  801. W(" call $"); W(p); WL("()")
  802. END;
  803. i := nFini;
  804. WHILE i > 0 DO
  805. DEC(i);
  806. IF NOT SymTab.Equal(finiNames[i], p) THEN
  807. W(" call $"); W(finiNames[i]); WL("()")
  808. END
  809. END
  810. END EmitFiniCalls;
  811. PROCEDURE EndModule (name: ARRAY OF CHAR);
  812. VAR i : CARDINAL;
  813. fname : ARRAY [0 .. 127] OF CHAR;
  814. ref : QVal;
  815. BEGIN
  816. IF NOT opened THEN RETURN END;
  817. (* Per-unit Lower emission: the grammar's own unit-end EndModule must
  818. not flush/close/write while the legacy emit is suppressed. The
  819. real session image is written by Lower.EndSession. *)
  820. IF noEmit THEN RETURN END;
  821. IF NOT inBody THEN BeginBody END;
  822. EmitFiniCalls(name);
  823. IF SymTab.Lookup("ExitCode")
  824. AND (SymTab.SymKind("ExitCode") = SymTab.KindVar)
  825. AND SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
  826. Cpy(ref, "$"); App(ref, name); App(ref, "_ExitCode");
  827. W(" %ec =w loadw "); WL(ref);
  828. WL(" ret %ec")
  829. ELSE
  830. WL(" ret 0")
  831. END;
  832. WL("}");
  833. (* hoisted nested functions, then deferred data *)
  834. i := 0;
  835. WHILE i <= HIGH(nestBufs) DO
  836. IF nestUsed[i] > 0 THEN
  837. BufApp(sessBuf, sessUsed, nestBufs[i], FALSE)
  838. END;
  839. INC(i)
  840. END;
  841. FlushStrings;
  842. FlushUStrings;
  843. FlushCtors;
  844. FlushSets;
  845. EmitVTables;
  846. (* the image is named after the program module *)
  847. fname[0] := CHR(0);
  848. App(fname, "gen_ssa/");
  849. IF hasOutName THEN App(fname, outName) ELSE App(fname, name) END;
  850. App(fname, ".ssa");
  851. FileIO.Open(out, fname, TRUE);
  852. IF FileIO.Okay THEN
  853. (* Flush exactly sessUsed bytes. FileIO.WriteString scans for a
  854. NUL and misbehaves for multi-megabyte buffers, so write the
  855. image byte by byte up to sessUsed. *)
  856. i := 0;
  857. WHILE i < sessUsed DO
  858. FileIO.Write(out, sessBuf[i]); INC(i)
  859. END
  860. END;
  861. FileIO.Close(out);
  862. opened := FALSE
  863. END EndModule;
  864. (* ---------------- functions and calls (step 4.1) ---------------- *)
  865. (* Module-level procedures only (nested → NoEmit until 4.2).
  866. Value params arrive as SSA values and are copied to slots;
  867. composite value params arrive as addresses and are copied;
  868. VAR params stay addresses. Locals live in stack slots. *)
  869. PROCEDURE LocFind (name: ARRAY OF CHAR): INTEGER;
  870. VAR i : CARDINAL;
  871. BEGIN
  872. i := 0;
  873. WHILE i < nLoc DO
  874. IF SymTab.Equal(locNames[i], name) THEN RETURN VAL(INTEGER, i) END;
  875. INC(i)
  876. END;
  877. RETURN -1
  878. END LocFind;
  879. PROCEDURE ScopeBegin;
  880. (* Pushes a procedure scope (always balanced, even under NoEmit). *)
  881. BEGIN
  882. IF scopeTop > HIGH(scopeLink) THEN RETURN END;
  883. scopeBase[scopeTop] := nLoc;
  884. INC(scopeTop);
  885. scopeBase[scopeTop] := nLoc
  886. END ScopeBegin;
  887. PROCEDURE ScopeEnd;
  888. BEGIN
  889. IF scopeTop > 0 THEN
  890. DEC(scopeTop);
  891. nLoc := scopeBase[scopeTop]
  892. END
  893. END ScopeEnd;
  894. PROCEDURE LocFindUp (name: ARRAY OF CHAR; VAR levels: CARDINAL;
  895. VAR flat: INTEGER): BOOLEAN;
  896. (* Innermost procedure scope holding name; levels = scopes crossed,
  897. flat = table index. FALSE when purely global. *)
  898. VAR s, top, lo, hi, j : CARDINAL;
  899. BEGIN
  900. levels := 0; flat := -1;
  901. IF scopeTop = 0 THEN RETURN FALSE END;
  902. top := scopeTop - 1;
  903. s := top;
  904. LOOP
  905. lo := scopeBase[s];
  906. IF s = top THEN hi := nLoc ELSE hi := scopeBase[s + 1] END;
  907. j := lo;
  908. WHILE j < hi DO
  909. IF SymTab.Equal(locNames[j], name) THEN
  910. levels := top - s;
  911. flat := VAL(INTEGER, j);
  912. RETURN TRUE
  913. END;
  914. INC(j)
  915. END;
  916. IF s = 0 THEN RETURN FALSE END;
  917. DEC(s)
  918. END
  919. END LocFindUp;
  920. PROCEDURE LocAdd (name: ARRAY OF CHAR; tag: INTEGER; rep: ARRAY OF CHAR;
  921. cls: CHAR; typ: INTEGER);
  922. VAR idx : CARDINAL;
  923. off : QVal;
  924. lk : QVal;
  925. BEGIN
  926. IF (scopeTop = 0) OR (nLoc > HIGH(locNames)) THEN RETURN END;
  927. idx := nLoc - scopeBase[scopeTop - 1];
  928. IF idx > 63 THEN RETURN END;
  929. Cpy(locNames[nLoc], name);
  930. locTag[nLoc] := tag;
  931. Cpy(locRep[nLoc], rep);
  932. locCls[nLoc] := cls;
  933. locTyp[nLoc] := typ;
  934. INC(nLoc);
  935. IF tag = 1 THEN RETURN END;
  936. Cpy(lk, scopeLink[scopeTop - 1]);
  937. IntStr(VAL(INTEGER, 8 * (idx + 1)), off);
  938. NewTemp(lk);
  939. Op3L("add", lk, scopeLink[scopeTop - 1], off);
  940. Revive;
  941. W(" storel "); W(rep); W(", "); WL(lk)
  942. END LocAdd;
  943. PROCEDURE LocFull (): BOOLEAN;
  944. (* TRUE past 64 locals in the current scope (→ 233). *)
  945. BEGIN
  946. IF scopeTop = 0 THEN RETURN FALSE END;
  947. RETURN nLoc - scopeBase[scopeTop - 1] > 63
  948. END LocFull;
  949. PROCEDURE UpAddr (levels: CARDINAL; rel: CARDINAL; VAR q: QVal);
  950. (* Address of an up-level local: walks the static chain, then
  951. loads the link cell (slot address or actual address). *)
  952. VAR cur, t, off : QVal;
  953. L : CARDINAL;
  954. BEGIN
  955. Cpy(cur, scopeLink[scopeTop - 1]);
  956. L := levels;
  957. WHILE L > 0 DO
  958. NewTemp(t);
  959. Revive;
  960. W(" "); W(t); W(" =l loadl "); WL(cur);
  961. Cpy(cur, t);
  962. DEC(L)
  963. END;
  964. IntStr(VAL(INTEGER, 8 * (rel + 1)), off);
  965. NewTemp(t);
  966. Op3L("add", t, cur, off);
  967. NewTemp(q);
  968. Revive;
  969. W(" "); W(q); W(" =l loadl "); WL(t)
  970. END UpAddr;
  971. PROCEDURE ResClass (t: INTEGER): CHAR;
  972. VAR cls : INTEGER;
  973. BEGIN
  974. cls := SymTab.ClassOf(t);
  975. IF cls = SymTab.ClReal THEN RETURN "d" END;
  976. IF (cls = SymTab.ClArray) OR (cls = SymTab.ClSet)
  977. OR (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass)
  978. OR (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong)
  979. OR (cls = SymTab.ClProc) THEN
  980. RETURN "l"
  981. END;
  982. RETURN "w"
  983. END ResClass;
  984. PROCEDURE Mangled (pname: ARRAY OF CHAR; uid: CARDINAL; VAR q: QVal);
  985. (* External procedures bind to their C link name; everything else
  986. mangles to <name>_<uid> (deterministic, collision-free). *)
  987. VAR link, base : SymTab.Name;
  988. BEGIN
  989. IF SymTab.ProcLink(pname, link) THEN
  990. Cpy(q, link);
  991. RETURN
  992. END;
  993. IF NOT SymTab.SymBase(pname, base) THEN
  994. IF NOT SymTab.ProcBaseByUid(uid, base) THEN Cpy(base, pname) END
  995. END;
  996. Cpy(q, base);
  997. App(q, "_");
  998. AppNum(q, uid)
  999. END Mangled;
  1000. PROCEDURE AllocLocal (t: INTEGER; VAR slot: QVal);
  1001. (* Stack slot sized for t's inline footprint; arrays/records get
  1002. full objects + static init. Scalar/pointer/set slots are
  1003. zero-initialized: QBE rejects reads of never-stored slots, and
  1004. the frontend emits a dead load for assignment targets (Test2
  1005. heritage, harmless for zero-initialized globals). Locals match
  1006. the globals' zero-init convention. *)
  1007. VAR cls : INTEGER;
  1008. nb : QVal;
  1009. BEGIN
  1010. cls := SymTab.ClassOf(t);
  1011. NewTemp(slot);
  1012. Revive;
  1013. W(" "); W(slot);
  1014. IF (cls = SymTab.ClArray) THEN
  1015. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  1016. W(" =l alloc8 "); WL(nb);
  1017. InitStack(slot, t)
  1018. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1019. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), nb);
  1020. W(" =l alloc8 "); WL(nb);
  1021. InitStack(slot, t)
  1022. ELSIF SymTab.IsPackedSet(t) THEN
  1023. W(" =l alloc4 4"); WL("");
  1024. IF SymTab.SetBytes(t) = 1 THEN W(" storeb 0, "); WL(slot)
  1025. ELSIF SymTab.SetBytes(t) = 2 THEN W(" storeh 0, "); WL(slot)
  1026. ELSE W(" storew 0, "); WL(slot)
  1027. END
  1028. ELSIF cls = SymTab.ClSet THEN
  1029. IntStr(VAL(INTEGER, SymTab.SetWords(t) * 4), nb);
  1030. W(" =l alloc8 "); WL(nb);
  1031. SetZero(slot, SymTab.SetWords(t))
  1032. ELSIF cls = SymTab.ClReal THEN
  1033. W(" =l alloc8 8"); WL("");
  1034. W(" stored d_0.0, "); WL(slot)
  1035. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong)
  1036. OR (cls = SymTab.ClProc) THEN
  1037. W(" =l alloc8 8"); WL("");
  1038. W(" storel 0, "); WL(slot)
  1039. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  1040. W(" =l alloc4 4"); WL("");
  1041. W(" storeb 0, "); WL(slot)
  1042. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  1043. W(" =l alloc4 4"); WL("");
  1044. W(" storeh 0, "); WL(slot)
  1045. ELSE
  1046. W(" =l alloc4 4"); WL("");
  1047. W(" storew 0, "); WL(slot)
  1048. END
  1049. END AllocLocal;
  1050. PROCEDURE OpenScalarDesc (val: ARRAY OF CHAR; t, ft: INTEGER; VAR desc: QVal);
  1051. (* gm2 compatibility: wrap a scalar actual as an `ARRAY OF BYTE`
  1052. descriptor in the frame. Layout is the usual [count][data]; the
  1053. count is ObjectSize(actual), so HIGH matches gm2's SIZE-1, and the
  1054. payload is a copy of the value (writes do not reach the actual). *)
  1055. VAR cnt, off, nb: QVal;
  1056. cls: INTEGER;
  1057. sz, esz: CARDINAL;
  1058. BEGIN
  1059. sz := SymTab.ObjectSize(t);
  1060. esz := SymTab.ObjectSize(SymTab.ArrayElem(ft));
  1061. IF esz = 0 THEN esz := 1 END;
  1062. NewTemp(desc); Revive;
  1063. W(" "); W(desc); W(" =l alloc8 ");
  1064. IntStr(VAL(INTEGER, 8 + sz * esz), nb); WL(nb);
  1065. NewTemp(cnt); IntStr(VAL(INTEGER, sz), cnt);
  1066. W(" storel "); W(cnt); W(", "); W(desc); WL("");
  1067. NewTemp(off); Op3L("add", off, desc, "8");
  1068. cls := SymTab.ClassOf(t);
  1069. IF cls = SymTab.ClReal THEN
  1070. W(" stored "); W(val); W(", "); W(off); WL("")
  1071. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong) OR (sz > 4) THEN
  1072. W(" storel "); W(val); W(", "); W(off); WL("")
  1073. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  1074. W(" storeb "); W(val); W(", "); W(off); WL("")
  1075. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  1076. W(" storeh "); W(val); W(", "); W(off); WL("")
  1077. ELSE
  1078. W(" storew "); W(val); W(", "); W(off); WL("")
  1079. END
  1080. END OpenScalarDesc;
  1081. PROCEDURE BeginFunc (mangled: ARRAY OF CHAR);
  1082. (* Opens function context and scope; the header (with a leading
  1083. static-link param) buffers until EndFuncHeader. FORWARD/DefUnit
  1084. paths discard via AbortFunc. *)
  1085. BEGIN
  1086. ScopeBegin;
  1087. INC(funcDepth);
  1088. IF funcDepth <= HIGH(excHas) THEN excHas[funcDepth] := FALSE END;
  1089. inFunc := TRUE;
  1090. nPar := 0;
  1091. funcRes := "w";
  1092. Cpy(funcName, mangled);
  1093. hbuf[0] := CHR(0);
  1094. NewTemp(slTmp);
  1095. HApp("l ");
  1096. HApp(slTmp);
  1097. hdrComma := TRUE;
  1098. IF funcDepth > 1 THEN
  1099. outSel := funcDepth - 1;
  1100. IF outSel > HIGH(nestBufs) + 1 THEN
  1101. outSel := HIGH(nestBufs) + 1
  1102. END
  1103. ELSE
  1104. outSel := 0
  1105. END
  1106. END BeginFunc;
  1107. PROCEDURE SetFuncRes (t: INTEGER);
  1108. BEGIN
  1109. funcRes := ResClass(t)
  1110. END SetFuncRes;
  1111. PROCEDURE HApp (s: ARRAY OF CHAR);
  1112. (* Appends to the header buffer (bounded: FormalParams cap it). *)
  1113. VAR i, j : CARDINAL;
  1114. BEGIN
  1115. i := 0;
  1116. WHILE (i <= HIGH(hbuf)) AND (hbuf[i] # CHR(0)) DO INC(i) END;
  1117. j := 0;
  1118. WHILE (i < HIGH(hbuf)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  1119. hbuf[i] := s[j]; INC(i); INC(j)
  1120. END;
  1121. IF i <= HIGH(hbuf) THEN hbuf[i] := CHR(0) END
  1122. END HApp;
  1123. PROCEDURE FuncParam (name: ARRAY OF CHAR; isVar: BOOLEAN;
  1124. t: INTEGER): BOOLEAN;
  1125. VAR c : CHAR;
  1126. tmp : QVal;
  1127. buf : ARRAY [0 .. 71] OF CHAR;
  1128. BEGIN
  1129. IF nPar > HIGH(parCls) THEN RETURN FALSE END;
  1130. IF isVar THEN c := "l" ELSE c := ResClass(t) END;
  1131. parCls[nPar] := c;
  1132. NewTemp(tmp);
  1133. Cpy(parTmp[nPar], tmp);
  1134. Cpy(parNam[nPar], name);
  1135. parVar[nPar] := isVar;
  1136. parTyp[nPar] := t;
  1137. IF hdrComma THEN HApp(", ") END;
  1138. hdrComma := TRUE;
  1139. buf[0] := c; buf[1] := " "; buf[2] := CHR(0);
  1140. App(buf, tmp);
  1141. HApp(buf);
  1142. INC(nPar);
  1143. RETURN TRUE
  1144. END FuncParam;
  1145. PROCEDURE EndFuncHeader;
  1146. (* Flushes the buffered header + body label, allocates the link
  1147. record ([0] = parent link), then emits entry copies. *)
  1148. VAR i : CARDINAL;
  1149. slot, nb, lk : QVal;
  1150. cls : INTEGER;
  1151. BEGIN
  1152. W("export function "); Wc(funcRes); W(" $"); W(funcName); W("(");
  1153. W(hbuf);
  1154. WL(") {");
  1155. WL("@start");
  1156. inBody := TRUE;
  1157. NewTemp(lk);
  1158. Cpy(scopeLink[scopeTop - 1], lk);
  1159. Revive;
  1160. W(" "); W(lk); W(" =l alloc8 520"); WL("");
  1161. W(" storel "); W(slTmp); W(", "); WL(lk);
  1162. i := 0;
  1163. WHILE i < nPar DO
  1164. cls := SymTab.ClassOf(parTyp[i]);
  1165. IF parVar[i] THEN
  1166. LocAdd(parNam[i], 2, parTmp[i], parCls[i], parTyp[i])
  1167. ELSE
  1168. AllocLocal(parTyp[i], slot);
  1169. LocAdd(parNam[i], 0, slot, parCls[i], parTyp[i]);
  1170. IF cls = SymTab.ClArray THEN
  1171. CopyArray(slot, parTmp[i], parTyp[i])
  1172. ELSIF cls = SymTab.ClSet THEN
  1173. CopySetVal(slot, parTyp[i], parTmp[i], parTyp[i])
  1174. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1175. CopyRecord(slot, parTmp[i], parTyp[i])
  1176. ELSIF cls = SymTab.ClReal THEN
  1177. Revive;
  1178. W(" stored "); W(parTmp[i]); W(", "); WL(slot)
  1179. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc)
  1180. OR (cls = SymTab.ClLong) THEN
  1181. Revive;
  1182. W(" storel "); W(parTmp[i]); W(", "); WL(slot)
  1183. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  1184. Revive;
  1185. W(" storeb "); W(parTmp[i]); W(", "); WL(slot)
  1186. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  1187. Revive;
  1188. W(" storeh "); W(parTmp[i]); W(", "); WL(slot)
  1189. ELSE
  1190. Revive;
  1191. W(" storew "); W(parTmp[i]); W(", "); WL(slot)
  1192. END
  1193. END;
  1194. INC(i)
  1195. END
  1196. END EndFuncHeader;
  1197. PROCEDURE AbortFunc;
  1198. (* Discards function context without emitting (DefUnit headings,
  1199. FORWARD, methods): pops the scope, restores the depth. *)
  1200. BEGIN
  1201. ScopeEnd;
  1202. IF funcDepth <= HIGH(excHas) THEN excHas[funcDepth] := FALSE END;
  1203. IF funcDepth > 0 THEN DEC(funcDepth) END;
  1204. inFunc := funcDepth > 0;
  1205. inBody := FALSE;
  1206. nPar := 0;
  1207. IF funcDepth > 1 THEN outSel := funcDepth - 1
  1208. ELSE outSel := 0
  1209. END
  1210. END AbortFunc;
  1211. PROCEDURE EndFunc (resT: INTEGER);
  1212. VAR rc : CHAR;
  1213. BEGIN
  1214. rc := ResClass(resT);
  1215. Revive;
  1216. IF resT # SymTab.InvalidType THEN
  1217. (* A function that reaches its end without RETURN raises the
  1218. language functionException instead of silently returning 0. *)
  1219. TrapCode(4)
  1220. ELSIF rc = "d" THEN WL(" ret d_0.0")
  1221. ELSIF rc = "l" THEN WL(" ret 0")
  1222. ELSE WL(" ret 0")
  1223. END;
  1224. WL("}");
  1225. ScopeEnd;
  1226. IF funcDepth <= HIGH(excHas) THEN excHas[funcDepth] := FALSE END;
  1227. IF funcDepth > 0 THEN DEC(funcDepth) END;
  1228. inFunc := funcDepth > 0;
  1229. inBody := FALSE;
  1230. IF funcDepth > 1 THEN outSel := funcDepth - 1
  1231. ELSE outSel := 0
  1232. END
  1233. END EndFunc;
  1234. PROCEDURE EmitRet (q: ARRAY OF CHAR; hasVal: BOOLEAN);
  1235. BEGIN
  1236. Revive;
  1237. IF (funcDepth <= HIGH(excHas)) AND excHas[funcDepth] THEN
  1238. WL(" call $m2_exc_leave()")
  1239. END;
  1240. IF hasVal THEN W(" ret "); WL(q)
  1241. ELSE WL(" ret 0")
  1242. END;
  1243. dead := TRUE
  1244. END EmitRet;
  1245. PROCEDURE ExcBegin;
  1246. (* M2: emit the handler prologue for the current function/module body.
  1247. The QBE frame owns a 512-byte sigjmp_buf; the runtime handler stores
  1248. that address. Dispatch: 0 = body, 2 = RETRY/body, 1 = handler. *)
  1249. VAR env, r, z, chk: QVal;
  1250. BEGIN
  1251. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1252. Revive;
  1253. NewTemp(env);
  1254. W(" "); W(env); WL(" =l alloc8 512");
  1255. W(" call $m2_exc_push(l "); W(env); WL(")");
  1256. NewTemp(r);
  1257. W(" "); W(r); W(" =w call $__sigsetjmp(l "); W(env);
  1258. W(", w 1)"); WL("");
  1259. NewLabel(excBodyL[funcDepth]);
  1260. NewLabel(excHandlerL[funcDepth]);
  1261. NewLabel(excAfterL[funcDepth]);
  1262. NewLabel(chk);
  1263. NewTemp(z);
  1264. Op3("ceqw", z, r, "0", FALSE);
  1265. Jnz(z, excBodyL[funcDepth], chk);
  1266. EmitLabel(chk);
  1267. NewTemp(z);
  1268. Op3("ceqw", z, r, "2", FALSE);
  1269. Jnz(z, excBodyL[funcDepth], excHandlerL[funcDepth]);
  1270. EmitLabel(excBodyL[funcDepth]);
  1271. excHas[funcDepth] := TRUE
  1272. END ExcBegin;
  1273. PROCEDURE ExcBodyDone;
  1274. BEGIN
  1275. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1276. Revive;
  1277. WL(" call $m2_exc_leave()");
  1278. Jmp(excAfterL[funcDepth])
  1279. END ExcBodyDone;
  1280. PROCEDURE ExcHandlerBegin;
  1281. BEGIN
  1282. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1283. EmitLabel(excHandlerL[funcDepth])
  1284. END ExcHandlerBegin;
  1285. PROCEDURE ExcEnd;
  1286. BEGIN
  1287. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1288. Revive;
  1289. WL(" call $m2_exc_leave()");
  1290. EmitLabel(excAfterL[funcDepth])
  1291. END ExcEnd;
  1292. PROCEDURE ExcRetry;
  1293. BEGIN
  1294. IF dead THEN RETURN END;
  1295. WL(" call $m2_exc_retry()");
  1296. dead := TRUE
  1297. END ExcRetry;
  1298. PROCEDURE ProcAddr (mangled: ARRAY OF CHAR; VAR q: QVal);
  1299. BEGIN
  1300. Cpy(q, "$");
  1301. App(q, mangled)
  1302. END ProcAddr;
  1303. PROCEDURE CallBeginInd (callee: ARRAY OF CHAR; resT: INTEGER;
  1304. isExt: BOOLEAN);
  1305. (* Indirect call through the code pointer in `callee`. *)
  1306. BEGIN
  1307. IF callDepth > HIGH(stkName) THEN RETURN END;
  1308. Cpy(stkName[callDepth], callee);
  1309. stkRes[callDepth] := ResClass(resT);
  1310. stkExt[callDepth] := isExt;
  1311. stkInd[callDepth] := TRUE;
  1312. Cpy(stkLink[callDepth], "0");
  1313. stkArg[callDepth][0] := CHR(0);
  1314. stkN[callDepth] := 0;
  1315. INC(callDepth);
  1316. IF recvArmed THEN
  1317. IF NOT CallArg(recvQ, "l") THEN
  1318. END;
  1319. recvArmed := FALSE
  1320. END
  1321. END CallBeginInd;
  1322. PROCEDURE VirtCallBegin (obj: ARRAY OF CHAR; slot: INTEGER; resT: INTEGER);
  1323. (* Virtual dispatch: load obj's vtable pointer, fetch slot `slot`,
  1324. and begin an indirect call through it. The receiver (obj) must be
  1325. armed (ArmRecv). *)
  1326. VAR vt, off, ea, fp: QVal;
  1327. BEGIN
  1328. NewTemp(vt);
  1329. W(" "); W(vt); W(" =l loadl "); WL(obj);
  1330. IntStr(slot * 8, off);
  1331. NewTemp(ea);
  1332. Op3L("add", ea, vt, off);
  1333. NewTemp(fp);
  1334. W(" "); W(fp); W(" =l loadl "); WL(ea);
  1335. CallBeginInd(fp, resT, FALSE)
  1336. END VirtCallBegin;
  1337. PROCEDURE ArmRecv (q: ARRAY OF CHAR);
  1338. (* Arms the receiver for the next class-method call: CallBegin passes
  1339. it as the hidden first argument. *)
  1340. BEGIN
  1341. Cpy(recvQ, q);
  1342. recvArmed := TRUE
  1343. END ArmRecv;
  1344. PROCEDURE CallBegin (mangled: ARRAY OF CHAR; resT: INTEGER;
  1345. fdep: CARDINAL; isExt: BOOLEAN);
  1346. (* Pushes a call level; the static link is resolved now (caller
  1347. context cannot change mid-call): module callers pass 0, others
  1348. walk the chain (inFuncDepth - fdep) from their link record.
  1349. External callees take no static link. *)
  1350. VAR walks : INTEGER;
  1351. cur, t : QVal;
  1352. BEGIN
  1353. IF callDepth > HIGH(stkName) THEN RETURN END;
  1354. Cpy(stkName[callDepth], mangled);
  1355. stkRes[callDepth] := ResClass(resT);
  1356. stkExt[callDepth] := isExt;
  1357. stkInd[callDepth] := FALSE;
  1358. stkArg[callDepth][0] := CHR(0);
  1359. stkN[callDepth] := 0;
  1360. IF isExt THEN
  1361. Cpy(stkLink[callDepth], "0")
  1362. ELSIF funcDepth = 0 THEN
  1363. Cpy(stkLink[callDepth], "0")
  1364. ELSE
  1365. walks := VAL(INTEGER, funcDepth) - VAL(INTEGER, fdep);
  1366. Cpy(cur, scopeLink[scopeTop - 1]);
  1367. WHILE walks > 0 DO
  1368. NewTemp(t);
  1369. Revive;
  1370. W(" "); W(t); W(" =l loadl "); WL(cur);
  1371. Cpy(cur, t);
  1372. DEC(walks)
  1373. END;
  1374. Cpy(stkLink[callDepth], cur)
  1375. END;
  1376. INC(callDepth);
  1377. IF recvArmed THEN
  1378. (* class method: the receiver is the hidden first argument *)
  1379. IF NOT CallArg(recvQ, "l") THEN
  1380. END;
  1381. recvArmed := FALSE
  1382. END
  1383. END CallBegin;
  1384. PROCEDURE CallArg (q: ARRAY OF CHAR; cls: CHAR): BOOLEAN;
  1385. (* Appends "c operand, " to the current level. FALSE when full. *)
  1386. VAR need, have, i, j, d : CARDINAL;
  1387. BEGIN
  1388. d := callDepth - 1;
  1389. IF callDepth = 0 THEN RETURN FALSE END;
  1390. IF d > HIGH(stkArg) THEN d := HIGH(stkArg) END;
  1391. need := Len(q) + 5;
  1392. have := Len(stkArg[d]);
  1393. IF (stkN[d] >= 64) OR (have + need > HIGH(stkArg[d])) THEN
  1394. RETURN FALSE
  1395. END;
  1396. i := have; j := 0;
  1397. stkArg[d][i] := cls; INC(i);
  1398. stkArg[d][i] := " "; INC(i);
  1399. WHILE q[j] # CHR(0) DO
  1400. stkArg[d][i] := q[j]; INC(i); INC(j)
  1401. END;
  1402. stkArg[d][i] := ","; INC(i);
  1403. stkArg[d][i] := " "; INC(i);
  1404. stkArg[d][i] := CHR(0);
  1405. INC(stkN[d]);
  1406. RETURN TRUE
  1407. END CallArg;
  1408. PROCEDURE CallEnd (wantRes: BOOLEAN; VAR q: QVal);
  1409. VAR i, d : CARDINAL;
  1410. rc : CHAR;
  1411. body : ARRAY [0 .. 1023] OF CHAR;
  1412. BEGIN
  1413. IF callDepth = 0 THEN Cpy(q, "0"); RETURN END;
  1414. DEC(callDepth);
  1415. d := callDepth;
  1416. IF d > HIGH(stkArg) THEN d := HIGH(stkArg) END;
  1417. Cpy(funcName, stkName[d]);
  1418. rc := stkRes[d];
  1419. i := 0;
  1420. WHILE (stkArg[d][i] # CHR(0)) AND (i < HIGH(body)) DO
  1421. body[i] := stkArg[d][i]; INC(i)
  1422. END;
  1423. IF (i >= 2) AND (body[i-2] = ",") THEN
  1424. body[i-2] := CHR(0)
  1425. ELSE
  1426. body[i] := CHR(0)
  1427. END;
  1428. Revive;
  1429. IF wantRes THEN
  1430. NewTemp(q);
  1431. W(" "); W(q); W(" ="); Wc(rc)
  1432. ELSE
  1433. W(" ")
  1434. END;
  1435. IF stkInd[d] THEN
  1436. W(" call "); W(funcName); W("(") (* callee operand already %-prefixed *)
  1437. ELSE
  1438. W(" call $"); W(funcName); W("(")
  1439. END;
  1440. IF stkExt[d] THEN
  1441. W(body) (* C callee: no static link *)
  1442. ELSE
  1443. W("l "); W(stkLink[d]);
  1444. IF body[0] # CHR(0) THEN W(", "); W(body) END
  1445. END;
  1446. WL(")")
  1447. END CallEnd;
  1448. PROCEDURE InitStack (addr: ARRAY OF CHAR; t: INTEGER);
  1449. BEGIN
  1450. useStack := TRUE;
  1451. InitHeap(addr, t);
  1452. useStack := FALSE
  1453. END InitStack;
  1454. PROCEDURE ArgClass (t: INTEGER): CHAR;
  1455. (* Formal/actual class for call emission. *)
  1456. BEGIN
  1457. RETURN ResClass(t)
  1458. END ArgClass;
  1459. PROCEDURE CArg (q: ARRAY OF CHAR; t: INTEGER; VAR out: QVal;
  1460. VAR cls: CHAR);
  1461. BEGIN
  1462. cls := ArgClass(t);
  1463. IF SymTab.ClassOf(t) = SymTab.ClStr THEN
  1464. NewTemp(out); Op3L("add", out, q, "8"); cls := "l"
  1465. ELSIF (SymTab.ClassOf(t) = SymTab.ClArray)
  1466. AND SymTab.IsCharArray(t) THEN
  1467. NewTemp(out); Op3L("add", out, q, "8"); cls := "l"
  1468. ELSE Cpy(out, q)
  1469. END
  1470. END CArg;
  1471. PROCEDURE CArgAdd (q: ARRAY OF CHAR; t: INTEGER; VAR out: QVal;
  1472. VAR cls: CHAR);
  1473. BEGIN
  1474. CArg(q, t, out, cls);
  1475. IF NOT CallArg(out, cls) THEN END
  1476. END CArgAdd;
  1477. (* ---------------- temporaries and operators ---------------- *)
  1478. PROCEDURE NewTemp (VAR t: QVal);
  1479. BEGIN
  1480. Cpy(t, "%t");
  1481. AppNum(t, nTemp);
  1482. INC(nTemp)
  1483. END NewTemp;
  1484. PROCEDURE LocLoadFlat (idx: INTEGER; long: BOOLEAN; VAR q: QVal);
  1485. (* Loads a same-scope entry: slots/data by class (or long for
  1486. pointers), addr entries via ElemLoad. *)
  1487. BEGIN
  1488. IF locTag[idx] = 2 THEN
  1489. ElemLoad(locRep[idx], locTyp[idx], q);
  1490. RETURN
  1491. END;
  1492. NewTemp(q);
  1493. Revive;
  1494. W(" "); W(q);
  1495. IF long THEN W(" =l loadl ")
  1496. ELSIF locCls[idx] = "d" THEN W(" =d loadd ")
  1497. ELSIF SymTab.IsByteType(locTyp[idx]) THEN
  1498. IF SymTab.IsSignedByte(locTyp[idx]) THEN W(" =w loadsb ")
  1499. ELSE W(" =w loadub ")
  1500. END
  1501. ELSIF SymTab.IsWord16Type(locTyp[idx]) THEN
  1502. IF SymTab.IsSignedWord16(locTyp[idx]) THEN W(" =w loadsh ")
  1503. ELSE W(" =w loaduh ")
  1504. END
  1505. ELSE W(" =w loadw ")
  1506. END;
  1507. IF locTag[idx] = 1 THEN W("$") END;
  1508. WL(locRep[idx])
  1509. END LocLoadFlat;
  1510. PROCEDURE LocStoreFlat (idx: INTEGER; q: ARRAY OF CHAR; long: BOOLEAN);
  1511. (* Stores a same-scope entry: slots/data by class (or long), addr
  1512. via ElemStore. Data stores are grammar-unreachable (consts). *)
  1513. BEGIN
  1514. IF locTag[idx] = 2 THEN
  1515. ElemStore(locRep[idx], q, locTyp[idx]);
  1516. RETURN
  1517. END;
  1518. Revive;
  1519. IF long THEN W(" storel ")
  1520. ELSIF locCls[idx] = "d" THEN W(" stored ")
  1521. ELSIF SymTab.IsByteType(locTyp[idx]) THEN W(" storeb ")
  1522. ELSIF SymTab.IsWord16Type(locTyp[idx]) THEN W(" storeh ")
  1523. ELSE W(" storew ")
  1524. END;
  1525. W(q); W(", ");
  1526. IF locTag[idx] = 1 THEN W("$") END;
  1527. WL(locRep[idx])
  1528. END LocStoreFlat;
  1529. PROCEDURE UpLoad (flat: INTEGER; levels: CARDINAL; long: BOOLEAN;
  1530. VAR q: QVal);
  1531. (* Up-level load: data entries live globally; otherwise the link
  1532. cell yields the address and ElemLoad reads through it. *)
  1533. VAR a : QVal;
  1534. rel : CARDINAL;
  1535. BEGIN
  1536. IF locTag[flat] = 1 THEN
  1537. NewTemp(q);
  1538. Revive;
  1539. W(" "); W(q);
  1540. IF long THEN W(" =l loadl $")
  1541. ELSIF locCls[flat] = "d" THEN W(" =d loadd $")
  1542. ELSIF SymTab.IsByteType(locTyp[flat]) THEN
  1543. IF SymTab.IsSignedByte(locTyp[flat]) THEN W(" =w loadsb $")
  1544. ELSE W(" =w loadub $")
  1545. END
  1546. ELSIF SymTab.IsWord16Type(locTyp[flat]) THEN
  1547. IF SymTab.IsSignedWord16(locTyp[flat]) THEN W(" =w loadsh $")
  1548. ELSE W(" =w loaduh $")
  1549. END
  1550. ELSE W(" =w loadw $")
  1551. END;
  1552. WL(locRep[flat]);
  1553. RETURN
  1554. END;
  1555. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1556. UpAddr(levels, rel, a);
  1557. ElemLoad(a, locTyp[flat], q)
  1558. END UpLoad;
  1559. PROCEDURE UpStore (flat: INTEGER; levels: CARDINAL; q: ARRAY OF CHAR;
  1560. long: BOOLEAN);
  1561. VAR a : QVal;
  1562. rel : CARDINAL;
  1563. BEGIN
  1564. IF locTag[flat] = 1 THEN
  1565. Revive;
  1566. IF long THEN W(" storel ")
  1567. ELSIF locCls[flat] = "d" THEN W(" stored ")
  1568. ELSIF SymTab.IsByteType(locTyp[flat]) THEN W(" storeb ")
  1569. ELSIF SymTab.IsWord16Type(locTyp[flat]) THEN W(" storeh ")
  1570. ELSE W(" storew ")
  1571. END;
  1572. W(q); W(", $"); WL(locRep[flat]);
  1573. RETURN
  1574. END;
  1575. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1576. UpAddr(levels, rel, a);
  1577. ElemStore(a, q, locTyp[flat])
  1578. END UpStore;
  1579. PROCEDURE UpAddrOf (flat: INTEGER; levels: CARDINAL; VAR q: QVal);
  1580. (* Up-level address: data entries name globals; otherwise the
  1581. link cell holds it (composites) or points at it. For scalars
  1582. the cell IS the usable address (slot or actual address). *)
  1583. VAR a : QVal;
  1584. rel : CARDINAL;
  1585. BEGIN
  1586. IF locTag[flat] = 1 THEN
  1587. Cpy(q, "$");
  1588. App(q, locRep[flat]);
  1589. RETURN
  1590. END;
  1591. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1592. UpAddr(levels, rel, q)
  1593. END UpAddrOf;
  1594. PROCEDURE LoadDesignator (name: ARRAY OF CHAR; t: INTEGER; k: INTEGER;
  1595. VAR q: QVal): BOOLEAN;
  1596. VAR cls : INTEGER;
  1597. cv : QVal;
  1598. BEGIN
  1599. cls := SymTab.ClassOf(t);
  1600. IF SymTab.Equal(name, "TRUE") THEN
  1601. Cpy(q, "1"); RETURN TRUE
  1602. ELSIF SymTab.Equal(name, "FALSE") THEN
  1603. Cpy(q, "0"); RETURN TRUE
  1604. ELSIF SymTab.Equal(name, "NIL") THEN
  1605. Cpy(q, "0"); RETURN TRUE
  1606. END;
  1607. (* an immediate CONST (incl. an enumeration literal) is its value *)
  1608. IF k = SymTab.KindConst THEN
  1609. IF SymTab.GetSymVal(name, cv) AND IsImm(cv) THEN
  1610. Cpy(q, cv); RETURN TRUE
  1611. END
  1612. END;
  1613. IF (k = SymTab.KindVar) OR (k = SymTab.KindParam)
  1614. OR (k = SymTab.KindConst) THEN
  1615. IF SymTab.IsSmallInt(t) THEN
  1616. LoadShortVar(name, SymTab.IsSignedSmallInt(t),
  1617. SymTab.SmallIntBytes(t), q); RETURN TRUE
  1618. ELSIF (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
  1619. OR (cls = SymTab.ClChar) OR (cls = SymTab.ClEnum)
  1620. OR (cls = SymTab.ClReal) THEN
  1621. LoadVar(name, cls = SymTab.ClReal, q); RETURN TRUE
  1622. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc) THEN
  1623. LoadPtr(name, q); RETURN TRUE
  1624. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClSet)
  1625. OR (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1626. AddrOf(name, q); RETURN TRUE
  1627. END
  1628. END;
  1629. Cpy(q, "0");
  1630. RETURN FALSE
  1631. END LoadDesignator;
  1632. PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
  1633. VAR idx : INTEGER;
  1634. levels : CARDINAL;
  1635. ref : QVal;
  1636. BEGIN
  1637. IF LocFindUp(name, levels, idx) THEN
  1638. IF levels = 0 THEN LocLoadFlat(idx, FALSE, q)
  1639. ELSE UpLoad(idx, levels, FALSE, q)
  1640. END;
  1641. RETURN
  1642. END;
  1643. NewTemp(q);
  1644. Revive;
  1645. SymRef(name, ref);
  1646. W(" "); W(q);
  1647. IF isReal THEN W(" =d loadd ") ELSE W(" =w loadw ") END;
  1648. WL(ref)
  1649. END LoadVar;
  1650. PROCEDURE LoadShortVar (name: ARRAY OF CHAR; signed: BOOLEAN;
  1651. bytes: CARDINAL; VAR q: QVal);
  1652. VAR idx : INTEGER;
  1653. levels : CARDINAL;
  1654. ref : QVal;
  1655. BEGIN
  1656. IF LocFindUp(name, levels, idx) THEN
  1657. IF levels = 0 THEN LocLoadFlat(idx, FALSE, q)
  1658. ELSE UpLoad(idx, levels, FALSE, q)
  1659. END;
  1660. RETURN
  1661. END;
  1662. NewTemp(q);
  1663. Revive;
  1664. SymRef(name, ref);
  1665. W(" "); W(q);
  1666. IF bytes = 1 THEN
  1667. IF signed THEN W(" =w loadsb ") ELSE W(" =w loadub ") END
  1668. ELSE
  1669. IF signed THEN W(" =w loadsh ") ELSE W(" =w loaduh ") END
  1670. END;
  1671. WL(ref)
  1672. END LoadShortVar;
  1673. PROCEDURE StoreShortVar (name: ARRAY OF CHAR; bytes: CARDINAL;
  1674. q: ARRAY OF CHAR);
  1675. VAR idx : INTEGER;
  1676. levels : CARDINAL;
  1677. ref : QVal;
  1678. BEGIN
  1679. IF LocFindUp(name, levels, idx) THEN
  1680. IF levels = 0 THEN LocStoreFlat(idx, q, FALSE)
  1681. ELSE UpStore(idx, levels, q, FALSE)
  1682. END;
  1683. RETURN
  1684. END;
  1685. Revive;
  1686. SymRef(name, ref);
  1687. IF bytes = 1 THEN W(" storeb ") ELSE W(" storeh ") END;
  1688. W(q); W(", "); WL(ref)
  1689. END StoreShortVar;
  1690. PROCEDURE LoadPtr (name: ARRAY OF CHAR; VAR q: QVal);
  1691. VAR idx : INTEGER;
  1692. levels : CARDINAL;
  1693. ref : QVal;
  1694. BEGIN
  1695. IF LocFindUp(name, levels, idx) THEN
  1696. IF levels = 0 THEN LocLoadFlat(idx, TRUE, q)
  1697. ELSE UpLoad(idx, levels, TRUE, q)
  1698. END;
  1699. RETURN
  1700. END;
  1701. NewTemp(q);
  1702. Revive;
  1703. SymRef(name, ref);
  1704. W(" "); W(q); W(" =l loadl ");
  1705. WL(ref)
  1706. END LoadPtr;
  1707. PROCEDURE LoadLong (name: ARRAY OF CHAR; VAR q: QVal);
  1708. VAR idx : INTEGER;
  1709. levels : CARDINAL;
  1710. ref : QVal;
  1711. BEGIN
  1712. IF LocFindUp(name, levels, idx) THEN
  1713. IF levels = 0 THEN LocLoadFlat(idx, TRUE, q)
  1714. ELSE UpLoad(idx, levels, TRUE, q)
  1715. END;
  1716. RETURN
  1717. END;
  1718. NewTemp(q);
  1719. Revive;
  1720. SymRef(name, ref);
  1721. W(" "); W(q); W(" =l loadl ");
  1722. WL(ref)
  1723. END LoadLong;
  1724. PROCEDURE StoreLong (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  1725. VAR idx : INTEGER;
  1726. levels : CARDINAL;
  1727. ref : QVal;
  1728. BEGIN
  1729. IF LocFindUp(name, levels, idx) THEN
  1730. IF levels = 0 THEN LocStoreFlat(idx, q, TRUE)
  1731. ELSE UpStore(idx, levels, q, TRUE)
  1732. END;
  1733. RETURN
  1734. END;
  1735. Revive;
  1736. SymRef(name, ref);
  1737. W(" storel "); W(q); W(", "); WL(ref)
  1738. END StoreLong;
  1739. PROCEDURE WidenLong (a: ARRAY OF CHAR; VAR q: QVal);
  1740. (* INTEGER (w) -> LONGINT (l) via extsw. *)
  1741. BEGIN
  1742. NewTemp(q);
  1743. Revive;
  1744. W(" "); W(q); W(" =l extsw "); WL(a)
  1745. END WidenLong;
  1746. PROCEDURE CmpLong (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  1747. (* 64-bit comparison (result w). *)
  1748. VAR mn : ARRAY [0 .. 7] OF CHAR;
  1749. BEGIN
  1750. mn[0] := CHR(0);
  1751. IF op = SymTab.OpEq THEN Cpy(mn, "ceql")
  1752. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnel")
  1753. ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltl")
  1754. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslel")
  1755. ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtl")
  1756. ELSE Cpy(mn, "csgel")
  1757. END;
  1758. NewTemp(q);
  1759. Op3(mn, q, l, r, FALSE)
  1760. END CmpLong;
  1761. PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
  1762. VAR idx : INTEGER;
  1763. levels : CARDINAL;
  1764. ref : QVal;
  1765. BEGIN
  1766. IF LocFindUp(name, levels, idx) THEN
  1767. IF levels = 0 THEN LocStoreFlat(idx, q, FALSE)
  1768. ELSE UpStore(idx, levels, q, FALSE)
  1769. END;
  1770. RETURN
  1771. END;
  1772. Revive;
  1773. SymRef(name, ref);
  1774. IF isReal THEN W(" stored ") ELSE W(" storew ") END;
  1775. W(q); W(", "); WL(ref)
  1776. END StoreVar;
  1777. PROCEDURE StorePtr (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  1778. VAR idx : INTEGER;
  1779. levels : CARDINAL;
  1780. ref : QVal;
  1781. BEGIN
  1782. IF LocFindUp(name, levels, idx) THEN
  1783. IF levels = 0 THEN LocStoreFlat(idx, q, TRUE)
  1784. ELSE UpStore(idx, levels, q, TRUE)
  1785. END;
  1786. RETURN
  1787. END;
  1788. Revive;
  1789. SymRef(name, ref);
  1790. W(" storel "); W(q); W(", "); WL(ref)
  1791. END StorePtr;
  1792. PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
  1793. isReal: BOOLEAN);
  1794. BEGIN
  1795. Revive;
  1796. W(" "); W(res);
  1797. IF isReal THEN W(" =d ") ELSE W(" =w ") END;
  1798. W(mn); W(" "); W(l); W(", "); WL(r)
  1799. END Op3;
  1800. PROCEDURE AbsQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  1801. VAR c, neg : QVal;
  1802. lNeg, lPos, lDone : QVal;
  1803. BEGIN
  1804. IF isReal THEN Cmp(SymTab.OpLt, a, "d_0.0", c, TRUE)
  1805. ELSE Cmp(SymTab.OpLt, a, "0", c, FALSE)
  1806. END;
  1807. NewLabel(lNeg); NewLabel(lPos); NewLabel(lDone);
  1808. NewTemp(neg);
  1809. NegQ(a, neg, isReal);
  1810. Jnz(c, lNeg, lPos);
  1811. EmitLabel(lNeg);
  1812. CopyOp(neg, q);
  1813. Jmp(lDone);
  1814. EmitLabel(lPos);
  1815. CopyOp(a, q);
  1816. EmitLabel(lDone)
  1817. END AbsQ;
  1818. PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  1819. BEGIN
  1820. NewTemp(q);
  1821. IF isReal THEN Op3("sub", q, "d_0.0", a, TRUE)
  1822. ELSE Op3("sub", q, "0", a, FALSE)
  1823. END
  1824. END NegQ;
  1825. PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
  1826. (* INTEGER -> REAL widening for assignments (swtof). *)
  1827. BEGIN
  1828. NewTemp(q);
  1829. Revive;
  1830. W(" "); W(q); W(" =d swtof "); WL(a)
  1831. END ConvIR;
  1832. PROCEDURE NarrowLong (a: ARRAY OF CHAR; VAR q: QVal);
  1833. (* LONGINT (l) -> INTEGER (w): keep the low 32 bits. *)
  1834. BEGIN
  1835. NewTemp(q);
  1836. Revive;
  1837. W(" "); W(q); W(" =w copy "); WL(a)
  1838. END NarrowLong;
  1839. PROCEDURE ConvRI (a: ARRAY OF CHAR; VAR q: QVal);
  1840. (* REAL -> INTEGER (truncate toward zero). *)
  1841. BEGIN
  1842. NewTemp(q);
  1843. Revive;
  1844. W(" "); W(q); W(" =w dtosi "); WL(a)
  1845. END ConvRI;
  1846. PROCEDURE ConvRL (a: ARRAY OF CHAR; VAR q: QVal);
  1847. (* REAL -> LONGINT (truncate toward zero). *)
  1848. BEGIN
  1849. NewTemp(q);
  1850. Revive;
  1851. W(" "); W(q); W(" =l dtosi "); WL(a)
  1852. END ConvRL;
  1853. PROCEDURE ConvLR (a: ARRAY OF CHAR; VAR q: QVal);
  1854. (* LONGINT -> REAL. *)
  1855. BEGIN
  1856. NewTemp(q);
  1857. Revive;
  1858. W(" "); W(q); W(" =d sltof "); WL(a)
  1859. END ConvLR;
  1860. PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
  1861. BEGIN
  1862. NewTemp(q);
  1863. Op3("xor", q, "1", a, FALSE)
  1864. END NotQ;
  1865. PROCEDURE CapQ (a: ARRAY OF CHAR; VAR q: QVal);
  1866. (* Branchless UPCASE: q := a - 32 * (a >= 'a' AND a <= 'z'). *)
  1867. VAR lo, hi, in1, delta: QVal;
  1868. BEGIN
  1869. NewTemp(lo); Op3("csgew", lo, a, "97", FALSE);
  1870. NewTemp(hi); Op3("cslew", hi, a, "122", FALSE);
  1871. NewTemp(in1); Op3("and", in1, lo, hi, FALSE);
  1872. NewTemp(delta); Op3("mul", delta, in1, "32", FALSE);
  1873. NewTemp(q); Op3("sub", q, a, delta, FALSE)
  1874. END CapQ;
  1875. PROCEDURE NewLabel (VAR l: QVal);
  1876. BEGIN
  1877. Cpy(l, "@L");
  1878. AppNum(l, nLab);
  1879. INC(nLab)
  1880. END NewLabel;
  1881. PROCEDURE Revive;
  1882. (* Opens an unreachable block if past a terminator. Keeps every
  1883. temporary defined and every instruction inside a block, even for
  1884. dead source tails (EXIT followed by more statements) and CASE
  1885. chains whose compares follow a Jmp. Counter-driven: fixpoint-safe. *)
  1886. VAR b: QVal;
  1887. BEGIN
  1888. IF opened AND dead THEN
  1889. NewLabel(b);
  1890. WL(b);
  1891. dead := FALSE
  1892. END
  1893. END Revive;
  1894. PROCEDURE EmitLabel (l: ARRAY OF CHAR);
  1895. BEGIN
  1896. WL(l);
  1897. dead := FALSE
  1898. END EmitLabel;
  1899. PROCEDURE Jmp (l: ARRAY OF CHAR);
  1900. BEGIN
  1901. IF dead THEN RETURN END; (* unreachable: a terminator with no
  1902. intervening label can never be reached; emitting it would end
  1903. the block and orphan whatever follows. *)
  1904. W(" jmp "); WL(l);
  1905. dead := TRUE
  1906. END Jmp;
  1907. PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
  1908. BEGIN
  1909. IF dead THEN RETURN END;
  1910. W(" jnz "); W(c); W(", "); W(t); W(", "); WL(f);
  1911. dead := TRUE
  1912. END Jnz;
  1913. PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
  1914. isReal: BOOLEAN);
  1915. VAR mn : ARRAY [0 .. 7] OF CHAR;
  1916. BEGIN
  1917. mn[0] := CHR(0);
  1918. IF isReal THEN
  1919. IF op = SymTab.OpEq THEN Cpy(mn, "ceqd")
  1920. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cned")
  1921. ELSIF op = SymTab.OpLt THEN Cpy(mn, "cltd")
  1922. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cled")
  1923. ELSIF op = SymTab.OpGt THEN Cpy(mn, "cgtd")
  1924. ELSE Cpy(mn, "cged")
  1925. END
  1926. ELSE
  1927. IF op = SymTab.OpEq THEN Cpy(mn, "ceqw")
  1928. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnew")
  1929. ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltw")
  1930. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslew")
  1931. ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtw")
  1932. ELSE Cpy(mn, "csgew")
  1933. END
  1934. END;
  1935. NewTemp(q);
  1936. Op3(mn, q, l, r, FALSE)
  1937. END Cmp;
  1938. PROCEDURE StrEq (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  1939. (* String equality via the shim: q := (l = r) as a BOOLEAN, negated for
  1940. OpNeq. Operands are descriptor addresses; the shim strcmps the
  1941. NUL-terminated contents. *)
  1942. VAR t: QVal;
  1943. BEGIN
  1944. NewTemp(q);
  1945. W(" "); W(q); W(" =w call $m2streq(l ");
  1946. W(l); W(", l "); W(r); WL(")");
  1947. IF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
  1948. NewTemp(t);
  1949. W(" "); W(t); W(" =w xor "); W(q); WL(", 1");
  1950. Cpy(q, t)
  1951. END
  1952. END StrEq;
  1953. PROCEDURE StrAssign (dst, src: ARRAY OF CHAR);
  1954. (* Copy the string src into the CHAR array at dst (content copy,
  1955. truncated to the destination capacity, NUL-terminated). *)
  1956. BEGIN
  1957. W(" call $m2strassign(l "); W(dst); W(", l "); W(src); WL(")")
  1958. END StrAssign;
  1959. PROCEDURE UAssign (dst, src: ARRAY OF CHAR);
  1960. (* Copy a U"..." descriptor (count + 4-byte codepoints) into the UCHAR
  1961. array at dst: min(count, capacity) codepoints + a 0 terminator. *)
  1962. BEGIN
  1963. W(" call $m2uassign(l "); W(dst); W(", l "); W(src); WL(")")
  1964. END UAssign;
  1965. PROCEDURE UStrLen (s: ARRAY OF CHAR; VAR q: QVal);
  1966. (* q := the UString codepoint count (INTEGER). *)
  1967. VAR t: QVal;
  1968. BEGIN
  1969. NewTemp(t);
  1970. W(" "); W(t); W(" =w call $m2ustrlen(l "); W(s); WL(")");
  1971. Cpy(q, t)
  1972. END UStrLen;
  1973. PROCEDURE DecQ (VAR q: QVal);
  1974. (* q := q - 1 (w domain; q is an INTEGER count). *)
  1975. VAR t: QVal;
  1976. BEGIN
  1977. NewTemp(t);
  1978. Op3("sub", t, q, "1", FALSE);
  1979. Cpy(q, t)
  1980. END DecQ;
  1981. PROCEDURE UStrCat (a, b: ARRAY OF CHAR; VAR q: QVal);
  1982. (* q := a + b (a UString descriptor in the shim's concat buffer). *)
  1983. BEGIN
  1984. NewTemp(q);
  1985. W(" "); W(q); W(" =l call $m2ustrcat(l "); W(a); W(", l "); W(b); WL(")")
  1986. END UStrCat;
  1987. PROCEDURE UStrFrom (cp: ARRAY OF CHAR; VAR q: QVal);
  1988. (* q := a 1-codepoint UString descriptor for the UCHAR value cp. *)
  1989. BEGIN
  1990. NewTemp(q);
  1991. W(" "); W(q); W(" =l call $m2ustrfrom(l "); W(cp); WL(")")
  1992. END UStrFrom;
  1993. PROCEDURE StrCat (a, b: ARRAY OF CHAR; VAR q: QVal);
  1994. (* q := a + b (a descriptor in the shim's concat buffer). *)
  1995. BEGIN
  1996. NewTemp(q);
  1997. W(" "); W(q); W(" =l call $m2strcat(l "); W(a); W(", l "); W(b); WL(")")
  1998. END StrCat;
  1999. (* ---------------- arrays: length-prefixed layout ---------------- *)
  2000. (* Indexes and counts are LONGCARD (l) in emitted code; immediates
  2001. pass through, w-temps widen via extsw. Traps call $abort + hlt
  2002. (interim; runtime/syslib/Trap replaces them later). *)
  2003. PROCEDURE ElemCls (t: SymTab.TypeIndex): INTEGER;
  2004. BEGIN
  2005. RETURN SymTab.ClassOf(SymTab.ArrayElem(t))
  2006. END ElemCls;
  2007. PROCEDURE ElemSize (t: SymTab.TypeIndex): CARDINAL;
  2008. (* Storage size of t's elements: CHAR 1, REAL 8, nested/pointer/long 8,
  2009. records/classes/sets their inline footprint, else 4. t is an array
  2010. (or string) descriptor. *)
  2011. VAR cls: INTEGER; et: SymTab.TypeIndex;
  2012. BEGIN
  2013. cls := SymTab.ClassOf(t);
  2014. IF cls = SymTab.ClStr THEN RETURN 1 END;
  2015. et := SymTab.ArrayElem(t);
  2016. cls := SymTab.ClassOf(et);
  2017. IF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  2018. OR (cls = SymTab.ClSByte) THEN RETURN 1
  2019. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN RETURN 2
  2020. ELSIF cls = SymTab.ClReal THEN RETURN 8
  2021. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr)
  2022. OR (cls = SymTab.ClLong) THEN RETURN 8
  2023. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass)
  2024. OR (cls = SymTab.ClSet) THEN
  2025. RETURN SymTab.TypeSize(et)
  2026. ELSE RETURN 4
  2027. END
  2028. END ElemSize;
  2029. PROCEDURE Op3L (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR);
  2030. BEGIN
  2031. Revive;
  2032. W(" "); W(res);
  2033. W(" =l ");
  2034. W(mn); W(" "); W(l); W(", "); WL(r)
  2035. END Op3L;
  2036. PROCEDURE HaltQ;
  2037. BEGIN
  2038. Revive;
  2039. WL(" call $exit(w 1)");
  2040. WL(" hlt");
  2041. dead := TRUE
  2042. END HaltQ;
  2043. PROCEDURE TrapCode (code: CARDINAL);
  2044. VAR q: QVal;
  2045. BEGIN
  2046. Revive;
  2047. IntStr(VAL(INTEGER, code), q);
  2048. W(" call $m2_exc_raise_lang(w "); W(q); WL(")");
  2049. WL(" hlt");
  2050. dead := TRUE
  2051. END TrapCode;
  2052. PROCEDURE Trap;
  2053. BEGIN
  2054. TrapCode(12) (* sysException *)
  2055. END Trap;
  2056. (* ---------------- records: flat blobs, pointer fields ---------------- *)
  2057. (* Scalars/sets inline, array fields as inline descriptors (8-byte length
  2058. word + data), nested records inline. Static offsets throughout. *)
  2059. PROCEDURE HasArrayField (t: SymTab.TypeIndex): BOOLEAN;
  2060. (* TRUE when record type t (recursively) has any ARRAY field. Such
  2061. record arrays need per-element expansion so each inline array field's
  2062. descriptor length word is initialised; a compact zero blob would
  2063. leave the count 0 and trap when the field is passed as an open array.
  2064. Records with no array field still stay a compact blob. *)
  2065. VAR i: CARDINAL; fn: SymTab.Name; ft: SymTab.TypeIndex; cls: INTEGER;
  2066. BEGIN
  2067. i := 0;
  2068. WHILE i < SymTab.FieldCount(t) DO
  2069. SymTab.FieldName(t, i, fn);
  2070. ft := SymTab.FieldType(t, fn);
  2071. cls := SymTab.ClassOf(ft);
  2072. IF cls = SymTab.ClArray THEN RETURN TRUE
  2073. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2074. IF HasArrayField(ft) THEN RETURN TRUE END
  2075. END;
  2076. INC(i)
  2077. END;
  2078. RETURN FALSE
  2079. END HasArrayField;
  2080. PROCEDURE HasMultiArrayField (t: SymTab.TypeIndex): BOOLEAN;
  2081. (* TRUE when a record/class contains a rank-2/3 array field, directly
  2082. or in a nested record. Such record constructors need the runtime
  2083. path so the flat field payload is handled by a view. *)
  2084. VAR i: CARDINAL; fn: SymTab.Name; ft: SymTab.TypeIndex; cls: INTEGER;
  2085. BEGIN
  2086. i := 0;
  2087. WHILE i < SymTab.FieldCount(t) DO
  2088. SymTab.FieldName(t, i, fn);
  2089. ft := SymTab.FieldType(t, fn);
  2090. cls := SymTab.ClassOf(ft);
  2091. IF (cls = SymTab.ClArray) AND SymTab.IsMultiArray(ft) THEN
  2092. RETURN TRUE
  2093. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2094. IF HasMultiArrayField(ft) THEN RETURN TRUE END
  2095. END;
  2096. INC(i)
  2097. END;
  2098. RETURN FALSE
  2099. END HasMultiArrayField;
  2100. PROCEDURE RecArrayExpanded (n: CARDINAL; t: INTEGER): BOOLEAN;
  2101. (* TRUE when a record-/class-array's per-element expansion fits the image
  2102. budget. Larger tables keep the compact zero blob and are instead
  2103. initialised at run time (RecArrayNeedsInit/InitRecArray). The budget
  2104. keeps the compiler's own huge tables (AST.arena: 262144 records) from
  2105. inflating the 4 MiB image. *)
  2106. BEGIN
  2107. RETURN VAL(INTEGER, n) * VAL(INTEGER, SymTab.TypeSize(t)) <= 131072
  2108. END RecArrayExpanded;
  2109. PROCEDURE ArrBodyItems (prefix: ARRAY OF CHAR; t: INTEGER);
  2110. (* Inline contents of an array descriptor (no "data $name = {" wrapper
  2111. and no closing brace): "l <n>[, <elem>...]". Nested levels are
  2112. referenced as $prefix_i (emitted by ArrData). Record/class elements
  2113. with nested-array fields are expanded per element (EmitRec) so their
  2114. sub-descriptors are referenced; others stay a compact zero blob. *)
  2115. VAR n, i: CARDINAL;
  2116. elem: SymTab.TypeIndex;
  2117. ecls: INTEGER;
  2118. esz: CARDINAL;
  2119. bv, sub: QVal;
  2120. first: BOOLEAN;
  2121. (* One inline record: mirrors RecItems (same field order and comma
  2122. handling), but array fields recurse into the enclosing
  2123. ArrBodyItems. Nested here so no FORWARD declaration is needed. *)
  2124. PROCEDURE EmitRec (rt: SymTab.TypeIndex; rpre: ARRAY OF CHAR;
  2125. VAR first: BOOLEAN);
  2126. VAR i, k, w: CARDINAL;
  2127. fn: SymTab.Name;
  2128. ft: SymTab.TypeIndex;
  2129. cls: INTEGER;
  2130. rsub: QVal;
  2131. PROCEDURE Sep;
  2132. BEGIN
  2133. IF first THEN first := FALSE ELSE W(", ") END
  2134. END Sep;
  2135. BEGIN
  2136. i := 0;
  2137. WHILE i < SymTab.FieldCount(rt) DO
  2138. SymTab.FieldName(rt, i, fn);
  2139. ft := SymTab.FieldType(rt, fn);
  2140. cls := SymTab.ClassOf(ft);
  2141. IF cls = SymTab.ClReal THEN Sep; W("d 0")
  2142. ELSIF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  2143. OR (cls = SymTab.ClSByte) THEN Sep; W("b 0")
  2144. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  2145. Sep; W("h 0")
  2146. ELSIF cls = SymTab.ClArray THEN
  2147. Sep;
  2148. IF SymTab.IsMultiArray(ft) THEN
  2149. W("z "); IntStr(VAL(INTEGER, SymTab.ArrayPayloadSize(ft)), rsub);
  2150. W(rsub)
  2151. ELSE
  2152. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2153. ArrBodyItems(rsub, ft)
  2154. END
  2155. ELSIF cls = SymTab.ClSet THEN
  2156. w := SymTab.SetWords(ft);
  2157. IF w = 0 THEN w := 1 END;
  2158. Sep; W("w 0");
  2159. k := 1;
  2160. WHILE k < w DO W(", w 0"); INC(k) END
  2161. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2162. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2163. EmitRec(ft, rsub, first)
  2164. ELSE Sep; W("w 0")
  2165. END;
  2166. INC(i)
  2167. END
  2168. END EmitRec;
  2169. BEGIN
  2170. n := SymTab.ArrayLen(t);
  2171. elem := SymTab.ArrayElem(t);
  2172. ecls := SymTab.ClassOf(elem);
  2173. W("l ");
  2174. IntStr(VAL(INTEGER, n), bv);
  2175. W(bv);
  2176. IF ecls = SymTab.ClArray THEN
  2177. i := 0;
  2178. WHILE i < n DO
  2179. W(", l $"); W(prefix); W("_");
  2180. IntStr(VAL(INTEGER, i), bv);
  2181. W(bv);
  2182. INC(i)
  2183. END
  2184. ELSIF ((ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass))
  2185. AND HasArrayField(elem)
  2186. AND RecArrayExpanded(n, elem) THEN
  2187. i := 0;
  2188. WHILE i < n DO
  2189. Cpy(sub, prefix); App(sub, "_");
  2190. IntStr(VAL(INTEGER, i), bv); App(sub, bv);
  2191. first := FALSE;
  2192. EmitRec(elem, sub, first);
  2193. INC(i)
  2194. END
  2195. ELSE
  2196. IF ecls = SymTab.ClChar THEN
  2197. (* CHAR: n data bytes + one NUL terminator slot *)
  2198. W(", z ");
  2199. IntStr(VAL(INTEGER, n + 1), bv);
  2200. W(bv)
  2201. ELSIF ecls = SymTab.ClUChar THEN
  2202. (* UCHAR: n codepoints + one 0-codepoint terminator slot *)
  2203. W(", z ");
  2204. IntStr(VAL(INTEGER, (n + 1) * 4), bv);
  2205. W(bv)
  2206. ELSE
  2207. IF (ecls = SymTab.ClByte) OR (ecls = SymTab.ClSByte) THEN esz := 1
  2208. ELSIF (ecls = SymTab.ClWord16) OR (ecls = SymTab.ClSWord16) THEN esz := 2
  2209. ELSIF (ecls = SymTab.ClReal) OR (ecls = SymTab.ClPtr)
  2210. OR (ecls = SymTab.ClProc) OR (ecls = SymTab.ClLong) THEN esz := 8
  2211. ELSIF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass)
  2212. OR (ecls = SymTab.ClSet) THEN
  2213. (* inline footprint, not a fixed 4 (same fix as ElemSize) *)
  2214. esz := SymTab.TypeSize(elem)
  2215. ELSE esz := 4
  2216. END;
  2217. IF n > 0 THEN
  2218. W(", z ");
  2219. IntStr(VAL(INTEGER, n * esz), bv);
  2220. W(bv)
  2221. END
  2222. END
  2223. END
  2224. END ArrBodyItems;
  2225. PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
  2226. (* "data $name = { <items> }" plus, for nested levels, the recursive
  2227. sub-descriptor data $name_i. *)
  2228. VAR n, i: CARDINAL;
  2229. elem: SymTab.TypeIndex;
  2230. bv: QVal;
  2231. sub: QVal;
  2232. (* Mirrors RecStatics, but nested-array sub-descriptors recurse into
  2233. the enclosing ArrData. Nested here so no FORWARD is needed. *)
  2234. PROCEDURE EmitRecStatics (rpre: ARRAY OF CHAR; rt: SymTab.TypeIndex);
  2235. VAR k, j, an: CARDINAL;
  2236. fn: SymTab.Name;
  2237. ft, et: SymTab.TypeIndex;
  2238. cls: INTEGER;
  2239. rsub, bv2: QVal;
  2240. BEGIN
  2241. k := 0;
  2242. WHILE k < SymTab.FieldCount(rt) DO
  2243. SymTab.FieldName(rt, k, fn);
  2244. ft := SymTab.FieldType(rt, fn);
  2245. cls := SymTab.ClassOf(ft);
  2246. IF (cls = SymTab.ClArray) AND NOT SymTab.IsMultiArray(ft) THEN
  2247. et := SymTab.ArrayElem(ft);
  2248. IF SymTab.ClassOf(et) = SymTab.ClArray THEN
  2249. an := SymTab.ArrayLen(ft);
  2250. j := 0;
  2251. WHILE j < an DO
  2252. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2253. App(rsub, "_");
  2254. IntStr(VAL(INTEGER, j), bv2);
  2255. App(rsub, bv2);
  2256. ArrData(rsub, et);
  2257. INC(j)
  2258. END
  2259. END
  2260. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2261. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2262. EmitRecStatics(rsub, ft)
  2263. END;
  2264. INC(k)
  2265. END
  2266. END EmitRecStatics;
  2267. BEGIN
  2268. IF NOT opened THEN RETURN END;
  2269. W("data $"); W(name);
  2270. W(" = { ");
  2271. ArrBodyItems(name, t);
  2272. WL(" }");
  2273. elem := SymTab.ArrayElem(t);
  2274. IF SymTab.ClassOf(elem) = SymTab.ClArray THEN
  2275. n := SymTab.ArrayLen(t);
  2276. i := 0;
  2277. WHILE i < n DO
  2278. Cpy(sub, name); App(sub, "_");
  2279. IntStr(VAL(INTEGER, i), bv);
  2280. App(sub, bv);
  2281. ArrData(sub, elem);
  2282. INC(i)
  2283. END
  2284. ELSIF ((SymTab.ClassOf(elem) = SymTab.ClRecord)
  2285. OR (SymTab.ClassOf(elem) = SymTab.ClClass))
  2286. AND HasArrayField(elem)
  2287. AND RecArrayExpanded(SymTab.ArrayLen(t), elem) THEN
  2288. (* Sub-descriptors referenced (as $name_i_field_k) from the inline
  2289. items emitted by ArrBodyItems; one set per element. *)
  2290. n := SymTab.ArrayLen(t);
  2291. i := 0;
  2292. WHILE i < n DO
  2293. Cpy(sub, name); App(sub, "_");
  2294. IntStr(VAL(INTEGER, i), bv);
  2295. App(sub, bv);
  2296. EmitRecStatics(sub, elem);
  2297. INC(i)
  2298. END
  2299. END
  2300. END ArrData;
  2301. PROCEDURE RecStatics (recname: ARRAY OF CHAR; t: SymTab.TypeIndex);
  2302. (* Pre-pass: static sub-descriptors for NESTED array fields (the
  2303. top-level array field is now inline in the record), recursive. *)
  2304. VAR n, i, k, an: CARDINAL;
  2305. fn: SymTab.Name;
  2306. ft, et: SymTab.TypeIndex;
  2307. cls: INTEGER;
  2308. sub, bv: QVal;
  2309. BEGIN
  2310. n := SymTab.FieldCount(t);
  2311. i := 0;
  2312. WHILE i < n DO
  2313. SymTab.FieldName(t, i, fn);
  2314. ft := SymTab.FieldType(t, fn);
  2315. cls := SymTab.ClassOf(ft);
  2316. IF (cls = SymTab.ClArray) AND NOT SymTab.IsMultiArray(ft) THEN
  2317. et := SymTab.ArrayElem(ft);
  2318. IF SymTab.ClassOf(et) = SymTab.ClArray THEN
  2319. an := SymTab.ArrayLen(ft);
  2320. k := 0;
  2321. WHILE k < an DO
  2322. Cpy(sub, recname); App(sub, "_"); App(sub, fn);
  2323. App(sub, "_");
  2324. IntStr(VAL(INTEGER, k), bv);
  2325. App(sub, bv);
  2326. ArrData(sub, et);
  2327. INC(k)
  2328. END
  2329. END
  2330. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2331. Cpy(sub, recname); App(sub, "_"); App(sub, fn);
  2332. RecStatics(sub, ft)
  2333. END;
  2334. INC(i)
  2335. END
  2336. END RecStatics;
  2337. PROCEDURE RecItems (t: SymTab.TypeIndex; prefix: ARRAY OF CHAR;
  2338. VAR first: BOOLEAN);
  2339. (* Comma-separated item list (no wrapper); nested records inline.
  2340. Emission order follows the (prepend-built) field chain, i.e.
  2341. reverse declaration; offsets (not positions) place everything. *)
  2342. VAR n, i, k, w: CARDINAL;
  2343. fn: SymTab.Name;
  2344. ft: SymTab.TypeIndex;
  2345. cls: INTEGER;
  2346. sub: QVal;
  2347. PROCEDURE Sep;
  2348. BEGIN
  2349. IF first THEN first := FALSE ELSE W(", ") END
  2350. END Sep;
  2351. BEGIN
  2352. n := SymTab.FieldCount(t);
  2353. i := 0;
  2354. WHILE i < n DO
  2355. SymTab.FieldName(t, i, fn);
  2356. ft := SymTab.FieldType(t, fn);
  2357. cls := SymTab.ClassOf(ft);
  2358. IF cls = SymTab.ClReal THEN Sep; W("d 0")
  2359. ELSIF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  2360. OR (cls = SymTab.ClSByte) THEN Sep; W("b 0")
  2361. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  2362. Sep; W("h 0")
  2363. ELSIF cls = SymTab.ClArray THEN
  2364. Sep;
  2365. IF SymTab.IsMultiArray(ft) THEN
  2366. W("z "); IntStr(VAL(INTEGER, SymTab.ArrayPayloadSize(ft)), sub);
  2367. W(sub)
  2368. ELSE
  2369. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  2370. ArrBodyItems(sub, ft)
  2371. END
  2372. ELSIF cls = SymTab.ClSet THEN
  2373. w := SymTab.SetWords(ft);
  2374. IF w = 0 THEN w := 1 END;
  2375. Sep; W("w 0");
  2376. k := 1;
  2377. WHILE k < w DO W(", w 0"); INC(k) END
  2378. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2379. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  2380. RecItems(ft, sub, first)
  2381. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong)
  2382. OR (cls = SymTab.ClProc) THEN
  2383. (* 8-byte fields: match the layout's pointer/long size (a `w 0`
  2384. here would shrink the global and clobber the next symbol) *)
  2385. Sep; W("l 0")
  2386. ELSE Sep; W("w 0")
  2387. END;
  2388. INC(i)
  2389. END
  2390. END RecItems;
  2391. PROCEDURE VtRef (t: INTEGER; VAR q: QVal);
  2392. (* The class's vtable symbol ($vt_<typeindex>). *)
  2393. VAR bv: QVal;
  2394. BEGIN
  2395. Cpy(q, "$vt_");
  2396. IntStr(t, bv);
  2397. App(q, bv)
  2398. END VtRef;
  2399. PROCEDURE EmitVTables;
  2400. (* One data array per class with a vtable: slots (inherited first) as
  2401. method code addresses. *)
  2402. VAR k, j, n: CARDINAL;
  2403. t: INTEGER;
  2404. nm: SymTab.Name;
  2405. mg, vt: QVal;
  2406. BEGIN
  2407. IF NOT opened THEN RETURN END;
  2408. k := 0;
  2409. WHILE k < SymTab.VtClassCount() DO
  2410. t := SymTab.VtClassAt(k);
  2411. n := SymTab.VtCount(t);
  2412. VtRef(t, vt);
  2413. W("data "); W(vt); W(" = { ");
  2414. j := 0;
  2415. WHILE j < n DO
  2416. IF SymTab.VtName(t, j, nm) THEN
  2417. IF j > 0 THEN W(", ") END;
  2418. IF SymTab.VtHasBody(t, j) THEN
  2419. Mangled(nm, SymTab.VtUid(t, j), mg);
  2420. W("l $"); W(mg)
  2421. ELSE
  2422. W("l 0") (* declared but never implemented *)
  2423. END
  2424. END;
  2425. INC(j)
  2426. END;
  2427. IF n = 0 THEN W("l 0") END;
  2428. WL(" }");
  2429. INC(k)
  2430. END
  2431. END EmitVTables;
  2432. PROCEDURE DeclRec (name: ARRAY OF CHAR; t: INTEGER);
  2433. VAR first: BOOLEAN;
  2434. vt, sz: QVal;
  2435. BEGIN
  2436. IF NOT opened THEN RETURN END;
  2437. IF SymTab.IsVariant(t) AND (SymTab.ClassOf(t) = SymTab.ClRecord) THEN
  2438. (* variant record: fields overlay, so emit one zero-filled blob
  2439. of the record's (max) size *)
  2440. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), sz);
  2441. W("data $"); W(name); W(" = { z "); W(sz); WL(" }");
  2442. RETURN
  2443. END;
  2444. RecStatics(name, t);
  2445. W("data $"); W(name);
  2446. W(" = { ");
  2447. first := TRUE;
  2448. (* a class with a vtable stores its vtable pointer at offset 0 *)
  2449. IF (SymTab.ClassOf(t) = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  2450. VtRef(t, vt);
  2451. W("l "); W(vt);
  2452. first := FALSE
  2453. END;
  2454. RecItems(t, name, first);
  2455. IF first THEN W("w 0") END;
  2456. WL(" }")
  2457. END DeclRec;
  2458. PROCEDURE FieldAddr (base: ARRAY OF CHAR; off: INTEGER; VAR q: QVal);
  2459. VAR sb: QVal;
  2460. BEGIN
  2461. NewTemp(q);
  2462. IntStr(off, sb);
  2463. Op3L("add", q, base, sb)
  2464. END FieldAddr;
  2465. PROCEDURE ThisBase (VAR q: QVal);
  2466. (* The current method's receiver address (the hidden THIS VAR param). *)
  2467. BEGIN
  2468. AddrOf("THIS", q)
  2469. END ThisBase;
  2470. PROCEDURE PushWith (base: ARRAY OF CHAR);
  2471. BEGIN
  2472. IF withTop <= HIGH(withSt) THEN
  2473. Cpy(withSt[withTop], base); INC(withTop)
  2474. END
  2475. END PushWith;
  2476. PROCEDURE PopWith;
  2477. BEGIN
  2478. IF withTop > 0 THEN DEC(withTop) END
  2479. END PopWith;
  2480. PROCEDURE TopWith (VAR base: QVal): BOOLEAN;
  2481. BEGIN
  2482. IF withTop = 0 THEN RETURN FALSE END;
  2483. Cpy(base, withSt[withTop - 1]);
  2484. RETURN TRUE
  2485. END TopWith;
  2486. PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  2487. t: INTEGER);
  2488. (* Whole-record copy: a flat byte blit of the record's (max) size.
  2489. Records are flat blobs (scalars/sets/pointers inline, arrays and
  2490. nested records inline), so this is correct — and the only correct
  2491. choice for variant records, whose fields overlay. *)
  2492. VAR n: QVal;
  2493. BEGIN
  2494. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), n);
  2495. Revive;
  2496. W(" call $memcpy(l "); W(dst); W(", l "); W(src);
  2497. W(", l "); W(n); WL(")")
  2498. END CopyRecord;
  2499. PROCEDURE WordsBytes (words: CARDINAL): CARDINAL;
  2500. BEGIN
  2501. IF words = 0 THEN RETURN 8 END;
  2502. RETURN ((words * 4 + 7) DIV 8) * 8
  2503. END WordsBytes;
  2504. PROCEDURE DeclSet (name: ARRAY OF CHAR; t: INTEGER);
  2505. VAR w, i: CARDINAL;
  2506. BEGIN
  2507. IF NOT opened THEN RETURN END;
  2508. w := SymTab.SetWords(t);
  2509. IF w = 0 THEN w := 1 END;
  2510. W("data $"); W(name);
  2511. W(" = { w 0");
  2512. i := 1;
  2513. WHILE i < w DO
  2514. W(", w 0");
  2515. INC(i)
  2516. END;
  2517. WL(" }")
  2518. END DeclSet;
  2519. PROCEDURE PoolSet (mask: ARRAY OF CARDINAL; words: CARDINAL; VAR q: QVal);
  2520. VAR k: CARDINAL;
  2521. BEGIN
  2522. IF NOT opened OR noEmit THEN Cpy(q, "0"); RETURN END;
  2523. IF setN > HIGH(setW) THEN Cpy(q, "0"); RETURN END;
  2524. k := 0;
  2525. WHILE (k < words) AND (k <= HIGH(mask)) AND (k <= 15) DO
  2526. setMask[setN][k] := mask[k]; INC(k)
  2527. END;
  2528. WHILE k <= 15 DO setMask[setN][k] := 0; INC(k) END;
  2529. setW[setN] := words;
  2530. Cpy(setNam[setN], "set"); AppNum(setNam[setN], setN);
  2531. Cpy(q, "$"); App(q, setNam[setN]);
  2532. INC(setN)
  2533. END PoolSet;
  2534. PROCEDURE PoolSetNamed (name: ARRAY OF CHAR; mask: ARRAY OF CARDINAL;
  2535. words: CARDINAL; VAR q: QVal);
  2536. (* Like PoolSet but registers the descriptor as `data $<name>` — used for
  2537. a module-level set CONST, whose global name (<unit>_<const>) is what a
  2538. client's qualified reference emits. *)
  2539. VAR k: CARDINAL;
  2540. BEGIN
  2541. IF NOT opened OR noEmit THEN Cpy(q, "0"); RETURN END;
  2542. IF setN > HIGH(setW) THEN Cpy(q, "0"); RETURN END;
  2543. k := 0;
  2544. WHILE (k < words) AND (k <= HIGH(mask)) AND (k <= 15) DO
  2545. setMask[setN][k] := mask[k]; INC(k)
  2546. END;
  2547. WHILE k <= 15 DO setMask[setN][k] := 0; INC(k) END;
  2548. setW[setN] := words;
  2549. Cpy(setNam[setN], name);
  2550. Cpy(q, "$"); App(q, name);
  2551. INC(setN)
  2552. END PoolSetNamed;
  2553. PROCEDURE NewSetTemp (words: CARDINAL; VAR q: QVal);
  2554. VAR nb: QVal;
  2555. BEGIN
  2556. NewTemp(q);
  2557. Revive;
  2558. IntStr(VAL(INTEGER, WordsBytes(words)), nb);
  2559. W(" "); W(q); W(" =l alloc8 "); WL(nb)
  2560. END NewSetTemp;
  2561. PROCEDURE SetZero (addr: ARRAY OF CHAR; words: CARDINAL);
  2562. VAR i: CARDINAL;
  2563. a, z, off: QVal;
  2564. BEGIN
  2565. NewTemp(z);
  2566. Op3("xor", z, "0", "0", FALSE);
  2567. i := 0;
  2568. WHILE i < words DO
  2569. NewTemp(a);
  2570. IntStr(VAL(INTEGER, i * 4), off);
  2571. Op3L("add", a, addr, off);
  2572. Revive;
  2573. W(" storew "); W(z); W(", "); WL(a);
  2574. INC(i)
  2575. END
  2576. END SetZero;
  2577. PROCEDURE SetBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  2578. lo: INTEGER; span: CARDINAL);
  2579. (* ORs one element in: off = val - lo trapped in [0, span). *)
  2580. VAR off, offL, hiS, loS: QVal;
  2581. wi, bi, wil, off4, wa, wcur, m, wn: QVal;
  2582. BEGIN
  2583. NewTemp(off);
  2584. IntStr(lo, loS);
  2585. Op3("sub", off, val, loS, FALSE);
  2586. WidenIndex(off, offL);
  2587. IntStr(VAL(INTEGER, span) - 1, hiS);
  2588. CheckRange(offL, "0", hiS);
  2589. NewTemp(wi);
  2590. Op3("shr", wi, off, "5", FALSE);
  2591. NewTemp(bi);
  2592. Op3("and", bi, off, "31", FALSE);
  2593. WidenIndex(wi, wil);
  2594. NewTemp(off4);
  2595. Op3L("mul", off4, wil, "4");
  2596. NewTemp(wa);
  2597. Op3L("add", wa, addr, off4);
  2598. NewTemp(m);
  2599. Op3("shl", m, "1", bi, FALSE);
  2600. NewTemp(wcur);
  2601. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  2602. NewTemp(wn);
  2603. Op3("or", wn, wcur, m, FALSE);
  2604. Revive;
  2605. W(" storew "); W(wn); W(", "); WL(wa)
  2606. END SetBit;
  2607. PROCEDURE SetClearBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  2608. lo: INTEGER; span: CARDINAL);
  2609. (* ANDs one element out: off = val - lo trapped in [0, span). *)
  2610. VAR off, offL, hiS, loS: QVal;
  2611. wi, bi, wil, off4, wa, wcur, m, nm, wn: QVal;
  2612. BEGIN
  2613. NewTemp(off);
  2614. IntStr(lo, loS);
  2615. Op3("sub", off, val, loS, FALSE);
  2616. WidenIndex(off, offL);
  2617. IntStr(VAL(INTEGER, span) - 1, hiS);
  2618. CheckRange(offL, "0", hiS);
  2619. NewTemp(wi);
  2620. Op3("shr", wi, off, "5", FALSE);
  2621. NewTemp(bi);
  2622. Op3("and", bi, off, "31", FALSE);
  2623. WidenIndex(wi, wil);
  2624. NewTemp(off4);
  2625. Op3L("mul", off4, wil, "4");
  2626. NewTemp(wa);
  2627. Op3L("add", wa, addr, off4);
  2628. NewTemp(m);
  2629. Op3("shl", m, "1", bi, FALSE);
  2630. NewTemp(nm);
  2631. Op3("xor", nm, m, "-1", FALSE);
  2632. NewTemp(wcur);
  2633. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  2634. NewTemp(wn);
  2635. Op3("and", wn, wcur, nm, FALSE);
  2636. Revive;
  2637. W(" storew "); W(wn); W(", "); WL(wa)
  2638. END SetClearBit;
  2639. PROCEDURE SetShift (src: ARRAY OF CHAR; n: ARRAY OF CHAR;
  2640. words: CARDINAL; span: CARDINAL; isRot: BOOLEAN;
  2641. VAR q: QVal);
  2642. (* Bit-by-bit shift/rotate by a runtime amount n over [0, span);
  2643. bits that leave the span are dropped (SHIFT) or wrapped (ROTATE). *)
  2644. VAR out, nn, sp, hi, i: QVal;
  2645. wi, bi, wil, off4, wa, m, t, bit, nzb: QVal;
  2646. j, c, cs, jw: QVal;
  2647. ok1, ok2, ok, sj, wj, bj, wjl, o2, wb2, mm, mm2, mm3: QVal;
  2648. wcur, wn, ip1: QVal;
  2649. ltop, lbody, lend: QVal;
  2650. BEGIN
  2651. NewSetTemp(words, out);
  2652. SetZero(out, words);
  2653. Cpy(nn, n);
  2654. IntStr(VAL(INTEGER, span), sp);
  2655. IntStr(VAL(INTEGER, span) - 1, hi);
  2656. IF isRot THEN
  2657. NewTemp(j); Op3("rem", j, n, sp, FALSE);
  2658. NewTemp(ok1); Op3("add", ok1, j, sp, FALSE);
  2659. NewTemp(cs); Op3("rem", cs, ok1, sp, FALSE);
  2660. Cpy(nn, cs)
  2661. END;
  2662. NewTemp(i); Op3("add", i, "0", "0", FALSE);
  2663. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  2664. EmitLabel(ltop);
  2665. NewTemp(c); Op3("cslew", c, i, hi, FALSE);
  2666. Jnz(c, lbody, lend);
  2667. EmitLabel(lbody);
  2668. NewTemp(wi); Op3("shr", wi, i, "5", FALSE);
  2669. NewTemp(bi); Op3("and", bi, i, "31", FALSE);
  2670. WidenIndex(wi, wil);
  2671. NewTemp(off4); Op3L("mul", off4, wil, "4");
  2672. NewTemp(wa); Op3L("add", wa, src, off4);
  2673. NewTemp(m); Op3("shl", m, "1", bi, FALSE);
  2674. NewTemp(t); W(" "); W(t); W(" =w loadw "); WL(wa);
  2675. NewTemp(bit); Op3("and", bit, t, m, FALSE);
  2676. NewTemp(nzb); Op3("cnew", nzb, bit, "0", FALSE);
  2677. NewTemp(j); Op3("add", j, i, nn, FALSE);
  2678. IF isRot THEN
  2679. NewTemp(c); Op3("csgew", c, j, sp, FALSE);
  2680. NewTemp(cs); Op3("mul", cs, c, sp, FALSE);
  2681. NewTemp(jw); Op3("sub", jw, j, cs, FALSE);
  2682. Cpy(j, jw)
  2683. END;
  2684. NewTemp(ok1); Op3("csgew", ok1, j, "0", FALSE);
  2685. NewTemp(ok2); Op3("cslew", ok2, j, hi, FALSE);
  2686. NewTemp(ok); Op3("and", ok, ok1, ok2, FALSE);
  2687. (* a dropped bit must still address a *valid* word: clamp the index
  2688. to 0 when out of range, so the load below cannot fault (the store
  2689. is already masked to a no-op by ok via mm3) *)
  2690. NewTemp(sj); Op3("mul", sj, j, ok, FALSE);
  2691. NewTemp(wj); Op3("shr", wj, sj, "5", FALSE);
  2692. NewTemp(bj); Op3("and", bj, sj, "31", FALSE);
  2693. WidenIndex(wj, wjl);
  2694. NewTemp(o2); Op3L("mul", o2, wjl, "4");
  2695. NewTemp(wb2); Op3L("add", wb2, out, o2);
  2696. NewTemp(mm); Op3("shl", mm, "1", bj, FALSE);
  2697. NewTemp(mm2); Op3("mul", mm2, mm, nzb, FALSE);
  2698. NewTemp(mm3); Op3("mul", mm3, mm2, ok, FALSE);
  2699. NewTemp(wcur); W(" "); W(wcur); W(" =w loadw "); WL(wb2);
  2700. NewTemp(wn); Op3("or", wn, wcur, mm3, FALSE);
  2701. Revive;
  2702. W(" storew "); W(wn); W(", "); WL(wb2);
  2703. Op3("add", i, i, "1", FALSE);
  2704. Jmp(ltop);
  2705. EmitLabel(lend);
  2706. Cpy(q, out)
  2707. END SetShift;
  2708. PROCEDURE SetRange (addr: ARRAY OF CHAR; a: ARRAY OF CHAR;
  2709. b: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  2710. VAR al, bl, hiS: QVal;
  2711. cur, c: QVal;
  2712. ltop, lbody, lend: QVal;
  2713. BEGIN
  2714. WidenIndex(a, al);
  2715. WidenIndex(b, bl);
  2716. IntStr(VAL(INTEGER, span) - 1, hiS);
  2717. CheckRange(al, "0", hiS);
  2718. CheckRange(bl, "0", hiS);
  2719. NewTemp(cur);
  2720. Op3("add", cur, a, "0", FALSE);
  2721. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  2722. EmitLabel(ltop);
  2723. NewTemp(c);
  2724. Op3("cslew", c, cur, b, FALSE);
  2725. Jnz(c, lbody, lend);
  2726. EmitLabel(lbody);
  2727. SetBit(addr, cur, lo, span);
  2728. Op3("add", cur, cur, "1", FALSE);
  2729. Jmp(ltop);
  2730. EmitLabel(lend)
  2731. END SetRange;
  2732. PROCEDURE SetBinOp (sel: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  2733. lw, rw: CARDINAL; VAR q: QVal);
  2734. (* Union/intersection/difference/symdiff over possibly different
  2735. spans: overlap via op, larger-side extras copied (union/symdiff/
  2736. left-diff) or zeroed. Result has max words. *)
  2737. VAR i, m, res: CARDINAL;
  2738. la, ra, ta, a, b, c, nb, z: QVal;
  2739. BEGIN
  2740. m := lw;
  2741. IF rw < m THEN m := rw END;
  2742. res := lw;
  2743. IF rw > res THEN res := rw END;
  2744. NewSetTemp(res, q);
  2745. NewTemp(z);
  2746. Op3("xor", z, "0", "0", FALSE);
  2747. i := 0;
  2748. WHILE i < m DO
  2749. IntStr(VAL(INTEGER, i * 4), nb);
  2750. NewTemp(la); Op3L("add", la, l, nb);
  2751. NewTemp(ra); Op3L("add", ra, r, nb);
  2752. NewTemp(ta); Op3L("add", ta, q, nb);
  2753. NewTemp(a);
  2754. W(" "); W(a); W(" =w loadw "); WL(la);
  2755. NewTemp(b);
  2756. W(" "); W(b); W(" =w loadw "); WL(ra);
  2757. NewTemp(c);
  2758. IF sel = 0 THEN Op3("or", c, a, b, FALSE)
  2759. ELSIF sel = 1 THEN Op3("and", c, a, b, FALSE)
  2760. ELSIF sel = 2 THEN
  2761. NewTemp(nb);
  2762. Op3("xor", nb, b, "-1", FALSE);
  2763. Op3("and", c, a, nb, FALSE)
  2764. ELSE Op3("xor", c, a, b, FALSE)
  2765. END;
  2766. Revive;
  2767. W(" storew "); W(c); W(", "); WL(ta);
  2768. INC(i)
  2769. END;
  2770. WHILE i < lw DO
  2771. IntStr(VAL(INTEGER, i * 4), nb);
  2772. NewTemp(la); Op3L("add", la, l, nb);
  2773. NewTemp(ta); Op3L("add", ta, q, nb);
  2774. IF (sel = 0) OR (sel = 2) OR (sel = 3) THEN
  2775. NewTemp(a);
  2776. W(" "); W(a); W(" =w loadw "); WL(la);
  2777. Revive;
  2778. W(" storew "); W(a); W(", "); WL(ta)
  2779. ELSE
  2780. Revive;
  2781. W(" storew "); W(z); W(", "); WL(ta)
  2782. END;
  2783. INC(i)
  2784. END;
  2785. WHILE i < rw DO
  2786. IntStr(VAL(INTEGER, i * 4), nb);
  2787. NewTemp(ra); Op3L("add", ra, r, nb);
  2788. NewTemp(ta); Op3L("add", ta, q, nb);
  2789. IF (sel = 0) OR (sel = 3) THEN
  2790. NewTemp(b);
  2791. W(" "); W(b); W(" =w loadw "); WL(ra);
  2792. Revive;
  2793. W(" storew "); W(b); W(", "); WL(ta)
  2794. ELSE
  2795. Revive;
  2796. W(" storew "); W(z); W(", "); WL(ta)
  2797. END;
  2798. INC(i)
  2799. END
  2800. END SetBinOp;
  2801. PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  2802. lw, rw: CARDINAL; VAR q: QVal);
  2803. VAR i, m: CARDINAL;
  2804. la, ra, a, b, c, acc, nb: QVal;
  2805. BEGIN
  2806. NewTemp(acc);
  2807. Op3("xor", acc, "1", "0", FALSE);
  2808. m := lw;
  2809. IF rw < m THEN m := rw END;
  2810. i := 0;
  2811. WHILE i < m DO
  2812. IntStr(VAL(INTEGER, i * 4), nb);
  2813. NewTemp(la); Op3L("add", la, l, nb);
  2814. NewTemp(ra); Op3L("add", ra, r, nb);
  2815. NewTemp(a);
  2816. W(" "); W(a); W(" =w loadw "); WL(la);
  2817. NewTemp(b);
  2818. W(" "); W(b); W(" =w loadw "); WL(ra);
  2819. NewTemp(c);
  2820. Op3("ceqw", c, a, b, FALSE);
  2821. NewTemp(q);
  2822. Op3("and", q, acc, c, FALSE);
  2823. CopyOp(q, acc);
  2824. INC(i)
  2825. END;
  2826. WHILE i < lw DO
  2827. IntStr(VAL(INTEGER, i * 4), nb);
  2828. NewTemp(la); Op3L("add", la, l, nb);
  2829. NewTemp(a);
  2830. W(" "); W(a); W(" =w loadw "); WL(la);
  2831. NewTemp(c);
  2832. Op3("ceqw", c, a, "0", FALSE);
  2833. NewTemp(q);
  2834. Op3("and", q, acc, c, FALSE);
  2835. CopyOp(q, acc);
  2836. INC(i)
  2837. END;
  2838. WHILE i < rw DO
  2839. IntStr(VAL(INTEGER, i * 4), nb);
  2840. NewTemp(ra); Op3L("add", ra, r, nb);
  2841. NewTemp(b);
  2842. W(" "); W(b); W(" =w loadw "); WL(ra);
  2843. NewTemp(c);
  2844. Op3("ceqw", c, b, "0", FALSE);
  2845. NewTemp(q);
  2846. Op3("and", q, acc, c, FALSE);
  2847. CopyOp(q, acc);
  2848. INC(i)
  2849. END;
  2850. IF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
  2851. NewTemp(q);
  2852. Op3("xor", q, acc, "1", FALSE)
  2853. ELSE
  2854. CopyOp(acc, q)
  2855. END
  2856. END CmpSet;
  2857. PROCEDURE LoadPacked (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  2858. VAR nb: CARDINAL;
  2859. BEGIN
  2860. nb := SymTab.SetBytes(t);
  2861. NewTemp(q);
  2862. Revive;
  2863. W(" "); W(q);
  2864. IF nb = 1 THEN W(" =w loadub ")
  2865. ELSIF nb = 2 THEN W(" =w loaduh ")
  2866. ELSE W(" =w loadw ")
  2867. END;
  2868. WL(addr)
  2869. END LoadPacked;
  2870. PROCEDURE StorePacked (addr: ARRAY OF CHAR; t: INTEGER;
  2871. v: ARRAY OF CHAR);
  2872. VAR nb: CARDINAL;
  2873. BEGIN
  2874. nb := SymTab.SetBytes(t);
  2875. Revive;
  2876. IF nb = 1 THEN W(" storeb ")
  2877. ELSIF nb = 2 THEN W(" storeh ")
  2878. ELSE W(" storew ")
  2879. END;
  2880. W(v); W(", "); WL(addr)
  2881. END StorePacked;
  2882. PROCEDURE CopySetVal (dst: ARRAY OF CHAR; dt: INTEGER;
  2883. src: ARRAY OF CHAR; et: INTEGER);
  2884. VAR q: QVal;
  2885. BEGIN
  2886. IF SymTab.IsPackedSet(dt) THEN
  2887. IF SymTab.IsPackedSet(et) THEN LoadPacked(src, et, q)
  2888. ELSE LoadW(src, q)
  2889. END;
  2890. StorePacked(dst, dt, q)
  2891. ELSIF SymTab.IsPackedSet(et) THEN
  2892. SetZero(dst, SymTab.SetWords(dt));
  2893. LoadPacked(src, et, q);
  2894. StoreW(dst, q)
  2895. ELSE CopySet(dst, src, SymTab.SetWords(dt), SymTab.SetWords(et))
  2896. END
  2897. END CopySetVal;
  2898. PROCEDURE PackedSetBit (addr: ARRAY OF CHAR; t: INTEGER;
  2899. val: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  2900. VAR off, offL, hiS, loS, m, old, nv: QVal;
  2901. BEGIN
  2902. NewTemp(off);
  2903. IntStr(lo, loS);
  2904. Op3("sub", off, val, loS, FALSE);
  2905. WidenIndex(off, offL);
  2906. IntStr(VAL(INTEGER, span) - 1, hiS);
  2907. CheckRange(offL, "0", hiS);
  2908. NewTemp(m);
  2909. Op3("shl", m, "1", off, FALSE);
  2910. LoadPacked(addr, t, old);
  2911. NewTemp(nv);
  2912. Op3("or", nv, old, m, FALSE);
  2913. StorePacked(addr, t, nv)
  2914. END PackedSetBit;
  2915. PROCEDURE PackedSetClearBit (addr: ARRAY OF CHAR; t: INTEGER;
  2916. val: ARRAY OF CHAR; lo: INTEGER;
  2917. span: CARDINAL);
  2918. VAR off, offL, hiS, loS, m, nm, old, nv: QVal;
  2919. BEGIN
  2920. NewTemp(off);
  2921. IntStr(lo, loS);
  2922. Op3("sub", off, val, loS, FALSE);
  2923. WidenIndex(off, offL);
  2924. IntStr(VAL(INTEGER, span) - 1, hiS);
  2925. CheckRange(offL, "0", hiS);
  2926. NewTemp(m);
  2927. Op3("shl", m, "1", off, FALSE);
  2928. NewTemp(nm);
  2929. Op3("xor", nm, m, "-1", FALSE);
  2930. LoadPacked(addr, t, old);
  2931. NewTemp(nv);
  2932. Op3("and", nv, old, nm, FALSE);
  2933. StorePacked(addr, t, nv)
  2934. END PackedSetClearBit;
  2935. PROCEDURE PackedInSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR;
  2936. lo: INTEGER; span: CARDINAL; t: INTEGER;
  2937. VAR q: QVal);
  2938. VAR off, offL, hiS, loS, word, sh, bit: QVal;
  2939. BEGIN
  2940. NewTemp(off);
  2941. IntStr(lo, loS);
  2942. Op3("sub", off, x, loS, FALSE);
  2943. WidenIndex(off, offL);
  2944. IntStr(VAL(INTEGER, span) - 1, hiS);
  2945. CheckRange(offL, "0", hiS);
  2946. LoadPacked(s, t, word);
  2947. NewTemp(sh);
  2948. Op3("shr", sh, word, off, FALSE);
  2949. NewTemp(bit);
  2950. Op3("and", bit, sh, "1", FALSE);
  2951. Cmp(SymTab.OpNeq1, bit, "0", q, FALSE)
  2952. END PackedInSet;
  2953. PROCEDURE PackedCmpSet (op: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
  2954. r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
  2955. VAR q1, q2: QVal;
  2956. BEGIN
  2957. IF SymTab.IsPackedSet(lt) THEN LoadPacked(l, lt, q1)
  2958. ELSE LoadW(l, q1)
  2959. END;
  2960. IF SymTab.IsPackedSet(rt) THEN LoadPacked(r, rt, q2)
  2961. ELSE LoadW(r, q2)
  2962. END;
  2963. Cmp(op, q1, q2, q, FALSE)
  2964. END PackedCmpSet;
  2965. PROCEDURE PackedSetBinOp (sel: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
  2966. r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
  2967. VAR tl, tr, w: QVal;
  2968. BEGIN
  2969. NewSetTemp(1, tl); NewSetTemp(1, tr);
  2970. IF SymTab.IsPackedSet(lt) THEN LoadPacked(l, lt, w)
  2971. ELSE LoadW(l, w)
  2972. END;
  2973. StoreW(tl, w);
  2974. IF SymTab.IsPackedSet(rt) THEN LoadPacked(r, rt, w)
  2975. ELSE LoadW(r, w)
  2976. END;
  2977. StoreW(tr, w);
  2978. SetBinOp(sel, tl, tr, 1, 1, q)
  2979. END PackedSetBinOp;
  2980. PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  2981. dw, sw: CARDINAL);
  2982. (* Copies min words via memcpy, zero-fills dst extras. Src extras
  2983. beyond dst must be zero (trap) — otherwise out-of-span bits
  2984. would vanish silently on narrowing assignment. *)
  2985. VAR m, i: CARDINAL;
  2986. n, da, sa, a, z, off, c: QVal;
  2987. qr, acc, lok, lbad: QVal;
  2988. BEGIN
  2989. m := dw;
  2990. IF sw < m THEN m := sw END;
  2991. IF sw > dw THEN
  2992. NewTemp(acc);
  2993. Op3("xor", acc, "1", "0", FALSE);
  2994. i := dw;
  2995. WHILE i < sw DO
  2996. IntStr(VAL(INTEGER, i * 4), off);
  2997. NewTemp(a); Op3L("add", a, src, off);
  2998. NewTemp(c);
  2999. W(" "); W(c); W(" =w loadw "); WL(a);
  3000. NewTemp(qr);
  3001. Op3("ceqw", qr, c, "0", FALSE);
  3002. NewTemp(c);
  3003. Op3("and", c, acc, qr, FALSE);
  3004. CopyOp(c, acc);
  3005. INC(i)
  3006. END;
  3007. NewLabel(lok); NewLabel(lbad);
  3008. Jnz(acc, lok, lbad);
  3009. EmitLabel(lbad);
  3010. Trap;
  3011. EmitLabel(lok)
  3012. END;
  3013. IF m > 0 THEN
  3014. IntStr(VAL(INTEGER, m * 4), n);
  3015. NewTemp(qr);
  3016. W(" "); W(qr); W(" =l call $memcpy(l ");
  3017. W(dst); W(", l "); W(src); W(", l "); W(n); WL(")")
  3018. END;
  3019. NewTemp(z);
  3020. Op3("xor", z, "0", "0", FALSE);
  3021. i := m;
  3022. WHILE i < dw DO
  3023. NewTemp(a);
  3024. IntStr(VAL(INTEGER, i * 4), off);
  3025. Op3L("add", a, dst, off);
  3026. Revive;
  3027. W(" storew "); W(z); W(", "); WL(a);
  3028. INC(i)
  3029. END
  3030. END CopySet;
  3031. PROCEDURE InSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR; lo: INTEGER;
  3032. span: CARDINAL; VAR q: QVal);
  3033. (* Membership bit test with span trap; q is fresh w 0/1. *)
  3034. VAR off, offL, hiS, loS: QVal;
  3035. wi, bi, wil, off4, wa, wcur, m, a: QVal;
  3036. spanS: QVal;
  3037. BEGIN
  3038. NewTemp(off);
  3039. IntStr(lo, loS);
  3040. Op3("sub", off, x, loS, FALSE);
  3041. WidenIndex(off, offL);
  3042. IntStr(VAL(INTEGER, span) - 1, spanS);
  3043. CheckRange(offL, "0", spanS);
  3044. NewTemp(wi);
  3045. Op3("shr", wi, off, "5", FALSE);
  3046. NewTemp(bi);
  3047. Op3("and", bi, off, "31", FALSE);
  3048. WidenIndex(wi, wil);
  3049. NewTemp(off4);
  3050. Op3L("mul", off4, wil, "4");
  3051. NewTemp(wa);
  3052. Op3L("add", wa, s, off4);
  3053. NewTemp(wcur);
  3054. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  3055. NewTemp(m);
  3056. Op3("shl", m, "1", bi, FALSE);
  3057. NewTemp(a);
  3058. Op3("and", a, wcur, m, FALSE);
  3059. NewTemp(q);
  3060. Op3("cnew", q, a, "0", FALSE)
  3061. END InSet;
  3062. PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
  3063. BEGIN
  3064. IF IsImm(idx) THEN Cpy(q, idx)
  3065. ELSE
  3066. NewTemp(q);
  3067. Revive;
  3068. W(" "); W(q); W(" =l extsw "); WL(idx)
  3069. END
  3070. END WidenIndex;
  3071. PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
  3072. VAR c: QVal;
  3073. BEGIN
  3074. NewTemp(c);
  3075. Revive;
  3076. W(" "); W(c); W(" =l loadl "); WL(base);
  3077. NewTemp(q);
  3078. Op3L("sub", q, c, "1")
  3079. END OpenHi;
  3080. PROCEDURE OpenHiChar (base: ARRAY OF CHAR; VAR q: QVal);
  3081. (* q := loadl(base) — the open-array count, i.e. the index of the NUL
  3082. terminator slot that CHAR arrays reserve. *)
  3083. BEGIN
  3084. NewTemp(q);
  3085. Revive;
  3086. W(" "); W(q); W(" =l loadl "); WL(base)
  3087. END OpenHiChar;
  3088. PROCEDURE LoadCount (base: ARRAY OF CHAR; VAR q: QVal);
  3089. BEGIN
  3090. NewTemp(q);
  3091. Revive;
  3092. W(" "); W(q); W(" =l loadl "); WL(base)
  3093. END LoadCount;
  3094. PROCEDURE CheckCode (idx, lo, hi: ARRAY OF CHAR; code: CARDINAL);
  3095. (* l-domain operands (widened index, immediates, or open hi temp);
  3096. comparisons are long (result w). *)
  3097. VAR c1, c2, c: QVal;
  3098. lok, lbad: QVal;
  3099. BEGIN
  3100. NewTemp(c1);
  3101. Op3("csgel", c1, idx, lo, FALSE);
  3102. NewTemp(c2);
  3103. Op3("cslel", c2, idx, hi, FALSE);
  3104. NewTemp(c);
  3105. Op3("and", c, c1, c2, FALSE);
  3106. NewLabel(lok); NewLabel(lbad);
  3107. Jnz(c, lok, lbad);
  3108. EmitLabel(lbad);
  3109. TrapCode(code);
  3110. EmitLabel(lok)
  3111. END CheckCode;
  3112. PROCEDURE CheckRange (idx, lo, hi: ARRAY OF CHAR);
  3113. BEGIN
  3114. CheckCode(idx, lo, hi, 1) (* rangeException *)
  3115. END CheckRange;
  3116. PROCEDURE CheckIndex (idx, lo, hi: ARRAY OF CHAR);
  3117. BEGIN
  3118. CheckCode(idx, lo, hi, 0) (* indexException *)
  3119. END CheckIndex;
  3120. PROCEDURE ElemAddr (base, idx, lo: ARRAY OF CHAR; elemT: INTEGER;
  3121. VAR q: QVal);
  3122. (* q := base + 8 + (idx - lo) * elemSize in l, fresh temp.
  3123. elemT is the array descriptor (open or fixed); all operands
  3124. l-domain (immediates pass, temps pre-widened). *)
  3125. VAR t1, t2, tb, sb: QVal;
  3126. BEGIN
  3127. NewTemp(t1);
  3128. Op3L("sub", t1, idx, lo);
  3129. IntStr(VAL(INTEGER, ElemSize(elemT)), sb);
  3130. NewTemp(t2);
  3131. Op3L("mul", t2, t1, sb);
  3132. NewTemp(tb);
  3133. Op3L("add", tb, base, "8");
  3134. NewTemp(q);
  3135. Op3L("add", q, tb, t2)
  3136. END ElemAddr;
  3137. PROCEDURE ViewField (view: ARRAY OF CHAR; off: CARDINAL; VAR q: QVal);
  3138. (* q := loadl(view + off), off one of 0,8,16,24,32. *)
  3139. VAR a, s: QVal;
  3140. BEGIN
  3141. NewTemp(a);
  3142. IntStr(VAL(INTEGER, off), s);
  3143. Op3L("add", a, view, s);
  3144. NewTemp(q);
  3145. Revive;
  3146. W(" "); W(q); W(" =l loadl "); WL(a)
  3147. END ViewField;
  3148. PROCEDURE ViewIndex (view, idx, lo: ARRAY OF CHAR;
  3149. nextIsArray: BOOLEAN; VAR q: QVal);
  3150. VAR t1, stride, off, base, addr, nv, next, tmp: QVal;
  3151. BEGIN
  3152. NewTemp(t1);
  3153. Op3L("sub", t1, idx, lo);
  3154. ViewField(view, 16, stride);
  3155. NewTemp(off);
  3156. Op3L("mul", off, t1, stride);
  3157. ViewField(view, 24, base);
  3158. NewTemp(addr);
  3159. Op3L("add", addr, base, off);
  3160. IF NOT nextIsArray THEN
  3161. CopyOp(addr, q)
  3162. ELSE
  3163. ViewField(view, 32, next);
  3164. NewTemp(nv);
  3165. Revive;
  3166. W(" "); W(nv); WL(" =l alloc8 40");
  3167. (* copy count, elemBytes, stride and next from the template *)
  3168. ViewField(next, 0, tmp);
  3169. Revive; W(" storel "); W(tmp); W(", "); WL(nv);
  3170. IntStr(8, off);
  3171. NewTemp(t1); Op3L("add", t1, nv, off);
  3172. ViewField(next, 8, tmp);
  3173. Revive; W(" storel "); W(tmp); W(", "); WL(t1);
  3174. IntStr(16, off);
  3175. NewTemp(t1); Op3L("add", t1, nv, off);
  3176. ViewField(next, 16, tmp);
  3177. Revive; W(" storel "); W(tmp); W(", "); WL(t1);
  3178. IntStr(32, off);
  3179. NewTemp(t1); Op3L("add", t1, nv, off);
  3180. ViewField(next, 32, tmp);
  3181. Revive; W(" storel "); W(tmp); W(", "); WL(t1);
  3182. IntStr(24, off);
  3183. NewTemp(t1); Op3L("add", t1, nv, off);
  3184. Revive; W(" storel "); W(addr); W(", "); WL(t1);
  3185. CopyOp(nv, q)
  3186. END
  3187. END ViewIndex;
  3188. PROCEDURE MakeFieldView (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  3189. VAR rank, k, count, stride: CARDINAL;
  3190. cur: SymTab.TypeIndex;
  3191. v, a, nb, off: QVal;
  3192. BEGIN
  3193. rank := SymTab.ArrayDepth(t);
  3194. IF rank <= 1 THEN CopyOp(addr, q); RETURN END;
  3195. IntStr(VAL(INTEGER, rank * 40), nb);
  3196. NewTemp(q);
  3197. Revive;
  3198. W(" "); W(q); W(" =l alloc8 "); WL(nb);
  3199. cur := t; k := 0;
  3200. WHILE k < rank DO
  3201. IntStr(VAL(INTEGER, k * 40), off);
  3202. NewTemp(v); Op3L("add", v, q, off);
  3203. count := SymTab.ArrayLen(cur);
  3204. stride := SymTab.ArrayStride(t, k);
  3205. IntStr(VAL(INTEGER, count), nb);
  3206. Revive; W(" storel "); W(nb); W(", "); WL(v);
  3207. IntStr(VAL(INTEGER, stride), nb);
  3208. NewTemp(a); Op3L("add", a, v, "8");
  3209. Revive; W(" storel "); W(nb); W(", "); WL(a);
  3210. NewTemp(a); Op3L("add", a, v, "16");
  3211. Revive; W(" storel "); W(nb); W(", "); WL(a);
  3212. IF k = 0 THEN
  3213. NewTemp(a); Op3L("add", a, v, "24");
  3214. Revive; W(" storel "); W(addr); W(", "); WL(a)
  3215. ELSE
  3216. NewTemp(a); Op3L("add", a, v, "24");
  3217. Revive; W(" storel 0, "); WL(a)
  3218. END;
  3219. IF k + 1 < rank THEN
  3220. NewTemp(a); Op3L("add", a, v, "32");
  3221. IntStr(VAL(INTEGER, (k + 1) * 40), off);
  3222. NewTemp(nb); Op3L("add", nb, q, off);
  3223. Revive; W(" storel "); W(nb); W(", "); WL(a)
  3224. ELSE
  3225. NewTemp(a); Op3L("add", a, v, "32");
  3226. Revive; W(" storel 0, "); WL(a)
  3227. END;
  3228. cur := SymTab.ArrayElem(cur);
  3229. INC(k)
  3230. END
  3231. END MakeFieldView;
  3232. PROCEDURE ViewToOpen1D (view: ARRAY OF CHAR; ft: INTEGER;
  3233. VAR q, base, nbytes: QVal);
  3234. VAR count, elem, total, n, desc, p, p2, eoff: QVal;
  3235. cls, extra: INTEGER;
  3236. BEGIN
  3237. ViewField(view, 0, count);
  3238. ViewField(view, 8, elem);
  3239. NewTemp(total);
  3240. Op3L("mul", total, count, elem);
  3241. cls := SymTab.ClassOf(SymTab.ArrayElem(ft));
  3242. IF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  3243. CopyOp(total, count)
  3244. END;
  3245. extra := 0;
  3246. IF cls = SymTab.ClChar THEN extra := 1
  3247. ELSIF cls = SymTab.ClUChar THEN extra := 4
  3248. END;
  3249. NewTemp(n);
  3250. Op3L("add", n, total, "8");
  3251. IF extra > 0 THEN
  3252. IntStr(VAL(INTEGER, extra), eoff);
  3253. NewTemp(p); Op3L("add", p, n, eoff); CopyOp(p, n)
  3254. END;
  3255. NewTemp(desc);
  3256. W(" "); W(desc); W(" =l call $malloc(l "); W(n); WL(")");
  3257. Revive;
  3258. W(" storel "); W(count); W(", "); WL(desc);
  3259. ViewField(view, 24, base);
  3260. CopyOp(total, nbytes);
  3261. NewTemp(p);
  3262. Op3L("add", p, desc, "8");
  3263. Revive;
  3264. W(" "); W(n); W(" =l call $memcpy(l ");
  3265. W(p); W(", l "); W(base); W(", l "); W(total); WL(")");
  3266. IF extra > 0 THEN
  3267. NewTemp(p); Op3L("add", p, desc, "8");
  3268. NewTemp(p2); Op3L("add", p2, p, total);
  3269. Revive;
  3270. IF extra = 1 THEN W(" storeb 0, "); WL(p2)
  3271. ELSE W(" storew 0, "); WL(p2) END
  3272. END;
  3273. CopyOp(desc, q)
  3274. END ViewToOpen1D;
  3275. PROCEDURE ViewCopyBack (desc, base, nbytes: ARRAY OF CHAR);
  3276. VAR p, r: QVal;
  3277. BEGIN
  3278. NewTemp(p);
  3279. Op3L("add", p, desc, "8");
  3280. NewTemp(r);
  3281. W(" "); W(r); W(" =l call $memcpy(l ");
  3282. W(base); W(", l "); W(p); W(", l "); W(nbytes); WL(")")
  3283. END ViewCopyBack;
  3284. PROCEDURE ViewFree (desc: ARRAY OF CHAR);
  3285. BEGIN
  3286. Revive;
  3287. W(" call $free(l "); W(desc); WL(")")
  3288. END ViewFree;
  3289. PROCEDURE ViewBase (view: ARRAY OF CHAR; VAR q: QVal);
  3290. BEGIN
  3291. ViewField(view, 24, q)
  3292. END ViewBase;
  3293. PROCEDURE ViewSize (view: ARRAY OF CHAR; VAR q: QVal);
  3294. VAR cnt, esz, r: QVal;
  3295. BEGIN
  3296. ViewField(view, 0, cnt);
  3297. ViewField(view, 8, esz);
  3298. NewTemp(r);
  3299. Op3L("mul", r, cnt, esz);
  3300. CopyOp(r, q)
  3301. END ViewSize;
  3302. PROCEDURE DescData (desc: ARRAY OF CHAR; VAR q: QVal);
  3303. BEGIN
  3304. NewTemp(q);
  3305. Op3L("add", q, desc, "8")
  3306. END DescData;
  3307. PROCEDURE OpenSize (desc: ARRAY OF CHAR; ft: INTEGER; VAR q: QVal);
  3308. VAR cnt, esz, r: QVal;
  3309. BEGIN
  3310. NewTemp(q);
  3311. Revive;
  3312. W(" "); W(q); W(" =l loadl "); WL(desc);
  3313. IntStr(VAL(INTEGER, SymTab.ArrayLeafBytes(ft)), esz);
  3314. NewTemp(r);
  3315. Op3L("mul", r, q, esz);
  3316. CopyOp(r, q)
  3317. END OpenSize;
  3318. PROCEDURE ElemLoad (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  3319. (* Loads one element of (element-)type t. Nested/pointer elements
  3320. are addresses (loadl). *)
  3321. VAR cls: INTEGER;
  3322. BEGIN
  3323. cls := SymTab.ClassOf(t);
  3324. NewTemp(q);
  3325. Revive;
  3326. W(" "); W(q);
  3327. IF cls = SymTab.ClReal THEN W(" =d loadd ")
  3328. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr)
  3329. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClProc)
  3330. OR (cls = SymTab.ClClass) THEN
  3331. W(" =l loadl ")
  3332. ELSIF cls = SymTab.ClChar THEN W(" =w loadub ")
  3333. ELSIF cls = SymTab.ClSet THEN
  3334. IF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 1) THEN
  3335. W(" =w loadub ")
  3336. ELSIF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 2) THEN
  3337. W(" =w loaduh ")
  3338. ELSE W(" =w loadw ")
  3339. END
  3340. ELSIF cls = SymTab.ClByte THEN W(" =w loadub ")
  3341. ELSIF cls = SymTab.ClSByte THEN W(" =w loadsb ")
  3342. ELSIF cls = SymTab.ClWord16 THEN W(" =w loaduh ")
  3343. ELSIF cls = SymTab.ClSWord16 THEN W(" =w loadsh ")
  3344. ELSE W(" =w loadw ")
  3345. END;
  3346. WL(addr)
  3347. END ElemLoad;
  3348. PROCEDURE ElemStore (addr, v: ARRAY OF CHAR; t: INTEGER);
  3349. VAR cls: INTEGER;
  3350. BEGIN
  3351. cls := SymTab.ClassOf(t);
  3352. Revive;
  3353. IF cls = SymTab.ClReal THEN W(" stored ")
  3354. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr)
  3355. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClProc)
  3356. OR (cls = SymTab.ClClass) THEN
  3357. W(" storel ")
  3358. ELSIF cls = SymTab.ClChar THEN W(" storeb ")
  3359. ELSIF cls = SymTab.ClSet THEN
  3360. IF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 1) THEN
  3361. W(" storeb ")
  3362. ELSIF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 2) THEN
  3363. W(" storeh ")
  3364. ELSE W(" storew ")
  3365. END
  3366. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN W(" storeb ")
  3367. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN W(" storeh ")
  3368. ELSE W(" storew ")
  3369. END;
  3370. W(v); W(", "); WL(addr)
  3371. END ElemStore;
  3372. PROCEDURE CopyOldNestedToView (dst, src: ARRAY OF CHAR;
  3373. t: INTEGER; rank: CARDINAL);
  3374. (* Adapt an old nested-descriptor constructor (e.g. names{"Thu","Fri"})
  3375. into a flat multi-dimensional view payload. Only static constructor
  3376. sources use this path. *)
  3377. VAR count, base, esz, row, a, off, off2, child, i, c: QVal;
  3378. ltop, lbody, lend: QVal;
  3379. BEGIN
  3380. IF rank <= 1 THEN
  3381. ViewField(dst, 24, base);
  3382. ViewField(dst, 0, count);
  3383. ViewField(dst, 8, esz);
  3384. NewTemp(a);
  3385. Op3L("mul", a, count, esz);
  3386. NewTemp(off); Op3L("add", off, src, "8");
  3387. NewTemp(c);
  3388. W(" "); W(c); W(" =l call $memcpy(l ");
  3389. W(base); W(", l "); W(off); W(", l "); W(a); WL(")")
  3390. ELSE
  3391. ViewField(dst, 0, count);
  3392. NewTemp(i);
  3393. W(" "); W(i); W(" =l copy 0"); WL("");
  3394. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  3395. EmitLabel(ltop);
  3396. NewTemp(c); Op3("csltl", c, i, count, FALSE);
  3397. Jnz(c, lbody, lend);
  3398. EmitLabel(lbody);
  3399. ViewIndex(dst, i, "0", TRUE, row);
  3400. NewTemp(off); Op3L("mul", off, i, "8");
  3401. NewTemp(a); Op3L("add", a, src, "8");
  3402. NewTemp(off2); Op3L("add", off2, a, off);
  3403. NewTemp(child); W(" "); W(child); W(" =l loadl "); WL(off2);
  3404. CopyOldNestedToView(row, child, SymTab.ArrayElem(t), rank - 1);
  3405. Op3L("add", i, i, "1");
  3406. Jmp(ltop);
  3407. EmitLabel(lend)
  3408. END
  3409. END CopyOldNestedToView;
  3410. PROCEDURE CopyArray (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  3411. t: INTEGER);
  3412. (* Whole-array copy with runtime count check + blit. Nested levels
  3413. recurse through a runtime loop; counts mismatch traps. dst/src
  3414. are descriptor address operands; t is the destination type. *)
  3415. VAR dc, sc, ok: QVal;
  3416. lok, lbad: QVal;
  3417. ecls: INTEGER;
  3418. n, da, sa: QVal;
  3419. sb: QVal;
  3420. qr: QVal;
  3421. i, c, de, se, di, si, dd0, doff, sd0, soff: QVal;
  3422. ltop, lbody, lend: QVal;
  3423. BEGIN
  3424. IF SymTab.IsMultiArray(t) THEN
  3425. IF (src[0] = "$") AND (src[1] = "c") AND (src[2] = "t")
  3426. AND (src[3] = "o") THEN
  3427. CopyOldNestedToView(dst, src, t, SymTab.ArrayDepth(t))
  3428. ELSE
  3429. (* src/dst are ArrayView pointers; copy the flat payload only. *)
  3430. ViewField(dst, 24, da);
  3431. ViewField(src, 24, sa);
  3432. ViewField(dst, 0, n);
  3433. ViewField(dst, 8, sb);
  3434. NewTemp(qr);
  3435. Op3L("mul", qr, n, sb);
  3436. NewTemp(n);
  3437. W(" "); W(n); W(" =l call $memcpy(l ");
  3438. W(da); W(", l "); W(sa); W(", l "); W(qr); WL(")")
  3439. END;
  3440. RETURN
  3441. END;
  3442. NewTemp(dc);
  3443. Revive;
  3444. W(" "); W(dc); W(" =l loadl "); WL(dst);
  3445. NewTemp(sc);
  3446. W(" "); W(sc); W(" =l loadl "); WL(src);
  3447. NewTemp(ok);
  3448. Op3("ceql", ok, dc, sc, FALSE);
  3449. NewLabel(lok); NewLabel(lbad);
  3450. Jnz(ok, lok, lbad);
  3451. EmitLabel(lbad);
  3452. Trap;
  3453. EmitLabel(lok);
  3454. ecls := ElemCls(t);
  3455. IF (ecls = SymTab.ClArray) THEN
  3456. NewTemp(i);
  3457. W(" "); W(i); W(" =l copy 0"); WL("");
  3458. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  3459. EmitLabel(ltop);
  3460. NewTemp(c);
  3461. Op3("csltl", c, i, dc, FALSE);
  3462. Jnz(c, lbody, lend);
  3463. EmitLabel(lbody);
  3464. NewTemp(dd0); Op3L("add", dd0, dst, "8");
  3465. NewTemp(doff); Op3L("mul", doff, i, "8");
  3466. NewTemp(de); Op3L("add", de, dd0, doff);
  3467. NewTemp(sd0); Op3L("add", sd0, src, "8");
  3468. NewTemp(soff); Op3L("mul", soff, i, "8");
  3469. NewTemp(se); Op3L("add", se, sd0, soff);
  3470. NewTemp(di);
  3471. W(" "); W(di); W(" =l loadl "); WL(de);
  3472. NewTemp(si);
  3473. W(" "); W(si); W(" =l loadl "); WL(se);
  3474. CopyArray(di, si, SymTab.ArrayElem(t));
  3475. Op3L("add", i, i, "1");
  3476. Jmp(ltop);
  3477. EmitLabel(lend)
  3478. ELSE
  3479. IntStr(VAL(INTEGER, ElemSize(t)), sb);
  3480. NewTemp(n);
  3481. Op3L("mul", n, dc, sb);
  3482. NewTemp(da);
  3483. Op3L("add", da, dst, "8");
  3484. NewTemp(sa);
  3485. Op3L("add", sa, src, "8");
  3486. NewTemp(qr);
  3487. W(" "); W(qr); W(" =l call $memcpy(l ");
  3488. W(da); W(", l "); W(sa); W(", l "); W(n); WL(")")
  3489. END
  3490. END CopyArray;
  3491. PROCEDURE CopyArrayEx (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  3492. t: INTEGER; dstIsView, srcIsView: BOOLEAN);
  3493. VAR db, dc, de, sb, sc, se, total, srcData, dstData, r: QVal;
  3494. BEGIN
  3495. IF SymTab.IsMultiArray(t) THEN
  3496. CopyArray(dst, src, t); RETURN
  3497. END;
  3498. IF dstIsView THEN
  3499. ViewField(dst, 24, db);
  3500. ViewField(dst, 0, dc);
  3501. ViewField(dst, 8, de);
  3502. NewTemp(total); Op3L("mul", total, dc, de);
  3503. IF srcIsView THEN
  3504. ViewField(src, 24, sb)
  3505. ELSE
  3506. NewTemp(srcData); Op3L("add", srcData, src, "8"); CopyOp(srcData, sb)
  3507. END;
  3508. NewTemp(r);
  3509. W(" "); W(r); W(" =l call $memcpy(l ");
  3510. W(db); W(", l "); W(sb); W(", l "); W(total); WL(")")
  3511. ELSIF srcIsView THEN
  3512. ViewField(src, 24, sb);
  3513. ViewField(src, 0, sc);
  3514. ViewField(src, 8, se);
  3515. NewTemp(total); Op3L("mul", total, sc, se);
  3516. NewTemp(dstData); Op3L("add", dstData, dst, "8");
  3517. NewTemp(r);
  3518. W(" "); W(r); W(" =l call $memcpy(l ");
  3519. W(dstData); W(", l "); W(sb); W(", l "); W(total); WL(")")
  3520. ELSE
  3521. CopyArray(dst, src, t)
  3522. END
  3523. END CopyArrayEx;
  3524. PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
  3525. (* Records a quoted literal for top-level emission at EndModule and
  3526. returns its address operand ($strN). Data definitions may only
  3527. appear outside functions, but literals occur mid-body. *)
  3528. VAR nm: QVal;
  3529. BEGIN
  3530. Cpy(nm, "str");
  3531. AppNum(nm, nStr);
  3532. IF nStr <= HIGH(strNams) THEN
  3533. Cpy(strNams[nStr], nm);
  3534. Cpy(strTexts[nStr], text);
  3535. INC(nStr)
  3536. END;
  3537. Cpy(q, "$");
  3538. App(q, nm)
  3539. END DeclStr;
  3540. PROCEDURE DeclUStr (text: ARRAY OF CHAR; VAR q: QVal;
  3541. VAR single: BOOLEAN; VAR cp: INTEGER;
  3542. VAR ok: BOOLEAN);
  3543. (* text is the raw lexeme U'...' / U"..." Strict RFC3629-decode the
  3544. bytes between the quotes. Exactly one codepoint -> single:=TRUE,
  3545. cp:=it. Otherwise record a UString descriptor and q := "$ustrN".
  3546. ok:=FALSE for invalid UTF-8 (overlong / surrogate / >10FFFF /
  3547. truncation). *)
  3548. VAR L, i, cnt, base: CARDINAL;
  3549. b0, b1, b2, b3, ch: INTEGER;
  3550. nm: QVal;
  3551. PROCEDURE Cont (VAR b: INTEGER): BOOLEAN;
  3552. (* consume a continuation byte, or fail *)
  3553. BEGIN
  3554. IF i >= L - 1 THEN RETURN FALSE END;
  3555. b := ORD(text[i]); INC(i);
  3556. RETURN (b >= 128) AND (b <= 191)
  3557. END Cont;
  3558. BEGIN
  3559. single := FALSE; cp := 0; ok := TRUE;
  3560. q[0] := "0"; q[1] := CHR(0);
  3561. L := Len(text);
  3562. IF (L < 3) OR (text[0] # "U") THEN ok := FALSE; RETURN END;
  3563. i := 2; cnt := 0; base := ustrUsed;
  3564. WHILE i < L - 1 DO
  3565. b0 := ORD(text[i]); INC(i);
  3566. ch := -1;
  3567. IF b0 <= 127 THEN
  3568. ch := b0
  3569. ELSIF (b0 >= 194) AND (b0 <= 223) THEN
  3570. IF Cont(b1) THEN ch := ((b0 - 192) * 64) + (b1 - 128) END
  3571. ELSIF (b0 >= 224) AND (b0 <= 239) THEN
  3572. IF Cont(b1) AND Cont(b2) THEN
  3573. ch := ((b0 - 224) * 4096) + ((b1 - 128) * 64) + (b2 - 128);
  3574. IF ch < 2048 THEN ch := -1 END
  3575. END
  3576. ELSIF (b0 >= 240) AND (b0 <= 244) THEN
  3577. IF Cont(b1) AND Cont(b2) AND Cont(b3) THEN
  3578. ch := ((b0 - 240) * 262144) + ((b1 - 128) * 4096)
  3579. + ((b2 - 128) * 64) + (b3 - 128);
  3580. IF ch < 65536 THEN ch := -1 END
  3581. END
  3582. ELSE ok := FALSE
  3583. END;
  3584. IF ok AND (ch < 0) THEN ok := FALSE END;
  3585. IF ok AND (ch >= 55296) AND (ch <= 57343) THEN ok := FALSE END;
  3586. IF ok AND (ch > 1114111) THEN ok := FALSE END;
  3587. IF NOT ok THEN RETURN END;
  3588. IF ustrUsed <= HIGH(ustrPool) THEN
  3589. ustrPool[ustrUsed] := ch; INC(ustrUsed)
  3590. END;
  3591. INC(cnt)
  3592. END;
  3593. IF cnt = 1 THEN
  3594. single := TRUE; cp := ustrPool[base]
  3595. ELSE
  3596. Cpy(nm, "ustr"); AppNum(nm, ustrN);
  3597. IF ustrN <= HIGH(ustrNams) THEN
  3598. Cpy(ustrNams[ustrN], nm);
  3599. ustrStart[ustrN] := base; ustrCount[ustrN] := cnt; INC(ustrN)
  3600. END;
  3601. Cpy(q, "$"); App(q, nm)
  3602. END
  3603. END DeclUStr;
  3604. PROCEDURE FlushUStrings;
  3605. VAR k, i: CARDINAL;
  3606. bv: QVal;
  3607. BEGIN
  3608. IF NOT opened THEN RETURN END;
  3609. k := 0;
  3610. WHILE k < ustrN DO
  3611. W("data $"); W(ustrNams[k]); W(" = { l ");
  3612. IntStr(VAL(INTEGER, ustrCount[k]), bv); W(bv);
  3613. i := 0;
  3614. WHILE i < ustrCount[k] DO
  3615. W(", w ");
  3616. IntStr(ustrPool[ustrStart[k] + i], bv); W(bv);
  3617. INC(i)
  3618. END;
  3619. WL(" }");
  3620. INC(k)
  3621. END
  3622. END FlushUStrings;
  3623. PROCEDURE DeclCharStr (ch: ARRAY OF CHAR; VAR q: QVal);
  3624. VAR v: INTEGER;
  3625. txt: ARRAY [0 .. 3] OF CHAR;
  3626. BEGIN
  3627. IF ParseInt(ch, v) AND (v >= 0) AND (v < 256) THEN
  3628. txt[0] := '"'; txt[1] := CHR(v); txt[2] := '"'; txt[3] := CHR(0);
  3629. DeclStr(txt, q)
  3630. ELSE Cpy(q, "0")
  3631. END
  3632. END DeclCharStr;
  3633. PROCEDURE FindStrPos (v: ARRAY OF CHAR; VAR k: CARDINAL): BOOLEAN;
  3634. VAR j: CARDINAL;
  3635. sv: QVal;
  3636. BEGIN
  3637. j := 0;
  3638. WHILE j < nStr DO
  3639. Cpy(sv, "$"); App(sv, strNams[j]);
  3640. IF SymTab.Equal(sv, v) THEN k := j; RETURN TRUE END;
  3641. INC(j)
  3642. END;
  3643. RETURN FALSE
  3644. END FindStrPos;
  3645. PROCEDURE StrLitLen (v: ARRAY OF CHAR; VAR n: INTEGER): BOOLEAN;
  3646. VAR k: CARDINAL;
  3647. BEGIN
  3648. n := 0;
  3649. IF NOT FindStrPos(v, k) THEN RETURN FALSE END;
  3650. n := VAL(INTEGER, SymTab.StrLen(strTexts[k]) - 2);
  3651. RETURN TRUE
  3652. END StrLitLen;
  3653. PROCEDURE StrFold (a, b: ARRAY OF CHAR; clsA, clsB: INTEGER;
  3654. VAR q: QVal; VAR ok: BOOLEAN);
  3655. (* Constant-fold `a + b` into one string literal descriptor. *)
  3656. VAR ka, kb: CARDINAL;
  3657. ta, tb, joined: ARRAY [0 .. 1023] OF CHAR;
  3658. oa, ob, ord: INTEGER;
  3659. i, L: CARDINAL;
  3660. isCharA, isCharB: BOOLEAN;
  3661. PROCEDURE AppendInner (VAR s: ARRAY OF CHAR; txt: ARRAY OF CHAR);
  3662. VAR n: CARDINAL;
  3663. c2: ARRAY [0 .. 1] OF CHAR;
  3664. BEGIN
  3665. n := Len(txt);
  3666. IF n >= 2 THEN
  3667. i := 1;
  3668. WHILE i < n - 1 DO
  3669. c2[0] := txt[i]; c2[1] := CHR(0);
  3670. App(s, c2);
  3671. INC(i)
  3672. END
  3673. END
  3674. END AppendInner;
  3675. BEGIN
  3676. ok := FALSE;
  3677. isCharA := (clsA = SymTab.ClChar) OR (clsA = SymTab.ClEnum)
  3678. OR (clsA = SymTab.ClBool);
  3679. isCharB := (clsB = SymTab.ClChar) OR (clsB = SymTab.ClEnum)
  3680. OR (clsB = SymTab.ClBool);
  3681. IF isCharA THEN
  3682. IF NOT ParseInt(a, oa) THEN RETURN END
  3683. ELSIF NOT FindStrPos(a, ka) THEN RETURN
  3684. END;
  3685. IF isCharB THEN
  3686. IF NOT ParseInt(b, ob) THEN RETURN END
  3687. ELSIF NOT FindStrPos(b, kb) THEN RETURN
  3688. END;
  3689. joined[0] := '"'; joined[1] := CHR(0);
  3690. IF isCharA THEN
  3691. IF (oa < 0) OR (oa > 255) THEN RETURN END;
  3692. joined[1] := CHR(oa); joined[2] := CHR(0)
  3693. ELSE AppendInner(joined, strTexts[ka])
  3694. END;
  3695. IF isCharB THEN
  3696. IF (ob < 0) OR (ob > 255) THEN RETURN END;
  3697. L := Len(joined); joined[L] := CHR(ob); joined[L + 1] := CHR(0)
  3698. ELSE AppendInner(joined, strTexts[kb])
  3699. END;
  3700. L := Len(joined); joined[L] := '"'; joined[L + 1] := CHR(0);
  3701. DeclStr(joined, q);
  3702. ok := TRUE
  3703. END StrFold;
  3704. PROCEDURE FlushStrings;
  3705. (* Emits all recorded string literals as top-level data. *)
  3706. VAR k, i, L: CARDINAL;
  3707. bv: QVal;
  3708. BEGIN
  3709. IF NOT opened THEN RETURN END;
  3710. k := 0;
  3711. WHILE k < nStr DO
  3712. L := Len(strTexts[k]);
  3713. IF L >= 2 THEN
  3714. W("data $"); W(strNams[k]);
  3715. W(" = { l ");
  3716. IntStr(VAL(INTEGER, L - 2), bv);
  3717. W(bv);
  3718. i := 1;
  3719. WHILE i < L - 1 DO
  3720. W(", b ");
  3721. IntStr(ORD(strTexts[k][i]), bv);
  3722. W(bv);
  3723. INC(i)
  3724. END;
  3725. W(", b 0"); (* NUL terminator (count excludes it) *)
  3726. WL(" }")
  3727. END;
  3728. INC(k)
  3729. END
  3730. END FlushStrings;
  3731. PROCEDURE DeclMultiArr (name: ARRAY OF CHAR; t: INTEGER);
  3732. (* Static fixed multi-dimensional array: a chain of view descriptors
  3733. plus one contiguous payload block. One-dimensional arrays still use
  3734. ArrData. *)
  3735. VAR rank, k, count, stride, payload: CARDINAL;
  3736. cur: SymTab.TypeIndex;
  3737. lab, base, nxt, bv, sv, pv: QVal;
  3738. BEGIN
  3739. IF NOT opened THEN RETURN END;
  3740. rank := SymTab.ArrayDepth(t);
  3741. IF rank < 2 THEN ArrData(name, t); RETURN END;
  3742. payload := SymTab.ArrayPayloadSize(t);
  3743. cur := t;
  3744. k := 0;
  3745. WHILE k < rank DO
  3746. count := SymTab.ArrayLen(cur);
  3747. stride := SymTab.ArrayStride(t, k);
  3748. Cpy(lab, name);
  3749. IF k > 0 THEN
  3750. App(lab, "_t"); IntStr(VAL(INTEGER, k), bv); App(lab, bv)
  3751. END;
  3752. IF k = 0 THEN
  3753. Cpy(base, "$"); App(base, name); App(base, "_data")
  3754. ELSE
  3755. Cpy(base, "0")
  3756. END;
  3757. IF k + 1 < rank THEN
  3758. Cpy(nxt, "$"); App(nxt, name); App(nxt, "_t");
  3759. IntStr(VAL(INTEGER, k + 1), bv); App(nxt, bv)
  3760. ELSE
  3761. Cpy(nxt, "0")
  3762. END;
  3763. W("data $"); W(lab); W(" = { l ");
  3764. IntStr(VAL(INTEGER, count), bv); W(bv);
  3765. W(", l "); IntStr(VAL(INTEGER, stride), sv); W(sv);
  3766. W(", l "); W(sv);
  3767. W(", l "); W(base);
  3768. W(", l "); W(nxt); WL(" }");
  3769. cur := SymTab.ArrayElem(cur);
  3770. INC(k)
  3771. END;
  3772. W("data $"); W(name); W("_data = { z ");
  3773. IntStr(VAL(INTEGER, payload), pv); W(pv); WL(" }")
  3774. END DeclMultiArr;
  3775. PROCEDURE DeclArr (name: ARRAY OF CHAR; t: INTEGER);
  3776. BEGIN
  3777. IF SymTab.IsOpenArray(t) OR (SymTab.ArrayDepth(t) = 0) THEN
  3778. DataLine(name, FALSE, "0"); RETURN
  3779. END;
  3780. IF SymTab.IsMultiArray(t) THEN DeclMultiArr(name, t)
  3781. ELSE ArrData(name, t)
  3782. END
  3783. END DeclArr;
  3784. (* ---------------- array constructors (step: `T{...}`) ---------------- *)
  3785. (* A constructor becomes a pooled static descriptor with the same
  3786. layout as a declared array: "l <ArrayLen>, <items>" (CHAR/UCHAR
  3787. get a trailing zero terminator slot, like ArrBodyItems). Nested
  3788. arrays are emitted as their own pooled descriptors and referenced
  3789. by `l $ctoK` so the runtime descriptor pointers stay valid. *)
  3790. PROCEDURE IsBakeOp (v: ARRAY OF CHAR): BOOLEAN;
  3791. (* TRUE when v may be embedded in a static descriptor: an immediate,
  3792. or a pooled constructor/label reference ($ctoN). A plain global
  3793. address ($mod_var) is NOT bakeable into an inline field. *)
  3794. BEGIN
  3795. IF (v[0] = CHR(0)) OR (v[0] = "%") THEN RETURN FALSE END;
  3796. IF v[0] # "$" THEN RETURN TRUE END;
  3797. (* accept $ctoN only *)
  3798. RETURN (v[1] = "c") AND (v[2] = "t") AND (v[3] = "o")
  3799. END IsBakeOp;
  3800. PROCEDURE CtorItem (VAR buf: ARRAY OF CHAR; v: ARRAY OF CHAR;
  3801. cls: INTEGER);
  3802. BEGIN
  3803. App(buf, ", ");
  3804. IF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  3805. OR (cls = SymTab.ClSByte) THEN
  3806. App(buf, "b ")
  3807. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  3808. App(buf, "h ")
  3809. ELSIF cls = SymTab.ClReal THEN
  3810. App(buf, "d ")
  3811. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc)
  3812. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClArray) THEN
  3813. App(buf, "l ")
  3814. ELSE
  3815. App(buf, "w ")
  3816. END;
  3817. App(buf, v)
  3818. END CtorItem;
  3819. PROCEDURE RecItem (VAR s: ARRAY OF CHAR; VAR first: BOOLEAN;
  3820. v: ARRAY OF CHAR; cls: INTEGER);
  3821. (* Record field item with a leading separator when not first. *)
  3822. BEGIN
  3823. IF first THEN first := FALSE ELSE App(s, ", ") END;
  3824. IF cls = SymTab.ClChar THEN App(s, "b ")
  3825. ELSIF cls = SymTab.ClReal THEN App(s, "d ")
  3826. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc)
  3827. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClArray) THEN
  3828. App(s, "l ")
  3829. ELSE
  3830. App(s, "w ")
  3831. END;
  3832. App(s, v)
  3833. END RecItem;
  3834. PROCEDURE ArrZeroBody (VAR s: ARRAY OF CHAR; t: INTEGER);
  3835. (* "l <n>, z <bytes>" — an all-zero array body (used for a record's
  3836. unprovided array field). *)
  3837. VAR n: CARDINAL;
  3838. elem: SymTab.TypeIndex;
  3839. ecls: INTEGER;
  3840. esz: CARDINAL;
  3841. bv: QVal;
  3842. BEGIN
  3843. n := SymTab.ArrayLen(t);
  3844. elem := SymTab.ArrayElem(t);
  3845. ecls := SymTab.ClassOf(elem);
  3846. App(s, "l ");
  3847. IntStr(VAL(INTEGER, n), bv);
  3848. App(s, bv);
  3849. IF ecls = SymTab.ClChar THEN
  3850. App(s, ", z "); IntStr(VAL(INTEGER, n + 1), bv); App(s, bv)
  3851. ELSIF ecls = SymTab.ClUChar THEN
  3852. App(s, ", z "); IntStr(VAL(INTEGER, (n + 1) * 4), bv); App(s, bv)
  3853. ELSE
  3854. IF (ecls = SymTab.ClReal) OR (ecls = SymTab.ClPtr)
  3855. OR (ecls = SymTab.ClProc) OR (ecls = SymTab.ClArray)
  3856. OR (ecls = SymTab.ClLong) THEN esz := 8
  3857. ELSE esz := 4
  3858. END;
  3859. IF n > 0 THEN
  3860. App(s, ", z "); IntStr(VAL(INTEGER, n * esz), bv); App(s, bv)
  3861. END
  3862. END
  3863. END ArrZeroBody;
  3864. PROCEDURE FindCtor (v: ARRAY OF CHAR): INTEGER;
  3865. VAR k: CARDINAL;
  3866. sv: QVal;
  3867. BEGIN
  3868. k := 0;
  3869. WHILE k < ctorN DO
  3870. Cpy(sv, "$"); App(sv, ctorNam[k]);
  3871. IF SymTab.Equal(sv, v) THEN RETURN VAL(INTEGER, k) END;
  3872. INC(k)
  3873. END;
  3874. RETURN -1
  3875. END FindCtor;
  3876. (* default items for a nested record field, appended to s *)
  3877. PROCEDURE RecItemDefaults (VAR s: ARRAY OF CHAR; VAR first: BOOLEAN;
  3878. prefix: ARRAY OF CHAR; t: INTEGER);
  3879. VAR i, n, cls, w: INTEGER;
  3880. fn: SymTab.Name;
  3881. ft: SymTab.TypeIndex;
  3882. sub: QVal;
  3883. BEGIN
  3884. n := VAL(INTEGER, SymTab.FieldCount(t));
  3885. i := 0;
  3886. WHILE i < n DO
  3887. SymTab.FieldName(t, i, fn);
  3888. ft := SymTab.FieldType(t, fn);
  3889. cls := SymTab.ClassOf(ft);
  3890. IF first THEN first := FALSE ELSE App(s, ", ") END;
  3891. IF cls = SymTab.ClReal THEN App(s, "d 0")
  3892. ELSIF cls = SymTab.ClChar THEN App(s, "b 0")
  3893. ELSIF cls = SymTab.ClArray THEN ArrZeroBody(s, ft)
  3894. ELSIF cls = SymTab.ClSet THEN
  3895. w := VAL(INTEGER, SymTab.SetWords(ft));
  3896. IF w = 0 THEN w := 1 END;
  3897. App(s, "w 0");
  3898. WHILE w > 1 DO App(s, ", w 0"); DEC(w) END
  3899. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  3900. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  3901. RecItemDefaults(s, first, sub, ft)
  3902. ELSE App(s, "w 0")
  3903. END;
  3904. INC(i)
  3905. END
  3906. END RecItemDefaults;
  3907. PROCEDURE CtorBegin (t: INTEGER);
  3908. BEGIN
  3909. IF ctorTop > HIGH(ctorTyp) THEN RETURN END;
  3910. ctorTyp[ctorTop] := t;
  3911. ctorCnt[ctorTop] := 0;
  3912. ctorBuf[ctorTop][0] := CHR(0);
  3913. INC(ctorTop)
  3914. END CtorBegin;
  3915. PROCEDURE CtorElemType (t: INTEGER; cnt: CARDINAL): SymTab.TypeIndex;
  3916. (* the type of the cnt-th constructor element: array element, or the
  3917. cnt-th record field in declaration order. *)
  3918. VAR fn: SymTab.Name;
  3919. BEGIN
  3920. IF SymTab.ClassOf(t) = SymTab.ClArray THEN
  3921. RETURN SymTab.ArrayElem(t)
  3922. END;
  3923. SymTab.FieldName(t, cnt, fn);
  3924. IF fn[0] = CHR(0) THEN RETURN SymTab.InvalidType END;
  3925. RETURN SymTab.FieldType(t, fn)
  3926. END CtorElemType;
  3927. PROCEDURE StrDesc (v: ARRAY OF CHAR; elemT: INTEGER; VAR out: QVal);
  3928. (* v is a $strN descriptor; build a CHAR-array descriptor of type
  3929. elemT from its text (padded/NUL-terminated) and return "$ctoM". *)
  3930. VAR k: CARDINAL;
  3931. found: BOOLEAN;
  3932. txt, bv, sv: QVal;
  3933. buf: ARRAY [0 .. 4095] OF CHAR;
  3934. n, i, L: CARDINAL;
  3935. BEGIN
  3936. Cpy(out, v);
  3937. IF (ctorN > HIGH(ctorNam)) THEN RETURN END;
  3938. found := FALSE; k := 0;
  3939. WHILE (k < nStr) AND NOT found DO
  3940. Cpy(sv, "$"); App(sv, strNams[k]);
  3941. IF SymTab.Equal(sv, v) THEN
  3942. Cpy(txt, strTexts[k]); found := TRUE
  3943. ELSE INC(k)
  3944. END
  3945. END;
  3946. IF NOT found THEN RETURN END;
  3947. L := Len(txt);
  3948. n := SymTab.ArrayLen(elemT);
  3949. buf[0] := CHR(0);
  3950. App(buf, "l ");
  3951. IntStr(VAL(INTEGER, n), bv);
  3952. App(buf, bv);
  3953. i := 0;
  3954. WHILE i < n DO
  3955. IF (i + 1 < L - 1) AND ((i + 1) <= HIGH(txt)) THEN
  3956. IntStr(ORD(txt[i + 1]), bv)
  3957. ELSE Cpy(bv, "0")
  3958. END;
  3959. CtorItem(buf, bv, SymTab.ClChar);
  3960. INC(i)
  3961. END;
  3962. App(buf, ", b 0");
  3963. Cpy(ctorNam[ctorN], "cto"); AppNum(ctorNam[ctorN], ctorN);
  3964. Cpy(ctorTxt[ctorN], buf);
  3965. ctorUse[ctorN] := TRUE;
  3966. INC(ctorN);
  3967. Cpy(out, "$"); App(out, ctorNam[ctorN - 1])
  3968. END StrDesc;
  3969. PROCEDURE AppCtorElem (v: ARRAY OF CHAR; cls: INTEGER);
  3970. VAR cnt: CARDINAL;
  3971. BEGIN
  3972. IF ctorTop = 0 THEN RETURN END;
  3973. cnt := ctorCnt[ctorTop - 1];
  3974. IF cnt > HIGH(ctorEv[0]) THEN RETURN END;
  3975. Cpy(ctorEv[ctorTop - 1][cnt], v);
  3976. ctorEk[ctorTop - 1][cnt] := cls;
  3977. INC(ctorCnt[ctorTop - 1])
  3978. END AppCtorElem;
  3979. PROCEDURE CtorElem (v: ARRAY OF CHAR);
  3980. (* Record the next constructor element. The element type is derived
  3981. from the constructor's type and the element index. A string literal
  3982. filling a CHAR element expands into consecutive elements. *)
  3983. VAR t, elemT, cls, k, si: INTEGER;
  3984. cnt: CARDINAL;
  3985. vv, bv: QVal;
  3986. isStr: BOOLEAN;
  3987. BEGIN
  3988. IF ctorTop = 0 THEN RETURN END;
  3989. t := ctorTyp[ctorTop - 1];
  3990. elemT := CtorElemType(t, ctorCnt[ctorTop - 1]);
  3991. cls := SymTab.ClassOf(elemT);
  3992. isStr := (Len(v) > 3) AND (v[0] = "$")
  3993. AND (v[1] = "s") AND (v[2] = "t");
  3994. IF cls = SymTab.ClChar THEN
  3995. IF isStr AND FindStrPos(v, cnt) THEN
  3996. k := 1;
  3997. WHILE k < VAL(INTEGER, Len(strTexts[cnt])) - 1 DO
  3998. IntStr(ORD(strTexts[cnt][k]), bv);
  3999. AppCtorElem(bv, SymTab.ClChar);
  4000. INC(k)
  4001. END;
  4002. RETURN
  4003. END;
  4004. AppCtorElem(v, SymTab.ClChar);
  4005. RETURN
  4006. END;
  4007. Cpy(vv, v);
  4008. IF (cls = SymTab.ClArray) AND isStr
  4009. AND (SymTab.ClassOf(SymTab.ArrayElem(elemT)) = SymTab.ClChar) THEN
  4010. StrDesc(v, elemT, vv)
  4011. END;
  4012. AppCtorElem(vv, cls)
  4013. END CtorElem;
  4014. PROCEDURE NewCtorTemp (t: INTEGER; VAR q: QVal);
  4015. VAR nb: QVal;
  4016. BEGIN
  4017. NewTemp(q);
  4018. Revive;
  4019. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  4020. W(" "); W(q); W(" =l alloc8 "); WL(nb)
  4021. END NewCtorTemp;
  4022. PROCEDURE InitArrHeader (addr: ARRAY OF CHAR; t: INTEGER);
  4023. (* Store an inline array's count header (and CHAR/UCHAR terminator
  4024. slot) at addr, so a following CopyArray sees matching counts. *)
  4025. VAR nb, ea: QVal;
  4026. BEGIN
  4027. IF SymTab.ClassOf(t) # SymTab.ClArray THEN RETURN END;
  4028. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), nb);
  4029. Revive; W(" storel "); W(nb); W(", "); WL(addr);
  4030. IF SymTab.IsCharArray(t) THEN
  4031. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t)), nb);
  4032. NewTemp(ea); Op3L("add", ea, addr, nb);
  4033. Revive; W(" storeb 0, "); WL(ea)
  4034. END;
  4035. IF SymTab.IsUCharArray(t) THEN
  4036. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t) * 4), nb);
  4037. NewTemp(ea); Op3L("add", ea, addr, nb);
  4038. Revive; W(" storew 0, "); WL(ea)
  4039. END
  4040. END InitArrHeader;
  4041. PROCEDURE CtorArrStatic (VAR s: ARRAY OF CHAR; lvl: CARDINAL;
  4042. t: INTEGER; cnt: CARDINAL);
  4043. VAR elem, ecls, n, k, ci: INTEGER;
  4044. v: QVal;
  4045. BEGIN
  4046. elem := SymTab.ArrayElem(t);
  4047. ecls := SymTab.ClassOf(elem);
  4048. n := VAL(INTEGER, SymTab.ArrayLen(t));
  4049. App(s, "l ");
  4050. IntStr(n, v);
  4051. App(s, v);
  4052. k := 0;
  4053. WHILE k < n DO
  4054. IF k < VAL(INTEGER, cnt) THEN
  4055. Cpy(v, ctorEv[lvl][k])
  4056. ELSE Cpy(v, "0")
  4057. END;
  4058. IF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass) THEN
  4059. ci := FindCtor(v);
  4060. IF ci >= 0 THEN
  4061. App(s, ", "); App(s, ctorTxt[ci]);
  4062. ctorUse[ci] := FALSE
  4063. ELSE
  4064. AppFlatZero(s, SymTab.TypeSize(elem))
  4065. END
  4066. ELSE
  4067. CtorItem(s, v, ecls)
  4068. END;
  4069. INC(k)
  4070. END;
  4071. IF ecls = SymTab.ClChar THEN App(s, ", b 0")
  4072. ELSIF ecls = SymTab.ClUChar THEN App(s, ", w 0")
  4073. END
  4074. END CtorArrStatic;
  4075. PROCEDURE NextCtorTok (txt: ARRAY OF CHAR; VAR pos: CARDINAL;
  4076. VAR kind: CHAR; VAR val: QVal): BOOLEAN;
  4077. VAR L, j: CARDINAL;
  4078. BEGIN
  4079. val[0] := CHR(0); kind := CHR(0);
  4080. L := Len(txt);
  4081. WHILE (pos < L) AND ((txt[pos] = " ") OR (txt[pos] = ",")) DO
  4082. INC(pos)
  4083. END;
  4084. IF (pos >= L) OR (txt[pos] = "}") THEN RETURN FALSE END;
  4085. kind := txt[pos]; INC(pos);
  4086. WHILE (pos < L) AND (txt[pos] = " ") DO INC(pos) END;
  4087. j := 0;
  4088. WHILE (pos < L) AND (txt[pos] # ",") AND (txt[pos] # " ")
  4089. AND (txt[pos] # "}") DO
  4090. IF j <= HIGH(val) THEN val[j] := txt[pos] END;
  4091. INC(j); INC(pos)
  4092. END;
  4093. IF j <= HIGH(val) THEN val[j] := CHR(0) END;
  4094. RETURN TRUE
  4095. END NextCtorTok;
  4096. PROCEDURE AppFlat (VAR out: ARRAY OF CHAR; kind: CHAR; val: ARRAY OF CHAR);
  4097. VAR n: CARDINAL;
  4098. BEGIN
  4099. IF out[0] # CHR(0) THEN App(out, ", ") END;
  4100. IF kind # CHR(0) THEN
  4101. n := Len(out);
  4102. out[n] := kind;
  4103. out[n + 1] := CHR(0);
  4104. App(out, " ")
  4105. END;
  4106. App(out, val)
  4107. END AppFlat;
  4108. PROCEDURE AppFlatZero (VAR out: ARRAY OF CHAR; n: CARDINAL);
  4109. VAR bv: QVal;
  4110. BEGIN
  4111. IF n = 0 THEN RETURN END;
  4112. IF out[0] # CHR(0) THEN App(out, ", ") END;
  4113. App(out, "z ");
  4114. IntStr(VAL(INTEGER, n), bv); App(out, bv)
  4115. END AppFlatZero;
  4116. PROCEDURE AppZeroItem (VAR out: ARRAY OF CHAR; n: CARDINAL);
  4117. VAR bv: QVal;
  4118. BEGIN
  4119. IF n = 0 THEN RETURN END;
  4120. App(out, "z ");
  4121. IntStr(VAL(INTEGER, n), bv); App(out, bv)
  4122. END AppZeroItem;
  4123. PROCEDURE FlattenArrayText (txt: ARRAY OF CHAR; t: INTEGER;
  4124. VAR out: ARRAY OF CHAR);
  4125. VAR pos: CARDINAL; kind: CHAR; val: QVal; n, i, elemN, ci: INTEGER;
  4126. elem: SymTab.TypeIndex;
  4127. BEGIN
  4128. pos := 0;
  4129. IF (NOT NextCtorTok(txt, pos, kind, val)) OR (kind # "l")
  4130. OR (NOT ParseInt(val, n)) OR (n < 0) THEN
  4131. AppFlatZero(out, SymTab.ArrayPayloadSize(t)); RETURN
  4132. END;
  4133. elem := SymTab.ArrayElem(t);
  4134. elemN := VAL(INTEGER, SymTab.ArrayPayloadSize(elem));
  4135. i := 0;
  4136. WHILE i < n DO
  4137. IF NOT NextCtorTok(txt, pos, kind, val) THEN
  4138. AppFlatZero(out, VAL(CARDINAL, elemN))
  4139. ELSIF SymTab.ClassOf(elem) = SymTab.ClArray THEN
  4140. ci := FindCtor(val);
  4141. IF (kind = "l") AND (val[0] = "$") AND (ci >= 0) THEN
  4142. FlattenArrayText(ctorTxt[ci], elem, out)
  4143. ELSE
  4144. AppFlatZero(out, VAL(CARDINAL, elemN))
  4145. END
  4146. ELSE
  4147. AppFlat(out, kind, val)
  4148. END;
  4149. INC(i)
  4150. END
  4151. END FlattenArrayText;
  4152. PROCEDURE FlattenCtorText (v: ARRAY OF CHAR; t: INTEGER;
  4153. VAR out: ARRAY OF CHAR);
  4154. VAR ci: INTEGER;
  4155. BEGIN
  4156. ci := FindCtor(v);
  4157. IF ci < 0 THEN
  4158. AppFlatZero(out, SymTab.ArrayPayloadSize(t))
  4159. ELSE
  4160. FlattenArrayText(ctorTxt[ci], t, out)
  4161. END
  4162. END FlattenCtorText;
  4163. PROCEDURE CtorRecStatic (VAR s: ARRAY OF CHAR; lvl: CARDINAL;
  4164. t: INTEGER; cnt: CARDINAL);
  4165. (* Static record body: fields in declaration order; an array/record
  4166. field given as a nested constructor is inlined (and that child
  4167. descriptor is marked consumed). *)
  4168. VAR i, n, cls, ci, w: INTEGER;
  4169. fn: SymTab.Name;
  4170. ft: SymTab.TypeIndex;
  4171. v, bv: QVal;
  4172. flat: ARRAY [0 .. 4095] OF CHAR;
  4173. first: BOOLEAN;
  4174. BEGIN
  4175. first := TRUE;
  4176. IF (SymTab.ClassOf(t) = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  4177. VtRef(t, bv);
  4178. App(s, "l "); App(s, bv);
  4179. first := FALSE
  4180. END;
  4181. n := VAL(INTEGER, SymTab.FieldCount(t));
  4182. i := 0;
  4183. WHILE i < n DO
  4184. SymTab.FieldName(t, i, fn);
  4185. ft := SymTab.FieldType(t, fn);
  4186. cls := SymTab.ClassOf(ft);
  4187. v[0] := CHR(0);
  4188. IF i < VAL(INTEGER, cnt) THEN Cpy(v, ctorEv[lvl][i]) END;
  4189. IF (v[0] # CHR(0)) AND (cls = SymTab.ClArray)
  4190. AND SymTab.IsMultiArray(ft) THEN
  4191. flat[0] := CHR(0);
  4192. IF (v[0] = "$") AND (v[1] = "c") THEN
  4193. FlattenCtorText(v, ft, flat)
  4194. END;
  4195. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4196. IF flat[0] # CHR(0) THEN App(s, flat)
  4197. ELSE AppZeroItem(s, SymTab.ArrayPayloadSize(ft))
  4198. END
  4199. ELSIF (v[0] # CHR(0)) AND (v[0] = "$")
  4200. AND ((cls = SymTab.ClArray) OR (cls = SymTab.ClRecord)
  4201. OR (cls = SymTab.ClClass)) THEN
  4202. ci := FindCtor(v);
  4203. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4204. IF ci >= 0 THEN
  4205. App(s, ctorTxt[ci]);
  4206. ctorUse[ci] := FALSE
  4207. ELSIF cls = SymTab.ClArray THEN
  4208. IF SymTab.IsMultiArray(ft) THEN
  4209. AppZeroItem(s, SymTab.ArrayPayloadSize(ft))
  4210. ELSE ArrZeroBody(s, ft)
  4211. END
  4212. ELSE App(s, "w 0")
  4213. END
  4214. ELSIF v[0] # CHR(0) THEN
  4215. RecItem(s, first, v, cls)
  4216. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  4217. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4218. Cpy(bv, ctorNam[ctorN]); App(bv, "_"); App(bv, fn);
  4219. RecItemDefaults(s, first, bv, ft)
  4220. ELSE
  4221. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4222. IF cls = SymTab.ClReal THEN App(s, "d 0")
  4223. ELSIF cls = SymTab.ClChar THEN App(s, "b 0")
  4224. ELSIF cls = SymTab.ClArray THEN
  4225. IF SymTab.IsMultiArray(ft) THEN
  4226. AppZeroItem(s, SymTab.ArrayPayloadSize(ft))
  4227. ELSE ArrZeroBody(s, ft)
  4228. END
  4229. ELSIF cls = SymTab.ClSet THEN
  4230. w := VAL(INTEGER, SymTab.SetWords(ft));
  4231. IF w = 0 THEN w := 1 END;
  4232. App(s, "w 0");
  4233. WHILE w > 1 DO App(s, ", w 0"); DEC(w) END
  4234. ELSE App(s, "w 0")
  4235. END
  4236. END;
  4237. INC(i)
  4238. END;
  4239. IF first THEN App(s, "w 0") END
  4240. END CtorRecStatic;
  4241. PROCEDURE ClearBytes (addr: ARRAY OF CHAR; n: CARDINAL);
  4242. VAR nb, a: QVal;
  4243. BEGIN
  4244. IF n = 0 THEN RETURN END;
  4245. IntStr(VAL(INTEGER, n), nb);
  4246. NewTemp(a);
  4247. W(" "); W(a); W(" =l call $memset(l "); W(addr);
  4248. W(", w 0, l "); W(nb); WL(")")
  4249. END ClearBytes;
  4250. PROCEDURE ClearMultiField (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4251. VAR nb, a: QVal;
  4252. BEGIN
  4253. IntStr(VAL(INTEGER, SymTab.ArrayPayloadSize(t)), nb);
  4254. NewTemp(a);
  4255. W(" "); W(a); W(" =l call $memset(l "); W(addr);
  4256. W(", w 0, l "); W(nb); WL(")")
  4257. END ClearMultiField;
  4258. PROCEDURE CtorEnd (VAR q: QVal);
  4259. VAR t, cls, lvl, k, n, cnt, esz, off, ci: INTEGER;
  4260. allc: BOOLEAN;
  4261. bv, a, v, qview: QVal;
  4262. s: ARRAY [0 .. 4095] OF CHAR;
  4263. ft, elem: SymTab.TypeIndex;
  4264. nm: SymTab.Name;
  4265. BEGIN
  4266. IF ctorTop = 0 THEN Cpy(q, "0"); RETURN END;
  4267. DEC(ctorTop);
  4268. lvl := VAL(INTEGER, ctorTop);
  4269. IF noEmit THEN Cpy(q, "0"); RETURN END;
  4270. t := ctorTyp[ctorTop];
  4271. cnt := VAL(INTEGER, ctorCnt[ctorTop]);
  4272. cls := SymTab.ClassOf(t);
  4273. IF (cls # SymTab.ClArray) AND (cls # SymTab.ClRecord)
  4274. AND (cls # SymTab.ClClass) THEN
  4275. Cpy(q, "0"); RETURN
  4276. END;
  4277. allc := TRUE; k := 0;
  4278. WHILE k < cnt DO
  4279. IF NOT IsBakeOp(ctorEv[lvl][k]) THEN allc := FALSE END;
  4280. INC(k)
  4281. END;
  4282. IF allc AND (ctorN <= HIGH(ctorNam)) THEN
  4283. s[0] := CHR(0);
  4284. IF cls = SymTab.ClArray THEN
  4285. CtorArrStatic(s, ctorTop, t, ctorCnt[ctorTop])
  4286. ELSE
  4287. CtorRecStatic(s, ctorTop, t, ctorCnt[ctorTop])
  4288. END;
  4289. Cpy(ctorNam[ctorN], "cto"); AppNum(ctorNam[ctorN], ctorN);
  4290. Cpy(ctorTxt[ctorN], s);
  4291. ctorUse[ctorN] := TRUE;
  4292. INC(ctorN);
  4293. Cpy(q, "$"); App(q, ctorNam[ctorN - 1])
  4294. ELSE
  4295. (* runtime construction: an all-zero descriptor filled in place *)
  4296. NewCtorTemp(t, q);
  4297. IF cls = SymTab.ClArray THEN
  4298. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), bv);
  4299. Revive; W(" storel "); W(bv); W(", "); WL(q);
  4300. elem := SymTab.ArrayElem(t);
  4301. esz := VAL(INTEGER, ElemSize(t));
  4302. n := VAL(INTEGER, SymTab.ArrayLen(t));
  4303. k := 0;
  4304. WHILE k < n DO
  4305. off := 8 + k * esz;
  4306. FieldAddr(q, off, a);
  4307. IF (SymTab.ClassOf(elem) = SymTab.ClRecord)
  4308. OR (SymTab.ClassOf(elem) = SymTab.ClClass) THEN
  4309. IF k < cnt THEN
  4310. Cpy(v, ctorEv[lvl][k]);
  4311. CopyRecord(a, v, elem)
  4312. ELSE
  4313. ClearBytes(a, SymTab.TypeSize(elem))
  4314. END
  4315. ELSIF k < cnt THEN
  4316. Cpy(v, ctorEv[lvl][k]);
  4317. ElemStore(a, v, elem)
  4318. ELSE ElemStore(a, "0", elem)
  4319. END;
  4320. INC(k)
  4321. END;
  4322. IF SymTab.ClassOf(elem) = SymTab.ClChar THEN
  4323. off := 8 + n;
  4324. FieldAddr(q, off, a);
  4325. Revive; W(" storeb 0, "); WL(a)
  4326. ELSIF SymTab.ClassOf(elem) = SymTab.ClUChar THEN
  4327. off := 8 + n * 4;
  4328. FieldAddr(q, off, a);
  4329. Revive; W(" storew 0, "); WL(a)
  4330. END
  4331. ELSE
  4332. (* record / class *)
  4333. IF (cls = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  4334. VtRef(t, bv);
  4335. off := SymTab.VptrOffset(t);
  4336. FieldAddr(q, off, a);
  4337. Revive; W(" storel "); W(bv); W(", "); WL(a)
  4338. END;
  4339. n := VAL(INTEGER, SymTab.FieldCount(t));
  4340. k := 0;
  4341. WHILE k < n DO
  4342. SymTab.FieldName(t, k, nm);
  4343. ft := SymTab.FieldType(t, nm);
  4344. off := SymTab.FieldOffset(t, nm);
  4345. FieldAddr(q, off, a);
  4346. IF k < cnt THEN
  4347. Cpy(v, ctorEv[lvl][k]);
  4348. IF SymTab.ClassOf(ft) = SymTab.ClArray THEN
  4349. IF SymTab.IsMultiArray(ft) THEN
  4350. MakeFieldView(a, ft, qview);
  4351. CopyArray(qview, v, ft)
  4352. ELSE
  4353. InitArrHeader(a, ft);
  4354. CopyArray(a, v, ft)
  4355. END
  4356. ELSIF (SymTab.ClassOf(ft) = SymTab.ClRecord)
  4357. OR (SymTab.ClassOf(ft) = SymTab.ClClass) THEN
  4358. CopyRecord(a, v, ft)
  4359. ELSIF SymTab.ClassOf(ft) = SymTab.ClSet THEN
  4360. CopySet(a, v, SymTab.SetWords(ft), SymTab.SetWords(ft))
  4361. ELSE ElemStore(a, v, ft)
  4362. END
  4363. ELSIF (SymTab.ClassOf(ft) = SymTab.ClArray)
  4364. AND SymTab.IsMultiArray(ft) THEN
  4365. ClearMultiField(a, ft)
  4366. ELSIF (SymTab.ClassOf(ft) = SymTab.ClReal)
  4367. OR (SymTab.ClassOf(ft) = SymTab.ClChar)
  4368. OR (SymTab.ClassOf(ft) = SymTab.ClInt)
  4369. OR (SymTab.ClassOf(ft) = SymTab.ClBool)
  4370. OR (SymTab.ClassOf(ft) = SymTab.ClEnum)
  4371. OR (SymTab.ClassOf(ft) = SymTab.ClLong)
  4372. OR (SymTab.ClassOf(ft) = SymTab.ClPtr)
  4373. OR (SymTab.ClassOf(ft) = SymTab.ClProc) THEN
  4374. ElemStore(a, "0", ft)
  4375. END;
  4376. INC(k)
  4377. END
  4378. END
  4379. END
  4380. END CtorEnd;
  4381. PROCEDURE FlushCtors;
  4382. VAR k: CARDINAL;
  4383. BEGIN
  4384. IF NOT opened THEN RETURN END;
  4385. k := 0;
  4386. WHILE k < ctorN DO
  4387. IF ctorUse[k] THEN
  4388. W("data $"); W(ctorNam[k]); W(" = { "); W(ctorTxt[k]); WL(" }")
  4389. END;
  4390. INC(k)
  4391. END
  4392. END FlushCtors;
  4393. PROCEDURE PushLoop (exit: ARRAY OF CHAR);
  4394. BEGIN
  4395. IF loopTop <= HIGH(loopSt) THEN
  4396. Cpy(loopSt[loopTop], exit); INC(loopTop)
  4397. END
  4398. END PushLoop;
  4399. PROCEDURE PopLoop;
  4400. BEGIN
  4401. IF loopTop > 0 THEN DEC(loopTop) END
  4402. END PopLoop;
  4403. PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
  4404. BEGIN
  4405. IF loopTop = 0 THEN RETURN FALSE END;
  4406. Cpy(exit, loopSt[loopTop - 1]);
  4407. RETURN TRUE
  4408. END TopLoop;
  4409. PROCEDURE CmpL (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  4410. VAR mn : ARRAY [0 .. 7] OF CHAR;
  4411. BEGIN
  4412. mn[0] := CHR(0);
  4413. IF op = SymTab.OpEq THEN Cpy(mn, "ceql")
  4414. ELSE Cpy(mn, "cnel")
  4415. END;
  4416. NewTemp(q);
  4417. Op3(mn, q, l, r, FALSE)
  4418. END CmpL;
  4419. (* ---------------- heap (step 3.6: extern malloc/free) ---------------- *)
  4420. (* Only the object skeleton is initialized (array counts); elements
  4421. and members stay garbage per Wirth, except nested objects which
  4422. are allocated recursively. DISPOSE is shallow (documented). *)
  4423. PROCEDURE HeapSize (t: INTEGER): CARDINAL;
  4424. VAR cls: INTEGER;
  4425. n: CARDINAL;
  4426. BEGIN
  4427. cls := SymTab.ClassOf(t);
  4428. IF (cls = SymTab.ClArray) AND SymTab.IsMultiArray(t) THEN
  4429. RETURN SymTab.ArrayDepth(t) * 40 + SymTab.ArrayPayloadSize(t)
  4430. ELSIF cls = SymTab.ClArray THEN
  4431. n := SymTab.ArrayLen(t) * ElemSize(t);
  4432. IF SymTab.IsCharArray(t) THEN n := n + 1 END;
  4433. IF SymTab.IsUCharArray(t) THEN n := n + 4 END;
  4434. RETURN 8 + n
  4435. END;
  4436. RETURN SymTab.TypeSize(t)
  4437. END HeapSize;
  4438. PROCEDURE NewHeap (t: SymTab.TypeIndex; VAR q: QVal);
  4439. VAR nb: QVal;
  4440. BEGIN
  4441. NewTemp(q);
  4442. Revive;
  4443. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  4444. W(" "); W(q);
  4445. IF useStack THEN W(" =l alloc8 "); W(nb); WL("")
  4446. ELSE W(" =l call $malloc(l "); W(nb); WL(")")
  4447. END
  4448. END NewHeap;
  4449. PROCEDURE FreeHeap (v: ARRAY OF CHAR);
  4450. BEGIN
  4451. Revive;
  4452. W(" call $free(l "); W(v); WL(")")
  4453. END FreeHeap;
  4454. PROCEDURE InitMultiHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4455. (* Initialise the per-level view chain and zero the flat payload. *)
  4456. VAR rank, k, count, stride, payload: CARDINAL;
  4457. cur: SymTab.TypeIndex;
  4458. v, a, nb, off, pay: QVal;
  4459. BEGIN
  4460. rank := SymTab.ArrayDepth(t);
  4461. payload := SymTab.ArrayPayloadSize(t);
  4462. cur := t;
  4463. k := 0;
  4464. WHILE k < rank DO
  4465. IntStr(VAL(INTEGER, k * 40), off);
  4466. NewTemp(v); Op3L("add", v, addr, off);
  4467. count := SymTab.ArrayLen(cur);
  4468. IntStr(VAL(INTEGER, count), nb);
  4469. Revive; W(" storel "); W(nb); W(", "); WL(v);
  4470. stride := SymTab.ArrayStride(t, k);
  4471. IntStr(VAL(INTEGER, stride), nb);
  4472. NewTemp(a); Op3L("add", a, v, "8");
  4473. Revive; W(" storel "); W(nb); W(", "); WL(a);
  4474. NewTemp(a); Op3L("add", a, v, "16");
  4475. Revive; W(" storel "); W(nb); W(", "); WL(a);
  4476. IF k = 0 THEN
  4477. IntStr(VAL(INTEGER, rank * 40), off);
  4478. NewTemp(pay); Op3L("add", pay, addr, off);
  4479. NewTemp(a); Op3L("add", a, v, "24");
  4480. Revive; W(" storel "); W(pay); W(", "); WL(a)
  4481. ELSE
  4482. NewTemp(a); Op3L("add", a, v, "24");
  4483. Revive; W(" storel 0, "); WL(a)
  4484. END;
  4485. IF k + 1 < rank THEN
  4486. IntStr(VAL(INTEGER, (k + 1) * 40), off);
  4487. NewTemp(a); Op3L("add", a, addr, off);
  4488. NewTemp(nb); Op3L("add", nb, v, "32");
  4489. Revive; W(" storel "); W(a); W(", "); WL(nb)
  4490. ELSE
  4491. NewTemp(a); Op3L("add", a, v, "32");
  4492. Revive; W(" storel 0, "); WL(a)
  4493. END;
  4494. cur := SymTab.ArrayElem(cur);
  4495. INC(k)
  4496. END;
  4497. IntStr(VAL(INTEGER, rank * 40), off);
  4498. NewTemp(pay); Op3L("add", pay, addr, off);
  4499. IntStr(VAL(INTEGER, payload), nb);
  4500. NewTemp(a); W(" "); W(a); W(" =l call $memset(l ");
  4501. W(pay); W(", w 0, l "); W(nb); WL(")")
  4502. END InitMultiHeap;
  4503. PROCEDURE InitMultiField (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4504. BEGIN
  4505. ClearMultiField(addr, t)
  4506. END InitMultiField;
  4507. PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4508. VAR cls, ecls: INTEGER;
  4509. n, i: CARDINAL;
  4510. fn: SymTab.Name;
  4511. ft: SymTab.TypeIndex;
  4512. nb, ea, eb, fa, fb: QVal;
  4513. BEGIN
  4514. cls := SymTab.ClassOf(t);
  4515. IF (cls = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  4516. (* install the class's vtable pointer *)
  4517. VtRef(t, eb);
  4518. IntStr(SymTab.VptrOffset(t), nb);
  4519. NewTemp(ea);
  4520. Op3L("add", ea, addr, nb);
  4521. Revive;
  4522. W(" storel "); W(eb); W(", "); WL(ea)
  4523. END;
  4524. IF (cls = SymTab.ClArray) AND SymTab.IsMultiArray(t) THEN
  4525. InitMultiHeap(addr, t)
  4526. ELSIF cls = SymTab.ClArray THEN
  4527. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), nb);
  4528. Revive;
  4529. W(" storel "); W(nb); W(", "); WL(addr);
  4530. IF SymTab.IsCharArray(t) THEN
  4531. (* NUL terminator slot at index = count *)
  4532. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t)), nb);
  4533. NewTemp(ea);
  4534. Op3L("add", ea, addr, nb);
  4535. Revive;
  4536. W(" storeb 0, "); WL(ea)
  4537. END;
  4538. IF SymTab.IsUCharArray(t) THEN
  4539. (* 0-codepoint terminator at index = count (4-byte element) *)
  4540. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t) * 4), nb);
  4541. NewTemp(ea);
  4542. Op3L("add", ea, addr, nb);
  4543. Revive;
  4544. W(" storew 0, "); WL(ea)
  4545. END;
  4546. ecls := SymTab.ClassOf(SymTab.ArrayElem(t));
  4547. IF ecls = SymTab.ClArray THEN
  4548. n := SymTab.ArrayLen(t);
  4549. i := 0;
  4550. WHILE i < n DO
  4551. IntStr(VAL(INTEGER, 8 + i * 8), nb);
  4552. NewTemp(ea);
  4553. Op3L("add", ea, addr, nb);
  4554. NewHeap(SymTab.ArrayElem(t), eb);
  4555. InitHeap(eb, SymTab.ArrayElem(t)); (* init the sub-array *)
  4556. Revive;
  4557. W(" storel "); W(eb); W(", "); WL(ea);
  4558. INC(i)
  4559. END
  4560. END
  4561. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  4562. n := SymTab.FieldCount(t);
  4563. i := 0;
  4564. WHILE i < n DO
  4565. SymTab.FieldName(t, i, fn);
  4566. ft := SymTab.FieldType(t, fn);
  4567. ecls := SymTab.ClassOf(ft);
  4568. IF ecls = SymTab.ClArray THEN
  4569. IntStr(SymTab.FieldOffset(t, fn), nb);
  4570. NewTemp(fa);
  4571. Op3L("add", fa, addr, nb);
  4572. IF SymTab.IsMultiArray(ft) THEN
  4573. InitMultiField(fa, ft)
  4574. ELSE
  4575. InitHeap(fa, ft)
  4576. END
  4577. ELSIF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass) THEN
  4578. IntStr(SymTab.FieldOffset(t, fn), nb);
  4579. NewTemp(fa);
  4580. Op3L("add", fa, addr, nb);
  4581. InitHeap(fa, ft)
  4582. END;
  4583. INC(i)
  4584. END
  4585. END
  4586. END InitHeap;
  4587. PROCEDURE InFunction (): BOOLEAN;
  4588. (* TRUE while a function body is open (module-level test). *)
  4589. BEGIN
  4590. RETURN inFunc
  4591. END InFunction;
  4592. PROCEDURE RecArrayNeedsInit (n: CARDINAL; t: INTEGER): BOOLEAN;
  4593. (* TRUE for an array of records/classes that (recursively) has array
  4594. fields and is too large to expand inline: its inline length words
  4595. must be initialised at run time (InitRecArray). *)
  4596. VAR elem: INTEGER;
  4597. BEGIN
  4598. IF SymTab.ClassOf(t) # SymTab.ClArray THEN RETURN FALSE END;
  4599. elem := SymTab.ArrayElem(t);
  4600. IF (SymTab.ClassOf(elem) # SymTab.ClRecord)
  4601. AND (SymTab.ClassOf(elem) # SymTab.ClClass) THEN RETURN FALSE END;
  4602. IF NOT HasArrayField(elem) THEN RETURN FALSE END;
  4603. RETURN NOT RecArrayExpanded(n, elem)
  4604. END RecArrayNeedsInit;
  4605. PROCEDURE DeclRecTemplate (varName: ARRAY OF CHAR; rec: INTEGER);
  4606. (* "data $<mod>_<varName>_tmpl = { <one record with counts set> }" plus
  4607. any nested sub-descriptors; InitRecArray copies it over each element
  4608. of the compact array-of-record blob. *)
  4609. VAR g: QVal; first: BOOLEAN;
  4610. BEGIN
  4611. IF NOT opened THEN RETURN END;
  4612. Cpy(g, curModName); App(g, "_"); App(g, varName); App(g, "_tmpl");
  4613. RecStatics(g, rec);
  4614. W("data $"); W(g); W(" = { ");
  4615. first := TRUE;
  4616. RecItems(rec, g, first);
  4617. WL(" }")
  4618. END DeclRecTemplate;
  4619. PROCEDURE InitRecArray (varName: ARRAY OF CHAR; arrT: INTEGER);
  4620. (* value-initialise $<mod>_<varName>'s element length words: copy the
  4621. template record over each element (element i is at base + 8 +
  4622. i*stride). *)
  4623. VAR base, tmpl, slot, i, il, off, tb, p, c, one, two, nStr, stStr: QVal;
  4624. elem: INTEGER; lTop, lBody, lDone: QVal;
  4625. BEGIN
  4626. IF NOT opened THEN RETURN END;
  4627. elem := SymTab.ArrayElem(arrT);
  4628. Cpy(base, "$"); App(base, curModName); App(base, "_"); App(base, varName);
  4629. Cpy(tmpl, base); App(tmpl, "_tmpl");
  4630. IntStr(VAL(INTEGER, SymTab.ArrayLen(arrT)), nStr);
  4631. IntStr(VAL(INTEGER, SymTab.TypeSize(elem)), stStr);
  4632. Slot4(slot);
  4633. StoreW(slot, "0");
  4634. NewLabel(lTop); NewLabel(lBody); NewLabel(lDone);
  4635. EmitLabel(lTop);
  4636. LoadW(slot, i);
  4637. NewTemp(c); Op3("csltw", c, i, nStr, FALSE);
  4638. Jnz(c, lBody, lDone);
  4639. EmitLabel(lBody);
  4640. LoadW(slot, i);
  4641. WidenIndex(i, il);
  4642. NewTemp(off); Op3L("mul", off, il, stStr);
  4643. NewTemp(tb); Op3L("add", tb, base, "8");
  4644. NewTemp(p); Op3L("add", p, tb, off);
  4645. CopyRecord(p, tmpl, elem);
  4646. LoadW(slot, i);
  4647. NewTemp(one); CopyOp("1", one);
  4648. NewTemp(two); Op3("add", two, i, one, FALSE);
  4649. StoreW(slot, two);
  4650. Jmp(lTop);
  4651. EmitLabel(lDone)
  4652. END InitRecArray;
  4653. BEGIN
  4654. opened := FALSE;
  4655. inBody := FALSE;
  4656. dead := FALSE;
  4657. nTemp := 0; nLab := 0; loopTop := 0; nR := 0; nStr := 0;
  4658. withTop := 0;
  4659. noEmit := FALSE; inFunc := FALSE; useStack := FALSE;
  4660. nLoc := 0; nPar := 0; nArg := 0; nn := 0; callDepth := 0;
  4661. recvArmed := FALSE;
  4662. funcDepth := 0; scopeTop := 0; scopeBase[0] := 0;
  4663. outSel := 0
  4664. END QbeGen.