123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980 |
- /*
- Copyright (c) 2021-2024, bartpleiter
- 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 */
- /* */
- /*****************************************************************************/
- // 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
- #define OUTFILE_DATA_ADDR 0x500000
- #include "lib/math.c"
- #include "lib/sys.c"
- #include "lib/stdlib.c"
- #include "lib/brfs.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 128
- #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 FileSizes[MAX_INCLUDES]; // file size in words
- 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 < MATH_divU(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 < MATH_divU(sizeof tktk , sizeof tktk[0]); i++)
- if (tktk[i] == token)
- return tks[i];
- // Reserved keywords:
- for (i = 0; i < MATH_divU(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], FileSizes[FileCnt - 1])) == EOF)
- {
- fs_close(Files[FileCnt - 1]);
- Files[FileCnt - 1] = NULL;
- bdos_println(" Done");
- // 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] = fs_open(cFileDir);
- bdos_print("- Compiling: ");
- bdos_print(basename(cFileDir));
- // Get file size
- struct brfs_dir_entry* entry = (struct brfs_dir_entry*)fs_stat(cFileDir);
- word filesize = entry->filesize;
- FileSizes[FileCnt] = filesize;
- }
- // 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] = fs_open(FileNames[FileCnt])) != NULL)
- {
- bdos_print("- Compiling: ");
- bdos_println(basename(FileNames[FileCnt]));
- // Get file size
- struct brfs_dir_entry* entry = (struct brfs_dir_entry*)fs_stat(FileNames[FileCnt]);
- word filesize = entry->filesize;
- FileSizes[FileCnt] = filesize;
- 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 < MATH_divU(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' + MATH_modU(n , 10);
- n = MATH_divU(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, MATH_divU(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) || MATH_divU(sl , sr) != truncInt(MATH_divU(sl , sr))))
- {
- div0 = 1;
- }
- else
- {
- if (Unsigned)
- {
- if (tok == '/')
- sl = (word)((unsigned)MATH_divU(sl , sr));
- else
- sl = (word)((unsigned)MATH_modU(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 = MATH_divU(sl, sr);
- else
- sl = MATH_modU(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])
- fs_close(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)
- fs_close(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 < MATH_divU(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 <= MATH_divU(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");
- // Read number of arguments
- word argc = shell_argc();
- if (argc < 3)
- {
- printf("Usage: BCC <source file> <output file>\n");
- return 1;
- }
- // Get input filename
- char** args = shell_argv();
- char* filename = args[1];
- char absolute_path_in[MAX_PATH_LENGTH];
- // Check if absolute path
- if (filename[0] != '/')
- {
- strcpy(absolute_path_in, fs_getcwd());
- strcat(absolute_path_in, "/");
- strcat(absolute_path_in, filename);
- }
- else
- {
- strcpy(absolute_path_in, filename);
- }
- // Get output filename
- args = shell_argv();
- filename = args[2];
- char absolute_path_out[MAX_PATH_LENGTH];
- // Check if absolute path
- if (filename[0] != '/')
- {
- strcpy(absolute_path_out, fs_getcwd());
- strcat(absolute_path_out, "/");
- strcat(absolute_path_out, filename);
- }
- else
- {
- strcpy(absolute_path_out, filename);
- }
- // 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();
- compileOS = 0;
- compileUserBDOS = 1;
- if (FileCnt == 0)
- {
- // If it's none of the known options,
- // assume it's the source code file name
- if (strlen(absolute_path_in) > MAX_FILE_NAME_LEN)
- {
- //error("File name too long\n");
- errorFileName();
- }
- strcpy(FileNames[0], absolute_path_in);
- Files[0] = fs_open(FileNames[0]);
- bdos_print("Compiling: ");
- bdos_println(basename(FileNames[0]));
- // Get file size
- struct brfs_dir_entry* entry = (struct brfs_dir_entry*)fs_stat(FileNames[0]);
- word filesize = entry->filesize;
- FileSizes[0] = filesize;
-
- if (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++;
- }
- if (FileCnt == 1 && OutFile == NULL)
- {
- // (re)create file for output
- fs_delete(absolute_path_out);
- fs_mkfile(absolute_path_out);
- // This should be the output file name
- OutFile = fs_open(absolute_path_out);
- if (OutFile == EOF)
- {
- //error("Cannot open output file \"%s\"\n", argv[i]);
- errorFile(absolute_path_out);
- }
- 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("Writing to file\n");
- stdio_flush(OutFile);
- if (OutFile)
- fs_close(OutFile);
- return 'q';
- }
- void interrupt()
- {
- // Handle all interrupts
- word i = get_int_id();
- switch(i)
- {
- case INTID_TIMER1:
- timer1Value = 1; // Notify ending of timer1
- break;
- }
- }
|