12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952 |
- /*
- Copyright (c) 2021, b4rt-dev
- Copyright (c) 2012-2020, Alexey Frunze
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /*****************************************************************************/
- /* */
- /* BCC (B322 C Compiler) */
- /* */
- /* C compiler for B322 */
- /* Modified version intended to run on FPGC */
- /* */
- /* Based on SmallerC: */
- /* A simple and small single-pass C compiler */
- /* */
- /* Main file */
- /* */
- /*****************************************************************************/
- /* PLAN:
- - move through program from execution start to finish
- - implement missing (mostly FS) functions on the go (skip unimportant ones first, and do them later)
- - try to implement vararg printf, since it will save hours of printf replacements
- - FS functions (test/create library in a seperate test program):
- - fopen: just return a pointer to (global var!) the full path of the file, init cursor (private)
- - fput/get: open the file if not already opened, use cursor to read/write
- */
- // Making most functions static helps with code optimization,
- // use that to further reduce compiler's code size on RetroBSD.
- #define word char
- #define NO_EXTRAS
- #define CAN_COMPILE_32BIT
- #define MIPS
- #define B322
- #define NO_PPACK
- #define NO_TYPEDEF_ENUM
- #define NO_FUNC_
- #define NO_EXTRA_WARNS
- #define NO_FOR_DECL
- #define NO_STRUCT_BY_VAL
- #define NO_FP
- #define NO_WCHAR
- #define NULL 0
- #define size_t word //unsigned int
- #define CHAR_BIT (8)
- #define CHAR_MIN (-128)
- #define CHAR_MAX (127)
- #define INT_MAX (2147483647)
- #define INT_MIN (-2147483647 - 1)
- #define UINT_MAX (4294967295u)
- #define UINT_MIN (0u)
- #define EXIT_FAILURE 1
- #define MACROTABLE_ADDR 0x440000
- #define IDENTTABLE_ADDR 0x450000
- #define SYNSTACK0_ADDR 0x460000
- #define SYNSTACK1_ADDR 0x470000
- #define INPUTBUFFER_ADDR 0x480000
- #define FILENAMES_ADDR 0x490000
- #include "lib/math.c"
- #include "lib/sys.c"
- //#include "lib/gfx.c"
- #include "lib/stdlib.c"
- #include "lib/fs.c"
- #include "lib/stdio.c"
- ////////////////////////////////////////////////////////////////////////////////
- // all public macros
- #define MAX_IDENT_LEN 63
- #define MAX_STRING_LEN 255
- #define MAX_CHAR_QUEUE_LEN (MAX_STRING_LEN + 1)
- #define MAX_MACRO_TABLE_LEN (4096+1024)
- #define MAX_IDENT_TABLE_LEN (4096+1024+512) // must be greater than MAX_IDENT_LEN
- #define SYNTAX_STACK_MAX (2048+1024)
- #define MAX_FILE_NAME_LEN 95
- #define MAX_INCLUDES 8
- #define PREP_STACK_SIZE 8
- #define MAX_SEARCH_PATH 256
- /* +-~* /% &|^! << >> && || < <= > >= == != () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
- #define tokEof 0
- #define tokNumInt 1
- #define tokNumUint 2
- #define tokLitStr 3
- #define tokLShift 4
- #define tokRShift 5
- #define tokLogAnd 6
- #define tokLogOr 7
- #define tokEQ 8
- #define tokNEQ 9
- #define tokLEQ 10
- #define tokGEQ 11
- #define tokInc 12
- #define tokDec 13
- #define tokArrow 14
- #define tokEllipsis 15
- #define tokIdent 16
- #define tokVoid 17
- #define tokChar 18
- #define tokInt 19
- #define tokReturn 20
- #define tokGoto 21
- #define tokIf 22
- #define tokElse 23
- #define tokWhile 24
- #define tokCont 25
- #define tokBreak 26
- #define tokSizeof 27
- #define tokAssignMul 'A'
- #define tokAssignDiv 'B'
- #define tokAssignMod 'C'
- #define tokAssignAdd 'D'
- #define tokAssignSub 'E'
- #define tokAssignLSh 'F'
- #define tokAssignRSh 'G'
- #define tokAssignAnd 'H'
- #define tokAssignXor 'I'
- #define tokAssignOr 'J'
- #define tokFloat 'a'
- #define tokDouble 'b'
- #define tokLong 'c'
- #define tokShort 'd'
- #define tokUnsigned 'e'
- #define tokSigned 'f'
- #define tokConst 'g'
- #define tokVolatile 'h'
- #define tokRestrict 'i'
- #define tokStatic 'j'
- #define tokInline 'k'
- #define tokExtern 'l'
- #define tokAuto 'm'
- #define tokRegister 'n'
- #define tokTypedef 'o'
- #define tokEnum 'p'
- #define tokStruct 'q'
- #define tokUnion 'r'
- #define tokDo 's'
- #define tokFor 't'
- #define tokSwitch 'u'
- #define tokCase 'v'
- #define tokDefault 'w'
- #define tok_Bool 'x'
- #define tok_Complex 'y'
- #define tok_Imagin 'z'
- #define tok_Asm '`'
- /* Pseudo-tokens (converted from others or generated) */
- #define tokURShift 28
- #define tokUDiv 29
- #define tokUMod 30
- #define tokAssignURSh 31
- #define tokAssignUDiv '@'
- #define tokAssignUMod 'K'
- #define tokComma '0'
- #define tokIfNot 'L'
- #define tokUnaryAnd 'M'
- #define tokUnaryStar 'N'
- #define tokUnaryPlus 'O'
- #define tokUnaryMinus 'P'
- #define tokPostInc 'Q'
- #define tokPostDec 'R'
- #define tokPostAdd 'S'
- #define tokPostSub 'T'
- #define tokULess 'U'
- #define tokUGreater 'V'
- #define tokULEQ 'W'
- #define tokUGEQ 'X'
- #define tokLocalOfs 'Y'
- #define tokShortCirc 'Z'
- #define tokSChar 0x80
- #define tokUChar 0x81
- #define tokUShort 0x82
- #define tokULong 0x83
- //#define tokLongLong 0x84
- //#define tokULongLong 0x85
- //#define tokLongDbl 0x86
- #define tokGotoLabel 0x8F
- #define tokStructPtr 0x90
- #define tokTag 0x91
- #define tokMemberIdent 0x92
- #define tokEnumPtr 0x93
- #define tokIntr 0x94
- #define tokNumFloat 0x95
- #define tokNumCharWide 0x96
- #define tokLitStrWide 0x97
- //#define FormatFlat 0
- #define FormatSegmented 1
- //#define FormatSegTurbo 2
- #define FormatSegHuge 3
- #define FormatSegUnreal 4
- #define SymVoidSynPtr 0
- #define SymIntSynPtr 1
- #define SymUintSynPtr 2
- #define SymWideCharSynPtr 3
- #define SymFloatSynPtr 4
- #define SymFuncPtr 5
- #define STACK_SIZE 129
- #define SymFxn 1
- #define SymGlobalVar 2
- #define SymGlobalArr 3
- #define SymLocalVar 4
- #define SymLocalArr 5
- // all public prototypes
- unsigned truncUint(unsigned);
- word truncInt(word);
- word GetToken(void);
- char* GetTokenName(word token);
- void DumpMacroTable(void);
- word AddIdent(char* name);
- word FindIdent(char* name);
- void DumpIdentTable(void);
- char* lab2str(char* p, word n);
- void GenInit(void);
- void GenFin(void);
- void GenInitFinalize(void);
- void GenStartCommentLine(void);
- void GenWordAlignment(word bss);
- void GenLabel(char* Label, word Static);
- void GenNumLabel(word Label);
- void GenZeroData(unsigned Size, word bss);
- void GenIntData(word Size, word Val);
- void GenStartAsciiString(void);
- void GenAddrData(word Size, char* Label, word ofs);
- void GenJumpUncond(word Label);
- void GenJumpIfZero(word Label);
- void GenJumpIfNotZero(word Label);
- void GenJumpIfEqual(word val, word Label);
- void GenFxnProlog(void);
- void GenFxnEpilog(void);
- void GenIsrProlog(void);
- void GenIsrEpilog(void);
- word GenMaxLocalsSize(void);
- void GenDumpChar(word ch);
- void GenExpr(void);
- void PushSyntax(word t);
- void PushSyntax2(word t, word v);
- void DumpSynDecls(void);
- void push2(word v, word v2);
- void ins2(word pos, word v, word v2);
- void ins(word pos, word v);
- void del(word pos, word cnt);
- word TokenStartsDeclaration(word t, word params);
- word ParseDecl(word tok, unsigned structInfo[4], word cast, word label);
- void ShiftChar(void);
- word puts2(char*);
- word printf2(char*);
- void error(char* strToPrint);
- void warning(char* strToPrint);
- void errorFile(char* n);
- void errorFileName(void);
- void errorInternal(word n);
- void errorChrStr(void);
- void errorStrLen(void);
- void errorUnexpectedToken(word tok);
- void errorDirective(void);
- void errorCtrlOutOfScope(void);
- void errorDecl(void);
- void errorVarSize(void);
- void errorInit(void);
- void errorUnexpectedVoid(void);
- void errorOpType(void);
- void errorNotLvalue(void);
- void errorNotConst(void);
- void errorLongExpr(void);
- word FindSymbol(char* s);
- word SymType(word SynPtr);
- word FindTaggedDecl(char* s, word start, word* CurScope);
- word GetDeclSize(word SyntaxPtr, word SizeForDeref);
- word ParseExpr(word tok, word* GotUnary, word* ExprTypeSynPtr, word* ConstExpr, word* ConstVal, word option, word option2);
- word GetFxnInfo(word ExprTypeSynPtr, word* MinParams, word* MaxParams, word* ReturnExprTypeSynPtr, word* FirstParamSynPtr);
- // all data
- word verbose = 0;
- word warnings = 0;
- word warnCnt = 0;
- word doAnnotations = 0;
- // custom compiler flags
- word compileUserBDOS = 0;
- word compileOS = 0;
- // prep.c data
- // TBD!!! get rid of TokenIdentName[] and TokenValueString[]
- // and work with CharQueue[] directly
- word TokenValueInt = 0;
- char TokenIdentName[MAX_IDENT_LEN + 1];
- word TokenIdentNameLen = 0;
- char TokenValueString[MAX_STRING_LEN + 1];
- unsigned TokenStringLen = 0;
- unsigned TokenStringSize = 0; // TokenStringLen * sizeof(char/wchar_t)
- word LineNo = 1;
- word LinePos = 1;
- char CharQueue[MAX_CHAR_QUEUE_LEN];
- word CharQueueLen = 0;
- /*
- Macro table entry format:
- idlen char: identifier length (<= 127)
- id char[idlen]: identifier (ASCIIZ)
- exlen char: length of what the identifier expands into (<= 127)
- ex char[exlen]: what the identifier expands into (ASCII)
- */
- char *MacroTable = (char*) MACROTABLE_ADDR; //[MAX_MACRO_TABLE_LEN];
- word MacroTableLen = 0;
- /*
- Identifier table entry format:
- id char[idlen]: string (ASCIIZ)
- idlen char: string length (<= 127)
- */
- char *IdentTable = (char*) IDENTTABLE_ADDR; //[MAX_IDENT_TABLE_LEN];
- word IdentTableLen = 0;
- word DummyIdent; // corresponds to empty string
- #define MAX_GOTO_LABELS 16
- word gotoLabels[MAX_GOTO_LABELS][2];
- // gotoLabStat[]: bit 1 = used (by "goto label;"), bit 0 = defined (with "label:")
- char gotoLabStat[MAX_GOTO_LABELS];
- word gotoLabCnt = 0;
- #define MAX_CASES 128
- word Cases[MAX_CASES][2]; // [0] is case constant, [1] is case label number
- word CasesCnt = 0;
- // Data structures to support #include
- word FileCnt = 0;
- char (*FileNames)[MAX_FILE_NAME_LEN + 1] = (char (*)[MAX_FILE_NAME_LEN + 1]) FILENAMES_ADDR;
- //char FileNames[MAX_INCLUDES][MAX_FILE_NAME_LEN + 1];
- word Files[MAX_INCLUDES]; // FILE
- word OutFile; // FILE
- char CharQueues[MAX_INCLUDES][3];
- word LineNos[MAX_INCLUDES];
- word LinePoss[MAX_INCLUDES];
- char SysSearchPaths[MAX_SEARCH_PATH];
- word SysSearchPathsLen = 0;
- char SearchPaths[MAX_SEARCH_PATH];
- word SearchPathsLen = 0;
- // Data structures to support #ifdef/#ifndef,#else,#endif
- word PrepDontSkipTokens = 1;
- word PrepStack[PREP_STACK_SIZE][2];
- word PrepSp = 0;
- // expr.c data
- word ExprLevel = 0;
- // TBD??? merge expression and operator stacks into one
- word stack[STACK_SIZE][2];
- word sp = 0;
- #define OPERATOR_STACK_SIZE STACK_SIZE
- word opstack[OPERATOR_STACK_SIZE][2];
- word opsp = 0;
- // smc.c data
- word OutputFormat = FormatSegmented;
- word GenExterns = 1;
- word UseBss = 1;
- // Names of C functions and variables are usually prefixed with an underscore.
- // One notable exception is the ELF format used by gcc in Linux.
- // Global C identifiers in the ELF format should not be predixed with an underscore.
- word UseLeadingUnderscores = 1;
- char* FileHeader = "";
- char* CodeHeaderFooter[2] = { "", "" };
- char* DataHeaderFooter[2] = { "", "" };
- char* RoDataHeaderFooter[2] = { "", "" };
- char* BssHeaderFooter[2] = { "", "" };
- char** CurHeaderFooter;
- word CharIsSigned = 1;
- word SizeOfWord = 2; // in chars (char can be a multiple of octets); ints and pointers are of word size
- //word SizeOfWideChar = 2; // in chars/bytes, 2 or 4
- //word WideCharIsSigned = 0; // 0 or 1
- //word WideCharType1;
- //word WideCharType2; // (un)signed counterpart of WideCharType1
- // TBD??? implement a function to allocate N labels with overflow checks
- word LabelCnt = 1; // label counter for jumps
- word StructCpyLabel = 0; // label of the function to copy structures/unions
- //word StructPushLabel = 0; // label of the function to push structures/unions onto the stack
- // call stack (from higher to lower addresses):
- // arg n
- // ...
- // arg 1
- // return address
- // saved xbp register
- // local var 1
- // ...
- // local var n
- word CurFxnSyntaxPtr = 0;
- word CurFxnParamCntMin = 0;
- word CurFxnParamCntMax = 0;
- word CurFxnLocalOfs = 0; // negative
- word CurFxnMinLocalOfs = 0; // negative
- word CurFxnReturnExprTypeSynPtr = 0;
- word CurFxnEpilogLabel = 0;
- char* CurFxnName = NULL;
- word IsMain; // if inside main()
- word ParseLevel = 0; // Parse level/scope (file:0, fxn:1+)
- word ParamLevel = 0; // 1+ if parsing params, 0 otherwise
- unsigned char *SyntaxStack0 = (unsigned char*) SYNSTACK0_ADDR; //[SYNTAX_STACK_MAX];
- word *SyntaxStack1 = (word*) SYNSTACK1_ADDR; //[SYNTAX_STACK_MAX];
- word SyntaxStackCnt;
- // all code
- unsigned truncUint(unsigned n)
- {
- // Truncate n to SizeOfWord * 8 bits
- if (SizeOfWord == 2)
- n &= ~(~0u << 8 << 8);
- else if (SizeOfWord == 4)
- n &= ~(~0u << 8 << 12 << 12);
- return n;
- }
- word truncInt(word n)
- {
- // Truncate n to SizeOfWord * 8 bits and then sign-extend it
- unsigned un = n;
- if (SizeOfWord == 2)
- {
- un &= ~(~0u << 8 << 8);
- un |= (((un >> 8 >> 7) & 1) * ~0u) << 8 << 8;
- }
- else if (SizeOfWord == 4)
- {
- un &= ~(~0u << 8 << 12 << 12);
- un |= (((un >> 8 >> 12 >> 11) & 1) * ~0u) << 8 << 12 << 12;
- }
- return (word)un;
- }
- // prep.c code
- word FindMacro(char* name)
- {
- word i;
- for (i = 0; i < MacroTableLen; )
- {
- if (!strcmp(MacroTable + i + 1, name))
- return i + 1 + MacroTable[i];
- i = i + 1 + MacroTable[i]; // skip id
- i = i + 1 + MacroTable[i]; // skip ex
- }
- return -1;
- }
- word UndefineMacro(char* name)
- {
- word i;
- for (i = 0; i < MacroTableLen; )
- {
- if (!strcmp(MacroTable + i + 1, name))
- {
- word len = 1 + MacroTable[i]; // id part len
- len = len + 1 + MacroTable[i + len]; // + ex part len
- memmove(MacroTable + i,
- MacroTable + i + len,
- MacroTableLen - i - len);
- MacroTableLen -= len;
- return 1;
- }
- i = i + 1 + MacroTable[i]; // skip id
- i = i + 1 + MacroTable[i]; // skip ex
- }
- return 0;
- }
- void AddMacroIdent(char* name)
- {
- word l = strlen(name);
- if (l >= 127)
- {
- printf("Macro identifier too long ");
- printf(name);
- error("\n");
- }
- if (MAX_MACRO_TABLE_LEN - MacroTableLen < l + 3)
- error("Macro table exhausted\n");
- MacroTable[MacroTableLen++] = l + 1; // idlen
- strcpy(MacroTable + MacroTableLen, name);
- MacroTableLen += l + 1;
- MacroTable[MacroTableLen] = 0; // exlen
- }
- void AddMacroExpansionChar(char e)
- {
- if (e == '\0')
- {
- // finalize macro definition entry
- // remove trailing space first
- while (MacroTable[MacroTableLen] &&
- strchr(" \t", MacroTable[MacroTableLen + MacroTable[MacroTableLen]]))
- MacroTable[MacroTableLen]--;
- MacroTableLen += 1 + MacroTable[MacroTableLen];
- return;
- }
- if (MacroTableLen + 1 + MacroTable[MacroTableLen] >= MAX_MACRO_TABLE_LEN)
- error("Macro table exhausted\n");
- if (MacroTable[MacroTableLen] >= 127)
- error("Macro definition too long\n");
- MacroTable[MacroTableLen + 1 + MacroTable[MacroTableLen]] = e;
- MacroTable[MacroTableLen]++;
- }
- void DumpMacroTable(void)
- {
- word i, j;
- puts2("");
- GenStartCommentLine(); printf2("Macro table:\n");
- for (i = 0; i < MacroTableLen; )
- {
- GenStartCommentLine();
- printf2("Macro ");
- printf2(MacroTable + i + 1);
- printf2(" = ");
- i = i + 1 + MacroTable[i]; // skip id
- printf2("`");
- j = MacroTable[i++];
- while (j--)
- {
- char* c = " ";
- c[0] = MacroTable[i++];
- printf2(c);
- }
- printf2("`\n");
- }
- GenStartCommentLine(); //TODO: printf2("Bytes used: %d/%d\n\n", MacroTableLen, MAX_MACRO_TABLE_LEN);
- }
- word FindIdent(char* name)
- {
- word i;
- for (i = IdentTableLen; i > 0; )
- {
- i -= 1 + IdentTable[i - 1];
- if (!strcmp(IdentTable + i, name))
- return i;
- }
- return -1;
- }
- word AddIdent(char* name)
- {
- word i, len;
- if ((i = FindIdent(name)) >= 0)
- return i;
- i = IdentTableLen;
- len = strlen(name);
- if (len >= 127)
- error("Identifier too long\n");
- if (MAX_IDENT_TABLE_LEN - IdentTableLen < len + 2)
- error("Identifier table exhausted\n");
- strcpy(IdentTable + IdentTableLen, name);
- IdentTableLen += len + 1;
- IdentTable[IdentTableLen++] = len + 1;
- return i;
- }
- word AddNumericIdent(word n)
- {
- char s[1 + (2 + CHAR_BIT * sizeof n) / 3];
- char *p = s + sizeof s;
- *--p = '\0';
- p = lab2str(p, n);
- return AddIdent(p);
- }
- word AddGotoLabel(char* name, word label)
- {
- word i;
- for (i = 0; i < gotoLabCnt; i++)
- {
- if (!strcmp(IdentTable + gotoLabels[i][0], name))
- {
- if (gotoLabStat[i] & label)
- {
- printf("Redefinition of label ");
- printf(name);
- error("\n");
- }
- gotoLabStat[i] |= 2*!label + label;
- return gotoLabels[i][1];
- }
- }
- if (gotoLabCnt >= MAX_GOTO_LABELS)
- error("Goto table exhausted\n");
- gotoLabels[gotoLabCnt][0] = AddIdent(name);
- gotoLabels[gotoLabCnt][1] = LabelCnt++;
- gotoLabStat[gotoLabCnt] = 2*!label + label;
- return gotoLabels[gotoLabCnt++][1];
- }
- void UndoNonLabelIdents(word len)
- {
- word i;
- IdentTableLen = len;
- for (i = 0; i < gotoLabCnt; i++)
- if (gotoLabels[i][0] >= len)
- {
- char* pfrom = IdentTable + gotoLabels[i][0];
- char* pto = IdentTable + IdentTableLen;
- word l = strlen(pfrom) + 2;
- memmove(pto, pfrom, l);
- IdentTableLen += l;
- gotoLabels[i][0] = pto - IdentTable;
- }
- }
- void AddCase(word val, word label)
- {
- if (CasesCnt >= MAX_CASES)
- error("Case table exhausted\n");
- Cases[CasesCnt][0] = val;
- Cases[CasesCnt++][1] = label;
- }
- void DumpIdentTable(void)
- {
- word i;
- puts2("");
- GenStartCommentLine(); printf2("Identifier table:\n");
- for (i = 0; i < IdentTableLen; )
- {
- GenStartCommentLine();
- printf2("Ident ");
- printf2(IdentTable + i);
- printf2("\n");
- i += strlen(IdentTable + i) + 2;
- }
- GenStartCommentLine(); //TODO: printf2("Bytes used: %d/%d\n\n", IdentTableLen, MAX_IDENT_TABLE_LEN);
- }
- char* rws[] =
- {
- "break", "case", "char", "continue", "default", "do", "else",
- "extern", "for", "if", "int", "return", "signed", "sizeof",
- "static", "switch", "unsigned", "void", "while", "asm", "auto",
- "const", "double", "enum", "float", "goto", "inline", "long",
- "register", "restrict", "short", "struct", "typedef", "union",
- "volatile", "_Bool", "_Complex", "_Imaginary",
- "__interrupt"
- };
- unsigned char rwtk[] =
- {
- tokBreak, tokCase, tokChar, tokCont, tokDefault, tokDo, tokElse,
- tokExtern, tokFor, tokIf, tokInt, tokReturn, tokSigned, tokSizeof,
- tokStatic, tokSwitch, tokUnsigned, tokVoid, tokWhile, tok_Asm, tokAuto,
- tokConst, tokDouble, tokEnum, tokFloat, tokGoto, tokInline, tokLong,
- tokRegister, tokRestrict, tokShort, tokStruct, tokTypedef, tokUnion,
- tokVolatile, tok_Bool, tok_Complex, tok_Imagin,
- tokIntr
- };
- word GetTokenByWord(char* wrd)
- {
- unsigned i;
- for (i = 0; i < division(sizeof rws, sizeof rws[0]); i++)
- if (!strcmp(rws[i], wrd))
- return rwtk[i];
- return tokIdent;
- }
- unsigned char tktk[] =
- {
- tokEof,
- // Single-character operators and punctuators:
- '+', '-', '~', '*', '/', '%', '&', '|', '^', '!',
- '<', '>', '(', ')', '[', ']',
- '{', '}', '=', ',', ';', ':', '.', '?',
- // Multi-character operators and punctuators:
- tokLShift, tokLogAnd, tokEQ, tokLEQ, tokInc, tokArrow, tokAssignMul,
- tokAssignMod, tokAssignSub, tokAssignRSh, tokAssignXor,
- tokRShift, tokLogOr, tokNEQ, tokGEQ, tokDec, tokEllipsis,
- tokAssignDiv, tokAssignAdd, tokAssignLSh, tokAssignAnd, tokAssignOr,
- // Some of the above tokens get converted into these in the process:
- tokUnaryAnd, tokUnaryPlus, tokPostInc, tokPostAdd,
- tokULess, tokULEQ, tokURShift, tokUDiv, tokUMod, tokComma,
- tokUnaryStar, tokUnaryMinus, tokPostDec, tokPostSub,
- tokUGreater, tokUGEQ, tokAssignURSh, tokAssignUDiv, tokAssignUMod,
- // Helper (pseudo-)tokens:
- tokNumInt, tokLitStr, tokLocalOfs, tokNumUint, tokIdent, tokShortCirc,
- tokSChar, tokShort, tokLong, tokUChar, tokUShort, tokULong, tokNumFloat,
- tokNumCharWide, tokLitStrWide
- };
- char* tks[] =
- {
- "<EOF>",
- // Single-character operators and punctuators:
- "+", "-", "~", "*", "/", "%", "&", "|", "^", "!",
- "<", ">", "(", ")", "[", "]",
- "{", "}", "=", ",", ";", ":", ".", "?",
- // Multi-character operators and punctuators:
- "<<", "&&", "==", "<=", "++", "->", "*=",
- "%=", "-=", ">>=", "^=",
- ">>", "||", "!=", ">=", "--", "...",
- "/=", "+=", "<<=", "&=", "|=",
- // Some of the above tokens get converted into these in the process:
- "&u", "+u", "++p", "+=p",
- "<u", "<=u", ">>u", "/u", "%u", ",b",
- "*u", "-u", "--p", "-=p",
- ">u", ">=u", ">>=u", "/=u", "%=u",
- // Helper (pseudo-)tokens:
- "<NumInt>", "<LitStr>", "<LocalOfs>", "<NumUint>", "<Ident>", "<ShortCirc>",
- "signed char", "short", "long", "unsigned char", "unsigned short", "unsigned long", "float",
- "<NumCharWide>", "<LitStrWide>"
- };
- char* GetTokenName(word token)
- {
- unsigned i;
- /* +-~* /% &|^! << >> && || < <= > >= == != () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
- // Tokens other than reserved keywords:
- for (i = 0; i < division(sizeof tktk , sizeof tktk[0]); i++)
- if (tktk[i] == token)
- return tks[i];
- // Reserved keywords:
- for (i = 0; i < division(sizeof rws , sizeof rws[0]); i++)
- if (rwtk[i] == token)
- return rws[i];
- //error("Internal Error: GetTokenName(): Invalid token %d\n", token);
- errorInternal(1);
- return "";
- }
- word GetNextChar(void)
- {
- word ch = EOF;
- if (FileCnt && Files[FileCnt - 1])
- {
- if ((ch = fgetc(Files[FileCnt - 1])) == EOF)
- {
- fclose(Files[FileCnt - 1]);
- Files[FileCnt - 1] = NULL;
- // store the last line/pos, they may still be needed later
- LineNos[FileCnt - 1] = LineNo;
- LinePoss[FileCnt - 1] = LinePos;
- // don't drop the file record just yet
- }
- }
- return ch;
- }
- void ShiftChar(void)
- {
- if (CharQueueLen)
- memmove(CharQueue, CharQueue + 1, --CharQueueLen);
- // make sure there always are at least 3 chars in the queue
- while (CharQueueLen < 3)
- {
- word ch = GetNextChar();
- if (ch == EOF)
- ch = '\0';
- CharQueue[CharQueueLen++] = ch;
- //BDOS_PrintcConsole(ch);
- }
- }
- void ShiftCharN(word n)
- {
- while (n-- > 0)
- {
- ShiftChar();
- LinePos++;
- }
- }
- void IncludeFile(word quot)
- {
- word nlen = strlen(TokenValueString);
- if (CharQueueLen != 3)
- //error("#include parsing error\n");
- errorInternal(2);
- if (FileCnt >= MAX_INCLUDES)
- error("Too many include files\n");
- // store the including file's position and buffered chars
- LineNos[FileCnt - 1] = LineNo;
- LinePoss[FileCnt - 1] = LinePos;
- memcpy(CharQueues[FileCnt - 1], CharQueue, CharQueueLen);
- // open the included file
- if (nlen > MAX_FILE_NAME_LEN)
- //error("File name too long\n");
- errorFileName();
- // DONE: differentiate between quot == '"' and quot == '<'
- // First, try opening "file" in the current directory
- // (Open Watcom C/C++ 1.9, Turbo C++ 1.01 use the current directory,
- // unlike gcc, which uses the same directory as the current file)
- if (quot == '"')
- {
- // Get path from c file to compile, so it can be appended to the include paths
- char cFileDir[255] = "";
- strcpy(cFileDir, FileNames[0]);
- word len = strlen(cFileDir);
- while (len > 0)
- {
- len--;
- if (cFileDir[len] == '/')
- {
- cFileDir[len+1] = '\0'; // keep the slash
- break;
- }
- }
- if (len == 0) // remove directory if there is none
- {
- cFileDir[0] = '\0';
- }
- strcpy(FileNames[FileCnt], TokenValueString);
- strcat(cFileDir, FileNames[FileCnt]);
- Files[FileCnt] = fopen(cFileDir, 0);
- }
- // Next, iterate the search paths trying to open "file" or <file>.
- // "file" is first searched using the list provided by the -I option.
- // "file" is then searched using the list provided by the -SI option.
- // <file> is searched using the list provided by the -SI option.
- if (Files[FileCnt] == NULL)
- {
- word i;
- char *paths = SearchPaths;
- word pl = SearchPathsLen;
- for (;;)
- {
- if (quot == '<')
- {
- paths = SysSearchPaths;
- pl = SysSearchPathsLen;
- }
- for (i = 0; i < pl; )
- {
- word plen = strlen(paths + i);
- if (plen + 1 + nlen < MAX_FILE_NAME_LEN)
- {
- strcpy(FileNames[FileCnt], paths + i);
- strcpy(FileNames[FileCnt] + plen + 1, TokenValueString);
- // Use '/' as a separator, typical for Linux/Unix,
- // but also supported by file APIs in DOS/Windows just as '\\'
- FileNames[FileCnt][plen] = '/';
- if ((Files[FileCnt] = fopen(FileNames[FileCnt], 0)) != NULL)
- break;
- }
- i += plen + 1;
- }
- if (Files[FileCnt] || quot == '<')
- break;
- quot = '<';
- }
- }
- if (Files[FileCnt] == NULL)
- {
- //error("Cannot open file \"%s\"\n", TokenValueString);
- errorFile(TokenValueString);
- }
- // reset line/pos and empty the char queue
- CharQueueLen = 0;
- LineNo = LinePos = 1;
- FileCnt++;
- // fill the char queue with file data
- ShiftChar();
- }
- word EndOfFiles(void)
- {
- // if there are no including files, we're done
- if (!--FileCnt)
- return 1;
- // restore the including file's position and buffered chars
- LineNo = LineNos[FileCnt - 1];
- LinePos = LinePoss[FileCnt - 1];
- CharQueueLen = 3;
- memcpy(CharQueue, CharQueues[FileCnt - 1], CharQueueLen);
- return 0;
- }
- void SkipSpace(word SkipNewLines)
- {
- char* p = CharQueue;
- while (*p != '\0')
- {
- if (strchr(" \t\f\v", *p))
- {
- ShiftCharN(1);
- continue;
- }
- if (strchr("\r\n", *p))
- {
- if (!SkipNewLines)
- return;
- if (*p == '\r' && p[1] == '\n')
- ShiftChar();
- ShiftChar();
- LineNo++;
- LinePos = 1;
- continue;
- }
- if (*p == '/')
- {
- if (p[1] == '/')
- {
- // // comment
- ShiftCharN(2);
- while (!strchr("\r\n", *p))
- ShiftCharN(1);
- continue;
- }
- else if (p[1] == '*')
- {
- // /**/ comment
- ShiftCharN(2);
- while (*p != '\0' && !(*p == '*' && p[1] == '/'))
- {
- if (strchr("\r\n", *p))
- {
- if (!SkipNewLines)
- error("Invalid comment\n");
- if (*p == '\r' && p[1] == '\n')
- ShiftChar();
- ShiftChar();
- LineNo++;
- LinePos = 1;
- }
- else
- {
- ShiftCharN(1);
- }
- }
- if (*p == '\0')
- error("Invalid comment\n");
- ShiftCharN(2);
- continue;
- }
- } // endof if (*p == '/')
- break;
- } // endof while (*p != '\0')
- }
- void SkipLine(void)
- {
- char* p = CharQueue;
- while (*p != '\0')
- {
- if (strchr("\r\n", *p))
- {
- if (*p == '\r' && p[1] == '\n')
- ShiftChar();
- ShiftChar();
- LineNo++;
- LinePos = 1;
- break;
- }
- else
- {
- ShiftCharN(1);
- }
- }
- }
- void GetIdent(void)
- {
- char* p = CharQueue;
- if (*p != '_' && !isalpha(*p & 0xFFu))
- error("Identifier expected\n");
- TokenIdentNameLen = 0;
- TokenIdentName[TokenIdentNameLen++] = *p;
- TokenIdentName[TokenIdentNameLen] = '\0';
- ShiftCharN(1);
- while (*p == '_' || isalnum(*p & 0xFFu))
- {
- if (TokenIdentNameLen == MAX_IDENT_LEN)
- {
- printf("Identifier too long ");
- printf(TokenIdentName);
- error("\n");
- }
- TokenIdentName[TokenIdentNameLen++] = *p;
- TokenIdentName[TokenIdentNameLen] = '\0';
- ShiftCharN(1);
- }
- }
- unsigned GetCharValue(word wide)
- {
- char* p = CharQueue;
- unsigned ch = 0;
- word cnt = 0;
- if (*p == '\\')
- {
- ShiftCharN(1);
- if (strchr("\n\r", *p))
- goto lerr;
- if (*p == 'x')
- {
- // hexadecimal character codes \xN+
- // hexadecimal escape sequence is not limited in length per se
- // (may have many leading zeroes)
- static char digs[] = "0123456789ABCDEFabcdef";
- static char vals[] =
- {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15,
- 10, 11, 12, 13, 14, 15
- };
- char* pp;
- word zeroes = 0;
- ShiftCharN(1);
- if (strchr("\n\r", *p))
- goto lerr;
- if (*p == '0')
- {
- do
- {
- ShiftCharN(1);
- } while (*p == '0');
- zeroes = 1;
- }
- while (*p && (pp = strchr(digs, *p)) != NULL)
- {
- ch <<= 4;
- ch |= vals[pp - digs];
- ShiftCharN(1);
- if (++cnt > 2)
- {
- if (PrepDontSkipTokens)
- goto lerr;
- }
- }
- if (zeroes + cnt == 0)
- goto lerr;
- }
- else if (*p >= '0' && *p <= '7')
- {
- // octal character codes \N+
- // octal escape sequence is terminated after three octal digits
- do
- {
- ch <<= 3;
- ch |= *p - '0';
- ShiftCharN(1);
- ++cnt;
- } while (*p >= '0' && *p <= '7' && cnt < 3);
- if (ch >> 8)
- goto lerr;
- }
- else
- {
- switch (*p)
- {
- case 'a': ch = '\a'; ShiftCharN(1); break;
- case 'b': ch = '\b'; ShiftCharN(1); break;
- case 'f': ch = '\f'; ShiftCharN(1); break;
- case 'n': ch = '\n'; ShiftCharN(1); break;
- case 'r': ch = '\r'; ShiftCharN(1); break;
- case 't': ch = '\t'; ShiftCharN(1); break;
- case 'v': ch = '\v'; ShiftCharN(1); break;
- default:
- goto lself;
- }
- }
- }
- else
- {
- lself:
- if (strchr("\n\r", *p))
- {
- lerr:
- //error("Unsupported or invalid character/string constant\n");
- errorChrStr();
- }
- ch = *p & 0xFFu;
- ShiftCharN(1);
- }
- return ch;
- }
- void GetString(char terminator, word wide, word option)
- {
- char* p = CharQueue;
- unsigned ch = '\0';
- unsigned chsz = 1;
- word i;
- char* ctmp = " ";
- TokenStringLen = 0;
- TokenStringSize = 0;
- TokenValueString[TokenStringLen] = '\0';
- ShiftCharN(1);
- while (!(*p == terminator || strchr("\n\r", *p)))
- {
- ch = GetCharValue(wide);
- switch (option)
- {
- case '#': // string literal (with file name) for #line and #include
- if (TokenStringLen == MAX_STRING_LEN)
- errorStrLen();
- TokenValueString[TokenStringLen++] = ch;
- TokenValueString[TokenStringLen] = '\0';
- TokenStringSize += chsz;
- break;
- case 'a': // string literal for asm()
- ctmp[0] = ch;
- printf2(ctmp);
- break;
- case 'd': // string literal / array of char in expression or initializer
- // Dump the char data to the appropriate data section
- for (i = 0; i < chsz; i++)
- {
- GenDumpChar(ch & 0xFFu);
- ch >>= 8;
- TokenStringLen++; // GenDumpChar() expects it to grow, doesn't know about wchar_t
- }
- TokenStringLen -= chsz;
- // fallthrough
- default: // skipped string literal (we may still need the size)
- if (TokenStringSize > UINT_MAX - chsz)
- errorStrLen();
- TokenStringSize += chsz;
- TokenStringLen++;
- break;
- } // endof switch (option)
- } // endof while (!(*p == '\0' || *p == terminator || strchr("\n\r", *p)))
- if (*p != terminator)
- //error("Unsupported or invalid character/string constant\n");
- errorChrStr();
- if (option == 'd')
- GenDumpChar(-1);
- ShiftCharN(1);
- SkipSpace(option != '#');
- }
- void pushPrep(word NoSkip)
- {
- if (PrepSp >= PREP_STACK_SIZE)
- error("Too many #if(n)def's\n");
- PrepStack[PrepSp][0] = PrepDontSkipTokens;
- PrepStack[PrepSp++][1] = NoSkip;
- PrepDontSkipTokens &= NoSkip;
- }
- word popPrep(void)
- {
- if (PrepSp <= 0)
- error("#else or #endif without #if(n)def\n");
- PrepDontSkipTokens = PrepStack[--PrepSp][0];
- return PrepStack[PrepSp][1];
- }
- word GetNumber(void)
- {
- char* p = CharQueue;
- word ch = *p;
- word leadingZero = (ch == '0');
- unsigned n = 0;
- word type = 0;
- word uSuffix = 0;
- word lSuffix = 0;
- char* eTooBig = "Constant too big\n";
- // First, detect and handle hex constants. Octals can't be detected immediately
- // because floating-point constants also may begin with the digit 0.
- if (leadingZero && (p[1] == 'x' || p[1] == 'X'))
- {
- // this is a hex constant
- word cnt = 0;
- type = 'h';
- ShiftCharN(1);
- ShiftCharN(1);
- while ((ch = *p) != '\0' && (isdigit(ch & 0xFFu) || strchr("abcdefABCDEF", ch)))
- {
- if (ch >= 'a') ch -= 'a' - 10;
- else if (ch >= 'A') ch -= 'A' - 10;
- else ch -= '0';
- //if (PrepDontSkipTokens && (n * 16 / 16 != n || n * 16 + ch < n * 16))
- // error(eTooBig);
- n = n * 16 + ch;
- ShiftCharN(1);
- cnt++;
- }
- if (!cnt)
- error("Invalid hexadecimal constant\n");
- }
- else
- {
- // handle decimal and octal integers
- word base = leadingZero ? 8 : 10;
- type = leadingZero ? 'o' : 'd';
- while ((ch = *p) >= '0' && ch < base + '0')
- {
- ch -= '0';
- if (PrepDontSkipTokens && (n * base + ch < n * base)) //n * base / base != n ||
- error(eTooBig);
- n = n * base + ch;
- ShiftCharN(1);
- }
- }
- // possible combinations of integer suffixes:
- // none
- // U
- // UL
- // L
- // LU
- {
- if ((ch = *p) == 'u' || ch == 'U')
- {
- uSuffix = 1;
- ShiftCharN(1);
- }
- if ((ch = *p) == 'l' || ch == 'L')
- {
- lSuffix = 1;
- ShiftCharN(1);
- if (!uSuffix && ((ch = *p) == 'u' || ch == 'U'))
- {
- uSuffix = 1;
- ShiftCharN(1);
- }
- }
- }
- if (!PrepDontSkipTokens)
- {
- // Don't fail on big constants when skipping tokens under #if
- TokenValueInt = 0;
- return tokNumInt;
- }
- // Ensure the constant fits into 16(32) bits
- if (
- (SizeOfWord == 2 && n >> 8 >> 8) // equiv. to SizeOfWord == 2 && n > 0xFFFF
- || (SizeOfWord == 2 && lSuffix) // long (which must have at least 32 bits) isn't supported in 16-bit models
- || (SizeOfWord == 4 && n >> 8 >> 12 >> 12) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF
- )
- error("Constant too big for 32-bit type\n");
- TokenValueInt = (word)n;
- // Unsuffixed (with 'u') integer constants (octal, decimal, hex)
- // fitting into 15(31) out of 16(32) bits are signed ints
- if (!uSuffix &&
- (
- (SizeOfWord == 2 && !(n >> 15)) // equiv. to SizeOfWord == 2 && n <= 0x7FFF
- || (SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF
- )
- )
- return tokNumInt;
- // Unlike octal and hex constants, decimal constants are always
- // a signed type. Error out when a decimal constant doesn't fit
- // into an int since currently there's no next bigger signed type
- // (e.g. long) to use instead of int.
- if (!uSuffix && type == 'd')
- error("Constant too big for 32-bit signed type\n");
- return tokNumUint;
- }
- word GetTokenInner(void)
- {
- char* p = CharQueue;
- word ch = *p;
- word wide = 0;
- // these single-character tokens/operators need no further processing
- if (strchr(",;:()[]{}~?", ch))
- {
- ShiftCharN(1);
- return ch;
- }
- // parse multi-character tokens/operators
- // DONE: other assignment operators
- switch (ch)
- {
- case '+':
- if (p[1] == '+') { ShiftCharN(2); return tokInc; }
- if (p[1] == '=') { ShiftCharN(2); return tokAssignAdd; }
- ShiftCharN(1); return ch;
- case '-':
- if (p[1] == '-') { ShiftCharN(2); return tokDec; }
- if (p[1] == '=') { ShiftCharN(2); return tokAssignSub; }
- if (p[1] == '>') { ShiftCharN(2); return tokArrow; }
- ShiftCharN(1); return ch;
- case '!':
- if (p[1] == '=') { ShiftCharN(2); return tokNEQ; }
- ShiftCharN(1); return ch;
- case '=':
- if (p[1] == '=') { ShiftCharN(2); return tokEQ; }
- ShiftCharN(1); return ch;
- case '<':
- if (p[1] == '=') { ShiftCharN(2); return tokLEQ; }
- if (p[1] == '<') { ShiftCharN(2); if (p[0] != '=') return tokLShift; ShiftCharN(1); return tokAssignLSh; }
- ShiftCharN(1); return ch;
- case '>':
- if (p[1] == '=') { ShiftCharN(2); return tokGEQ; }
- if (p[1] == '>') { ShiftCharN(2); if (p[0] != '=') return tokRShift; ShiftCharN(1); return tokAssignRSh; }
- ShiftCharN(1); return ch;
- case '&':
- if (p[1] == '&') { ShiftCharN(2); return tokLogAnd; }
- if (p[1] == '=') { ShiftCharN(2); return tokAssignAnd; }
- ShiftCharN(1); return ch;
- case '|':
- if (p[1] == '|') { ShiftCharN(2); return tokLogOr; }
- if (p[1] == '=') { ShiftCharN(2); return tokAssignOr; }
- ShiftCharN(1); return ch;
- case '^':
- if (p[1] == '=') { ShiftCharN(2); return tokAssignXor; }
- ShiftCharN(1); return ch;
- case '.':
- if (p[1] == '.' && p[2] == '.') { ShiftCharN(3); return tokEllipsis; }
- ShiftCharN(1); return ch;
- case '*':
- if (p[1] == '=') { ShiftCharN(2); return tokAssignMul; }
- ShiftCharN(1); return ch;
- case '%':
- if (p[1] == '=') { ShiftCharN(2); return tokAssignMod; }
- ShiftCharN(1); return ch;
- case '/':
- if (p[1] == '=') { ShiftCharN(2); return tokAssignDiv; }
- ShiftCharN(1); return ch;
- }
- // DONE: hex and octal constants
- if (isdigit(ch & 0xFFu))
- return GetNumber();
- // parse character and string constants
- if (ch == '\'')
- {
- unsigned v = 0;
- word cnt = 0;
- word max_cnt = SizeOfWord;
- ShiftCharN(1);
- if (strchr("'\n\r", *p))
- //error("Character constant too short\n");
- errorChrStr();
- do
- {
- v <<= 8;
- v |= GetCharValue(wide);
- if (++cnt > max_cnt)
- //error("Character constant too long\n");
- errorChrStr();
- } while (!strchr("'\n\r", *p));
- if (*p != '\'')
- //error("Unsupported or invalid character/string constant\n");
- errorChrStr();
- ShiftCharN(1);
- {
- if (cnt == 1)
- {
- TokenValueInt = v;
- TokenValueInt -= (CharIsSigned && TokenValueInt >= 0x80) * 0x100;
- }
- else
- {
- TokenValueInt = v;
- TokenValueInt -= (SizeOfWord == 2 && TokenValueInt >= 0x8000) * 0x10000;
- }
- return tokNumInt;
- }
- }
- else if (ch == '"')
- {
- // The caller of GetTokenInner()/GetToken() will call GetString('"', wide, 'd')
- // to complete string literal parsing and storing as appropriate
- return tokLitStr;
- }
- return tokEof;
- }
- void Reserve4Expansion(char* name, word len)
- {
- if (MAX_CHAR_QUEUE_LEN - CharQueueLen < len + 1)
- {
- printf("Too long expansion of macro ");
- printf(name);
- error("\n");
- }
- memmove(CharQueue + len + 1, CharQueue, CharQueueLen);
- CharQueue[len] = ' '; // space to avoid concatenation
- CharQueueLen += len + 1;
- }
- // TBD??? implement file I/O for input source code and output code (use fxn ptrs/wrappers to make librarization possible)
- // DONE: support string literals
- word GetToken(void)
- {
- char* p = CharQueue;
- word ch;
- word tok;
- for (;;)
- {
- /* +-~* /% &|^! << >> && || < <= > >= == != () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
- // skip white space and comments
- SkipSpace(1);
- if ((ch = *p) == '\0')
- {
- // done with the current file, drop its record,
- // pick up the including files (if any) or terminate
- if (EndOfFiles())
- break;
- continue;
- }
- if ((tok = GetTokenInner()) != tokEof)
- {
- if (PrepDontSkipTokens)
- return tok;
- if (tok == tokLitStr)
- GetString('"', 0, 0);
- continue;
- }
- // parse identifiers and reserved keywords
- if (ch == '_' || isalpha(ch & 0xFFu))
- {
- word midx;
- GetIdent();
- if (!PrepDontSkipTokens)
- continue;
- tok = GetTokenByWord(TokenIdentName);
- // TBD!!! think of expanding macros in the context of concatenating string literals,
- // maybe factor out this piece of code
- if (!strcmp(TokenIdentName, "__FILE__"))
- {
- char* p = FileNames[FileCnt - 1];
- word len = strlen(p);
- Reserve4Expansion(TokenIdentName, len + 2);
- *CharQueue = '"';
- memcpy(CharQueue + 1, p, len);
- CharQueue[len + 1] = '"';
- continue;
- }
- else if (!strcmp(TokenIdentName, "__LINE__"))
- {
- char s[(2 + CHAR_BIT * sizeof LineNo) / 3];
- char *p = lab2str(s + sizeof s, LineNo);
- word len = s + sizeof s - p;
- Reserve4Expansion(TokenIdentName, len);
- memcpy(CharQueue, p, len);
- continue;
- }
- else if ((midx = FindMacro(TokenIdentName)) >= 0)
- {
- // this is a macro identifier, need to expand it
- word len = MacroTable[midx];
- Reserve4Expansion(TokenIdentName, len);
- memcpy(CharQueue, MacroTable + midx + 1, len);
- continue;
- }
- // treat keywords auto, const, register, restrict and volatile as white space for now
- if ((tok == tokConst) | (tok == tokVolatile) |
- (tok == tokAuto) | (tok == tokRegister) |
- (tok == tokRestrict))
- continue;
- return tok;
- } // endof if (ch == '_' || isalpha(ch))
- // parse preprocessor directives
- if (ch == '#')
- {
- word line = 0;
- ShiftCharN(1);
- // Skip space
- SkipSpace(0);
- // Allow # not followed by a directive
- if (strchr("\r\n", *p))
- continue;
- // Get preprocessor directive
- if (isdigit(*p & 0xFFu))
- {
- // gcc-style #line directive without "line"
- line = 1;
- }
- else
- {
- GetIdent();
- if (!strcmp(TokenIdentName, "line"))
- {
- // C89-style #line directive
- SkipSpace(0);
- if (!isdigit(*p & 0xFFu))
- errorDirective();
- line = 1;
- }
- }
- if (line)
- {
- // Support for external, gcc-like, preprocessor output:
- // # linenum filename flags
- //
- // no flags, flag = 1 -- start of a file
- // flag = 2 -- return to a file after #include
- // other flags -- uninteresting
- // DONE: should also support the following C89 form:
- // # line linenum filename-opt
- if (GetNumber() != tokNumInt)
- //error("Invalid line number in preprocessor output\n");
- errorDirective();
- line = TokenValueInt;
- SkipSpace(0);
- if (*p == '"' || *p == '<')
- {
- if (*p == '"')
- GetString('"', 0, '#');
- else
- GetString('>', 0, '#');
- if (strlen(TokenValueString) > MAX_FILE_NAME_LEN)
- //error("File name too long in preprocessor output\n");
- errorFileName();
- strcpy(FileNames[FileCnt - 1], TokenValueString);
- }
- // Ignore gcc-style #line's flags, if any
- while (!strchr("\r\n", *p))
- ShiftCharN(1);
- LineNo = line - 1; // "line" is the number of the next line
- LinePos = 1;
- continue;
- } // endof if (line)
- if (!strcmp(TokenIdentName, "define"))
- {
- // Skip space and get macro name
- SkipSpace(0);
- GetIdent();
- if (!PrepDontSkipTokens)
- {
- SkipSpace(0);
- while (!strchr("\r\n", *p))
- ShiftCharN(1);
- continue;
- }
- if (FindMacro(TokenIdentName) >= 0)
- {
- printf("Redefinition of macro ");
- printf(TokenIdentName);
- error("\n");
- }
- if (*p == '(')
- //error("Unsupported type of macro '%s'\n", TokenIdentName);
- errorDirective();
- AddMacroIdent(TokenIdentName);
- SkipSpace(0);
- // accumulate the macro expansion text
- while (!strchr("\r\n", *p))
- {
- AddMacroExpansionChar(*p);
- ShiftCharN(1);
- if (*p != '\0' && (strchr(" \t", *p) || (*p == '/' && (p[1] == '/' || p[1] == '*'))))
- {
- SkipSpace(0);
- AddMacroExpansionChar(' ');
- }
- }
- AddMacroExpansionChar('\0');
- continue;
- }
- else if (!strcmp(TokenIdentName, "undef"))
- {
- // Skip space and get macro name
- SkipSpace(0);
- GetIdent();
- if (PrepDontSkipTokens)
- UndefineMacro(TokenIdentName);
- SkipSpace(0);
- if (!strchr("\r\n", *p))
- //error("Invalid preprocessor directive\n");
- errorDirective();
- continue;
- }
- else if (!strcmp(TokenIdentName, "include"))
- {
- word quot;
- // Skip space and get file name
- SkipSpace(0);
- quot = *p;
- if (*p == '"')
- GetString('"', 0, '#');
- else if (*p == '<')
- GetString('>', 0, '#');
- else
- //error("Invalid file name\n");
- errorFileName();
- SkipSpace(0);
- if (!strchr("\r\n", *p))
- //error("Unsupported or invalid preprocessor directive\n");
- errorDirective();
- if (PrepDontSkipTokens)
- IncludeFile(quot);
- continue;
- }
- else if (!strcmp(TokenIdentName, "ifdef"))
- {
- word def;
- // Skip space and get macro name
- SkipSpace(0);
- GetIdent();
- def = FindMacro(TokenIdentName) >= 0;
- SkipSpace(0);
- if (!strchr("\r\n", *p))
- //error("Invalid preprocessor directive\n");
- errorDirective();
- pushPrep(def);
- continue;
- }
- else if (!strcmp(TokenIdentName, "ifndef"))
- {
- word def;
- // Skip space and get macro name
- SkipSpace(0);
- GetIdent();
- def = FindMacro(TokenIdentName) >= 0;
- SkipSpace(0);
- if (!strchr("\r\n", *p))
- //error("Invalid preprocessor directive\n");
- errorDirective();
- pushPrep(!def);
- continue;
- }
- else if (!strcmp(TokenIdentName, "else"))
- {
- word def;
- SkipSpace(0);
- if (!strchr("\r\n", *p))
- //error("Invalid preprocessor directive\n");
- errorDirective();
- def = popPrep();
- if (def >= 2)
- error("#else or #endif without #if(n)def\n");
- pushPrep(2 + !def); // #else works in opposite way to its preceding #if(n)def
- continue;
- }
- else if (!strcmp(TokenIdentName, "endif"))
- {
- SkipSpace(0);
- if (!strchr("\r\n", *p))
- //error("Invalid preprocessor directive\n");
- errorDirective();
- popPrep();
- continue;
- }
- if (!PrepDontSkipTokens)
- {
- // If skipping code and directives under #ifdef/#ifndef/#else,
- // ignore unsupported directives #if, #elif, #error (no error checking)
- if (!strcmp(TokenIdentName, "if"))
- pushPrep(0);
- else if (!strcmp(TokenIdentName, "elif"))
- popPrep(), pushPrep(0);
- SkipLine();
- continue;
- }
- //error("Unsupported or invalid preprocessor directive\n");
- errorDirective();
- } // endof if (ch == '#')
- error("Invalid or unsupported character");
- //error("Invalid or unsupported character with code 0x%02X\n", *p & 0xFFu);
- } // endof for (;;)
- return tokEof;
- }
- void errorRedecl(char* s)
- {
- printf("Invalid or unsupported redeclaration of ");
- printf(s);
- error("\n");
- }
- #include "backend.c"
- // expr.c code
- void push2(word v, word v2)
- {
- if (sp >= STACK_SIZE)
- //error("expression stack overflow!\n");
- errorLongExpr();
- stack[sp][0] = v;
- stack[sp++][1] = v2;
- }
- void push(word v)
- {
- push2(v, 0);
- }
- word stacktop()
- {
- if (sp == 0)
- //error("expression stack underflow!\n");
- errorInternal(3);
- return stack[sp - 1][0];
- }
- word pop2(word* v2)
- {
- word v = stacktop();
- *v2 = stack[sp - 1][1];
- sp--;
- return v;
- }
- void ins2(word pos, word v, word v2)
- {
- if (sp >= STACK_SIZE)
- //error("expression stack overflow!\n");
- errorLongExpr();
- memmove(&stack[pos + 1], &stack[pos], sizeof(stack[0]) * (sp - pos));
- stack[pos][0] = v;
- stack[pos][1] = v2;
- sp++;
- }
- void ins(word pos, word v)
- {
- ins2(pos, v, 0);
- }
- void del(word pos, word cnt)
- {
- memmove(stack[pos],
- stack[pos + cnt],
- sizeof(stack[0]) * (sp - (pos + cnt)));
- sp -= cnt;
- }
- void pushop2(word v, word v2)
- {
- if (opsp >= OPERATOR_STACK_SIZE)
- //error("operator stack overflow!\n");
- errorLongExpr();
- opstack[opsp][0] = v;
- opstack[opsp++][1] = v2;
- }
- void pushop(word v)
- {
- pushop2(v, 0);
- }
- word opstacktop()
- {
- if (opsp == 0)
- //error("operator stack underflow!\n");
- errorInternal(4);
- return opstack[opsp - 1][0];
- }
- word popop2(word* v2)
- {
- word v = opstacktop();
- *v2 = opstack[opsp - 1][1];
- opsp--;
- return v;
- }
- word popop()
- {
- word v2;
- return popop2(&v2);
- }
- word isop(word tok)
- {
- static unsigned char toks[] =
- {
- '!',
- '~',
- '&',
- '*',
- '/', '%',
- '+', '-',
- '|', '^',
- '<', '>',
- '=',
- tokLogOr, tokLogAnd,
- tokEQ, tokNEQ,
- tokLEQ, tokGEQ,
- tokLShift, tokRShift,
- tokInc, tokDec,
- tokSizeof,
- tokAssignMul, tokAssignDiv, tokAssignMod,
- tokAssignAdd, tokAssignSub,
- tokAssignLSh, tokAssignRSh,
- tokAssignAnd, tokAssignXor, tokAssignOr,
- tokComma,
- '?'
- };
- unsigned i;
- for (i = 0; i < division(sizeof toks , sizeof toks[0]); i++)
- if (toks[i] == tok)
- return 1;
- return 0;
- }
- word isunary(word tok)
- {
- return (tok == '!') | (tok == '~') | (tok == tokInc) | (tok == tokDec) | (tok == tokSizeof);
- }
- word preced(word tok)
- {
- switch (tok)
- {
- case '*': case '/': case '%': return 13;
- case '+': case '-': return 12;
- case tokLShift: case tokRShift: return 11;
- case '<': case '>': case tokLEQ: case tokGEQ: return 10;
- case tokEQ: case tokNEQ: return 9;
- case '&': return 8;
- case '^': return 7;
- case '|': return 6;
- case tokLogAnd: return 5;
- case tokLogOr: return 4;
- case '?': case ':': return 3;
- case '=':
- case tokAssignMul: case tokAssignDiv: case tokAssignMod:
- case tokAssignAdd: case tokAssignSub:
- case tokAssignLSh: case tokAssignRSh:
- case tokAssignAnd: case tokAssignXor: case tokAssignOr:
- return 2;
- case tokComma:
- return 1;
- }
- return 0;
- }
- word precedGEQ(word lfttok, word rhttok)
- {
- // DONE: rethink the comma operator as it could be implemented similarly
- // DONE: is this correct:???
- word pl = preced(lfttok);
- word pr = preced(rhttok);
- // ternary/conditional operator ?: is right-associative
- if (pl == 3 && pr >= 3)
- pl = 0;
- // assignment is right-associative
- if (pl == 2 && pr >= 2)
- pl = 0;
- return pl >= pr;
- }
- word expr(word tok, word* gotUnary, word commaSeparator);
- char* lab2str(char* p, word n)
- {
- do
- {
- *--p = '0' + modulo(n , 10);
- n = division(n, 10);
- } while (n);
- return p;
- }
- word exprUnary(word tok, word* gotUnary, word commaSeparator, word argOfSizeOf)
- {
- static word sizeofLevel = 0;
- word decl = 0;
- *gotUnary = 0;
- if (isop(tok) && (isunary(tok) || strchr("&*+-", tok)))
- {
- word lastTok = tok;
- word sizeofLevelInc = lastTok == tokSizeof;
- sizeofLevel += sizeofLevelInc;
- tok = exprUnary(GetToken(), gotUnary, commaSeparator, sizeofLevelInc);
- sizeofLevel -= sizeofLevelInc;
- if (!*gotUnary)
- //error("exprUnary(): primary expression expected after token %s\n", GetTokenName(lastTok));
- errorUnexpectedToken(tok);
- switch (lastTok)
- {
- // DONE: remove all collapsing of all unary operators.
- // It's wrong because type checking must occur before any optimizations.
- // WRONG: DONE: collapse alternating & and * (e.g. "*&*&x" "&*&*x")
- // WRONGISH: DONE: replace prefix ++/-- with +=1/-=1
- case '&':
- push(tokUnaryAnd);
- break;
- case '*':
- push(tokUnaryStar);
- break;
- case '+':
- push(tokUnaryPlus);
- break;
- case '-':
- push(tokUnaryMinus);
- break;
- case '!':
- // replace "!" with "== 0"
- push(tokNumInt);
- push(tokEQ);
- break;
- default:
- push(lastTok);
- break;
- }
- }
- else
- {
- word inspos = sp;
- if (tok == tokNumInt ||
- tok == tokNumUint)
- {
- push2(tok, TokenValueInt);
- *gotUnary = 1;
- tok = GetToken();
- }
- else if (tok == tokLitStr
- )
- {
- word lbl = LabelCnt++;
- word id;
- word ltok = tok;
- word wide = 0;
- unsigned chsz = 1;
- unsigned sz = chsz;
- // imitate definition: char #[len] = "...";
- if (!sizeofLevel)
- {
- if (CurHeaderFooter)
- puts2(CurHeaderFooter[1]);
- puts2(RoDataHeaderFooter[0]);
- GenNumLabel(lbl);
- }
- do
- {
- GetString('"', wide, sizeofLevel ? 0 : 'd'); // throw away string data inside sizeof, e.g. sizeof "a" or sizeof("a" + 1)
- if (sz + TokenStringSize < sz ||
- sz + TokenStringSize >= truncUint(-1))
- errorStrLen();
- sz += TokenStringSize;
- tok = GetToken();
- } while (tok == ltok); // concatenate adjacent string literals
- if (!sizeofLevel)
- {
- GenZeroData(chsz, 0);
- puts2(RoDataHeaderFooter[1]);
- if (CurHeaderFooter)
- puts2(CurHeaderFooter[0]);
- }
- // DONE: can this break incomplete yet declarations???, e.g.: int x[sizeof("az")][5];
- PushSyntax2(tokIdent, id = AddNumericIdent(lbl));
- PushSyntax('[');
- PushSyntax2(tokNumUint, division(sz, chsz));
- PushSyntax(']');
- PushSyntax(tokChar);
- push2(tokIdent, id);
- *gotUnary = 1;
- }
- else if (tok == tokIdent)
- {
- push2(tok, AddIdent(TokenIdentName));
- *gotUnary = 1;
- tok = GetToken();
- }
- else if (tok == '(')
- {
- tok = GetToken();
- decl = TokenStartsDeclaration(tok, 1);
- if (decl)
- {
- word synPtr;
- word lbl = LabelCnt++;
- char s[1 + (2 + CHAR_BIT * sizeof lbl) / 3 + sizeof "<something>" - 1];
- char *p = s + sizeof s;
- tok = ParseDecl(tok, NULL, !argOfSizeOf, 0);
- if (tok != ')')
- //error("exprUnary(): ')' expected, unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- synPtr = FindSymbol("<something>");
- // Rename "<something>" to "<something#>", where # is lbl.
- // This makes the nameless declaration uniquely identifiable by name.
- *--p = '\0';
- *--p = ")>"[argOfSizeOf]; // differentiate casts (something#) from not casts <something#>
- p = lab2str(p, lbl);
- p -= sizeof "<something>" - 2 - 1;
- memcpy(p, "something", sizeof "something" - 1);
- *--p = "(<"[argOfSizeOf]; // differentiate casts (something#) from not casts <something#>
- SyntaxStack1[synPtr] = AddIdent(p);
- tok = GetToken();
- if (argOfSizeOf)
- {
- // expression: sizeof(type)
- *gotUnary = 1;
- }
- else
- {
- // unary type cast operator: (type)
- decl = 0;
- tok = exprUnary(tok, gotUnary, commaSeparator, 0);
- if (!*gotUnary)
- //error("exprUnary(): primary expression expected after '(type)'\n");
- errorUnexpectedToken(tok);
- }
- push2(tokIdent, SyntaxStack1[synPtr]);
- }
- else
- {
- tok = expr(tok, gotUnary, 0);
- if (tok != ')')
- //error("exprUnary(): ')' expected, unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- if (!*gotUnary)
- //error("exprUnary(): primary expression expected in '()'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- }
- while (*gotUnary && !decl)
- {
- // DONE: f(args1)(args2) and the like: need stack order: args2, args1, f, (), ()
- // DONE: reverse the order of evaluation of groups of args in
- // f(args1)(args2)(args3)
- // DONE: reverse the order of function argument evaluation for variadic functions
- // we want 1st arg to be the closest to the stack top.
- // DONE: (args)[index] can be repeated interchangeably indefinitely
- // DONE: (expr)() & (expr)[]
- // DONE: [index] can be followed by ++/--, which can be followed by [index] and so on...
- // DONE: postfix ++/-- & differentiate from prefix ++/--
- if (tok == '(')
- {
- word acnt = 0;
- ins(inspos, '(');
- for (;;)
- {
- word pos2 = sp;
- tok = GetToken();
- tok = expr(tok, gotUnary, 1);
- // Reverse the order of argument evaluation, which is important for
- // variadic functions like printf():
- // we want 1st arg to be the closest to the stack top.
- // This also reverses the order of evaluation of all groups of
- // arguments.
- while (pos2 < sp)
- {
- // TBD??? not quite efficient
- word v, v2;
- v = pop2(&v2);
- ins2(inspos + 1, v, v2);
- pos2++;
- }
- if (tok == ',')
- {
- if (!*gotUnary)
- //error("exprUnary(): primary expression (fxn argument) expected before ','\n");
- errorUnexpectedToken(tok);
- acnt++;
- ins(inspos + 1, ','); // helper argument separator (hint for expression evaluator)
- continue; // off to next arg
- }
- if (tok == ')')
- {
- if (acnt && !*gotUnary)
- //error("exprUnary(): primary expression (fxn argument) expected between ',' and ')'\n");
- errorUnexpectedToken(tok);
- *gotUnary = 1; // don't fail for 0 args in ()
- break; // end of args
- }
- // DONE: think of inserting special arg pseudo tokens for verification purposes
- //error("exprUnary(): ',' or ')' expected, unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- } // endof for(;;) for fxn args
- push(')');
- }
- else if (tok == '[')
- {
- tok = GetToken();
- tok = expr(tok, gotUnary, 0);
- if (!*gotUnary)
- //error("exprUnary(): primary expression expected in '[]'\n");
- errorUnexpectedToken(tok);
- if (tok != ']')
- //error("exprUnary(): ']' expected, unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- // TBD??? add implicit casts to size_t of array indicies.
- // E1[E2] -> *(E1 + E2)
- // push('[');
- push('+');
- push(tokUnaryStar);
- }
- // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1
- else if (tok == tokInc)
- {
- push(tokPostInc);
- }
- else if (tok == tokDec)
- {
- push(tokPostDec);
- }
- else if (tok == '.' || tok == tokArrow)
- {
- // transform a.b into (&a)->b
- if (tok == '.')
- push(tokUnaryAnd);
- tok = GetToken();
- if (tok != tokIdent)
- errorUnexpectedToken(tok);
- push2(tok, AddIdent(TokenIdentName));
- // "->" in "a->b" will function as "+" in "*(type_of_b*)((char*)a + offset_of_b_in_a)"
- push(tokArrow);
- push(tokUnaryStar);
- }
- else
- {
- break;
- }
- tok = GetToken();
- } // endof while (*gotUnary)
- }
- if (tok == ',' && !commaSeparator)
- tok = tokComma;
- return tok;
- }
- word expr(word tok, word* gotUnary, word commaSeparator)
- {
- *gotUnary = 0;
- pushop(tokEof);
- tok = exprUnary(tok, gotUnary, commaSeparator, 0);
- while (tok != tokEof && strchr(",;:)]}", tok) == NULL && *gotUnary)
- {
- if (isop(tok) && !isunary(tok))
- {
- while (precedGEQ(opstacktop(), tok))
- {
- word v, v2;
- v = popop2(&v2);
- // move ?expr: as a whole to the expression stack as "expr?"
- if (v == '?')
- {
- word cnt = v2;
- while (cnt--)
- {
- v = popop2(&v2);
- push2(v, v2);
- }
- v = '?';
- v2 = 0;
- }
- push2(v, v2);
- }
- // here: preced(postacktop()) < preced(tok)
- // treat the ternary/conditional operator ?expr: as a pseudo binary operator
- if (tok == '?')
- {
- word ssp = sp;
- word cnt;
- tok = expr(GetToken(), gotUnary, 0);
- if (!*gotUnary || tok != ':')
- errorUnexpectedToken(tok);
- // move ?expr: as a whole to the operator stack
- // this is beautiful and ugly at the same time
- cnt = sp - ssp;
- while (sp > ssp)
- {
- word v, v2;
- v = pop2(&v2);
- pushop2(v, v2);
- }
- // remember the length of the expression between ? and :
- pushop2('?', cnt);
- }
- else
- {
- pushop(tok);
- }
- tok = exprUnary(GetToken(), gotUnary, commaSeparator, 0);
- // DONE: figure out a check to see if exprUnary() fails to add a rhs operand
- if (!*gotUnary)
- //error("expr(): primary expression expected after token %s\n", GetTokenName(lastTok));
- errorUnexpectedToken(tok);
- continue;
- }
- //error("expr(): Unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- }
- while (opstacktop() != tokEof)
- {
- word v, v2;
- v = popop2(&v2);
- // move ?expr: as a whole to the expression stack as "expr?"
- if (v == '?')
- {
- word cnt = v2;
- while (cnt--)
- {
- v = popop2(&v2);
- push2(v, v2);
- }
- v = '?';
- v2 = 0;
- }
- push2(v, v2);
- }
- popop();
- return tok;
- }
- word isAnyPtr(word ExprTypeSynPtr)
- {
- if (ExprTypeSynPtr < 0)
- return 1;
- switch (SyntaxStack0[ExprTypeSynPtr])
- {
- case '*':
- case '[':
- case '(':
- return 1;
- }
- return 0;
- }
- word derefAnyPtr(word ExprTypeSynPtr)
- {
- if (ExprTypeSynPtr < 0)
- return -ExprTypeSynPtr;
- switch (SyntaxStack0[ExprTypeSynPtr])
- {
- case '*':
- return ExprTypeSynPtr + 1;
- case '[':
- return ExprTypeSynPtr + 3;
- case '(':
- return ExprTypeSynPtr;
- }
- errorInternal(22);
- return -1;
- }
- void decayArray(word* ExprTypeSynPtr, word arithmetic)
- {
- // Dacay arrays to pointers to their first elements
- if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == '[')
- {
- (*ExprTypeSynPtr) += 3;
- // we cannot insert another '*' into the type to make it a pointer
- // to the first element, so make the index into the type negative
- *ExprTypeSynPtr = -*ExprTypeSynPtr;
- }
- // DONE: disallow arithmetic on pointers to void
- // DONE: disallow function pointers
- if (arithmetic && isAnyPtr(*ExprTypeSynPtr))
- {
- word pointee = derefAnyPtr(*ExprTypeSynPtr);
- switch (SyntaxStack0[pointee])
- {
- case tokVoid:
- //error("decayArray(): cannot do pointer arithmetic on a pointer to 'void'\n");
- errorUnexpectedVoid();
- default:
- //error("decayArray(): cannot do pointer arithmetic on a pointer to an incomplete type\n");
- if (!GetDeclSize(pointee, 0))
- // "fallthrough"
- case '(':
- //error("decayArray(): cannot do pointer arithmetic on a pointer to a function\n");
- errorOpType();
- }
- }
- }
- void lvalueCheck(word ExprTypeSynPtr, word pos)
- {
- if (ExprTypeSynPtr >= 0 &&
- (SyntaxStack0[ExprTypeSynPtr] == '[' || SyntaxStack0[ExprTypeSynPtr] == '('))
- {
- // we can have arrays formed by dereference, e.g.
- // char (*pac)[1]; // *pac is array of 1 char
- // // ++*pac or (*pac)-- are not allowed
- // and likewise functions, e.g.
- // int (*pf)(int); // *pf is a function taking int and returning int
- // // *pf = 0; is not allowed
- // and that dereference shouldn't be confused for lvalue,
- // hence explicitly checking for array and function types
- //error("exprval(): lvalue expected\n");
- errorNotLvalue();
- }
- // lvalue is a dereferenced address, check for a dereference
- if (stack[pos][0] != tokUnaryStar)
- //error("exprval(): lvalue expected\n");
- errorNotLvalue();
- }
- void nonVoidTypeCheck(word ExprTypeSynPtr)
- {
- if (ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokVoid)
- //error("nonVoidTypeCheck(): unexpected operand type 'void' for operator '%s'\n", GetTokenName(tok));
- errorUnexpectedVoid();
- }
- void scalarTypeCheck(word ExprTypeSynPtr)
- {
- nonVoidTypeCheck(ExprTypeSynPtr);
- if (ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokStructPtr)
- errorOpType();
- }
- void numericTypeCheck(word ExprTypeSynPtr)
- {
- if (ExprTypeSynPtr >= 0)
- switch (SyntaxStack0[ExprTypeSynPtr])
- {
- case tokChar:
- case tokSChar:
- case tokUChar:
- case tokShort:
- case tokUShort:
- case tokInt:
- case tokUnsigned:
- return;
- }
- //error("numericTypeCheck(): unexpected operand type for operator '%s', numeric type expected\n", GetTokenName(tok));
- errorOpType();
- }
- void anyIntTypeCheck(word ExprTypeSynPtr)
- {
- // Check for any integer type
- numericTypeCheck(ExprTypeSynPtr);
- }
- word isUint(word ExprTypeSynPtr)
- {
- return ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokUnsigned;
- }
- void compatCheck(word* ExprTypeSynPtr, word TheOtherExprTypeSynPtr, word ConstExpr[2], word lidx, word ridx)
- {
- word exprTypeSynPtr = *ExprTypeSynPtr;
- word c = 0;
- word lptr, rptr, lnum, rnum;
- // (un)decay/convert functions to pointers to functions
- // and to simplify matters convert all '*' pointers to negative type indices
- if (exprTypeSynPtr >= 0)
- {
- switch (SyntaxStack0[exprTypeSynPtr])
- {
- case '*':
- exprTypeSynPtr++;
- // fallthrough
- case '(':
- exprTypeSynPtr = -exprTypeSynPtr;
- }
- *ExprTypeSynPtr = exprTypeSynPtr;
- }
- if (TheOtherExprTypeSynPtr >= 0)
- {
- switch (SyntaxStack0[TheOtherExprTypeSynPtr])
- {
- case '*':
- TheOtherExprTypeSynPtr++;
- // fallthrough
- case '(':
- TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr;
- }
- }
- lptr = exprTypeSynPtr < 0;
- rptr = TheOtherExprTypeSynPtr < 0;
- lnum = !lptr && (SyntaxStack0[exprTypeSynPtr] == tokInt ||
- SyntaxStack0[exprTypeSynPtr] == tokUnsigned);
- rnum = !rptr && (SyntaxStack0[TheOtherExprTypeSynPtr] == tokInt ||
- SyntaxStack0[TheOtherExprTypeSynPtr] == tokUnsigned);
- // both operands have arithmetic type
- // (arithmetic operands have been already promoted):
- if (lnum && rnum)
- return;
- // both operands have void type:
- if (!lptr && SyntaxStack0[exprTypeSynPtr] == tokVoid &&
- !rptr && SyntaxStack0[TheOtherExprTypeSynPtr] == tokVoid)
- return;
- // one operand is a pointer and the other is NULL constant
- // ((void*)0 is also a valid null pointer constant),
- // the type of the expression is that of the pointer:
- if (lptr &&
- ((rnum && ConstExpr[1] && truncInt(stack[ridx][1]) == 0) ||
- (rptr && SyntaxStack0[-TheOtherExprTypeSynPtr] == tokVoid &&
- (stack[ridx][0] == tokNumInt || stack[ridx][0] == tokNumUint) &&
- truncInt(stack[ridx][1]) == 0)))
- return;
- if (rptr &&
- ((lnum && ConstExpr[0] && truncInt(stack[lidx][1]) == 0) ||
- (lptr && SyntaxStack0[-exprTypeSynPtr] == tokVoid &&
- (stack[lidx][0] == tokNumInt || stack[lidx][0] == tokNumUint) &&
- truncInt(stack[lidx][1]) == 0)))
- {
- *ExprTypeSynPtr = TheOtherExprTypeSynPtr;
- return;
- }
- // not expecting non-pointers beyond this point
- if (!(lptr && rptr))
- errorOpType();
- // one operand is a pointer and the other is a pointer to void
- // (except (void*)0 (AKA NULL), which is different from other pointers to void),
- // the type of the expression is pointer to void:
- if (SyntaxStack0[-exprTypeSynPtr] == tokVoid)
- return;
- if (SyntaxStack0[-TheOtherExprTypeSynPtr] == tokVoid)
- {
- *ExprTypeSynPtr = TheOtherExprTypeSynPtr;
- return;
- }
- // both operands are pointers to compatible types:
- if (exprTypeSynPtr == TheOtherExprTypeSynPtr)
- return;
- exprTypeSynPtr = -exprTypeSynPtr;
- TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr;
- for (;;)
- {
- word tok = SyntaxStack0[exprTypeSynPtr];
- if (tok != SyntaxStack0[TheOtherExprTypeSynPtr])
- errorOpType();
- if (tok != tokIdent &&
- SyntaxStack1[exprTypeSynPtr] != SyntaxStack1[TheOtherExprTypeSynPtr])
- errorOpType();
- c += (tok == '(') - (tok == ')') + (tok == '[') - (tok == ']');
- if (!c)
- {
- switch (tok)
- {
- case tokVoid:
- case tokChar: case tokSChar: case tokUChar:
- case tokShort: case tokUShort:
- case tokInt: case tokUnsigned:
- case tokStructPtr:
- return;
- }
- }
- exprTypeSynPtr++;
- TheOtherExprTypeSynPtr++;
- }
- }
- void shiftCountCheck(word *psr, word idx, word ExprTypeSynPtr)
- {
- word sr = *psr;
- // can't shift by a negative count and by a count exceeding
- // the number of bits in int
- if ((SyntaxStack0[ExprTypeSynPtr] != tokUnsigned && sr < 0) ||
- (unsigned)sr >= CHAR_BIT * sizeof(word) ||
- (unsigned)sr >= 8u * SizeOfWord)
- {
- //error("exprval(): Invalid shift count\n");
- warning("Shift count out of range\n");
- // truncate the count, so the assembler doesn't get an invalid count
- sr &= SizeOfWord * 8 - 1;
- *psr = sr;
- stack[idx][1] = sr;
- }
- }
- word divCheckAndCalc(word tok, word* psl, word sr, word Unsigned, word ConstExpr[2])
- {
- word div0 = 0;
- word sl = *psl;
- word int_min = INT_MIN;
- if (!ConstExpr[1])
- return !div0;
- if (Unsigned)
- {
- sl = (word)truncUint(sl);
- sr = (word)truncUint(sr);
- }
- else
- {
- sl = truncInt(sl);
- sr = truncInt(sr);
- }
- if (sr == 0)
- {
- div0 = 1;
- }
- else if (!ConstExpr[0])
- {
- return !div0;
- }
- else if (!Unsigned && ((sl == int_min && sr == -1) || division(sl , sr) != truncInt(division(sl , sr))))
- {
- div0 = 1;
- }
- else
- {
- if (Unsigned)
- {
- if (tok == '/')
- sl = (word)((unsigned)division(sl , sr));
- else
- sl = (word)((unsigned)modulo(sl , sr));
- }
- else
- {
- // TBD!!! C89 gives freedom in how exactly division of negative integers
- // can be implemented w.r.t. rounding and w.r.t. the sign of the remainder.
- // A stricter, C99-conforming implementation, non-dependent on the
- // compiler used to compile Smaller C is needed.
- if (tok == '/')
- sl = division(sl, sr);
- else
- sl = modulo(sl, sr);
- }
- *psl = sl;
- }
- if (div0)
- warning("Division by 0 or division overflow\n");
- return !div0;
- }
- void promoteType(word* ExprTypeSynPtr, word* TheOtherExprTypeSynPtr)
- {
- // Integer promotion to signed int or unsigned int from smaller types
- // (all kinds of char and short). Promotion to unsigned int occurs
- // only if the other operand (of a binary operator) is already an
- // unsigned int. Effectively, this promotion to unsigned int performs
- // usual arithmetic conversion for integers.
- if (*ExprTypeSynPtr >= 0)
- {
- // chars must be promoted to ints in expressions as the very first thing
- switch (SyntaxStack0[*ExprTypeSynPtr])
- {
- case tokChar:
- case tokShort:
- case tokUShort:
- case tokSChar:
- case tokUChar:
- *ExprTypeSynPtr = SymIntSynPtr;
- }
- if (*TheOtherExprTypeSynPtr >= 0)
- {
- // ints must be converted to unsigned ints if they are used in binary
- // operators whose other operand is unsigned int (except <<,>>,<<=,>>=)
- if (SyntaxStack0[*ExprTypeSynPtr] == tokInt &&
- SyntaxStack0[*TheOtherExprTypeSynPtr] == tokUnsigned)
- *ExprTypeSynPtr = SymUintSynPtr;
- }
- }
- }
- word GetFxnInfo(word ExprTypeSynPtr, word* MinParams, word* MaxParams, word* ReturnExprTypeSynPtr, word* FirstParamSynPtr)
- {
- *MaxParams = *MinParams = 0;
- if (ExprTypeSynPtr < 0)
- {
- ExprTypeSynPtr = -ExprTypeSynPtr;
- }
- else
- {
- while (SyntaxStack0[ExprTypeSynPtr] == tokIdent || SyntaxStack0[ExprTypeSynPtr] == tokLocalOfs)
- ExprTypeSynPtr++;
- if (SyntaxStack0[ExprTypeSynPtr] == '*')
- ExprTypeSynPtr++;
- }
- if (SyntaxStack0[ExprTypeSynPtr] != '(')
- return 0;
- // DONE: return syntax pointer to the function's return type
- // Count params
- ExprTypeSynPtr++;
- if (FirstParamSynPtr)
- *FirstParamSynPtr = ExprTypeSynPtr;
- if (SyntaxStack0[ExprTypeSynPtr] == ')')
- {
- // "fxn()": unspecified parameters, so, there can be any number of them
- *MaxParams = 32767; // INT_MAX;
- *ReturnExprTypeSynPtr = ExprTypeSynPtr + 1;
- return 1;
- }
- if (SyntaxStack0[ExprTypeSynPtr + 1] == tokVoid)
- {
- // "fxn(void)": 0 parameters
- *ReturnExprTypeSynPtr = ExprTypeSynPtr + 3;
- return 1;
- }
- for (;;)
- {
- word tok = SyntaxStack0[ExprTypeSynPtr];
- if (tok == tokIdent)
- {
- if (SyntaxStack0[ExprTypeSynPtr + 1] != tokEllipsis)
- {
- ++*MinParams;
- ++*MaxParams;
- }
- else
- {
- *MaxParams = 32767; // INT_MAX;
- }
- }
- else if (tok == '(')
- {
- // skip parameters in parameters
- word c = 1;
- while (c && ExprTypeSynPtr < SyntaxStackCnt)
- {
- tok = SyntaxStack0[++ExprTypeSynPtr];
- c += (tok == '(') - (tok == ')');
- }
- }
- else if (tok == ')')
- {
- ExprTypeSynPtr++;
- break;
- }
- ExprTypeSynPtr++;
- }
- // get the function's return type
- *ReturnExprTypeSynPtr = ExprTypeSynPtr;
- return 1;
- }
- void simplifyConstExpr(word val, word isConst, word* ExprTypeSynPtr, word top, word bottom)
- {
- // If non-const, nothing to do.
- // If const and already a number behind the scenes, nothing to do
- // (val must not differ from the number!).
- if (!isConst || stack[top][0] == tokNumInt || stack[top][0] == tokNumUint)
- return;
- // Const, but not a number yet. Reduce to a number equal val.
- if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned)
- stack[top][0] = tokNumUint;
- else
- stack[top][0] = tokNumInt;
- stack[top][1] = val;
- del(bottom, top - bottom);
- }
- word AllocLocal(unsigned size)
- {
- // Let's calculate variable's relative on-stack location
- word oldOfs = CurFxnLocalOfs;
- // Note: local vars are word-aligned on the stack
- CurFxnLocalOfs = (word)((CurFxnLocalOfs - size) & ~(SizeOfWord - 1u));
- if (CurFxnLocalOfs >= oldOfs ||
- CurFxnLocalOfs != truncInt(CurFxnLocalOfs) ||
- (unsigned int)CurFxnLocalOfs < (unsigned int) (-GenMaxLocalsSize()))
- //error("AllocLocal(): Local variables take too much space\n");
- {
- //printf("a");
- errorVarSize();
- }
-
- if (CurFxnMinLocalOfs > CurFxnLocalOfs)
- CurFxnMinLocalOfs = CurFxnLocalOfs;
- return CurFxnLocalOfs;
- }
- // DONE: sizeof(type)
- // DONE: "sizeof expr"
- // DONE: constant expressions
- // DONE: collapse constant subexpressions into constants
- word exprval(word* idx, word* ExprTypeSynPtr, word* ConstExpr)
- {
- word tok;
- word s;
- word RightExprTypeSynPtr;
- word oldIdxRight;
- word oldSpRight;
- word constExpr[3];
- if (*idx < 0)
- //error("exprval(): idx < 0\n");
- errorInternal(5);
- tok = stack[*idx][0];
- s = stack[*idx][1];
- --*idx;
- oldIdxRight = *idx;
- oldSpRight = sp;
- switch (tok)
- {
- // Constants
- case tokNumInt:
- // return the constant's type: int
- *ExprTypeSynPtr = SymIntSynPtr;
- *ConstExpr = 1;
- break;
- case tokNumUint:
- // return the constant's type: unsigned int
- *ExprTypeSynPtr = SymUintSynPtr;
- *ConstExpr = 1;
- break;
- // Identifiers
- case tokIdent:
- {
- // DONE: support __func__
- char* ident = IdentTable + s;
- word synPtr, type;
- {
- synPtr = FindSymbol(ident);
- // "Rename" static vars in function scope
- if (synPtr >= 0 && synPtr + 1 < SyntaxStackCnt && SyntaxStack0[synPtr + 1] == tokIdent)
- {
- s = stack[*idx + 1][1] = SyntaxStack1[++synPtr];
- ident = IdentTable + s;
- }
- }
- if (synPtr < 0)
- {
- if ((*idx + 2 >= sp) || stack[*idx + 2][0] != ')')
- {
- printf("Undeclared identifier ");
- error(ident);
- }
- else
- {
- // silent this warning for now, since it seems to trigger false positives
- //printf("Call to undeclared function ");
- //warning(ident);
- // Implicitly declare "extern int ident();"
- PushSyntax2(tokIdent, s);
- PushSyntax('(');
- PushSyntax(')');
- PushSyntax(tokInt);
- synPtr = FindSymbol(ident);
- }
- }
- // DONE: this declaration is actually a type cast
- if (!strncmp(IdentTable + SyntaxStack1[synPtr], "(something", sizeof "(something)" - 1 - 1))
- {
- word castSize;
- if (SyntaxStack0[++synPtr] == tokLocalOfs) // TBD!!! is this really needed???
- synPtr++;
- s = exprval(idx, ExprTypeSynPtr, ConstExpr);
- // can't cast void or structure/union to anything (except void)
- if (*ExprTypeSynPtr >= 0 &&
- (SyntaxStack0[*ExprTypeSynPtr] == tokVoid ||
- SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) &&
- SyntaxStack0[synPtr] != tokVoid)
- errorOpType();
- // can't cast to function, array or structure/union
- if (SyntaxStack0[synPtr] == '(' ||
- SyntaxStack0[synPtr] == '[' ||
- SyntaxStack0[synPtr] == tokStructPtr)
- errorOpType();
- // will try to propagate constants through casts
- if (!*ConstExpr &&
- (stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumInt ||
- stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumUint))
- {
- s = stack[oldIdxRight - (oldSpRight - sp)][1];
- *ConstExpr = 1;
- }
- castSize = GetDeclSize(synPtr, 1); // 0 for cast to void
- // insertion of tokUChar, tokSChar and tokUnaryPlus transforms
- // lvalues (values formed by dereferences) into rvalues
- // (by hiding the dereferences), just as casts should do
- switch (castSize)
- {
- case 1:
- // cast to unsigned char
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUChar;
- s &= 0xFFu;
- break;
- case -1:
- // cast to signed char
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokSChar;
- if ((s &= 0xFFu) >= 0x80)
- s -= 0x100;
- break;
- default:
- if (castSize && castSize != SizeOfWord)
- {
- // cast not to void and not to word-sized type (int/unsigned/pointer/float)
- if (castSize == 2)
- {
- // cast to unsigned short
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUShort;
- s &= 0xFFFFu;
- }
- else
- {
- // cast to signed short
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokShort;
- if ((s &= 0xFFFFu) >= 0x8000)
- s -= 0x10000;
- }
- }
- else // fallthrough
- {
- // cast to void or word-sized type (int/unsigned/pointer/float)
- if (stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar)
- // hide the dereference
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus;
- }
- break;
- }
- if (*ConstExpr)
- stack[oldIdxRight - (oldSpRight - sp)][1] = s;
- *ExprTypeSynPtr = synPtr;
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- if (!*ConstExpr && stack[oldIdxRight + 1 - (oldSpRight - sp)][0] == tokIdent)
- // nothing to hide, remove the cast
- del(oldIdxRight + 1 - (oldSpRight - sp), 1);
- switch (SyntaxStack0[synPtr])
- {
- case tokChar:
- case tokSChar:
- case tokUChar:
- case tokShort:
- case tokUShort:
- case tokInt:
- case tokUnsigned:
- break;
- default:
- // only numeric types can be const
- *ConstExpr = 0;
- break;
- }
- break;
- }
- // Finally, not __func__, not enum, not cast.
- type = SymType(synPtr);
- if (type == SymLocalVar || type == SymLocalArr)
- {
- // replace local variables/arrays with their local addresses
- // (global variables/arrays' addresses are their names)
- stack[*idx + 1][0] = tokLocalOfs;
- stack[*idx + 1][1] = SyntaxStack1[synPtr + 1];
- }
- if (type == SymLocalVar || type == SymGlobalVar)
- {
- // add implicit dereferences for local/global variables
- ins2(*idx + 2, tokUnaryStar, GetDeclSize(synPtr, 1));
- }
- // return the identifier's type
- while (SyntaxStack0[synPtr] == tokIdent || SyntaxStack0[synPtr] == tokLocalOfs)
- synPtr++;
- *ExprTypeSynPtr = synPtr;
- }
- *ConstExpr = 0;
- break;
- // sizeof operator
- case tokSizeof:
- exprval(idx, ExprTypeSynPtr, ConstExpr);
- s = GetDeclSize(*ExprTypeSynPtr, 0);
- if (s == 0)
- error("sizeof of incomplete type\n");
- // replace sizeof with its numeric value
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokNumUint;
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = s;
- // remove the sizeof's subexpression
- del(*idx + 1, oldIdxRight - (oldSpRight - sp) - *idx);
- *ExprTypeSynPtr = SymUintSynPtr;
- *ConstExpr = 1;
- break;
- // Address unary operator
- case tokUnaryAnd:
- exprval(idx, ExprTypeSynPtr, ConstExpr);
- if (*ExprTypeSynPtr >= 0 &&
- (SyntaxStack0[*ExprTypeSynPtr] == '[' || SyntaxStack0[*ExprTypeSynPtr] == '('))
- {
- // convert an array into a pointer to the array,
- // convert a function into a pointer to the function,
- // remove the reference
- del(oldIdxRight + 1 - (oldSpRight - sp), 1);
- }
- else if (*ExprTypeSynPtr >= 0 &&
- stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar)
- {
- // it's an lvalue (with implicit or explicit dereference),
- // convert it into its address by
- // collapsing/removing the reference and the dereference
- del(oldIdxRight - (oldSpRight - sp), 2);
- }
- else
- //error("exprval(): lvalue expected after '&'\n");
- errorNotLvalue();
- // we cannot insert another '*' into the type to make it a pointer
- // to an array/function/etc, so make the index into the type negative
- *ExprTypeSynPtr = -*ExprTypeSynPtr;
- *ConstExpr = 0;
- break;
- // Indirection unary operator
- case tokUnaryStar:
- exprval(idx, ExprTypeSynPtr, ConstExpr);
- if (*ExprTypeSynPtr < 0 || SyntaxStack0[*ExprTypeSynPtr] == '*')
- {
- // type is a pointer to something,
- // transform it into that something
- if (*ExprTypeSynPtr < 0)
- *ExprTypeSynPtr = -*ExprTypeSynPtr;
- else
- ++*ExprTypeSynPtr;
- nonVoidTypeCheck(*ExprTypeSynPtr);
- if (SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr && !GetDeclSize(*ExprTypeSynPtr, 0))
- // incomplete structure/union type
- errorOpType();
- // remove the dereference if that something is an array or a function
- if (SyntaxStack0[*ExprTypeSynPtr] == '[' ||
- SyntaxStack0[*ExprTypeSynPtr] == '(')
- del(oldIdxRight + 1 - (oldSpRight - sp), 1);
- // else attach dereference size in bytes
- else
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1);
- }
- else if (SyntaxStack0[*ExprTypeSynPtr] == '[')
- {
- // type is an array,
- // transform it into the array's first element
- // (a subarray, if type is a multidimensional array)
- (*ExprTypeSynPtr) += 3;
- // remove the dereference if that element is an array
- if (SyntaxStack0[*ExprTypeSynPtr] == '[')
- del(oldIdxRight + 1 - (oldSpRight - sp), 1);
- // else attach dereference size in bytes
- else
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1);
- }
- else
- //error("exprval(): pointer/array expected after '*' / before '[]'\n");
- errorOpType();
- *ConstExpr = 0;
- break;
- // Additive binary operators
- case '+':
- case '-':
- // WRONGISH: DONE: replace prefix ++/-- with +=1/-=1
- // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1
- {
- word ptrmask;
- word oldIdxLeft, oldSpLeft;
- word sl, sr;
- word incSize;
- sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- oldIdxLeft = *idx;
- oldSpLeft = sp;
- sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- // Decay arrays to pointers to their first elements
- // and ensure that the pointers are suitable for pointer arithmetic
- // (not pointers to functions, sizes of pointees are known and non-zero)
- decayArray(&RightExprTypeSynPtr, 1);
- decayArray(ExprTypeSynPtr, 1);
- // Bar void and struct/union
- scalarTypeCheck(RightExprTypeSynPtr);
- scalarTypeCheck(*ExprTypeSynPtr);
- ptrmask = isAnyPtr(RightExprTypeSynPtr) + isAnyPtr(*ExprTypeSynPtr) * 2;
- // DONE: index/subscript scaling
- if (ptrmask == 1 && tok == '+') // pointer in right-hand expression
- {
- incSize = GetDeclSize(derefAnyPtr(RightExprTypeSynPtr), 0);
- if (constExpr[0]) // integer constant in left-hand expression
- {
- s = (word)((unsigned)sl * incSize);
- stack[oldIdxLeft - (oldSpLeft - sp)][1] = s;
- // optimize a little if possible
- {
- word i = oldIdxRight - (oldSpRight - sp);
- // Skip any type cast markers
- while (stack[i][0] == tokUnaryPlus || stack[i][0] == '+')
- i--;
- // See if the pointer is an integer constant or a local variable offset
- // and if it is, adjust it here instead of generating code for
- // addition/subtraction
- if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs)
- {
- s = (word)((unsigned)stack[i][1] + s);
- stack[i][1] = s; // TBD!!! need extra truncation?
- del(oldIdxLeft - (oldSpLeft - sp), 1);
- del(oldIdxRight - (oldSpRight - sp) + 1, 1);
- }
- }
- }
- else if (incSize != 1)
- {
- ins2(oldIdxLeft + 1 - (oldSpLeft - sp), tokNumInt, incSize);
- ins(oldIdxLeft + 1 - (oldSpLeft - sp), '*');
- }
- *ExprTypeSynPtr = RightExprTypeSynPtr;
- }
- else if (ptrmask == 2) // pointer in left-hand expression
- {
- incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
- if (constExpr[1]) // integer constant in right-hand expression
- {
- s = (word)((unsigned)sr * incSize);
- stack[oldIdxRight - (oldSpRight - sp)][1] = s;
- // optimize a little if possible
- {
- word i = oldIdxLeft - (oldSpLeft - sp);
- // Skip any type cast markers
- while (stack[i][0] == tokUnaryPlus || stack[i][0] == '+')
- i--;
- // See if the pointer is an integer constant or a local variable offset
- // and if it is, adjust it here instead of generating code for
- // addition/subtraction
- if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs)
- {
- if (tok == '-')
- s = (word)~(s - 1u);
- s = (word)((unsigned)stack[i][1] + s);
- stack[i][1] = s; // TBD!!! need extra truncation?
- del(oldIdxRight - (oldSpRight - sp), 2);
- }
- }
- }
- else if (incSize != 1)
- {
- ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize);
- ins(oldIdxRight + 1 - (oldSpRight - sp), '*');
- }
- }
- else if (ptrmask == 3 && tok == '-') // pointers in both expressions
- {
- incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
- // TBD!!! "ptr1-ptr2": better pointer type compatibility test needed, like compatCheck()?
- if (incSize != GetDeclSize(derefAnyPtr(RightExprTypeSynPtr), 0))
- //error("exprval(): incompatible pointers\n");
- errorOpType();
- if (incSize != 1)
- {
- ins2(oldIdxRight + 2 - (oldSpRight - sp), tokNumInt, incSize);
- ins(oldIdxRight + 2 - (oldSpRight - sp), '/');
- }
- *ExprTypeSynPtr = SymIntSynPtr;
- }
- else if (ptrmask)
- //error("exprval(): invalid combination of operands for '+' or '-'\n");
- errorOpType();
- // Promote the result from char to int (and from int to unsigned) if necessary
- promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr);
- *ConstExpr = constExpr[0] && constExpr[1];
- {
- if (tok == '+')
- s = (word)((unsigned)sl + sr);
- else
- s = (word)((unsigned)sl - sr);
- }
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- }
- break;
- // Prefix/postfix increment/decrement unary operators
- case tokInc:
- case tokDec:
- case tokPostInc:
- case tokPostDec:
- {
- word incSize = 1;
- word inc = tok == tokInc || tok == tokPostInc;
- word post = tok == tokPostInc || tok == tokPostDec;
- word opSize;
- exprval(idx, ExprTypeSynPtr, ConstExpr);
- lvalueCheck(*ExprTypeSynPtr, oldIdxRight - (oldSpRight - sp));
- // if it's a pointer, ensure that it's suitable for pointer arithmetic
- // (not pointer to function, pointee size is known and non-zero)
- decayArray(ExprTypeSynPtr, 1); // no actual decay here, just a type check
- // Bar void and struct/union
- scalarTypeCheck(*ExprTypeSynPtr);
- // "remove" the lvalue dereference as we don't need
- // to read the value while forgetting its location.
- // We need to keep the lvalue location.
- // Remember the operand size.
- opSize = stack[oldIdxRight - (oldSpRight - sp)][1];
- del(oldIdxRight - (oldSpRight - sp), 1);
- if (isAnyPtr(*ExprTypeSynPtr))
- incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
- if (incSize == 1)
- {
- // store the operand size in the operator
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
- }
- else
- {
- // replace ++/-- with "postfix" +=/-= incSize when incSize != 1
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] =
- inc ? (post ? tokPostAdd : tokAssignAdd) :
- (post ? tokPostSub : tokAssignSub);
- // store the operand size in the operator
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
- ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize);
- }
- *ConstExpr = 0;
- }
- break;
- // Simple assignment binary operator
- case '=':
- {
- word oldIdxLeft, oldSpLeft;
- word opSize;
- word structs;
- exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- oldIdxLeft = *idx;
- oldSpLeft = sp;
- exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- lvalueCheck(*ExprTypeSynPtr, oldIdxLeft - (oldSpLeft - sp));
- nonVoidTypeCheck(RightExprTypeSynPtr);
- nonVoidTypeCheck(*ExprTypeSynPtr);
- structs = (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2 +
- (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr);
- if (structs)
- {
- word sz;
- if (structs != 3 ||
- SyntaxStack1[RightExprTypeSynPtr] != SyntaxStack1[*ExprTypeSynPtr])
- errorOpType();
- // TBD??? (a = b) should be an rvalue and so &(a = b) and (&(a = b))->c shouldn't be
- // allowed, while (a = b).c should be allowed.
- // transform "*psleft = *psright" into "*fxn(sizeof *psright, psright, psleft)"
- /*
- if (stack[oldIdxLeft - (oldSpLeft - sp)][0] != tokUnaryStar ||
- stack[oldIdxRight - (oldSpRight - sp)][0] != tokUnaryStar)
- errorInternal(18);
- */
- stack[oldIdxLeft - (oldSpLeft - sp)][0] = ','; // replace '*' with ','
- stack[oldIdxRight - (oldSpRight - sp)][0] = ','; // replace '*' with ','
- sz = GetDeclSize(RightExprTypeSynPtr, 0);
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokNumUint; // replace '=' with "sizeof *psright"
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = sz;
- ins(oldIdxRight + 2 - (oldSpRight - sp), ',');
- if (!StructCpyLabel)
- StructCpyLabel = LabelCnt++;
- ins2(oldIdxRight + 2 - (oldSpRight - sp), tokIdent, AddNumericIdent(StructCpyLabel));
- ins2(oldIdxRight + 2 - (oldSpRight - sp), ')', SizeOfWord * 3);
- ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences
- ins2(*idx + 1, '(', SizeOfWord * 3);
- }
- else
- {
- // "remove" the lvalue dereference as we don't need
- // to read the value while forgetting its location.
- // We need to keep the lvalue location.
- // Remember the operand size.
- opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1];
- // store the operand size in the operator
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
- del(oldIdxLeft - (oldSpLeft - sp), 1);
- }
- *ConstExpr = 0;
- }
- break;
- // DONE: other assignment operators
- // Arithmetic and bitwise unary operators
- case '~':
- case tokUnaryPlus:
- case tokUnaryMinus:
- s = exprval(idx, ExprTypeSynPtr, ConstExpr);
- numericTypeCheck(*ExprTypeSynPtr);
- promoteType(ExprTypeSynPtr, ExprTypeSynPtr);
- switch (tok)
- {
- case '~':
- s = ~s;
- break;
- case tokUnaryPlus:
- break;
- case tokUnaryMinus:
- {
- s = (word)~(s - 1u);
- }
- break;
- }
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- break;
- // Arithmetic and bitwise binary operators
- case '*':
- case '/':
- case '%':
- case tokLShift:
- case tokRShift:
- case '&':
- case '^':
- case '|':
- {
- word sr, sl;
- word Unsigned;
- sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- numericTypeCheck(RightExprTypeSynPtr);
- numericTypeCheck(*ExprTypeSynPtr);
- *ConstExpr = constExpr[0] && constExpr[1];
- Unsigned = SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned || SyntaxStack0[RightExprTypeSynPtr] == tokUnsigned;
- {
- switch (tok)
- {
- // DONE: check for division overflows
- case '/':
- case '%':
- *ConstExpr &= divCheckAndCalc(tok, &sl, sr, Unsigned, constExpr);
- if (Unsigned)
- {
- if (tok == '/')
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUDiv;
- else
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUMod;
- }
- break;
- case '*':
- sl = (word)((unsigned)sl * sr);
- break;
- case tokLShift:
- case tokRShift:
- if (constExpr[1])
- {
- if (SyntaxStack0[RightExprTypeSynPtr] != tokUnsigned)
- sr = truncInt(sr);
- else
- sr = (word)truncUint(sr);
- shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr);
- }
- if (*ConstExpr)
- {
- if (tok == tokLShift)
- {
- // left shift is the same for signed and unsigned ints
- sl = (word)((unsigned)sl << sr);
- }
- else
- {
- if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned)
- {
- // right shift for unsigned ints
- sl = (word)(truncUint(sl) >> sr);
- }
- else if (sr)
- {
- // right shift for signed ints is arithmetic, sign-bit-preserving
- // don't depend on the compiler's implementation, do it "manually"
- sl = truncInt(sl);
- sl = (word)((truncUint(sl) >> sr) |
- ((sl < 0) * (~0u << (8 * SizeOfWord - sr))));
- }
- }
- }
- if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned && tok == tokRShift)
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokURShift;
- // ignore RightExprTypeSynPtr for the purpose of promotion/conversion of the result of <</>>
- RightExprTypeSynPtr = SymIntSynPtr;
- break;
- case '&': sl &= sr; break;
- case '^': sl ^= sr; break;
- case '|': sl |= sr; break;
- }
- s = sl;
- }
- promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr);
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- }
- break;
- // Relational and equality binary operators
- // DONE: add (sub)tokens for unsigned >, >=, <, <= for pointers
- case '<':
- case '>':
- case tokLEQ:
- case tokGEQ:
- case tokEQ:
- case tokNEQ:
- {
- word ptrmask;
- word sr, sl;
- sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- // Bar void and struct/union
- scalarTypeCheck(RightExprTypeSynPtr);
- scalarTypeCheck(*ExprTypeSynPtr);
- ptrmask = isAnyPtr(RightExprTypeSynPtr) + isAnyPtr(*ExprTypeSynPtr) * 2;
- // TBD??? stricter type checks???
- if (tok != tokEQ && tok != tokNEQ)
- {
- // Disallow >, <, >=, <= between a pointer and a number
- if (ptrmask == 1 || ptrmask == 2)
- //error("exprval(): Invalid/unsupported combination of compared operands\n");
- errorOpType();
- // Disallow >, <, >=, <= with pointers to functions
- if (((ptrmask & 1) && SyntaxStack0[derefAnyPtr(RightExprTypeSynPtr)] == '(') ||
- ((ptrmask & 2) && SyntaxStack0[derefAnyPtr(*ExprTypeSynPtr)] == '('))
- errorOpType();
- }
- else
- {
- // Disallow == and != between a pointer and a number other than constant 0 (AKA NULL)
- if ((ptrmask == 1 && !(constExpr[0] && !truncInt(sl))) ||
- (ptrmask == 2 && !(constExpr[1] && !truncInt(sr))))
- errorOpType();
- }
- *ConstExpr = constExpr[0] && constExpr[1];
- {
- word Unsigned = isUint(*ExprTypeSynPtr) || isUint(RightExprTypeSynPtr);
- if (*ConstExpr)
- {
- if (!Unsigned)
- {
- sl = truncInt(sl);
- sr = truncInt(sr);
- switch (tok)
- {
- case '<': sl = sl < sr; break;
- case '>': sl = sl > sr; break;
- case tokLEQ: sl = sl <= sr; break;
- case tokGEQ: sl = sl >= sr; break;
- case tokEQ: sl = sl == sr; break;
- case tokNEQ: sl = sl != sr; break;
- }
- }
- else
- {
- sl = (word)truncUint(sl);
- sr = (word)truncUint(sr);
- switch (tok)
- {
- case '<': sl = (unsigned)sl < (unsigned)sr; break;
- case '>': sl = (unsigned)sl > (unsigned)sr; break;
- case tokLEQ: sl = (unsigned)sl <= (unsigned)sr; break;
- case tokGEQ: sl = (unsigned)sl >= (unsigned)sr; break;
- case tokEQ: sl = sl == sr; break;
- case tokNEQ: sl = sl != sr; break;
- }
- }
- }
- if (ptrmask || Unsigned)
- {
- // Pointer comparison should be unsigned
- word t = tok;
- switch (tok)
- {
- case '<': t = tokULess; break;
- case '>': t = tokUGreater; break;
- case tokLEQ: t = tokULEQ; break;
- case tokGEQ: t = tokUGEQ; break;
- }
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t;
- }
- }
- s = sl;
- *ExprTypeSynPtr = SymIntSynPtr;
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- }
- break;
- // implicit pseudo-conversion to _Bool of operands of && and ||
- case tok_Bool:
- s = exprval(idx, ExprTypeSynPtr, ConstExpr);
- // Bar void and struct/union
- scalarTypeCheck(*ExprTypeSynPtr);
- {
- s = truncInt(s) != 0;
- }
- *ExprTypeSynPtr = SymIntSynPtr;
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- break;
- // Logical binary operators
- case tokLogAnd: // DONE: short-circuit
- case tokLogOr: // DONE: short-circuit
- {
- word sr, sl;
- // DONE: think of pushing a special short-circuit (jump-to) token
- // to skip the rhs operand evaluation in && and ||
- // DONE: add implicit "casts to _Bool" of && and || operands,
- // do the same for control statements of if() while() and for(;;).
- word sc = LabelCnt++;
- // tag the logical operator as a numbered short-circuit jump target
- stack[*idx + 1][1] = sc;
- // insert "!= 0" for right-hand operand
- switch (stack[*idx][0])
- {
- case '<':
- case tokULess:
- case '>':
- case tokUGreater:
- case tokLEQ:
- case tokULEQ:
- case tokGEQ:
- case tokUGEQ:
- case tokEQ:
- case tokNEQ:
- break;
- default:
- ins(++*idx, tok_Bool);
- break;
- }
- sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- // insert a reference to the short-circuit jump target
- if (tok == tokLogAnd)
- ins2(++*idx, tokShortCirc, sc);
- else
- ins2(++*idx, tokShortCirc, -sc);
- // insert "!= 0" for left-hand operand
- switch (stack[*idx - 1][0])
- {
- case '<':
- case tokULess:
- case '>':
- case tokUGreater:
- case tokLEQ:
- case tokULEQ:
- case tokGEQ:
- case tokUGEQ:
- case tokEQ:
- case tokNEQ:
- --*idx;
- break;
- default:
- ins(*idx, tok_Bool);
- break;
- }
- sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- if (tok == tokLogAnd)
- s = sl && sr;
- else
- s = sl || sr;
- *ExprTypeSynPtr = SymIntSynPtr;
- *ConstExpr = constExpr[0] && constExpr[1];
- if (constExpr[0])
- {
- if (tok == tokLogAnd)
- {
- if (!sl)
- *ConstExpr = 1, s = 0;
- // TBD??? else can drop LHS expression
- }
- else
- {
- if (sl)
- *ConstExpr = s = 1;
- // TBD??? else can drop LHS expression
- }
- }
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- }
- break;
- // Function call
- case ')':
- {
- word tmpSynPtr, c;
- word minParams, maxParams;
- word firstParamSynPtr;
- word oldIdx, oldSp;
- exprval(idx, ExprTypeSynPtr, ConstExpr);
- if (!GetFxnInfo(*ExprTypeSynPtr, &minParams, &maxParams, ExprTypeSynPtr, &firstParamSynPtr))
- //error("exprval(): function or function pointer expected\n");
- errorOpType();
- // DONE: validate the number of function arguments
- // DONE: warnings on int<->pointer substitution in params/args
- // evaluate function arguments
- c = 0;
- while (stack[*idx][0] != '(')
- {
- word ptrmask;
- // add a comma after the first (last to be pushed) argument,
- // so all arguments can be pushed whenever a comma is encountered
- if (!c)
- ins(*idx + 1, ',');
- oldIdx = *idx;
- oldSp = sp;
- (void)oldIdx;
- (void)oldSp;
- exprval(idx, &tmpSynPtr, ConstExpr);
- //error("exprval(): function arguments cannot be of type 'void'\n");
- if (c >= maxParams)
- error("Too many function arguments\n");
- // Find the type of the formal parameter in the function declaration
- if (c < minParams)
- {
- word t;
- while ((t = SyntaxStack0[firstParamSynPtr]) != tokIdent)
- {
- if (t == '(')
- {
- // skip parameters in parameters
- word c = 1;
- while (c)
- {
- t = SyntaxStack0[++firstParamSynPtr];
- c += (t == '(') - (t == ')');
- }
- }
- firstParamSynPtr++;
- }
- firstParamSynPtr++;
- }
- else
- {
- firstParamSynPtr = SymVoidSynPtr;
- }
- ptrmask = isAnyPtr(firstParamSynPtr) * 2 + isAnyPtr(tmpSynPtr);
- (void)ptrmask;
- // Bar void and struct/union
- scalarTypeCheck(tmpSynPtr);
- // if there's a formal parameter for this argument, check the types
- if (c < minParams)
- {
- }
- c++;
- if (stack[*idx][0] == ',')
- --*idx;
- }
- --*idx;
- if (c < minParams)
- error("Too few function arguments\n");
- // store the cumulative argument size in the function call operators
- {
- word i = oldIdxRight + 1 - (oldSpRight - sp);
- stack[1 + *idx][1] = stack[i][1] = c * SizeOfWord;
- }
- *ConstExpr = 0;
- }
- break;
- // Binary comma operator
- case tokComma:
- {
- word oldIdxLeft, oldSpLeft;
- word retStruct = 0;
- s = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- oldIdxLeft = *idx;
- oldSpLeft = sp;
- // Signify uselessness of the result of the left operand's value
- ins(*idx + 1, tokVoid);
- exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- *ConstExpr = constExpr[0] && constExpr[1];
- *ExprTypeSynPtr = RightExprTypeSynPtr;
- retStruct = RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr;
- if (*ConstExpr)
- {
- // both subexprs are const, remove both and comma
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- }
- else if (constExpr[0])
- {
- // only left subexpr is const, remove it
- del(*idx + 1, oldIdxLeft - (oldSpLeft - sp) - *idx);
- if (!retStruct)
- // Ensure non-lvalue-ness of the result by changing comma to unary plus
- // and thus hiding dereference, if any
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus;
- else
- // However, (something, struct).member should still be allowed,
- // so, comma needs to produce lvalue
- del(oldIdxRight + 1 - (oldSpRight - sp), 1);
- }
- else if (retStruct)
- {
- // However, (something, struct).member should still be allowed,
- // so, comma needs to produce lvalue. Swap comma and structure dereference.
- word i = oldIdxRight + 1 - (oldSpRight - sp);
- stack[i][0] = tokUnaryStar;
- stack[i][1] = stack[i - 1][1];
- stack[i - 1][0] = tokComma;
- }
- }
- break;
- // Compound assignment operators
- case tokAssignMul: case tokAssignDiv: case tokAssignMod:
- case tokAssignAdd: case tokAssignSub:
- case tokAssignLSh: case tokAssignRSh:
- case tokAssignAnd: case tokAssignXor: case tokAssignOr:
- {
- word ptrmask;
- word oldIdxLeft, oldSpLeft;
- word incSize;
- word opSize;
- word Unsigned;
- word sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
- oldIdxLeft = *idx;
- oldSpLeft = sp;
- exprval(idx, ExprTypeSynPtr, &constExpr[0]);
- lvalueCheck(*ExprTypeSynPtr, oldIdxLeft - (oldSpLeft - sp));
- // if it's a pointer, ensure that it's suitable for pointer arithmetic
- // (not pointer to function, pointee size is known and non-zero)
- decayArray(ExprTypeSynPtr, 1); // no actual decay here, just a type check
- // Bar void and struct/union
- scalarTypeCheck(RightExprTypeSynPtr);
- scalarTypeCheck(*ExprTypeSynPtr);
- // "remove" the lvalue dereference as we don't need
- // to read the value while forgetting its location.
- // We need to keep the lvalue location.
- // Remember the operand size.
- opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1];
- // store the operand size in the operator
- stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
- del(oldIdxLeft - (oldSpLeft - sp), 1);
- ptrmask = isAnyPtr(*ExprTypeSynPtr) * 2 + isAnyPtr(RightExprTypeSynPtr);
- Unsigned = isUint(*ExprTypeSynPtr) * 2 + isUint(RightExprTypeSynPtr);
- if (tok != tokAssignAdd && tok != tokAssignSub)
- {
- if (ptrmask)
- //error("exprval(): invalid combination of operands for %s\n", GetTokenName(tok));
- errorOpType();
- }
- else
- {
- // No pointer to the right of += and -=
- if (ptrmask & 1)
- //error("exprval(): invalid combination of operands for %s\n", GetTokenName(tok));
- errorOpType();
- }
- if (tok == tokAssignLSh || tok == tokAssignRSh)
- {
- if (constExpr[1])
- {
- if (Unsigned & 1)
- sr = (word)truncUint(sr);
- else
- sr = truncInt(sr);
- shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr);
- }
- }
- if (tok == tokAssignDiv || tok == tokAssignMod)
- {
- word t, sl = 0;
- if (tok == tokAssignDiv)
- t = '/';
- else
- t = '%';
- divCheckAndCalc(t, &sl, sr, 1, constExpr);
- }
- // TBD??? replace +=/-= with prefix ++/-- if incSize == 1
- if (ptrmask == 2) // left-hand expression
- {
- incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
- if (constExpr[1])
- {
- word t = (word)(stack[oldIdxRight - (oldSpRight - sp)][1] * (unsigned)incSize);
- stack[oldIdxRight - (oldSpRight - sp)][1] = t;
- }
- else if (incSize != 1)
- {
- ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize);
- ins(oldIdxRight + 1 - (oldSpRight - sp), '*');
- }
- }
- else if (Unsigned)
- {
- word t = tok;
- switch (tok)
- {
- case tokAssignDiv: t = tokAssignUDiv; break;
- case tokAssignMod: t = tokAssignUMod; break;
- case tokAssignRSh:
- if (Unsigned & 2)
- t = tokAssignURSh;
- break;
- }
- stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t;
- }
- *ConstExpr = 0;
- }
- break;
- // Ternary/conditional operator
- case '?':
- {
- word oldIdxLeft, oldSpLeft;
- word oldIdxCond, oldSpCond;
- word sr, sl, smid;
- word condTypeSynPtr;
- word sc = (LabelCnt += 2) - 2;
- word structs;
- // "exprL ? exprMID : exprR" appears on the stack as
- // "exprL exprR exprMID ?"
- // label at the end of ?:
- stack[*idx + 1][0] = tokLogAnd; // piggyback on && for CG (ugly, but simple)
- stack[*idx + 1][1] = sc + 1;
- smid = exprval(idx, ExprTypeSynPtr, &constExpr[1]);
- oldIdxLeft = *idx;
- oldSpLeft = sp;
- sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[2]);
- decayArray(&RightExprTypeSynPtr, 0);
- decayArray(ExprTypeSynPtr, 0);
- promoteType(&RightExprTypeSynPtr, ExprTypeSynPtr);
- promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr);
- structs = (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2 +
- (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr);
- // TBD??? move struct/union-related checks into compatChecks()
- if (structs)
- {
- if (structs != 3 ||
- SyntaxStack1[RightExprTypeSynPtr] != SyntaxStack1[*ExprTypeSynPtr])
- errorOpType();
- // transform "cond ? a : b" into "*(cond ? &a : &b)"
- /*
- if (stack[oldIdxLeft - (oldSpLeft - sp)][0] != tokUnaryStar ||
- stack[oldIdxRight - (oldSpRight - sp)][0] != tokUnaryStar)
- errorInternal(19);
- */
- del(oldIdxLeft - (oldSpLeft - sp), 1); // delete '*'
- del(oldIdxRight - (oldSpRight - sp), 1); // delete '*'
- oldSpLeft--;
- // '*' will be inserted at the end
- }
- else
- {
- compatCheck(ExprTypeSynPtr,
- RightExprTypeSynPtr,
- &constExpr[1],
- oldIdxRight - (oldSpRight - sp),
- oldIdxLeft - (oldSpLeft - sp));
- }
- // label at the start of exprMID
- ins2(oldIdxLeft + 1 - (oldSpLeft - sp), tokLogAnd, sc); // piggyback on && for CG (ugly, but simple)
- // jump from the end of exprR over exprMID to the end of ?:
- ins2(oldIdxLeft - (oldSpLeft - sp), tokGoto, sc + 1);
- // jump to exprMID if exprL is non-zero
- ins2(*idx + 1, tokShortCirc, -sc);
- oldIdxCond = *idx;
- oldSpCond = sp;
- sl = exprval(idx, &condTypeSynPtr, &constExpr[0]);
- // Bar void and struct/union
- scalarTypeCheck(condTypeSynPtr);
- *ConstExpr = s = 0;
- if (constExpr[0])
- {
- word c1 = 0, c2 = 0;
- // Stack now: exprL tokShortCirc exprR tokGoto tokLogAnd exprMID ?/tokLogAnd
- if (
- (truncUint(sl) != 0))
- {
- if (constExpr[1])
- {
- *ConstExpr = 1, s = smid;
- }
- else
- {
- // Drop exprL and exprR subexpressions
- c1 = oldIdxLeft - (oldSpLeft - sp) - *idx; // includes tokShortCirc, tokGoto, tokLogAnd
- c2 = 1; // include '?'/tokLogAnd
- }
- }
- else
- {
- if (constExpr[2])
- {
- *ConstExpr = 1, s = sr;
- }
- else
- {
- // Drop exprL and exprMID subexpressions
- c1 = oldIdxCond - (oldSpCond - sp) - *idx + 1; // includes tokShortCirc
- c2 = (oldIdxRight - (oldSpRight - sp)) -
- (oldIdxLeft - (oldSpLeft - sp)) + 3; // includes tokGoto, tokLogAnd, '?'/tokLogAnd
- }
- }
- if (c1)
- {
- word pos = oldIdxRight - (oldSpRight - sp) + 2 - c2;
- if (!structs && stack[pos - 1][0] == tokUnaryStar)
- stack[pos++][0] = tokUnaryPlus, c2--; // ensure non-lvalue-ness by hiding the dereference
- del(pos, c2);
- del(*idx + 1, c1);
- }
- }
- // finish transforming "cond ? a : b" into "*(cond ? &a : &b)", insert '*'
- if (structs)
- ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences
- simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
- }
- break;
- // Postfix indirect structure/union member selection operator
- case tokArrow:
- {
- word member, i = 0, j = 0, c = 1, ofs = 0;
- stack[*idx + 1][0] = '+'; // replace -> with +
- member = stack[*idx][1]; // keep the member name, it will be replaced with member offset
- stack[*idx][0] = tokNumInt;
- --*idx;
- exprval(idx, ExprTypeSynPtr, ConstExpr);
- if (!isAnyPtr(*ExprTypeSynPtr) ||
- SyntaxStack0[i = derefAnyPtr(*ExprTypeSynPtr)] != tokStructPtr)
- error("Pointer to or structure or union expected\n");
- i = SyntaxStack1[i];
- if (i + 2 > SyntaxStackCnt ||
- (SyntaxStack0[i] != tokStruct && SyntaxStack0[i] != tokUnion) ||
- SyntaxStack0[i + 1] != tokTag)
- errorInternal(20);
- if (!GetDeclSize(i, 0))
- // incomplete structure/union type
- errorOpType();
- i += 5; // step inside the {} body of the struct/union
- while (c)
- {
- word t = SyntaxStack0[i];
- c += (t == '(') - (t == ')') + (t == '{') - (t == '}');
- if (c == 1 &&
- t == tokMemberIdent && SyntaxStack1[i] == member &&
- SyntaxStack0[i + 1] == tokLocalOfs)
- {
- j = i;
- ofs = SyntaxStack1[i + 1];
- break;
- }
- i++;
- }
- if (!j)
- {
- printf("Undefined structure or union member ");
- error(IdentTable + member);
- }
- j += 2;
- // we cannot insert another '*' into the type to make it a pointer,
- // so make the index into the type negative
- *ExprTypeSynPtr = -j; // type: pointer to member's type
- stack[oldIdxRight - (oldSpRight - sp)][1] = ofs; // member offset within structure/union
- // optimize a little, if possible
- {
- word i = oldIdxRight - (oldSpRight - sp) - 1;
- // Skip any type cast markers
- while (stack[i][0] == tokUnaryPlus)
- i--;
- // See if the pointer is an integer constant or a local variable offset
- // and if it is, adjust it here instead of generating code for
- // addition/subtraction
- if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs)
- {
- stack[i][1] = (word)((unsigned)stack[i][1] + ofs); // TBD!!! need extra truncation?
- del(oldIdxRight - (oldSpRight - sp), 2);
- }
- }
- *ConstExpr = 0;
- }
- break;
- default:
- //error("exprval(): Unexpected token %s\n", GetTokenName(tok));
- errorInternal(21);
- }
- return s;
- }
- word ParseExpr(word tok, word* GotUnary, word* ExprTypeSynPtr, word* ConstExpr, word* ConstVal, word option, word option2)
- {
- word identFirst = tok == tokIdent;
- *ConstVal = *ConstExpr = 0;
- *ExprTypeSynPtr = SymVoidSynPtr;
- if (!ExprLevel++)
- {
- opsp = sp = 0;
- }
- if (option == '=')
- push2(tokIdent, option2);
- tok = expr(tok, GotUnary, option == ',' || option == '=');
- if (tok == tokEof || strchr(",;:)]}", tok) == NULL)
- //error("ParseExpr(): Unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- if (option == '=')
- {
- push('=');
- }
- else if (option == tokGotoLabel && identFirst && tok == ':' && *GotUnary && sp == 1 && stack[sp - 1][0] == tokIdent)
- {
- // This is a label.
- ExprLevel--;
- return tokGotoLabel;
- }
- if (*GotUnary)
- {
- word j;
- // Do this twice so we can see the stack before
- // and after manipulations
- for (j = 0; j < 2; j++)
- {
- if (doAnnotations)
- {
- word i;
- GenStartCommentLine();
- if (j) printf2("Expanded");
- else printf2("RPN'ized");
- printf2(" expression: \"");
- for (i = 0; i < sp; i++)
- {
- word tok = stack[i][0];
- switch (tok)
- {
- case tokNumInt:
- printd2(truncInt(stack[i][1]));
- break;
- case tokNumUint:
- printd2(truncUint(stack[i][1]));
- break;
- case tokIdent:
- {
- char* p = IdentTable + stack[i][1];
- if (isdigit(*p))
- printf2("L");
- printf2(p);
- }
- break;
- case tokShortCirc:
- if (stack[i][1] >= 0)
- {
- printf2("[sh&&->");
- printd2(stack[i][1]);
- printf2("]");
- }
- else
- {
- printf2("[sh||->");
- printd2(-stack[i][1]);
- printf2("]");
- }
- break;
- case tokLocalOfs:
- printf2("(@");
- printd2(truncInt(stack[i][1]));
- printf2(")");
- break;
- case tokUnaryStar:
- if (j)
- {
- printf2("*(");
- printd2(stack[i][1]);
- printf2(")");
- }
- else printf2("*u");
- break;
- case '(': case ',':
- if (!j)
- {
- char* ctmp = " ";
- ctmp[0] = tok;
- printf2(ctmp);
- }
-
- // else printf2("\b");
- break;
- case ')':
- if (j) printf2("(");
- char* ctmp = " ";
- ctmp[0] = tok;
- printf2(ctmp);
- if (j) printd2(stack[i][1]);
- break;
- default:
- printf2(GetTokenName(tok));
- if (j)
- {
- switch (tok)
- {
- case tokLogOr: case tokLogAnd:
- printf2("[");
- printd2(stack[i][1]);
- printf2("]");
- break;
- case '=':
- case tokInc: case tokDec:
- case tokPostInc: case tokPostDec:
- case tokAssignAdd: case tokAssignSub:
- case tokPostAdd: case tokPostSub:
- case tokAssignMul:
- case tokAssignDiv: case tokAssignMod:
- case tokAssignUDiv: case tokAssignUMod:
- case tokAssignLSh: case tokAssignRSh: case tokAssignURSh:
- case tokAssignAnd: case tokAssignXor: case tokAssignOr:
- printf2("(");
- printd2(stack[i][1]);
- printf2(")");
- break;
- }
- }
- break;
- }
- printf2(" ");
- }
- printf2("\"\n");
- }
- if (!j)
- {
- word idx = sp - 1;
- *ConstVal = exprval(&idx, ExprTypeSynPtr, ConstExpr);
- // remove the unneeded unary +'s that have served their cast-substitute purpose
- // also remove dereferences of size 0 (dereferences of pointers to structures)
- for (idx = sp - 1; idx >= 0; idx--)
- if (stack[idx][0] == tokUnaryPlus ||
- (stack[idx][0] == tokUnaryStar && !stack[idx][1]))
- del(idx, 1);
- }
- else if (*ConstExpr)
- {
- if (doAnnotations)
- {
- GenStartCommentLine();
- switch (SyntaxStack0[*ExprTypeSynPtr])
- {
- case tokChar:
- case tokSChar:
- case tokUChar:
- case tokShort:
- case tokUShort:
- case tokInt:
- printf2("Expression value: ");
- printd2(truncInt(*ConstVal));
- printf2("\n");
- break;
- default:
- case tokUnsigned:
- printf2("Expression value: ");
- printd2(truncUint(*ConstVal));
- printf2("\n");
- break;
- }
- }
- }
- }
- }
- ExprLevel--;
- return tok;
- }
- // smc.c code
- // Equivalent to puts() but outputs to OutFile.
- word puts2(char* s)
- {
- word res;
- if (!OutFile)
- return 0;
- // Turbo C++ 1.01's fputs() returns EOF if s is empty, which is wrong.
- // Hence the workaround.
- fputs(OutFile, s);
- res = fputc(OutFile, '\n');
- return res;
- }
- // Print string to outfile
- word printf2(char* sToWrite)
- {
- if (!OutFile)
- {
- printf("COULD NOT WRITE TO OUT!");
- return 0;
- }
- // TODO: escape handling
- word res = fputs(OutFile, sToWrite);
- return res;
- }
- // Print decimal to outfile
- word printd2(word dToWrite)
- {
- if (!OutFile)
- return 0;
- char buf[32];
- // handle negative numbers
- if (dToWrite < 0)
- {
- fputc(OutFile, '-');
- dToWrite = -dToWrite;
- }
- itoa(dToWrite, buf);
- word res = fputs(OutFile, buf);
- return res;
- }
- void error(char* strToPrint)
- {
- word i, fidx = FileCnt - 1 + !FileCnt;
- for (i = 0; i < FileCnt; i++)
- if (Files[i])
- fclose(Files[i]);
- /*
- puts2("");
- DumpSynDecls();
- DumpMacroTable();
- DumpIdentTable();
- */
- // using stdout implicitly instead of stderr explicitly because:
- // - stderr can be a macro and it's unknown if standard headers
- // aren't included (which is the case when SmallerC is compiled
- // with itself and linked with some other compiler's standard
- // libraries)
- // - output to stderr can interfere/overlap with buffered
- // output to stdout and the result may literally look ugly
- //GenStartCommentLine(); printf2("Compilation failed.\n");
- if (OutFile)
- fclose(OutFile);
- printf("Error in ");
- printf(FileNames[fidx]);
- printf(" at ");
- printd(LineNo);
- printf(":");
- printd(LinePos);
- printf("\n");
- printf(strToPrint);
- printf("\n");
- exit(EXIT_FAILURE);
- }
- void warning(char* strToPrint)
- {
- word fidx = FileCnt - 1 + !FileCnt;
- warnCnt++;
- if (!warnings)
- return;
- //printf("Warning in \"%s\" (%d:%d)\n", FileNames[fidx], LineNo, LinePos);
- printf("warning.");
- printf(strToPrint);
- }
- void errorFile(char* n)
- {
- printf("Unable to open, read, write or close file ");
- error(n);
- }
- void errorFileName(void)
- {
- error("Invalid or too long file name or path name\n");
- }
- void errorInternal(word n)
- {
- printd(n);
- error(" internal error\n");
- }
- void errorChrStr(void)
- {
- error("Invalid or unsupported character constant or string literal\n");
- }
- void errorStrLen(void)
- {
- error("String literal too long\n");
- }
- void errorUnexpectedToken(word tok)
- {
- printf("Unexpected token ");
- error((tok == tokIdent) ? TokenIdentName : GetTokenName(tok));
- }
- void errorDirective(void)
- {
- error("Invalid or unsupported preprocessor directive\n");
- }
- void errorCtrlOutOfScope(void)
- {
- error("break, continue, case or default in wrong scope\n");
- }
- void errorDecl(void)
- {
- error("Invalid or unsupported declaration\n");
- }
- void errorTagRedef(word ident)
- {
- printf("Redefinition of type tagged ");
- printd(IdentTable + ident);
- error("\n");
- }
- void errorVarSize(void)
- {
- error("Variable(s) take(s) too much space\n");
- }
- void errorInit(void)
- {
- error("Invalid or unsupported initialization\n");
- }
- void errorUnexpectedVoid(void)
- {
- error("Unexpected declaration or expression of type void\n");
- }
- void errorOpType(void)
- {
- error("Unexpected operand type\n");
- }
- void errorNotLvalue(void)
- {
- error("lvalue expected\n");
- }
- void errorNotConst(void)
- {
- error("Non-constant expression\n");
- }
- void errorLongExpr(void)
- {
- error("Expression too long\n");
- }
- word tsd[] =
- {
- tokVoid, tokChar, tokInt,
- tokSigned, tokUnsigned, tokShort,
- tokStruct, tokUnion,
- };
- word TokenStartsDeclaration(word t, word params)
- {
- unsigned i;
- for (i = 0; i < division(sizeof tsd, sizeof tsd[0]); i++)
- if (tsd[i] == t)
- return 1;
- return
- (SizeOfWord != 2 && t == tokLong) ||
- (!params && (t == tokExtern ||
- t == tokStatic));
- }
- void PushSyntax2(word t, word v)
- {
- if (SyntaxStackCnt >= SYNTAX_STACK_MAX)
- error("Symbol table exhausted\n");
- SyntaxStack0[SyntaxStackCnt] = t;
- SyntaxStack1[SyntaxStackCnt++] = v;
- }
- void PushSyntax(word t)
- {
- PushSyntax2(t, 0);
- }
- void InsertSyntax2(word pos, word t, word v)
- {
- if (SyntaxStackCnt >= SYNTAX_STACK_MAX)
- error("Symbol table exhausted\n");
- memmove(&SyntaxStack0[pos + 1],
- &SyntaxStack0[pos],
- sizeof(SyntaxStack0[0]) * (SyntaxStackCnt - pos));
- memmove(&SyntaxStack1[pos + 1],
- &SyntaxStack1[pos],
- sizeof(SyntaxStack1[0]) * (SyntaxStackCnt - pos));
- SyntaxStack0[pos] = t;
- SyntaxStack1[pos] = v;
- SyntaxStackCnt++;
- }
- void InsertSyntax(word pos, word t)
- {
- InsertSyntax2(pos, t, 0);
- }
- void DeleteSyntax(word pos, word cnt)
- {
- memmove(&SyntaxStack0[pos],
- &SyntaxStack0[pos + cnt],
- sizeof(SyntaxStack0[0]) * (SyntaxStackCnt - (pos + cnt)));
- memmove(&SyntaxStack1[pos],
- &SyntaxStack1[pos + cnt],
- sizeof(SyntaxStack1[0]) * (SyntaxStackCnt - (pos + cnt)));
- SyntaxStackCnt -= cnt;
- }
- word FindSymbol(char* s)
- {
- word i;
- // TBD!!! return declaration scope number so
- // redeclarations can be reported if occur in the same scope.
- // TBD??? Also, I could first use FindIdent() and then just look for the
- // index into IdentTable[] instead of doing strcmp()
- for (i = SyntaxStackCnt - 1; i >= 0; i--)
- {
- word t = SyntaxStack0[i];
- if (t == tokIdent &&
- !strcmp(IdentTable + SyntaxStack1[i], s))
- {
- return i;
- }
- if (t == ')')
- {
- // Skip over the function params
- word c = -1;
- while (c)
- {
- t = SyntaxStack0[--i];
- c += (t == '(') - (t == ')');
- }
- }
- }
- return -1;
- }
- word SymType(word SynPtr)
- {
- word local = 0;
- if (SyntaxStack0[SynPtr] == tokIdent)
- SynPtr++;
- if ((local = SyntaxStack0[SynPtr] == tokLocalOfs) != 0)
- SynPtr++;
- switch (SyntaxStack0[SynPtr])
- {
- case '(':
- return SymFxn;
- case '[':
- if (local)
- return SymLocalArr;
- return SymGlobalArr;
- default:
- if (local)
- return SymLocalVar;
- return SymGlobalVar;
- }
- }
- word FindTaggedDecl(char* s, word start, word* CurScope)
- {
- word i;
- *CurScope = 1;
- for (i = start; i >= 0; i--)
- {
- word t = SyntaxStack0[i];
- if (t == tokTag &&
- !strcmp(IdentTable + SyntaxStack1[i], s))
- {
- return i - 1;
- }
- else if (t == ')')
- {
- // Skip over the function params
- word c = -1;
- while (c)
- {
- t = SyntaxStack0[--i];
- c += (t == '(') - (t == ')');
- }
- }
- else if (t == '#')
- {
- // the scope has changed to the outer scope
- *CurScope = 0;
- }
- }
- return -1;
- }
- word GetDeclSize(word SyntaxPtr, word SizeForDeref)
- {
- word i;
- unsigned size = 1;
- word arr = 0;
- if (SyntaxPtr < 0) // pointer?
- return SizeOfWord;
- for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
- {
- word tok = SyntaxStack0[i];
- switch (tok)
- {
- case tokIdent: // skip leading identifiers, if any
- case tokLocalOfs: // skip local var offset, too
- break;
- case tokChar:
- case tokSChar:
- if (!arr && ((tok == tokSChar) || CharIsSigned) && SizeForDeref)
- return -1; // 1 byte, needing sign extension when converted to int/unsigned int
- // fallthrough
- case tokUChar:
- return (word)size;
- case tokShort:
- if (!arr && SizeForDeref)
- return -2; // 2 bytes, needing sign extension when converted to int/unsigned int
- // fallthrough
- case tokUShort:
- //if (size * 2 / 2 != size)
- //error("Variable too big\n");
- // errorVarSize();
- size *= 2;
- if (size != truncUint(size))
- //error("Variable too big\n");
- {
- //printf("b");
- errorVarSize();
- }
-
- return (word)size;
- case tokInt:
- case tokUnsigned:
- case '*':
- case '(': // size of fxn = size of ptr for now
- //if (size * SizeOfWord / SizeOfWord != size)
- //error("Variable too big\n");
- //errorVarSize();
- size *= SizeOfWord;
- if (size != truncUint(size))
- //error("Variable too big\n");
- {
- //printf("c");
- errorVarSize();
- }
- return (word)size;
- case '[':
- if (SyntaxStack0[i + 1] != tokNumInt && SyntaxStack0[i + 1] != tokNumUint)
- errorInternal(11);
- //if (SyntaxStack1[i + 1] &&
- //size * SyntaxStack1[i + 1] / SyntaxStack1[i + 1] != size)
- //error("Variable too big\n");
- //errorVarSize();
- size *= SyntaxStack1[i + 1];
- if (size != truncUint(size))
- //error("Variable too big\n");
- {
- //printf("d");
- errorVarSize();
- }
- i += 2;
- arr = 1;
- break;
- case tokStructPtr:
- // follow the "type pointer"
- i = SyntaxStack1[i] - 1;
- break;
- case tokStruct:
- case tokUnion:
- if (i + 2 < SyntaxStackCnt && SyntaxStack0[i + 2] == tokSizeof && !SizeForDeref)
- {
- unsigned s = SyntaxStack1[i + 2];
- //if (s && size * s / s != size)
- // errorVarSize();
- size *= s;
- if (size != truncUint(size))
- {
- //printf("d");
- errorVarSize();
- }
- return (word)size;
- }
- return 0;
- case tokVoid:
- return 0;
- default:
- errorInternal(12);
- }
- }
- errorInternal(13);
- return 0;
- }
- word GetDeclAlignment(word SyntaxPtr)
- {
- word i;
- if (SyntaxPtr < 0) // pointer?
- return SizeOfWord;
- for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
- {
- word tok = SyntaxStack0[i];
- switch (tok)
- {
- case tokIdent: // skip leading identifiers, if any
- case tokLocalOfs: // skip local var offset, too
- break;
- case tokChar:
- case tokSChar:
- case tokUChar:
- return 1;
- case tokShort:
- case tokUShort:
- return 2;
- case tokInt:
- case tokUnsigned:
- case '*':
- case '(':
- return SizeOfWord;
- case '[':
- if (SyntaxStack0[i + 1] != tokNumInt && SyntaxStack0[i + 1] != tokNumUint)
- errorInternal(15);
- i += 2;
- break;
- case tokStructPtr:
- // follow the "type pointer"
- i = SyntaxStack1[i] - 1;
- break;
- case tokStruct:
- case tokUnion:
- if (i + 3 < SyntaxStackCnt && SyntaxStack0[i + 2] == tokSizeof)
- {
- return SyntaxStack1[i + 3];
- }
- return 1;
- case tokVoid:
- return 1;
- default:
- errorInternal(16);
- }
- }
- errorInternal(17);
- return 0;
- }
- void DumpDecl(word SyntaxPtr, word IsParam)
- {
- word i;
- word icnt = 0;
- if (SyntaxPtr < 0)
- return;
- for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
- {
- word tok = SyntaxStack0[i];
- word v = SyntaxStack1[i];
- switch (tok)
- {
- case tokLocalOfs:
- printf2("(@");
- printd2(truncInt(v));
- printf2(") : ");
- break;
- case tokIdent:
- if (++icnt > 1 && !IsParam) // show at most one declaration, except params
- return;
- GenStartCommentLine();
- if (ParseLevel == 0)
- printf2("glb ");
- else if (IsParam)
- printf2("prm ");
- else
- printf2("loc ");
- {
- word j;
- for (j = 0; j < ParseLevel * 4; j++)
- printf2(" ");
- }
- if (IsParam && !strcmp(IdentTable + v, "<something>") && (i + 1 < SyntaxStackCnt))
- {
- if (SyntaxStack0[i + 1] == tokEllipsis)
- continue;
- }
- printf2(IdentTable + v);
- printf2(" : ");
- if (!IsParam && (i + 1 < SyntaxStackCnt) && SyntaxStack0[i + 1] == tokIdent)
- {
- // renamed local static variable
- GenPrintLabel(IdentTable + SyntaxStack1[++i]);
- printf2(" : ");
- }
- break;
- case '[':
- printf2("[");
- break;
- case tokNumInt:
- printd2(truncInt(v));
- break;
- case tokNumUint:
- printd2(truncUint(v));
- break;
- case ']':
- printf2("] ");
- break;
- case '(':
- {
- word noparams;
- // Skip over the params to the base type
- word j = ++i, c = 1;
- while (c)
- {
- word t = SyntaxStack0[j++];
- c += (t == '(') - (t == ')');
- }
- noparams = (i + 1 == j) || (SyntaxStack0[i + 1] == tokVoid);
- printf2("(");
- // Print the params (recursively)
- if (noparams)
- {
- // Don't recurse if it's "fxn()" or "fxn(void)"
- if (i + 1 != j)
- printf2("void");
- }
- else
- {
- puts2("");
- ParseLevel++;
- DumpDecl(i, 1);
- ParseLevel--;
- }
- // Continue normally
- i = j - 1;
- if (!noparams)
- {
- GenStartCommentLine();
- printf2(" ");
- {
- word j;
- for (j = 0; j < ParseLevel * 4; j++)
- printf2(" ");
- }
- }
- printf2(") ");
- }
- break;
- case ')': // end of param list
- return;
- case tokStructPtr:
- DumpDecl(v, 0);
- break;
- default:
- switch (tok)
- {
- case tokVoid:
- case tokChar:
- case tokSChar:
- case tokUChar:
- case tokShort:
- case tokUShort:
- case tokInt:
- case tokUnsigned:
- case tokEllipsis:
- printf2(GetTokenName(tok));
- printf2("\n");
- break;
- default:
- printf2(GetTokenName(tok));
- printf2(" ");
- break;
- case tokTag:
- printf2(IdentTable + v);
- printf2("\n");
- return;
- }
- break;
- }
- }
- }
- void DumpSynDecls(void)
- {
- word used = SyntaxStackCnt * (sizeof SyntaxStack0[0] + sizeof SyntaxStack1[0]);
- word total = SYNTAX_STACK_MAX * (sizeof SyntaxStack0[0] + sizeof SyntaxStack1[0]);
- puts2("");
- GenStartCommentLine(); printf2("Syntax/declaration table/stack:\n");
- GenStartCommentLine();
- printf2("Bytes used: ");
- printd2(used);
- printf2("/");
- printd2(total);
- printf2("\n\n");
- }
- word ParseArrayDimension(word AllowEmptyDimension)
- {
- word tok;
- word gotUnary, synPtr, constExpr, exprVal;
- unsigned exprValU;
- word oldssp, oldesp, undoIdents;
- tok = GetToken();
- // DONE: support arbitrary constant expressions
- oldssp = SyntaxStackCnt;
- oldesp = sp;
- undoIdents = IdentTableLen;
- tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0);
- IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof"
- SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" in the expression
- sp = oldesp;
- if (tok != ']')
- //error("ParseArrayDimension(): Unsupported or invalid array dimension (token %s)\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- if (!gotUnary)
- {
- if (!AllowEmptyDimension)
- //error("ParseArrayDimension(): missing array dimension\n");
- errorUnexpectedToken(tok);
- // Empty dimension is dimension of 0
- exprVal = 0;
- }
- else
- {
- if (!constExpr)
- //error("ParseArrayDimension(): non-constant array dimension\n");
- errorNotConst();
- exprValU = truncUint(exprVal);
- exprVal = truncInt(exprVal);
- promoteType(&synPtr, &synPtr);
- anyIntTypeCheck(synPtr);
- if ((SyntaxStack0[synPtr] == tokInt && exprVal < 1) || (SyntaxStack0[synPtr] == tokUnsigned && exprValU < 1))
- error("Array dimension less than 1\n");
- exprVal = (word)exprValU;
- }
- PushSyntax2(tokNumUint, exprVal);
- return tok;
- }
- void ParseFxnParams(word tok);
- static word BrkCntTargetFxn[2];
- word ParseBlock(word BrkCntTarget[2], word casesIdx);
- void AddFxnParamSymbols(word SyntaxPtr);
- void CheckRedecl(word lastSyntaxPtr);
- word ParseBase(word tok, word base[2])
- {
- word valid = 1;
- base[1] = 0;
- switch (tok)
- {
- case tokVoid:
- *base = tok;
- tok = GetToken();
- break;
- case tokChar:
- case tokInt:
- case tokShort:
- case tokLong:
- case tokSigned:
- case tokUnsigned:
- {
- word allowedMask = 0x7F; // double:0x40 unsigned:0x20 signed:0x10 long:0x08 int:0x04 short:0x02 char:0x01
- word typeMask = 0;
- word tokMask, disallowedMask;
- lcont:
- switch (tok)
- {
- case tokChar:
- tokMask = 0x01; disallowedMask = 0x4E; break; // disallows double, long, int, short
- case tokShort:
- tokMask = 0x02; disallowedMask = 0x49; break; // disallows double, long, char
- case tokInt:
- tokMask = 0x04; disallowedMask = 0x41; break; // disallows double, char
- case tokLong:
- tokMask = 0x08; disallowedMask = 0x03; break; // disallows short, char
- case tokSigned:
- tokMask = 0x10; disallowedMask = 0x60; break; // disallows double, unsigned
- case tokUnsigned:
- tokMask = 0x20; disallowedMask = 0x50; break; // disallows double, signed
- default:
- tokMask = disallowedMask = 0; break;
- }
- if (allowedMask & tokMask)
- {
- typeMask |= tokMask;
- allowedMask &= ~(disallowedMask | tokMask);
- tok = GetToken();
- goto lcont;
- }
- switch (typeMask)
- {
- case 0x01: typeMask = tokChar; break;
- case 0x11: typeMask = tokSChar; break;
- case 0x21: typeMask = tokUChar; break;
- case 0x02: case 0x12: case 0x06: case 0x16: typeMask = tokShort; break;
- case 0x22: case 0x26: typeMask = tokUShort; break;
- case 0x04: case 0x10: case 0x14: typeMask = tokInt; break;
- case 0x20: case 0x24: typeMask = tokUnsigned; break;
- case 0x08: case 0x18: case 0x0C: case 0x1C: typeMask = tokLong; break;
- case 0x28: case 0x2C: typeMask = tokULong; break;
- default:
- errorDecl();
- }
- *base = typeMask;
- }
- break;
- case tokStruct:
- case tokUnion:
- {
- word structType = tok;
- word empty = 1;
- word typePtr = SyntaxStackCnt;
- word gotTag = 0, tagIdent = 0, declPtr = -1, curScope = 0;
- tok = GetToken();
- if (tok == tokIdent)
- {
- // this is a structure/union/enum tag
- gotTag = 1;
- declPtr = FindTaggedDecl(TokenIdentName, SyntaxStackCnt - 1, &curScope);
- tagIdent = AddIdent(TokenIdentName);
- if (declPtr >= 0)
- {
- // Within the same scope we can't declare more than one union, structure or enum
- // with the same tag.
- // There's one common tag namespace for structures, unions and enumerations.
- if (curScope && SyntaxStack0[declPtr] != structType)
- errorTagRedef(tagIdent);
- }
- else if (ParamLevel)
- {
- // new structure/union/enum declarations aren't supported in function parameters
- errorDecl();
- }
- tok = GetToken();
- }
- else
- {
- // structure/union/enum declarations aren't supported in expressions
- if (ExprLevel)
- errorDecl();
- PushSyntax(structType);
- PushSyntax2(tokTag, AddIdent("<something>"));
- }
- if (tok == '{')
- {
- unsigned structInfo[4], sz, alignment, tmp;
- // new structure/union/enum declarations aren't supported in expressions and function parameters
- if (ExprLevel || ParamLevel)
- errorDecl();
- if (gotTag)
- {
- // Cannot redefine a tagged structure/union/enum within the same scope
- if (declPtr >= 0 &&
- curScope &&
- ((declPtr + 2 < SyntaxStackCnt && SyntaxStack0[declPtr + 2] == tokSizeof)
- ))
- errorTagRedef(tagIdent);
- PushSyntax(structType);
- PushSyntax2(tokTag, tagIdent);
- }
- {
- structInfo[0] = structType;
- structInfo[1] = 1; // initial member alignment
- structInfo[2] = 0; // initial member offset
- structInfo[3] = 0; // initial max member size (for unions)
- PushSyntax(tokSizeof); // 0 = initial structure/union size, to be updated
- PushSyntax2(tokSizeof, 1); // 1 = initial structure/union alignment, to be updated
- PushSyntax('{');
- tok = GetToken();
- while (tok != '}')
- {
- if (!TokenStartsDeclaration(tok, 1))
- errorUnexpectedToken(tok);
- tok = ParseDecl(tok, structInfo, 0, 0);
- empty = 0;
- }
- if (empty)
- errorUnexpectedToken('}');
- PushSyntax('}');
- // Update structure/union alignment
- alignment = structInfo[1];
- SyntaxStack1[typePtr + 3] = alignment;
- // Update structure/union size and include trailing padding if needed
- sz = structInfo[2] + structInfo[3];
- tmp = sz;
- sz = (sz + alignment - 1) & ~(alignment - 1);
- if (sz < tmp || sz != truncUint(sz))
- {
- //printf("e");
- errorVarSize();
- }
- SyntaxStack1[typePtr + 2] = (word)sz;
- tok = GetToken();
- }
- }
- else
- {
- if (gotTag)
- {
- if (declPtr >= 0 &&
- SyntaxStack0[declPtr] == structType)
- {
- base[0] = tokStructPtr;
- base[1] = declPtr;
- return tok;
- }
- PushSyntax(structType);
- PushSyntax2(tokTag, tagIdent);
- empty = 0;
- }
- }
- if (empty)
- errorDecl();
- base[0] = tokStructPtr;
- base[1] = typePtr;
- // If we've just defined a structure/union and there are
- // preceding references to this tag within this scope,
- // IOW references to an incomplete type, complete the
- // type in the references
- if (gotTag && SyntaxStack0[SyntaxStackCnt - 1] == '}')
- {
- word i;
- for (i = SyntaxStackCnt - 1; i >= 0; i--)
- if (SyntaxStack0[i] == tokStructPtr)
- {
- word j = SyntaxStack1[i];
- if (SyntaxStack1[j + 1] == tagIdent && !GetDeclSize(i, 0))
- SyntaxStack1[i] = typePtr;
- }
- else if (SyntaxStack0[i] == '#')
- {
- // reached the beginning of the current scope
- break;
- }
- }
- }
- break;
- default:
- valid = 0;
- break;
- }
- if (SizeOfWord == 2 &&
- (*base == tokLong || *base == tokULong))
- valid = 0;
- // to simplify matters, treat long and unsigned long as aliases for int and unsigned int
- // in 32-bit and huge mode(l)s
- if (*base == tokLong)
- *base = tokInt;
- if (*base == tokULong)
- *base = tokUnsigned;
- if (SizeOfWord == 2)
- {
- // to simplify matters, treat short and unsigned short as aliases for int and unsigned int
- // in 16-bit mode
- if (*base == tokShort)
- *base = tokInt;
- if (*base == tokUShort)
- *base = tokUnsigned;
- }
- // TBD!!! review/test this fxn
- // if (!valid || !tok || !(strchr("*([,)", tok) || tok == tokIdent))
- if (!valid | !tok)
- //error("ParseBase(): Invalid or unsupported type\n");
- error("Invalid or unsupported type\n");
- return tok;
- }
- /*
- base * name [] -> name : [] * base
- base *2 (*1 name []1) []2 -> name : []1 *1 []2 *2 base
- base *3 (*2 (*1 name []1) []2) []3 -> name : []1 *1 []2 *2 []3 *3 base
- */
- word ParseDerived(word tok)
- {
- word stars = 0;
- word params = 0;
- while (tok == '*')
- {
- stars++;
- tok = GetToken();
- }
- if (tok == '(')
- {
- tok = GetToken();
- if (tok != ')' && !TokenStartsDeclaration(tok, 1))
- {
- tok = ParseDerived(tok);
- if (tok != ')')
- //error("ParseDerived(): ')' expected\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- else
- {
- params = 1;
- }
- }
- else if (tok == tokIdent)
- {
- PushSyntax2(tok, AddIdent(TokenIdentName));
- tok = GetToken();
- }
- else
- {
- PushSyntax2(tokIdent, AddIdent("<something>"));
- }
- if (params | (tok == '('))
- {
- word t = SyntaxStack0[SyntaxStackCnt - 1];
- if ((t == ')') | (t == ']'))
- errorUnexpectedToken('('); // array of functions or function returning function
- if (!params)
- tok = GetToken();
- else
- PushSyntax2(tokIdent, AddIdent("<something>"));
- PushSyntax('(');
- ParseLevel++;
- ParamLevel++;
- ParseFxnParams(tok);
- ParamLevel--;
- ParseLevel--;
- PushSyntax(')');
- tok = GetToken();
- }
- else if (tok == '[')
- {
- // DONE!!! allow the first [] without the dimension in function parameters
- word allowEmptyDimension = 1;
- if (SyntaxStack0[SyntaxStackCnt - 1] == ')')
- errorUnexpectedToken('['); // function returning array
- while (tok == '[')
- {
- word oldsp = SyntaxStackCnt;
- PushSyntax(tokVoid); // prevent cases like "int arr[arr];" and "int arr[arr[0]];"
- PushSyntax(tok);
- tok = ParseArrayDimension(allowEmptyDimension);
- if (tok != ']')
- //error("ParseDerived(): ']' expected\n");
- errorUnexpectedToken(tok);
- PushSyntax(']');
- tok = GetToken();
- DeleteSyntax(oldsp, 1);
- allowEmptyDimension = 0;
- }
- }
- while (stars--)
- PushSyntax('*');
- if (!tok || !strchr(",;{=)", tok))
- //error("ParseDerived(): unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- return tok;
- }
- void PushBase(word base[2])
- {
- {
- PushSyntax2(base[0], base[1]);
- }
- // Cannot have array of void
- if (SyntaxStack0[SyntaxStackCnt - 1] == tokVoid &&
- SyntaxStack0[SyntaxStackCnt - 2] == ']')
- errorUnexpectedVoid();
- }
- word InitScalar(word synPtr, word tok);
- word InitArray(word synPtr, word tok);
- word InitStruct(word synPtr, word tok);
- word InitVar(word synPtr, word tok)
- {
- word p = synPtr, t;
- word undoIdents = IdentTableLen;
- while ((t = SyntaxStack0[p]), (t == tokIdent) | (t == tokLocalOfs))
- p++;
- switch (t)
- {
- case '[':
- // Initializers for aggregates must be enclosed in braces,
- // except for arrays of char initialized with string literals,
- // in which case braces are optional
- if (tok != '{')
- {
- t = SyntaxStack0[p + 3];
- if (((tok != tokLitStr) | ((t != tokChar) & (t != tokUChar) & (t != tokSChar)))
- )
- errorUnexpectedToken(tok);
- }
- tok = InitArray(p, tok);
- break;
- case tokStructPtr:
- // Initializers for aggregates must be enclosed in braces
- if (tok != '{')
- errorUnexpectedToken(tok);
- tok = InitStruct(p, tok);
- break;
- default:
- tok = InitScalar(p, tok);
- break;
- }
- if (!strchr(",;", tok))
- errorUnexpectedToken(tok);
- IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" or "str"
- return tok;
- }
- word InitScalar(word synPtr, word tok)
- {
- unsigned elementSz = GetDeclSize(synPtr, 0);
- word gotUnary, synPtr2, constExpr, exprVal;
- word oldssp = SyntaxStackCnt;
- word undoIdents = IdentTableLen;
- word ttop;
- word braces = 0;
- // Initializers for scalars can be optionally enclosed in braces
- if (tok == '{')
- {
- braces = 1;
- tok = GetToken();
- }
- tok = ParseExpr(tok, &gotUnary, &synPtr2, &constExpr, &exprVal, ',', 0);
- if (!gotUnary)
- errorUnexpectedToken(tok);
- if (braces)
- {
- if (tok != '}')
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- // Bar void and struct/union
- scalarTypeCheck(synPtr2);
- ttop = stack[sp - 1][0];
- if (ttop == tokNumInt || ttop == tokNumUint)
- {
- word val = stack[sp - 1][1];
- // TBD??? truncate values for types smaller than int (e.g. char and short),
- // so they are always in range for the assembler?
- GenIntData(elementSz, val);
- }
- else if (elementSz == (unsigned)SizeOfWord)
- {
- if (ttop == tokIdent)
- {
- GenAddrData(elementSz, IdentTable + stack[sp - 1][1], 0);
- }
- else if (ttop == '+' || ttop == '-')
- {
- word tleft = stack[sp - 3][0];
- word tright = stack[sp - 2][0];
- if (tleft == tokIdent &&
- (tright == tokNumInt || tright == tokNumUint))
- {
- GenAddrData(elementSz, IdentTable + stack[sp - 3][1], (ttop == '+') ? stack[sp - 2][1] : -stack[sp - 2][1]);
- }
- else if (ttop == '+' &&
- tright == tokIdent &&
- (tleft == tokNumInt || tleft == tokNumUint))
- {
- GenAddrData(elementSz, IdentTable + stack[sp - 2][1], stack[sp - 3][1]);
- }
- else
- errorNotConst();
- }
- else
- errorNotConst();
- // Defer storage of string literal data (if any) until the end.
- // This will let us generate the contiguous array of pointers to
- // string literals unperturbed by the string literal data
- // (e.g. "char* colors[] = { "red", "green", "blue" };").
- }
- else
- //error("ParseDecl(): cannot initialize a global variable with a non-constant expression\n");
- errorNotConst();
- IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" or "str"
- SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" or "str" in the expression
- return tok;
- }
- word InitArray(word synPtr, word tok)
- {
- word elementTypePtr = synPtr + 3;
- word elementType = SyntaxStack0[elementTypePtr];
- unsigned elementSz = GetDeclSize(elementTypePtr, 0);
- word braces = 0;
- unsigned elementCnt = 0;
- unsigned elementsRequired = SyntaxStack1[synPtr + 1];
- word arrOfChar = (elementType == tokChar) | (elementType == tokUChar) | (elementType == tokSChar);
- if (tok == '{')
- {
- braces = 1;
- tok = GetToken();
- }
- if ((arrOfChar & (tok == tokLitStr))
- )
- {
- word ltok = tok;
- unsigned sz = 0;
- // this is 'someArray[someCountIfAny] = "some string"' or
- // 'someArray[someCountIfAny] = { "some string" }'
- do
- {
- GetString('"', 0, 'd');
- if (sz + TokenStringSize < sz ||
- sz + TokenStringSize >= truncUint(-1))
- errorStrLen();
- sz += TokenStringSize;
- elementCnt += TokenStringLen;
- tok = GetToken();
- } while (tok == ltok); // concatenate adjacent string literals
- if (elementsRequired && elementCnt > elementsRequired)
- errorStrLen();
- if (elementCnt < elementsRequired)
- GenZeroData(elementsRequired - elementCnt, 0);
- if (!elementsRequired)
- GenZeroData(elementSz, 0), elementCnt++;
- if (braces)
- {
- if (tok != '}')
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- }
- else
- {
- while (tok != '}')
- {
- if (elementType == '[')
- {
- tok = InitArray(elementTypePtr, tok);
- }
- else if (elementType == tokStructPtr)
- {
- tok = InitStruct(elementTypePtr, tok);
- }
- else
- {
- tok = InitScalar(elementTypePtr, tok);
- }
- // Last element?
- if (++elementCnt >= elementsRequired && elementsRequired)
- {
- if (braces & (tok == ','))
- tok = GetToken();
- break;
- }
- if (tok == ',')
- tok = GetToken();
- else if (tok != '}')
- errorUnexpectedToken(tok);
- }
- if (braces)
- {
- if ((!elementCnt) | (tok != '}'))
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- if (elementCnt < elementsRequired)
- GenZeroData((elementsRequired - elementCnt) * elementSz, 0);
- }
- // Store the element count if it's an incomplete array
- if (!elementsRequired)
- SyntaxStack1[synPtr + 1] = elementCnt;
- return tok;
- }
- word InitStruct(word synPtr, word tok)
- {
- word isUnion;
- unsigned size, ofs = 0;
- word braces = 0;
- word c = 1;
- synPtr = SyntaxStack1[synPtr];
- isUnion = SyntaxStack0[synPtr++] == tokUnion;
- size = SyntaxStack1[++synPtr];
- synPtr += 3; // step inside the {} body of the struct/union
- if (tok == '{')
- {
- braces = 1;
- tok = GetToken();
- }
- // Find the first member
- while (c)
- {
- word t = SyntaxStack0[synPtr];
- c += (t == '(') - (t == ')') + (t == '{') - (t == '}');
- if (c == 1 && t == tokMemberIdent)
- break;
- synPtr++;
- }
- while (tok != '}')
- {
- word c = 1;
- word elementTypePtr, elementType;
- unsigned elementOfs, elementSz;
- elementOfs = SyntaxStack1[++synPtr];
- elementTypePtr = ++synPtr;
- elementType = SyntaxStack0[elementTypePtr];
- elementSz = GetDeclSize(elementTypePtr, 0);
- // Alignment
- if (ofs < elementOfs)
- GenZeroData(elementOfs - ofs, 0);
- if (elementType == '[')
- {
- tok = InitArray(elementTypePtr, tok);
- }
- else if (elementType == tokStructPtr)
- {
- tok = InitStruct(elementTypePtr, tok);
- }
- else
- {
- tok = InitScalar(elementTypePtr, tok);
- }
- ofs = elementOfs + elementSz;
- // Find the next member or the closing brace
- while (c)
- {
- word t = SyntaxStack0[synPtr];
- c += (t == '(') - (t == ')') + (t == '{') - (t == '}');
- if (c == 1 && t == tokMemberIdent)
- break;
- synPtr++;
- }
- // Last member?
- // Only one member (first) is initialized in unions explicitly
- if ((!c) | isUnion)
- {
- if (braces & (tok == ','))
- tok = GetToken();
- break;
- }
- if (tok == ',')
- tok = GetToken();
- else if (tok != '}')
- errorUnexpectedToken(tok);
- }
- if (braces)
- {
- if ((!ofs) | (tok != '}'))
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- // Implicit initialization of the rest and trailing padding
- if (ofs < size)
- GenZeroData(size - ofs, 0);
- return tok;
- }
- word compatCheck2(word lastSyntaxPtr, word i)
- {
- word res = 0;
- word c = 0;
- word t;
- for (;;)
- {
- t = SyntaxStack0[lastSyntaxPtr];
- if (t != SyntaxStack0[i])
- {
- if (SyntaxStack0[i] == ')' && SyntaxStack0[i - 1] == '(')
- {
- // Complete a previously incomplete parameter specification
- word c1 = 1;
- // Skip over the function params
- do
- {
- t = SyntaxStack0[lastSyntaxPtr++];
- c1 += (t == '(') - (t == ')');
- } while (c1);
- lastSyntaxPtr--;
- }
- else if (t == ')' &&
- SyntaxStack0[i - 1] == '(' && SyntaxStack0[i] == tokIdent &&
- SyntaxStack0[i + 1] == tokVoid && SyntaxStack0[i + 2] == ')')
- {
- // As an exception allow foo(void) to be redeclared as foo()
- // since this happens very often in code.
- // This weakens our redeclaration checks, however. Warn about it.
- i += 2;
- warning("Redeclaration from no parameters to unspecified parameters.\n");
- }
- else
- goto lend;
- }
- if (t != tokIdent &&
- SyntaxStack1[lastSyntaxPtr] != SyntaxStack1[i])
- {
- if (SyntaxStack0[lastSyntaxPtr - 1] == '[')
- {
- // Complete an incomplete array dimension or check for dimension mismatch
- if (SyntaxStack1[lastSyntaxPtr] == 0)
- SyntaxStack1[lastSyntaxPtr] = SyntaxStack1[i];
- else if (SyntaxStack1[i])
- goto lend;
- }
- else
- goto lend;
- }
- c += (t == '(') - (t == ')') + (t == '[') - (t == ']');
- if (!c)
- {
- switch (t)
- {
- case tokVoid:
- case tokChar: case tokSChar: case tokUChar:
- case tokShort: case tokUShort:
- case tokInt: case tokUnsigned:
- case tokStructPtr:
- goto lok;
- }
- }
- lastSyntaxPtr++;
- i++;
- }
- lok:
- res = 1;
- lend:
- return res;
- }
- void CheckRedecl(word lastSyntaxPtr)
- {
- word tid, id, external = 0;
- word i;
- word curScopeOnly;
- word level = ParseLevel;
- tid = SyntaxStack0[lastSyntaxPtr];
- id = SyntaxStack1[lastSyntaxPtr];
- switch (tid)
- {
- case tokIdent:
- switch (SyntaxStack0[lastSyntaxPtr + 1])
- {
- default:
- external = 1;
- // fallthrough
- case tokLocalOfs: // block-scope auto
- case tokIdent: // block-scope static
- ;
- }
- // fallthrough
- case tokTypedef:
- break;
- case tokMemberIdent:
- {
- word c = 1;
- i = lastSyntaxPtr - 1;
- do
- {
- word t = SyntaxStack0[i];
- c -= (t == '(') - (t == ')') + (t == '{') - (t == '}');
- if (c == 1 &&
- t == tokMemberIdent && SyntaxStack1[i] == id &&
- SyntaxStack0[i + 1] == tokLocalOfs)
- errorRedecl(IdentTable + id);
- i--;
- } while (c);
- }
- return;
- default:
- errorInternal(23);
- }
- // limit search to current scope for typedef and enum,
- // ditto for non-external declarations
- curScopeOnly = tid != tokIdent || !external;
- for (i = lastSyntaxPtr - 1; i >= 0; i--)
- {
- word t = SyntaxStack0[i];
- switch (t)
- {
- case ')':
- {
- // Skip over the function params
- word c = -1;
- while (c)
- {
- t = SyntaxStack0[--i];
- c += (t == '(') - (t == ')');
- }
- }
- break;
- case '#':
- // the scope has changed to the outer scope
- if (curScopeOnly)
- return;
- level--;
- break;
- case tokTypedef:
- case tokIdent:
- if (SyntaxStack1[i] == id)
- {
- if (level == ParseLevel)
- {
- // block scope:
- // can differentiate between auto(tokLocalOfs), static(tokIdent),
- // extern/proto(nothing) in SyntaxStack*[], hence dup checks and
- // type match checks needed here
- // file scope:
- // can't differentiate between static(nothing), extern(nothing),
- // neither(nothing) in SyntaxStack*[], but duplicate definitions
- // are taken care of (in CG), hence only type match checks needed
- // here
- if (level) // block scope: check for bad dups
- {
- switch (SyntaxStack0[i + 1])
- {
- case tokLocalOfs: // block-scope auto
- case tokIdent: // block-scope static
- // auto and static can't be redefined in block scope
- errorRedecl(IdentTable + id);
- default:
- // extern can't be redefined as non-extern in block scope
- if (!external)
- errorRedecl(IdentTable + id);
- }
- // extern/proto type match check follows
- }
- if (compatCheck2(lastSyntaxPtr, i))
- return;
- errorRedecl(IdentTable + id);
- }
- else // elseof if (level == ParseLevel)
- {
- // The new decl is extern/proto.
- // Ignore typedef and enum
- if (t == tokIdent)
- {
- switch (SyntaxStack0[i + 1])
- {
- case tokLocalOfs: // block-scope auto
- case tokIdent: // block-scope static
- // Ignore auto and static
- break;
- default:
- // extern/proto
- if (compatCheck2(lastSyntaxPtr, i))
- return;
- errorRedecl(IdentTable + id);
- }
- }
- }
- } // endof if (SyntaxStack1[i] == id)
- break;
- } // endof switch (t)
- } // endof for (i = lastSyntaxPtr - 1; i >= 0; i--)
- }
- // DONE: support extern
- // DONE: support static
- // DONE: support basic initialization
- // DONE: support simple non-array initializations with string literals
- // DONE: support basic 1-d array initialization
- // DONE: global/static data allocations
- word ParseDecl(word tok, unsigned structInfo[4], word cast, word label)
- {
- word base[2];
- word lastSyntaxPtr;
- word external = tok == tokExtern;
- word Static = tok == tokStatic;
- (void)label;
- if (external |
- Static)
- {
- tok = GetToken();
- if (!TokenStartsDeclaration(tok, 1))
- //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok));
- // Implicit int (as in "extern x; static y;") isn't supported
- errorUnexpectedToken(tok);
- }
- tok = ParseBase(tok, base);
- for (;;)
- {
- lastSyntaxPtr = SyntaxStackCnt;
- /* derived type */
- tok = ParseDerived(tok);
- /* base type */
- PushBase(base);
- if ((tok && strchr(",;{=", tok)) || (tok == ')' && ExprLevel))
- {
- word isLocal = 0, isGlobal = 0, isFxn, isStruct, isArray, isIncompleteArr;
- unsigned alignment = 0;
- word staticLabel = 0;
- // Disallow void variables
- if (SyntaxStack0[SyntaxStackCnt - 1] == tokVoid)
- {
- if (SyntaxStack0[SyntaxStackCnt - 2] == tokIdent &&
- !(cast
- ))
- //error("ParseDecl(): Cannot declare a variable ('%s') of type 'void'\n", IdentTable + SyntaxStack1[lastSyntaxPtr]);
- errorUnexpectedVoid();
- }
- isFxn = SyntaxStack0[lastSyntaxPtr + 1] == '(';
- isArray = SyntaxStack0[lastSyntaxPtr + 1] == '[';
- isIncompleteArr = isArray && SyntaxStack1[lastSyntaxPtr + 2] == 0;
- isStruct = SyntaxStack0[lastSyntaxPtr + 1] == tokStructPtr;
- if (!(ExprLevel || structInfo) &&
- !(external |
- Static) &&
- !strcmp(IdentTable + SyntaxStack1[lastSyntaxPtr], "<something>") &&
- tok == ';')
- {
- if (isStruct)
- {
- // This is either an incomplete tagged structure/union declaration, e.g. "struct sometag;",
- // or a tagged complete structure/union declaration, e.g. "struct sometag { ... };", without an instance variable,
- // or an untagged complete structure/union declaration, e.g. "struct { ... };", without an instance variable
- word declPtr, curScope;
- word j = SyntaxStack1[lastSyntaxPtr + 1];
- if (j + 2 < SyntaxStackCnt &&
- IdentTable[SyntaxStack1[j + 1]] == '<' && // without tag
- SyntaxStack0[j + 2] == tokSizeof) // but with the {} "body"
- errorDecl();
- // If a structure/union with this tag has been declared in an outer scope,
- // this new declaration should override it
- declPtr = FindTaggedDecl(IdentTable + SyntaxStack1[j + 1], lastSyntaxPtr - 1, &curScope);
- if (declPtr >= 0 && !curScope)
- {
- // If that's the case, unbind this declaration from the old declaration
- // and make it a new incomplete declaration
- PushSyntax(SyntaxStack0[j]); // tokStruct or tokUnion
- PushSyntax2(tokTag, SyntaxStack1[j + 1]);
- SyntaxStack1[lastSyntaxPtr + 1] = SyntaxStackCnt - 2;
- }
- return GetToken();
- }
- }
- // Structure/union members can't be initialized nor be functions nor
- // be incompletely typed arrays inside structure/union declarations
- if (structInfo && ((tok == '=') | isFxn | (tok == '{') | isIncompleteArr))
- errorDecl();
- // Error conditions in declarations(/definitions/initializations):
- // Legend:
- // + error
- // - no error
- //
- // file scope fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[]
- // - - - - - + +
- // file scope fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]=
- // + - - + - +
- // file scope extern fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[]
- // - - - - - - -
- // file scope extern fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]=
- // + + + + + +
- // file scope static fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[]
- // - - - - - + +
- // file scope static fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]=
- // + - - + - +
- // fxn scope fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[]
- // - + - - - + +
- // fxn scope fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]=
- // + - + + + +
- // fxn scope extern fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[]
- // - + - - - - -
- // fxn scope extern fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]=
- // + + + + + +
- // fxn scope static fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[]
- // + + + + + + +
- // fxn scope static fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]=
- // + + + + + +
- if (isFxn & (tok == '='))
- //error("ParseDecl(): cannot initialize a function\n");
- errorInit();
- if ((isFxn & (tok == '{')) && ParseLevel)
- //error("ParseDecl(): cannot define a nested function\n");
- errorDecl();
- if ((isFxn & Static) && ParseLevel)
- //error("ParseDecl(): cannot declare a static function in this scope\n");
- errorDecl();
- if (external & (tok == '='))
- //error("ParseDecl(): cannot initialize an external variable\n");
- errorInit();
- if (isIncompleteArr & !(external |
- (tok == '=')))
- //error("ParseDecl(): cannot define an array of incomplete type\n");
- errorDecl();
- // TBD!!! de-uglify
- if (!strcmp(IdentTable + SyntaxStack1[lastSyntaxPtr], "<something>"))
- {
- // Disallow nameless variables, prototypes, structure/union members and typedefs.
- if (structInfo ||
- !ExprLevel)
- error("Identifier expected in declaration\n");
- }
- else
- {
- // Disallow named variables and prototypes in sizeof(typedecl) and (typedecl).
- if (ExprLevel && !structInfo)
- error("Identifier unexpected in declaration\n");
- }
- if (!isFxn
- )
- {
- // This is a variable or a variable (member) in a struct/union declaration
- word sz = GetDeclSize(lastSyntaxPtr, 0);
- if (!((sz | isIncompleteArr) || ExprLevel)) // incomplete type
- errorDecl(); // TBD!!! different error when struct/union tag is not found
- if (isArray && !GetDeclSize(lastSyntaxPtr + 4, 0))
- // incomplete type of array element (e.g. struct/union)
- errorDecl();
- alignment = GetDeclAlignment(lastSyntaxPtr);
- if (structInfo)
- {
- // It's a variable (member) in a struct/union declaration
- unsigned tmp;
- unsigned newAlignment = alignment;
- // Update structure/union alignment
- if (structInfo[1] < newAlignment)
- structInfo[1] = newAlignment;
- // Align structure member
- tmp = structInfo[2];
- structInfo[2] = (structInfo[2] + newAlignment - 1) & ~(newAlignment - 1);
- if (structInfo[2] < tmp || structInfo[2] != truncUint(structInfo[2]))
- {
- //printf("f");
- errorVarSize();
- }
- // Change tokIdent to tokMemberIdent and insert a local var offset token
- SyntaxStack0[lastSyntaxPtr] = tokMemberIdent;
- InsertSyntax2(lastSyntaxPtr + 1, tokLocalOfs, (word)structInfo[2]);
- // Advance member offset for structures, keep it zero for unions
- if (structInfo[0] == tokStruct)
- {
- tmp = structInfo[2];
- structInfo[2] += sz;
- if (structInfo[2] < tmp || structInfo[2] != truncUint(structInfo[2]))
- {
- //printf("g");
- errorVarSize();
- }
- }
- // Update max member size for unions
- else if (structInfo[3] < (unsigned)sz)
- {
- structInfo[3] = sz;
- }
- }
- else if (ParseLevel && !((external | Static) || ExprLevel))
- {
- // It's a local variable
- isLocal = 1;
- // Defer size calculation until initialization
- // Insert a local var offset token, the offset is to be updated
- InsertSyntax2(lastSyntaxPtr + 1, tokLocalOfs, 0);
- }
- else if (!ExprLevel)
- {
- // It's a global variable (external, static or neither)
- isGlobal = 1;
- if (Static && ParseLevel)
- {
- // It's a static variable in function scope, "rename" it by providing
- // an alternative unique numeric identifier right next to it and use it
- staticLabel = LabelCnt++;
- InsertSyntax2(lastSyntaxPtr + 1, tokIdent, AddNumericIdent(staticLabel));
- }
- }
- }
- // If it's a type declaration in a sizeof(typedecl) expression or
- // in an expression with a cast, e.g. (typedecl)expr, we're done
- if (ExprLevel && !structInfo)
- {
- if (doAnnotations)
- {
- DumpDecl(lastSyntaxPtr, 0);
- }
- return tok;
- }
- if (isLocal | isGlobal)
- {
- word hasInit = tok == '=';
- word needsGlobalInit = isGlobal & !external;
- word sz = GetDeclSize(lastSyntaxPtr, 0);
- word initLabel = 0;
- word bss = (!hasInit) & UseBss;
- if (doAnnotations)
- {
- if (isGlobal)
- DumpDecl(lastSyntaxPtr, 0);
- }
- if (hasInit)
- {
- tok = GetToken();
- }
- if (isLocal & hasInit)
- needsGlobalInit = isArray | (isStruct & (tok == '{'));
- if (needsGlobalInit)
- {
- char** oldHeaderFooter = CurHeaderFooter;
- if (oldHeaderFooter)
- puts2(oldHeaderFooter[1]);
- CurHeaderFooter = bss ? BssHeaderFooter : DataHeaderFooter;
- puts2(CurHeaderFooter[0]);
- // DONE: imperfect condition for alignment
- if (alignment != 1)
- GenWordAlignment(bss);
- if (isGlobal)
- {
- if (Static && ParseLevel)
- GenNumLabel(staticLabel);
- else
- GenLabel(IdentTable + SyntaxStack1[lastSyntaxPtr], Static);
- }
- else
- {
- // Generate numeric labels for global initializers of local vars
- GenNumLabel(initLabel = LabelCnt++);
- }
- // Generate global initializers
- if (hasInit)
- {
- if (doAnnotations)
- {
- if (isGlobal)
- {
- GenStartCommentLine(); printf2("=\n");
- }
- }
- tok = InitVar(lastSyntaxPtr, tok);
- // Update the size in case it's an incomplete array
- sz = GetDeclSize(lastSyntaxPtr, 0);
- }
- else
- {
- GenZeroData(sz, bss);
- }
- puts2(CurHeaderFooter[1]);
- if (oldHeaderFooter)
- puts2(oldHeaderFooter[0]);
- CurHeaderFooter = oldHeaderFooter;
- }
- if (isLocal)
- {
- // Now that the size of the local is certainly known,
- // update its offset in the offset token
- SyntaxStack1[lastSyntaxPtr + 1] = AllocLocal(sz);
- if (doAnnotations)
- {
- DumpDecl(lastSyntaxPtr, 0);
- }
- }
- // Copy global initializers into local vars
- if (isLocal & needsGlobalInit)
- {
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("=\n");
- }
- if (!StructCpyLabel)
- StructCpyLabel = LabelCnt++;
- sp = 0;
- push2('(', SizeOfWord * 3);
- push2(tokLocalOfs, SyntaxStack1[lastSyntaxPtr + 1]);
- push(',');
- push2(tokIdent, AddNumericIdent(initLabel));
- push(',');
- push2(tokNumUint, sz);
- push(',');
- push2(tokIdent, AddNumericIdent(StructCpyLabel));
- push2(')', SizeOfWord * 3);
- GenExpr();
- }
- // Initialize local vars with expressions
- else if (hasInit & !needsGlobalInit)
- {
- word gotUnary, synPtr, constExpr, exprVal;
- word brace = 0;
- // Initializers for scalars can be optionally enclosed in braces
- if ((!isStruct) & (tok == '{'))
- {
- brace = 1;
- tok = GetToken();
- }
- // ParseExpr() will transform the initializer expression into an assignment expression here
- tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, '=', SyntaxStack1[lastSyntaxPtr]);
- if (!gotUnary)
- errorUnexpectedToken(tok);
- if (brace)
- {
- if (tok != '}')
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- if (!isStruct)
- {
- // This is a special case for initialization of integers smaller than int.
- // Since a local integer variable always takes as much space as a whole int,
- // we can optimize code generation a bit by storing the initializer as an int.
- // This is an old accidental optimization and I preserve it for now.
- // Note, this implies a little-endian CPU.
- stack[sp - 1][1] = SizeOfWord;
- }
- // Storage of string literal data from the initializing expression
- // occurs here.
- GenExpr();
- }
- }
- else if (tok == '{')
- {
- // It's a function body. Let's add function parameters as
- // local variables to the symbol table and parse the body.
- word undoSymbolsPtr = SyntaxStackCnt;
- word undoIdents = IdentTableLen;
- word i;
- word endLabel = 0;
- if (doAnnotations)
- {
- DumpDecl(lastSyntaxPtr, 0);
- }
- CurFxnName = IdentTable + SyntaxStack1[lastSyntaxPtr];
- IsMain = !strcmp(CurFxnName, "main");
- gotoLabCnt = 0;
- if (verbose)
- {
- printf(CurFxnName);
- printf("()\n");
- }
- ParseLevel++;
- GetFxnInfo(lastSyntaxPtr, &CurFxnParamCntMin, &CurFxnParamCntMax, &CurFxnReturnExprTypeSynPtr, NULL); // get return type
- CurHeaderFooter = CodeHeaderFooter;
- puts2(CurHeaderFooter[0]);
- //BDOS_PrintlnConsole(CurFxnName);
- //printf2("; put the function label here:\n");
- GenLabel(CurFxnName, Static);
- GenFxnProlog();
- CurFxnEpilogLabel = LabelCnt++;
- // A new scope begins before the function parameters
- PushSyntax('#');
- AddFxnParamSymbols(lastSyntaxPtr);
- // The block doesn't begin yet another new scope.
- // This is to catch redeclarations of the function parameters.
- tok = ParseBlock(BrkCntTargetFxn, 0);
- ParseLevel--;
- if (tok != '}')
- //error("ParseDecl(): '}' expected\n");
- errorUnexpectedToken(tok);
- for (i = 0; i < gotoLabCnt; i++)
- if (gotoLabStat[i] == 2)
- {
- printf("Undeclared label ");
- error(IdentTable + gotoLabels[i][0]);
- }
- // DONE: if execution of main() reaches here, before the epilog (i.e. without using return),
- // main() should return 0.
- if (IsMain)
- {
- sp = 0;
- push(tokNumInt);
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- }
- GenNumLabel(CurFxnEpilogLabel);
- GenFxnEpilog();
- if (GenFxnSizeNeeded())
- GenNumLabel(endLabel = LabelCnt++);
- puts2(CurHeaderFooter[1]);
- CurHeaderFooter = NULL;
- if (GenFxnSizeNeeded())
- GenRecordFxnSize(CurFxnName, endLabel);
- CurFxnName = NULL;
- IdentTableLen = undoIdents; // remove all identifier names
- SyntaxStackCnt = undoSymbolsPtr; // remove all params and locals
- SyntaxStack1[SymFuncPtr] = DummyIdent;
- }
- else if (isFxn)
- {
- if (doAnnotations)
- {
- // function prototype
- DumpDecl(lastSyntaxPtr, 0);
- }
- }
- CheckRedecl(lastSyntaxPtr);
- if ((tok == ';') | (tok == '}'))
- break;
- tok = GetToken();
- continue;
- }
- //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- }
- tok = GetToken();
- return tok;
- }
- void ParseFxnParams(word tok)
- {
- word base[2];
- word lastSyntaxPtr;
- word cnt = 0;
- word ellCnt = 0;
- for (;;)
- {
- lastSyntaxPtr = SyntaxStackCnt;
- if (tok == ')') /* unspecified params */
- break;
- if (!TokenStartsDeclaration(tok, 1))
- {
- if (tok == tokEllipsis)
- {
- // "..." cannot be the first parameter and
- // it can be only one
- if (!cnt || ellCnt)
- //error("ParseFxnParams(): '...' unexpected here\n");
- errorUnexpectedToken(tok);
- ellCnt++;
- }
- else
- //error("ParseFxnParams(): Unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- base[0] = tok; // "..."
- base[1] = 0;
- PushSyntax2(tokIdent, AddIdent("<something>"));
- tok = GetToken();
- }
- else
- {
- if (ellCnt)
- //error("ParseFxnParams(): '...' must be the last in the parameter list\n");
- errorUnexpectedToken(tok);
- /* base type */
- tok = ParseBase(tok, base);
- /* derived type */
- tok = ParseDerived(tok);
- }
- /* base type */
- PushBase(base);
- /* Decay arrays to pointers */
- lastSyntaxPtr++; /* skip name */
- if (SyntaxStack0[lastSyntaxPtr] == '[')
- {
- word t;
- DeleteSyntax(lastSyntaxPtr, 1);
- t = SyntaxStack0[lastSyntaxPtr];
- if (t == tokNumInt || t == tokNumUint)
- DeleteSyntax(lastSyntaxPtr, 1);
- SyntaxStack0[lastSyntaxPtr] = '*';
- }
- /* "(Un)decay" functions to function pointers */
- else if (SyntaxStack0[lastSyntaxPtr] == '(')
- {
- InsertSyntax(lastSyntaxPtr, '*');
- }
- lastSyntaxPtr--; /* "unskip" name */
- cnt++;
- if (tok == ')' || tok == ',')
- {
- word t = SyntaxStack0[SyntaxStackCnt - 2];
- if (SyntaxStack0[SyntaxStackCnt - 1] == tokVoid)
- {
- // Disallow void variables. TBD!!! de-uglify
- if (t == tokIdent &&
- !(!strcmp(IdentTable + SyntaxStack1[SyntaxStackCnt - 2], "<something>") &&
- cnt == 1 && tok == ')'))
- //error("ParseFxnParams(): Cannot declare a variable ('%s') of type 'void'\n", IdentTable + SyntaxStack1[lastSyntaxPtr]);
- errorUnexpectedVoid();
- }
- if (tok == ')')
- break;
- tok = GetToken();
- continue;
- }
- //error("ParseFxnParams(): Unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- }
- }
- void AddFxnParamSymbols(word SyntaxPtr)
- {
- word i;
- unsigned paramOfs = 2 * SizeOfWord; // ret addr, xbp
- if (SyntaxPtr < 0 ||
- SyntaxPtr > SyntaxStackCnt - 3 ||
- SyntaxStack0[SyntaxPtr] != tokIdent ||
- SyntaxStack0[SyntaxPtr + 1] != '(')
- //error("Internal error: AddFxnParamSymbols(): Invalid input\n");
- errorInternal(6);
- CurFxnSyntaxPtr = SyntaxPtr;
- CurFxnLocalOfs = 0;
- CurFxnMinLocalOfs = 0;
- SyntaxPtr += 2; // skip "ident("
- for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
- {
- word tok = SyntaxStack0[i];
- if (tok == tokIdent)
- {
- unsigned sz;
- word paramPtr;
- if (i + 1 >= SyntaxStackCnt)
- //error("Internal error: AddFxnParamSymbols(): Invalid input\n");
- errorInternal(7);
- if (SyntaxStack0[i + 1] == tokVoid) // "ident(void)" = no params
- break;
- if (SyntaxStack0[i + 1] == tokEllipsis) // "ident(something,...)" = no more params
- break;
- // Make sure the parameter is not an incomplete structure
- sz = GetDeclSize(i, 0);
- if (sz == 0)
- //error("Internal error: AddFxnParamSymbols(): GetDeclSize() = 0\n");
- //errorInternal(8);
- errorDecl();
- // Let's calculate this parameter's relative on-stack location
- paramPtr = SyntaxStackCnt;
- PushSyntax2(SyntaxStack0[i], SyntaxStack1[i]);
- PushSyntax2(tokLocalOfs, paramOfs);
- if (sz + SizeOfWord - 1 < sz)
- {
- //printf("h");
- errorVarSize();
- }
- sz = (sz + SizeOfWord - 1) & ~(SizeOfWord - 1u);
- if (paramOfs + sz < paramOfs)
- {
- //printf("i");
- errorVarSize();
- }
- paramOfs += sz;
- if (paramOfs > (unsigned)GenMaxLocalsSize())
- {
- //printf("j");
- errorVarSize();
- }
- // Duplicate this parameter in the symbol table
- i++;
- while (i < SyntaxStackCnt)
- {
- tok = SyntaxStack0[i];
- if (tok == tokIdent || tok == ')')
- {
- if (doAnnotations)
- {
- DumpDecl(paramPtr, 0);
- }
- if (IdentTable[SyntaxStack1[paramPtr]] == '<')
- error("Parameter name expected\n");
- CheckRedecl(paramPtr);
- i--;
- break;
- }
- else if (tok == '(')
- {
- word c = 1;
- i++;
- PushSyntax(tok);
- while (c && i < SyntaxStackCnt)
- {
- tok = SyntaxStack0[i];
- c += (tok == '(') - (tok == ')');
- PushSyntax2(SyntaxStack0[i], SyntaxStack1[i]);
- i++;
- }
- }
- else
- {
- PushSyntax2(SyntaxStack0[i], SyntaxStack1[i]);
- i++;
- }
- }
- }
- else if (tok == ')') // endof "ident(" ... ")"
- break;
- else
- //error("Internal error: AddFxnParamSymbols(): Unexpected token %s\n", GetTokenName(tok));
- errorInternal(9);
- }
- }
- word ParseStatement(word tok, word BrkCntTarget[2], word casesIdx)
- {
- /*
- labeled statements:
- + ident : statement
- + case const-expr : statement
- + default : statement
- compound statement:
- + { declaration(s)/statement(s)-opt }
- expression statement:
- + expression-opt ;
- selection statements:
- + if ( expression ) statement
- + if ( expression ) statement else statement
- + switch ( expression ) { statement(s)-opt }
- iteration statements:
- + while ( expression ) statement
- + do statement while ( expression ) ;
- + for ( expression-opt ; expression-opt ; expression-opt ) statement
- jump statements:
- + goto ident ;
- + continue ;
- + break ;
- + return expression-opt ;
- */
- word gotUnary, synPtr, constExpr, exprVal;
- word brkCntTarget[2];
- word statementNeeded;
- do
- {
- statementNeeded = 0;
- if (tok == ';')
- {
- tok = GetToken();
- }
- else if (tok == '{')
- {
- // A new {} block begins in the function body
- word undoSymbolsPtr = SyntaxStackCnt;
- word undoLocalOfs = CurFxnLocalOfs;
- word undoIdents = IdentTableLen;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("{\n");
- }
- ParseLevel++;
- tok = ParseBlock(BrkCntTarget, casesIdx);
- ParseLevel--;
- if (tok != '}')
- //error("ParseStatement(): '}' expected. Unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- UndoNonLabelIdents(undoIdents); // remove all identifier names, except those of labels
- SyntaxStackCnt = undoSymbolsPtr; // remove all params and locals
- CurFxnLocalOfs = undoLocalOfs; // destroy on-stack local variables
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("}\n");
- }
- tok = GetToken();
- }
- else if (tok == tokReturn)
- {
- // DONE: functions returning void vs non-void
- word retVoid = CurFxnReturnExprTypeSynPtr >= 0 &&
- SyntaxStack0[CurFxnReturnExprTypeSynPtr] == tokVoid;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("return\n");
- }
- tok = GetToken();
- if (tok == ';')
- {
- gotUnary = 0;
- if (!retVoid)
- //error("ParseStatement(): missing return value\n");
- errorUnexpectedToken(tok);
- }
- else
- {
- if (retVoid)
- //error("Error: ParseStatement(): cannot return a value from a function returning 'void'\n");
- errorUnexpectedToken(tok);
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';')
- //error("ParseStatement(): ';' expected\n");
- errorUnexpectedToken(tok);
- if (gotUnary)
- //error("ParseStatement(): cannot return a value of type 'void'\n");
- // Bar void
- nonVoidTypeCheck(synPtr);
- }
- if (gotUnary)
- {
- decayArray(&synPtr, 0);
- {
- word castSize = GetDeclSize(CurFxnReturnExprTypeSynPtr, 1);
- // If return value (per function declaration) is a scalar type smaller than machine word,
- // properly zero- or sign-extend the returned value to machine word size.
- // TBD??? Move this cast to the caller?
- if (castSize != SizeOfWord && castSize != GetDeclSize(synPtr, 1))
- {
- if (constExpr)
- {
- switch (castSize)
- {
- case 1:
- exprVal &= 0xFFu;
- break;
- case -1:
- if ((exprVal &= 0xFFu) >= 0x80)
- exprVal -= 0x100;
- break;
- case 2:
- exprVal &= 0xFFFFu;
- break;
- case -2:
- if ((exprVal &= 0xFFFFu) >= 0x8000)
- exprVal -= 0x10000;
- break;
- }
- }
- else
- {
- switch (castSize)
- {
- case 1:
- push(tokUChar);
- break;
- case -1:
- push(tokSChar);
- break;
- case 2:
- push(tokUShort);
- break;
- case -2:
- push(tokShort);
- break;
- }
- }
- }
- }
- if (constExpr)
- stack[0][1] = exprVal;
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- }
- tok = GetToken();
- // If this return is the last statement in the function, the epilogue immediately
- // follows and there's no need to jump to it.
- if (!(tok == '}' && ParseLevel == 1 && !IsMain))
- GenJumpUncond(CurFxnEpilogLabel);
- }
- else if (tok == tokWhile)
- {
- word labelBefore = LabelCnt++;
- word labelAfter = LabelCnt++;
- word forever = 0;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("while\n");
- }
- tok = GetToken();
- if (tok != '(')
- //error("ParseStatement(): '(' expected after 'while'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
- //error("ParseStatement(): ')' expected after 'while ( expression'\n");
- errorUnexpectedToken(tok);
- if (!gotUnary)
- //error("ParseStatement(): expression expected in 'while ( expression )'\n");
- errorUnexpectedToken(tok);
- // DONE: void control expressions
- //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n");
- // Bar void and struct/union
- scalarTypeCheck(synPtr);
- GenNumLabel(labelBefore);
- if (constExpr)
- {
- // Special cases for while(0) and while(1)
- if (!(forever = truncInt(exprVal)))
- GenJumpUncond(labelAfter);
- }
- else
- {
- switch (stack[sp - 1][0])
- {
- case '<':
- case '>':
- case tokEQ:
- case tokNEQ:
- case tokLEQ:
- case tokGEQ:
- case tokULess:
- case tokUGreater:
- case tokULEQ:
- case tokUGEQ:
- push2(tokIfNot, labelAfter);
- GenExpr();
- break;
- default:
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- GenJumpIfZero(labelAfter);
- break;
- }
- }
- tok = GetToken();
- brkCntTarget[0] = labelAfter; // break target
- brkCntTarget[1] = labelBefore; // continue target
- tok = ParseStatement(tok, brkCntTarget, casesIdx);
- // Special case for while(0)
- if (!(constExpr && !forever))
- GenJumpUncond(labelBefore);
- GenNumLabel(labelAfter);
- }
- else if (tok == tokDo)
- {
- word labelBefore = LabelCnt++;
- word labelWhile = LabelCnt++;
- word labelAfter = LabelCnt++;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("do\n");
- }
- GenNumLabel(labelBefore);
- tok = GetToken();
- brkCntTarget[0] = labelAfter; // break target
- brkCntTarget[1] = labelWhile; // continue target
- tok = ParseStatement(tok, brkCntTarget, casesIdx);
- if (tok != tokWhile)
- //error("ParseStatement(): 'while' expected after 'do statement'\n");
- errorUnexpectedToken(tok);
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("while\n");
- }
- tok = GetToken();
- if (tok != '(')
- //error("ParseStatement(): '(' expected after 'while'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
- //error("ParseStatement(): ')' expected after 'while ( expression'\n");
- errorUnexpectedToken(tok);
- if (!gotUnary)
- //error("ParseStatement(): expression expected in 'while ( expression )'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if (tok != ';')
- //error("ParseStatement(): ';' expected after 'do statement while ( expression )'\n");
- errorUnexpectedToken(tok);
- // DONE: void control expressions
- //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n");
- // Bar void and struct/union
- scalarTypeCheck(synPtr);
- GenNumLabel(labelWhile);
- if (constExpr)
- {
- // Special cases for while(0) and while(1)
- if (truncInt(exprVal))
- GenJumpUncond(labelBefore);
- }
- else
- {
- switch (stack[sp - 1][0])
- {
- case '<':
- case '>':
- case tokEQ:
- case tokNEQ:
- case tokLEQ:
- case tokGEQ:
- case tokULess:
- case tokUGreater:
- case tokULEQ:
- case tokUGEQ:
- push2(tokIf, labelBefore);
- GenExpr();
- break;
- default:
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- GenJumpIfNotZero(labelBefore);
- break;
- }
- }
- GenNumLabel(labelAfter);
- tok = GetToken();
- }
- else if (tok == tokIf)
- {
- word labelAfterIf = LabelCnt++;
- word labelAfterElse = LabelCnt++;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("if\n");
- }
- tok = GetToken();
- if (tok != '(')
- //error("ParseStatement(): '(' expected after 'if'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
- //error("ParseStatement(): ')' expected after 'if ( expression'\n");
- errorUnexpectedToken(tok);
- if (!gotUnary)
- //error("ParseStatement(): expression expected in 'if ( expression )'\n");
- errorUnexpectedToken(tok);
- // DONE: void control expressions
- //error("ParseStatement(): unexpected 'void' expression in 'if ( expression )'\n");
- // Bar void and struct/union
- scalarTypeCheck(synPtr);
- if (constExpr)
- {
- // Special cases for if(0) and if(1)
- if (!truncInt(exprVal))
- GenJumpUncond(labelAfterIf);
- }
- else
- {
- switch (stack[sp - 1][0])
- {
- case '<':
- case '>':
- case tokEQ:
- case tokNEQ:
- case tokLEQ:
- case tokGEQ:
- case tokULess:
- case tokUGreater:
- case tokULEQ:
- case tokUGEQ:
- push2(tokIfNot, labelAfterIf);
- GenExpr();
- break;
- default:
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- GenJumpIfZero(labelAfterIf);
- break;
- }
- }
- tok = GetToken();
- tok = ParseStatement(tok, BrkCntTarget, casesIdx);
- // DONE: else
- if (tok == tokElse)
- {
- GenJumpUncond(labelAfterElse);
- GenNumLabel(labelAfterIf);
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("else\n");
- }
- tok = GetToken();
- tok = ParseStatement(tok, BrkCntTarget, casesIdx);
- GenNumLabel(labelAfterElse);
- }
- else
- {
- GenNumLabel(labelAfterIf);
- }
- }
- else if (tok == tokFor)
- {
- word labelBefore = LabelCnt++;
- word labelExpr3 = LabelCnt++;
- word labelBody = LabelCnt++;
- word labelAfter = LabelCnt++;
- word cond = -1;
- static word expr3Stack[STACK_SIZE >> 1][2];
- static word expr3Sp;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("for\n");
- }
- tok = GetToken();
- if (tok != '(')
- //error("ParseStatement(): '(' expected after 'for'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- {
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';')
- //error("ParseStatement(): ';' expected after 'for ( expression'\n");
- errorUnexpectedToken(tok);
- if (gotUnary)
- {
- GenExpr();
- }
- tok = GetToken();
- }
- GenNumLabel(labelBefore);
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';')
- //error("ParseStatement(): ';' expected after 'for ( expression ; expression'\n");
- errorUnexpectedToken(tok);
- if (gotUnary)
- {
- // DONE: void control expressions
- //error("ParseStatement(): unexpected 'void' expression in 'for ( ; expression ; )'\n");
- // Bar void and struct/union
- scalarTypeCheck(synPtr);
- if (constExpr)
- {
- // Special cases for for(...; 0; ...) and for(...; 1; ...)
- cond = truncInt(exprVal) != 0;
- }
- else
- {
- switch (stack[sp - 1][0])
- {
- case '<':
- case '>':
- case tokEQ:
- case tokNEQ:
- case tokLEQ:
- case tokGEQ:
- case tokULess:
- case tokUGreater:
- case tokULEQ:
- case tokUGEQ:
- push2(tokIfNot, labelAfter);
- GenExpr();
- break;
- default:
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- GenJumpIfZero(labelAfter);
- break;
- }
- }
- }
- else
- {
- // Special case for for(...; ; ...)
- cond = 1;
- }
- if (!cond)
- // Special case for for(...; 0; ...)
- GenJumpUncond(labelAfter);
- tok = GetToken();
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
- //error("ParseStatement(): ')' expected after 'for ( expression ; expression ; expression'\n");
- errorUnexpectedToken(tok);
- // Try to reorder expr3 with body to reduce the number of jumps, favor small expr3's
- if (gotUnary && sp <= 16 && (unsigned)sp <= division(sizeof expr3Stack , sizeof expr3Stack[0]) - expr3Sp)
- {
- word cnt = sp;
- // Stash the stack containing expr3
- memcpy(expr3Stack + expr3Sp, stack, cnt * sizeof stack[0]);
- expr3Sp += cnt;
- // Body
- tok = GetToken();
- brkCntTarget[0] = labelAfter; // break target
- brkCntTarget[1] = labelExpr3; // continue target
- tok = ParseStatement(tok, brkCntTarget, casesIdx);
- // Unstash expr3 and generate code for it
- expr3Sp -= cnt;
- memcpy(stack, expr3Stack + expr3Sp, cnt * sizeof stack[0]);
- sp = cnt;
- GenNumLabel(labelExpr3);
- GenExpr();
- // Special case for for(...; 0; ...)
- if (cond)
- GenJumpUncond(labelBefore);
- }
- else
- {
- if (gotUnary)
- {
- GenJumpUncond(labelBody);
- // expr3
- GenNumLabel(labelExpr3);
- GenExpr();
- GenJumpUncond(labelBefore);
- GenNumLabel(labelBody);
- }
- // Body
- tok = GetToken();
- brkCntTarget[0] = labelAfter; // break target
- brkCntTarget[1] = gotUnary ? labelExpr3 : (cond ? labelBefore : labelAfter); // continue target
- tok = ParseStatement(tok, brkCntTarget, casesIdx);
- // Special case for for(...; 0; ...)
- if (brkCntTarget[1] != labelAfter)
- GenJumpUncond(brkCntTarget[1]);
- }
- GenNumLabel(labelAfter);
- }
- else if (tok == tokBreak)
- {
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("break\n");
- }
- if ((tok = GetToken()) != ';')
- //error("ParseStatement(): ';' expected\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if (BrkCntTarget == NULL)
- //error("ParseStatement(): 'break' must be within 'while', 'for' or 'switch' statement\n");
- errorCtrlOutOfScope();
- GenJumpUncond(BrkCntTarget[0]);
- }
- else if (tok == tokCont)
- {
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("continue\n");
- }
- if ((tok = GetToken()) != ';')
- //error("ParseStatement(): ';' expected\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if (BrkCntTarget == NULL || BrkCntTarget[1] == 0)
- //error("ParseStatement(): 'continue' must be within 'while' or 'for' statement\n");
- errorCtrlOutOfScope();
- GenJumpUncond(BrkCntTarget[1]);
- }
- else if (tok == tokSwitch)
- {
- word undoCases = CasesCnt;
- word brkLabel = LabelCnt++;
- word lbl = LabelCnt++;
- word i;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("switch\n");
- }
- tok = GetToken();
- if (tok != '(')
- //error("ParseStatement(): '(' expected after 'switch'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
- //error("ParseStatement(): ')' expected after 'switch ( expression'\n");
- errorUnexpectedToken(tok);
- if (!gotUnary)
- //error("ParseStatement(): expression expected in 'switch ( expression )'\n");
- errorUnexpectedToken(tok);
- // DONE: void control expressions
- //error("ParseStatement(): unexpected 'void' expression in 'switch ( expression )'\n");
- anyIntTypeCheck(synPtr);
- push(tokReturn); // value produced by generated code is used
- GenExpr();
- tok = GetToken();
- // Skip the code for the cases
- GenJumpUncond(lbl);
- brkCntTarget[0] = brkLabel; // break target
- brkCntTarget[1] = 0; // continue target
- if (BrkCntTarget)
- {
- // Preserve the continue target
- brkCntTarget[1] = BrkCntTarget[1]; // continue target
- }
- // Reserve a slot in the case table for the default label
- AddCase(0, 0);
- tok = ParseStatement(tok, brkCntTarget, CasesCnt);
- // If there's no default target, will use the break target as default
- if (!Cases[undoCases][1])
- Cases[undoCases][1] = brkLabel;
- // End of switch reached (not via break), skip conditional jumps
- GenJumpUncond(brkLabel);
- // Generate conditional jumps
- GenNumLabel(lbl);
- for (i = undoCases + 1; i < CasesCnt; i++)
- {
- GenJumpIfEqual(Cases[i][0], Cases[i][1]);
- }
- // If none of the cases matches, take the default case
- if (Cases[undoCases][1] != brkLabel)
- GenJumpUncond(Cases[undoCases][1]);
- GenNumLabel(brkLabel); // break label
- CasesCnt = undoCases;
- }
- else if (tok == tokCase)
- {
- word i;
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("case\n");
- }
- if (!casesIdx)
- //error("ParseStatement(): 'case' must be within 'switch' statement\n");
- errorCtrlOutOfScope();
- tok = GetToken();
- if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ':')
- //error("ParseStatement(): ':' expected after 'case expression'\n");
- errorUnexpectedToken(tok);
- if (!gotUnary)
- errorUnexpectedToken(tok);
- anyIntTypeCheck(synPtr);
- if (!constExpr)
- //error("ParseStatement(): constant integer expression expected in 'case expression :'\n");
- errorNotConst();
- // Check for dups
- exprVal = truncInt(exprVal);
- for (i = casesIdx; i < CasesCnt; i++)
- if (Cases[i][0] == exprVal)
- error("Duplicate case value\n");
- AddCase(exprVal, LabelCnt);
- GenNumLabel(LabelCnt++); // case exprVal:
- tok = GetToken();
- // a statement is needed after "case:"
- statementNeeded = 1;
- }
- else if (tok == tokDefault)
- {
- if (doAnnotations)
- {
- GenStartCommentLine(); printf2("default\n");
- }
- if (!casesIdx)
- //error("ParseStatement(): 'default' must be within 'switch' statement\n");
- errorCtrlOutOfScope();
- if (Cases[casesIdx - 1][1])
- //error("ParseStatement(): only one 'default' allowed in 'switch'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if (tok != ':')
- //error("ParseStatement(): ':' expected after 'default'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- GenNumLabel(Cases[casesIdx - 1][1] = LabelCnt++); // default:
- // a statement is needed after "default:"
- statementNeeded = 1;
- }
- else if (tok == tok_Asm)
- {
- tok = GetToken();
- if (tok != '(')
- //error("ParseStatement(): '(' expected after 'asm'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if (tok != tokLitStr)
- //error("ParseStatement(): string literal expression expected in 'asm ( expression )'\n");
- errorUnexpectedToken(tok);
- do
- {
- GetString('"', 0, 'a');
- tok = GetToken();
- } while (tok == tokLitStr); // concatenate adjacent string literals
- printf2("\n");
- if (tok != ')')
- //error("ParseStatement(): ')' expected after 'asm ( expression'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- if (tok != ';')
- //error("ParseStatement(): ';' expected after 'asm ( expression )'\n");
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- else if (tok == tokGoto)
- {
- if ((tok = GetToken()) != tokIdent)
- errorUnexpectedToken(tok);
- GenStartCommentLine();
- if (doAnnotations)
- {
- printf2("goto ");
- printf2(TokenIdentName);
- printf2("\n");
- }
- GenJumpUncond(AddGotoLabel(TokenIdentName, 0));
- if ((tok = GetToken()) != ';')
- errorUnexpectedToken(tok);
- tok = GetToken();
- }
- else
- {
- tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, tokGotoLabel, 0);
- if (tok == tokGotoLabel)
- {
- // found a label
- if (doAnnotations)
- {
- GenStartCommentLine();
- printf2(IdentTable + stack[0][1]);
- printf2(":\n");
- }
- GenNumLabel(AddGotoLabel(IdentTable + stack[0][1], 1));
- // a statement is needed after "label:"
- statementNeeded = 1;
- }
- else
- {
- if (tok != ';')
- //error("ParseStatement(): ';' expected\n");
- errorUnexpectedToken(tok);
- if (gotUnary)
- GenExpr();
- }
- tok = GetToken();
- }
- } while (statementNeeded);
- return tok;
- }
- // TBD!!! think of ways of getting rid of casesIdx
- word ParseBlock(word BrkCntTarget[2], word casesIdx)
- {
- word tok = GetToken();
- // Catch redeclarations of function parameters by not
- // beginning a new scope if this block begins a function
- // (the caller of ParseBlock() must've begun a new scope
- // already, before the function parameters).
- if (BrkCntTarget == BrkCntTargetFxn)
- BrkCntTarget = NULL;
- else
- // Otherwise begin a new scope.
- PushSyntax('#');
- for (;;)
- {
- if (tok == 0)
- return tok;
- if (tok == '}' && ParseLevel > 0)
- return tok;
- if (TokenStartsDeclaration(tok, 0))
- {
- tok = ParseDecl(tok, NULL, 0, 1);
- }
- else if (ParseLevel > 0 || tok == tok_Asm)
- {
- tok = ParseStatement(tok, BrkCntTarget, casesIdx);
- }
- else
- //error("ParseBlock(): Unexpected token %s\n", GetTokenName(tok));
- errorUnexpectedToken(tok);
- }
- }
- int main()
- {
- printf("BCC Compiler\n");
- // Run-time initializer for SyntaxStack0[] to reduce
- // executable file size (SyntaxStack0[] will be in .bss)
- static unsigned char SyntaxStackInit[] =
- {
- tokVoid, // SymVoidSynPtr
- tokInt, // SymIntSynPtr
- tokUnsigned, // SymUintSynPtr
- tokVoid, // SymWideCharSynPtr
- tokFloat, // SymFloatSynPtr
- tokIdent, // SymFuncPtr
- '[',
- tokNumUint,
- ']',
- tokChar
- }; // SyntaxStackCnt must be initialized to the number of elements in SyntaxStackInit[]
- memcpy(SyntaxStack0, SyntaxStackInit, sizeof SyntaxStackInit);
- SyntaxStackCnt = 10;
- SyntaxStack1[SymFuncPtr] = DummyIdent = AddIdent("");
- GenInit();
- // TODO: add BDOS path to filenames if not absolute path
- compileOS = 0;
- compileUserBDOS = 1;
- char infilename[64];
- BDOS_GetArgN(1, infilename);
- if (infilename[0] == 0)
- {
- strcat(infilename, BDOS_GetPath());
- if (infilename[strlen(infilename)-1] != '/')
- {
- strcat(infilename, "/");
- }
- strcat(infilename, "CODE.C");
- //strcpy(infilename, "/TEST/TEST.C");
- }
- if (infilename[0] != '/')
- {
- char bothPath[64];
- bothPath[0] = 0;
- strcat(bothPath, BDOS_GetPath());
- if (bothPath[strlen(bothPath)-1] != '/')
- {
- strcat(bothPath, "/");
- }
- strcat(bothPath, infilename);
- strcpy(infilename, bothPath);
- }
- if (FileCnt == 0)
- {
- // If it's none of the known options,
- // assume it's the source code file name
- if (strlen(infilename) > MAX_FILE_NAME_LEN)
- {
- //error("File name too long\n");
- errorFileName();
- }
- strcpy(FileNames[0], infilename);
- Files[0] = fopen(FileNames[0], 0);
- if (fcanopen(Files[0]) == EOF)
- {
- //error("Cannot open file \"%s\"\n", FileNames[0]);
- errorFile(FileNames[0]);
- }
- else
- {
- //printf("Opened input file\n");
- }
- LineNos[0] = LineNo;
- LinePoss[0] = LinePos;
- FileCnt++;
- }
- char outfilename[64];
- BDOS_GetArgN(2, outfilename);
- if (outfilename[0] == 0)
- {
- strcat(outfilename, BDOS_GetPath());
- if (outfilename[strlen(outfilename)-1] != '/')
- {
- strcat(outfilename, "/");
- }
- strcat(outfilename, "OUT.ASM");
- //strcpy(outfilename, "/TEST/A.OUT");
- }
- if (outfilename[0] != '/')
- {
- char bothPath[64];
- bothPath[0] = 0;
- strcat(bothPath, BDOS_GetPath());
- if (bothPath[strlen(bothPath)-1] != '/')
- {
- strcat(bothPath, "/");
- }
- strcat(bothPath, outfilename);
- strcpy(outfilename, bothPath);
- }
- if (FileCnt == 1 && OutFile == NULL)
- {
- // This should be the output file name
- OutFile = fopen(outfilename, 1);
- if (fcanopen(OutFile) == EOF)
- {
- //error("Cannot open output file \"%s\"\n", argv[i]);
- errorFile(outfilename);
- }
- else
- {
- //printf("Opened output file\n");
- }
- }
- if (!FileCnt)
- error("Input file not specified\n");
- if (!OutFile)
- error("Output file not specified\n");
- GenInitFinalize();
- // Define a few macros useful for conditional compilation
- /*
- DefineMacro("__SMALLER_C__", "0x0100");
- DefineMacro("__SMALLER_C_32__", "");
- DefineMacro("__SMALLER_C_SCHAR__", "");
- */
- // populate CharQueue[] with the initial file characters
- ShiftChar();
- puts2(FileHeader);
- // compile
- ParseBlock(NULL, 0);
- GenFin();
- if (doAnnotations)
- {
- DumpSynDecls();
- DumpMacroTable();
- DumpIdentTable();
- }
-
- /*
- GenStartCommentLine();
- printf2("Next label number: ");
- printd2(LabelCnt);
- printf2("\n");
- */
- //GenStartCommentLine();
- printf("Finished compiling\n");
- if (OutFile)
- fclose(OutFile);
- return 'q';
- }
- void interrupt()
- {
- }
|