scanner.pas 216 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the scanner part and handling of the switches
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit scanner;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,
  22. globtype,globals,constexp,version,tokens,
  23. symtype,symdef,symsym,
  24. verbose,comphook,
  25. finput,
  26. widestr;
  27. const
  28. max_include_nesting=32;
  29. max_macro_nesting=16;
  30. preprocbufsize=32*1024;
  31. { when parsing an internally generated macro, if an identifier is
  32. prefixed with this constant then it will always be interpreted as a
  33. unit name (to avoid clashes with user-specified parameter or field
  34. names duplicated in internally generated code) }
  35. internal_macro_escape_unit_namespace_name = #1;
  36. internal_macro_escape_begin = internal_macro_escape_unit_namespace_name;
  37. internal_macro_escape_end = internal_macro_escape_unit_namespace_name;
  38. type
  39. tcommentstyle = (comment_none,comment_tp,comment_oldtp,comment_delphi,comment_c);
  40. tscannerfile = class;
  41. preproctyp = (pp_ifdef,pp_ifndef,pp_if,pp_ifopt,pp_else,pp_elseif);
  42. tpreprocstack = class
  43. typ,
  44. { stores the preproctyp of the last (else)if(ndef) directive
  45. so we can check properly for ifend when legacyifend is on }
  46. iftyp : preproctyp;
  47. accept : boolean;
  48. next : tpreprocstack;
  49. name : TIDString;
  50. line_nb : longint;
  51. fileindex : longint;
  52. constructor Create(atyp:preproctyp;a:boolean;n:tpreprocstack);
  53. end;
  54. tdirectiveproc=procedure;
  55. tdirectiveitem = class(TFPHashObject)
  56. public
  57. is_conditional : boolean;
  58. proc : tdirectiveproc;
  59. constructor Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  60. constructor CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  61. end;
  62. // stack for replay buffers
  63. treplaystack = class
  64. token : ttoken;
  65. idtoken : ttoken;
  66. orgpattern,
  67. pattern : string;
  68. cstringpattern: ansistring;
  69. patternw : pcompilerwidestring;
  70. settings : tsettings;
  71. tokenbuf : tdynamicarray;
  72. tokenbuf_needs_swapping : boolean;
  73. next : treplaystack;
  74. constructor Create(atoken: ttoken;aidtoken:ttoken;
  75. const aorgpattern,apattern:string;const acstringpattern:ansistring;
  76. apatternw:pcompilerwidestring;asettings:tsettings;
  77. atokenbuf:tdynamicarray;change_endian:boolean;anext:treplaystack);
  78. destructor destroy;override;
  79. end;
  80. tcompile_time_predicate = function(var valuedescr: String) : Boolean;
  81. tspecialgenerictoken =
  82. (ST_LOADSETTINGS,
  83. ST_LINE,
  84. ST_COLUMN,
  85. ST_FILEINDEX,
  86. ST_LOADMESSAGES);
  87. { tscannerfile }
  88. tscannerfile = class
  89. private
  90. procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
  91. procedure cachenexttokenpos;
  92. procedure setnexttoken;
  93. procedure savetokenpos;
  94. procedure restoretokenpos;
  95. procedure writetoken(t: ttoken);
  96. function readtoken : ttoken;
  97. public
  98. inputfile : tinputfile; { current inputfile list }
  99. inputfilecount : longint;
  100. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  101. private
  102. hidden_inputbuffer, { input buffer }
  103. hidden_inputpointer : pchar;
  104. { Gets char at inputpointer with offset,
  105. after checking that it doesn't overflow inputfile.bufsize }
  106. function get_inputpointer_char(offset : longint = 0) : char;
  107. procedure inc_inputpointer(amount : longint = 1);
  108. procedure dec_inputpointer;
  109. public
  110. {$else not CHECK_INPUTPOINTER_LIMITS}
  111. inputbuffer, { input buffer }
  112. inputpointer : pchar;
  113. {$endif}
  114. inputstart : longint;
  115. line_no, { line }
  116. lastlinepos : longint;
  117. lasttokenpos,
  118. nexttokenpos : longint; { token }
  119. lasttoken,
  120. nexttoken : ttoken;
  121. oldlasttokenpos : longint; { temporary saving/restoring tokenpos }
  122. oldcurrent_filepos,
  123. oldcurrent_tokenpos : tfileposinfo;
  124. replaytokenbuf,
  125. recordtokenbuf : tdynamicarray;
  126. { last settings we stored }
  127. last_settings : tsettings;
  128. last_message : pmessagestaterecord;
  129. { last filepos we stored }
  130. last_filepos,
  131. { if nexttoken<>NOTOKEN, then nexttokenpos holds its filepos }
  132. next_filepos : tfileposinfo;
  133. { current macro nesting depth }
  134. macro_nesting_depth,
  135. comment_level,
  136. yylexcount : longint;
  137. ignoredirectives : TFPHashList; { ignore directives, used to give warnings only once }
  138. preprocstack : tpreprocstack;
  139. replaystack : treplaystack;
  140. preproc_pattern : string;
  141. preproc_token : ttoken;
  142. { true, if we are parsing preprocessor expressions }
  143. in_preproc_comp_expr : boolean;
  144. { true if tokens must be converted to opposite endianess}
  145. change_endian_for_replay : boolean;
  146. constructor Create(const fn:string; is_macro: boolean = false);
  147. destructor Destroy;override;
  148. { File buffer things }
  149. function openinputfile:boolean;
  150. procedure closeinputfile;
  151. function tempopeninputfile:boolean;
  152. procedure tempcloseinputfile;
  153. procedure saveinputfile;
  154. procedure restoreinputfile;
  155. procedure firstfile;
  156. procedure nextfile;
  157. procedure addfile(hp:tinputfile);
  158. procedure reload;
  159. { replaces current token with the text in p }
  160. procedure substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);
  161. { Scanner things }
  162. procedure gettokenpos;
  163. procedure inc_comment_level;
  164. procedure dec_comment_level;
  165. procedure illegal_char(c:char);
  166. procedure end_of_file;
  167. procedure checkpreprocstack;
  168. procedure poppreprocstack;
  169. procedure ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  170. procedure elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  171. procedure elsepreprocstack;
  172. procedure popreplaystack;
  173. function replay_stack_depth:longint;
  174. procedure handleconditional(p:tdirectiveitem);
  175. procedure handledirectives;
  176. procedure linebreak;
  177. procedure recordtoken;
  178. procedure startrecordtokens(buf:tdynamicarray);
  179. procedure stoprecordtokens;
  180. function is_recording_tokens:boolean;
  181. procedure replaytoken;
  182. procedure startreplaytokens(buf:tdynamicarray; change_endian:boolean);
  183. { bit length asizeint is target depend }
  184. procedure tokenwritesizeint(val : asizeint);
  185. procedure tokenwritelongint(val : longint);
  186. procedure tokenwritelongword(val : longword);
  187. procedure tokenwriteword(val : word);
  188. procedure tokenwriteshortint(val : shortint);
  189. procedure tokenwriteset(var b;size : longint);
  190. procedure tokenwriteenum(var b;size : longint);
  191. function tokenreadsizeint : asizeint;
  192. procedure tokenwritesettings(var asettings : tsettings; var size : asizeint);
  193. { longword/longint are 32 bits on all targets }
  194. { word/smallint are 16-bits on all targest }
  195. function tokenreadlongword : longword;
  196. function tokenreadword : word;
  197. function tokenreadlongint : longint;
  198. function tokenreadsmallint : smallint;
  199. { short int is one a signed byte }
  200. function tokenreadshortint : shortint;
  201. function tokenreadbyte : byte;
  202. { This one takes the set size as an parameter }
  203. procedure tokenreadset(var b;size : longint);
  204. function tokenreadenum(size : longint) : longword;
  205. procedure tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
  206. procedure readchar;
  207. procedure readstring;
  208. procedure readnumber;
  209. function readid:string;
  210. function readval:longint;
  211. function readcomment(include_special_char: boolean = false):string;
  212. function readquotedstring:string;
  213. function readstate:char;
  214. function readoptionalstate(fallback:char):char;
  215. function readstatedefault:char;
  216. procedure skipspace;
  217. procedure skipuntildirective;
  218. procedure skipcomment(read_first_char:boolean);
  219. procedure skipdelphicomment;
  220. procedure skipoldtpcomment(read_first_char:boolean);
  221. procedure readtoken(allowrecordtoken:boolean);
  222. function readpreproc:ttoken;
  223. function readpreprocint(var value:int64;const place:string):boolean;
  224. function readpreprocset(conform_to:tsetdef;var value:tnormalset;const place:string):boolean;
  225. function asmgetchar:char;
  226. {$ifdef EXTDEBUG}
  227. function DumpPointer : string;
  228. {$endif EXTDEBUG}
  229. end;
  230. {$ifdef PREPROCWRITE}
  231. tpreprocfile=class
  232. f : text;
  233. buf : pointer;
  234. spacefound,
  235. eolfound : boolean;
  236. constructor create(const fn:string);
  237. destructor destroy; override;
  238. procedure Add(const s:string);
  239. procedure AddSpace;
  240. end;
  241. {$endif PREPROCWRITE}
  242. var
  243. { read strings }
  244. c : char;
  245. orgpattern,
  246. pattern : string;
  247. cstringpattern : ansistring;
  248. patternw : pcompilerwidestring;
  249. { token }
  250. token, { current token being parsed }
  251. idtoken : ttoken; { holds the token if the pattern is a known word }
  252. current_commentstyle : tcommentstyle; { needed to use read_comment from directives }
  253. {$ifdef PREPROCWRITE}
  254. preprocfile : tpreprocfile; { used with only preprocessing }
  255. {$endif PREPROCWRITE}
  256. type
  257. tdirectivemode = (directive_all, directive_turbo, directive_mac);
  258. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  259. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  260. procedure InitScanner;
  261. procedure DoneScanner;
  262. function current_scanner : tscannerfile; { current scanner in use }
  263. procedure set_current_scanner(avalue : tscannerfile); { current scanner in use }
  264. { To be called when the language mode is finally determined }
  265. Function SetCompileMode(const s:string; changeInit: boolean):boolean;
  266. Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
  267. procedure SetAppType(NewAppType:tapptype);
  268. var
  269. onfreescanner : procedure(s : tscannerfile) = nil;
  270. implementation
  271. uses
  272. SysUtils,
  273. cutils,cfileutl,
  274. systems,
  275. switches,
  276. symbase,symtable,symconst,defutil,defcmp,node,
  277. { This is needed for tcputype }
  278. cpuinfo,
  279. fmodule,fppu,
  280. { this is needed for $I %CURRENTROUTINE%}
  281. procinfo;
  282. var
  283. { dictionaries with the supported directives }
  284. turbo_scannerdirectives : TFPHashObjectList; { for other modes }
  285. mac_scannerdirectives : TFPHashObjectList; { for mode mac }
  286. {
  287. By default the current_scanner is current_module.scanner.
  288. set_current_scanner sets the _temp_scanner variable.
  289. If _temp_scanner is set, it is returned as the current scanner
  290. }
  291. _temp_scanner : tscannerfile;
  292. function current_scanner : tscannerfile; { current scanner in use }
  293. begin
  294. Result:=_temp_scanner;
  295. if result<>nil then
  296. exit;
  297. if assigned(current_module) then
  298. Result:=Tscannerfile(current_module.scanner)
  299. else
  300. Result:=Nil;
  301. end;
  302. {*****************************************************************************
  303. Helper routines
  304. *****************************************************************************}
  305. const
  306. { use any special name that is an invalid file name to avoid problems }
  307. preprocstring : array [preproctyp] of string[7]
  308. = ('$IFDEF','$IFNDEF','$IF','$IFOPT','$ELSE','$ELSEIF');
  309. function is_keyword(const s:string):boolean;
  310. var
  311. low,high,mid : longint;
  312. begin
  313. if not (length(s) in [tokenlenmin..tokenlenmax]) or
  314. not (s[1] in ['a'..'z','A'..'Z']) then
  315. begin
  316. is_keyword:=false;
  317. exit;
  318. end;
  319. low:=ord(tokenidx^[length(s),s[1]].first);
  320. high:=ord(tokenidx^[length(s),s[1]].last);
  321. while low<high do
  322. begin
  323. mid:=(high+low+1) shr 1;
  324. if pattern<tokeninfo^[ttoken(mid)].str then
  325. high:=mid-1
  326. else
  327. low:=mid;
  328. end;
  329. is_keyword:=(pattern=tokeninfo^[ttoken(high)].str) and
  330. ((tokeninfo^[ttoken(high)].keyword*current_settings.modeswitches)<>[]);
  331. end;
  332. Procedure HandleModeSwitches(switch: tmodeswitch; changeInit: boolean);
  333. begin
  334. { turn ansi/unicodestrings on by default ? (only change when this
  335. particular setting is changed, so that a random modeswitch won't
  336. change the state of $h+/$h-) }
  337. if switch in [m_none,m_default_ansistring,m_default_unicodestring] then
  338. begin
  339. if ([m_default_ansistring,m_default_unicodestring]*current_settings.modeswitches)<>[] then
  340. begin
  341. { can't have both ansistring and unicodestring as default }
  342. if switch=m_default_ansistring then
  343. begin
  344. exclude(current_settings.modeswitches,m_default_unicodestring);
  345. if changeinit then
  346. exclude(init_settings.modeswitches,m_default_unicodestring);
  347. end
  348. else if switch=m_default_unicodestring then
  349. begin
  350. exclude(current_settings.modeswitches,m_default_ansistring);
  351. if changeinit then
  352. exclude(init_settings.modeswitches,m_default_ansistring);
  353. end;
  354. { enable $h+ }
  355. include(current_settings.localswitches,cs_refcountedstrings);
  356. if changeinit then
  357. include(init_settings.localswitches,cs_refcountedstrings);
  358. if m_default_unicodestring in current_settings.modeswitches then
  359. begin
  360. def_system_macro('FPC_UNICODESTRINGS');
  361. def_system_macro('UNICODE');
  362. end;
  363. end
  364. else
  365. begin
  366. exclude(current_settings.localswitches,cs_refcountedstrings);
  367. if changeinit then
  368. exclude(init_settings.localswitches,cs_refcountedstrings);
  369. undef_system_macro('FPC_UNICODESTRINGS');
  370. undef_system_macro('UNICODE');
  371. end;
  372. end;
  373. { turn inline on by default ? }
  374. if switch in [m_none,m_default_inline] then
  375. begin
  376. if (m_default_inline in current_settings.modeswitches) then
  377. begin
  378. include(current_settings.localswitches,cs_do_inline);
  379. if changeinit then
  380. include(init_settings.localswitches,cs_do_inline);
  381. end
  382. else
  383. begin
  384. exclude(current_settings.localswitches,cs_do_inline);
  385. if changeinit then
  386. exclude(init_settings.localswitches,cs_do_inline);
  387. end;
  388. end;
  389. { turn on system codepage by default }
  390. if switch in [m_none,m_systemcodepage] then
  391. begin
  392. { both m_systemcodepage and specifying a code page via -FcXXX or
  393. "$codepage XXX" change current_settings.sourcecodepage. If
  394. we used -FcXXX and then have a sourcefile with "$mode objfpc",
  395. this routine will be called to disable m_systemcodepage (to ensure
  396. it's off in case it would have been set on the command line, or
  397. by a previous mode(switch).
  398. In that case, we have to ensure that we don't overwrite
  399. current_settings.sourcecodepage, as that would cancel out the
  400. -FcXXX. This is why we use two separate module switches
  401. (cs_explicit_codepage and cs_system_codepage) for the same setting
  402. (current_settings.sourcecodepage)
  403. }
  404. if m_systemcodepage in current_settings.modeswitches then
  405. begin
  406. { m_systemcodepage gets enabled -> disable any -FcXXX and
  407. "codepage XXX" settings (exclude cs_explicit_codepage), and
  408. overwrite the sourcecode page }
  409. current_settings.sourcecodepage:=DefaultSystemCodePage;
  410. if (current_settings.sourcecodepage<>CP_UTF8) and not cpavailable(current_settings.sourcecodepage) then
  411. begin
  412. Message2(scan_w_unavailable_system_codepage,IntToStr(current_settings.sourcecodepage),IntToStr(default_settings.sourcecodepage));
  413. current_settings.sourcecodepage:=default_settings.sourcecodepage;
  414. end;
  415. exclude(current_settings.moduleswitches,cs_explicit_codepage);
  416. include(current_settings.moduleswitches,cs_system_codepage);
  417. if changeinit then
  418. begin
  419. init_settings.sourcecodepage:=current_settings.sourcecodepage;
  420. exclude(init_settings.moduleswitches,cs_explicit_codepage);
  421. include(init_settings.moduleswitches,cs_system_codepage);
  422. end;
  423. end
  424. else
  425. begin
  426. { m_systemcodepage gets disabled -> reset sourcecodepage only if
  427. cs_explicit_codepage is not set (it may be set in the scenario
  428. where -FcXXX was passed on the command line and then "$mode
  429. fpc" is used, because then the caller of this routine will
  430. set the "$mode fpc" modeswitches (which don't include
  431. m_systemcodepage) and call this routine with m_none).
  432. Or it can happen if -FcXXX was passed, and the sourcefile
  433. contains "$modeswitch systemcodepage-" statement.
  434. Since we unset cs_system_codepage if m_systemcodepage gets
  435. activated, we will revert to the default code page if you
  436. set a source file code page, then enable the systemcode page
  437. and finally disable it again. We don't keep a stack of
  438. settings, by design. The only thing we have to ensure is that
  439. disabling m_systemcodepage if it wasn't on in the first place
  440. doesn't overwrite the sourcecodepage }
  441. exclude(current_settings.moduleswitches,cs_system_codepage);
  442. if not(cs_explicit_codepage in current_settings.moduleswitches) then
  443. current_settings.sourcecodepage:=default_settings.sourcecodepage;
  444. if changeinit then
  445. begin
  446. exclude(init_settings.moduleswitches,cs_system_codepage);
  447. if not(cs_explicit_codepage in init_settings.moduleswitches) then
  448. init_settings.sourcecodepage:=default_settings.sourcecodepage;
  449. end;
  450. end;
  451. end;
  452. {$ifdef i8086}
  453. { enable cs_force_far_calls when m_nested_procvars is enabled }
  454. if switch=m_nested_procvars then
  455. begin
  456. include(current_settings.localswitches,cs_force_far_calls);
  457. if changeinit then
  458. include(init_settings.localswitches,cs_force_far_calls);
  459. end;
  460. {$endif i8086}
  461. end;
  462. procedure set_current_scanner(avalue: tscannerfile);
  463. begin
  464. _temp_scanner:=avalue;
  465. end;
  466. Function SetCompileMode(const s:string; changeInit: boolean):boolean;
  467. var
  468. b : boolean;
  469. oldmodeswitches : tmodeswitches;
  470. begin
  471. oldmodeswitches:=current_settings.modeswitches;
  472. b:=true;
  473. if s='DEFAULT' then
  474. current_settings.modeswitches:=fpcmodeswitches
  475. else
  476. if s='DELPHI' then
  477. current_settings.modeswitches:=delphimodeswitches
  478. else
  479. if s='DELPHIUNICODE' then
  480. current_settings.modeswitches:=delphiunicodemodeswitches
  481. else
  482. if s='TP' then
  483. current_settings.modeswitches:=tpmodeswitches
  484. else
  485. if s='FPC' then begin
  486. current_settings.modeswitches:=fpcmodeswitches;
  487. { TODO: enable this for 2.3/2.9 }
  488. // include(current_settings.localswitches, cs_typed_addresses);
  489. end else
  490. if s='OBJFPC' then begin
  491. current_settings.modeswitches:=objfpcmodeswitches;
  492. { TODO: enable this for 2.3/2.9 }
  493. // include(current_settings.localswitches, cs_typed_addresses);
  494. end
  495. {$ifdef gpc_mode}
  496. else if s='GPC' then
  497. current_settings.modeswitches:=gpcmodeswitches
  498. {$endif}
  499. else
  500. if s='MACPAS' then
  501. current_settings.modeswitches:=macmodeswitches
  502. else
  503. if s='ISO' then
  504. current_settings.modeswitches:=isomodeswitches
  505. else
  506. if s='EXTENDEDPASCAL' then
  507. current_settings.modeswitches:=extpasmodeswitches
  508. else
  509. b:=false;
  510. {$ifdef jvm}
  511. { enable final fields by default for the JVM targets }
  512. include(current_settings.modeswitches,m_final_fields);
  513. {$endif jvm}
  514. if b and changeInit then
  515. init_settings.modeswitches := current_settings.modeswitches;
  516. if b then
  517. begin
  518. { resolve all postponed switch changes }
  519. flushpendingswitchesstate;
  520. HandleModeSwitches(m_none,changeinit);
  521. { turn on bitpacking and case checking for mode macpas and iso pascal,
  522. as well as extended pascal }
  523. if ([m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then
  524. begin
  525. include(current_settings.localswitches,cs_bitpacking);
  526. include(current_settings.localswitches,cs_check_all_case_coverage);
  527. if changeinit then
  528. begin
  529. include(init_settings.localswitches,cs_bitpacking);
  530. include(init_settings.localswitches,cs_check_all_case_coverage);
  531. end;
  532. end;
  533. { support goto/label by default in delphi/tp7/mac/iso/extpas modes }
  534. if ([m_delphi,m_tp7,m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then
  535. begin
  536. include(current_settings.moduleswitches,cs_support_goto);
  537. if changeinit then
  538. include(init_settings.moduleswitches,cs_support_goto);
  539. end;
  540. { support pointer math by default in fpc/objfpc modes }
  541. if ([m_fpc,m_objfpc] * current_settings.modeswitches <> []) then
  542. begin
  543. include(current_settings.localswitches,cs_pointermath);
  544. if changeinit then
  545. include(init_settings.localswitches,cs_pointermath);
  546. end
  547. else
  548. begin
  549. exclude(current_settings.localswitches,cs_pointermath);
  550. if changeinit then
  551. exclude(init_settings.localswitches,cs_pointermath);
  552. end;
  553. { Default enum and set packing for delphi/tp7 }
  554. if (m_tp7 in current_settings.modeswitches) or
  555. (m_delphi in current_settings.modeswitches) then
  556. begin
  557. current_settings.packenum:=1;
  558. current_settings.setalloc:=1;
  559. end
  560. else if (m_mac in current_settings.modeswitches) then
  561. begin
  562. { compatible with Metrowerks Pascal }
  563. current_settings.packenum:=2;
  564. current_settings.setalloc:=default_settings.setalloc;
  565. end
  566. else
  567. begin
  568. current_settings.packenum:=default_settings.packenum;
  569. current_settings.setalloc:=default_settings.setalloc;
  570. end;
  571. if changeinit then
  572. begin
  573. init_settings.packenum:=current_settings.packenum;
  574. init_settings.setalloc:=current_settings.setalloc;
  575. end;
  576. {$if defined(i386) or defined(i8086)}
  577. { Default to intel assembler for delphi/tp7 on i386/i8086 }
  578. if (m_delphi in current_settings.modeswitches) or
  579. (m_tp7 in current_settings.modeswitches) then
  580. begin
  581. {$ifdef i8086}
  582. current_settings.asmmode:=asmmode_i8086_intel;
  583. {$else i8086}
  584. current_settings.asmmode:=asmmode_i386_intel;
  585. {$endif i8086}
  586. if changeinit then
  587. init_settings.asmmode:=current_settings.asmmode;
  588. end;
  589. {$endif i386 or i8086}
  590. { Exception support explicitly turned on (mainly for macpas, to }
  591. { compensate for lack of interprocedural goto support) }
  592. if (cs_support_exceptions in current_settings.globalswitches) then
  593. include(current_settings.modeswitches,m_except);
  594. { Default strict string var checking in TP/Delphi modes }
  595. if ([m_delphi,m_tp7] * current_settings.modeswitches <> []) then
  596. begin
  597. include(current_settings.localswitches,cs_strict_var_strings);
  598. if changeinit then
  599. include(init_settings.localswitches,cs_strict_var_strings);
  600. end;
  601. { in delphi mode, excess precision and open strings are by default on }
  602. if ([m_delphi] * current_settings.modeswitches <> []) then
  603. begin
  604. include(current_settings.localswitches,cs_excessprecision);
  605. include(current_settings.localswitches,cs_openstring);
  606. if changeinit then
  607. begin
  608. include(init_settings.localswitches,cs_excessprecision);
  609. include(init_settings.localswitches,cs_openstring);
  610. end;
  611. end;
  612. {$ifdef i8086}
  613. { Do not force far calls in the TP mode by default, force it in other modes }
  614. if (m_tp7 in current_settings.modeswitches) then
  615. begin
  616. exclude(current_settings.localswitches,cs_force_far_calls);
  617. if changeinit then
  618. exclude(init_settings.localswitches,cs_force_far_calls);
  619. end
  620. else
  621. begin
  622. include(current_settings.localswitches,cs_force_far_calls);
  623. if changeinit then
  624. include(init_settings.localswitches,cs_force_far_calls);
  625. end;
  626. {$endif i8086}
  627. { Undefine old symbol }
  628. if (m_delphi in oldmodeswitches) then
  629. undef_system_macro('FPC_DELPHI')
  630. else if (m_tp7 in oldmodeswitches) then
  631. undef_system_macro('FPC_TP')
  632. else if (m_objfpc in oldmodeswitches) then
  633. undef_system_macro('FPC_OBJFPC')
  634. {$ifdef gpc_mode}
  635. else if (m_gpc in oldmodeswitches) then
  636. undef_system_macro('FPC_GPC')
  637. {$endif}
  638. else if (m_mac in oldmodeswitches) then
  639. undef_system_macro('FPC_MACPAS')
  640. else if (m_iso in oldmodeswitches) then
  641. undef_system_macro('FPC_ISO')
  642. else if (m_extpas in oldmodeswitches) then
  643. undef_system_macro('FPC_EXTENDEDPASCAL');
  644. { define new symbol in delphi,objfpc,tp,gpc,macpas mode }
  645. if (m_delphi in current_settings.modeswitches) then
  646. def_system_macro('FPC_DELPHI')
  647. else if (m_tp7 in current_settings.modeswitches) then
  648. def_system_macro('FPC_TP')
  649. else if (m_objfpc in current_settings.modeswitches) then
  650. def_system_macro('FPC_OBJFPC')
  651. {$ifdef gpc_mode}
  652. else if (m_gpc in current_settings.modeswitches) then
  653. def_system_macro('FPC_GPC')
  654. {$endif}
  655. else if (m_mac in current_settings.modeswitches) then
  656. def_system_macro('FPC_MACPAS')
  657. else if (m_iso in current_settings.modeswitches) then
  658. def_system_macro('FPC_ISO')
  659. else if (m_extpas in current_settings.modeswitches) then
  660. def_system_macro('FPC_EXTENDEDPASCAL');
  661. end;
  662. SetCompileMode:=b;
  663. end;
  664. Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
  665. var
  666. i : tmodeswitch;
  667. doinclude : boolean;
  668. begin
  669. s:=upper(s);
  670. { on/off? }
  671. doinclude:=true;
  672. case s[length(s)] of
  673. '+':
  674. setlength(s,length(s)-1);
  675. '-':
  676. begin
  677. setlength(s,length(s)-1);
  678. doinclude:=false;
  679. end;
  680. end;
  681. Result:=false;
  682. for i:=m_class to high(tmodeswitch) do
  683. if s=modeswitchstr[i] then
  684. begin
  685. { Objective-C is currently only supported for Darwin targets }
  686. if doinclude and
  687. (i in [m_objectivec1,m_objectivec2]) and
  688. not(target_info.system in systems_objc_supported) then
  689. begin
  690. Message1(option_unsupported_target_for_feature,'Objective-C');
  691. break;
  692. end;
  693. { Blocks supported? }
  694. if doinclude and
  695. (i = m_blocks) and
  696. not(target_info.system in systems_blocks_supported) then
  697. begin
  698. Message1(option_unsupported_target_for_feature,'Blocks');
  699. break;
  700. end;
  701. if changeInit then
  702. current_settings.modeswitches:=init_settings.modeswitches;
  703. Result:=true;
  704. if doinclude then
  705. begin
  706. include(current_settings.modeswitches,i);
  707. { Objective-C 2.0 support implies 1.0 support }
  708. if (i=m_objectivec2) then
  709. include(current_settings.modeswitches,m_objectivec1);
  710. if (i in [m_objectivec1,m_objectivec2]) then
  711. include(current_settings.modeswitches,m_class);
  712. end
  713. else
  714. begin
  715. exclude(current_settings.modeswitches,i);
  716. { Objective-C 2.0 support implies 1.0 support }
  717. if (i=m_objectivec2) then
  718. exclude(current_settings.modeswitches,m_objectivec1);
  719. if (i in [m_objectivec1,m_objectivec2]) and
  720. ([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then
  721. exclude(current_settings.modeswitches,m_class);
  722. end;
  723. { set other switches depending on changed mode switch }
  724. HandleModeSwitches(i,changeinit);
  725. if changeInit then
  726. init_settings.modeswitches:=current_settings.modeswitches;
  727. break;
  728. end;
  729. end;
  730. procedure SetAppType(NewAppType:tapptype);
  731. begin
  732. {$ifdef i8086}
  733. if (target_info.system in [system_i8086_msdos,system_i8086_embedded]) and (apptype<>NewAppType) then
  734. begin
  735. if NewAppType=app_com then
  736. begin
  737. targetinfos[target_info.system]^.exeext:='.com';
  738. target_info.exeext:='.com';
  739. end
  740. else
  741. begin
  742. targetinfos[target_info.system]^.exeext:='.exe';
  743. target_info.exeext:='.exe';
  744. end;
  745. end;
  746. {$endif i8086}
  747. {$ifdef m68k}
  748. if target_info.system in [system_m68k_atari] then
  749. case NewAppType of
  750. app_cui:
  751. begin
  752. targetinfos[target_info.system]^.exeext:='.ttp';
  753. target_info.exeext:='.ttp';
  754. end;
  755. app_gui:
  756. begin
  757. targetinfos[target_info.system]^.exeext:='.prg';
  758. target_info.exeext:='.prg';
  759. end;
  760. else
  761. ;
  762. end;
  763. {$endif m68k}
  764. if apptype in [app_cui,app_com] then
  765. undef_system_macro('CONSOLE');
  766. apptype:=NewAppType;
  767. if apptype in [app_cui,app_com] then
  768. def_system_macro('CONSOLE');
  769. end;
  770. {*****************************************************************************
  771. Conditional Directives
  772. *****************************************************************************}
  773. procedure dir_else;
  774. begin
  775. current_scanner.elsepreprocstack;
  776. end;
  777. procedure dir_endif;
  778. begin
  779. if (cs_legacyifend in current_settings.localswitches) and
  780. (current_scanner.preprocstack.typ<>pp_ifdef) and (current_scanner.preprocstack.typ<>pp_ifndef) and
  781. not((current_scanner.preprocstack.typ=pp_else) and (current_scanner.preprocstack.iftyp in [pp_ifdef,pp_ifndef])) then
  782. Message(scan_e_unexpected_endif);
  783. current_scanner.poppreprocstack;
  784. end;
  785. procedure dir_ifend;
  786. begin
  787. if (cs_legacyifend in current_settings.localswitches) and
  788. (current_scanner.preprocstack.typ<>pp_elseif) and (current_scanner.preprocstack.typ<>pp_if) and
  789. not((current_scanner.preprocstack.typ=pp_else) and (current_scanner.preprocstack.iftyp in [pp_if,pp_elseif])) then
  790. Message(scan_e_unexpected_ifend);
  791. current_scanner.poppreprocstack;
  792. end;
  793. function isdef(var valuedescr: String): Boolean;
  794. var
  795. hs : string;
  796. begin
  797. current_scanner.skipspace;
  798. hs:=current_scanner.readid;
  799. valuedescr:= hs;
  800. if hs='' then
  801. Message(scan_e_error_in_preproc_expr);
  802. isdef:=defined_macro(hs);
  803. end;
  804. procedure dir_ifdef;
  805. begin
  806. current_scanner.ifpreprocstack(pp_ifdef,@isdef,scan_c_ifdef_found);
  807. end;
  808. function isnotdef(var valuedescr: String): Boolean;
  809. var
  810. hs : string;
  811. begin
  812. current_scanner.skipspace;
  813. hs:=current_scanner.readid;
  814. valuedescr:= hs;
  815. if hs='' then
  816. Message(scan_e_error_in_preproc_expr);
  817. isnotdef:=not defined_macro(hs);
  818. end;
  819. procedure dir_ifndef;
  820. begin
  821. current_scanner.ifpreprocstack(pp_ifndef,@isnotdef,scan_c_ifndef_found);
  822. end;
  823. function opt_check(var valuedescr: String): Boolean;
  824. var
  825. hs : string;
  826. state : char;
  827. begin
  828. opt_check:= false;
  829. current_scanner.skipspace;
  830. hs:=current_scanner.readid;
  831. valuedescr:= hs;
  832. if (length(hs)>1) then
  833. Message1(scan_w_illegal_switch,hs)
  834. else
  835. begin
  836. state:=current_scanner.ReadState;
  837. if state in ['-','+'] then
  838. opt_check:=CheckSwitch(hs[1],state)
  839. else
  840. Message(scan_e_error_in_preproc_expr);
  841. end;
  842. end;
  843. procedure dir_ifopt;
  844. begin
  845. flushpendingswitchesstate;
  846. current_scanner.ifpreprocstack(pp_ifopt,@opt_check,scan_c_ifopt_found);
  847. end;
  848. procedure dir_libprefix;
  849. var
  850. s : string;
  851. begin
  852. current_scanner.skipspace;
  853. if c <> '''' then
  854. Message2(scan_f_syn_expected, '''', c);
  855. s := current_scanner.readquotedstring;
  856. stringdispose(outputprefix);
  857. outputprefix := stringdup(s);
  858. with current_module do
  859. setfilename(paramfn, paramallowoutput);
  860. end;
  861. procedure dir_libsuffix;
  862. var
  863. s : string;
  864. begin
  865. current_scanner.skipspace;
  866. if c <> '''' then
  867. Message2(scan_f_syn_expected, '''', c);
  868. s := current_scanner.readquotedstring;
  869. stringdispose(outputsuffix);
  870. outputsuffix := stringdup(s);
  871. with current_module do
  872. setfilename(paramfn, paramallowoutput);
  873. end;
  874. procedure dir_extension;
  875. var
  876. s : string;
  877. begin
  878. current_scanner.skipspace;
  879. if c <> '''' then
  880. Message2(scan_f_syn_expected, '''', c);
  881. s := current_scanner.readquotedstring;
  882. if OutputFileName='' then
  883. OutputFileName:=InputFileName;
  884. OutputFileName:=ChangeFileExt(OutputFileName,'.'+s);
  885. with current_module do
  886. setfilename(paramfn, paramallowoutput);
  887. end;
  888. {
  889. Compile time expression type check
  890. ----------------------------------
  891. Each subexpression returns its type to the caller, which then can
  892. do type check. Since data types of compile time expressions is
  893. not well defined, the type system does a best effort. The drawback is
  894. that some errors might not be detected.
  895. Instead of returning a particular data type, a set of possible data types
  896. are returned. This way ambigouos types can be handled. For instance a
  897. value of 1 can be both a boolean and and integer.
  898. Booleans
  899. --------
  900. The following forms of boolean values are supported:
  901. * C coded, that is 0 is false, non-zero is true.
  902. * TRUE/FALSE for mac style compile time variables
  903. Thus boolean mac compile time variables are always stored as TRUE/FALSE.
  904. When a compile time expression is evaluated, they are then translated
  905. to C coded booleans (0/1), to simplify for the expression evaluator.
  906. Note that this scheme then also of support mac compile time variables which
  907. are 0/1 but with a boolean meaning.
  908. The TRUE/FALSE format is new from 22 august 2005, but the above scheme
  909. means that units which is not recompiled, and thus stores
  910. compile time variables as the old format (0/1), continue to work.
  911. Short circuit evaluation
  912. ------------------------
  913. For this to work, the part of a compile time expression which is short
  914. circuited, should not be evaluated, while it still should be parsed.
  915. Therefor there is a parameter eval, telling whether evaluation is needed.
  916. In case not, the value returned can be arbitrary.
  917. }
  918. type
  919. { texprvalue }
  920. texprvalue = class
  921. private
  922. { we can't use built-in defs since they
  923. may be not created at the moment }
  924. class var
  925. sintdef,uintdef,booldef,strdef,setdef,realdef: tdef;
  926. class constructor createdefs;
  927. class destructor destroydefs;
  928. public
  929. consttyp: tconsttyp;
  930. value: tconstvalue;
  931. def: tdef;
  932. constructor create_const(c:tconstsym);
  933. constructor create_error;
  934. constructor create_ord(v: Tconstexprint);
  935. constructor create_int(v: int64);
  936. constructor create_uint(v: qword);
  937. constructor create_bool(b: boolean);
  938. constructor create_str(const s: string);
  939. constructor create_set(ns: tnormalset);
  940. constructor create_real(r: bestreal);
  941. class function try_parse_number(const s:string):texprvalue; static;
  942. class function try_parse_real(const s:string):texprvalue; static;
  943. function evaluate(v:texprvalue;op:ttoken):texprvalue;
  944. procedure error(expecteddef, place: string);
  945. function isBoolean: Boolean;
  946. function isInt: Boolean;
  947. function asBool: Boolean;
  948. function asInt: Integer;
  949. function asInt64: Int64;
  950. function asStr: String;
  951. function asSet: tnormalset;
  952. destructor destroy; override;
  953. end;
  954. class constructor texprvalue.createdefs;
  955. begin
  956. { do not use corddef etc here: this code is executed before those
  957. variables are initialised. Since these types are only used for
  958. compile-time evaluation of conditional expressions, it doesn't matter
  959. that we use the base types instead of the cpu-specific ones. }
  960. sintdef:=torddef.create(s64bit,low(int64),high(int64),false);
  961. uintdef:=torddef.create(u64bit,low(qword),high(qword),false);
  962. booldef:=torddef.create(pasbool1,0,1,false);
  963. strdef:=tstringdef.createansi(0,false);
  964. setdef:=tsetdef.create(sintdef,0,255,false);
  965. realdef:=tfloatdef.create(s80real,false);
  966. end;
  967. class destructor texprvalue.destroydefs;
  968. begin
  969. setdef.free;
  970. sintdef.free;
  971. uintdef.free;
  972. booldef.free;
  973. strdef.free;
  974. realdef.free;
  975. end;
  976. constructor texprvalue.create_const(c: tconstsym);
  977. begin
  978. consttyp:=c.consttyp;
  979. def:=c.constdef;
  980. case consttyp of
  981. conststring,
  982. constresourcestring:
  983. begin
  984. value.len:=c.value.len;
  985. getmem(value.valueptr,value.len+1);
  986. move(c.value.valueptr^,value.valueptr^,value.len+1);
  987. end;
  988. constwstring,
  989. constwresourcestring:
  990. begin
  991. initwidestring(value.valueptr);
  992. copywidestring(c.value.valueptr,value.valueptr);
  993. end;
  994. constreal:
  995. begin
  996. new(pbestreal(value.valueptr));
  997. pbestreal(value.valueptr)^:=pbestreal(c.value.valueptr)^;
  998. end;
  999. constset:
  1000. begin
  1001. new(pnormalset(value.valueptr));
  1002. pnormalset(value.valueptr)^:=pnormalset(c.value.valueptr)^;
  1003. end;
  1004. constguid:
  1005. begin
  1006. new(pguid(value.valueptr));
  1007. pguid(value.valueptr)^:=pguid(c.value.valueptr)^;
  1008. end;
  1009. else
  1010. value:=c.value;
  1011. end;
  1012. end;
  1013. constructor texprvalue.create_error;
  1014. begin
  1015. fillchar(value,sizeof(value),#0);
  1016. consttyp:=constnone;
  1017. def:=generrordef;
  1018. end;
  1019. constructor texprvalue.create_ord(v: Tconstexprint);
  1020. begin
  1021. fillchar(value,sizeof(value),#0);
  1022. consttyp:=constord;
  1023. value.valueord:=v;
  1024. if v.signed then
  1025. def:=sintdef
  1026. else
  1027. def:=uintdef;
  1028. end;
  1029. constructor texprvalue.create_int(v: int64);
  1030. begin
  1031. fillchar(value,sizeof(value),#0);
  1032. consttyp:=constord;
  1033. value.valueord:=v;
  1034. def:=sintdef;
  1035. end;
  1036. constructor texprvalue.create_uint(v: qword);
  1037. begin
  1038. fillchar(value,sizeof(value),#0);
  1039. consttyp:=constord;
  1040. value.valueord:=v;
  1041. def:=uintdef;
  1042. end;
  1043. constructor texprvalue.create_bool(b: boolean);
  1044. begin
  1045. fillchar(value,sizeof(value),#0);
  1046. consttyp:=constord;
  1047. value.valueord:=ord(b);
  1048. def:=booldef;
  1049. end;
  1050. constructor texprvalue.create_str(const s: string);
  1051. var
  1052. sp: pansichar;
  1053. len: integer;
  1054. begin
  1055. fillchar(value,sizeof(value),#0);
  1056. consttyp:=conststring;
  1057. len:=length(s);
  1058. getmem(sp,len+1);
  1059. move(s[1],sp^,len+1);
  1060. value.valueptr:=sp;
  1061. value.len:=len;
  1062. def:=strdef;
  1063. end;
  1064. constructor texprvalue.create_set(ns: tnormalset);
  1065. begin
  1066. fillchar(value,sizeof(value),#0);
  1067. consttyp:=constset;
  1068. new(pnormalset(value.valueptr));
  1069. pnormalset(value.valueptr)^:=ns;
  1070. def:=setdef;
  1071. end;
  1072. constructor texprvalue.create_real(r: bestreal);
  1073. begin
  1074. fillchar(value,sizeof(value),#0);
  1075. consttyp:=constreal;
  1076. new(pbestreal(value.valueptr));
  1077. pbestreal(value.valueptr)^:=r;
  1078. def:=realdef;
  1079. end;
  1080. class function texprvalue.try_parse_number(const s:string):texprvalue;
  1081. var
  1082. ic: int64;
  1083. qc: qword;
  1084. code: integer;
  1085. begin
  1086. { try int64 }
  1087. val(s,ic,code);
  1088. if code=0 then
  1089. result:=texprvalue.create_int(ic)
  1090. else
  1091. begin
  1092. { try qword }
  1093. val(s,qc,code);
  1094. if code=0 then
  1095. result:=texprvalue.create_uint(qc)
  1096. else
  1097. result:=try_parse_real(s);
  1098. end;
  1099. end;
  1100. class function texprvalue.try_parse_real(const s:string):texprvalue;
  1101. var
  1102. d: bestreal;
  1103. code: integer;
  1104. begin
  1105. val(s,d,code);
  1106. if code=0 then
  1107. result:=texprvalue.create_real(d)
  1108. else
  1109. result:=nil;
  1110. end;
  1111. function texprvalue.evaluate(v:texprvalue;op:ttoken):texprvalue;
  1112. function check_compatible: boolean;
  1113. begin
  1114. result:=(
  1115. (is_ordinal(v.def) or is_fpu(v.def)) and
  1116. (is_ordinal(def) or is_fpu(def))
  1117. ) or
  1118. (is_stringlike(v.def) and is_stringlike(def));
  1119. if not result then
  1120. Message2(type_e_incompatible_types,def.typename,v.def.typename);
  1121. end;
  1122. var
  1123. lv,rv: tconstexprint;
  1124. lvd,rvd: bestreal;
  1125. lvs,rvs: string;
  1126. begin
  1127. case op of
  1128. _OP_IN:
  1129. begin
  1130. if not is_set(v.def) then
  1131. begin
  1132. v.error('Set', 'IN');
  1133. result:=texprvalue.create_error;
  1134. end
  1135. else
  1136. if not is_ordinal(def) then
  1137. begin
  1138. error('Ordinal', 'IN');
  1139. result:=texprvalue.create_error;
  1140. end
  1141. else
  1142. if value.valueord.signed then
  1143. result:=texprvalue.create_bool(value.valueord.svalue in pnormalset(v.value.valueptr)^)
  1144. else
  1145. result:=texprvalue.create_bool(value.valueord.uvalue in pnormalset(v.value.valueptr)^);
  1146. end;
  1147. _OP_NOT:
  1148. begin
  1149. if isBoolean then
  1150. result:=texprvalue.create_bool(not asBool)
  1151. else if is_ordinal(def) then
  1152. begin
  1153. result:=texprvalue.create_ord(value.valueord);
  1154. result.def:=def;
  1155. calc_not_ordvalue(result.value.valueord,result.def);
  1156. end
  1157. else
  1158. begin
  1159. error('Boolean', 'NOT');
  1160. result:=texprvalue.create_error;
  1161. end;
  1162. end;
  1163. _OP_OR:
  1164. begin
  1165. if isBoolean then
  1166. if v.isBoolean then
  1167. result:=texprvalue.create_bool(asBool or v.asBool)
  1168. else
  1169. begin
  1170. v.error('Boolean','OR');
  1171. result:=texprvalue.create_error;
  1172. end
  1173. else if is_ordinal(def) then
  1174. if is_ordinal(v.def) then
  1175. result:=texprvalue.create_ord(value.valueord or v.value.valueord)
  1176. else
  1177. begin
  1178. v.error('Ordinal','OR');
  1179. result:=texprvalue.create_error;
  1180. end
  1181. else
  1182. begin
  1183. error('Boolean','OR');
  1184. result:=texprvalue.create_error;
  1185. end;
  1186. end;
  1187. _OP_XOR:
  1188. begin
  1189. if isBoolean then
  1190. if v.isBoolean then
  1191. result:=texprvalue.create_bool(asBool xor v.asBool)
  1192. else
  1193. begin
  1194. v.error('Boolean','XOR');
  1195. result:=texprvalue.create_error;
  1196. end
  1197. else if is_ordinal(def) then
  1198. if is_ordinal(v.def) then
  1199. result:=texprvalue.create_ord(value.valueord xor v.value.valueord)
  1200. else
  1201. begin
  1202. v.error('Ordinal','XOR');
  1203. result:=texprvalue.create_error;
  1204. end
  1205. else
  1206. begin
  1207. error('Boolean','XOR');
  1208. result:=texprvalue.create_error;
  1209. end;
  1210. end;
  1211. _OP_AND:
  1212. begin
  1213. if isBoolean then
  1214. if v.isBoolean then
  1215. result:=texprvalue.create_bool(asBool and v.asBool)
  1216. else
  1217. begin
  1218. v.error('Boolean','AND');
  1219. result:=texprvalue.create_error;
  1220. end
  1221. else if is_ordinal(def) then
  1222. if is_ordinal(v.def) then
  1223. result:=texprvalue.create_ord(value.valueord and v.value.valueord)
  1224. else
  1225. begin
  1226. v.error('Ordinal','AND');
  1227. result:=texprvalue.create_error;
  1228. end
  1229. else
  1230. begin
  1231. error('Boolean','AND');
  1232. result:=texprvalue.create_error;
  1233. end;
  1234. end;
  1235. _EQ,_NE,_LT,_GT,_GTE,_LTE,_PLUS,_MINUS,_STAR,_SLASH,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR:
  1236. if check_compatible then
  1237. begin
  1238. if (is_ordinal(def) and is_ordinal(v.def)) then
  1239. begin
  1240. lv:=value.valueord;
  1241. rv:=v.value.valueord;
  1242. case op of
  1243. _EQ:
  1244. result:=texprvalue.create_bool(lv=rv);
  1245. _NE:
  1246. result:=texprvalue.create_bool(lv<>rv);
  1247. _LT:
  1248. result:=texprvalue.create_bool(lv<rv);
  1249. _GT:
  1250. result:=texprvalue.create_bool(lv>rv);
  1251. _GTE:
  1252. result:=texprvalue.create_bool(lv>=rv);
  1253. _LTE:
  1254. result:=texprvalue.create_bool(lv<=rv);
  1255. _PLUS:
  1256. result:=texprvalue.create_ord(lv+rv);
  1257. _MINUS:
  1258. result:=texprvalue.create_ord(lv-rv);
  1259. _STAR:
  1260. result:=texprvalue.create_ord(lv*rv);
  1261. _SLASH:
  1262. result:=texprvalue.create_real(lv/rv);
  1263. _OP_DIV:
  1264. result:=texprvalue.create_ord(lv div rv);
  1265. _OP_MOD:
  1266. result:=texprvalue.create_ord(lv mod rv);
  1267. _OP_SHL:
  1268. result:=texprvalue.create_ord(lv shl rv);
  1269. _OP_SHR:
  1270. result:=texprvalue.create_ord(lv shr rv);
  1271. else
  1272. begin
  1273. { actually we should never get here but this avoids a warning }
  1274. Message(parser_e_illegal_expression);
  1275. result:=texprvalue.create_error;
  1276. end;
  1277. end;
  1278. end
  1279. else
  1280. if (is_fpu(def) or is_ordinal(def)) and
  1281. (is_fpu(v.def) or is_ordinal(v.def)) then
  1282. begin
  1283. if is_fpu(def) then
  1284. lvd:=pbestreal(value.valueptr)^
  1285. else
  1286. lvd:=value.valueord;
  1287. if is_fpu(v.def) then
  1288. rvd:=pbestreal(v.value.valueptr)^
  1289. else
  1290. rvd:=v.value.valueord;
  1291. case op of
  1292. _EQ:
  1293. result:=texprvalue.create_bool(lvd=rvd);
  1294. _NE:
  1295. result:=texprvalue.create_bool(lvd<>rvd);
  1296. _LT:
  1297. result:=texprvalue.create_bool(lvd<rvd);
  1298. _GT:
  1299. result:=texprvalue.create_bool(lvd>rvd);
  1300. _GTE:
  1301. result:=texprvalue.create_bool(lvd>=rvd);
  1302. _LTE:
  1303. result:=texprvalue.create_bool(lvd<=rvd);
  1304. _PLUS:
  1305. result:=texprvalue.create_real(lvd+rvd);
  1306. _MINUS:
  1307. result:=texprvalue.create_real(lvd-rvd);
  1308. _STAR:
  1309. result:=texprvalue.create_real(lvd*rvd);
  1310. _SLASH:
  1311. result:=texprvalue.create_real(lvd/rvd);
  1312. else
  1313. begin
  1314. Message(parser_e_illegal_expression);
  1315. result:=texprvalue.create_error;
  1316. end;
  1317. end;
  1318. end
  1319. else
  1320. begin
  1321. lvs:=asStr;
  1322. rvs:=v.asStr;
  1323. case op of
  1324. _EQ:
  1325. result:=texprvalue.create_bool(lvs=rvs);
  1326. _NE:
  1327. result:=texprvalue.create_bool(lvs<>rvs);
  1328. _LT:
  1329. result:=texprvalue.create_bool(lvs<rvs);
  1330. _GT:
  1331. result:=texprvalue.create_bool(lvs>rvs);
  1332. _GTE:
  1333. result:=texprvalue.create_bool(lvs>=rvs);
  1334. _LTE:
  1335. result:=texprvalue.create_bool(lvs<=rvs);
  1336. _PLUS:
  1337. result:=texprvalue.create_str(lvs+rvs);
  1338. else
  1339. begin
  1340. Message(parser_e_illegal_expression);
  1341. result:=texprvalue.create_error;
  1342. end;
  1343. end;
  1344. end;
  1345. end
  1346. else
  1347. result:=texprvalue.create_error;
  1348. else
  1349. result:=texprvalue.create_error;
  1350. end;
  1351. end;
  1352. procedure texprvalue.error(expecteddef, place: string);
  1353. begin
  1354. Message3(scan_e_compile_time_typeerror,
  1355. expecteddef,
  1356. def.typename,
  1357. place
  1358. );
  1359. end;
  1360. function texprvalue.isBoolean: Boolean;
  1361. var
  1362. i: int64;
  1363. begin
  1364. result:=is_boolean(def);
  1365. if not result and is_integer(def) then
  1366. begin
  1367. i:=asInt64;
  1368. result:=(i=0)or(i=1);
  1369. end;
  1370. end;
  1371. function texprvalue.isInt: Boolean;
  1372. begin
  1373. result:=is_integer(def);
  1374. end;
  1375. function texprvalue.asBool: Boolean;
  1376. begin
  1377. result:=value.valueord<>0;
  1378. end;
  1379. function texprvalue.asInt: Integer;
  1380. begin
  1381. result:=value.valueord.svalue;
  1382. end;
  1383. function texprvalue.asInt64: Int64;
  1384. begin
  1385. result:=value.valueord.svalue;
  1386. end;
  1387. function texprvalue.asSet: tnormalset;
  1388. begin
  1389. result:=pnormalset(value.valueptr)^;
  1390. end;
  1391. function texprvalue.asStr: String;
  1392. var
  1393. b:byte;
  1394. begin
  1395. case consttyp of
  1396. constord:
  1397. result:=tostr(value.valueord);
  1398. conststring,
  1399. constresourcestring:
  1400. SetString(result,pchar(value.valueptr),value.len);
  1401. constreal:
  1402. str(pbestreal(value.valueptr)^,result);
  1403. constset:
  1404. begin
  1405. result:=',';
  1406. for b:=0 to 255 do
  1407. if b in pconstset(value.valueptr)^ then
  1408. result:=result+tostr(b)+',';
  1409. end;
  1410. { error values }
  1411. constnone:
  1412. result:='';
  1413. else
  1414. internalerror(2013112801);
  1415. end;
  1416. end;
  1417. destructor texprvalue.destroy;
  1418. begin
  1419. case consttyp of
  1420. conststring,
  1421. constresourcestring :
  1422. freemem(value.valueptr,value.len+1);
  1423. constwstring,
  1424. constwresourcestring:
  1425. donewidestring(pcompilerwidestring(value.valueptr));
  1426. constreal :
  1427. dispose(pbestreal(value.valueptr));
  1428. constset :
  1429. dispose(pnormalset(value.valueptr));
  1430. constguid :
  1431. dispose(pguid(value.valueptr));
  1432. constord,
  1433. { error values }
  1434. constnone:
  1435. ;
  1436. else
  1437. internalerror(2013112802);
  1438. end;
  1439. inherited destroy;
  1440. end;
  1441. const
  1442. preproc_operators=[_EQ,_NE,_LT,_GT,_LTE,_GTE,_MINUS,_PLUS,_STAR,_SLASH,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR,_OP_IN,_OP_AND,_OP_OR,_OP_XOR];
  1443. function findincludefile(const path,name:TCmdStr;var foundfile:TCmdStr):boolean;
  1444. var
  1445. found : boolean;
  1446. hpath : TCmdStr;
  1447. begin
  1448. (* look for the include file
  1449. If path was absolute and specified as part of {$I } then
  1450. 1. specified path
  1451. else
  1452. 1. path of current inputfile,current dir
  1453. 2. local includepath
  1454. 3. global includepath
  1455. -- Check mantis #13461 before changing this *)
  1456. found:=false;
  1457. foundfile:='';
  1458. hpath:='';
  1459. if path_absolute(path) then
  1460. begin
  1461. found:=FindFile(name,path,true,foundfile);
  1462. end
  1463. else
  1464. begin
  1465. hpath:=current_scanner.inputfile.path+';'+CurDirRelPath(source_info);
  1466. found:=FindFile(path+name, hpath,true,foundfile);
  1467. if not found then
  1468. found:=current_module.localincludesearchpath.FindFile(path+name,true,foundfile);
  1469. if not found then
  1470. found:=includesearchpath.FindFile(path+name,true,foundfile);
  1471. end;
  1472. result:=found;
  1473. end;
  1474. function preproc_comp_expr(conform_to:tdef):texprvalue;
  1475. function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean):texprvalue; forward;
  1476. procedure preproc_consume(t:ttoken);
  1477. begin
  1478. if t<>current_scanner.preproc_token then
  1479. Message(scan_e_preproc_syntax_error);
  1480. current_scanner.preproc_token:=current_scanner.readpreproc;
  1481. end;
  1482. function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;out tokentoconsume:ttoken):boolean;
  1483. var
  1484. hmodule: tmodule;
  1485. ns:ansistring;
  1486. nssym:tsym;
  1487. begin
  1488. result:=false;
  1489. tokentoconsume:=_ID;
  1490. if assigned(srsym) and (srsym.typ in [unitsym,namespacesym]) then
  1491. begin
  1492. if not(srsym.owner.symtabletype in [staticsymtable,globalsymtable]) then
  1493. internalerror(200501154);
  1494. { only allow unit.symbol access if the name was
  1495. found in the current module
  1496. we can use iscurrentunit because generic specializations does not
  1497. change current_unit variable }
  1498. hmodule:=find_module_from_symtable(srsym.Owner);
  1499. if not Assigned(hmodule) then
  1500. internalerror(201001120);
  1501. if hmodule.unit_index=current_filepos.moduleindex then
  1502. begin
  1503. preproc_consume(_POINT);
  1504. current_scanner.skipspace;
  1505. if srsym.typ=namespacesym then
  1506. begin
  1507. ns:=srsym.name;
  1508. nssym:=srsym;
  1509. while assigned(srsym) and (srsym.typ=namespacesym) do
  1510. begin
  1511. { we have a namespace. the next identifier should be either a namespace or a unit }
  1512. searchsym_in_module(hmodule,ns+'.'+current_scanner.preproc_pattern,srsym,srsymtable);
  1513. if assigned(srsym) and (srsym.typ in [namespacesym,unitsym]) then
  1514. begin
  1515. ns:=ns+'.'+current_scanner.preproc_pattern;
  1516. nssym:=srsym;
  1517. preproc_consume(_ID);
  1518. current_scanner.skipspace;
  1519. preproc_consume(_POINT);
  1520. current_scanner.skipspace;
  1521. end;
  1522. end;
  1523. { check if there is a hidden unit with this pattern in the namespace }
  1524. if not assigned(srsym) and
  1525. assigned(nssym) and (nssym.typ=namespacesym) and assigned(tnamespacesym(nssym).unitsym) then
  1526. srsym:=tnamespacesym(nssym).unitsym;
  1527. if assigned(srsym) and (srsym.typ<>unitsym) then
  1528. internalerror(201108260);
  1529. if not assigned(srsym) then
  1530. begin
  1531. result:=true;
  1532. srsymtable:=nil;
  1533. exit;
  1534. end;
  1535. end;
  1536. case current_scanner.preproc_token of
  1537. _ID:
  1538. { system.char? (char=widechar comes from the implicit
  1539. uachar/uuchar unit -> override) }
  1540. if (current_scanner.preproc_pattern='CHAR') and
  1541. (tmodule(tunitsym(srsym).module).globalsymtable=systemunit) then
  1542. begin
  1543. if m_default_unicodestring in current_settings.modeswitches then
  1544. searchsym_in_module(tunitsym(srsym).module,'WIDECHAR',srsym,srsymtable)
  1545. else
  1546. searchsym_in_module(tunitsym(srsym).module,'ANSICHAR',srsym,srsymtable)
  1547. end
  1548. else
  1549. searchsym_in_module(tunitsym(srsym).module,current_scanner.preproc_pattern,srsym,srsymtable);
  1550. _STRING:
  1551. begin
  1552. { system.string? }
  1553. if tmodule(tunitsym(srsym).module).globalsymtable=systemunit then
  1554. begin
  1555. if cs_refcountedstrings in current_settings.localswitches then
  1556. begin
  1557. if m_default_unicodestring in current_settings.modeswitches then
  1558. searchsym_in_module(tunitsym(srsym).module,'UNICODESTRING',srsym,srsymtable)
  1559. else
  1560. searchsym_in_module(tunitsym(srsym).module,'ANSISTRING',srsym,srsymtable)
  1561. end
  1562. else
  1563. searchsym_in_module(tunitsym(srsym).module,'SHORTSTRING',srsym,srsymtable);
  1564. tokentoconsume:=_STRING;
  1565. end;
  1566. end
  1567. else
  1568. ;
  1569. end;
  1570. end
  1571. else
  1572. begin
  1573. srsym:=nil;
  1574. srsymtable:=nil;
  1575. end;
  1576. result:=true;
  1577. end;
  1578. end;
  1579. procedure try_consume_nestedsym(var srsym:tsym;var srsymtable:TSymtable);
  1580. var
  1581. def:tdef;
  1582. tokentoconsume:ttoken;
  1583. found:boolean;
  1584. begin
  1585. found:=try_consume_unitsym(srsym,srsymtable,tokentoconsume);
  1586. if found then
  1587. begin
  1588. preproc_consume(tokentoconsume);
  1589. current_scanner.skipspace;
  1590. end;
  1591. while (current_scanner.preproc_token=_POINT) do
  1592. begin
  1593. if assigned(srsym)and(srsym.typ=typesym) then
  1594. begin
  1595. def:=ttypesym(srsym).typedef;
  1596. if is_class_or_object(def) or is_record(def) or is_java_class_or_interface(def) then
  1597. begin
  1598. preproc_consume(_POINT);
  1599. current_scanner.skipspace;
  1600. if def.typ=objectdef then
  1601. found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,[ssf_search_helper])
  1602. else
  1603. found:=searchsym_in_record(trecorddef(def),current_scanner.preproc_pattern,srsym,srsymtable);
  1604. if not found then
  1605. begin
  1606. Message1(sym_e_id_not_found,current_scanner.preproc_pattern);
  1607. exit;
  1608. end;
  1609. preproc_consume(_ID);
  1610. current_scanner.skipspace;
  1611. end
  1612. else
  1613. begin
  1614. Message(sym_e_type_must_be_rec_or_object_or_class);
  1615. exit;
  1616. end;
  1617. end
  1618. else
  1619. begin
  1620. Message(type_e_type_id_expected);
  1621. exit;
  1622. end;
  1623. end;
  1624. end;
  1625. function preproc_substitutedtoken(const basesearchstr:string;eval:Boolean):texprvalue;
  1626. { Currently this parses identifiers as well as numbers.
  1627. The result from this procedure can either be that the token
  1628. itself is a value, or that it is a compile time variable/macro,
  1629. which then is substituted for another value (for macros
  1630. recursivelly substituted).}
  1631. var
  1632. hs: string;
  1633. mac: tmacro;
  1634. macrocount,
  1635. len: integer;
  1636. foundmacro: boolean;
  1637. searchstr: pshortstring;
  1638. searchstr2store: string;
  1639. begin
  1640. if not eval then
  1641. begin
  1642. result:=texprvalue.create_str(basesearchstr);
  1643. exit;
  1644. end;
  1645. searchstr := @basesearchstr;
  1646. mac:=nil;
  1647. foundmacro:=false;
  1648. { Substitue macros and compiler variables with their content/value.
  1649. For real macros also do recursive substitution. }
  1650. macrocount:=0;
  1651. repeat
  1652. mac:=tmacro(search_macro(searchstr^));
  1653. inc(macrocount);
  1654. if macrocount>max_macro_nesting then
  1655. begin
  1656. Message(scan_w_macro_too_deep);
  1657. break;
  1658. end;
  1659. if assigned(mac) and mac.defined then
  1660. if assigned(mac.buftext) then
  1661. begin
  1662. if mac.buflen>255 then
  1663. begin
  1664. len:=255;
  1665. Message(scan_w_macro_cut_after_255_chars);
  1666. end
  1667. else
  1668. len:=mac.buflen;
  1669. hs[0]:=char(len);
  1670. move(mac.buftext^,hs[1],len);
  1671. searchstr2store:=upcase(hs);
  1672. searchstr:=@searchstr2store;
  1673. mac.is_used:=true;
  1674. foundmacro:=true;
  1675. end
  1676. else
  1677. begin
  1678. Message1(scan_e_error_macro_lacks_value,searchstr^);
  1679. break;
  1680. end
  1681. else
  1682. break;
  1683. if mac.is_compiler_var then
  1684. break;
  1685. until false;
  1686. { At this point, result do contain the value. Do some decoding and
  1687. determine the type.}
  1688. result:=texprvalue.try_parse_number(searchstr^);
  1689. if not assigned(result) then
  1690. begin
  1691. if foundmacro and (searchstr^='FALSE') then
  1692. result:=texprvalue.create_bool(false)
  1693. else if foundmacro and (searchstr^='TRUE') then
  1694. result:=texprvalue.create_bool(true)
  1695. else if (m_mac in current_settings.modeswitches) and
  1696. (not assigned(mac) or not mac.defined) and
  1697. (macrocount = 1) then
  1698. begin
  1699. {Errors in mode mac is issued here. For non macpas modes there is
  1700. more liberty, but the error will eventually be caught at a later stage.}
  1701. Message1(scan_e_error_macro_undefined,searchstr^);
  1702. result:=texprvalue.create_str(searchstr^); { just to have something }
  1703. end
  1704. else
  1705. result:=texprvalue.create_str(searchstr^);
  1706. end;
  1707. end;
  1708. function preproc_factor(eval: Boolean):texprvalue;
  1709. var
  1710. hs,countstr,storedpattern: string;
  1711. mac: tmacro;
  1712. srsym : tsym;
  1713. srsymtable : TSymtable;
  1714. hdef : TDef;
  1715. l : longint;
  1716. hasKlammer,
  1717. read_next: Boolean;
  1718. exprvalue:texprvalue;
  1719. ns:tnormalset;
  1720. fs,path,name: tpathstr;
  1721. foundfile: TCmdStr;
  1722. found: boolean;
  1723. begin
  1724. result:=nil;
  1725. hasKlammer:=false;
  1726. if current_scanner.preproc_token=_ID then
  1727. begin
  1728. if current_scanner.preproc_pattern='FILEEXISTS' then
  1729. begin
  1730. preproc_consume(_ID);
  1731. preproc_consume(_LKLAMMER);
  1732. hs:=current_scanner.preproc_pattern;
  1733. preproc_consume(_CSTRING);
  1734. fs:=GetToken(hs,' ');
  1735. fs:=FixFileName(fs);
  1736. path:=ExtractFilePath(fs);
  1737. name:=ExtractFileName(fs);
  1738. { this like 'include' }
  1739. if (length(name)>=1) and
  1740. (name[1]='*') then
  1741. name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);
  1742. { try to find the file, this like 'include' }
  1743. found:=findincludefile(path,name,foundfile);
  1744. if (not found) and (ExtractFileExt(name)='') then
  1745. begin
  1746. { try default extensions .inc , .pp and .pas }
  1747. if (not found) then
  1748. found:=findincludefile(path,ChangeFileExt(name,'.inc'),foundfile);
  1749. if (not found) then
  1750. found:=findincludefile(path,ChangeFileExt(name,sourceext),foundfile);
  1751. if (not found) then
  1752. found:=findincludefile(path,ChangeFileExt(name,pasext),foundfile);
  1753. end;
  1754. if (not found) and (ExtractFileExt(name)=ExtensionSeparator) and (Length(name)>=2) then
  1755. found:=findincludefile(path,Copy(name,1,Length(name)-1),foundfile);
  1756. result:=texprvalue.create_bool(found);
  1757. current_scanner.skipspace;
  1758. preproc_consume(_RKLAMMER);
  1759. end
  1760. else
  1761. if current_scanner.preproc_pattern='DEFINED' then
  1762. begin
  1763. preproc_consume(_ID);
  1764. current_scanner.skipspace;
  1765. if current_scanner.preproc_token =_LKLAMMER then
  1766. begin
  1767. preproc_consume(_LKLAMMER);
  1768. current_scanner.skipspace;
  1769. hasKlammer:= true;
  1770. end
  1771. else if (m_mac in current_settings.modeswitches) then
  1772. hasKlammer:= false
  1773. else
  1774. Message(scan_e_error_in_preproc_expr);
  1775. if current_scanner.preproc_token =_ID then
  1776. begin
  1777. hs := current_scanner.preproc_pattern;
  1778. mac := tmacro(search_macro(hs));
  1779. if assigned(mac) and mac.defined then
  1780. begin
  1781. result:=texprvalue.create_bool(true);
  1782. mac.is_used:=true;
  1783. end
  1784. else
  1785. result:=texprvalue.create_bool(false);
  1786. preproc_consume(_ID);
  1787. current_scanner.skipspace;
  1788. end
  1789. else
  1790. Message(scan_e_error_in_preproc_expr);
  1791. if hasKlammer then
  1792. if current_scanner.preproc_token =_RKLAMMER then
  1793. preproc_consume(_RKLAMMER)
  1794. else
  1795. Message(scan_e_error_in_preproc_expr);
  1796. end
  1797. else
  1798. if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='UNDEFINED') then
  1799. begin
  1800. preproc_consume(_ID);
  1801. current_scanner.skipspace;
  1802. if current_scanner.preproc_token =_ID then
  1803. begin
  1804. hs := current_scanner.preproc_pattern;
  1805. mac := tmacro(search_macro(hs));
  1806. if assigned(mac) then
  1807. begin
  1808. result:=texprvalue.create_bool(false);
  1809. mac.is_used:=true;
  1810. end
  1811. else
  1812. result:=texprvalue.create_bool(true);
  1813. preproc_consume(_ID);
  1814. current_scanner.skipspace;
  1815. end
  1816. else
  1817. Message(scan_e_error_in_preproc_expr);
  1818. end
  1819. else
  1820. if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='OPTION') then
  1821. begin
  1822. preproc_consume(_ID);
  1823. current_scanner.skipspace;
  1824. if current_scanner.preproc_token =_LKLAMMER then
  1825. begin
  1826. preproc_consume(_LKLAMMER);
  1827. current_scanner.skipspace;
  1828. end
  1829. else
  1830. Message(scan_e_error_in_preproc_expr);
  1831. if not (current_scanner.preproc_token = _ID) then
  1832. Message(scan_e_error_in_preproc_expr);
  1833. hs:=current_scanner.preproc_pattern;
  1834. if (length(hs) > 1) then
  1835. {This is allowed in Metrowerks Pascal}
  1836. Message(scan_e_error_in_preproc_expr)
  1837. else
  1838. begin
  1839. if CheckSwitch(hs[1],'+') then
  1840. result:=texprvalue.create_bool(true)
  1841. else
  1842. result:=texprvalue.create_bool(false);
  1843. end;
  1844. preproc_consume(_ID);
  1845. current_scanner.skipspace;
  1846. if current_scanner.preproc_token =_RKLAMMER then
  1847. preproc_consume(_RKLAMMER)
  1848. else
  1849. Message(scan_e_error_in_preproc_expr);
  1850. end
  1851. else
  1852. if current_scanner.preproc_pattern='SIZEOF' then
  1853. begin
  1854. preproc_consume(_ID);
  1855. current_scanner.skipspace;
  1856. if current_scanner.preproc_token =_LKLAMMER then
  1857. begin
  1858. preproc_consume(_LKLAMMER);
  1859. current_scanner.skipspace;
  1860. end
  1861. else
  1862. Message(scan_e_preproc_syntax_error);
  1863. storedpattern:=current_scanner.preproc_pattern;
  1864. preproc_consume(_ID);
  1865. current_scanner.skipspace;
  1866. if eval then
  1867. if searchsym(storedpattern,srsym,srsymtable) then
  1868. begin
  1869. try_consume_nestedsym(srsym,srsymtable);
  1870. l:=0;
  1871. if assigned(srsym) then
  1872. case srsym.typ of
  1873. staticvarsym,
  1874. localvarsym,
  1875. paravarsym :
  1876. l:=tabstractvarsym(srsym).getsize;
  1877. typesym:
  1878. l:=ttypesym(srsym).typedef.size;
  1879. else
  1880. Message(scan_e_error_in_preproc_expr);
  1881. end;
  1882. result:=texprvalue.create_int(l);
  1883. end
  1884. else
  1885. Message1(sym_e_id_not_found,storedpattern);
  1886. if current_scanner.preproc_token =_RKLAMMER then
  1887. preproc_consume(_RKLAMMER)
  1888. else
  1889. Message(scan_e_preproc_syntax_error);
  1890. end
  1891. else
  1892. if current_scanner.preproc_pattern='HIGH' then
  1893. begin
  1894. preproc_consume(_ID);
  1895. current_scanner.skipspace;
  1896. if current_scanner.preproc_token =_LKLAMMER then
  1897. begin
  1898. preproc_consume(_LKLAMMER);
  1899. current_scanner.skipspace;
  1900. end
  1901. else
  1902. Message(scan_e_preproc_syntax_error);
  1903. storedpattern:=current_scanner.preproc_pattern;
  1904. preproc_consume(_ID);
  1905. current_scanner.skipspace;
  1906. if eval then
  1907. if searchsym(storedpattern,srsym,srsymtable) then
  1908. begin
  1909. try_consume_nestedsym(srsym,srsymtable);
  1910. hdef:=nil;
  1911. hs:='';
  1912. l:=0;
  1913. if assigned(srsym) then
  1914. case srsym.typ of
  1915. staticvarsym,
  1916. localvarsym,
  1917. paravarsym :
  1918. hdef:=tabstractvarsym(srsym).vardef;
  1919. typesym:
  1920. hdef:=ttypesym(srsym).typedef;
  1921. else
  1922. Message(scan_e_error_in_preproc_expr);
  1923. end;
  1924. if assigned(hdef) then
  1925. begin
  1926. if hdef.typ=setdef then
  1927. hdef:=tsetdef(hdef).elementdef;
  1928. case hdef.typ of
  1929. orddef:
  1930. with torddef(hdef).high do
  1931. if signed then
  1932. result:=texprvalue.create_int(svalue)
  1933. else
  1934. result:=texprvalue.create_uint(uvalue);
  1935. enumdef:
  1936. result:=texprvalue.create_int(tenumdef(hdef).maxval);
  1937. arraydef:
  1938. if is_open_array(hdef) or is_array_of_const(hdef) or is_dynamic_array(hdef) then
  1939. Message(type_e_mismatch)
  1940. else
  1941. result:=texprvalue.create_int(tarraydef(hdef).highrange);
  1942. stringdef:
  1943. if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then
  1944. Message(type_e_mismatch)
  1945. else
  1946. result:=texprvalue.create_int(tstringdef(hdef).len);
  1947. else
  1948. Message(type_e_mismatch);
  1949. end;
  1950. end;
  1951. end
  1952. else
  1953. Message1(sym_e_id_not_found,storedpattern);
  1954. if current_scanner.preproc_token =_RKLAMMER then
  1955. preproc_consume(_RKLAMMER)
  1956. else
  1957. Message(scan_e_preproc_syntax_error);
  1958. end
  1959. else
  1960. if current_scanner.preproc_pattern='DECLARED' then
  1961. begin
  1962. preproc_consume(_ID);
  1963. current_scanner.skipspace;
  1964. if current_scanner.preproc_token =_LKLAMMER then
  1965. begin
  1966. preproc_consume(_LKLAMMER);
  1967. current_scanner.skipspace;
  1968. end
  1969. else
  1970. Message(scan_e_error_in_preproc_expr);
  1971. if current_scanner.preproc_token =_ID then
  1972. begin
  1973. hs := upper(current_scanner.preproc_pattern);
  1974. preproc_consume(_ID);
  1975. current_scanner.skipspace;
  1976. if current_scanner.preproc_token in [_LT,_LSHARPBRACKET] then
  1977. begin
  1978. l:=1;
  1979. preproc_consume(current_scanner.preproc_token);
  1980. current_scanner.skipspace;
  1981. while current_scanner.preproc_token=_COMMA do
  1982. begin
  1983. inc(l);
  1984. preproc_consume(_COMMA);
  1985. current_scanner.skipspace;
  1986. end;
  1987. if not (current_scanner.preproc_token in [_GT,_RSHARPBRACKET]) then
  1988. Message(scan_e_error_in_preproc_expr)
  1989. else
  1990. preproc_consume(current_scanner.preproc_token);
  1991. str(l,countstr);
  1992. hs:=hs+'$'+countstr;
  1993. end
  1994. else
  1995. { special case: <> }
  1996. if current_scanner.preproc_token=_NE then
  1997. begin
  1998. hs:=hs+'$1';
  1999. preproc_consume(_NE);
  2000. end;
  2001. current_scanner.skipspace;
  2002. if searchsym(hs,srsym,srsymtable) then
  2003. begin
  2004. { TSomeGeneric<...> also adds a TSomeGeneric symbol }
  2005. if (sp_generic_dummy in srsym.symoptions) and
  2006. (srsym.typ=typesym) and
  2007. (
  2008. { mode delphi}
  2009. (ttypesym(srsym).typedef.typ in [undefineddef,errordef]) or
  2010. { non-delphi modes }
  2011. (df_generic in ttypesym(srsym).typedef.defoptions)
  2012. ) then
  2013. result:=texprvalue.create_bool(false)
  2014. else
  2015. result:=texprvalue.create_bool(true);
  2016. end
  2017. else
  2018. result:=texprvalue.create_bool(false);
  2019. end
  2020. else
  2021. Message(scan_e_error_in_preproc_expr);
  2022. if current_scanner.preproc_token =_RKLAMMER then
  2023. preproc_consume(_RKLAMMER)
  2024. else
  2025. Message(scan_e_error_in_preproc_expr);
  2026. end
  2027. else
  2028. if current_scanner.preproc_pattern='ORD' then
  2029. begin
  2030. preproc_consume(_ID);
  2031. current_scanner.skipspace;
  2032. if current_scanner.preproc_token =_LKLAMMER then
  2033. begin
  2034. preproc_consume(_LKLAMMER);
  2035. current_scanner.skipspace;
  2036. end
  2037. else
  2038. Message(scan_e_preproc_syntax_error);
  2039. exprvalue:=preproc_factor(eval);
  2040. if eval then
  2041. begin
  2042. if is_ordinal(exprvalue.def) then
  2043. result:=texprvalue.create_int(exprvalue.asInt)
  2044. else
  2045. begin
  2046. exprvalue.error('Ordinal','ORD');
  2047. result:=texprvalue.create_int(0);
  2048. end;
  2049. end
  2050. else
  2051. result:=texprvalue.create_int(0);
  2052. exprvalue.free;
  2053. if current_scanner.preproc_token =_RKLAMMER then
  2054. preproc_consume(_RKLAMMER)
  2055. else
  2056. Message(scan_e_error_in_preproc_expr);
  2057. end
  2058. else
  2059. if current_scanner.preproc_pattern='NOT' then
  2060. begin
  2061. preproc_consume(_ID);
  2062. exprvalue:=preproc_factor(eval);
  2063. if eval then
  2064. result:=exprvalue.evaluate(nil,_OP_NOT)
  2065. else
  2066. result:=texprvalue.create_bool(false); {Just to have something}
  2067. exprvalue.free;
  2068. end
  2069. else
  2070. if (current_scanner.preproc_pattern='TRUE') then
  2071. begin
  2072. result:=texprvalue.create_bool(true);
  2073. preproc_consume(_ID);
  2074. end
  2075. else
  2076. if (current_scanner.preproc_pattern='FALSE') then
  2077. begin
  2078. result:=texprvalue.create_bool(false);
  2079. preproc_consume(_ID);
  2080. end
  2081. else
  2082. begin
  2083. storedpattern:=current_scanner.preproc_pattern;
  2084. preproc_consume(_ID);
  2085. current_scanner.skipspace;
  2086. { first look for a macros/int/float }
  2087. result:=preproc_substitutedtoken(storedpattern,eval);
  2088. if eval and (result.consttyp=conststring) then
  2089. begin
  2090. if searchsym(storedpattern,srsym,srsymtable) then
  2091. begin
  2092. try_consume_nestedsym(srsym,srsymtable);
  2093. if assigned(srsym) then
  2094. case srsym.typ of
  2095. constsym:
  2096. begin
  2097. { const def must conform to the set type }
  2098. if (conform_to<>nil) and
  2099. (conform_to.typ=setdef) and
  2100. (tconstsym(srsym).constdef.typ=setdef) and
  2101. (compare_defs(tsetdef(tconstsym(srsym).constdef).elementdef,tsetdef(conform_to).elementdef,nothingn)<>te_exact) then
  2102. begin
  2103. result.free;
  2104. result:=nil;
  2105. // TODO(ryan): better error?
  2106. Message(scan_e_error_in_preproc_expr);
  2107. end;
  2108. if result<>nil then
  2109. begin
  2110. result.free;
  2111. result:=texprvalue.create_const(tconstsym(srsym));
  2112. tconstsym(srsym).IncRefCount;
  2113. end;
  2114. end;
  2115. enumsym:
  2116. begin
  2117. { enum definition must conform to the set type }
  2118. if (conform_to<>nil) and
  2119. (conform_to.typ=setdef) and
  2120. (compare_defs(tenumsym(srsym).definition,tsetdef(conform_to).elementdef,nothingn)<>te_exact) then
  2121. begin
  2122. result.free;
  2123. result:=nil;
  2124. // TODO(ryan): better error?
  2125. Message(scan_e_error_in_preproc_expr);
  2126. end;
  2127. if result<>nil then
  2128. begin
  2129. result.free;
  2130. result:=texprvalue.create_int(tenumsym(srsym).value);
  2131. tenumsym(srsym).IncRefCount;
  2132. end;
  2133. end;
  2134. else
  2135. ;
  2136. end;
  2137. end
  2138. { the id must be belong to the set type }
  2139. else if (conform_to<>nil) and (conform_to.typ=setdef) then
  2140. begin
  2141. result.free;
  2142. result:=nil;
  2143. // TODO(ryan): better error?
  2144. Message(scan_e_error_in_preproc_expr);
  2145. end;
  2146. end
  2147. { skip id(<expr>) if expression must not be evaluated }
  2148. else if not(eval) and (result.consttyp=conststring) then
  2149. begin
  2150. if current_scanner.preproc_token =_LKLAMMER then
  2151. begin
  2152. preproc_consume(_LKLAMMER);
  2153. current_scanner.skipspace;
  2154. result:=preproc_factor(false);
  2155. if current_scanner.preproc_token =_RKLAMMER then
  2156. preproc_consume(_RKLAMMER)
  2157. else
  2158. Message(scan_e_error_in_preproc_expr);
  2159. end;
  2160. end;
  2161. end
  2162. end
  2163. else if current_scanner.preproc_token =_LKLAMMER then
  2164. begin
  2165. preproc_consume(_LKLAMMER);
  2166. result:=preproc_sub_expr(opcompare,eval);
  2167. preproc_consume(_RKLAMMER);
  2168. end
  2169. else if current_scanner.preproc_token = _LECKKLAMMER then
  2170. begin
  2171. preproc_consume(_LECKKLAMMER);
  2172. ns:=[];
  2173. read_next:=false;
  2174. while (current_scanner.preproc_token in [_ID,_INTCONST]) or read_next do
  2175. begin
  2176. read_next:=false;
  2177. exprvalue:=preproc_factor(eval);
  2178. { the const set does not conform to the set def }
  2179. if (conform_to<>nil) and
  2180. (conform_to.typ=setdef) and
  2181. (exprvalue.consttyp=constnone) then
  2182. begin
  2183. result:=texprvalue.create_error;
  2184. break;
  2185. end;
  2186. { reject duplicate enums in the set }
  2187. if exprvalue.asInt in ns then
  2188. begin
  2189. Message1(sym_e_duplicate_id,current_scanner.preproc_pattern);
  2190. result:=texprvalue.create_error;
  2191. break;
  2192. end;
  2193. include(ns,exprvalue.asInt);
  2194. if current_scanner.preproc_token = _COMMA then
  2195. begin
  2196. preproc_consume(_COMMA);
  2197. read_next:=true;
  2198. end
  2199. end;
  2200. preproc_consume(_RECKKLAMMER);
  2201. if result=nil then
  2202. result:=texprvalue.create_set(ns);
  2203. end
  2204. else if current_scanner.preproc_token = _INTCONST then
  2205. begin
  2206. result:=texprvalue.try_parse_number(current_scanner.preproc_pattern);
  2207. if not assigned(result) then
  2208. begin
  2209. Message(parser_e_invalid_integer);
  2210. result:=texprvalue.create_int(1);
  2211. end;
  2212. preproc_consume(_INTCONST);
  2213. end
  2214. else if current_scanner.preproc_token = _CSTRING then
  2215. begin
  2216. result:=texprvalue.create_str(current_scanner.preproc_pattern);
  2217. preproc_consume(_CSTRING);
  2218. end
  2219. else if current_scanner.preproc_token = _REALNUMBER then
  2220. begin
  2221. result:=texprvalue.try_parse_real(current_scanner.preproc_pattern);
  2222. if not assigned(result) then
  2223. begin
  2224. Message(parser_e_error_in_real);
  2225. result:=texprvalue.create_real(1.0);
  2226. end;
  2227. preproc_consume(_REALNUMBER);
  2228. end
  2229. else
  2230. Message(scan_e_error_in_preproc_expr);
  2231. if not assigned(result) then
  2232. result:=texprvalue.create_error;
  2233. end;
  2234. function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean): texprvalue;
  2235. var
  2236. hs1,hs2: texprvalue;
  2237. op: ttoken;
  2238. begin
  2239. if pred_level=highest_precedence then
  2240. result:=preproc_factor(eval)
  2241. else
  2242. result:=preproc_sub_expr(succ(pred_level),eval);
  2243. repeat
  2244. op:=current_scanner.preproc_token;
  2245. if (op in preproc_operators) and
  2246. (op in operator_levels[pred_level]) then
  2247. begin
  2248. hs1:=result;
  2249. preproc_consume(op);
  2250. if (op=_OP_OR) and hs1.isBoolean and hs1.asBool then
  2251. begin
  2252. { stop evaluation the rest of expression }
  2253. result:=texprvalue.create_bool(true);
  2254. if pred_level=highest_precedence then
  2255. hs2:=preproc_factor(false)
  2256. else
  2257. hs2:=preproc_sub_expr(succ(pred_level),false);
  2258. end
  2259. else if (op=_OP_AND) and hs1.isBoolean and not hs1.asBool then
  2260. begin
  2261. { stop evaluation the rest of expression }
  2262. result:=texprvalue.create_bool(false);
  2263. if pred_level=highest_precedence then
  2264. hs2:=preproc_factor(false)
  2265. else
  2266. hs2:=preproc_sub_expr(succ(pred_level),false);
  2267. end
  2268. else
  2269. begin
  2270. if pred_level=highest_precedence then
  2271. hs2:=preproc_factor(eval)
  2272. else
  2273. hs2:=preproc_sub_expr(succ(pred_level),eval);
  2274. if eval then
  2275. result:=hs1.evaluate(hs2,op)
  2276. else
  2277. result:=texprvalue.create_bool(false); {Just to have something}
  2278. end;
  2279. hs1.free;
  2280. hs2.free;
  2281. end
  2282. else
  2283. break;
  2284. until false;
  2285. end;
  2286. begin
  2287. current_scanner.in_preproc_comp_expr:=true;
  2288. current_scanner.skipspace;
  2289. { start preproc expression scanner }
  2290. current_scanner.preproc_token:=current_scanner.readpreproc;
  2291. preproc_comp_expr:=preproc_sub_expr(opcompare,true);
  2292. current_scanner.in_preproc_comp_expr:=false;
  2293. end;
  2294. function boolean_compile_time_expr(var valuedescr: string): Boolean;
  2295. var
  2296. hs: texprvalue;
  2297. begin
  2298. hs:=preproc_comp_expr(nil);
  2299. if hs.isBoolean then
  2300. result:=hs.asBool
  2301. else
  2302. begin
  2303. hs.error('Boolean', 'IF or ELSEIF');
  2304. result:=false;
  2305. end;
  2306. valuedescr:=hs.asStr;
  2307. hs.free;
  2308. end;
  2309. procedure dir_if;
  2310. begin
  2311. current_scanner.ifpreprocstack(pp_if,@boolean_compile_time_expr, scan_c_if_found);
  2312. end;
  2313. procedure dir_elseif;
  2314. begin
  2315. current_scanner.elseifpreprocstack(@boolean_compile_time_expr);
  2316. end;
  2317. procedure dir_define_impl(macstyle: boolean);
  2318. var
  2319. hs : string;
  2320. bracketcount : longint;
  2321. mac : tmacro;
  2322. macropos : longint;
  2323. macrobuffer : pmacrobuffer;
  2324. begin
  2325. current_scanner.skipspace;
  2326. hs:=current_scanner.readid;
  2327. if hs='' then
  2328. begin
  2329. Message(scan_e_emptymacroname);
  2330. exit;
  2331. end;
  2332. mac:=tmacro(search_macro(hs));
  2333. if not assigned(mac) or (mac.owner <> current_module.localmacrosymtable) then
  2334. begin
  2335. mac:=tmacro.create(hs);
  2336. mac.defined:=true;
  2337. current_module.localmacrosymtable.insertsym(mac);
  2338. end
  2339. else
  2340. begin
  2341. mac.defined:=true;
  2342. mac.is_compiler_var:=false;
  2343. { delete old definition }
  2344. if assigned(mac.buftext) then
  2345. begin
  2346. freemem(mac.buftext,mac.buflen);
  2347. mac.buftext:=nil;
  2348. end;
  2349. end;
  2350. Message1(parser_c_macro_defined,mac.name);
  2351. mac.is_used:=true;
  2352. if (cs_support_macro in current_settings.moduleswitches) then
  2353. begin
  2354. current_scanner.skipspace;
  2355. if not macstyle then
  2356. begin
  2357. { may be a macro? }
  2358. if c <> ':' then
  2359. exit;
  2360. current_scanner.readchar;
  2361. if c <> '=' then
  2362. exit;
  2363. current_scanner.readchar;
  2364. current_scanner.skipspace;
  2365. end;
  2366. { key words are never substituted }
  2367. if is_keyword(hs) then
  2368. Message(scan_e_keyword_cant_be_a_macro);
  2369. new(macrobuffer);
  2370. macropos:=0;
  2371. { parse macro, brackets are counted so it's possible
  2372. to have a $ifdef etc. in the macro }
  2373. bracketcount:=0;
  2374. repeat
  2375. case c of
  2376. '}' :
  2377. if (bracketcount=0) then
  2378. break
  2379. else
  2380. dec(bracketcount);
  2381. '{' :
  2382. inc(bracketcount);
  2383. #10,#13 :
  2384. current_scanner.linebreak;
  2385. #26 :
  2386. current_scanner.end_of_file;
  2387. end;
  2388. macrobuffer^[macropos]:=c;
  2389. inc(macropos);
  2390. if macropos>=maxmacrolen then
  2391. Message(scan_f_macro_buffer_overflow);
  2392. current_scanner.readchar;
  2393. until false;
  2394. { free buffer of macro ?}
  2395. if assigned(mac.buftext) then
  2396. freemem(mac.buftext,mac.buflen);
  2397. { get new mem }
  2398. getmem(mac.buftext,macropos);
  2399. mac.buflen:=macropos;
  2400. { copy the text }
  2401. move(macrobuffer^,mac.buftext^,macropos);
  2402. dispose(macrobuffer);
  2403. end
  2404. else
  2405. begin
  2406. { check if there is an assignment, then we need to give a
  2407. warning }
  2408. current_scanner.skipspace;
  2409. if c=':' then
  2410. begin
  2411. current_scanner.readchar;
  2412. if c='=' then
  2413. Message(scan_w_macro_support_turned_off);
  2414. end;
  2415. end;
  2416. end;
  2417. procedure dir_define;
  2418. begin
  2419. dir_define_impl(false);
  2420. end;
  2421. procedure dir_definec;
  2422. begin
  2423. dir_define_impl(true);
  2424. end;
  2425. procedure dir_setc;
  2426. var
  2427. hs : string;
  2428. mac : tmacro;
  2429. exprvalue: texprvalue;
  2430. begin
  2431. current_scanner.skipspace;
  2432. hs:=current_scanner.readid;
  2433. mac:=tmacro(search_macro(hs));
  2434. if not assigned(mac) or
  2435. (mac.owner <> current_module.localmacrosymtable) then
  2436. begin
  2437. mac:=tmacro.create(hs);
  2438. mac.defined:=true;
  2439. mac.is_compiler_var:=true;
  2440. current_module.localmacrosymtable.insertsym(mac);
  2441. end
  2442. else
  2443. begin
  2444. mac.defined:=true;
  2445. mac.is_compiler_var:=true;
  2446. { delete old definition }
  2447. if assigned(mac.buftext) then
  2448. begin
  2449. freemem(mac.buftext,mac.buflen);
  2450. mac.buftext:=nil;
  2451. end;
  2452. end;
  2453. Message1(parser_c_macro_defined,mac.name);
  2454. mac.is_used:=true;
  2455. { key words are never substituted }
  2456. if is_keyword(hs) then
  2457. Message(scan_e_keyword_cant_be_a_macro);
  2458. { macro assignment can be both := and = }
  2459. current_scanner.skipspace;
  2460. if c=':' then
  2461. current_scanner.readchar;
  2462. if c='=' then
  2463. begin
  2464. current_scanner.readchar;
  2465. exprvalue:=preproc_comp_expr(nil);
  2466. if not is_boolean(exprvalue.def) and
  2467. not is_integer(exprvalue.def) then
  2468. exprvalue.error('Boolean, Integer', 'SETC');
  2469. hs:=exprvalue.asStr;
  2470. if length(hs) <> 0 then
  2471. begin
  2472. {If we are absolutely shure it is boolean, translate
  2473. to TRUE/FALSE to increase possibility to do future type check}
  2474. if exprvalue.isBoolean then
  2475. begin
  2476. if exprvalue.asBool then
  2477. hs:='TRUE'
  2478. else
  2479. hs:='FALSE';
  2480. end;
  2481. Message2(parser_c_macro_set_to,mac.name,hs);
  2482. { free buffer of macro ?}
  2483. if assigned(mac.buftext) then
  2484. freemem(mac.buftext,mac.buflen);
  2485. { get new mem }
  2486. getmem(mac.buftext,length(hs));
  2487. mac.buflen:=length(hs);
  2488. { copy the text }
  2489. move(hs[1],mac.buftext^,mac.buflen);
  2490. end
  2491. else
  2492. Message(scan_e_preproc_syntax_error);
  2493. exprvalue.free;
  2494. end
  2495. else
  2496. Message(scan_e_preproc_syntax_error);
  2497. end;
  2498. procedure dir_undef;
  2499. var
  2500. hs : string;
  2501. mac : tmacro;
  2502. begin
  2503. current_scanner.skipspace;
  2504. hs:=current_scanner.readid;
  2505. mac:=tmacro(search_macro(hs));
  2506. if not assigned(mac) or
  2507. (mac.owner <> current_module.localmacrosymtable) then
  2508. begin
  2509. mac:=tmacro.create(hs);
  2510. mac.defined:=false;
  2511. current_module.localmacrosymtable.insertsym(mac);
  2512. end
  2513. else
  2514. begin
  2515. mac.defined:=false;
  2516. mac.is_compiler_var:=false;
  2517. { delete old definition }
  2518. if assigned(mac.buftext) then
  2519. begin
  2520. freemem(mac.buftext,mac.buflen);
  2521. mac.buftext:=nil;
  2522. end;
  2523. end;
  2524. Message1(parser_c_macro_undefined,mac.name);
  2525. mac.is_used:=true;
  2526. end;
  2527. procedure dir_include;
  2528. var
  2529. foundfile : TCmdStr;
  2530. path,
  2531. name,
  2532. hs : tpathstr;
  2533. args : string;
  2534. hp : tinputfile;
  2535. found : boolean;
  2536. macroIsString : boolean;
  2537. begin
  2538. current_scanner.skipspace;
  2539. args:=current_scanner.readcomment;
  2540. hs:=GetToken(args,' ');
  2541. if hs='' then
  2542. exit;
  2543. if (hs[1]='%') then
  2544. begin
  2545. { case insensitive }
  2546. hs:=upper(hs);
  2547. { remove %'s }
  2548. Delete(hs,1,1);
  2549. if hs[length(hs)]='%' then
  2550. Delete(hs,length(hs),1);
  2551. { save old }
  2552. path:=hs;
  2553. { first check for internal macros }
  2554. macroIsString:=true;
  2555. case hs of
  2556. 'TIME':
  2557. if timestr<>'' then
  2558. hs:=timestr
  2559. else
  2560. hs:=gettimestr;
  2561. 'DATE':
  2562. if datestr<>'' then
  2563. hs:=datestr
  2564. else
  2565. hs:=getdatestr;
  2566. 'DATEYEAR':
  2567. begin
  2568. hs:=tostr(startsystime.Year);
  2569. macroIsString:=false;
  2570. end;
  2571. 'DATEMONTH':
  2572. begin
  2573. hs:=tostr(startsystime.Month);
  2574. macroIsString:=false;
  2575. end;
  2576. 'DATEDAY':
  2577. begin
  2578. hs:=tostr(startsystime.Day);
  2579. macroIsString:=false;
  2580. end;
  2581. 'TIMEHOUR':
  2582. begin
  2583. hs:=tostr(startsystime.Hour);
  2584. macroIsString:=false;
  2585. end;
  2586. 'TIMEMINUTE':
  2587. begin
  2588. hs:=tostr(startsystime.Minute);
  2589. macroIsString:=false;
  2590. end;
  2591. 'TIMESECOND':
  2592. begin
  2593. hs:=tostr(startsystime.Second);
  2594. macroIsString:=false;
  2595. end;
  2596. 'FILE':
  2597. hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);
  2598. 'LINE':
  2599. hs:=tostr(current_filepos.line);
  2600. 'LINENUM':
  2601. begin
  2602. hs:=tostr(current_filepos.line);
  2603. macroIsString:=false;
  2604. end;
  2605. 'FPCVERSION':
  2606. hs:=version_string;
  2607. 'FPCDATE':
  2608. hs:=date_string;
  2609. 'FPCTARGET':
  2610. hs:=target_cpu_string;
  2611. 'FPCTARGETCPU':
  2612. hs:=target_cpu_string;
  2613. 'FPCTARGETOS':
  2614. hs:=target_info.shortname;
  2615. 'CURRENTROUTINE':
  2616. hs:=current_procinfo.procdef.procsym.RealName;
  2617. else
  2618. hs:=GetEnvironmentVariable(hs);
  2619. end;
  2620. if hs='' then
  2621. Message1(scan_w_include_env_not_found,path);
  2622. { make it a stringconst }
  2623. if macroIsString then
  2624. hs:=''''+hs+'''';
  2625. current_scanner.substitutemacro(path,@hs[1],length(hs),
  2626. current_scanner.line_no,current_scanner.inputfile.ref_index,false);
  2627. end
  2628. else
  2629. begin
  2630. hs:=FixFileName(hs);
  2631. path:=ExtractFilePath(hs);
  2632. name:=ExtractFileName(hs);
  2633. { Special case for Delphi compatibility: '*' has to be replaced
  2634. by the file name of the current source file. }
  2635. if (length(name)>=1) and
  2636. (name[1]='*') then
  2637. name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);
  2638. { try to find the file }
  2639. found:=findincludefile(path,name,foundfile);
  2640. if (not found) and (ExtractFileExt(name)='') then
  2641. begin
  2642. { try default extensions .inc , .pp and .pas }
  2643. if (not found) then
  2644. found:=findincludefile(path,ChangeFileExt(name,'.inc'),foundfile);
  2645. if (not found) then
  2646. found:=findincludefile(path,ChangeFileExt(name,sourceext),foundfile);
  2647. if (not found) then
  2648. found:=findincludefile(path,ChangeFileExt(name,pasext),foundfile);
  2649. end;
  2650. { if the name ends in dot, try without the dot }
  2651. if (not found) and (ExtractFileExt(name)=ExtensionSeparator) and (Length(name)>=2) then
  2652. found:=findincludefile(path,Copy(name,1,Length(name)-1),foundfile);
  2653. if current_scanner.inputfilecount<max_include_nesting then
  2654. begin
  2655. inc(current_scanner.inputfilecount);
  2656. { we need to reread the current char }
  2657. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2658. current_scanner.dec_inputpointer;
  2659. {$else not CHECK_INPUTPOINTER_LIMITS}
  2660. dec(current_scanner.inputpointer);
  2661. {$endif CHECK_INPUTPOINTER_LIMITS}
  2662. { reset c }
  2663. c:=#0;
  2664. { shutdown current file }
  2665. current_scanner.tempcloseinputfile;
  2666. { load new file }
  2667. hp:=do_openinputfile(foundfile);
  2668. hp.inc_path:=path;
  2669. current_scanner.addfile(hp);
  2670. current_module.sourcefiles.register_file(hp);
  2671. if (not found) then
  2672. Message1(scan_f_cannot_open_includefile,hs);
  2673. if (not current_scanner.openinputfile) then
  2674. Message1(scan_f_cannot_open_includefile,hs);
  2675. Message1(scan_t_start_include_file,current_scanner.inputfile.path+current_scanner.inputfile.name);
  2676. current_scanner.reload;
  2677. end
  2678. else
  2679. Message(scan_f_include_deep_ten);
  2680. end;
  2681. end;
  2682. {*****************************************************************************
  2683. Preprocessor writing
  2684. *****************************************************************************}
  2685. {$ifdef PREPROCWRITE}
  2686. constructor tpreprocfile.create(const fn:string);
  2687. begin
  2688. inherited create;
  2689. { open outputfile }
  2690. assign(f,fn);
  2691. {$push}{$I-}
  2692. rewrite(f);
  2693. {$pop}
  2694. if ioresult<>0 then
  2695. Comment(V_Fatal,'can''t create file '+fn);
  2696. getmem(buf,preprocbufsize);
  2697. settextbuf(f,buf^,preprocbufsize);
  2698. { reset }
  2699. eolfound:=false;
  2700. spacefound:=false;
  2701. end;
  2702. destructor tpreprocfile.destroy;
  2703. begin
  2704. close(f);
  2705. freemem(buf,preprocbufsize);
  2706. end;
  2707. procedure tpreprocfile.add(const s:string);
  2708. begin
  2709. write(f,s);
  2710. end;
  2711. procedure tpreprocfile.addspace;
  2712. begin
  2713. if eolfound then
  2714. begin
  2715. writeln(f,'');
  2716. eolfound:=false;
  2717. spacefound:=false;
  2718. end
  2719. else
  2720. if spacefound then
  2721. begin
  2722. write(f,' ');
  2723. spacefound:=false;
  2724. end;
  2725. end;
  2726. {$endif PREPROCWRITE}
  2727. {*****************************************************************************
  2728. TPreProcStack
  2729. *****************************************************************************}
  2730. constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
  2731. begin
  2732. accept:=a;
  2733. typ:=atyp;
  2734. next:=n;
  2735. end;
  2736. {*****************************************************************************
  2737. TReplayStack
  2738. *****************************************************************************}
  2739. constructor treplaystack.Create(atoken:ttoken;aidtoken:ttoken;
  2740. const aorgpattern,apattern:string;const acstringpattern:ansistring;
  2741. apatternw:pcompilerwidestring;asettings:tsettings;
  2742. atokenbuf:tdynamicarray;change_endian:boolean;anext:treplaystack);
  2743. begin
  2744. token:=atoken;
  2745. idtoken:=aidtoken;
  2746. orgpattern:=aorgpattern;
  2747. pattern:=apattern;
  2748. cstringpattern:=acstringpattern;
  2749. initwidestring(patternw);
  2750. if assigned(apatternw) then
  2751. begin
  2752. setlengthwidestring(patternw,apatternw^.len);
  2753. move(apatternw^.data^,patternw^.data^,apatternw^.len*sizeof(tcompilerwidechar));
  2754. end;
  2755. settings:=asettings;
  2756. tokenbuf:=atokenbuf;
  2757. tokenbuf_needs_swapping:=change_endian;
  2758. next:=anext;
  2759. end;
  2760. destructor treplaystack.destroy;
  2761. begin
  2762. donewidestring(patternw);
  2763. end;
  2764. {*****************************************************************************
  2765. TDirectiveItem
  2766. *****************************************************************************}
  2767. constructor TDirectiveItem.Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  2768. begin
  2769. inherited Create(AList,n);
  2770. is_conditional:=false;
  2771. proc:=p;
  2772. end;
  2773. constructor TDirectiveItem.CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  2774. begin
  2775. inherited Create(AList,n);
  2776. is_conditional:=true;
  2777. proc:=p;
  2778. end;
  2779. {****************************************************************************
  2780. TSCANNERFILE
  2781. ****************************************************************************}
  2782. constructor tscannerfile.Create(const fn: string; is_macro: boolean);
  2783. begin
  2784. inputfile:=do_openinputfile(fn);
  2785. if is_macro then
  2786. inputfile.is_macro:=true;
  2787. if assigned(current_module) then
  2788. current_module.sourcefiles.register_file(inputfile);
  2789. { reset localinput }
  2790. c:=#0;
  2791. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2792. hidden_inputbuffer:=nil;
  2793. hidden_inputpointer:=nil;
  2794. {$else not CHECK_INPUTPOINTER_LIMITS}
  2795. inputbuffer:=nil;
  2796. inputpointer:=nil;
  2797. {$endif CHECK_INPUTPOINTER_LIMITS}
  2798. inputstart:=0;
  2799. { reset scanner }
  2800. preprocstack:=nil;
  2801. replaystack:=nil;
  2802. comment_level:=0;
  2803. yylexcount:=0;
  2804. block_type:=bt_general;
  2805. line_no:=0;
  2806. lastlinepos:=0;
  2807. lasttokenpos:=0;
  2808. nexttokenpos:=0;
  2809. lasttoken:=NOTOKEN;
  2810. nexttoken:=NOTOKEN;
  2811. ignoredirectives:=TFPHashList.Create;
  2812. change_endian_for_replay:=false;
  2813. end;
  2814. procedure tscannerfile.firstfile;
  2815. begin
  2816. { load block }
  2817. if not openinputfile then
  2818. Message1(scan_f_cannot_open_input,inputfile.name);
  2819. reload;
  2820. end;
  2821. destructor tscannerfile.Destroy;
  2822. begin
  2823. if assigned(onfreescanner) then
  2824. onfreescanner(self);
  2825. if assigned(current_module) and
  2826. (current_module.state in [ms_processed,ms_compiled]) and
  2827. (status.errorcount=0) then
  2828. checkpreprocstack
  2829. else
  2830. begin
  2831. while assigned(preprocstack) do
  2832. poppreprocstack;
  2833. end;
  2834. while assigned(replaystack) do
  2835. popreplaystack;
  2836. if not inputfile.closed then
  2837. closeinputfile;
  2838. if inputfile.is_macro then
  2839. inputfile.free;
  2840. ignoredirectives.free;
  2841. end;
  2842. function tscannerfile.openinputfile:boolean;
  2843. begin
  2844. openinputfile:=inputfile.open;
  2845. { load buffer }
  2846. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2847. hidden_inputbuffer:=inputfile.buf;
  2848. hidden_inputpointer:=inputfile.buf;
  2849. {$else not CHECK_INPUTPOINTER_LIMITS}
  2850. inputbuffer:=inputfile.buf;
  2851. inputpointer:=inputfile.buf;
  2852. {$endif CHECK_INPUTPOINTER_LIMITS}
  2853. inputstart:=inputfile.bufstart;
  2854. { line }
  2855. line_no:=0;
  2856. lastlinepos:=0;
  2857. lasttokenpos:=0;
  2858. nexttokenpos:=0;
  2859. end;
  2860. procedure tscannerfile.closeinputfile;
  2861. begin
  2862. inputfile.close;
  2863. { reset buffer }
  2864. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2865. hidden_inputbuffer:=nil;
  2866. hidden_inputpointer:=nil;
  2867. {$else not CHECK_INPUTPOINTER_LIMITS}
  2868. inputbuffer:=nil;
  2869. inputpointer:=nil;
  2870. {$endif CHECK_INPUTPOINTER_LIMITS}
  2871. inputstart:=0;
  2872. { reset line }
  2873. line_no:=0;
  2874. lastlinepos:=0;
  2875. lasttokenpos:=0;
  2876. nexttokenpos:=0;
  2877. end;
  2878. function tscannerfile.tempopeninputfile:boolean;
  2879. begin
  2880. tempopeninputfile:=false;
  2881. if inputfile.is_macro then
  2882. exit;
  2883. tempopeninputfile:=inputfile.tempopen;
  2884. { reload buffer }
  2885. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2886. hidden_inputbuffer:=inputfile.buf;
  2887. hidden_inputpointer:=inputfile.buf;
  2888. {$else not CHECK_INPUTPOINTER_LIMITS}
  2889. inputbuffer:=inputfile.buf;
  2890. inputpointer:=inputfile.buf;
  2891. {$endif CHECK_INPUTPOINTER_LIMITS}
  2892. inputstart:=inputfile.bufstart;
  2893. end;
  2894. procedure tscannerfile.tempcloseinputfile;
  2895. begin
  2896. if inputfile.closed or inputfile.is_macro then
  2897. exit;
  2898. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2899. inputfile.setpos(inputstart+(hidden_inputpointer-hidden_inputbuffer));
  2900. {$else not CHECK_INPUTPOINTER_LIMITS}
  2901. inputfile.setpos(inputstart+(inputpointer-inputbuffer));
  2902. {$endif CHECK_INPUTPOINTER_LIMITS}
  2903. inputfile.tempclose;
  2904. { reset buffer }
  2905. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2906. hidden_inputbuffer:=nil;
  2907. hidden_inputpointer:=nil;
  2908. {$else not CHECK_INPUTPOINTER_LIMITS}
  2909. inputbuffer:=nil;
  2910. inputpointer:=nil;
  2911. {$endif CHECK_INPUTPOINTER_LIMITS}
  2912. inputstart:=0;
  2913. end;
  2914. procedure tscannerfile.saveinputfile;
  2915. begin
  2916. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2917. inputfile.saveinputpointer:=hidden_inputpointer;
  2918. {$else not CHECK_INPUTPOINTER_LIMITS}
  2919. inputfile.saveinputpointer:=inputpointer;
  2920. {$endif CHECK_INPUTPOINTER_LIMITS}
  2921. inputfile.savelastlinepos:=lastlinepos;
  2922. inputfile.saveline_no:=line_no;
  2923. end;
  2924. procedure tscannerfile.restoreinputfile;
  2925. begin
  2926. {$ifdef check_inputpointer_limits}
  2927. hidden_inputbuffer:=inputfile.buf;
  2928. hidden_inputpointer:=inputfile.saveinputpointer;
  2929. {$else not check_inputpointer_limits}
  2930. inputbuffer:=inputfile.buf;
  2931. inputpointer:=inputfile.saveinputpointer;
  2932. {$endif check_inputpointer_limits}
  2933. lastlinepos:=inputfile.savelastlinepos;
  2934. line_no:=inputfile.saveline_no;
  2935. if not inputfile.is_macro then
  2936. parser_current_file:=inputfile.name;
  2937. end;
  2938. procedure tscannerfile.nextfile;
  2939. var
  2940. to_dispose : tinputfile;
  2941. begin
  2942. if assigned(inputfile.next) then
  2943. begin
  2944. if inputfile.is_macro then
  2945. begin
  2946. to_dispose:=inputfile;
  2947. dec(macro_nesting_depth);
  2948. end
  2949. else
  2950. begin
  2951. to_dispose:=nil;
  2952. dec(inputfilecount);
  2953. end;
  2954. { we can allways close the file, no ? }
  2955. inputfile.close;
  2956. inputfile:=inputfile.next;
  2957. if assigned(to_dispose) then
  2958. to_dispose.free;
  2959. restoreinputfile;
  2960. end;
  2961. end;
  2962. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  2963. function tscannerfile.get_inputpointer_char(offset : longint = 0) : char;
  2964. begin
  2965. assert(hidden_inputpointer-hidden_inputbuffer+offset<=inputfile.bufsize);
  2966. get_inputpointer_char:=(hidden_inputpointer+offset)^;
  2967. end;
  2968. procedure tscannerfile.inc_inputpointer(amount : longint = 1);
  2969. begin
  2970. assert(hidden_inputpointer-hidden_inputbuffer+amount<=inputfile.bufsize);
  2971. inc(hidden_inputpointer,amount);
  2972. end;
  2973. procedure tscannerfile.dec_inputpointer;
  2974. begin
  2975. assert(hidden_inputpointer>hidden_inputbuffer);
  2976. dec(hidden_inputpointer);
  2977. end;
  2978. {$endif}
  2979. procedure tscannerfile.startrecordtokens(buf:tdynamicarray);
  2980. begin
  2981. if not assigned(buf) then
  2982. internalerror(200511172);
  2983. if assigned(recordtokenbuf) then
  2984. internalerror(200511173);
  2985. recordtokenbuf:=buf;
  2986. fillchar(last_settings,sizeof(last_settings),0);
  2987. last_message:=nil;
  2988. fillchar(last_filepos,sizeof(last_filepos),0);
  2989. end;
  2990. procedure tscannerfile.stoprecordtokens;
  2991. begin
  2992. if not assigned(recordtokenbuf) then
  2993. internalerror(200511174);
  2994. recordtokenbuf:=nil;
  2995. end;
  2996. function tscannerfile.is_recording_tokens: boolean;
  2997. begin
  2998. result:=assigned(recordtokenbuf);
  2999. end;
  3000. procedure tscannerfile.writetoken(t : ttoken);
  3001. var
  3002. b : byte;
  3003. begin
  3004. if ord(t)>$7f then
  3005. begin
  3006. b:=(ord(t) shr 8) or $80;
  3007. recordtokenbuf.write(b,1);
  3008. end;
  3009. b:=ord(t) and $ff;
  3010. recordtokenbuf.write(b,1);
  3011. end;
  3012. procedure tscannerfile.tokenwritesizeint(val : asizeint);
  3013. begin
  3014. recordtokenbuf.write(val,sizeof(asizeint));
  3015. end;
  3016. procedure tscannerfile.tokenwritelongint(val : longint);
  3017. begin
  3018. recordtokenbuf.write(val,sizeof(longint));
  3019. end;
  3020. procedure tscannerfile.tokenwriteshortint(val : shortint);
  3021. begin
  3022. recordtokenbuf.write(val,sizeof(shortint));
  3023. end;
  3024. procedure tscannerfile.tokenwriteword(val : word);
  3025. begin
  3026. recordtokenbuf.write(val,sizeof(word));
  3027. end;
  3028. procedure tscannerfile.tokenwritelongword(val : longword);
  3029. begin
  3030. recordtokenbuf.write(val,sizeof(longword));
  3031. end;
  3032. function tscannerfile.tokenreadsizeint : asizeint;
  3033. var
  3034. val : asizeint;
  3035. begin
  3036. replaytokenbuf.read(val,sizeof(asizeint));
  3037. if change_endian_for_replay then
  3038. val:=swapendian(val);
  3039. result:=val;
  3040. end;
  3041. function tscannerfile.tokenreadlongword : longword;
  3042. var
  3043. val : longword;
  3044. begin
  3045. replaytokenbuf.read(val,sizeof(longword));
  3046. if change_endian_for_replay then
  3047. val:=swapendian(val);
  3048. result:=val;
  3049. end;
  3050. function tscannerfile.tokenreadlongint : longint;
  3051. var
  3052. val : longint;
  3053. begin
  3054. replaytokenbuf.read(val,sizeof(longint));
  3055. if change_endian_for_replay then
  3056. val:=swapendian(val);
  3057. result:=val;
  3058. end;
  3059. function tscannerfile.tokenreadshortint : shortint;
  3060. var
  3061. val : shortint;
  3062. begin
  3063. replaytokenbuf.read(val,sizeof(shortint));
  3064. result:=val;
  3065. end;
  3066. function tscannerfile.tokenreadbyte : byte;
  3067. var
  3068. val : byte;
  3069. begin
  3070. replaytokenbuf.read(val,sizeof(byte));
  3071. result:=val;
  3072. end;
  3073. function tscannerfile.tokenreadsmallint : smallint;
  3074. var
  3075. val : smallint;
  3076. begin
  3077. replaytokenbuf.read(val,sizeof(smallint));
  3078. if change_endian_for_replay then
  3079. val:=swapendian(val);
  3080. result:=val;
  3081. end;
  3082. function tscannerfile.tokenreadword : word;
  3083. var
  3084. val : word;
  3085. begin
  3086. replaytokenbuf.read(val,sizeof(word));
  3087. if change_endian_for_replay then
  3088. val:=swapendian(val);
  3089. result:=val;
  3090. end;
  3091. function tscannerfile.tokenreadenum(size : longint) : longword;
  3092. begin
  3093. if size=1 then
  3094. result:=tokenreadbyte
  3095. else if size=2 then
  3096. result:=tokenreadword
  3097. else if size=4 then
  3098. result:=tokenreadlongword
  3099. else
  3100. internalerror(2013112901);
  3101. end;
  3102. procedure tscannerfile.tokenreadset(var b;size : longint);
  3103. var
  3104. i : longint;
  3105. begin
  3106. replaytokenbuf.read(b,size);
  3107. if change_endian_for_replay then
  3108. for i:=0 to size-1 do
  3109. Pbyte(@b)[i]:=reverse_byte(Pbyte(@b)[i]);
  3110. end;
  3111. procedure tscannerfile.tokenwriteenum(var b;size : longint);
  3112. begin
  3113. recordtokenbuf.write(b,size);
  3114. end;
  3115. procedure tscannerfile.tokenwriteset(var b;size : longint);
  3116. begin
  3117. recordtokenbuf.write(b,size);
  3118. end;
  3119. procedure tscannerfile.tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
  3120. { This procedure
  3121. needs to be changed whenever
  3122. globals.tsettings type is changed,
  3123. the problem is that no error will appear
  3124. before tests with generics are tested. PM }
  3125. var
  3126. startpos, endpos : longword;
  3127. begin
  3128. { WARNING all those fields need to be in the correct
  3129. order otherwise cross_endian PPU reading will fail }
  3130. startpos:=replaytokenbuf.pos;
  3131. with asettings do
  3132. begin
  3133. alignment.procalign:=tokenreadlongint;
  3134. alignment.loopalign:=tokenreadlongint;
  3135. alignment.jumpalign:=tokenreadlongint;
  3136. alignment.jumpalignskipmax:=tokenreadlongint;
  3137. alignment.coalescealign:=tokenreadlongint;
  3138. alignment.coalescealignskipmax:=tokenreadlongint;
  3139. alignment.constalignmin:=tokenreadlongint;
  3140. alignment.constalignmax:=tokenreadlongint;
  3141. alignment.varalignmin:=tokenreadlongint;
  3142. alignment.varalignmax:=tokenreadlongint;
  3143. alignment.localalignmin:=tokenreadlongint;
  3144. alignment.localalignmax:=tokenreadlongint;
  3145. alignment.recordalignmin:=tokenreadlongint;
  3146. alignment.recordalignmax:=tokenreadlongint;
  3147. alignment.maxCrecordalign:=tokenreadlongint;
  3148. tokenreadset(globalswitches,sizeof(globalswitches));
  3149. tokenreadset(targetswitches,sizeof(targetswitches));
  3150. tokenreadset(moduleswitches,sizeof(moduleswitches));
  3151. tokenreadset(localswitches,sizeof(localswitches));
  3152. tokenreadset(modeswitches,sizeof(modeswitches));
  3153. tokenreadset(optimizerswitches,sizeof(optimizerswitches));
  3154. tokenreadset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
  3155. tokenreadset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
  3156. tokenreadset(debugswitches,sizeof(debugswitches));
  3157. { 0: old behaviour for sets <=256 elements
  3158. >0: round to this size }
  3159. setalloc:=tokenreadshortint;
  3160. packenum:=tokenreadshortint;
  3161. packrecords:=tokenreadshortint;
  3162. maxfpuregisters:=tokenreadshortint;
  3163. cputype:=tcputype(tokenreadenum(sizeof(tcputype)));
  3164. optimizecputype:=tcputype(tokenreadenum(sizeof(tcputype)));
  3165. fputype:=tfputype(tokenreadenum(sizeof(tfputype)));
  3166. asmmode:=tasmmode(tokenreadenum(sizeof(tasmmode)));
  3167. interfacetype:=tinterfacetypes(tokenreadenum(sizeof(tinterfacetypes)));
  3168. defproccall:=tproccalloption(tokenreadenum(sizeof(tproccalloption)));
  3169. { tstringencoding is word type,
  3170. thus this should be OK here }
  3171. sourcecodepage:=tstringEncoding(tokenreadword);
  3172. minfpconstprec:=tfloattype(tokenreadenum(sizeof(tfloattype)));
  3173. disabledircache:=boolean(tokenreadbyte);
  3174. tlsmodel:=ttlsmodel(tokenreadenum(sizeof(ttlsmodel)));
  3175. { TH: Since the field was conditional originally, it was not stored in PPUs. }
  3176. { While adding ControllerSupport constant, I decided not to store ct_none }
  3177. { on targets not supporting controllers, but this might be changed here and }
  3178. { in tokenwritesettings in the future to unify the PPU structure and handling }
  3179. { of this field in the compiler. }
  3180. {$PUSH}
  3181. {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)
  3182. if ControllerSupport then
  3183. controllertype:=tcontrollertype(tokenreadenum(sizeof(tcontrollertype)))
  3184. else
  3185. ControllerType:=ct_none;
  3186. {$POP}
  3187. endpos:=replaytokenbuf.pos;
  3188. if endpos-startpos<>expected_size then
  3189. Comment(V_Error,'Wrong size of Settings read-in');
  3190. end;
  3191. end;
  3192. procedure tscannerfile.tokenwritesettings(var asettings : tsettings; var size : asizeint);
  3193. { This procedure
  3194. needs to be changed whenever
  3195. globals.tsettings type is changed,
  3196. the problem is that no error will appear
  3197. before tests with generics are tested. PM }
  3198. var
  3199. sizepos, startpos, endpos : longword;
  3200. begin
  3201. { WARNING all those fields need to be in the correct
  3202. order otherwise cross_endian PPU reading will fail }
  3203. sizepos:=recordtokenbuf.pos;
  3204. size:=0;
  3205. tokenwritesizeint(size);
  3206. startpos:=recordtokenbuf.pos;
  3207. with asettings do
  3208. begin
  3209. tokenwritelongint(alignment.procalign);
  3210. tokenwritelongint(alignment.loopalign);
  3211. tokenwritelongint(alignment.jumpalign);
  3212. tokenwritelongint(alignment.jumpalignskipmax);
  3213. tokenwritelongint(alignment.coalescealign);
  3214. tokenwritelongint(alignment.coalescealignskipmax);
  3215. tokenwritelongint(alignment.constalignmin);
  3216. tokenwritelongint(alignment.constalignmax);
  3217. tokenwritelongint(alignment.varalignmin);
  3218. tokenwritelongint(alignment.varalignmax);
  3219. tokenwritelongint(alignment.localalignmin);
  3220. tokenwritelongint(alignment.localalignmax);
  3221. tokenwritelongint(alignment.recordalignmin);
  3222. tokenwritelongint(alignment.recordalignmax);
  3223. tokenwritelongint(alignment.maxCrecordalign);
  3224. tokenwriteset(globalswitches,sizeof(globalswitches));
  3225. tokenwriteset(targetswitches,sizeof(targetswitches));
  3226. tokenwriteset(moduleswitches,sizeof(moduleswitches));
  3227. tokenwriteset(localswitches,sizeof(localswitches));
  3228. tokenwriteset(modeswitches,sizeof(modeswitches));
  3229. tokenwriteset(optimizerswitches,sizeof(optimizerswitches));
  3230. tokenwriteset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
  3231. tokenwriteset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
  3232. tokenwriteset(debugswitches,sizeof(debugswitches));
  3233. { 0: old behaviour for sets <=256 elements
  3234. >0: round to this size }
  3235. tokenwriteshortint(setalloc);
  3236. tokenwriteshortint(packenum);
  3237. tokenwriteshortint(packrecords);
  3238. tokenwriteshortint(maxfpuregisters);
  3239. tokenwriteenum(cputype,sizeof(tcputype));
  3240. tokenwriteenum(optimizecputype,sizeof(tcputype));
  3241. tokenwriteenum(fputype,sizeof(tfputype));
  3242. tokenwriteenum(asmmode,sizeof(tasmmode));
  3243. tokenwriteenum(interfacetype,sizeof(tinterfacetypes));
  3244. tokenwriteenum(defproccall,sizeof(tproccalloption));
  3245. { tstringencoding is word type,
  3246. thus this should be OK here }
  3247. tokenwriteword(sourcecodepage);
  3248. tokenwriteenum(minfpconstprec,sizeof(tfloattype));
  3249. recordtokenbuf.write(byte(disabledircache),1);
  3250. tokenwriteenum(tlsmodel,sizeof(tlsmodel));
  3251. { TH: See note about controllertype field in tokenreadsettings. }
  3252. {$PUSH}
  3253. {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)
  3254. if ControllerSupport then
  3255. tokenwriteenum(controllertype,sizeof(tcontrollertype));
  3256. {$POP}
  3257. endpos:=recordtokenbuf.pos;
  3258. size:=endpos-startpos;
  3259. recordtokenbuf.seek(sizepos);
  3260. tokenwritesizeint(size);
  3261. recordtokenbuf.seek(endpos);
  3262. end;
  3263. end;
  3264. procedure tscannerfile.recordtoken;
  3265. var
  3266. t : ttoken;
  3267. s : tspecialgenerictoken;
  3268. len,msgnb,copy_size : asizeint;
  3269. val : longint;
  3270. b : byte;
  3271. pmsg : pmessagestaterecord;
  3272. begin
  3273. if not assigned(recordtokenbuf) then
  3274. internalerror(200511176);
  3275. t:=_GENERICSPECIALTOKEN;
  3276. { settings changed? }
  3277. { last field pmessage is handled separately below in
  3278. ST_LOADMESSAGES }
  3279. if CompareByte(current_settings,last_settings,
  3280. sizeof(current_settings)-sizeof(pointer))<>0 then
  3281. begin
  3282. { use a special token to record it }
  3283. s:=ST_LOADSETTINGS;
  3284. writetoken(t);
  3285. recordtokenbuf.write(s,1);
  3286. copy_size:=sizeof(current_settings)-sizeof(pointer);
  3287. tokenwritesettings(current_settings,copy_size);
  3288. last_settings:=current_settings;
  3289. end;
  3290. if current_settings.pmessage<>last_message then
  3291. begin
  3292. { use a special token to record it }
  3293. s:=ST_LOADMESSAGES;
  3294. writetoken(t);
  3295. recordtokenbuf.write(s,1);
  3296. msgnb:=0;
  3297. pmsg:=current_settings.pmessage;
  3298. while assigned(pmsg) do
  3299. begin
  3300. if msgnb=high(asizeint) then
  3301. { Too many messages }
  3302. internalerror(2011090401);
  3303. inc(msgnb);
  3304. pmsg:=pmsg^.next;
  3305. end;
  3306. tokenwritesizeint(msgnb);
  3307. pmsg:=current_settings.pmessage;
  3308. while assigned(pmsg) do
  3309. begin
  3310. { What about endianess here?}
  3311. { SB: this is handled by tokenreadlongint }
  3312. val:=pmsg^.value;
  3313. tokenwritelongint(val);
  3314. val:=ord(pmsg^.state);
  3315. tokenwritelongint(val);
  3316. pmsg:=pmsg^.next;
  3317. end;
  3318. last_message:=current_settings.pmessage;
  3319. end;
  3320. { file pos changes? }
  3321. if current_tokenpos.fileindex<>last_filepos.fileindex then
  3322. begin
  3323. s:=ST_FILEINDEX;
  3324. writetoken(t);
  3325. recordtokenbuf.write(s,1);
  3326. tokenwriteword(current_tokenpos.fileindex);
  3327. last_filepos.fileindex:=current_tokenpos.fileindex;
  3328. last_filepos.line:=0;
  3329. end;
  3330. if current_tokenpos.line<>last_filepos.line then
  3331. begin
  3332. s:=ST_LINE;
  3333. writetoken(t);
  3334. recordtokenbuf.write(s,1);
  3335. tokenwritelongint(current_tokenpos.line);
  3336. last_filepos.line:=current_tokenpos.line;
  3337. last_filepos.column:=0;
  3338. end;
  3339. if current_tokenpos.column<>last_filepos.column then
  3340. begin
  3341. s:=ST_COLUMN;
  3342. writetoken(t);
  3343. { can the column be written packed? }
  3344. if current_tokenpos.column<$80 then
  3345. begin
  3346. b:=$80 or current_tokenpos.column;
  3347. recordtokenbuf.write(b,1);
  3348. end
  3349. else
  3350. begin
  3351. recordtokenbuf.write(s,1);
  3352. tokenwriteword(current_tokenpos.column);
  3353. end;
  3354. last_filepos.column:=current_tokenpos.column;
  3355. end;
  3356. writetoken(token);
  3357. if token<>_GENERICSPECIALTOKEN then
  3358. writetoken(idtoken);
  3359. case token of
  3360. _CWCHAR,
  3361. _CWSTRING :
  3362. begin
  3363. tokenwritesizeint(patternw^.len);
  3364. if patternw^.len>0 then
  3365. recordtokenbuf.write(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
  3366. end;
  3367. _CSTRING:
  3368. begin
  3369. len:=length(cstringpattern);
  3370. tokenwritesizeint(len);
  3371. if len>0 then
  3372. recordtokenbuf.write(cstringpattern[1],len);
  3373. end;
  3374. _CCHAR,
  3375. _INTCONST,
  3376. _REALNUMBER :
  3377. begin
  3378. { pexpr.pas messes with pattern in case of negative integer consts,
  3379. see around line 2562 the comment of JM; remove the - before recording it
  3380. (FK)
  3381. }
  3382. if (token=_INTCONST) and (pattern[1]='-') then
  3383. delete(pattern,1,1);
  3384. recordtokenbuf.write(pattern[0],1);
  3385. recordtokenbuf.write(pattern[1],length(pattern));
  3386. end;
  3387. _ID :
  3388. begin
  3389. recordtokenbuf.write(orgpattern[0],1);
  3390. recordtokenbuf.write(orgpattern[1],length(orgpattern));
  3391. end;
  3392. else
  3393. ;
  3394. end;
  3395. end;
  3396. procedure tscannerfile.startreplaytokens(buf:tdynamicarray; change_endian:boolean);
  3397. begin
  3398. if not assigned(buf) then
  3399. internalerror(200511175);
  3400. { save current scanner state }
  3401. replaystack:=treplaystack.create(token,idtoken,orgpattern,pattern,
  3402. cstringpattern,patternw,current_settings,replaytokenbuf,change_endian_for_replay,replaystack);
  3403. {$ifdef check_inputpointer_limits}
  3404. if assigned(hidden_inputpointer) then
  3405. dec_inputpointer;
  3406. {$else not check_inputpointer_limits}
  3407. if assigned(inputpointer) then
  3408. dec(inputpointer);
  3409. {$endif check_inputpointer_limits}
  3410. { install buffer }
  3411. replaytokenbuf:=buf;
  3412. { Initialize value of change_endian_for_replay variable }
  3413. change_endian_for_replay:=change_endian;
  3414. { reload next token }
  3415. replaytokenbuf.seek(0);
  3416. replaytoken;
  3417. end;
  3418. function tscannerfile.readtoken: ttoken;
  3419. var
  3420. b,b2 : byte;
  3421. begin
  3422. replaytokenbuf.read(b,1);
  3423. if (b and $80)<>0 then
  3424. begin
  3425. replaytokenbuf.read(b2,1);
  3426. result:=ttoken(((b and $7f) shl 8) or b2);
  3427. end
  3428. else
  3429. result:=ttoken(b);
  3430. end;
  3431. procedure tscannerfile.replaytoken;
  3432. var
  3433. wlen,mesgnb,copy_size : asizeint;
  3434. specialtoken : tspecialgenerictoken;
  3435. i : byte;
  3436. pmsg,prevmsg : pmessagestaterecord;
  3437. begin
  3438. if not assigned(replaytokenbuf) then
  3439. internalerror(200511177);
  3440. { End of replay buffer? Then load the next char from the file again }
  3441. if replaytokenbuf.pos>=replaytokenbuf.size then
  3442. begin
  3443. token:=replaystack.token;
  3444. idtoken:=replaystack.idtoken;
  3445. pattern:=replaystack.pattern;
  3446. orgpattern:=replaystack.orgpattern;
  3447. setlengthwidestring(patternw,replaystack.patternw^.len);
  3448. move(replaystack.patternw^.data^,patternw^.data^,replaystack.patternw^.len*sizeof(tcompilerwidechar));
  3449. cstringpattern:=replaystack.cstringpattern;
  3450. replaytokenbuf:=replaystack.tokenbuf;
  3451. change_endian_for_replay:=replaystack.tokenbuf_needs_swapping;
  3452. { restore compiler settings }
  3453. current_settings:=replaystack.settings;
  3454. popreplaystack;
  3455. {$ifdef check_inputpointer_limits}
  3456. if assigned(hidden_inputpointer) then
  3457. begin
  3458. c:=get_inputpointer_char;
  3459. inc_inputpointer;
  3460. end;
  3461. {$else not check_inputpointer_limits}
  3462. if assigned(inputpointer) then
  3463. begin
  3464. c:=inputpointer^;
  3465. inc(inputpointer);
  3466. end;
  3467. {$endif check_inputpointer_limits}
  3468. exit;
  3469. end;
  3470. repeat
  3471. { load token from the buffer }
  3472. token:=readtoken;
  3473. if token<>_GENERICSPECIALTOKEN then
  3474. idtoken:=readtoken
  3475. else
  3476. idtoken:=_NOID;
  3477. case token of
  3478. _CWCHAR,
  3479. _CWSTRING :
  3480. begin
  3481. wlen:=tokenreadsizeint;
  3482. setlengthwidestring(patternw,wlen);
  3483. if wlen>0 then
  3484. replaytokenbuf.read(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
  3485. orgpattern:='';
  3486. pattern:='';
  3487. cstringpattern:='';
  3488. end;
  3489. _CSTRING:
  3490. begin
  3491. wlen:=tokenreadsizeint;
  3492. if wlen>0 then
  3493. begin
  3494. setlength(cstringpattern,wlen);
  3495. replaytokenbuf.read(cstringpattern[1],wlen);
  3496. end
  3497. else
  3498. cstringpattern:='';
  3499. orgpattern:='';
  3500. pattern:='';
  3501. end;
  3502. _CCHAR,
  3503. _INTCONST,
  3504. _REALNUMBER :
  3505. begin
  3506. replaytokenbuf.read(pattern[0],1);
  3507. replaytokenbuf.read(pattern[1],length(pattern));
  3508. orgpattern:='';
  3509. end;
  3510. _ID :
  3511. begin
  3512. replaytokenbuf.read(orgpattern[0],1);
  3513. replaytokenbuf.read(orgpattern[1],length(orgpattern));
  3514. pattern:=upper(orgpattern);
  3515. end;
  3516. _GENERICSPECIALTOKEN:
  3517. begin
  3518. replaytokenbuf.read(specialtoken,1);
  3519. { packed column? }
  3520. if (ord(specialtoken) and $80)<>0 then
  3521. begin
  3522. current_tokenpos.column:=ord(specialtoken) and $7f;
  3523. current_filepos:=current_tokenpos;
  3524. end
  3525. else
  3526. case specialtoken of
  3527. ST_LOADSETTINGS:
  3528. begin
  3529. copy_size:=tokenreadsizeint;
  3530. //if copy_size <> sizeof(current_settings)-sizeof(pointer) then
  3531. // internalerror(2011090501);
  3532. {
  3533. replaytokenbuf.read(current_settings,copy_size);
  3534. }
  3535. tokenreadsettings(current_settings,copy_size);
  3536. end;
  3537. ST_LOADMESSAGES:
  3538. begin
  3539. current_settings.pmessage:=nil;
  3540. mesgnb:=tokenreadsizeint;
  3541. prevmsg:=nil;
  3542. for i:=1 to mesgnb do
  3543. begin
  3544. new(pmsg);
  3545. if i=1 then
  3546. current_settings.pmessage:=pmsg
  3547. else
  3548. prevmsg^.next:=pmsg;
  3549. pmsg^.value:=tokenreadlongint;
  3550. pmsg^.state:=tmsgstate(tokenreadlongint);
  3551. pmsg^.next:=nil;
  3552. prevmsg:=pmsg;
  3553. end;
  3554. end;
  3555. ST_LINE:
  3556. begin
  3557. current_tokenpos.line:=tokenreadlongint;
  3558. current_filepos:=current_tokenpos;
  3559. end;
  3560. ST_COLUMN:
  3561. begin
  3562. current_tokenpos.column:=tokenreadword;
  3563. current_filepos:=current_tokenpos;
  3564. end;
  3565. ST_FILEINDEX:
  3566. begin
  3567. current_tokenpos.fileindex:=tokenreadword;
  3568. current_filepos:=current_tokenpos;
  3569. end;
  3570. end;
  3571. continue;
  3572. end;
  3573. else
  3574. ;
  3575. end;
  3576. break;
  3577. until false;
  3578. end;
  3579. procedure tscannerfile.addfile(hp:tinputfile);
  3580. begin
  3581. saveinputfile;
  3582. { add to list }
  3583. hp.next:=inputfile;
  3584. inputfile:=hp;
  3585. { load new inputfile }
  3586. restoreinputfile;
  3587. end;
  3588. procedure tscannerfile.reload;
  3589. var
  3590. wasmacro: Boolean;
  3591. begin
  3592. with inputfile do
  3593. begin
  3594. { when nothing more to read then leave immediatly, so we
  3595. don't change the current_filepos and leave it point to the last
  3596. char }
  3597. if (c=#26) and (not assigned(next)) then
  3598. exit;
  3599. repeat
  3600. { still more to read?, then change the #0 to a space so its seen
  3601. as a separator, this can't be used for macro's which can change
  3602. the place of the #0 in the buffer with tempopen }
  3603. if (c=#0) and (bufsize>0) and
  3604. not(inputfile.is_macro) and
  3605. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3606. (hidden_inputpointer-hidden_inputbuffer<bufsize) then
  3607. {$else not CHECK_INPUTPOINTER_LIMITS}
  3608. (inputpointer-inputbuffer<bufsize) then
  3609. {$endif CHECK_INPUTPOINTER_LIMITS}
  3610. begin
  3611. c:=' ';
  3612. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3613. inc_inputpointer;
  3614. {$else not CHECK_INPUTPOINTER_LIMITS}
  3615. inc(inputpointer);
  3616. {$endif CHECK_INPUTPOINTER_LIMITS}
  3617. exit;
  3618. end;
  3619. { can we read more from this file ? }
  3620. if (c<>#26) and (not endoffile) then
  3621. begin
  3622. readbuf;
  3623. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3624. hidden_inputpointer:=buf;
  3625. hidden_inputbuffer:=buf;
  3626. {$else not CHECK_INPUTPOINTER_LIMITS}
  3627. inputpointer:=buf;
  3628. inputbuffer:=buf;
  3629. {$endif CHECK_INPUTPOINTER_LIMITS}
  3630. inputstart:=bufstart;
  3631. { first line? }
  3632. if line_no=0 then
  3633. begin
  3634. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3635. c:=get_inputpointer_char;
  3636. { eat utf-8 signature? }
  3637. if (bufsize>2) and
  3638. (ord(get_inputpointer_char)=$ef) and
  3639. (ord(get_inputpointer_char(1))=$bb) and
  3640. (ord(get_inputpointer_char(2))=$bf) then
  3641. begin
  3642. {$else not CHECK_INPUTPOINTER_LIMITS}
  3643. c:=inputpointer^;
  3644. { eat utf-8 signature? }
  3645. if (bufsize>2) and
  3646. (ord(inputpointer^)=$ef) and
  3647. (ord((inputpointer+1)^)=$bb) and
  3648. (ord((inputpointer+2)^)=$bf) then
  3649. begin
  3650. {$endif CHECK_INPUTPOINTER_LIMITS}
  3651. (* we don't support including files with an UTF-8 bom
  3652. inside another file that wasn't encoded as UTF-8
  3653. already (we don't support {$codepage xxx} switches in
  3654. the middle of a file either) *)
  3655. if (current_settings.sourcecodepage<>CP_UTF8) and
  3656. not current_module.in_global then
  3657. Message(scanner_f_illegal_utf8_bom);
  3658. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3659. inc_inputpointer(3);
  3660. {$else not CHECK_INPUTPOINTER_LIMITS}
  3661. inc(inputpointer,3);
  3662. {$endif CHECK_INPUTPOINTER_LIMITS}
  3663. message(scan_c_switching_to_utf8);
  3664. current_settings.sourcecodepage:=CP_UTF8;
  3665. exclude(current_settings.moduleswitches,cs_system_codepage);
  3666. include(current_settings.moduleswitches,cs_explicit_codepage);
  3667. end;
  3668. line_no:=1;
  3669. if cs_asm_source in current_settings.globalswitches then
  3670. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3671. inputfile.setline(line_no,inputstart+hidden_inputpointer-hidden_inputbuffer);
  3672. {$else not CHECK_INPUTPOINTER_LIMITS}
  3673. inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);
  3674. {$endif CHECK_INPUTPOINTER_LIMITS}
  3675. end;
  3676. end
  3677. else
  3678. begin
  3679. wasmacro:=inputfile.is_macro;
  3680. { load eof position in tokenpos/current_filepos }
  3681. gettokenpos;
  3682. { close file }
  3683. closeinputfile;
  3684. { no next module, than EOF }
  3685. if not assigned(inputfile.next) then
  3686. begin
  3687. c:=#26;
  3688. exit;
  3689. end;
  3690. { load next file and reopen it }
  3691. nextfile;
  3692. tempopeninputfile;
  3693. { status }
  3694. Message1(scan_t_back_in,inputfile.name);
  3695. { end of include file is like a line break which ends e.g. also // style comments }
  3696. if not(wasmacro) and (current_commentstyle=comment_delphi) then
  3697. begin
  3698. c:=#10;
  3699. { ... but we have to decrease the line number first because it is increased due to this
  3700. inserted line break later on }
  3701. dec(line_no);
  3702. exit;
  3703. end;
  3704. end;
  3705. { load next char }
  3706. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3707. c:=get_inputpointer_char;
  3708. inc_inputpointer;
  3709. {$else not CHECK_INPUTPOINTER_LIMITS}
  3710. c:=inputpointer^;
  3711. inc(inputpointer);
  3712. {$endif CHECK_INPUTPOINTER_LIMITS}
  3713. until c<>#0; { if also end, then reload again }
  3714. end;
  3715. end;
  3716. procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);
  3717. var
  3718. hp : tinputfile;
  3719. begin
  3720. { save old postion }
  3721. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3722. dec_inputpointer;
  3723. {$else not CHECK_INPUTPOINTER_LIMITS}
  3724. dec(inputpointer);
  3725. {$endif CHECK_INPUTPOINTER_LIMITS}
  3726. tempcloseinputfile;
  3727. { create macro 'file' }
  3728. { use special name to dispose after !! }
  3729. hp:=do_openinputfile('_Macro_.'+macname);
  3730. addfile(hp);
  3731. with inputfile do
  3732. begin
  3733. inc(macro_nesting_depth);
  3734. setmacro(p,len);
  3735. { local buffer }
  3736. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3737. hidden_inputbuffer:=buf;
  3738. hidden_inputpointer:=buf;
  3739. {$else not CHECK_INPUTPOINTER_LIMITS}
  3740. inputbuffer:=buf;
  3741. inputpointer:=buf;
  3742. {$endif CHECK_INPUTPOINTER_LIMITS}
  3743. inputstart:=bufstart;
  3744. ref_index:=fileindex;
  3745. internally_generated_macro:=internally_generated;
  3746. end;
  3747. { reset line }
  3748. line_no:=line;
  3749. lastlinepos:=0;
  3750. lasttokenpos:=0;
  3751. nexttokenpos:=0;
  3752. { load new c }
  3753. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3754. c:=get_inputpointer_char;
  3755. inc_inputpointer;
  3756. {$else not CHECK_INPUTPOINTER_LIMITS}
  3757. c:=inputpointer^;
  3758. inc(inputpointer);
  3759. {$endif CHECK_INPUTPOINTER_LIMITS}
  3760. end;
  3761. procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
  3762. begin
  3763. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3764. tokenpos:=inputstart+(hidden_inputpointer-hidden_inputbuffer);
  3765. {$else not CHECK_INPUTPOINTER_LIMITS}
  3766. tokenpos:=inputstart+(inputpointer-inputbuffer);
  3767. {$endif CHECK_INPUTPOINTER_LIMITS}
  3768. filepos.line:=line_no;
  3769. filepos.column:=tokenpos-lastlinepos;
  3770. filepos.fileindex:=inputfile.ref_index;
  3771. filepos.moduleindex:=current_module.unit_index;
  3772. end;
  3773. procedure tscannerfile.gettokenpos;
  3774. { load the values of tokenpos and lasttokenpos }
  3775. begin
  3776. do_gettokenpos(lasttokenpos,current_tokenpos);
  3777. current_filepos:=current_tokenpos;
  3778. end;
  3779. procedure tscannerfile.cachenexttokenpos;
  3780. begin
  3781. do_gettokenpos(nexttokenpos,next_filepos);
  3782. end;
  3783. procedure tscannerfile.setnexttoken;
  3784. begin
  3785. token:=nexttoken;
  3786. nexttoken:=NOTOKEN;
  3787. lasttokenpos:=nexttokenpos;
  3788. current_tokenpos:=next_filepos;
  3789. current_filepos:=current_tokenpos;
  3790. nexttokenpos:=0;
  3791. end;
  3792. procedure tscannerfile.savetokenpos;
  3793. begin
  3794. oldlasttokenpos:=lasttokenpos;
  3795. oldcurrent_filepos:=current_filepos;
  3796. oldcurrent_tokenpos:=current_tokenpos;
  3797. end;
  3798. procedure tscannerfile.restoretokenpos;
  3799. begin
  3800. lasttokenpos:=oldlasttokenpos;
  3801. current_filepos:=oldcurrent_filepos;
  3802. current_tokenpos:=oldcurrent_tokenpos;
  3803. end;
  3804. procedure tscannerfile.inc_comment_level;
  3805. begin
  3806. if (m_nested_comment in current_settings.modeswitches) then
  3807. inc(comment_level)
  3808. else
  3809. comment_level:=1;
  3810. if (comment_level>1) then
  3811. begin
  3812. savetokenpos;
  3813. gettokenpos; { update for warning }
  3814. Message1(scan_w_comment_level,tostr(comment_level));
  3815. restoretokenpos;
  3816. end;
  3817. end;
  3818. procedure tscannerfile.dec_comment_level;
  3819. begin
  3820. if (m_nested_comment in current_settings.modeswitches) then
  3821. dec(comment_level)
  3822. else
  3823. comment_level:=0;
  3824. end;
  3825. procedure tscannerfile.linebreak;
  3826. var
  3827. cur : char;
  3828. begin
  3829. with inputfile do
  3830. begin
  3831. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3832. if (byte(get_inputpointer_char)=0) and not(endoffile) then
  3833. {$else not CHECK_INPUTPOINTER_LIMITS}
  3834. if (byte(inputpointer^)=0) and not(endoffile) then
  3835. {$endif CHECK_INPUTPOINTER_LIMITS}
  3836. begin
  3837. cur:=c;
  3838. reload;
  3839. if byte(cur)+byte(c)<>23 then
  3840. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3841. dec_inputpointer;
  3842. {$else not CHECK_INPUTPOINTER_LIMITS}
  3843. dec(inputpointer);
  3844. {$endif CHECK_INPUTPOINTER_LIMITS}
  3845. end
  3846. else
  3847. begin
  3848. { Support all combination of #10 and #13 as line break }
  3849. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3850. if (byte(get_inputpointer_char)+byte(c)=23) then
  3851. inc_inputpointer;
  3852. {$else not CHECK_INPUTPOINTER_LIMITS}
  3853. if (byte(inputpointer^)+byte(c)=23) then
  3854. inc(inputpointer);
  3855. {$endif CHECK_INPUTPOINTER_LIMITS}
  3856. end;
  3857. { Always return #10 as line break }
  3858. c:=#10;
  3859. { increase line counters }
  3860. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  3861. lastlinepos:=inputstart+(hidden_inputpointer-hidden_inputbuffer);
  3862. {$else not CHECK_INPUTPOINTER_LIMITS}
  3863. lastlinepos:=inputstart+(inputpointer-inputbuffer);
  3864. {$endif CHECK_INPUTPOINTER_LIMITS}
  3865. inc(line_no);
  3866. { update linebuffer }
  3867. if cs_asm_source in current_settings.globalswitches then
  3868. inputfile.setline(line_no,lastlinepos);
  3869. { update for status and call the show status routine,
  3870. but don't touch current_filepos ! }
  3871. savetokenpos;
  3872. gettokenpos; { update for v_status }
  3873. inc(status.compiledlines);
  3874. ShowStatus;
  3875. restoretokenpos;
  3876. end;
  3877. end;
  3878. procedure tscannerfile.illegal_char(c:char);
  3879. var
  3880. s : string;
  3881. begin
  3882. if c in [#32..#255] then
  3883. s:=''''+c+''''
  3884. else
  3885. s:='#'+tostr(ord(c));
  3886. Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
  3887. end;
  3888. procedure tscannerfile.end_of_file;
  3889. begin
  3890. checkpreprocstack;
  3891. Message(scan_f_end_of_file);
  3892. end;
  3893. {-------------------------------------------
  3894. IF Conditional Handling
  3895. -------------------------------------------}
  3896. procedure tscannerfile.checkpreprocstack;
  3897. begin
  3898. { check for missing ifdefs }
  3899. while assigned(preprocstack) do
  3900. begin
  3901. Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
  3902. current_module.sourcefiles.get_file_name(preprocstack.fileindex),
  3903. tostr(preprocstack.line_nb));
  3904. poppreprocstack;
  3905. end;
  3906. end;
  3907. procedure tscannerfile.poppreprocstack;
  3908. var
  3909. hp : tpreprocstack;
  3910. begin
  3911. if assigned(preprocstack) then
  3912. begin
  3913. Message1(scan_c_endif_found,preprocstack.name);
  3914. hp:=preprocstack.next;
  3915. preprocstack.free;
  3916. preprocstack:=hp;
  3917. end
  3918. else
  3919. Message(scan_e_endif_without_if);
  3920. end;
  3921. procedure tscannerfile.ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  3922. var
  3923. condition: Boolean;
  3924. valuedescr: String;
  3925. begin
  3926. if (preprocstack=nil) or preprocstack.accept then
  3927. condition:=compile_time_predicate(valuedescr)
  3928. else
  3929. begin
  3930. condition:= false;
  3931. valuedescr:= '';
  3932. end;
  3933. preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
  3934. preprocstack.name:=valuedescr;
  3935. preprocstack.line_nb:=line_no;
  3936. preprocstack.fileindex:=current_filepos.fileindex;
  3937. if preprocstack.accept then
  3938. Message2(messid,preprocstack.name,'accepted')
  3939. else
  3940. Message2(messid,preprocstack.name,'rejected');
  3941. end;
  3942. procedure tscannerfile.elsepreprocstack;
  3943. begin
  3944. if assigned(preprocstack) and
  3945. (preprocstack.typ<>pp_else) then
  3946. begin
  3947. if (preprocstack.typ=pp_elseif) then
  3948. preprocstack.accept:=false
  3949. else
  3950. if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
  3951. preprocstack.accept:=not preprocstack.accept;
  3952. preprocstack.iftyp:=preprocstack.typ;
  3953. preprocstack.typ:=pp_else;
  3954. preprocstack.line_nb:=line_no;
  3955. preprocstack.fileindex:=current_filepos.fileindex;
  3956. if preprocstack.accept then
  3957. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3958. else
  3959. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3960. end
  3961. else
  3962. Message(scan_e_endif_without_if);
  3963. end;
  3964. procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  3965. var
  3966. valuedescr: String;
  3967. begin
  3968. if assigned(preprocstack) and
  3969. (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef,pp_elseif]) then
  3970. begin
  3971. { when the branch is accepted we use pp_elseif so we know that
  3972. all the next branches need to be rejected. when this branch is still
  3973. not accepted then leave it at pp_if }
  3974. if (preprocstack.typ=pp_elseif) then
  3975. preprocstack.accept:=false
  3976. else if (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef]) and preprocstack.accept then
  3977. begin
  3978. preprocstack.accept:=false;
  3979. preprocstack.typ:=pp_elseif;
  3980. end
  3981. else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
  3982. and compile_time_predicate(valuedescr) then
  3983. begin
  3984. preprocstack.name:=valuedescr;
  3985. preprocstack.accept:=true;
  3986. preprocstack.typ:=pp_elseif;
  3987. end;
  3988. preprocstack.line_nb:=line_no;
  3989. preprocstack.fileindex:=current_filepos.fileindex;
  3990. if preprocstack.accept then
  3991. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3992. else
  3993. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3994. end
  3995. else
  3996. Message(scan_e_endif_without_if);
  3997. end;
  3998. procedure tscannerfile.popreplaystack;
  3999. var
  4000. hp : treplaystack;
  4001. begin
  4002. if assigned(replaystack) then
  4003. begin
  4004. hp:=replaystack.next;
  4005. replaystack.free;
  4006. replaystack:=hp;
  4007. end;
  4008. end;
  4009. function tscannerfile.replay_stack_depth:longint;
  4010. var
  4011. tmp: treplaystack;
  4012. begin
  4013. result:=0;
  4014. tmp:=replaystack;
  4015. while assigned(tmp) do
  4016. begin
  4017. inc(result);
  4018. tmp:=tmp.next;
  4019. end;
  4020. end;
  4021. procedure tscannerfile.handleconditional(p:tdirectiveitem);
  4022. begin
  4023. savetokenpos;
  4024. repeat
  4025. current_scanner.gettokenpos;
  4026. Message1(scan_d_handling_switch,'$'+p.name);
  4027. p.proc();
  4028. { accept the text ? }
  4029. if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
  4030. break
  4031. else
  4032. begin
  4033. current_scanner.gettokenpos;
  4034. Message(scan_c_skipping_until);
  4035. repeat
  4036. current_scanner.skipuntildirective;
  4037. if not (m_mac in current_settings.modeswitches) then
  4038. p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))
  4039. else
  4040. p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));
  4041. until assigned(p) and (p.is_conditional);
  4042. current_scanner.gettokenpos;
  4043. end;
  4044. until false;
  4045. restoretokenpos;
  4046. end;
  4047. procedure tscannerfile.handledirectives;
  4048. var
  4049. t : tdirectiveitem;
  4050. hs : string;
  4051. begin
  4052. gettokenpos;
  4053. readchar; {Remove the $}
  4054. hs:=readid;
  4055. { handle empty directive }
  4056. if hs='' then
  4057. begin
  4058. Message1(scan_w_illegal_switch,'$');
  4059. exit;
  4060. end;
  4061. {$ifdef PREPROCWRITE}
  4062. if parapreprocess then
  4063. begin
  4064. if not (m_mac in current_settings.modeswitches) then
  4065. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  4066. else
  4067. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  4068. if assigned(t) and not(t.is_conditional) then
  4069. begin
  4070. preprocfile.AddSpace;
  4071. preprocfile.Add('{$'+hs+current_scanner.readcomment+'}');
  4072. exit;
  4073. end;
  4074. end;
  4075. {$endif PREPROCWRITE}
  4076. { skip this directive? }
  4077. if (ignoredirectives.find(hs)<>nil) then
  4078. begin
  4079. if (comment_level>0) then
  4080. readcomment;
  4081. { we've read the whole comment }
  4082. current_commentstyle:=comment_none;
  4083. exit;
  4084. end;
  4085. { Check for compiler switches }
  4086. while (length(hs)=1) and (c in ['-','+']) do
  4087. begin
  4088. Message1(scan_d_handling_switch,'$'+hs+c);
  4089. HandleSwitch(hs[1],c);
  4090. current_scanner.readchar; {Remove + or -}
  4091. if c=',' then
  4092. begin
  4093. current_scanner.readchar; {Remove , }
  4094. { read next switch, support $v+,$+}
  4095. hs:=current_scanner.readid;
  4096. if (hs='') then
  4097. begin
  4098. if (c='$') and (m_fpc in current_settings.modeswitches) then
  4099. begin
  4100. current_scanner.readchar; { skip $ }
  4101. hs:=current_scanner.readid;
  4102. end;
  4103. if (hs='') then
  4104. Message1(scan_w_illegal_directive,'$'+c);
  4105. end;
  4106. end
  4107. else
  4108. hs:='';
  4109. end;
  4110. { directives may follow switches after a , }
  4111. if hs<>'' then
  4112. begin
  4113. if not (m_mac in current_settings.modeswitches) then
  4114. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  4115. else
  4116. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  4117. if assigned(t) then
  4118. begin
  4119. if t.is_conditional then
  4120. handleconditional(t)
  4121. else
  4122. begin
  4123. Message1(scan_d_handling_switch,'$'+hs);
  4124. t.proc();
  4125. end;
  4126. end
  4127. else
  4128. begin
  4129. current_scanner.ignoredirectives.Add(hs,nil);
  4130. Message1(scan_w_illegal_directive,'$'+hs);
  4131. end;
  4132. { conditionals already read the comment }
  4133. if (current_scanner.comment_level>0) then
  4134. current_scanner.readcomment;
  4135. { we've read the whole comment }
  4136. current_commentstyle:=comment_none;
  4137. end;
  4138. end;
  4139. procedure tscannerfile.readchar;
  4140. begin
  4141. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  4142. c:=get_inputpointer_char;
  4143. {$else not CHECK_INPUTPOINTER_LIMITS}
  4144. c:=inputpointer^;
  4145. {$endif CHECK_INPUTPOINTER_LIMITS}
  4146. if c=#0 then
  4147. reload
  4148. else
  4149. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  4150. inc_inputpointer;
  4151. {$else not CHECK_INPUTPOINTER_LIMITS}
  4152. inc(inputpointer);
  4153. {$endif CHECK_INPUTPOINTER_LIMITS}
  4154. end;
  4155. procedure tscannerfile.readstring;
  4156. var
  4157. i : longint;
  4158. err : boolean;
  4159. begin
  4160. err:=false;
  4161. i:=0;
  4162. repeat
  4163. case c of
  4164. '_',
  4165. '0'..'9',
  4166. 'A'..'Z',
  4167. 'a'..'z' :
  4168. begin
  4169. if i<255 then
  4170. begin
  4171. inc(i);
  4172. orgpattern[i]:=c;
  4173. if c in ['a'..'z'] then
  4174. pattern[i]:=chr(ord(c)-32)
  4175. else
  4176. pattern[i]:=c;
  4177. end
  4178. else
  4179. begin
  4180. if not err then
  4181. begin
  4182. Message(scan_e_string_exceeds_255_chars);
  4183. err:=true;
  4184. end;
  4185. end;
  4186. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  4187. c:=get_inputpointer_char;
  4188. inc_inputpointer;
  4189. {$else not CHECK_INPUTPOINTER_LIMITS}
  4190. c:=inputpointer^;
  4191. inc(inputpointer);
  4192. {$endif CHECK_INPUTPOINTER_LIMITS}
  4193. end;
  4194. #0 :
  4195. reload;
  4196. else if inputfile.internally_generated_macro and
  4197. (c in [internal_macro_escape_begin..internal_macro_escape_end]) then
  4198. begin
  4199. if i<255 then
  4200. begin
  4201. inc(i);
  4202. orgpattern[i]:=c;
  4203. pattern[i]:=c;
  4204. end
  4205. else
  4206. begin
  4207. if not err then
  4208. begin
  4209. Message(scan_e_string_exceeds_255_chars);
  4210. err:=true;
  4211. end;
  4212. end;
  4213. {$ifdef CHECK_INPUTPOINTER_LIMITS}
  4214. c:=get_inputpointer_char;
  4215. inc_inputpointer;
  4216. {$else not CHECK_INPUTPOINTER_LIMITS}
  4217. c:=inputpointer^;
  4218. inc(inputpointer);
  4219. {$endif CHECK_INPUTPOINTER_LIMITS}
  4220. end
  4221. else
  4222. break;
  4223. end;
  4224. until false;
  4225. orgpattern[0]:=chr(i);
  4226. pattern[0]:=chr(i);
  4227. end;
  4228. procedure tscannerfile.readnumber;
  4229. var
  4230. base,
  4231. i : longint;
  4232. firstdigitread: Boolean;
  4233. begin
  4234. case c of
  4235. '%' :
  4236. begin
  4237. readchar;
  4238. base:=2;
  4239. pattern[1]:='%';
  4240. i:=1;
  4241. end;
  4242. '&' :
  4243. begin
  4244. readchar;
  4245. base:=8;
  4246. pattern[1]:='&';
  4247. i:=1;
  4248. end;
  4249. '$' :
  4250. begin
  4251. readchar;
  4252. base:=16;
  4253. pattern[1]:='$';
  4254. i:=1;
  4255. end;
  4256. else
  4257. begin
  4258. base:=10;
  4259. i:=0;
  4260. end;
  4261. end;
  4262. firstdigitread:=false;
  4263. while ((base>=10) and (c in ['0'..'9'])) or
  4264. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  4265. ((base=8) and (c in ['0'..'7'])) or
  4266. ((base=2) and (c in ['0'..'1'])) or
  4267. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  4268. begin
  4269. if (i<255) and (c<>'_') then
  4270. begin
  4271. inc(i);
  4272. pattern[i]:=c;
  4273. end;
  4274. readchar;
  4275. firstdigitread:=true;
  4276. end;
  4277. pattern[0]:=chr(i);
  4278. end;
  4279. function tscannerfile.readid:string;
  4280. begin
  4281. readstring;
  4282. readid:=pattern;
  4283. end;
  4284. function tscannerfile.readval:longint;
  4285. var
  4286. l : longint;
  4287. w : integer;
  4288. begin
  4289. readnumber;
  4290. val(pattern,l,w);
  4291. readval:=l;
  4292. end;
  4293. function tscannerfile.readcomment(include_special_char: boolean):string;
  4294. var
  4295. i : longint;
  4296. begin
  4297. i:=0;
  4298. repeat
  4299. case c of
  4300. '{' :
  4301. begin
  4302. if (include_special_char) and (i<255) then
  4303. begin
  4304. inc(i);
  4305. readcomment[i]:=c;
  4306. end;
  4307. if current_commentstyle=comment_tp then
  4308. inc_comment_level;
  4309. end;
  4310. '}' :
  4311. begin
  4312. if (include_special_char) and (i<255) then
  4313. begin
  4314. inc(i);
  4315. readcomment[i]:=c;
  4316. end;
  4317. if current_commentstyle=comment_tp then
  4318. begin
  4319. readchar;
  4320. dec_comment_level;
  4321. if comment_level=0 then
  4322. break
  4323. else
  4324. continue;
  4325. end;
  4326. end;
  4327. '*' :
  4328. begin
  4329. if current_commentstyle=comment_oldtp then
  4330. begin
  4331. readchar;
  4332. if c=')' then
  4333. begin
  4334. readchar;
  4335. dec_comment_level;
  4336. break;
  4337. end
  4338. else
  4339. { Add both characters !!}
  4340. if (i<255) then
  4341. begin
  4342. inc(i);
  4343. readcomment[i]:='*';
  4344. if (i<255) then
  4345. begin
  4346. inc(i);
  4347. readcomment[i]:=c;
  4348. end;
  4349. end;
  4350. end
  4351. else
  4352. { Not old TP comment, so add...}
  4353. begin
  4354. if (i<255) then
  4355. begin
  4356. inc(i);
  4357. readcomment[i]:='*';
  4358. end;
  4359. end;
  4360. end;
  4361. #10,#13 :
  4362. linebreak;
  4363. #26 :
  4364. end_of_file;
  4365. else
  4366. begin
  4367. if (i<255) then
  4368. begin
  4369. inc(i);
  4370. readcomment[i]:=c;
  4371. end;
  4372. end;
  4373. end;
  4374. readchar;
  4375. until false;
  4376. readcomment[0]:=chr(i);
  4377. end;
  4378. function tscannerfile.readquotedstring:string;
  4379. var
  4380. i : longint;
  4381. msgwritten : boolean;
  4382. begin
  4383. i:=0;
  4384. msgwritten:=false;
  4385. if (c='''') then
  4386. begin
  4387. repeat
  4388. readchar;
  4389. case c of
  4390. #26 :
  4391. end_of_file;
  4392. #10,#13 :
  4393. Message(scan_f_string_exceeds_line);
  4394. '''' :
  4395. begin
  4396. readchar;
  4397. if c<>'''' then
  4398. break;
  4399. end;
  4400. end;
  4401. if i<255 then
  4402. begin
  4403. inc(i);
  4404. result[i]:=c;
  4405. end
  4406. else
  4407. begin
  4408. if not msgwritten then
  4409. begin
  4410. Message(scan_e_string_exceeds_255_chars);
  4411. msgwritten:=true;
  4412. end;
  4413. end;
  4414. until false;
  4415. end;
  4416. result[0]:=chr(i);
  4417. end;
  4418. function tscannerfile.readstate:char;
  4419. var
  4420. state : char;
  4421. begin
  4422. state:=' ';
  4423. if c=' ' then
  4424. begin
  4425. current_scanner.skipspace;
  4426. current_scanner.readid;
  4427. if pattern='ON' then
  4428. state:='+'
  4429. else
  4430. if pattern='OFF' then
  4431. state:='-';
  4432. end
  4433. else
  4434. state:=c;
  4435. if not (state in ['+','-']) then
  4436. Message(scan_e_wrong_switch_toggle);
  4437. readstate:=state;
  4438. end;
  4439. function tscannerfile.readoptionalstate(fallback:char):char;
  4440. var
  4441. state : char;
  4442. begin
  4443. state:=' ';
  4444. if c=' ' then
  4445. begin
  4446. current_scanner.skipspace;
  4447. if c in ['*','}'] then
  4448. state:=fallback
  4449. else
  4450. begin
  4451. current_scanner.readid;
  4452. if pattern='ON' then
  4453. state:='+'
  4454. else
  4455. if pattern='OFF' then
  4456. state:='-';
  4457. end;
  4458. end
  4459. else
  4460. if c in ['*','}'] then
  4461. state:=fallback
  4462. else
  4463. state:=c;
  4464. if not (state in ['+','-']) then
  4465. Message(scan_e_wrong_switch_toggle);
  4466. readoptionalstate:=state;
  4467. end;
  4468. function tscannerfile.readstatedefault:char;
  4469. var
  4470. state : char;
  4471. begin
  4472. state:=' ';
  4473. if c=' ' then
  4474. begin
  4475. current_scanner.skipspace;
  4476. current_scanner.readid;
  4477. if pattern='ON' then
  4478. state:='+'
  4479. else
  4480. if pattern='OFF' then
  4481. state:='-'
  4482. else
  4483. if pattern='DEFAULT' then
  4484. state:='*';
  4485. end
  4486. else
  4487. state:=c;
  4488. if not (state in ['+','-','*']) then
  4489. Message(scan_e_wrong_switch_toggle_default);
  4490. readstatedefault:=state;
  4491. end;
  4492. procedure tscannerfile.skipspace;
  4493. begin
  4494. repeat
  4495. case c of
  4496. #26 :
  4497. begin
  4498. reload;
  4499. if (c=#26) and not assigned(inputfile.next) then
  4500. break;
  4501. continue;
  4502. end;
  4503. #10,
  4504. #13 :
  4505. linebreak;
  4506. #9,#11,#12,' ' :
  4507. ;
  4508. else
  4509. break;
  4510. end;
  4511. readchar;
  4512. until false;
  4513. end;
  4514. procedure tscannerfile.skipuntildirective;
  4515. var
  4516. found : longint;
  4517. next_char_loaded : boolean;
  4518. begin
  4519. found:=0;
  4520. next_char_loaded:=false;
  4521. repeat
  4522. case c of
  4523. #10,
  4524. #13 :
  4525. linebreak;
  4526. #26 :
  4527. begin
  4528. reload;
  4529. if (c=#26) and not assigned(inputfile.next) then
  4530. end_of_file;
  4531. continue;
  4532. end;
  4533. '{' :
  4534. begin
  4535. if (current_commentstyle in [comment_tp,comment_none]) then
  4536. begin
  4537. current_commentstyle:=comment_tp;
  4538. if (comment_level=0) then
  4539. found:=1;
  4540. inc_comment_level;
  4541. end;
  4542. end;
  4543. '*' :
  4544. begin
  4545. if (current_commentstyle=comment_oldtp) then
  4546. begin
  4547. readchar;
  4548. if c=')' then
  4549. begin
  4550. dec_comment_level;
  4551. found:=0;
  4552. current_commentstyle:=comment_none;
  4553. end
  4554. else
  4555. next_char_loaded:=true;
  4556. end
  4557. else
  4558. found := 0;
  4559. end;
  4560. '}' :
  4561. begin
  4562. if (current_commentstyle=comment_tp) then
  4563. begin
  4564. dec_comment_level;
  4565. if (comment_level=0) then
  4566. current_commentstyle:=comment_none;
  4567. found:=0;
  4568. end;
  4569. end;
  4570. '$' :
  4571. begin
  4572. if found=1 then
  4573. found:=2;
  4574. end;
  4575. '''' :
  4576. if (current_commentstyle=comment_none) then
  4577. begin
  4578. repeat
  4579. readchar;
  4580. case c of
  4581. #26 :
  4582. end_of_file;
  4583. #10,#13 :
  4584. break;
  4585. '''' :
  4586. begin
  4587. readchar;
  4588. if c<>'''' then
  4589. begin
  4590. next_char_loaded:=true;
  4591. break;
  4592. end;
  4593. end;
  4594. end;
  4595. until false;
  4596. end;
  4597. '(' :
  4598. begin
  4599. if (current_commentstyle=comment_none) then
  4600. begin
  4601. readchar;
  4602. if c='*' then
  4603. begin
  4604. readchar;
  4605. if c='$' then
  4606. begin
  4607. found:=2;
  4608. inc_comment_level;
  4609. current_commentstyle:=comment_oldtp;
  4610. end
  4611. else
  4612. begin
  4613. skipoldtpcomment(false);
  4614. next_char_loaded:=true;
  4615. end;
  4616. end
  4617. else
  4618. next_char_loaded:=true;
  4619. end
  4620. else
  4621. found:=0;
  4622. end;
  4623. '/' :
  4624. begin
  4625. if (current_commentstyle=comment_none) then
  4626. begin
  4627. readchar;
  4628. if c='/' then
  4629. skipdelphicomment;
  4630. next_char_loaded:=true;
  4631. end
  4632. else
  4633. found:=0;
  4634. end;
  4635. else
  4636. found:=0;
  4637. end;
  4638. if next_char_loaded then
  4639. next_char_loaded:=false
  4640. else
  4641. readchar;
  4642. until (found=2);
  4643. end;
  4644. {****************************************************************************
  4645. Comment Handling
  4646. ****************************************************************************}
  4647. procedure tscannerfile.skipcomment(read_first_char:boolean);
  4648. begin
  4649. current_commentstyle:=comment_tp;
  4650. if read_first_char then
  4651. readchar;
  4652. inc_comment_level;
  4653. { handle compiler switches }
  4654. if (c='$') then
  4655. handledirectives;
  4656. { handle_switches can dec comment_level, }
  4657. while (comment_level>0) do
  4658. begin
  4659. case c of
  4660. '{' :
  4661. inc_comment_level;
  4662. '}' :
  4663. dec_comment_level;
  4664. '*' :
  4665. { in iso mode, comments opened by a curly bracket can be closed by asterisk, round bracket }
  4666. if m_iso in current_settings.modeswitches then
  4667. begin
  4668. readchar;
  4669. if c=')' then
  4670. dec_comment_level
  4671. else
  4672. continue;
  4673. end;
  4674. #10,#13 :
  4675. linebreak;
  4676. #26 :
  4677. begin
  4678. reload;
  4679. if (c=#26) and not assigned(inputfile.next) then
  4680. end_of_file;
  4681. continue;
  4682. end;
  4683. end;
  4684. readchar;
  4685. end;
  4686. current_commentstyle:=comment_none;
  4687. end;
  4688. procedure tscannerfile.skipdelphicomment;
  4689. begin
  4690. current_commentstyle:=comment_delphi;
  4691. inc_comment_level;
  4692. readchar;
  4693. { this is not supported }
  4694. if c='$' then
  4695. Message(scan_w_wrong_styled_switch);
  4696. { skip comment }
  4697. while not (c in [#10,#13,#26]) do
  4698. readchar;
  4699. dec_comment_level;
  4700. current_commentstyle:=comment_none;
  4701. end;
  4702. procedure tscannerfile.skipoldtpcomment(read_first_char:boolean);
  4703. var
  4704. found : longint;
  4705. begin
  4706. current_commentstyle:=comment_oldtp;
  4707. inc_comment_level;
  4708. { only load a char if last already processed,
  4709. was cause of bug1634 PM }
  4710. if read_first_char then
  4711. readchar;
  4712. { this is now supported }
  4713. if (c='$') then
  4714. handledirectives;
  4715. { skip comment }
  4716. while (comment_level>0) do
  4717. begin
  4718. found:=0;
  4719. repeat
  4720. case c of
  4721. #26 :
  4722. begin
  4723. reload;
  4724. if (c=#26) and not assigned(inputfile.next) then
  4725. end_of_file;
  4726. continue;
  4727. end;
  4728. #10,#13 :
  4729. begin
  4730. if found=4 then
  4731. inc_comment_level;
  4732. linebreak;
  4733. found:=0;
  4734. end;
  4735. '*' :
  4736. begin
  4737. if found=3 then
  4738. found:=4
  4739. else
  4740. begin
  4741. if found=4 then
  4742. inc_comment_level;
  4743. found:=1;
  4744. end;
  4745. end;
  4746. ')' :
  4747. begin
  4748. if found in [1,4] then
  4749. begin
  4750. dec_comment_level;
  4751. if comment_level=0 then
  4752. found:=2
  4753. else
  4754. found:=0;
  4755. end
  4756. else
  4757. found:=0;
  4758. end;
  4759. '}' :
  4760. { in iso mode, comments opened by asterisk, round bracket can be closed by a curly bracket }
  4761. if m_iso in current_settings.modeswitches then
  4762. begin
  4763. dec_comment_level;
  4764. if comment_level=0 then
  4765. found:=2
  4766. else
  4767. found:=0;
  4768. end;
  4769. '(' :
  4770. begin
  4771. if found=4 then
  4772. inc_comment_level;
  4773. found:=3;
  4774. end;
  4775. else
  4776. begin
  4777. if found=4 then
  4778. inc_comment_level;
  4779. found:=0;
  4780. end;
  4781. end;
  4782. readchar;
  4783. until (found=2);
  4784. end;
  4785. current_commentstyle:=comment_none;
  4786. end;
  4787. {****************************************************************************
  4788. Token Scanner
  4789. ****************************************************************************}
  4790. procedure tscannerfile.readtoken(allowrecordtoken:boolean);
  4791. var
  4792. code : integer;
  4793. d : cardinal;
  4794. len,
  4795. low,high,mid : longint;
  4796. w : word;
  4797. m : longint;
  4798. mac : tmacro;
  4799. asciinr : string[33];
  4800. iswidestring , firstdigitread: boolean;
  4801. label
  4802. exit_label;
  4803. begin
  4804. flushpendingswitchesstate;
  4805. { record tokens? }
  4806. if allowrecordtoken and
  4807. assigned(recordtokenbuf) then
  4808. recordtoken;
  4809. { replay tokens? }
  4810. if assigned(replaytokenbuf) then
  4811. begin
  4812. replaytoken;
  4813. goto exit_label;
  4814. end;
  4815. { was there already a token read, then return that token }
  4816. if nexttoken<>NOTOKEN then
  4817. begin
  4818. setnexttoken;
  4819. goto exit_label;
  4820. end;
  4821. { Skip all spaces and comments }
  4822. repeat
  4823. case c of
  4824. '{' :
  4825. skipcomment(true);
  4826. #26 :
  4827. begin
  4828. reload;
  4829. if (c=#26) and not assigned(inputfile.next) then
  4830. break;
  4831. end;
  4832. ' ',#9..#13 :
  4833. begin
  4834. {$ifdef PREPROCWRITE}
  4835. if parapreprocess then
  4836. begin
  4837. if c=#10 then
  4838. preprocfile.eolfound:=true
  4839. else
  4840. preprocfile.spacefound:=true;
  4841. end;
  4842. {$endif PREPROCWRITE}
  4843. skipspace;
  4844. end
  4845. else
  4846. break;
  4847. end;
  4848. until false;
  4849. { Save current token position, for EOF its already loaded }
  4850. if c<>#26 then
  4851. gettokenpos;
  4852. { Check first for a identifier/keyword, this is 20+% faster (PFV) }
  4853. if c in ['A'..'Z','a'..'z','_'] then
  4854. begin
  4855. readstring;
  4856. token:=_ID;
  4857. idtoken:=_ID;
  4858. { keyword or any other known token,
  4859. pattern is always uppercased }
  4860. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  4861. begin
  4862. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  4863. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  4864. while low<high do
  4865. begin
  4866. mid:=(high+low+1) shr 1;
  4867. if pattern<tokeninfo^[ttoken(mid)].str then
  4868. high:=mid-1
  4869. else
  4870. low:=mid;
  4871. end;
  4872. with tokeninfo^[ttoken(high)] do
  4873. if pattern=str then
  4874. begin
  4875. if (keyword*current_settings.modeswitches)<>[] then
  4876. if op=NOTOKEN then
  4877. token:=ttoken(high)
  4878. else
  4879. token:=op;
  4880. idtoken:=ttoken(high);
  4881. end;
  4882. end;
  4883. { Only process identifiers and not keywords }
  4884. if token=_ID then
  4885. begin
  4886. { this takes some time ... }
  4887. if (cs_support_macro in current_settings.moduleswitches) then
  4888. begin
  4889. mac:=tmacro(search_macro(pattern));
  4890. if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
  4891. begin
  4892. if (yylexcount<max_macro_nesting) and (macro_nesting_depth<max_macro_nesting) then
  4893. begin
  4894. mac.is_used:=true;
  4895. inc(yylexcount);
  4896. substitutemacro(pattern,mac.buftext,mac.buflen,
  4897. mac.fileinfo.line,mac.fileinfo.fileindex,false);
  4898. { handle empty macros }
  4899. if c=#0 then
  4900. begin
  4901. reload;
  4902. { avoid macro nesting error in case of
  4903. a sequence of empty macros, see #38802 }
  4904. dec(yylexcount);
  4905. readtoken(false);
  4906. end
  4907. else
  4908. begin
  4909. readtoken(false);
  4910. { that's all folks }
  4911. dec(yylexcount);
  4912. end;
  4913. exit;
  4914. end
  4915. else
  4916. Message(scan_w_macro_too_deep);
  4917. end;
  4918. end;
  4919. end;
  4920. { return token }
  4921. goto exit_label;
  4922. end
  4923. else
  4924. begin
  4925. idtoken:=_NOID;
  4926. case c of
  4927. '$' :
  4928. begin
  4929. readnumber;
  4930. token:=_INTCONST;
  4931. goto exit_label;
  4932. end;
  4933. '%' :
  4934. begin
  4935. if [m_fpc,m_delphi] * current_settings.modeswitches = [] then
  4936. Illegal_Char(c)
  4937. else
  4938. begin
  4939. readnumber;
  4940. token:=_INTCONST;
  4941. goto exit_label;
  4942. end;
  4943. end;
  4944. '&' :
  4945. begin
  4946. if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then
  4947. begin
  4948. readnumber;
  4949. if length(pattern)=1 then
  4950. begin
  4951. { does really an identifier follow? }
  4952. if not (c in ['_','A'..'Z','a'..'z']) then
  4953. message2(scan_f_syn_expected,tokeninfo^[_ID].str,c);
  4954. readstring;
  4955. token:=_ID;
  4956. idtoken:=_ID;
  4957. end
  4958. else
  4959. token:=_INTCONST;
  4960. goto exit_label;
  4961. end
  4962. else if m_mac in current_settings.modeswitches then
  4963. begin
  4964. readchar;
  4965. token:=_AMPERSAND;
  4966. goto exit_label;
  4967. end
  4968. else
  4969. Illegal_Char(c);
  4970. end;
  4971. '0'..'9' :
  4972. begin
  4973. readnumber;
  4974. if (c in ['.','e','E']) then
  4975. begin
  4976. { first check for a . }
  4977. if c='.' then
  4978. begin
  4979. cachenexttokenpos;
  4980. readchar;
  4981. { is it a .. from a range? }
  4982. case c of
  4983. '.' :
  4984. begin
  4985. readchar;
  4986. token:=_INTCONST;
  4987. nexttoken:=_POINTPOINT;
  4988. goto exit_label;
  4989. end;
  4990. ')' :
  4991. begin
  4992. readchar;
  4993. token:=_INTCONST;
  4994. nexttoken:=_RECKKLAMMER;
  4995. goto exit_label;
  4996. end;
  4997. '0'..'9' :
  4998. begin
  4999. { insert the number after the . }
  5000. pattern:=pattern+'.';
  5001. firstdigitread:=false;
  5002. while (c in ['0'..'9']) or
  5003. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  5004. begin
  5005. if c<>'_' then
  5006. pattern:=pattern+c;
  5007. readchar;
  5008. firstdigitread:=true;
  5009. end;
  5010. end;
  5011. else
  5012. begin
  5013. token:=_INTCONST;
  5014. nexttoken:=_POINT;
  5015. goto exit_label;
  5016. end;
  5017. end;
  5018. end;
  5019. { E can also follow after a point is scanned }
  5020. if c in ['e','E'] then
  5021. begin
  5022. pattern:=pattern+'E';
  5023. readchar;
  5024. if c in ['-','+'] then
  5025. begin
  5026. pattern:=pattern+c;
  5027. readchar;
  5028. end;
  5029. if not(c in ['0'..'9']) then
  5030. Illegal_Char(c);
  5031. firstdigitread:=false;
  5032. while (c in ['0'..'9']) or
  5033. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  5034. begin
  5035. if c<>'_' then
  5036. pattern:=pattern+c;
  5037. readchar;
  5038. firstdigitread:=true;
  5039. end;
  5040. end;
  5041. token:=_REALNUMBER;
  5042. goto exit_label;
  5043. end;
  5044. token:=_INTCONST;
  5045. goto exit_label;
  5046. end;
  5047. ';' :
  5048. begin
  5049. readchar;
  5050. token:=_SEMICOLON;
  5051. goto exit_label;
  5052. end;
  5053. '[' :
  5054. begin
  5055. readchar;
  5056. token:=_LECKKLAMMER;
  5057. goto exit_label;
  5058. end;
  5059. ']' :
  5060. begin
  5061. readchar;
  5062. token:=_RECKKLAMMER;
  5063. goto exit_label;
  5064. end;
  5065. '(' :
  5066. begin
  5067. readchar;
  5068. case c of
  5069. '*' :
  5070. begin
  5071. skipoldtpcomment(true);
  5072. readtoken(false);
  5073. exit;
  5074. end;
  5075. '.' :
  5076. begin
  5077. readchar;
  5078. token:=_LECKKLAMMER;
  5079. goto exit_label;
  5080. end;
  5081. end;
  5082. token:=_LKLAMMER;
  5083. goto exit_label;
  5084. end;
  5085. ')' :
  5086. begin
  5087. readchar;
  5088. token:=_RKLAMMER;
  5089. goto exit_label;
  5090. end;
  5091. '+' :
  5092. begin
  5093. readchar;
  5094. if c='=' then
  5095. begin
  5096. readchar;
  5097. token:=_PLUSASN;
  5098. goto exit_label;
  5099. end;
  5100. token:=_PLUS;
  5101. goto exit_label;
  5102. end;
  5103. '-' :
  5104. begin
  5105. readchar;
  5106. if c='=' then
  5107. begin
  5108. readchar;
  5109. token:=_MINUSASN;
  5110. goto exit_label;
  5111. end;
  5112. token:=_MINUS;
  5113. goto exit_label;
  5114. end;
  5115. ':' :
  5116. begin
  5117. readchar;
  5118. if c='=' then
  5119. begin
  5120. readchar;
  5121. token:=_ASSIGNMENT;
  5122. goto exit_label;
  5123. end;
  5124. token:=_COLON;
  5125. goto exit_label;
  5126. end;
  5127. '*' :
  5128. begin
  5129. readchar;
  5130. if c='=' then
  5131. begin
  5132. readchar;
  5133. token:=_STARASN;
  5134. end
  5135. else
  5136. if c='*' then
  5137. begin
  5138. readchar;
  5139. token:=_STARSTAR;
  5140. end
  5141. else
  5142. token:=_STAR;
  5143. goto exit_label;
  5144. end;
  5145. '/' :
  5146. begin
  5147. readchar;
  5148. case c of
  5149. '=' :
  5150. begin
  5151. readchar;
  5152. token:=_SLASHASN;
  5153. goto exit_label;
  5154. end;
  5155. '/' :
  5156. begin
  5157. skipdelphicomment;
  5158. readtoken(false);
  5159. exit;
  5160. end;
  5161. end;
  5162. token:=_SLASH;
  5163. goto exit_label;
  5164. end;
  5165. '|' :
  5166. if m_mac in current_settings.modeswitches then
  5167. begin
  5168. readchar;
  5169. token:=_PIPE;
  5170. goto exit_label;
  5171. end
  5172. else
  5173. Illegal_Char(c);
  5174. '=' :
  5175. begin
  5176. readchar;
  5177. token:=_EQ;
  5178. goto exit_label;
  5179. end;
  5180. '.' :
  5181. begin
  5182. readchar;
  5183. case c of
  5184. '.' :
  5185. begin
  5186. readchar;
  5187. case c of
  5188. '.' :
  5189. begin
  5190. readchar;
  5191. token:=_POINTPOINTPOINT;
  5192. goto exit_label;
  5193. end;
  5194. else
  5195. begin
  5196. token:=_POINTPOINT;
  5197. goto exit_label;
  5198. end;
  5199. end;
  5200. end;
  5201. ')' :
  5202. begin
  5203. readchar;
  5204. token:=_RECKKLAMMER;
  5205. goto exit_label;
  5206. end;
  5207. end;
  5208. token:=_POINT;
  5209. goto exit_label;
  5210. end;
  5211. '@' :
  5212. begin
  5213. readchar;
  5214. token:=_KLAMMERAFFE;
  5215. goto exit_label;
  5216. end;
  5217. ',' :
  5218. begin
  5219. readchar;
  5220. token:=_COMMA;
  5221. goto exit_label;
  5222. end;
  5223. '''','#','^' :
  5224. begin
  5225. len:=0;
  5226. cstringpattern:='';
  5227. iswidestring:=false;
  5228. if c='^' then
  5229. begin
  5230. readchar;
  5231. c:=upcase(c);
  5232. if (block_type in [bt_type,bt_const_type,bt_var_type]) or
  5233. (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or
  5234. (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
  5235. begin
  5236. token:=_CARET;
  5237. goto exit_label;
  5238. end
  5239. else
  5240. begin
  5241. inc(len);
  5242. setlength(cstringpattern,256);
  5243. if c<#64 then
  5244. cstringpattern[len]:=chr(ord(c)+64)
  5245. else
  5246. cstringpattern[len]:=chr(ord(c)-64);
  5247. readchar;
  5248. end;
  5249. end;
  5250. repeat
  5251. case c of
  5252. '#' :
  5253. begin
  5254. readchar; { read # }
  5255. case c of
  5256. '$':
  5257. begin
  5258. readchar; { read leading $ }
  5259. asciinr:='$';
  5260. while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=7) do
  5261. begin
  5262. asciinr:=asciinr+c;
  5263. readchar;
  5264. end;
  5265. end;
  5266. '&':
  5267. begin
  5268. readchar; { read leading $ }
  5269. asciinr:='&';
  5270. while (upcase(c) in ['0'..'7']) and (length(asciinr)<=8) do
  5271. begin
  5272. asciinr:=asciinr+c;
  5273. readchar;
  5274. end;
  5275. end;
  5276. '%':
  5277. begin
  5278. readchar; { read leading $ }
  5279. asciinr:='%';
  5280. while (upcase(c) in ['0','1']) and (length(asciinr)<=22) do
  5281. begin
  5282. asciinr:=asciinr+c;
  5283. readchar;
  5284. end;
  5285. end;
  5286. else
  5287. begin
  5288. asciinr:='';
  5289. while (c in ['0'..'9']) and (length(asciinr)<=8) do
  5290. begin
  5291. asciinr:=asciinr+c;
  5292. readchar;
  5293. end;
  5294. end;
  5295. end;
  5296. val(asciinr,m,code);
  5297. if (asciinr='') or (code<>0) then
  5298. Message(scan_e_illegal_char_const)
  5299. else if (m<0) or (m>255) or (length(asciinr)>3) then
  5300. begin
  5301. if (m>=0) and (m<=$10FFFF) then
  5302. begin
  5303. if not iswidestring then
  5304. begin
  5305. if len>0 then
  5306. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  5307. else
  5308. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  5309. iswidestring:=true;
  5310. len:=0;
  5311. end;
  5312. if m<=$FFFF then
  5313. concatwidestringchar(patternw,tcompilerwidechar(m))
  5314. else
  5315. begin
  5316. { split into surrogate pair }
  5317. dec(m,$10000);
  5318. concatwidestringchar(patternw,tcompilerwidechar((m shr 10) + $D800));
  5319. concatwidestringchar(patternw,tcompilerwidechar((m and $3FF) + $DC00));
  5320. end;
  5321. end
  5322. else
  5323. Message(scan_e_illegal_char_const)
  5324. end
  5325. else if iswidestring then
  5326. concatwidestringchar(patternw,asciichar2unicode(char(m)))
  5327. else
  5328. begin
  5329. if len>=length(cstringpattern) then
  5330. setlength(cstringpattern,length(cstringpattern)+256);
  5331. inc(len);
  5332. cstringpattern[len]:=chr(m);
  5333. end;
  5334. end;
  5335. '''' :
  5336. begin
  5337. repeat
  5338. readchar;
  5339. case c of
  5340. #26 :
  5341. end_of_file;
  5342. #10,#13 :
  5343. Message(scan_f_string_exceeds_line);
  5344. '''' :
  5345. begin
  5346. readchar;
  5347. if c<>'''' then
  5348. break;
  5349. end;
  5350. end;
  5351. { interpret as utf-8 string? }
  5352. if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then
  5353. begin
  5354. { convert existing string to an utf-8 string }
  5355. if not iswidestring then
  5356. begin
  5357. if len>0 then
  5358. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  5359. else
  5360. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  5361. iswidestring:=true;
  5362. len:=0;
  5363. end;
  5364. { four chars }
  5365. if (ord(c) and $f0)=$f0 then
  5366. begin
  5367. { this always represents a surrogate pair, so
  5368. read as 32-bit value and then split into
  5369. the corresponding pair of two wchars }
  5370. d:=ord(c) and $f;
  5371. readchar;
  5372. if (ord(c) and $c0)<>$80 then
  5373. message(scan_e_utf8_malformed);
  5374. d:=(d shl 6) or (ord(c) and $3f);
  5375. readchar;
  5376. if (ord(c) and $c0)<>$80 then
  5377. message(scan_e_utf8_malformed);
  5378. d:=(d shl 6) or (ord(c) and $3f);
  5379. readchar;
  5380. if (ord(c) and $c0)<>$80 then
  5381. message(scan_e_utf8_malformed);
  5382. d:=(d shl 6) or (ord(c) and $3f);
  5383. if d<$10000 then
  5384. message(scan_e_utf8_malformed);
  5385. d:=d-$10000;
  5386. { high surrogate }
  5387. w:=$d800+(d shr 10);
  5388. concatwidestringchar(patternw,w);
  5389. { low surrogate }
  5390. w:=$dc00+(d and $3ff);
  5391. concatwidestringchar(patternw,w);
  5392. end
  5393. { three chars }
  5394. else if (ord(c) and $e0)=$e0 then
  5395. begin
  5396. w:=ord(c) and $f;
  5397. readchar;
  5398. if (ord(c) and $c0)<>$80 then
  5399. message(scan_e_utf8_malformed);
  5400. w:=(w shl 6) or (ord(c) and $3f);
  5401. readchar;
  5402. if (ord(c) and $c0)<>$80 then
  5403. message(scan_e_utf8_malformed);
  5404. w:=(w shl 6) or (ord(c) and $3f);
  5405. concatwidestringchar(patternw,w);
  5406. end
  5407. { two chars }
  5408. else if (ord(c) and $c0)<>0 then
  5409. begin
  5410. w:=ord(c) and $1f;
  5411. readchar;
  5412. if (ord(c) and $c0)<>$80 then
  5413. message(scan_e_utf8_malformed);
  5414. w:=(w shl 6) or (ord(c) and $3f);
  5415. concatwidestringchar(patternw,w);
  5416. end
  5417. { illegal }
  5418. else if (ord(c) and $80)<>0 then
  5419. message(scan_e_utf8_malformed)
  5420. else
  5421. concatwidestringchar(patternw,tcompilerwidechar(c))
  5422. end
  5423. else if iswidestring then
  5424. begin
  5425. if current_settings.sourcecodepage=CP_UTF8 then
  5426. concatwidestringchar(patternw,ord(c))
  5427. else
  5428. concatwidestringchar(patternw,asciichar2unicode(c))
  5429. end
  5430. else
  5431. begin
  5432. if len>=length(cstringpattern) then
  5433. setlength(cstringpattern,length(cstringpattern)+256);
  5434. inc(len);
  5435. cstringpattern[len]:=c;
  5436. end;
  5437. until false;
  5438. end;
  5439. '^' :
  5440. begin
  5441. readchar;
  5442. c:=upcase(c);
  5443. if c<#64 then
  5444. c:=chr(ord(c)+64)
  5445. else
  5446. c:=chr(ord(c)-64);
  5447. if iswidestring then
  5448. concatwidestringchar(patternw,asciichar2unicode(c))
  5449. else
  5450. begin
  5451. if len>=length(cstringpattern) then
  5452. setlength(cstringpattern,length(cstringpattern)+256);
  5453. inc(len);
  5454. cstringpattern[len]:=c;
  5455. end;
  5456. readchar;
  5457. end;
  5458. else
  5459. break;
  5460. end;
  5461. until false;
  5462. { strings with length 1 become const chars }
  5463. if iswidestring then
  5464. begin
  5465. if patternw^.len=1 then
  5466. token:=_CWCHAR
  5467. else
  5468. token:=_CWSTRING;
  5469. end
  5470. else
  5471. begin
  5472. setlength(cstringpattern,len);
  5473. if length(cstringpattern)=1 then
  5474. begin
  5475. token:=_CCHAR;
  5476. pattern:=cstringpattern;
  5477. end
  5478. else
  5479. token:=_CSTRING;
  5480. end;
  5481. goto exit_label;
  5482. end;
  5483. '>' :
  5484. begin
  5485. readchar;
  5486. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  5487. token:=_RSHARPBRACKET
  5488. else
  5489. begin
  5490. case c of
  5491. '=' :
  5492. begin
  5493. readchar;
  5494. token:=_GTE;
  5495. goto exit_label;
  5496. end;
  5497. '>' :
  5498. begin
  5499. readchar;
  5500. token:=_OP_SHR;
  5501. goto exit_label;
  5502. end;
  5503. '<' :
  5504. begin { >< is for a symetric diff for sets }
  5505. readchar;
  5506. token:=_SYMDIF;
  5507. goto exit_label;
  5508. end;
  5509. end;
  5510. token:=_GT;
  5511. end;
  5512. goto exit_label;
  5513. end;
  5514. '<' :
  5515. begin
  5516. readchar;
  5517. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  5518. token:=_LSHARPBRACKET
  5519. else
  5520. begin
  5521. case c of
  5522. '>' :
  5523. begin
  5524. readchar;
  5525. token:=_NE;
  5526. goto exit_label;
  5527. end;
  5528. '=' :
  5529. begin
  5530. readchar;
  5531. token:=_LTE;
  5532. goto exit_label;
  5533. end;
  5534. '<' :
  5535. begin
  5536. readchar;
  5537. token:=_OP_SHL;
  5538. goto exit_label;
  5539. end;
  5540. end;
  5541. token:=_LT;
  5542. end;
  5543. goto exit_label;
  5544. end;
  5545. #26 :
  5546. begin
  5547. token:=_EOF;
  5548. checkpreprocstack;
  5549. goto exit_label;
  5550. end;
  5551. else if inputfile.internally_generated_macro and
  5552. (c in [internal_macro_escape_begin..internal_macro_escape_end]) then
  5553. begin
  5554. token:=_ID;
  5555. readstring;
  5556. end
  5557. else
  5558. Illegal_Char(c);
  5559. end;
  5560. end;
  5561. exit_label:
  5562. lasttoken:=token;
  5563. end;
  5564. function tscannerfile.readpreproc:ttoken;
  5565. var
  5566. low,high,mid: longint;
  5567. optoken: ttoken;
  5568. begin
  5569. skipspace;
  5570. case c of
  5571. '_',
  5572. 'A'..'Z',
  5573. 'a'..'z' :
  5574. begin
  5575. readstring;
  5576. optoken:=_ID;
  5577. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  5578. begin
  5579. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  5580. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  5581. while low<high do
  5582. begin
  5583. mid:=(high+low+1) shr 1;
  5584. if pattern<tokeninfo^[ttoken(mid)].str then
  5585. high:=mid-1
  5586. else
  5587. low:=mid;
  5588. end;
  5589. with tokeninfo^[ttoken(high)] do
  5590. if pattern=str then
  5591. begin
  5592. if (keyword*current_settings.modeswitches)<>[] then
  5593. if op=NOTOKEN then
  5594. optoken:=ttoken(high)
  5595. else
  5596. optoken:=op;
  5597. end;
  5598. if not (optoken in preproc_operators) then
  5599. optoken:=_ID;
  5600. end;
  5601. current_scanner.preproc_pattern:=pattern;
  5602. readpreproc:=optoken;
  5603. end;
  5604. '''' :
  5605. begin
  5606. current_scanner.preproc_pattern:=readquotedstring;
  5607. readpreproc:=_CSTRING;
  5608. end;
  5609. '0'..'9' :
  5610. begin
  5611. readnumber;
  5612. if (c in ['.','e','E']) then
  5613. begin
  5614. { first check for a . }
  5615. if c='.' then
  5616. begin
  5617. readchar;
  5618. if c in ['0'..'9'] then
  5619. begin
  5620. { insert the number after the . }
  5621. pattern:=pattern+'.';
  5622. while c in ['0'..'9'] do
  5623. begin
  5624. pattern:=pattern+c;
  5625. readchar;
  5626. end;
  5627. end
  5628. else
  5629. Illegal_Char(c);
  5630. end;
  5631. { E can also follow after a point is scanned }
  5632. if c in ['e','E'] then
  5633. begin
  5634. pattern:=pattern+'E';
  5635. readchar;
  5636. if c in ['-','+'] then
  5637. begin
  5638. pattern:=pattern+c;
  5639. readchar;
  5640. end;
  5641. if not(c in ['0'..'9']) then
  5642. Illegal_Char(c);
  5643. while c in ['0'..'9'] do
  5644. begin
  5645. pattern:=pattern+c;
  5646. readchar;
  5647. end;
  5648. end;
  5649. readpreproc:=_REALNUMBER;
  5650. end
  5651. else
  5652. readpreproc:=_INTCONST;
  5653. current_scanner.preproc_pattern:=pattern;
  5654. end;
  5655. '$','%':
  5656. begin
  5657. readnumber;
  5658. current_scanner.preproc_pattern:=pattern;
  5659. readpreproc:=_INTCONST;
  5660. end;
  5661. '&' :
  5662. begin
  5663. readnumber;
  5664. if length(pattern)=1 then
  5665. begin
  5666. readstring;
  5667. readpreproc:=_ID;
  5668. end
  5669. else
  5670. readpreproc:=_INTCONST;
  5671. current_scanner.preproc_pattern:=pattern;
  5672. end;
  5673. '.' :
  5674. begin
  5675. readchar;
  5676. readpreproc:=_POINT;
  5677. end;
  5678. ',' :
  5679. begin
  5680. readchar;
  5681. readpreproc:=_COMMA;
  5682. end;
  5683. '}' :
  5684. begin
  5685. readpreproc:=_END;
  5686. end;
  5687. '(' :
  5688. begin
  5689. readchar;
  5690. readpreproc:=_LKLAMMER;
  5691. end;
  5692. ')' :
  5693. begin
  5694. readchar;
  5695. readpreproc:=_RKLAMMER;
  5696. end;
  5697. '[' :
  5698. begin
  5699. readchar;
  5700. readpreproc:=_LECKKLAMMER;
  5701. end;
  5702. ']' :
  5703. begin
  5704. readchar;
  5705. readpreproc:=_RECKKLAMMER;
  5706. end;
  5707. '+' :
  5708. begin
  5709. readchar;
  5710. readpreproc:=_PLUS;
  5711. end;
  5712. '-' :
  5713. begin
  5714. readchar;
  5715. readpreproc:=_MINUS;
  5716. end;
  5717. '*' :
  5718. begin
  5719. readchar;
  5720. readpreproc:=_STAR;
  5721. end;
  5722. '/' :
  5723. begin
  5724. readchar;
  5725. readpreproc:=_SLASH;
  5726. end;
  5727. '=' :
  5728. begin
  5729. readchar;
  5730. readpreproc:=_EQ;
  5731. end;
  5732. '>' :
  5733. begin
  5734. readchar;
  5735. if c='=' then
  5736. begin
  5737. readchar;
  5738. readpreproc:=_GTE;
  5739. end
  5740. else
  5741. readpreproc:=_GT;
  5742. end;
  5743. '<' :
  5744. begin
  5745. readchar;
  5746. case c of
  5747. '>' :
  5748. begin
  5749. readchar;
  5750. readpreproc:=_NE;
  5751. end;
  5752. '=' :
  5753. begin
  5754. readchar;
  5755. readpreproc:=_LTE;
  5756. end;
  5757. else
  5758. readpreproc:=_LT;
  5759. end;
  5760. end;
  5761. #26 :
  5762. begin
  5763. readpreproc:=_EOF;
  5764. checkpreprocstack;
  5765. end;
  5766. else
  5767. begin
  5768. Illegal_Char(c);
  5769. readpreproc:=NOTOKEN;
  5770. end;
  5771. end;
  5772. end;
  5773. function tscannerfile.readpreprocint(var value:int64;const place:string):boolean;
  5774. var
  5775. hs : texprvalue;
  5776. begin
  5777. hs:=preproc_comp_expr(nil);
  5778. if hs.isInt then
  5779. begin
  5780. value:=hs.asInt64;
  5781. result:=true;
  5782. end
  5783. else
  5784. begin
  5785. hs.error('Integer',place);
  5786. result:=false;
  5787. end;
  5788. hs.free;
  5789. end;
  5790. function tscannerfile.readpreprocset(conform_to:tsetdef;var value:tnormalset;const place:string):boolean;
  5791. var
  5792. hs : texprvalue;
  5793. begin
  5794. hs:=preproc_comp_expr(conform_to);
  5795. if hs.def.typ=setdef then
  5796. begin
  5797. value:=hs.asSet;
  5798. result:=true;
  5799. end
  5800. else
  5801. begin
  5802. hs.error('Set',place);
  5803. result:=false;
  5804. end;
  5805. hs.free;
  5806. end;
  5807. function tscannerfile.asmgetchar : char;
  5808. begin
  5809. readchar;
  5810. repeat
  5811. case c of
  5812. #26 :
  5813. begin
  5814. reload;
  5815. if (c=#26) and not assigned(inputfile.next) then
  5816. end_of_file;
  5817. continue;
  5818. end;
  5819. else
  5820. begin
  5821. asmgetchar:=c;
  5822. exit;
  5823. end;
  5824. end;
  5825. until false;
  5826. end;
  5827. {$ifdef EXTDEBUG}
  5828. function tscannerfile.DumpPointer: string;
  5829. var
  5830. i: Integer;
  5831. begin
  5832. Result:='';
  5833. if inputpointer=nil then exit;
  5834. i:=0;
  5835. While (inputpointer[I]<>#0) and (i<200) do
  5836. inc(i);
  5837. Setlength(result,I);
  5838. move(inputpointer^,Result[1],I);
  5839. result:='<'+inttostr(inputstart)+'>'+result;
  5840. end;
  5841. {$endif EXTDEBUG}
  5842. {*****************************************************************************
  5843. Helpers
  5844. *****************************************************************************}
  5845. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5846. begin
  5847. if dm in [directive_all, directive_turbo] then
  5848. tdirectiveitem.create(turbo_scannerdirectives,s,p);
  5849. if dm in [directive_all, directive_mac] then
  5850. tdirectiveitem.create(mac_scannerdirectives,s,p);
  5851. end;
  5852. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5853. begin
  5854. if dm in [directive_all, directive_turbo] then
  5855. tdirectiveitem.createcond(turbo_scannerdirectives,s,p);
  5856. if dm in [directive_all, directive_mac] then
  5857. tdirectiveitem.createcond(mac_scannerdirectives,s,p);
  5858. end;
  5859. {*****************************************************************************
  5860. Initialization
  5861. *****************************************************************************}
  5862. procedure InitScanner;
  5863. begin
  5864. InitWideString(patternw);
  5865. turbo_scannerdirectives:=TFPHashObjectList.Create;
  5866. mac_scannerdirectives:=TFPHashObjectList.Create;
  5867. { Common directives and conditionals }
  5868. AddDirective('I',directive_all, @dir_include);
  5869. AddDirective('DEFINE',directive_all, @dir_define);
  5870. AddDirective('UNDEF',directive_all, @dir_undef);
  5871. AddConditional('IF',directive_all, @dir_if);
  5872. AddConditional('IFDEF',directive_all, @dir_ifdef);
  5873. AddConditional('IFNDEF',directive_all, @dir_ifndef);
  5874. AddConditional('ELSE',directive_all, @dir_else);
  5875. AddConditional('ELSEIF',directive_all, @dir_elseif);
  5876. AddConditional('ENDIF',directive_all, @dir_endif);
  5877. { Directives and conditionals for all modes except mode macpas}
  5878. AddDirective('INCLUDE',directive_turbo, @dir_include);
  5879. AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
  5880. AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
  5881. AddDirective('EXTENSION',directive_turbo, @dir_extension);
  5882. AddConditional('IFEND',directive_turbo, @dir_ifend);
  5883. AddConditional('IFOPT',directive_turbo, @dir_ifopt);
  5884. { Directives and conditionals for mode macpas: }
  5885. AddDirective('SETC',directive_mac, @dir_setc);
  5886. AddDirective('DEFINEC',directive_mac, @dir_definec);
  5887. AddDirective('UNDEFC',directive_mac, @dir_undef);
  5888. AddConditional('IFC',directive_mac, @dir_if);
  5889. AddConditional('ELSEC',directive_mac, @dir_else);
  5890. AddConditional('ELIFC',directive_mac, @dir_elseif);
  5891. AddConditional('ENDC',directive_mac, @dir_endif);
  5892. end;
  5893. procedure DoneScanner;
  5894. begin
  5895. turbo_scannerdirectives.Free;
  5896. mac_scannerdirectives.Free;
  5897. DoneWideString(patternw);
  5898. end;
  5899. end.