1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975 |
- /*
- 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
- #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;
- // 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_println(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(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(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("Finished compiling\n");
- 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;
- }
- }
|