| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005 | {    Copyright (c) 1998-2002 by Florian Klaempfl    This unit implements the scanner part and handling of the switches    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************}unit scanner;{$i fpcdefs.inc}interface    uses       cclasses,       globtype,globals,constexp,version,tokens,       symtype,symdef,symsym,       verbose,comphook,       finput,       widestr;    const       max_include_nesting=32;       max_macro_nesting=16;       preprocbufsize=32*1024;       { when parsing an internally generated macro, if an identifier is         prefixed with this constant then it will always be interpreted as a         unit name (to avoid clashes with user-specified parameter or field         names duplicated in internally generated code) }       internal_macro_escape_unit_namespace_name = #1;       internal_macro_escape_begin = internal_macro_escape_unit_namespace_name;       internal_macro_escape_end = internal_macro_escape_unit_namespace_name;    type       tcommentstyle = (comment_none,comment_tp,comment_oldtp,comment_delphi,comment_c);       tscannerfile = class;       preproctyp = (pp_ifdef,pp_ifndef,pp_if,pp_ifopt,pp_else,pp_elseif);       tpreprocstack = class          typ,          { stores the preproctyp of the last (else)if(ndef) directive            so we can check properly for ifend when legacyifend is on }          iftyp   : preproctyp;          accept  : boolean;          next    : tpreprocstack;          name    : TIDString;          line_nb : longint;          fileindex : longint;          constructor Create(atyp:preproctyp;a:boolean;n:tpreprocstack);       end;       tdirectiveproc=procedure;       tdirectiveitem = class(TFPHashObject)       public          is_conditional : boolean;          proc : tdirectiveproc;          constructor Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);          constructor CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);       end;       // stack for replay buffers       treplaystack = class         token    : ttoken;         idtoken  : ttoken;         orgpattern,         pattern  : string;         cstringpattern: ansistring;         patternw : tcompilerwidestring;         settings : tsettings;         tokenbuf : tdynamicarray;         tokenbuf_needs_swapping : boolean;         next     : treplaystack;         pending  : tpendingstate;         verbosity : longint;         constructor Create(atoken: ttoken;aidtoken:ttoken;           const aorgpattern,apattern:string;const acstringpattern:ansistring;           apatternw:tcompilerwidestring;asettings:tsettings;           atokenbuf:tdynamicarray;change_endian:boolean;const apending:tpendingstate;           averbosity:longint;anext:treplaystack);         destructor destroy;override;       end;       tcompile_time_predicate = function(var valuedescr: String) : Boolean;       tspecialgenerictoken =         (ST_LOADSETTINGS,          ST_LINE,          ST_COLUMN,          ST_FILEINDEX,          ST_LOADMESSAGES);       { tscannerfile }       tscannerfile = class       private         procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);         procedure cachenexttokenpos;         procedure postprocessmultiline(len, quote_pos, quote_count: integer);         procedure postprocessutf8multiline(len, quote_pos, quote_count: integer);         procedure setnexttoken;         procedure savetokenpos;         procedure restoretokenpos;         procedure writetoken(t: ttoken);         function readtoken : ttoken;       public          inputfile    : tinputfile;  { current inputfile list }          inputfilecount : longint;{$ifdef CHECK_INPUTPOINTER_LIMITS}       private          hidden_inputbuffer,                { input buffer }          hidden_inputpointer : pchar;          { Gets char at inputpointer with offset,            after checking that it doesn't overflow inputfile.bufsize }          function get_inputpointer_char(offset : longint = 0) : char;          procedure inc_inputpointer(amount : longint = 1);          procedure dec_inputpointer;       public{$else not CHECK_INPUTPOINTER_LIMITS}          inputbuffer,                { input buffer }          inputpointer : pchar;{$endif}          inputstart   : longint;          line_no,                    { line }          lastlinepos  : longint;          lasttokenpos,          nexttokenpos : longint;     { token }          lasttoken,          nexttoken    : ttoken;          oldlasttokenpos     : longint; { temporary saving/restoring tokenpos }          oldcurrent_filepos,          oldcurrent_tokenpos : tfileposinfo;          replaytokenbuf,          recordtokenbuf : tdynamicarray;          { last settings we stored }          last_settings : tsettings;          last_message : pmessagestaterecord;          { last filepos we stored }          last_filepos,          { if nexttoken<>NOTOKEN, then nexttokenpos holds its filepos }          next_filepos   : tfileposinfo;          { current macro nesting depth }          macro_nesting_depth,          comment_level,          yylexcount     : longint;          ignoredirectives : TFPHashList; { ignore directives, used to give warnings only once }          preprocstack   : tpreprocstack;          replaystack    : treplaystack;          preproc_pattern : string;          preproc_token   : ttoken;          { true, if we are parsing preprocessor expressions }          in_preproc_comp_expr : boolean;          { true if tokens must be converted to opposite endianess}          change_endian_for_replay : boolean;          { hack to allow reading generic generated identifiers IDs}          allowgenericid : boolean;          { Having these tracked in the scanner class itself versus local variables allows for            informative error handling that would be impossible otherwise }          in_multiline_string, had_multiline_string : boolean;          multiline_start_line : longint;          multiline_start_column : word;          constructor Create(const fn:string; is_macro: boolean = false);          destructor Destroy;override;        { File buffer things }          function  openinputfile:boolean;          procedure closeinputfile;          function  tempopeninputfile:boolean;          procedure tempcloseinputfile;          procedure saveinputfile;          procedure restoreinputfile;          procedure firstfile;          procedure nextfile;          procedure addfile(hp:tinputfile);          procedure reload;          { replaces current token with the text in p }          procedure substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);        { Scanner things }          procedure gettokenpos;          procedure inc_comment_level;          procedure dec_comment_level;          procedure illegal_char(c:char);          procedure end_of_file;          procedure checkpreprocstack;          procedure poppreprocstack;          procedure ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);          procedure elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);          procedure elsepreprocstack;          procedure popreplaystack;          function replay_stack_depth:longint;          procedure handleconditional(p:tdirectiveitem);          procedure handledirectives;          procedure linebreak;          procedure recordtoken;          procedure startrecordtokens(buf:tdynamicarray);          procedure stoprecordtokens;          function is_recording_tokens:boolean;          procedure replaytoken;          procedure startreplaytokens(buf:tdynamicarray; change_endian:boolean);          { bit length asizeint is target depend }          procedure tokenwritesizeint(val : asizeint);          procedure tokenwritelongint(val : longint);          procedure tokenwritelongword(val : longword);          procedure tokenwritebyte(val : byte);          procedure tokenwriteword(val : word);          procedure tokenwriteshortint(val : shortint);          procedure tokenwriteset(var b;size : longint);          procedure tokenwriteenum(var b;size : longint);          function  tokenreadsizeint : asizeint;          procedure tokenwritesettings(var asettings : tsettings; var size : asizeint);          { longword/longint are 32 bits on all targets }          { word/smallint are 16-bits on all targest }          function  tokenreadlongword : longword;          function  tokenreadword : word;          function  tokenreadlongint : longint;          function  tokenreadsmallint : smallint;          { short int is one a signed byte }          function  tokenreadshortint : shortint;          function  tokenreadbyte : byte;          { This one takes the set size as an parameter }          procedure tokenreadset(var b;size : longint);          function  tokenreadenum(size : longint) : longword;          procedure tokenreadsettings(var asettings : tsettings; expected_size : asizeint);          procedure readchar;          procedure readstring;          procedure readnumber;          function  readid:string;          function  readval:longint;          function  readval64:int64;          function  readcomment(include_special_char: boolean = false):string;          function  readquotedstring:string;          function  readlongcomment(include_special_char: boolean = false):RawByteString;          function  readlongquotedstring:RawByteString;          function readstringconstant: boolean;          function  readstate:char;          function  readoptionalstate(fallback:char):char;          function  readstatedefault:char;          procedure skipspace;          procedure skipuntildirective;          procedure skipcomment(read_first_char:boolean);          procedure skipdelphicomment;          procedure skipoldtpcomment(read_first_char:boolean);          procedure readtoken(allowrecordtoken:boolean);          function  readpreproc:ttoken;          function  readpreprocint(var value:int64;const place:string):boolean;          function  readpreprocset(conform_to:tsetdef;var value:tnormalset;const place:string):boolean;          function  asmgetchar:char;{$ifdef EXTDEBUG}          function DumpPointer : string;{$endif EXTDEBUG}       end;{$ifdef PREPROCWRITE}       tpreprocfile=class         f   : text;         buf : TByteDynArray;         spacefound,         eolfound : boolean;         constructor create(const fn:string);         destructor  destroy; override;         procedure Add(const s:string);         procedure AddSpace;       end;{$endif PREPROCWRITE}    var        { read strings }        c              : char;        orgpattern,        pattern        : string;        cstringpattern : ansistring;        patternw       : tcompilerwidestring;        { token }        token,                        { current token being parsed }        idtoken    : ttoken;          { holds the token if the pattern is a known word }        current_commentstyle : tcommentstyle; { needed to use read_comment from directives }{$ifdef PREPROCWRITE}        preprocfile     : tpreprocfile;  { used with only preprocessing }{$endif PREPROCWRITE}    type        tdirectivemode = (directive_all, directive_turbo, directive_mac);    procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);    procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);    procedure InitScanner;    procedure DoneScanner;    function current_scanner : tscannerfile;  { current scanner in use }    procedure set_current_scanner(avalue : tscannerfile);  { current scanner in use }    { To be called when the language mode is finally determined }    Function SetCompileMode(const s:string; changeInit: boolean):boolean;    Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;    procedure SetAppType(NewAppType:tapptype);    var      onfreescanner : procedure(s : tscannerfile) = nil;implementation    uses      SysUtils,      cutils,cfileutl,      systems,      switches,      symbase,symtable,symconst,defutil,defcmp,node,      { This is needed for tcputype }      cpuinfo,      fmodule,fppu,      { this is needed for $I %CURRENTROUTINE%}      procinfo;    var      { dictionaries with the supported directives }      turbo_scannerdirectives : TFPHashObjectList;     { for other modes }      mac_scannerdirectives   : TFPHashObjectList;     { for mode mac }      {        By default the current_scanner is current_module.scanner.        set_current_scanner sets the _temp_scanner variable.        If _temp_scanner is set, it is returned as the current scanner      }      _temp_scanner : tscannerfile;      function current_scanner : tscannerfile;  { current scanner in use }      begin        Result:=_temp_scanner;        if result<>nil then          exit;        if assigned(current_module) then          Result:=Tscannerfile(current_module.scanner)        else          Result:=Nil;      end;{*****************************************************************************                              Helper routines*****************************************************************************}    const      { use any special name that is an invalid file name to avoid problems }      preprocstring : array [preproctyp] of string[7]        = ('$IFDEF','$IFNDEF','$IF','$IFOPT','$ELSE','$ELSEIF');    function is_keyword(const s:string):boolean;      var        low,high,mid : longint;      begin        if not (length(s) in [tokenlenmin..tokenlenmax]) or           not (s[1] in ['a'..'z','A'..'Z']) then         begin           is_keyword:=false;           exit;         end;        low:=ord(tokenidx^[length(s),s[1]].first);        high:=ord(tokenidx^[length(s),s[1]].last);        while low<high do         begin           mid:=(high+low+1) shr 1;           if pattern<tokeninfo^[ttoken(mid)].str then            high:=mid-1           else            low:=mid;         end;        is_keyword:=(pattern=tokeninfo^[ttoken(high)].str) and                    ((tokeninfo^[ttoken(high)].keyword*current_settings.modeswitches)<>[]);      end;    Procedure HandleModeSwitches(switch: tmodeswitch; changeInit: boolean);      begin        { turn ansi/unicodestrings on by default ? (only change when this          particular setting is changed, so that a random modeswitch won't          change the state of $h+/$h-) }        if switch in [m_none,m_default_ansistring,m_default_unicodestring] then          begin            if ([m_default_ansistring,m_default_unicodestring]*current_settings.modeswitches)<>[] then              begin                { can't have both ansistring and unicodestring as default }                if switch=m_default_ansistring then                  begin                    exclude(current_settings.modeswitches,m_default_unicodestring);                    if changeinit then                      exclude(init_settings.modeswitches,m_default_unicodestring);                  end                else if switch=m_default_unicodestring then                  begin                    exclude(current_settings.modeswitches,m_default_ansistring);                    if changeinit then                      exclude(init_settings.modeswitches,m_default_ansistring);                  end;                { enable $h+ }                include(current_settings.localswitches,cs_refcountedstrings);                if changeinit then                  include(init_settings.localswitches,cs_refcountedstrings);                if m_default_unicodestring in current_settings.modeswitches then                  begin                    def_system_macro('FPC_UNICODESTRINGS');                    def_system_macro('UNICODE');                  end;              end            else              begin                exclude(current_settings.localswitches,cs_refcountedstrings);                if changeinit then                  exclude(init_settings.localswitches,cs_refcountedstrings);                undef_system_macro('FPC_UNICODESTRINGS');                undef_system_macro('UNICODE');              end;          end;        { turn inline on by default ? }        if switch in [m_none,m_default_inline] then          begin            if (m_default_inline in current_settings.modeswitches) then             begin               include(current_settings.localswitches,cs_do_inline);               if changeinit then                 include(init_settings.localswitches,cs_do_inline);             end            else             begin               exclude(current_settings.localswitches,cs_do_inline);               if changeinit then                 exclude(init_settings.localswitches,cs_do_inline);             end;          end;        { turn on system codepage by default }        if switch in [m_none,m_systemcodepage] then          begin            { both m_systemcodepage and specifying a code page via -FcXXX or              "$codepage XXX" change current_settings.sourcecodepage. If              we used -FcXXX and then have a sourcefile with "$mode objfpc",              this routine will be called to disable m_systemcodepage (to ensure              it's off in case it would have been set on the command line, or              by a previous mode(switch).              In that case, we have to ensure that we don't overwrite              current_settings.sourcecodepage, as that would cancel out the              -FcXXX. This is why we use two separate module switches              (cs_explicit_codepage and cs_system_codepage) for the same setting              (current_settings.sourcecodepage)            }            if m_systemcodepage in current_settings.modeswitches then              begin                { m_systemcodepage gets enabled -> disable any -FcXXX and                  "codepage XXX" settings (exclude cs_explicit_codepage), and                  overwrite the sourcecode page }                current_settings.sourcecodepage:=DefaultSystemCodePage;                if (current_settings.sourcecodepage<>CP_UTF8) and not cpavailable(current_settings.sourcecodepage) then                  begin                    Message2(scan_w_unavailable_system_codepage,IntToStr(current_settings.sourcecodepage),IntToStr(default_settings.sourcecodepage));                    current_settings.sourcecodepage:=default_settings.sourcecodepage;                  end;                exclude(current_settings.moduleswitches,cs_explicit_codepage);                include(current_settings.moduleswitches,cs_system_codepage);                if changeinit then                  begin                    init_settings.sourcecodepage:=current_settings.sourcecodepage;                    exclude(init_settings.moduleswitches,cs_explicit_codepage);                    include(init_settings.moduleswitches,cs_system_codepage);                  end;              end            else              begin                { m_systemcodepage gets disabled -> reset sourcecodepage only if                  cs_explicit_codepage is not set (it may be set in the scenario                  where -FcXXX was passed on the command line and then "$mode                  fpc" is used, because then the caller of this routine will                  set the "$mode fpc" modeswitches (which don't include                  m_systemcodepage) and call this routine with m_none).                  Or it can happen if -FcXXX was passed, and the sourcefile                  contains "$modeswitch systemcodepage-" statement.                  Since we unset cs_system_codepage if m_systemcodepage gets                  activated, we will revert to the default code page if you                  set a source file code page, then enable the systemcode page                  and finally disable it again. We don't keep a stack of                  settings, by design. The only thing we have to ensure is that                  disabling m_systemcodepage if it wasn't on in the first place                  doesn't overwrite the sourcecodepage }                exclude(current_settings.moduleswitches,cs_system_codepage);                if not(cs_explicit_codepage in current_settings.moduleswitches) then                  current_settings.sourcecodepage:=default_settings.sourcecodepage;                if changeinit then                  begin                    exclude(init_settings.moduleswitches,cs_system_codepage);                    if not(cs_explicit_codepage in init_settings.moduleswitches) then                      init_settings.sourcecodepage:=default_settings.sourcecodepage;                  end;              end;          end;{$ifdef i8086}        { enable cs_force_far_calls when m_nested_procvars is enabled }        if switch=m_nested_procvars then          begin            include(current_settings.localswitches,cs_force_far_calls);            if changeinit then              include(init_settings.localswitches,cs_force_far_calls);          end;{$endif i8086}      end;    procedure set_current_scanner(avalue: tscannerfile);    begin      _temp_scanner:=avalue;    end;    Function SetCompileMode(const s:string; changeInit: boolean):boolean;      var        b : boolean;        oldmodeswitches : tmodeswitches;      begin        oldmodeswitches:=current_settings.modeswitches;        b:=true;        if s='DEFAULT' then          current_settings.modeswitches:=fpcmodeswitches        else         if s='DELPHI' then          current_settings.modeswitches:=delphimodeswitches        else         if s='DELPHIUNICODE' then          current_settings.modeswitches:=delphiunicodemodeswitches        else         if s='TP' then          current_settings.modeswitches:=tpmodeswitches        else         if s='FPC' then begin          current_settings.modeswitches:=fpcmodeswitches;          { TODO: enable this for 2.3/2.9 }          //  include(current_settings.localswitches, cs_typed_addresses);        end else         if s='OBJFPC' then begin          current_settings.modeswitches:=objfpcmodeswitches;          { TODO: enable this for 2.3/2.9 }          //  include(current_settings.localswitches, cs_typed_addresses);        end{$ifdef gpc_mode}        else if s='GPC' then          current_settings.modeswitches:=gpcmodeswitches{$endif}        else         if s='MACPAS' then          current_settings.modeswitches:=macmodeswitches        else         if s='ISO' then          current_settings.modeswitches:=isomodeswitches        else         if s='EXTENDEDPASCAL' then          current_settings.modeswitches:=extpasmodeswitches        else         b:=false;{$ifdef jvm}          { enable final fields by default for the JVM targets }          include(current_settings.modeswitches,m_final_fields);{$endif jvm}        if b and changeInit then          init_settings.modeswitches := current_settings.modeswitches;        if b then         begin           { resolve all postponed switch changes }           flushpendingswitchesstate;           HandleModeSwitches(m_none,changeinit);           { turn on bitpacking and case checking for mode macpas and iso pascal,             as well as extended pascal }           if ([m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then             begin               include(current_settings.localswitches,cs_bitpacking);               include(current_settings.localswitches,cs_check_all_case_coverage);               if changeinit then                 begin                   include(init_settings.localswitches,cs_bitpacking);                   include(init_settings.localswitches,cs_check_all_case_coverage);                 end;             end;           { support goto/label by default in delphi/tp7/mac/iso/extpas modes }           if ([m_delphi,m_tp7,m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then             begin               include(current_settings.moduleswitches,cs_support_goto);               if changeinit then                 include(init_settings.moduleswitches,cs_support_goto);             end;           { support pointer math by default in fpc/objfpc modes }           if ([m_fpc,m_objfpc] * current_settings.modeswitches <> []) then             begin               include(current_settings.localswitches,cs_pointermath);               if changeinit then                 include(init_settings.localswitches,cs_pointermath);             end           else             begin               exclude(current_settings.localswitches,cs_pointermath);               if changeinit then                 exclude(init_settings.localswitches,cs_pointermath);             end;           { Default enum and set packing for delphi/tp7 }           if (m_tp7 in current_settings.modeswitches) or              (m_delphi in current_settings.modeswitches) then             begin               current_settings.packenum:=1;               current_settings.setalloc:=1;             end           else if (m_mac in current_settings.modeswitches) then             begin               { compatible with Metrowerks Pascal }               current_settings.packenum:=2;               current_settings.setalloc:=default_settings.setalloc;             end           else             begin               current_settings.packenum:=default_settings.packenum;               current_settings.setalloc:=default_settings.setalloc;             end;           if changeinit then             begin               init_settings.packenum:=current_settings.packenum;               init_settings.setalloc:=current_settings.setalloc;             end;{$if defined(i386) or defined(i8086)}           { Default to intel assembler for delphi/tp7 on i386/i8086 }           if (m_delphi in current_settings.modeswitches) or              (m_tp7 in current_settings.modeswitches) then             begin{$ifdef i8086}               current_settings.asmmode:=asmmode_i8086_intel;{$else i8086}               current_settings.asmmode:=asmmode_i386_intel;{$endif i8086}               if changeinit then                 init_settings.asmmode:=current_settings.asmmode;             end;{$endif i386 or i8086}           { Exception support explicitly turned on (mainly for macpas, to }           { compensate for lack of interprocedural goto support)          }           if (cs_support_exceptions in current_settings.globalswitches) then             include(current_settings.modeswitches,m_except);           { Default strict string var checking in TP/Delphi modes }           if ([m_delphi,m_tp7] * current_settings.modeswitches <> []) then             begin               include(current_settings.localswitches,cs_strict_var_strings);               if changeinit then                 include(init_settings.localswitches,cs_strict_var_strings);             end;           { in delphi mode, excess precision and open strings are by default on }           if ([m_delphi] * current_settings.modeswitches <> []) then             begin               include(current_settings.localswitches,cs_excessprecision);               include(current_settings.localswitches,cs_openstring);               if changeinit then                 begin                   include(init_settings.localswitches,cs_excessprecision);                   include(init_settings.localswitches,cs_openstring);                 end;             end;{$ifdef i8086}           { Do not force far calls in the TP mode by default, force it in other modes }           if (m_tp7 in current_settings.modeswitches) then             begin               exclude(current_settings.localswitches,cs_force_far_calls);               if changeinit then                 exclude(init_settings.localswitches,cs_force_far_calls);             end           else             begin               include(current_settings.localswitches,cs_force_far_calls);               if changeinit then                 include(init_settings.localswitches,cs_force_far_calls);             end;{$endif i8086}            { Undefine old symbol }            if (m_delphi in oldmodeswitches) then              undef_system_macro('FPC_DELPHI')            else if (m_tp7 in oldmodeswitches) then              undef_system_macro('FPC_TP')            else if (m_objfpc in oldmodeswitches) then              undef_system_macro('FPC_OBJFPC'){$ifdef gpc_mode}            else if (m_gpc in oldmodeswitches) then              undef_system_macro('FPC_GPC'){$endif}            else if (m_mac in oldmodeswitches) then              undef_system_macro('FPC_MACPAS')            else if (m_iso in oldmodeswitches) then              undef_system_macro('FPC_ISO')            else if (m_extpas in oldmodeswitches) then              undef_system_macro('FPC_EXTENDEDPASCAL');            { define new symbol in delphi,objfpc,tp,gpc,macpas mode }            if (m_delphi in current_settings.modeswitches) then              def_system_macro('FPC_DELPHI')            else if (m_tp7 in current_settings.modeswitches) then              def_system_macro('FPC_TP')            else if (m_objfpc in current_settings.modeswitches) then              def_system_macro('FPC_OBJFPC'){$ifdef gpc_mode}            else if (m_gpc in current_settings.modeswitches) then              def_system_macro('FPC_GPC'){$endif}            else if (m_mac in current_settings.modeswitches) then              def_system_macro('FPC_MACPAS')            else if (m_iso in current_settings.modeswitches) then              def_system_macro('FPC_ISO')            else if (m_extpas in current_settings.modeswitches) then              def_system_macro('FPC_EXTENDEDPASCAL');         end;        SetCompileMode:=b;      end;    Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;      var        i : tmodeswitch;        doinclude : boolean;      begin        s:=upper(s);        { on/off? }        doinclude:=true;        case s[length(s)] of          '+':            setlength(s,length(s)-1);          '-':            begin              setlength(s,length(s)-1);              doinclude:=false;            end;        end;        Result:=false;        for i:=m_class to high(tmodeswitch) do          if s=modeswitchstr[i] then            begin              { Objective-C is currently only supported for Darwin targets }              if doinclude and                 (i in [m_objectivec1,m_objectivec2]) and                 not(target_info.system in systems_objc_supported) then                begin                  Message1(option_unsupported_target_for_feature,'Objective-C');                  break;                end;              { Blocks supported? }              if doinclude and                 (i = m_blocks) and                 not(target_info.system in systems_blocks_supported) then                begin                  Message1(option_unsupported_target_for_feature,'Blocks');                  break;                end;              if changeInit then                current_settings.modeswitches:=init_settings.modeswitches;              Result:=true;              if doinclude then                begin                  include(current_settings.modeswitches,i);                  { Objective-C 2.0 support implies 1.0 support }                  if (i=m_objectivec2) then                    include(current_settings.modeswitches,m_objectivec1);                  if (i in [m_objectivec1,m_objectivec2]) then                    include(current_settings.modeswitches,m_class);                end              else                begin                  exclude(current_settings.modeswitches,i);                  { Objective-C 2.0 support implies 1.0 support }                  if (i=m_objectivec2) then                    exclude(current_settings.modeswitches,m_objectivec1);                  if (i in [m_objectivec1,m_objectivec2]) and                     ([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then                    exclude(current_settings.modeswitches,m_class);                end;              { set other switches depending on changed mode switch }              HandleModeSwitches(i,changeinit);              if changeInit then                init_settings.modeswitches:=current_settings.modeswitches;              break;            end;      end;    procedure SetAppType(NewAppType:tapptype);      begin{$ifdef i8086}        if (target_info.system in [system_i8086_msdos,system_i8086_embedded]) and (apptype<>NewAppType) then          begin            if NewAppType=app_com then              begin                targetinfos[target_info.system]^.exeext:='.com';                target_info.exeext:='.com';              end            else              begin                targetinfos[target_info.system]^.exeext:='.exe';                target_info.exeext:='.exe';              end;          end;{$endif i8086}{$ifdef m68k}        if target_info.system in [system_m68k_atari] then          case NewAppType of            app_cui:              begin                targetinfos[target_info.system]^.exeext:='.ttp';                target_info.exeext:='.ttp';              end;            app_gui:              begin                targetinfos[target_info.system]^.exeext:='.prg';                target_info.exeext:='.prg';              end;            else              ;          end;{$endif m68k}        if apptype in [app_cui,app_com] then          undef_system_macro('CONSOLE');        apptype:=NewAppType;        if apptype in [app_cui,app_com] then          def_system_macro('CONSOLE');      end;{*****************************************************************************                           Conditional Directives*****************************************************************************}    procedure dir_else;      begin        current_scanner.elsepreprocstack;      end;    procedure dir_endif;      begin        if (cs_legacyifend in current_settings.localswitches) and          (current_scanner.preprocstack.typ<>pp_ifdef) and (current_scanner.preprocstack.typ<>pp_ifndef) and            not((current_scanner.preprocstack.typ=pp_else) and (current_scanner.preprocstack.iftyp in [pp_ifdef,pp_ifndef])) then          Message(scan_e_unexpected_endif);        current_scanner.poppreprocstack;      end;    procedure dir_ifend;      begin        if (cs_legacyifend in current_settings.localswitches) and          (current_scanner.preprocstack.typ<>pp_elseif) and (current_scanner.preprocstack.typ<>pp_if) and            not((current_scanner.preprocstack.typ=pp_else) and (current_scanner.preprocstack.iftyp in [pp_if,pp_elseif])) then          Message(scan_e_unexpected_ifend);        current_scanner.poppreprocstack;      end;    function isdef(var valuedescr: String): Boolean;      var        hs    : string;      begin        current_scanner.skipspace;        hs:=current_scanner.readid;        valuedescr:= hs;        if hs='' then          Message(scan_e_error_in_preproc_expr);        isdef:=defined_macro(hs);      end;    procedure dir_ifdef;      begin        current_scanner.ifpreprocstack(pp_ifdef,@isdef,scan_c_ifdef_found);      end;    function isnotdef(var valuedescr: String): Boolean;      var        hs    : string;      begin        current_scanner.skipspace;        hs:=current_scanner.readid;        valuedescr:= hs;        if hs='' then          Message(scan_e_error_in_preproc_expr);        isnotdef:=not defined_macro(hs);      end;    procedure dir_ifndef;      begin        current_scanner.ifpreprocstack(pp_ifndef,@isnotdef,scan_c_ifndef_found);      end;    function opt_check(var valuedescr: String): Boolean;      var        hs    : string;        state : char;      begin        opt_check:= false;        current_scanner.skipspace;        hs:=current_scanner.readid;        valuedescr:= hs;        if (length(hs)>1) then          Message1(scan_w_illegal_switch,hs)        else          begin            state:=current_scanner.ReadState;            if state in ['-','+'] then              opt_check:=CheckSwitch(hs[1],state)            else              Message(scan_e_error_in_preproc_expr);          end;      end;    procedure dir_ifopt;      begin        flushpendingswitchesstate;        current_scanner.ifpreprocstack(pp_ifopt,@opt_check,scan_c_ifopt_found);      end;    procedure dir_libprefix;      var        s : string;      begin        current_scanner.skipspace;        if c <> '''' then          Message2(scan_f_syn_expected, '''', c);        s := current_scanner.readquotedstring;        stringdispose(outputprefix);        outputprefix := stringdup(s);        with current_module do         setfilename(paramfn, paramallowoutput);      end;    procedure dir_libsuffix;      var        s : string;      begin        current_scanner.skipspace;        if c <> '''' then          Message2(scan_f_syn_expected, '''', c);        s := current_scanner.readquotedstring;        stringdispose(outputsuffix);        outputsuffix := stringdup(s);        with current_module do          setfilename(paramfn, paramallowoutput);      end;    procedure dir_extension;      var        s : string;      begin        current_scanner.skipspace;        if c <> '''' then          Message2(scan_f_syn_expected, '''', c);        s := current_scanner.readquotedstring;        if OutputFileName='' then          OutputFileName:=InputFileName;        OutputFileName:=ChangeFileExt(OutputFileName,'.'+s);        with current_module do          setfilename(paramfn, paramallowoutput);      end;{Compile time expression type check----------------------------------Each subexpression returns its type to the caller, which then cando type check.  Since data types of compile time expressions isnot well defined, the type system does a best effort. The drawback isthat some errors might not be detected.Instead of returning a particular data type, a set of possible data typesare returned. This way ambigouos types can be handled.  For instance avalue of 1 can be both a boolean and and integer.Booleans--------The following forms of boolean values are supported:* C coded, that is 0 is false, non-zero is true.* TRUE/FALSE for mac style compile time variablesThus boolean mac compile time variables are always stored as TRUE/FALSE.When a compile time expression is evaluated, they are then translatedto C coded booleans (0/1), to simplify for the expression evaluator.Note that this scheme then also of support mac compile time variables whichare 0/1 but with a boolean meaning.The TRUE/FALSE format is new from 22 august 2005, but the above schememeans that units which is not recompiled, and thus storescompile time variables as the old format (0/1), continue to work.Short circuit evaluation------------------------For this to work, the part of a compile time expression which is shortcircuited, should not be evaluated, while it still should be parsed.Therefor there is a parameter eval, telling whether evaluation is needed.In case not, the value returned can be arbitrary.}type  { texprvalue }  texprvalue = class  private    { we can't use built-in defs since they      may be not created at the moment }    class var       sintdef,uintdef,booldef,strdef,setdef,realdef: tdef;    class constructor createdefs;    class destructor destroydefs;  public    consttyp: tconsttyp;    value: tconstvalue;    def: tdef;    constructor create_const(c:tconstsym);    constructor create_error;    constructor create_ord(v: Tconstexprint);    constructor create_int(v: int64);    constructor create_uint(v: qword);    constructor create_bool(b: boolean);    constructor create_str(const s: string);    constructor create_set(ns: tnormalset);    constructor create_real(r: bestreal);    class function try_parse_number(const s:string):texprvalue; static;    class function try_parse_real(const s:string):texprvalue; static;    function evaluate(v:texprvalue;op:ttoken):texprvalue;    procedure error(expecteddef, place: string);    function isBoolean: Boolean;    function isInt: Boolean;    function asBool: Boolean;    function asInt: Integer;    function asInt64: Int64;    function asStr: String;    function asSet: tnormalset;    destructor destroy; override;  end;  class constructor texprvalue.createdefs;    begin      { do not use corddef etc here: this code is executed before those        variables are initialised. Since these types are only used for        compile-time evaluation of conditional expressions, it doesn't matter        that we use the base types instead of the cpu-specific ones. }      sintdef:=torddef.create(s64bit,low(int64),high(int64),false);      uintdef:=torddef.create(u64bit,low(qword),high(qword),false);      booldef:=torddef.create(pasbool1,0,1,false);      strdef:=tstringdef.createansi(0,false);      setdef:=tsetdef.create(sintdef,0,255,false);      realdef:=tfloatdef.create(s80real,false);    end;  class destructor texprvalue.destroydefs;    begin      setdef.free;      sintdef.free;      uintdef.free;      booldef.free;      strdef.free;      realdef.free;    end;  constructor texprvalue.create_const(c: tconstsym);    begin      consttyp:=c.consttyp;      def:=c.constdef;      case consttyp of        conststring,        constresourcestring:          begin            value.len:=c.value.len;            getmem(value.valueptr,value.len+1);            move(c.value.valueptr^,value.valueptr^,value.len+1);          end;        constwstring,        constwresourcestring:          begin            initwidestring(value.valuews);            copywidestring(c.value.valuews,value.valuews);          end;        constreal:          begin            new(pbestreal(value.valueptr));            pbestreal(value.valueptr)^:=pbestreal(c.value.valueptr)^;          end;        constset:          begin            new(pnormalset(value.valueptr));            pnormalset(value.valueptr)^:=pnormalset(c.value.valueptr)^;          end;        constguid:          begin            new(pguid(value.valueptr));            pguid(value.valueptr)^:=pguid(c.value.valueptr)^;          end;        else          value:=c.value;      end;    end;  constructor texprvalue.create_error;    begin      fillchar(value,sizeof(value),#0);      consttyp:=constnone;      def:=generrordef;    end;  constructor texprvalue.create_ord(v: Tconstexprint);    begin      fillchar(value,sizeof(value),#0);      consttyp:=constord;      value.valueord:=v;      if v.signed then        def:=sintdef      else        def:=uintdef;    end;  constructor texprvalue.create_int(v: int64);    begin      fillchar(value,sizeof(value),#0);      consttyp:=constord;      value.valueord:=v;      def:=sintdef;    end;  constructor texprvalue.create_uint(v: qword);    begin      fillchar(value,sizeof(value),#0);      consttyp:=constord;      value.valueord:=v;      def:=uintdef;    end;  constructor texprvalue.create_bool(b: boolean);    begin      fillchar(value,sizeof(value),#0);      consttyp:=constord;      value.valueord:=ord(b);      def:=booldef;    end;  constructor texprvalue.create_str(const s: string);    var      sp: pansichar;      len: integer;    begin      fillchar(value,sizeof(value),#0);      consttyp:=conststring;      len:=length(s);      getmem(sp,len+1);      move(s[1],sp^,len+1);      value.valueptr:=sp;      value.len:=len;      def:=strdef;    end;  constructor texprvalue.create_set(ns: tnormalset);    begin      fillchar(value,sizeof(value),#0);      consttyp:=constset;      new(pnormalset(value.valueptr));      pnormalset(value.valueptr)^:=ns;      def:=setdef;    end;  constructor texprvalue.create_real(r: bestreal);    begin      fillchar(value,sizeof(value),#0);      consttyp:=constreal;      new(pbestreal(value.valueptr));      pbestreal(value.valueptr)^:=r;      def:=realdef;    end;  class function texprvalue.try_parse_number(const s:string):texprvalue;    var      ic: int64;      qc: qword;      code: integer;    begin      { try int64 }      val(s,ic,code);      if code=0 then        result:=texprvalue.create_int(ic)      else        begin          { try qword }          val(s,qc,code);          if code=0 then            result:=texprvalue.create_uint(qc)          else            result:=try_parse_real(s);        end;    end;  class function texprvalue.try_parse_real(const s:string):texprvalue;    var      d: bestreal;      code: integer;    begin      val(s,d,code);      if code=0 then        result:=texprvalue.create_real(d)      else        result:=nil;    end;  function texprvalue.evaluate(v:texprvalue;op:ttoken):texprvalue;    function check_compatible: boolean;      begin        result:=(                  (is_ordinal(v.def) or is_fpu(v.def)) and                  (is_ordinal(def) or is_fpu(def))                ) or                (is_stringlike(v.def) and is_stringlike(def));        if not result then          Message2(type_e_incompatible_types,def.typename,v.def.typename);      end;    var      lv,rv: tconstexprint;      lvd,rvd: bestreal;      lvs,rvs: string;    begin      case op of        _OP_IN:        begin          if not is_set(v.def) then            begin              v.error('Set', 'IN');              result:=texprvalue.create_error;            end          else          if not is_ordinal(def) then            begin              error('Ordinal', 'IN');              result:=texprvalue.create_error;            end          else          if value.valueord.signed then            result:=texprvalue.create_bool(value.valueord.svalue in pnormalset(v.value.valueptr)^)          else            result:=texprvalue.create_bool(value.valueord.uvalue in pnormalset(v.value.valueptr)^);        end;        _OP_NOT:        begin          if isBoolean then            result:=texprvalue.create_bool(not asBool)          else if is_ordinal(def) then            begin              result:=texprvalue.create_ord(value.valueord);              result.def:=def;              calc_not_ordvalue(result.value.valueord,result.def);            end          else            begin              error('Boolean', 'NOT');              result:=texprvalue.create_error;            end;        end;        _OP_OR:        begin          if isBoolean then            if v.isBoolean then              result:=texprvalue.create_bool(asBool or v.asBool)            else              begin                v.error('Boolean','OR');                result:=texprvalue.create_error;              end          else if is_ordinal(def) then            if is_ordinal(v.def) then              result:=texprvalue.create_ord(value.valueord or v.value.valueord)            else              begin                v.error('Ordinal','OR');                result:=texprvalue.create_error;              end          else            begin              error('Boolean','OR');              result:=texprvalue.create_error;            end;        end;        _OP_XOR:        begin          if isBoolean then            if v.isBoolean then              result:=texprvalue.create_bool(asBool xor v.asBool)            else              begin                v.error('Boolean','XOR');                result:=texprvalue.create_error;              end          else if is_ordinal(def) then            if is_ordinal(v.def) then              result:=texprvalue.create_ord(value.valueord xor v.value.valueord)            else              begin                v.error('Ordinal','XOR');                result:=texprvalue.create_error;              end          else            begin              error('Boolean','XOR');              result:=texprvalue.create_error;            end;        end;        _OP_AND:        begin          if isBoolean then            if v.isBoolean then              result:=texprvalue.create_bool(asBool and v.asBool)            else              begin                v.error('Boolean','AND');                result:=texprvalue.create_error;              end          else if is_ordinal(def) then            if is_ordinal(v.def) then              result:=texprvalue.create_ord(value.valueord and v.value.valueord)            else              begin                v.error('Ordinal','AND');                result:=texprvalue.create_error;              end          else            begin              error('Boolean','AND');              result:=texprvalue.create_error;            end;        end;        _EQ,_NE,_LT,_GT,_GTE,_LTE,_PLUS,_MINUS,_STAR,_SLASH,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR:        if (op=_MINUS) and not(assigned(v)) then          begin            if is_ordinal(def) then              result:=texprvalue.create_ord(-value.valueord)            else if is_fpu(def) then              result:=texprvalue.create_real(-pbestreal(value.valueptr)^)            else              InternalError(2025050610);          end        else if check_compatible then          begin            if (is_ordinal(def) and is_ordinal(v.def)) then              begin                lv:=value.valueord;                rv:=v.value.valueord;                case op of                  _EQ:                    result:=texprvalue.create_bool(lv=rv);                  _NE:                    result:=texprvalue.create_bool(lv<>rv);                  _LT:                    result:=texprvalue.create_bool(lv<rv);                  _GT:                    result:=texprvalue.create_bool(lv>rv);                  _GTE:                    result:=texprvalue.create_bool(lv>=rv);                  _LTE:                    result:=texprvalue.create_bool(lv<=rv);                  _PLUS:                    result:=texprvalue.create_ord(lv+rv);                  _MINUS:                    result:=texprvalue.create_ord(lv-rv);                  _STAR:                    result:=texprvalue.create_ord(lv*rv);                  _SLASH:                    result:=texprvalue.create_real(lv/rv);                  _OP_DIV:                    result:=texprvalue.create_ord(lv div rv);                  _OP_MOD:                    result:=texprvalue.create_ord(lv mod rv);                  _OP_SHL:                    result:=texprvalue.create_ord(lv shl rv);                  _OP_SHR:                    result:=texprvalue.create_ord(lv shr rv);                  else                    InternalError(2025050611);                end;              end            else            if (is_fpu(def) or is_ordinal(def)) and               (is_fpu(v.def) or is_ordinal(v.def)) then              begin                if is_fpu(def) then                  lvd:=pbestreal(value.valueptr)^                else                  lvd:=value.valueord;                if is_fpu(v.def) then                  rvd:=pbestreal(v.value.valueptr)^                else                  rvd:=v.value.valueord;                case op of                  _EQ:                    result:=texprvalue.create_bool(lvd=rvd);                  _NE:                    result:=texprvalue.create_bool(lvd<>rvd);                  _LT:                    result:=texprvalue.create_bool(lvd<rvd);                  _GT:                    result:=texprvalue.create_bool(lvd>rvd);                  _GTE:                    result:=texprvalue.create_bool(lvd>=rvd);                  _LTE:                    result:=texprvalue.create_bool(lvd<=rvd);                  _PLUS:                    result:=texprvalue.create_real(lvd+rvd);                  _MINUS:                    result:=texprvalue.create_real(lvd-rvd);                  _STAR:                    result:=texprvalue.create_real(lvd*rvd);                  _SLASH:                    result:=texprvalue.create_real(lvd/rvd);                  else                    begin                      Message(parser_e_illegal_expression);                      result:=texprvalue.create_error;                    end;                end;              end            else            begin              lvs:=asStr;              rvs:=v.asStr;              case op of                _EQ:                  result:=texprvalue.create_bool(lvs=rvs);                _NE:                  result:=texprvalue.create_bool(lvs<>rvs);                _LT:                  result:=texprvalue.create_bool(lvs<rvs);                _GT:                  result:=texprvalue.create_bool(lvs>rvs);                _GTE:                  result:=texprvalue.create_bool(lvs>=rvs);                _LTE:                  result:=texprvalue.create_bool(lvs<=rvs);                _PLUS:                  result:=texprvalue.create_str(lvs+rvs);                else                  begin                    Message(parser_e_illegal_expression);                    result:=texprvalue.create_error;                  end;              end;            end;          end        else          result:=texprvalue.create_error;        else          result:=texprvalue.create_error;      end;    end;  procedure texprvalue.error(expecteddef, place: string);    begin      Message3(scan_e_compile_time_typeerror,               expecteddef,               def.typename,               place              );    end;  function texprvalue.isBoolean: Boolean;    var      i: int64;    begin      result:=is_boolean(def);      if not result and is_integer(def) then        begin          i:=asInt64;          result:=(i=0)or(i=1);        end;    end;  function texprvalue.isInt: Boolean;    begin      result:=is_integer(def);    end;  function texprvalue.asBool: Boolean;    begin      result:=value.valueord<>0;    end;  function texprvalue.asInt: Integer;    begin      result:=value.valueord.svalue;    end;  function texprvalue.asInt64: Int64;    begin      result:=value.valueord.svalue;    end;  function texprvalue.asSet: tnormalset;    begin      result:=pnormalset(value.valueptr)^;    end;  function texprvalue.asStr: String;    var      b:byte;    begin      case consttyp of        constord:          result:=tostr(value.valueord);        conststring,        constresourcestring:          SetString(result,pchar(value.valueptr),value.len);        constreal:          str(pbestreal(value.valueptr)^,result);        constset:          begin            result:=',';            for b:=0 to 255 do              if b in pconstset(value.valueptr)^ then                result:=result+tostr(b)+',';          end;        { error values }        constnone:          result:='';        else          internalerror(2013112801);      end;    end;  destructor texprvalue.destroy;    begin      case consttyp of        conststring,        constresourcestring :          freemem(value.valueptr,value.len+1);        constwstring,        constwresourcestring:          donewidestring(value.valuews);        constreal :          dispose(pbestreal(value.valueptr));        constset :          dispose(pnormalset(value.valueptr));        constguid :          dispose(pguid(value.valueptr));        constord,        { error values }        constnone:          ;        else          internalerror(2013112802);      end;      inherited destroy;    end;  const    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];    function findincludefile(const path,name:TCmdStr;var foundfile:TCmdStr):boolean;      var        found  : boolean;        hpath  : TCmdStr;      begin        (* look for the include file         If path was absolute and specified as part of {$I } then          1. specified path         else          1. path of current inputfile,current dir          2. local includepath          3. global includepath          -- Check mantis #13461 before changing this *)         found:=false;         foundfile:='';         hpath:='';         if path_absolute(path) then           begin             found:=FindFile(name,path,true,foundfile);           end         else           begin             hpath:=current_scanner.inputfile.path+';'+CurDirRelPath(source_info);             found:=FindFile(path+name, hpath,true,foundfile);             if not found then               found:=current_module.localincludesearchpath.FindFile(path+name,true,foundfile);             if not found  then               found:=includesearchpath.FindFile(path+name,true,foundfile);           end;         result:=found;      end;    function preproc_comp_expr(conform_to:tdef):texprvalue;        function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean):texprvalue; forward;        procedure preproc_consume(t:ttoken);        begin          if t<>current_scanner.preproc_token then            Message(scan_e_preproc_syntax_error);          current_scanner.preproc_token:=current_scanner.readpreproc;        end;        function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;out tokentoconsume:ttoken):boolean;          var            hmodule: tmodule;            ns:ansistring;            nssym:tsym;          begin            result:=false;            tokentoconsume:=_ID;            if assigned(srsym) and (srsym.typ in [unitsym,namespacesym]) then              begin                if not(srsym.owner.symtabletype in [staticsymtable,globalsymtable]) then                  internalerror(200501154);                { only allow unit.symbol access if the name was                  found in the current module                  we can use iscurrentunit because generic specializations does not                  change current_unit variable }                hmodule:=find_module_from_symtable(srsym.Owner);                if not Assigned(hmodule) then                  internalerror(201001120);                if hmodule.unit_index=current_filepos.moduleindex then                  begin                    preproc_consume(_POINT);                    current_scanner.skipspace;                    if srsym.typ=namespacesym then                      begin                        ns:=srsym.name;                        nssym:=srsym;                        while assigned(srsym) and (srsym.typ=namespacesym) do                          begin                            { we have a namespace. the next identifier should be either a namespace or a unit }                            searchsym_in_module(hmodule,ns+'.'+current_scanner.preproc_pattern,srsym,srsymtable);                            if assigned(srsym) and (srsym.typ in [namespacesym,unitsym]) then                              begin                                ns:=ns+'.'+current_scanner.preproc_pattern;                                nssym:=srsym;                                preproc_consume(_ID);                                current_scanner.skipspace;                                preproc_consume(_POINT);                                current_scanner.skipspace;                              end;                          end;                        { check if there is a hidden unit with this pattern in the namespace }                        if not assigned(srsym) and                           assigned(nssym) and (nssym.typ=namespacesym) and assigned(tnamespacesym(nssym).unitsym) then                          srsym:=tnamespacesym(nssym).unitsym;                        if assigned(srsym) and (srsym.typ<>unitsym) then                          internalerror(201108260);                        if not assigned(srsym) then                          begin                            result:=true;                            srsymtable:=nil;                            exit;                          end;                      end;                    case current_scanner.preproc_token of                      _ID:                        { system.char? (char=widechar comes from the implicit                          uachar/uuchar unit -> override) }                        if (current_scanner.preproc_pattern='CHAR') and                           (tmodule(tunitsym(srsym).module).globalsymtable=systemunit) then                          begin                            if m_default_unicodestring in current_settings.modeswitches then                              searchsym_in_module(tunitsym(srsym).module,'WIDECHAR',srsym,srsymtable)                            else                              searchsym_in_module(tunitsym(srsym).module,'ANSICHAR',srsym,srsymtable)                          end                        else                          searchsym_in_module(tunitsym(srsym).module,current_scanner.preproc_pattern,srsym,srsymtable);                      _STRING:                        begin                          { system.string? }                          if tmodule(tunitsym(srsym).module).globalsymtable=systemunit then                            begin                              if cs_refcountedstrings in current_settings.localswitches then                                begin                                  if m_default_unicodestring in current_settings.modeswitches then                                    searchsym_in_module(tunitsym(srsym).module,'UNICODESTRING',srsym,srsymtable)                                  else                                    searchsym_in_module(tunitsym(srsym).module,'ANSISTRING',srsym,srsymtable)                                end                              else                                searchsym_in_module(tunitsym(srsym).module,'SHORTSTRING',srsym,srsymtable);                              tokentoconsume:=_STRING;                            end;                        end                      else                        ;                    end;                  end                else                  begin                    srsym:=nil;                    srsymtable:=nil;                  end;                result:=true;              end;          end;        procedure try_consume_nestedsym(var srsym:tsym;var srsymtable:TSymtable);          var            def:tdef;            tokentoconsume:ttoken;            found:boolean;          begin            found:=try_consume_unitsym(srsym,srsymtable,tokentoconsume);            if found then              begin                preproc_consume(tokentoconsume);                current_scanner.skipspace;              end;             while (current_scanner.preproc_token=_POINT) do               begin                 if assigned(srsym)and(srsym.typ=typesym) then                   begin                     def:=ttypesym(srsym).typedef;                     if is_class_or_object(def) or is_record(def) or is_java_class_or_interface(def) then                       begin                         preproc_consume(_POINT);                         current_scanner.skipspace;                         if def.typ=objectdef then                           found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,[ssf_search_helper])                         else                           found:=searchsym_in_record(trecorddef(def),current_scanner.preproc_pattern,srsym,srsymtable);                         if not found then                           begin                             Message1(sym_e_id_not_found,current_scanner.preproc_pattern);                             exit;                           end;                         preproc_consume(_ID);                         current_scanner.skipspace;                       end                     else                       begin                         Message(sym_e_type_must_be_rec_or_object_or_class);                         exit;                       end;                   end                 else                   begin                     Message(type_e_type_id_expected);                     exit;                   end;               end;          end;        function preproc_substitutedtoken(const basesearchstr:string;eval:Boolean):texprvalue;        { Currently this parses identifiers as well as numbers.          The result from this procedure can either be that the token          itself is a value, or that it is a compile time variable/macro,          which then is substituted for another value (for macros          recursivelly substituted).}        var          hs: string;          mac: tmacro;          macrocount,          len: integer;          foundmacro: boolean;          searchstr: pshortstring;          searchstr2store: string;        begin          if not eval then            begin              result:=texprvalue.create_str(basesearchstr);              exit;            end;          searchstr := @basesearchstr;          mac:=nil;          foundmacro:=false;          { Substitue macros and compiler variables with their content/value.            For real macros also do recursive substitution. }          macrocount:=0;          repeat            mac:=tmacro(search_macro(searchstr^));            inc(macrocount);            if macrocount>max_macro_nesting then              begin                Message(scan_w_macro_too_deep);                break;              end;            if assigned(mac) and mac.defined then              if assigned(mac.buftext) then                begin                  if mac.buflen>255 then                    begin                      len:=255;                      Message(scan_w_macro_cut_after_255_chars);                    end                  else                    len:=mac.buflen;                  hs[0]:=char(len);                  if len>0 then                    move(mac.buftext[0],hs[1],len);                  searchstr2store:=upcase(hs);                  searchstr:=@searchstr2store;                  mac.is_used:=true;                  foundmacro:=true;                end              else                begin                  Message1(scan_e_error_macro_lacks_value,searchstr^);                  break;                end            else              break;            if mac.is_compiler_var then              break;          until false;          { At this point, result do contain the value. Do some decoding and            determine the type.}          result:=texprvalue.try_parse_number(searchstr^);          if not assigned(result) then            begin              if foundmacro and (searchstr^='FALSE') then                result:=texprvalue.create_bool(false)              else if foundmacro and (searchstr^='TRUE') then                result:=texprvalue.create_bool(true)              else if (m_mac in current_settings.modeswitches) and                      (not assigned(mac) or not mac.defined) and                      (macrocount = 1) then                begin                  {Errors in mode mac is issued here. For non macpas modes there is                   more liberty, but the error will eventually be caught at a later stage.}                  Message1(scan_e_error_macro_undefined,searchstr^);                  result:=texprvalue.create_str(searchstr^); { just to have something }                end              else                result:=texprvalue.create_str(searchstr^);            end;        end;        procedure MarkSymbolAsUsed(sym: tsym);          begin           sym.IncRefCount;           { do we know an owner? }           if Assigned(current_module) and Assigned(current_module.unitmap) and Assigned(sym.owner) then             inc(current_module.unitmap[sym.owner.moduleid].refs);          end;        function preproc_factor(eval: Boolean):texprvalue;        var           hs,countstr,storedpattern,fileext: string;           mac: tmacro;           srsym : tsym;           srsymtable : TSymtable;           hdef : TDef;           l : longint;           hasKlammer,           read_next: Boolean;           exprvalue:texprvalue;           ns:tnormalset;           fs,path,name: tpathstr;           foundfile: TCmdStr;           found: boolean;        begin          result:=nil;          hasKlammer:=false;           if current_scanner.preproc_token=_ID then             begin                if current_scanner.preproc_pattern='FILEEXISTS' then                  begin                    preproc_consume(_ID);                    preproc_consume(_LKLAMMER);                    hs:=current_scanner.preproc_pattern;                    preproc_consume(_CSTRING);                    fs:=GetToken(hs,' ');                    fs:=FixFileName(fs);                    path:=ExtractFilePath(fs);                    name:=ExtractFileName(fs);                    { this like 'include' }                    if (length(name)>=1) and                       (name[1]='*') then                      name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);                    { try to find the file, this like 'include' }                    found:=findincludefile(path,name,foundfile);                    fileext:=lower(ExtractFileExt(name));                    if (not found) and ((fileext<>'.inc') and (fileext<>sourceext) and (fileext<>pasext)) then                     begin                       { try default extensions .inc , .pp and .pas }                       if (not found) then                        found:=findincludefile(path,name+'.inc',foundfile);                       if (not found) then                        found:=findincludefile(path,name+sourceext,foundfile);                       if (not found) then                        found:=findincludefile(path,name+pasext,foundfile);                     end;                    if (not found) and (ExtractFileExt(name)=ExtensionSeparator) and (Length(name)>=2) then                      found:=findincludefile(path,Copy(name,1,Length(name)-1),foundfile);                    result:=texprvalue.create_bool(found);                    current_scanner.skipspace;                    preproc_consume(_RKLAMMER);                  end                else                if current_scanner.preproc_pattern='DEFINED' then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_LKLAMMER then                      begin                        preproc_consume(_LKLAMMER);                        current_scanner.skipspace;                        hasKlammer:= true;                      end                    else if (m_mac in current_settings.modeswitches) then                      hasKlammer:= false                    else                      Message(scan_e_error_in_preproc_expr);                    if current_scanner.preproc_token =_ID then                      begin                        hs := current_scanner.preproc_pattern;                        mac := tmacro(search_macro(hs));                        if assigned(mac) and mac.defined then                          begin                            result:=texprvalue.create_bool(true);                            mac.is_used:=true;                          end                        else                          result:=texprvalue.create_bool(false);                        preproc_consume(_ID);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_error_in_preproc_expr);                    if hasKlammer then                      if current_scanner.preproc_token =_RKLAMMER then                        preproc_consume(_RKLAMMER)                      else                        Message(scan_e_error_in_preproc_expr);                  end                else                if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='UNDEFINED') then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_ID then                      begin                        hs := current_scanner.preproc_pattern;                        mac := tmacro(search_macro(hs));                        if assigned(mac) then                          begin                            result:=texprvalue.create_bool(false);                            mac.is_used:=true;                          end                        else                          result:=texprvalue.create_bool(true);                        preproc_consume(_ID);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_error_in_preproc_expr);                  end                else                if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='OPTION') then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_LKLAMMER then                      begin                        preproc_consume(_LKLAMMER);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_error_in_preproc_expr);                    if not (current_scanner.preproc_token = _ID) then                      Message(scan_e_error_in_preproc_expr);                    hs:=current_scanner.preproc_pattern;                    if (length(hs) > 1) then                      {This is allowed in Metrowerks Pascal}                      Message(scan_e_error_in_preproc_expr)                    else                      begin                        if CheckSwitch(hs[1],'+') then                          result:=texprvalue.create_bool(true)                        else                          result:=texprvalue.create_bool(false);                      end;                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_RKLAMMER then                      preproc_consume(_RKLAMMER)                    else                      Message(scan_e_error_in_preproc_expr);                  end                else                if current_scanner.preproc_pattern='SIZEOF' then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_LKLAMMER then                      begin                        preproc_consume(_LKLAMMER);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_preproc_syntax_error);                    storedpattern:=current_scanner.preproc_pattern;                    preproc_consume(_ID);                    current_scanner.skipspace;                    if eval then                      if searchsym(storedpattern,srsym,srsymtable) then                        begin                          try_consume_nestedsym(srsym,srsymtable);                          l:=0;                          if assigned(srsym) then                            case srsym.typ of                              staticvarsym,                              localvarsym,                              paravarsym :                                begin                                  l:=tabstractvarsym(srsym).getsize;                                  MarkSymbolAsUsed(srsym);                                end;                              typesym:                                begin                                  l:=ttypesym(srsym).typedef.size;                                  MarkSymbolAsUsed(srsym);                                end;                              else                                Message(scan_e_error_in_preproc_expr);                            end;                          result:=texprvalue.create_int(l);                        end                      else                        Message1(sym_e_id_not_found,storedpattern);                    if current_scanner.preproc_token =_RKLAMMER then                      preproc_consume(_RKLAMMER)                    else                      Message(scan_e_preproc_syntax_error);                  end                else                if current_scanner.preproc_pattern='HIGH' then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_LKLAMMER then                      begin                        preproc_consume(_LKLAMMER);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_preproc_syntax_error);                    storedpattern:=current_scanner.preproc_pattern;                    preproc_consume(_ID);                    current_scanner.skipspace;                    if eval then                      if searchsym(storedpattern,srsym,srsymtable) then                        begin                          try_consume_nestedsym(srsym,srsymtable);                          hdef:=nil;                          hs:='';                          l:=0;                          if assigned(srsym) then                            case srsym.typ of                              staticvarsym,                              localvarsym,                              paravarsym :                                begin                                  hdef:=tabstractvarsym(srsym).vardef;                                  MarkSymbolAsUsed(srsym);                                end;                              typesym:                                begin                                  hdef:=ttypesym(srsym).typedef;                                  MarkSymbolAsUsed(srsym);                                end;                              else                                Message(scan_e_error_in_preproc_expr);                            end;                          if assigned(hdef) then                            begin                              if hdef.typ=setdef then                                hdef:=tsetdef(hdef).elementdef;                              case hdef.typ of                                orddef:                                  with torddef(hdef).high do                                    if signed then                                      result:=texprvalue.create_int(svalue)                                    else                                      result:=texprvalue.create_uint(uvalue);                                enumdef:                                  result:=texprvalue.create_int(tenumdef(hdef).maxval);                                arraydef:                                  if is_open_array(hdef) or is_array_of_const(hdef) or is_dynamic_array(hdef) then                                    Message(type_e_mismatch)                                  else                                    result:=texprvalue.create_int(tarraydef(hdef).highrange);                                stringdef:                                  if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then                                    Message(type_e_mismatch)                                  else                                    result:=texprvalue.create_int(tstringdef(hdef).len);                                else                                  Message(type_e_mismatch);                              end;                            end;                        end                      else                        Message1(sym_e_id_not_found,storedpattern);                    if current_scanner.preproc_token =_RKLAMMER then                      preproc_consume(_RKLAMMER)                    else                      Message(scan_e_preproc_syntax_error);                  end                else                if current_scanner.preproc_pattern='DECLARED' then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_LKLAMMER then                      begin                        preproc_consume(_LKLAMMER);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_error_in_preproc_expr);                    if current_scanner.preproc_token =_ID then                      begin                        hs := upper(current_scanner.preproc_pattern);                        preproc_consume(_ID);                        current_scanner.skipspace;                        if current_scanner.preproc_token in [_LT,_LSHARPBRACKET] then                          begin                            l:=1;                            preproc_consume(current_scanner.preproc_token);                            current_scanner.skipspace;                            while current_scanner.preproc_token=_COMMA do                              begin                                inc(l);                                preproc_consume(_COMMA);                                current_scanner.skipspace;                              end;                            if not (current_scanner.preproc_token in [_GT,_RSHARPBRACKET]) then                              Message(scan_e_error_in_preproc_expr)                            else                              preproc_consume(current_scanner.preproc_token);                            str(l,countstr);                            hs:=hs+'$'+countstr;                          end                        else                          { special case: <> }                          if current_scanner.preproc_token=_NE then                            begin                              hs:=hs+'$1';                              preproc_consume(_NE);                            end;                        current_scanner.skipspace;                        if searchsym(hs,srsym,srsymtable) then                          begin                            { TSomeGeneric<...> also adds a TSomeGeneric symbol }                            if (sp_generic_dummy in srsym.symoptions) and                                (srsym.typ=typesym) and                                (                                  { mode delphi}                                  (ttypesym(srsym).typedef.typ in [undefineddef,errordef]) or                                  { non-delphi modes }                                  (df_generic in ttypesym(srsym).typedef.defoptions)                                ) then                              result:=texprvalue.create_bool(false)                            else                              result:=texprvalue.create_bool(true);                            MarkSymbolAsUsed(srsym);                          end                        else                          result:=texprvalue.create_bool(false);                      end                    else                      Message(scan_e_error_in_preproc_expr);                    if current_scanner.preproc_token =_RKLAMMER then                      preproc_consume(_RKLAMMER)                    else                      Message(scan_e_error_in_preproc_expr);                  end                else                if current_scanner.preproc_pattern='ORD' then                  begin                    preproc_consume(_ID);                    current_scanner.skipspace;                    if current_scanner.preproc_token =_LKLAMMER then                      begin                        preproc_consume(_LKLAMMER);                        current_scanner.skipspace;                      end                    else                      Message(scan_e_preproc_syntax_error);                    exprvalue:=preproc_factor(eval);                    if eval then                      begin                        if is_ordinal(exprvalue.def) then                          result:=texprvalue.create_int(exprvalue.asInt)                        else                          begin                            exprvalue.error('Ordinal','ORD');                            result:=texprvalue.create_int(0);                          end;                      end                    else                      result:=texprvalue.create_int(0);                    exprvalue.free;                    if current_scanner.preproc_token =_RKLAMMER then                      preproc_consume(_RKLAMMER)                    else                      Message(scan_e_error_in_preproc_expr);                  end                else                if current_scanner.preproc_pattern='NOT' then                  begin                    preproc_consume(_ID);                    exprvalue:=preproc_factor(eval);                    if eval then                      result:=exprvalue.evaluate(nil,_OP_NOT)                    else                      result:=texprvalue.create_bool(false); {Just to have something}                    exprvalue.free;                  end                else                if (current_scanner.preproc_pattern='TRUE') then                  begin                    result:=texprvalue.create_bool(true);                    preproc_consume(_ID);                  end                else                if (current_scanner.preproc_pattern='FALSE') then                  begin                    result:=texprvalue.create_bool(false);                    preproc_consume(_ID);                  end                else                  begin                    storedpattern:=current_scanner.preproc_pattern;                    preproc_consume(_ID);                    current_scanner.skipspace;                    { first look for a macros/int/float }                    result:=preproc_substitutedtoken(storedpattern,eval);                    if eval and (result.consttyp=conststring) then                      begin                        if searchsym(storedpattern,srsym,srsymtable) then                          begin                            try_consume_nestedsym(srsym,srsymtable);                            if assigned(srsym) then                              begin                                MarkSymbolAsUsed(srsym);                                case srsym.typ of                                  constsym:                                    begin                                      { const def must conform to the set type }                                      if (conform_to<>nil) and                                        (conform_to.typ=setdef) and                                        (tconstsym(srsym).constdef.typ=setdef) and                                        (compare_defs(tsetdef(tconstsym(srsym).constdef).elementdef,tsetdef(conform_to).elementdef,nothingn)<>te_exact) then                                          begin                                            result.free;                                            result:=nil;                                            // TODO(ryan): better error?                                            Message(scan_e_error_in_preproc_expr);                                          end;                                      if result<>nil then                                        begin                                          result.free;                                          result:=texprvalue.create_const(tconstsym(srsym));                                        end;                                    end;                                  enumsym:                                    begin                                      { enum definition must conform to the set type }                                      if (conform_to<>nil) and                                        (conform_to.typ=setdef) and                                        (compare_defs(tenumsym(srsym).definition,tsetdef(conform_to).elementdef,nothingn)<>te_exact) then                                          begin                                            result.free;                                            result:=nil;                                            // TODO(ryan): better error?                                            Message(scan_e_error_in_preproc_expr);                                          end;                                      if result<>nil then                                        begin                                          result.free;                                          result:=texprvalue.create_int(tenumsym(srsym).value);                                        end;                                    end;                                  else                                    ;                                end;                              end;                          end                        { the id must be belong to the set type }                        else if (conform_to<>nil) and (conform_to.typ=setdef) then                          begin                            result.free;                            result:=nil;                            // TODO(ryan): better error?                            Message(scan_e_error_in_preproc_expr);                          end;                      end                      { skip id(<expr>) if expression must not be evaluated }                      else if not(eval) and (result.consttyp=conststring) then                        begin                          if current_scanner.preproc_token =_LKLAMMER then                            begin                              preproc_consume(_LKLAMMER);                              current_scanner.skipspace;                              result:=preproc_factor(false);                              if current_scanner.preproc_token =_RKLAMMER then                                preproc_consume(_RKLAMMER)                              else                                Message(scan_e_error_in_preproc_expr);                            end;                        end;                  end             end           else if current_scanner.preproc_token =_LKLAMMER then             begin                preproc_consume(_LKLAMMER);                result:=preproc_sub_expr(opcompare,eval);                preproc_consume(_RKLAMMER);             end           else if current_scanner.preproc_token = _LECKKLAMMER then             begin               preproc_consume(_LECKKLAMMER);               ns:=[];               read_next:=false;               while (current_scanner.preproc_token in [_ID,_INTCONST]) or read_next do               begin                 read_next:=false;                 exprvalue:=preproc_factor(eval);                 { the const set does not conform to the set def }                 if (conform_to<>nil) and                   (conform_to.typ=setdef) and                   (exprvalue.consttyp=constnone) then                   begin                     result:=texprvalue.create_error;                     break;                   end;                 { reject duplicate enums in the set }                 if exprvalue.asInt in ns then                   begin                     Message1(sym_e_duplicate_id,current_scanner.preproc_pattern);                     result:=texprvalue.create_error;                     break;                   end;                 include(ns,exprvalue.asInt);                 if current_scanner.preproc_token = _COMMA then                   begin                     preproc_consume(_COMMA);                     read_next:=true;                   end               end;               preproc_consume(_RECKKLAMMER);               if result=nil then                 result:=texprvalue.create_set(ns);             end           else if current_scanner.preproc_token = _INTCONST then             begin               result:=texprvalue.try_parse_number(current_scanner.preproc_pattern);               if not assigned(result) then                 begin                   Message(parser_e_invalid_integer);                   result:=texprvalue.create_int(1);                 end;               preproc_consume(_INTCONST);             end           else if current_scanner.preproc_token = _CSTRING then             begin               result:=texprvalue.create_str(current_scanner.preproc_pattern);               preproc_consume(_CSTRING);             end           else if current_scanner.preproc_token = _REALNUMBER then             begin               result:=texprvalue.try_parse_real(current_scanner.preproc_pattern);               if not assigned(result) then                 begin                   Message(parser_e_error_in_real);                   result:=texprvalue.create_real(1.0);                 end;               preproc_consume(_REALNUMBER);             end           else if current_scanner.preproc_token = _MINUS then             begin               preproc_consume(_MINUS);               exprvalue:=preproc_factor(eval);               if eval then                 result:=exprvalue.evaluate(nil,_MINUS)               else if exprvalue.isInt then                 result:=texprvalue.create_int(-exprvalue.asInt)               else if is_fpu(exprvalue.def) then                 result:=texprvalue.create_real(-pbestreal(exprvalue.value.valueptr)^)               else                 Message(scan_e_error_in_preproc_expr);               exprvalue.free;             end           else             Message(scan_e_error_in_preproc_expr);           if not assigned(result) then             result:=texprvalue.create_error;        end;        function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean): texprvalue;        var          hs1,hs2: texprvalue;          op: ttoken;        begin           if pred_level=highest_precedence then             result:=preproc_factor(eval)           else             result:=preproc_sub_expr(succ(pred_level),eval);          repeat            op:=current_scanner.preproc_token;            if (op in preproc_operators) and               (op in operator_levels[pred_level]) then             begin               hs1:=result;               preproc_consume(op);               if (op=_OP_OR) and hs1.isBoolean and hs1.asBool then                 begin                   { stop evaluation the rest of expression }                   result:=texprvalue.create_bool(true);                   if pred_level=highest_precedence then                     hs2:=preproc_factor(false)                   else                     hs2:=preproc_sub_expr(succ(pred_level),false);                 end               else if (op=_OP_AND) and hs1.isBoolean and not hs1.asBool then                 begin                   { stop evaluation the rest of expression }                   result:=texprvalue.create_bool(false);                   if pred_level=highest_precedence then                     hs2:=preproc_factor(false)                   else                     hs2:=preproc_sub_expr(succ(pred_level),false);                 end               else                 begin                   if pred_level=highest_precedence then                     hs2:=preproc_factor(eval)                   else                     hs2:=preproc_sub_expr(succ(pred_level),eval);                   if eval then                     result:=hs1.evaluate(hs2,op)                   else                     result:=texprvalue.create_bool(false); {Just to have something}                 end;               hs1.free;               hs2.free;             end           else             break;          until false;        end;     begin       current_scanner.in_preproc_comp_expr:=true;       current_scanner.skipspace;       { start preproc expression scanner }       current_scanner.preproc_token:=current_scanner.readpreproc;       preproc_comp_expr:=preproc_sub_expr(opcompare,true);       current_scanner.in_preproc_comp_expr:=false;     end;    function boolean_compile_time_expr(var valuedescr: string): Boolean;      var        hs: texprvalue;      begin        hs:=preproc_comp_expr(nil);        if hs.isBoolean then          result:=hs.asBool        else          begin            hs.error('Boolean', 'IF or ELSEIF');            result:=false;          end;        valuedescr:=hs.asStr;        hs.free;      end;    procedure dir_if;      begin        current_scanner.ifpreprocstack(pp_if,@boolean_compile_time_expr, scan_c_if_found);      end;    procedure dir_elseif;      begin        current_scanner.elseifpreprocstack(@boolean_compile_time_expr);      end;    procedure dir_define_impl(macstyle: boolean);      var        hs  : string;        bracketcount : longint;        mac : tmacro;        macropos : SizeInt;        macrobuffer : array[0..maxmacrolen-1] of char;      begin        current_scanner.skipspace;        hs:=current_scanner.readid;        if hs='' then          begin            Message(scan_e_emptymacroname);            exit;          end;        mac:=tmacro(search_macro(hs));        if not assigned(mac) or (mac.owner <> current_module.localmacrosymtable) then          begin            mac:=tmacro.create(hs);            mac.defined:=true;            current_module.localmacrosymtable.insertsym(mac);          end        else          begin            mac.defined:=true;            mac.is_compiler_var:=false;          { delete old definition }            mac.free_buftext;          end;        Message1(parser_c_macro_defined,mac.name);        mac.is_used:=true;        if (cs_support_macro in current_settings.moduleswitches) then          begin             current_scanner.skipspace;             if not macstyle then               begin                 { may be a macro? }                 if c <> ':' then                   exit;                 current_scanner.readchar;                 if c <> '=' then                   exit;                 mac.is_c_macro:=true;                 current_scanner.readchar;                 current_scanner.skipspace;               end;             { key words are never substituted }             if is_keyword(hs) then               Message(scan_e_keyword_cant_be_a_macro);             current_scanner.gettokenpos;             mac.fileinfo:=current_tokenpos;             macropos:=0;             { parse macro, brackets are counted so it's possible               to have a $ifdef etc. in the macro }             bracketcount:=0;             repeat               case c of                 '}' :                   if (bracketcount=0) then                    break                   else                    dec(bracketcount);                 '{' :                   inc(bracketcount);                 #10,#13 :                   current_scanner.linebreak;                 #26 :                   current_scanner.end_of_file;               end;               if macropos>=maxmacrolen then                 Message(scan_f_macro_buffer_overflow);               macrobuffer[macropos]:=c;               inc(macropos);               current_scanner.readchar;             until false;             { copy the text }             if macropos>0 then               move(pchar(@macrobuffer[0])^,mac.allocate_buftext(macropos)^,macropos);          end        else          begin           { check if there is an assignment, then we need to give a             warning }             current_scanner.skipspace;             if c=':' then              begin                current_scanner.readchar;                if c='=' then                  Message(scan_w_macro_support_turned_off);              end;          end;      end;    procedure dir_define;      begin        dir_define_impl(false);      end;    procedure dir_definec;      begin        dir_define_impl(true);      end;    procedure dir_setc;      var        hs  : string;        mac : tmacro;        exprvalue: texprvalue;      begin        current_scanner.skipspace;        hs:=current_scanner.readid;        mac:=tmacro(search_macro(hs));        if not assigned(mac) or           (mac.owner <> current_module.localmacrosymtable) then          begin            mac:=tmacro.create(hs);            mac.defined:=true;            mac.is_compiler_var:=true;            current_module.localmacrosymtable.insertsym(mac);          end        else          begin            mac.defined:=true;            mac.is_compiler_var:=true;          { delete old definition }            mac.free_buftext;          end;        Message1(parser_c_macro_defined,mac.name);        mac.is_used:=true;        { key words are never substituted }        if is_keyword(hs) then          Message(scan_e_keyword_cant_be_a_macro);        { macro assignment can be both := and = }        current_scanner.skipspace;        if c=':' then          current_scanner.readchar;        if c='=' then          begin             current_scanner.readchar;             exprvalue:=preproc_comp_expr(nil);             if not is_boolean(exprvalue.def) and                not is_integer(exprvalue.def) then               exprvalue.error('Boolean, Integer', 'SETC');             hs:=exprvalue.asStr;             if length(hs) <> 0 then               begin                 {If we are absolutely shure it is boolean, translate                  to TRUE/FALSE to increase possibility to do future type check}                 if exprvalue.isBoolean then                   begin                     if exprvalue.asBool then                       hs:='TRUE'                     else                       hs:='FALSE';                   end;                 Message2(parser_c_macro_set_to,mac.name,hs);                 { copy the text }                 move(hs[1],mac.allocate_buftext(length(hs))^,length(hs));               end             else               Message(scan_e_preproc_syntax_error);             exprvalue.free;          end        else          Message(scan_e_preproc_syntax_error);      end;    procedure dir_undef;      var        hs  : string;        mac : tmacro;      begin        current_scanner.skipspace;        hs:=current_scanner.readid;        mac:=tmacro(search_macro(hs));        if not assigned(mac) or           (mac.owner <> current_module.localmacrosymtable) then          begin             mac:=tmacro.create(hs);             mac.defined:=false;             current_module.localmacrosymtable.insertsym(mac);          end        else          begin             mac.defined:=false;             mac.is_compiler_var:=false;             mac.is_c_macro:=false;             { delete old definition }             mac.free_buftext;          end;        Message1(parser_c_macro_undefined,mac.name);        mac.is_used:=true;      end;    procedure dir_include;      var        foundfile : TCmdStr;        path,        name,        hs    : tpathstr;        args  : string;        hp    : tinputfile;        found : boolean;        macroIsString : boolean;        fileext: string;      begin        current_scanner.skipspace;        args:=current_scanner.readcomment;        hs:=GetToken(args,' ');        if hs='' then         exit;        if (hs[1]='%') then         begin         { case insensitive }           hs:=upper(hs);         { remove %'s }           Delete(hs,1,1);           if hs[length(hs)]='%' then            Delete(hs,length(hs),1);         { save old }           path:=hs;         { first check for internal macros }           macroIsString:=true;           case hs of             'TIME':               if timestr<>'' then                 hs:=timestr               else                 hs:=gettimestr;             'DATE':               if datestr<>'' then                 hs:=datestr               else                 hs:=getdatestr;             'DATEYEAR':               begin                 hs:=tostr(startsystime.Year);                 macroIsString:=false;               end;             'DATEMONTH':               begin                 hs:=tostr(startsystime.Month);                 macroIsString:=false;               end;             'DATEDAY':               begin                 hs:=tostr(startsystime.Day);                 macroIsString:=false;               end;             'TIMEHOUR':               begin                 hs:=tostr(startsystime.Hour);                 macroIsString:=false;               end;             'TIMEMINUTE':               begin                 hs:=tostr(startsystime.Minute);                 macroIsString:=false;               end;             'TIMESECOND':               begin                 hs:=tostr(startsystime.Second);                 macroIsString:=false;               end;             'FILE':               hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);             'LINE':               hs:=tostr(current_filepos.line);             'LINENUM':               begin                 hs:=tostr(current_filepos.line);                 macroIsString:=false;               end;             'FPCVERSION':               hs:=version_string;             'FPCDATE':               hs:=date_string;             'FPCTARGET':               hs:=target_cpu_string;             'FPCTARGETCPU':               hs:=target_cpu_string;             'FPCTARGETOS':               hs:=target_info.shortname;             'CURRENTROUTINE':               hs:=current_procinfo.procdef.procsym.RealName;             else               hs:=GetEnvironmentVariable(hs);           end;           if hs='' then            Message1(scan_w_include_env_not_found,path);           { make it a stringconst }           if macroIsString then             hs:=''''+hs+'''';           current_scanner.substitutemacro(path,@hs[1],length(hs),             current_scanner.line_no,current_scanner.inputfile.ref_index,false);         end        else         begin           hs:=FixFileName(hs);           path:=ExtractFilePath(hs);           name:=ExtractFileName(hs);           { Special case for Delphi compatibility: '*' has to be replaced             by the file name of the current source file.  }           if (length(name)>=1) and              (name[1]='*') then             name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);           { try to find the file }           found:=findincludefile(path,name,foundfile);           fileext:=lower(ExtractFileExt(name));           if (not found) and ((fileext<>'.inc') and (fileext<>sourceext) and (fileext<>pasext)) then            begin              { try default extensions .inc , .pp and .pas }              if (not found) then               found:=findincludefile(path,name+'.inc',foundfile);              if (not found) then               found:=findincludefile(path,name+sourceext,foundfile);              if (not found) then               found:=findincludefile(path,name+pasext,foundfile);            end;           { if the name ends in dot, try without the dot }           if (not found) and (ExtractFileExt(name)=ExtensionSeparator) and (Length(name)>=2) then             found:=findincludefile(path,Copy(name,1,Length(name)-1),foundfile);           if current_scanner.inputfilecount<max_include_nesting then             begin               inc(current_scanner.inputfilecount);               { we need to reread the current char }{$ifdef CHECK_INPUTPOINTER_LIMITS}               current_scanner.dec_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}               dec(current_scanner.inputpointer);{$endif  CHECK_INPUTPOINTER_LIMITS}               { reset c }               c:=#0;               { shutdown current file }               current_scanner.tempcloseinputfile;               { load new file }               hp:=do_openinputfile(foundfile);               hp.inc_path:=path;               current_scanner.addfile(hp);               current_module.sourcefiles.register_file(hp);               if (not found) then                Message1(scan_f_cannot_open_includefile,hs);              if (not current_scanner.openinputfile) then                Message1(scan_f_cannot_open_includefile,hs);               Message1(scan_t_start_include_file,current_scanner.inputfile.path+current_scanner.inputfile.name);               current_scanner.reload;             end           else             Message(scan_f_include_deep_ten);         end;      end;{*****************************************************************************                            Preprocessor writing*****************************************************************************}{$ifdef PREPROCWRITE}    constructor tpreprocfile.create(const fn:string);      begin        inherited create;      { open outputfile }        assign(f,fn);        {$push}{$I-}         rewrite(f);        {$pop}        if ioresult<>0 then         Comment(V_Fatal,'can''t create file '+fn);        setlength(buf,preprocbufsize);        settextbuf(f,buf[0],preprocbufsize);      { reset }        eolfound:=false;        spacefound:=false;      end;    destructor tpreprocfile.destroy;      begin        close(f);        buf:=nil;      end;    procedure tpreprocfile.add(const s:string);      begin        write(f,s);      end;    procedure tpreprocfile.addspace;      begin        if eolfound then         begin           writeln(f,'');           eolfound:=false;           spacefound:=false;         end        else         if spacefound then          begin            write(f,' ');            spacefound:=false;          end;      end;{$endif PREPROCWRITE}{*****************************************************************************                              TPreProcStack*****************************************************************************}    constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);      begin        accept:=a;        typ:=atyp;        next:=n;      end;{*****************************************************************************                              TReplayStack*****************************************************************************}    constructor treplaystack.Create(atoken:ttoken;aidtoken:ttoken;      const aorgpattern,apattern:string;const acstringpattern:ansistring;      apatternw:tcompilerwidestring;asettings:tsettings;      atokenbuf:tdynamicarray;change_endian:boolean;const apending:tpendingstate;      averbosity:longint;anext:treplaystack);      begin        token:=atoken;        idtoken:=aidtoken;        orgpattern:=aorgpattern;        pattern:=apattern;        cstringpattern:=acstringpattern;        initwidestring(patternw);        if assigned(apatternw) then          begin            copywidestring(patternw,apatternw);          end;        settings:=asettings;        pending:=apending;        verbosity:=averbosity;        tokenbuf:=atokenbuf;        tokenbuf_needs_swapping:=change_endian;        next:=anext;      end;    destructor treplaystack.destroy;      begin        donewidestring(patternw);      end;{*****************************************************************************                              TDirectiveItem*****************************************************************************}    constructor TDirectiveItem.Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);      begin        inherited Create(AList,n);        is_conditional:=false;        proc:=p;      end;    constructor TDirectiveItem.CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);      begin        inherited Create(AList,n);        is_conditional:=true;        proc:=p;      end;{****************************************************************************                                TSCANNERFILE ****************************************************************************}    constructor tscannerfile.Create(const fn: string; is_macro: boolean);      begin        inputfile:=do_openinputfile(fn);        if is_macro then          inputfile.is_macro:=true;        if assigned(current_module) then          current_module.sourcefiles.register_file(inputfile);      { reset localinput }        c:=#0;{$ifdef CHECK_INPUTPOINTER_LIMITS}        hidden_inputbuffer:=nil;        hidden_inputpointer:=nil;{$else not CHECK_INPUTPOINTER_LIMITS}        inputbuffer:=nil;        inputpointer:=nil;{$endif CHECK_INPUTPOINTER_LIMITS}        inputstart:=0;      { reset scanner }        preprocstack:=nil;        replaystack:=nil;        comment_level:=0;        yylexcount:=0;        block_type:=bt_general;        line_no:=0;        lastlinepos:=0;        lasttokenpos:=0;        nexttokenpos:=0;        lasttoken:=NOTOKEN;        nexttoken:=NOTOKEN;        ignoredirectives:=TFPHashList.Create;        change_endian_for_replay:=false;      end;    procedure tscannerfile.firstfile;      begin      { load block }        if not openinputfile then          Message1(scan_f_cannot_open_input,inputfile.name);        reload;      end;    destructor tscannerfile.Destroy;      begin        if assigned(onfreescanner) then          onfreescanner(self);        if assigned(current_module) and           (current_module.state in [ms_processed,ms_compiled]) and           (status.errorcount=0) then          checkpreprocstack        else          begin            while assigned(preprocstack) do             poppreprocstack;          end;        while assigned(replaystack) do          popreplaystack;        if not inputfile.closed then          closeinputfile;        if inputfile.is_macro then          inputfile.free;        ignoredirectives.free;      end;    function tscannerfile.openinputfile:boolean;      begin        openinputfile:=inputfile.open;      { load buffer }{$ifdef CHECK_INPUTPOINTER_LIMITS}        hidden_inputbuffer:=PAnsiChar(inputfile.buf);        hidden_inputpointer:=PAnsiChar(inputfile.buf);{$else not CHECK_INPUTPOINTER_LIMITS}        inputbuffer:=PAnsiChar(inputfile.buf);        inputpointer:=PAnsiChar(inputfile.buf);{$endif CHECK_INPUTPOINTER_LIMITS}        inputstart:=inputfile.bufstart;      { line }        line_no:=0;        lastlinepos:=0;        lasttokenpos:=0;        nexttokenpos:=0;      end;    procedure tscannerfile.closeinputfile;      begin        inputfile.close;      { reset buffer }{$ifdef CHECK_INPUTPOINTER_LIMITS}        hidden_inputbuffer:=nil;        hidden_inputpointer:=nil;{$else not CHECK_INPUTPOINTER_LIMITS}        inputbuffer:=nil;        inputpointer:=nil;{$endif CHECK_INPUTPOINTER_LIMITS}        inputstart:=0;      { reset line }        line_no:=0;        lastlinepos:=0;        lasttokenpos:=0;        nexttokenpos:=0;      end;    function tscannerfile.tempopeninputfile:boolean;      begin        tempopeninputfile:=false;        if inputfile.is_macro then          exit;        tempopeninputfile:=inputfile.tempopen;      { reload buffer }{$ifdef CHECK_INPUTPOINTER_LIMITS}        hidden_inputbuffer:=PAnsiChar(inputfile.buf);        hidden_inputpointer:=PAnsiChar(inputfile.buf);{$else not CHECK_INPUTPOINTER_LIMITS}        inputbuffer:=PAnsiChar(inputfile.buf);        inputpointer:=PAnsiChar(inputfile.buf);{$endif CHECK_INPUTPOINTER_LIMITS}        inputstart:=inputfile.bufstart;      end;    procedure tscannerfile.tempcloseinputfile;      begin        if inputfile.closed or inputfile.is_macro then         exit;{$ifdef CHECK_INPUTPOINTER_LIMITS}        inputfile.setpos(inputstart+(hidden_inputpointer-hidden_inputbuffer));{$else not CHECK_INPUTPOINTER_LIMITS}        inputfile.setpos(inputstart+(inputpointer-inputbuffer));{$endif CHECK_INPUTPOINTER_LIMITS}        inputfile.tempclose;      { reset buffer }{$ifdef CHECK_INPUTPOINTER_LIMITS}        hidden_inputbuffer:=nil;        hidden_inputpointer:=nil;{$else not CHECK_INPUTPOINTER_LIMITS}        inputbuffer:=nil;        inputpointer:=nil;{$endif CHECK_INPUTPOINTER_LIMITS}        inputstart:=0;      end;    procedure tscannerfile.saveinputfile;      begin{$ifdef CHECK_INPUTPOINTER_LIMITS}        inputfile.saveinputpointer:=hidden_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}        inputfile.saveinputpointer:=inputpointer;{$endif CHECK_INPUTPOINTER_LIMITS}        inputfile.savelastlinepos:=lastlinepos;        inputfile.saveline_no:=line_no;      end;    procedure tscannerfile.restoreinputfile;      begin{$ifdef check_inputpointer_limits}        hidden_inputbuffer:=PAnsiChar(inputfile.buf);        hidden_inputpointer:=inputfile.saveinputpointer;{$else not check_inputpointer_limits}        inputbuffer:=PAnsiChar(inputfile.buf);        inputpointer:=inputfile.saveinputpointer;{$endif check_inputpointer_limits}        lastlinepos:=inputfile.savelastlinepos;        line_no:=inputfile.saveline_no;        if not inputfile.is_macro then          parser_current_file:=inputfile.name;      end;    procedure tscannerfile.nextfile;      var        to_dispose : tinputfile;      begin        if assigned(inputfile.next) then         begin           if inputfile.is_macro then             begin               to_dispose:=inputfile;               dec(macro_nesting_depth);             end           else             begin               to_dispose:=nil;               dec(inputfilecount);             end;           { we can allways close the file, no ? }           inputfile.close;           inputfile:=inputfile.next;           if assigned(to_dispose) then             to_dispose.free;           restoreinputfile;         end;      end;{$ifdef CHECK_INPUTPOINTER_LIMITS}    function tscannerfile.get_inputpointer_char(offset : longint = 0) : char;      begin	assert(hidden_inputpointer-hidden_inputbuffer+offset<=inputfile.bufsize);	get_inputpointer_char:=(hidden_inputpointer+offset)^;      end;    procedure tscannerfile.inc_inputpointer(amount : longint = 1);      begin        assert(hidden_inputpointer-hidden_inputbuffer+amount<=inputfile.bufsize);        inc(hidden_inputpointer,amount);      end;    procedure tscannerfile.dec_inputpointer;      begin        assert(hidden_inputpointer>hidden_inputbuffer);        dec(hidden_inputpointer);      end;{$endif}    procedure tscannerfile.startrecordtokens(buf:tdynamicarray);      begin        if not assigned(buf) then          internalerror(200511172);        if assigned(recordtokenbuf) then          internalerror(200511173);        recordtokenbuf:=buf;        fillchar(last_settings,sizeof(last_settings),0);        last_message:=nil;        fillchar(last_filepos,sizeof(last_filepos),0);      end;    procedure tscannerfile.stoprecordtokens;      begin        if not assigned(recordtokenbuf) then          internalerror(200511174);        recordtokenbuf:=nil;      end;    function tscannerfile.is_recording_tokens: boolean;      begin        result:=assigned(recordtokenbuf);      end;    procedure tscannerfile.writetoken(t : ttoken);      var        b : byte;      begin        if ord(t)>$7f then          begin            b:=(ord(t) shr 8) or $80;            recordtokenbuf.write(b,1);          end;        b:=ord(t) and $ff;        recordtokenbuf.write(b,1);      end;    procedure tscannerfile.tokenwritesizeint(val : asizeint);      begin        recordtokenbuf.write(val,sizeof(asizeint));      end;    procedure tscannerfile.tokenwritelongint(val : longint);      begin        recordtokenbuf.write(val,sizeof(longint));      end;    procedure tscannerfile.tokenwriteshortint(val : shortint);      begin        recordtokenbuf.write(val,sizeof(shortint));      end;    procedure tscannerfile.tokenwritebyte(val : byte);      begin{$ifdef FPC_BIG_ENDIAN}        val:=swapendian(val);{$endif}        recordtokenbuf.write(val,sizeof(byte));      end;    procedure tscannerfile.tokenwriteword(val : word);      begin        recordtokenbuf.write(val,sizeof(word));      end;    procedure tscannerfile.tokenwritelongword(val : longword);      begin        recordtokenbuf.write(val,sizeof(longword));      end;    function tscannerfile.tokenreadsizeint : asizeint;      var        val : asizeint;      begin        replaytokenbuf.read(val,sizeof(asizeint));        if change_endian_for_replay then          val:=swapendian(val);        result:=val;      end;    function tscannerfile.tokenreadlongword : longword;      var        val : longword;      begin        replaytokenbuf.read(val,sizeof(longword));        if change_endian_for_replay then          val:=swapendian(val);        result:=val;      end;    function tscannerfile.tokenreadlongint : longint;      var        val : longint;      begin        replaytokenbuf.read(val,sizeof(longint));        if change_endian_for_replay then          val:=swapendian(val);        result:=val;      end;    function tscannerfile.tokenreadshortint : shortint;      var        val : shortint;      begin        replaytokenbuf.read(val,sizeof(shortint));        result:=val;      end;    function tscannerfile.tokenreadbyte : byte;      var        val : byte;      begin        replaytokenbuf.read(val,sizeof(byte));        result:=val;      end;    function tscannerfile.tokenreadsmallint : smallint;      var        val : smallint;      begin        replaytokenbuf.read(val,sizeof(smallint));        if change_endian_for_replay then          val:=swapendian(val);        result:=val;      end;    function tscannerfile.tokenreadword : word;      var        val : word;      begin        replaytokenbuf.read(val,sizeof(word));        if change_endian_for_replay then          val:=swapendian(val);        result:=val;      end;   function tscannerfile.tokenreadenum(size : longint) : longword;   begin     if size=1 then       result:=tokenreadbyte     else if size=2 then       result:=tokenreadword     else if size=4 then       result:=tokenreadlongword     else       internalerror(2013112901);   end;   procedure tscannerfile.tokenreadset(var b;size : longint);   var     i : longint;   begin     replaytokenbuf.read(b,size);     if change_endian_for_replay then       for i:=0 to size-1 do         Pbyte(@b)[i]:=reverse_byte(Pbyte(@b)[i]);   end;   procedure tscannerfile.tokenwriteenum(var b;size : longint);   begin     recordtokenbuf.write(b,size);   end;   procedure tscannerfile.tokenwriteset(var b;size : longint);   begin     recordtokenbuf.write(b,size);   end;    procedure tscannerfile.tokenreadsettings(var asettings : tsettings; expected_size : asizeint);    {    This procedure       needs to be changed whenever       globals.tsettings type is changed,       the problem is that no error will appear       before tests with generics are tested. PM }       var         startpos, endpos : longword;      begin        { WARNING all those fields need to be in the correct        order otherwise cross_endian PPU reading will fail }        startpos:=replaytokenbuf.pos;        with asettings do          begin            alignment.procalign:=tokenreadlongint;            alignment.loopalign:=tokenreadlongint;            alignment.jumpalign:=tokenreadlongint;            alignment.jumpalignskipmax:=tokenreadlongint;            alignment.coalescealign:=tokenreadlongint;            alignment.coalescealignskipmax:=tokenreadlongint;            alignment.constalignmin:=tokenreadlongint;            alignment.constalignmax:=tokenreadlongint;            alignment.varalignmin:=tokenreadlongint;            alignment.varalignmax:=tokenreadlongint;            alignment.localalignmin:=tokenreadlongint;            alignment.localalignmax:=tokenreadlongint;            alignment.recordalignmin:=tokenreadlongint;            alignment.recordalignmax:=tokenreadlongint;            alignment.maxCrecordalign:=tokenreadlongint;            tokenreadset(globalswitches,sizeof(globalswitches));            tokenreadset(targetswitches,sizeof(targetswitches));            tokenreadset(moduleswitches,sizeof(moduleswitches));            tokenreadset(localswitches,sizeof(localswitches));            tokenreadset(modeswitches,sizeof(modeswitches));            tokenreadset(optimizerswitches,sizeof(optimizerswitches));            tokenreadset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));            tokenreadset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));            tokenreadset(debugswitches,sizeof(debugswitches));            { 0: old behaviour for sets <=256 elements              >0: round to this size }            setalloc:=tokenreadshortint;            packenum:=tokenreadshortint;            packrecords:=tokenreadshortint;            maxfpuregisters:=tokenreadshortint;            verbosity:=tokenreadlongint;            cputype:=tcputype(tokenreadenum(sizeof(tcputype)));            optimizecputype:=tcputype(tokenreadenum(sizeof(tcputype)));            fputype:=tfputype(tokenreadenum(sizeof(tfputype)));            asmmode:=tasmmode(tokenreadenum(sizeof(tasmmode)));            interfacetype:=tinterfacetypes(tokenreadenum(sizeof(tinterfacetypes)));            defproccall:=tproccalloption(tokenreadenum(sizeof(tproccalloption)));            { tstringencoding is word type,              thus this should be OK here }            sourcecodepage:=tstringEncoding(tokenreadword);            minfpconstprec:=tfloattype(tokenreadenum(sizeof(tfloattype)));            disabledircache:=boolean(tokenreadbyte);            tlsmodel:=ttlsmodel(tokenreadenum(sizeof(ttlsmodel)));{ TH: Since the field was conditional originally, it was not stored in PPUs.  }{ While adding ControllerSupport constant, I decided not to store ct_none     }{ on targets not supporting controllers, but this might be changed here and   }{ in tokenwritesettings in the future to unify the PPU structure and handling }{ of this field in the compiler.                                              }{$PUSH} {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)            if ControllerSupport then             controllertype:=tcontrollertype(tokenreadenum(sizeof(tcontrollertype)))            else             ControllerType:=ct_none;{$POP}            lineendingtype:=tlineendingtype(tokenreadenum(sizeof(tlineendingtype)));            whitespacetrimcount:=tokenreadword;            whitespacetrimauto:=boolean(tokenreadbyte);           endpos:=replaytokenbuf.pos;           if endpos-startpos<>expected_size then             Comment(V_Error,'Wrong size of Settings read-in');         end;     end;    procedure tscannerfile.tokenwritesettings(var asettings : tsettings; var size : asizeint);    {    This procedure       needs to be changed whenever       globals.tsettings type is changed,       the problem is that no error will appear       before tests with generics are tested. PM }       var         sizepos, startpos, endpos : longword;      begin        { WARNING all those fields need to be in the correct        order otherwise cross_endian PPU reading will fail }        sizepos:=recordtokenbuf.pos;        size:=0;        tokenwritesizeint(size);        startpos:=recordtokenbuf.pos;        with asettings do          begin            tokenwritelongint(alignment.procalign);            tokenwritelongint(alignment.loopalign);            tokenwritelongint(alignment.jumpalign);            tokenwritelongint(alignment.jumpalignskipmax);            tokenwritelongint(alignment.coalescealign);            tokenwritelongint(alignment.coalescealignskipmax);            tokenwritelongint(alignment.constalignmin);            tokenwritelongint(alignment.constalignmax);            tokenwritelongint(alignment.varalignmin);            tokenwritelongint(alignment.varalignmax);            tokenwritelongint(alignment.localalignmin);            tokenwritelongint(alignment.localalignmax);            tokenwritelongint(alignment.recordalignmin);            tokenwritelongint(alignment.recordalignmax);            tokenwritelongint(alignment.maxCrecordalign);            tokenwriteset(globalswitches,sizeof(globalswitches));            tokenwriteset(targetswitches,sizeof(targetswitches));            tokenwriteset(moduleswitches,sizeof(moduleswitches));            tokenwriteset(localswitches,sizeof(localswitches));            tokenwriteset(modeswitches,sizeof(modeswitches));            tokenwriteset(optimizerswitches,sizeof(optimizerswitches));            tokenwriteset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));            tokenwriteset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));            tokenwriteset(debugswitches,sizeof(debugswitches));            { 0: old behaviour for sets <=256 elements              >0: round to this size }            tokenwriteshortint(setalloc);            tokenwriteshortint(packenum);            tokenwriteshortint(packrecords);            tokenwriteshortint(maxfpuregisters);            tokenwritelongint(verbosity);            tokenwriteenum(cputype,sizeof(tcputype));            tokenwriteenum(optimizecputype,sizeof(tcputype));            tokenwriteenum(fputype,sizeof(tfputype));            tokenwriteenum(asmmode,sizeof(tasmmode));            tokenwriteenum(interfacetype,sizeof(tinterfacetypes));            tokenwriteenum(defproccall,sizeof(tproccalloption));            { tstringencoding is word type,              thus this should be OK here }            tokenwriteword(sourcecodepage);            tokenwriteenum(minfpconstprec,sizeof(tfloattype));            recordtokenbuf.write(byte(disabledircache),1);            tokenwriteenum(tlsmodel,sizeof(tlsmodel));{ TH: See note about controllertype field in tokenreadsettings. }{$PUSH} {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)            if ControllerSupport then              tokenwriteenum(controllertype,sizeof(tcontrollertype));{$POP}            tokenwriteenum(lineendingtype,sizeof(tlineendingtype));            tokenwriteword(whitespacetrimcount);            tokenwritebyte(byte(whitespacetrimauto));           endpos:=recordtokenbuf.pos;           size:=endpos-startpos;           recordtokenbuf.seek(sizepos);           tokenwritesizeint(size);           recordtokenbuf.seek(endpos);         end;     end;    procedure tscannerfile.recordtoken;      var        t : ttoken;        s : tspecialgenerictoken;        len,msgnb,copy_size : asizeint;        val : longint;        b : byte;        pmsg : pmessagestaterecord;      begin        if not assigned(recordtokenbuf) then          internalerror(200511176);        t:=_GENERICSPECIALTOKEN;        { ensure that all fields of settings are up to date }        current_settings.verbosity:=status.verbosity;        { settings changed? }        { last field pmessage is handled separately below in          ST_LOADMESSAGES }        if CompareByte(current_settings,last_settings,             sizeof(current_settings)-sizeof(pointer))<>0 then          begin            { use a special token to record it }            s:=ST_LOADSETTINGS;            writetoken(t);            recordtokenbuf.write(s,1);            copy_size:=sizeof(current_settings)-sizeof(pointer);            tokenwritesettings(current_settings,copy_size);            last_settings:=current_settings;          end;        if current_settings.pmessage<>last_message then          begin            { use a special token to record it }            s:=ST_LOADMESSAGES;            writetoken(t);            recordtokenbuf.write(s,1);            msgnb:=0;            pmsg:=current_settings.pmessage;            while assigned(pmsg) do              begin                if msgnb=high(asizeint) then                  { Too many messages }                  internalerror(2011090401);                inc(msgnb);                pmsg:=pmsg^.next;              end;            tokenwritesizeint(msgnb);            pmsg:=current_settings.pmessage;            while assigned(pmsg) do              begin                { What about endianess here?}                { SB: this is handled by tokenreadlongint }                val:=pmsg^.value;                tokenwritelongint(val);                val:=ord(pmsg^.state);                tokenwritelongint(val);                pmsg:=pmsg^.next;              end;            last_message:=current_settings.pmessage;          end;        { file pos changes? }        if current_tokenpos.fileindex<>last_filepos.fileindex then          begin            s:=ST_FILEINDEX;            writetoken(t);            recordtokenbuf.write(s,1);            tokenwriteword(current_tokenpos.fileindex);            last_filepos.fileindex:=current_tokenpos.fileindex;            last_filepos.line:=0;          end;        if current_tokenpos.line<>last_filepos.line then          begin            s:=ST_LINE;            writetoken(t);            recordtokenbuf.write(s,1);            tokenwritelongint(current_tokenpos.line);            last_filepos.line:=current_tokenpos.line;            last_filepos.column:=0;          end;        if current_tokenpos.column<>last_filepos.column then          begin            s:=ST_COLUMN;            writetoken(t);            { can the column be written packed? }            if current_tokenpos.column<$80 then              begin                b:=$80 or current_tokenpos.column;                recordtokenbuf.write(b,1);              end            else              begin                recordtokenbuf.write(s,1);                tokenwriteword(current_tokenpos.column);              end;            last_filepos.column:=current_tokenpos.column;          end;        writetoken(token);        if token<>_GENERICSPECIALTOKEN then          writetoken(idtoken);        case token of          _CWCHAR,          _CWSTRING :            begin              tokenwritesizeint(patternw.len);              if patternw.len>0 then                recordtokenbuf.write(patternw.data[0],patternw.len*sizeof(tcompilerwidechar));            end;          _CSTRING:            begin              len:=length(cstringpattern);              tokenwritesizeint(len);              if len>0 then                recordtokenbuf.write(cstringpattern[1],len);            end;          _CCHAR,          _INTCONST,          _REALNUMBER :            begin              { pexpr.pas messes with pattern in case of negative integer consts,                see around line 2562 the comment of JM; remove the - before recording it                                                     (FK)              }              if (token=_INTCONST) and (pattern[1]='-') then                delete(pattern,1,1);              recordtokenbuf.write(pattern[0],1);              recordtokenbuf.write(pattern[1],length(pattern));            end;          _ID :            begin              recordtokenbuf.write(orgpattern[0],1);              recordtokenbuf.write(orgpattern[1],length(orgpattern));            end;          else            ;        end;      end;    procedure tscannerfile.startreplaytokens(buf:tdynamicarray; change_endian:boolean);      begin        if not assigned(buf) then          internalerror(200511175);        { save current scanner state }        replaystack:=treplaystack.create(token,idtoken,orgpattern,pattern,          cstringpattern,patternw,current_settings,replaytokenbuf,change_endian_for_replay,          pendingstate,status.verbosity,replaystack);{$ifdef check_inputpointer_limits}        if assigned(hidden_inputpointer) then          dec_inputpointer;{$else not check_inputpointer_limits}        if assigned(inputpointer) then          dec(inputpointer);{$endif check_inputpointer_limits}        { install buffer }        replaytokenbuf:=buf;        { ensure that existing message state records won't be freed }        current_settings.pmessage:=nil;        pendingstate:=default(tpendingstate);        { Initialize value of change_endian_for_replay variable }        change_endian_for_replay:=change_endian;        { reload next token }        replaytokenbuf.seek(0);        replaytoken;      end;    function tscannerfile.readtoken: ttoken;      var        b,b2 : byte;      begin        replaytokenbuf.read(b,1);        if (b and $80)<>0 then          begin            replaytokenbuf.read(b2,1);            result:=ttoken(((b and $7f) shl 8) or b2);          end        else          result:=ttoken(b);      end;    procedure tscannerfile.replaytoken;      var        wlen,mesgnb,copy_size : asizeint;        specialtoken : tspecialgenerictoken;        i : byte;        pmsg,prevmsg : pmessagestaterecord;        msgset : thashset;        msgfound : boolean;      begin        if not assigned(replaytokenbuf) then          internalerror(200511177);        { End of replay buffer? Then load the next char from the file again }        if replaytokenbuf.pos>=replaytokenbuf.size then          begin            token:=replaystack.token;            idtoken:=replaystack.idtoken;            pattern:=replaystack.pattern;            orgpattern:=replaystack.orgpattern;            copywidestring(replaystack.patternw,patternw);            cstringpattern:=replaystack.cstringpattern;            replaytokenbuf:=replaystack.tokenbuf;            change_endian_for_replay:=replaystack.tokenbuf_needs_swapping;            { restore compiler settings }            current_settings:=replaystack.settings;            pendingstate:=replaystack.pending;            if assigned(pendingstate.nextmessagerecord) then              FreeLocalVerbosity(pendingstate.nextmessagerecord);            recordpendingverbosityfullswitch(replaystack.verbosity);            pendingstate.nextmessagerecord:=current_settings.pmessage;            current_settings.pmessage:=nil;            popreplaystack;{$ifdef check_inputpointer_limits}            if assigned(hidden_inputpointer) then              begin                c:=get_inputpointer_char;                inc_inputpointer;              end;{$else not check_inputpointer_limits}            if assigned(inputpointer) then              begin                c:=inputpointer^;                inc(inputpointer);              end;{$endif check_inputpointer_limits}            exit;          end;        repeat          { load token from the buffer }          token:=readtoken;          if token<>_GENERICSPECIALTOKEN then            idtoken:=readtoken          else            idtoken:=_NOID;          case token of            _CWCHAR,            _CWSTRING :              begin                wlen:=tokenreadsizeint;                setlengthwidestring(patternw,wlen);                if wlen>0 then                  replaytokenbuf.read(patternw.data[0],patternw.len*sizeof(tcompilerwidechar));                orgpattern:='';                pattern:='';                cstringpattern:='';              end;            _CSTRING:              begin                wlen:=tokenreadsizeint;                if wlen>0 then                  begin                    setlength(cstringpattern,wlen);                    replaytokenbuf.read(cstringpattern[1],wlen);                  end                else                  cstringpattern:='';                orgpattern:='';                pattern:='';              end;            _CCHAR,            _INTCONST,            _REALNUMBER :              begin                replaytokenbuf.read(pattern[0],1);                replaytokenbuf.read(pattern[1],length(pattern));                orgpattern:='';              end;            _ID :              begin                replaytokenbuf.read(orgpattern[0],1);                replaytokenbuf.read(orgpattern[1],length(orgpattern));                pattern:=upper(orgpattern);              end;            _GENERICSPECIALTOKEN:              begin                replaytokenbuf.read(specialtoken,1);                { packed column? }                if (ord(specialtoken) and $80)<>0 then                  begin                      current_tokenpos.column:=ord(specialtoken) and $7f;                      current_filepos:=current_tokenpos;                  end                else                  case specialtoken of                    ST_LOADSETTINGS:                      begin                        copy_size:=tokenreadsizeint;                        //if copy_size <> sizeof(current_settings)-sizeof(pointer) then                        //  internalerror(2011090501);                        {                        replaytokenbuf.read(current_settings,copy_size);                        }                        tokenreadsettings(current_settings,copy_size);                        recordpendingverbosityfullswitch(current_settings.verbosity);                      end;                    ST_LOADMESSAGES:                      begin                        { free current and pending messages }                        FreeLocalVerbosity(current_settings.pmessage);                        FreeLocalVerbosity(pendingstate.nextmessagerecord);                        { the message settings are stored from newest to oldest                          change for the whole stack, so we only want to apply                          the newest changes for each message type }                        mesgnb:=tokenreadsizeint;                        msgset:=thashset.create(min(mesgnb,10),false,false);                        prevmsg:=nil;                        pmsg:=nil;                        for i:=1 to mesgnb do                          begin                            if not assigned(pmsg) then                              new(pmsg);                            pmsg^.value:=tokenreadlongint;                            pmsg^.state:=tmsgstate(tokenreadlongint);                            pmsg^.next:=nil;                            msgfound:=false;                            if assigned(msgset.findoradd(@pmsg^.value,sizeof(pmsg^.value),msgfound)) and msgfound then                              continue;                            if i=1 then                              pendingstate.nextmessagerecord:=pmsg                            else                              prevmsg^.next:=pmsg;                            prevmsg:=pmsg;                            pmsg:=nil;                          end;                        if assigned(pmsg) then                          dispose(pmsg);                        msgset.free;                      end;                    ST_LINE:                      begin                        current_tokenpos.line:=tokenreadlongint;                        current_filepos:=current_tokenpos;                      end;                    ST_COLUMN:                      begin                        current_tokenpos.column:=tokenreadword;                        current_filepos:=current_tokenpos;                      end;                    ST_FILEINDEX:                      begin                        current_tokenpos.fileindex:=tokenreadword;                        current_filepos:=current_tokenpos;                      end;                  end;                continue;              end;            else              ;          end;          break;        until false;      end;    procedure tscannerfile.addfile(hp:tinputfile);      begin        saveinputfile;        { add to list }        hp.next:=inputfile;        inputfile:=hp;        { load new inputfile }        restoreinputfile;      end;    procedure tscannerfile.reload;      var        wasmacro: Boolean;      begin        with inputfile do         begin           { when nothing more to read then leave immediatly, so we             don't change the current_filepos and leave it point to the last             char }           if (c=#26) and (not assigned(next)) then            exit;           repeat           { still more to read?, then change the #0 to a space so its seen             as a separator, this can't be used for macro's which can change             the place of the #0 in the buffer with tempopen }             if (c=#0) and (bufsize>0) and                not(inputfile.is_macro) and{$ifdef CHECK_INPUTPOINTER_LIMITS}                (hidden_inputpointer-hidden_inputbuffer<bufsize) then{$else not CHECK_INPUTPOINTER_LIMITS}                (inputpointer-inputbuffer<bufsize) then{$endif CHECK_INPUTPOINTER_LIMITS}              begin                c:=' ';{$ifdef CHECK_INPUTPOINTER_LIMITS}                inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}                inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}                exit;              end;           { can we read more from this file ? }             if (c<>#26) and (not endoffile) then              begin                readbuf;{$ifdef CHECK_INPUTPOINTER_LIMITS}                hidden_inputpointer:=PAnsiChar(buf);                hidden_inputbuffer:=PAnsiChar(buf);{$else not CHECK_INPUTPOINTER_LIMITS}                inputpointer:=PAnsiChar(buf);                inputbuffer:=PAnsiChar(buf);{$endif CHECK_INPUTPOINTER_LIMITS}                inputstart:=bufstart;              { first line? }                if line_no=0 then                 begin{$ifdef CHECK_INPUTPOINTER_LIMITS}                   c:=get_inputpointer_char;                   { eat utf-8 signature? }                   if (bufsize>2) and                     (ord(get_inputpointer_char)=$ef) and                     (ord(get_inputpointer_char(1))=$bb) and                     (ord(get_inputpointer_char(2))=$bf) then                     begin{$else not CHECK_INPUTPOINTER_LIMITS}                   c:=inputpointer^;                   { eat utf-8 signature? }                   if (bufsize>2) and                     (ord(inputpointer^)=$ef) and                     (ord((inputpointer+1)^)=$bb) and                     (ord((inputpointer+2)^)=$bf) then                     begin{$endif CHECK_INPUTPOINTER_LIMITS}                       (* we don't support including files with an UTF-8 bom                          inside another file that wasn't encoded as UTF-8                          already (we don't support {$codepage xxx} switches in                          the middle of a file either) *)                       if (current_settings.sourcecodepage<>CP_UTF8) and                          not current_module.in_global then                         Message(scanner_f_illegal_utf8_bom);{$ifdef CHECK_INPUTPOINTER_LIMITS}                       inc_inputpointer(3);{$else not CHECK_INPUTPOINTER_LIMITS}                       inc(inputpointer,3);{$endif CHECK_INPUTPOINTER_LIMITS}                       message(scan_c_switching_to_utf8);                       current_settings.sourcecodepage:=CP_UTF8;                       exclude(current_settings.moduleswitches,cs_system_codepage);                       include(current_settings.moduleswitches,cs_explicit_codepage);                     end;                   line_no:=1;                   if cs_asm_source in current_settings.globalswitches then{$ifdef CHECK_INPUTPOINTER_LIMITS}                     inputfile.setline(line_no,inputstart+hidden_inputpointer-hidden_inputbuffer);{$else not CHECK_INPUTPOINTER_LIMITS}                     inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);{$endif CHECK_INPUTPOINTER_LIMITS}                 end;              end             else              begin                wasmacro:=inputfile.is_macro;              { load eof position in tokenpos/current_filepos }                gettokenpos;              { close file }                closeinputfile;              { no next module, than EOF }                if not assigned(inputfile.next) then                 begin                   c:=#26;                   exit;                 end;              { load next file and reopen it }                nextfile;                tempopeninputfile;              { status }                Message1(scan_t_back_in,inputfile.name);              { end of include file is like a line break which ends e.g. also // style comments }                if not(wasmacro) and (current_commentstyle=comment_delphi) then                  begin                    c:=#10;                  { ... but we have to decrease the line number first because it is increased due to this                    inserted line break later on }                    dec(line_no);                    exit;                  end;              end;           { load next char }{$ifdef CHECK_INPUTPOINTER_LIMITS}             c:=get_inputpointer_char;             inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}             c:=inputpointer^;             inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}           until c<>#0; { if also end, then reload again }         end;      end;    procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);      var        hp : tinputfile;      begin        { save old postion }{$ifdef CHECK_INPUTPOINTER_LIMITS}        dec_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}        dec(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}        tempcloseinputfile;      { create macro 'file' }        { use special name to dispose after !! }        hp:=do_openinputfile('_Macro_.'+macname);        addfile(hp);        with inputfile do         begin           inc(macro_nesting_depth);           setmacro(p,len);         { local buffer }{$ifdef CHECK_INPUTPOINTER_LIMITS}           hidden_inputbuffer:=PAnsiChar(buf);           hidden_inputpointer:=PAnsiChar(buf);{$else not CHECK_INPUTPOINTER_LIMITS}           inputbuffer:=PAnsiChar(buf);           inputpointer:=PAnsiChar(buf);{$endif CHECK_INPUTPOINTER_LIMITS}           inputstart:=bufstart;           ref_index:=fileindex;           internally_generated_macro:=internally_generated;         end;      { reset line }        line_no:=line;        lastlinepos:=0;        lasttokenpos:=0;        nexttokenpos:=0;      { load new c }{$ifdef CHECK_INPUTPOINTER_LIMITS}        c:=get_inputpointer_char;        inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}        c:=inputpointer^;        inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}      end;    procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);      begin{$ifdef CHECK_INPUTPOINTER_LIMITS}        tokenpos:=inputstart+(hidden_inputpointer-hidden_inputbuffer);{$else not CHECK_INPUTPOINTER_LIMITS}        tokenpos:=inputstart+(inputpointer-inputbuffer);{$endif CHECK_INPUTPOINTER_LIMITS}        filepos.line:=line_no;        filepos.column:=tokenpos-lastlinepos;        filepos.fileindex:=inputfile.ref_index;        filepos.moduleindex:=current_module.unit_index;      end;    procedure tscannerfile.gettokenpos;    { load the values of tokenpos and lasttokenpos }      begin        do_gettokenpos(lasttokenpos,current_tokenpos);        current_filepos:=current_tokenpos;      end;    procedure tscannerfile.cachenexttokenpos;      begin        do_gettokenpos(nexttokenpos,next_filepos);      end;    procedure tscannerfile.setnexttoken;      begin        token:=nexttoken;        nexttoken:=NOTOKEN;        lasttokenpos:=nexttokenpos;        current_tokenpos:=next_filepos;        current_filepos:=current_tokenpos;        nexttokenpos:=0;      end;    procedure tscannerfile.savetokenpos;      begin        oldlasttokenpos:=lasttokenpos;        oldcurrent_filepos:=current_filepos;        oldcurrent_tokenpos:=current_tokenpos;      end;    procedure tscannerfile.restoretokenpos;      begin        lasttokenpos:=oldlasttokenpos;        current_filepos:=oldcurrent_filepos;        current_tokenpos:=oldcurrent_tokenpos;      end;    procedure tscannerfile.inc_comment_level;      begin         if (m_nested_comment in current_settings.modeswitches) then           inc(comment_level)         else           comment_level:=1;         if (comment_level>1) then          begin             savetokenpos;             gettokenpos; { update for warning }             Message1(scan_w_comment_level,tostr(comment_level));             restoretokenpos;          end;      end;    procedure tscannerfile.dec_comment_level;      begin         if (m_nested_comment in current_settings.modeswitches) then           dec(comment_level)         else           comment_level:=0;      end;    procedure tscannerfile.linebreak;      var         cur : char;      begin        with inputfile do         begin{$ifdef CHECK_INPUTPOINTER_LIMITS}           if (byte(get_inputpointer_char)=0) and not(endoffile) then{$else not CHECK_INPUTPOINTER_LIMITS}           if (byte(inputpointer^)=0) and not(endoffile) then{$endif CHECK_INPUTPOINTER_LIMITS}             begin               cur:=c;               reload;               if byte(cur)+byte(c)<>23 then{$ifdef CHECK_INPUTPOINTER_LIMITS}                 dec_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}                 dec(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}             end           else             begin               { Support all combination of #10 and #13 as line break }{$ifdef CHECK_INPUTPOINTER_LIMITS}               if (byte(get_inputpointer_char)+byte(c)=23) then                 inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}               if (byte(inputpointer^)+byte(c)=23) then                 inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}             end;           { Always return #10 as line break }           c:=#10;           { increase line counters }{$ifdef CHECK_INPUTPOINTER_LIMITS}           lastlinepos:=inputstart+(hidden_inputpointer-hidden_inputbuffer);{$else not CHECK_INPUTPOINTER_LIMITS}           lastlinepos:=inputstart+(inputpointer-inputbuffer);{$endif CHECK_INPUTPOINTER_LIMITS}           inc(line_no);           { update linebuffer }           if cs_asm_source in current_settings.globalswitches then             inputfile.setline(line_no,lastlinepos);           { update for status and call the show status routine,             but don't touch current_filepos ! }           savetokenpos;           gettokenpos; { update for v_status }           inc(status.compiledlines);           ShowStatus;           restoretokenpos;         end;      end;    procedure tscannerfile.illegal_char(c:char);      var        s : string;      begin        if c in [#32..#255] then          s:=''''+c+''''        else          s:='#'+tostr(ord(c));        Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));      end;    procedure tscannerfile.end_of_file;      begin        checkpreprocstack;        if in_multiline_string then          Message2(scan_f_unterminated_multiline_string, tostr(multiline_start_line), tostr(multiline_start_column))        else          Message(scan_f_end_of_file);      end;  {-------------------------------------------           IF Conditional Handling  -------------------------------------------}    procedure tscannerfile.checkpreprocstack;      begin      { check for missing ifdefs }        while assigned(preprocstack) do         begin           Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,             current_module.sourcefiles.get_file_name(preprocstack.fileindex),             tostr(preprocstack.line_nb));           poppreprocstack;         end;      end;    procedure tscannerfile.poppreprocstack;      var        hp : tpreprocstack;      begin        if assigned(preprocstack) then         begin           Message1(scan_c_endif_found,preprocstack.name);           hp:=preprocstack.next;           preprocstack.free;           preprocstack:=hp;         end        else         Message(scan_e_endif_without_if);      end;    procedure tscannerfile.ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);      var        condition: Boolean;        valuedescr: String;      begin        if (preprocstack=nil) or preprocstack.accept then          condition:=compile_time_predicate(valuedescr)        else          begin            condition:= false;            valuedescr:= '';          end;        preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);        preprocstack.name:=valuedescr;        preprocstack.line_nb:=line_no;        preprocstack.fileindex:=current_filepos.fileindex;        if preprocstack.accept then          Message2(messid,preprocstack.name,'accepted')        else          Message2(messid,preprocstack.name,'rejected');      end;    procedure tscannerfile.elsepreprocstack;      begin        if assigned(preprocstack) and           (preprocstack.typ<>pp_else) then         begin           if (preprocstack.typ=pp_elseif) then             preprocstack.accept:=false           else             if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then               preprocstack.accept:=not preprocstack.accept;           preprocstack.iftyp:=preprocstack.typ;           preprocstack.typ:=pp_else;           preprocstack.line_nb:=line_no;           preprocstack.fileindex:=current_filepos.fileindex;           if preprocstack.accept then            Message2(scan_c_else_found,preprocstack.name,'accepted')           else            Message2(scan_c_else_found,preprocstack.name,'rejected');         end        else         Message(scan_e_endif_without_if);      end;    procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);      var        valuedescr: String;      begin        if assigned(preprocstack) and           (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef,pp_elseif]) then         begin           { when the branch is accepted we use pp_elseif so we know that             all the next branches need to be rejected. when this branch is still             not accepted then leave it at pp_if }           if (preprocstack.typ=pp_elseif) then             preprocstack.accept:=false           else if (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef]) and preprocstack.accept then               begin                 preprocstack.accept:=false;                 preprocstack.typ:=pp_elseif;               end           else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))                   and compile_time_predicate(valuedescr) then               begin                 preprocstack.name:=valuedescr;                 preprocstack.accept:=true;                 preprocstack.typ:=pp_elseif;               end;           preprocstack.line_nb:=line_no;           preprocstack.fileindex:=current_filepos.fileindex;           if preprocstack.accept then             Message2(scan_c_else_found,preprocstack.name,'accepted')           else             Message2(scan_c_else_found,preprocstack.name,'rejected');         end        else         Message(scan_e_endif_without_if);      end;    procedure tscannerfile.popreplaystack;      var        hp : treplaystack;      begin        if assigned(replaystack) then         begin           hp:=replaystack.next;           replaystack.free;           replaystack:=hp;         end;      end;    function tscannerfile.replay_stack_depth:longint;      var        tmp: treplaystack;      begin        result:=0;        tmp:=replaystack;        while assigned(tmp) do          begin            inc(result);            tmp:=tmp.next;          end;      end;    procedure tscannerfile.handleconditional(p:tdirectiveitem);      begin        savetokenpos;        repeat          current_scanner.gettokenpos;          Message1(scan_d_handling_switch,'$'+p.name);          p.proc();          { accept the text ? }          if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then           break          else           begin             current_scanner.gettokenpos;             Message(scan_c_skipping_until);             repeat               current_scanner.skipuntildirective;               if not (m_mac in current_settings.modeswitches) then                 p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))               else                 p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));             until assigned(p) and (p.is_conditional);             current_scanner.gettokenpos;           end;        until false;        restoretokenpos;      end;    procedure tscannerfile.handledirectives;      var         t  : tdirectiveitem;         hs : string;      begin         gettokenpos;         readchar; {Remove the $}         hs:=readid;         { handle empty directive }         if hs='' then           begin             Message1(scan_w_illegal_switch,'$');             exit;           end;{$ifdef PREPROCWRITE}         if parapreprocess then          begin            if not (m_mac in current_settings.modeswitches) then              t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))            else              t:=tdirectiveitem(mac_scannerdirectives.Find(hs));            if assigned(t) and not(t.is_conditional) then             begin               preprocfile.AddSpace;               preprocfile.Add('{$'+hs+current_scanner.readcomment+'}');               exit;             end;          end;{$endif PREPROCWRITE}         { skip this directive? }         if (ignoredirectives.find(hs)<>nil) then          begin            if (comment_level>0) then             readcomment;            { we've read the whole comment }            current_commentstyle:=comment_none;            exit;          end;         { Check for compiler switches }         while (length(hs)=1) and (c in ['-','+']) do          begin            Message1(scan_d_handling_switch,'$'+hs+c);            HandleSwitch(hs[1],c);            current_scanner.readchar; {Remove + or -}            if c=',' then             begin               current_scanner.readchar;   {Remove , }               { read next switch, support $v+,$+}               hs:=current_scanner.readid;               if (hs='') then                begin                  if (c='$') and (m_fpc in current_settings.modeswitches) then                   begin                     current_scanner.readchar;  { skip $ }                     hs:=current_scanner.readid;                   end;                  if (hs='') then                   Message1(scan_w_illegal_directive,'$'+c);                end;             end            else             hs:='';          end;         { directives may follow switches after a , }         if hs<>'' then          begin            if not (m_mac in current_settings.modeswitches) then              t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))            else              t:=tdirectiveitem(mac_scannerdirectives.Find(hs));            if assigned(t) then             begin               if t.is_conditional then                handleconditional(t)               else                begin                  Message1(scan_d_handling_switch,'$'+hs);                  t.proc();                end;             end            else             begin               current_scanner.ignoredirectives.Add(hs,nil);               Message1(scan_w_illegal_directive,'$'+hs);             end;            { conditionals already read the comment }            if (current_scanner.comment_level>0) then             current_scanner.readcomment;            { we've read the whole comment }            current_commentstyle:=comment_none;          end;      end;    procedure tscannerfile.readchar;      begin{$ifdef CHECK_INPUTPOINTER_LIMITS}        c:=get_inputpointer_char;{$else not CHECK_INPUTPOINTER_LIMITS}        c:=inputpointer^;{$endif CHECK_INPUTPOINTER_LIMITS}        if c=#0 then          reload        else{$ifdef CHECK_INPUTPOINTER_LIMITS}          inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}          inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}      end;    procedure tscannerfile.readstring;      var        i : longint;        err : boolean;      begin        err:=false;        i:=0;        repeat          case c of            '_','$',            '0'..'9',            'A'..'Z',            'a'..'z' :              begin                if (c='$') and not allowgenericid then                  break;                if i<255 then                 begin                   inc(i);                   orgpattern[i]:=c;                   if c in ['a'..'z'] then                     pattern[i]:=chr(ord(c)-32)                   else                     pattern[i]:=c;                 end                else                 begin                   if not err then                     begin                       Message(scan_e_string_exceeds_255_chars);                       err:=true;                     end;                 end;{$ifdef CHECK_INPUTPOINTER_LIMITS}                c:=get_inputpointer_char;                inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}                c:=inputpointer^;                inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}              end;            #0 :              reload;            else if inputfile.internally_generated_macro and                    (c in [internal_macro_escape_begin..internal_macro_escape_end]) then              begin                if i<255 then                 begin                   inc(i);                   orgpattern[i]:=c;                   pattern[i]:=c;                 end                else                 begin                   if not err then                     begin                       Message(scan_e_string_exceeds_255_chars);                       err:=true;                     end;                 end;{$ifdef CHECK_INPUTPOINTER_LIMITS}                c:=get_inputpointer_char;                inc_inputpointer;{$else not CHECK_INPUTPOINTER_LIMITS}                c:=inputpointer^;                inc(inputpointer);{$endif CHECK_INPUTPOINTER_LIMITS}              end            else              break;          end;        until false;        orgpattern[0]:=chr(i);        pattern[0]:=chr(i);      end;    procedure tscannerfile.readnumber;      var        base,        i  : longint;        firstdigitread: Boolean;      begin        case c of          '%' :            begin              readchar;              base:=2;              pattern[1]:='%';              i:=1;            end;          '&' :            begin              readchar;              base:=8;              pattern[1]:='&';              i:=1;            end;          '$' :            begin              readchar;              base:=16;              pattern[1]:='$';              i:=1;            end;          else            begin              base:=10;              i:=0;            end;        end;        firstdigitread:=false;        while ((base>=10) and (c in ['0'..'9'])) or              ((base=16) and (c in ['A'..'F','a'..'f'])) or              ((base=8) and (c in ['0'..'7'])) or              ((base=2) and (c in ['0'..'1'])) or              ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do         begin           if (i<255) and (c<>'_') then            begin              inc(i);              pattern[i]:=c;            end;           readchar;           firstdigitread:=true;         end;        pattern[0]:=chr(i);      end;    function tscannerfile.readid:string;      begin        readstring;        readid:=pattern;      end;    function tscannerfile.readval:longint;      var        l : longint;        w : integer;      begin        readnumber;        val(pattern,l,w);        readval:=l;      end;    function tscannerfile.readval64:int64;      var        l : int64;        w : integer;      begin        readnumber;        val(pattern,l,w);        readval64:=l;      end;    function tscannerfile.readcomment(include_special_char: boolean):string;      var        i : longint;      begin        i:=0;        repeat          case c of            '{' :              begin                if (include_special_char) and (i<255) then                begin                  inc(i);                  readcomment[i]:=c;                end;                if current_commentstyle=comment_tp then                  inc_comment_level;              end;            '}' :              begin                if (include_special_char) and (i<255) then                begin                  inc(i);                  readcomment[i]:=c;                end;                if current_commentstyle=comment_tp then                  begin                    readchar;                    dec_comment_level;                    if comment_level=0 then                      break                    else                      continue;                  end;              end;            '*' :              begin                if current_commentstyle=comment_oldtp then                  begin                    readchar;                    if c=')' then                      begin                        readchar;                        dec_comment_level;                        break;                      end                    else                    { Add both characters !!}                      if (i<255) then                        begin                          inc(i);                          readcomment[i]:='*';                          if (i<255) then                            begin                              inc(i);                              readcomment[i]:=c;                            end;                        end;                  end                else                { Not old TP comment, so add...}                  begin                    if (i<255) then                      begin                        inc(i);                        readcomment[i]:='*';                      end;                  end;              end;            #10,#13 :              linebreak;            #26 :              end_of_file;            else              begin                if (i<255) then                  begin                    inc(i);                    readcomment[i]:=c;                  end;              end;          end;          readchar;        until false;        readcomment[0]:=chr(i);      end;    function tscannerfile.readquotedstring:string;      var        i : longint;        msgwritten : boolean;      begin        i:=0;        msgwritten:=false;        if (c in ['''','`']) then          begin            had_multiline_string:=in_multiline_string;            in_multiline_string:=(c='`');            if in_multiline_string and (not (m_multiline_strings in current_settings.modeswitches)) then              begin                result[0]:=chr(0);                Illegal_Char(c);              end;            repeat              readchar;              case c of                #26 :                  end_of_file;                #10,#13 :                  if not in_multiline_string then                    begin                      if had_multiline_string then                        Message2(scan_f_unterminated_multiline_string,                                 tostr(multiline_start_line),                                 tostr(multiline_start_column))                      else                        Message(scan_f_string_exceeds_line);                    end;                '''' :                  if not in_multiline_string then                    begin                      readchar;                      if c<>'''' then                       break;                    end;                '`' :                  if in_multiline_string then                    begin                      readchar;                      if c<>'`' then                       break;                    end;              end;              if i<255 then                begin                  inc(i);                  result[i]:=c;                end              else                begin                  if not msgwritten then                    begin                      Message(scan_e_string_exceeds_255_chars);                      msgwritten:=true;                    end;                 end;            until false;          end;        result[0]:=chr(i);      end;    function tscannerfile.readlongcomment(include_special_char: boolean):RawByteString;      var        i : longint;        procedure addchar(char: AnsiChar = #0);        begin          Inc(i);          if i>Length(readlongcomment) then            SetLength(readlongcomment, Length(readlongcomment)+256);          if char<>#0 then            readlongcomment[i]:=char          else            readlongcomment[i]:=c;        end;      begin        i:=0;        SetLength(readlongcomment, 256);        repeat          case c of            '{' :              begin                if (include_special_char) then                  addchar;                if current_commentstyle=comment_tp then                  inc_comment_level;              end;            '}' :              begin                if (include_special_char) then                  addchar;                if current_commentstyle=comment_tp then                  begin                    readchar;                    dec_comment_level;                    if comment_level=0 then                      break                    else                      continue;                  end;              end;            '*' :              begin                if current_commentstyle=comment_oldtp then                  begin                    readchar;                    if c=')' then                      begin                        readchar;                        dec_comment_level;                        break;                      end                    else                    { Add both characters !!}                      begin                        addchar('*');                        addchar;                      end;                  end                else                { Not old TP comment, so add...}                  addchar('*');              end;            #10,#13 :              linebreak;            #26 :              end_of_file;            else              addchar;          end;          readchar;        until false;        SetLength(readlongcomment, i);        SetCodePage(readlongcomment, current_settings.sourcecodepage, False);      end;    function tscannerfile.readlongquotedstring:RawByteString;      var        i : longint;        msgwritten : boolean;        procedure addchar;        begin          Inc(i);          if i>Length(readlongquotedstring) then            SetLength(readlongquotedstring, Length(readlongquotedstring)+256);          readlongquotedstring[i]:=c;        end;      begin        i:=0;        Setlength(readlongquotedstring, 256);        msgwritten:=false;        if (c='''') then          begin            repeat              readchar;              case c of                #26 :                  end_of_file;                #10,#13 :                  Message(scan_f_string_exceeds_line);                '''' :                  begin                    readchar;                    if c<>'''' then                     break;                  end;              end;              addchar;            until false;          end;        SetLength(readlongquotedstring, i);        SetCodePage(readlongquotedstring, current_settings.sourcecodepage, False);      end;    function tscannerfile.readstate:char;      var        state : char;      begin        state:=' ';        if c=' ' then         begin           current_scanner.skipspace;           current_scanner.readid;           if pattern='ON' then            state:='+'           else            if pattern='OFF' then             state:='-';         end        else         state:=c;        if not (state in ['+','-']) then         Message(scan_e_wrong_switch_toggle);        readstate:=state;      end;    function tscannerfile.readoptionalstate(fallback:char):char;      var        state : char;      begin        state:=' ';        if c=' ' then         begin           current_scanner.skipspace;           if c in ['*','}'] then             state:=fallback           else             begin               current_scanner.readid;               if pattern='ON' then                state:='+'               else                if pattern='OFF' then                 state:='-';             end;         end        else          if c in ['*','}'] then            state:=fallback          else            state:=c;        if not (state in ['+','-']) then         Message(scan_e_wrong_switch_toggle);        readoptionalstate:=state;      end;    function tscannerfile.readstatedefault:char;      var        state : char;      begin        state:=' ';        if c=' ' then         begin           current_scanner.skipspace;           current_scanner.readid;           if pattern='ON' then            state:='+'           else            if pattern='OFF' then             state:='-'            else             if pattern='DEFAULT' then              state:='*';         end        else         state:=c;        if not (state in ['+','-','*']) then         Message(scan_e_wrong_switch_toggle_default);        readstatedefault:=state;      end;    procedure tscannerfile.skipspace;      begin        repeat          case c of            #26 :              begin                reload;                if (c=#26) and not assigned(inputfile.next) then                  break;                continue;              end;            #10,            #13 :              linebreak;            #9,#11,#12,' ' :              ;            else              break;          end;          readchar;        until false;      end;    procedure tscannerfile.skipuntildirective;      var        found : longint;        next_char_loaded : boolean;      begin         found:=0;         next_char_loaded:=false;         repeat           case c of             #10,             #13 :               linebreak;             #26 :               begin                 reload;                 if (c=#26) and not assigned(inputfile.next) then                   end_of_file;                 continue;               end;             '{' :               begin                 if (current_commentstyle in [comment_tp,comment_none]) then                   begin                     current_commentstyle:=comment_tp;                     if (comment_level=0) then                       found:=1;                     inc_comment_level;                   end;               end;             '*' :               begin                 if (current_commentstyle=comment_oldtp) then                   begin                     readchar;                     if c=')' then                       begin                         dec_comment_level;                         found:=0;                         current_commentstyle:=comment_none;                       end                     else                       next_char_loaded:=true;                   end                 else                   found := 0;               end;             '}' :               begin                 if (current_commentstyle=comment_tp) then                   begin                     dec_comment_level;                     if (comment_level=0) then                       current_commentstyle:=comment_none;                     found:=0;                   end;               end;             '$' :               begin                 if found=1 then                  found:=2;               end;             '''','`' :               if (current_commentstyle=comment_none) then                 begin                   had_multiline_string:=in_multiline_string;                   in_multiline_string:=(c='`');                   if in_multiline_string and (not (m_multiline_strings in current_settings.modeswitches)) then                     Illegal_Char(c);                   repeat                     readchar;                     case c of                       #26 :                         end_of_file;                       #10,#13 :                         if not in_multiline_string then                           break;                       '''' :                         if not in_multiline_string then                           begin                             readchar;                             if c<>'''' then                              begin                                next_char_loaded:=true;                                break;                              end;                           end;                       '`' :                         if in_multiline_string then                           begin                             readchar;                             if c<>'`' then                              begin                                next_char_loaded:=true;                                break;                              end;                           end;                     end;                   until false;                 end;             '(' :               begin                 if (current_commentstyle=comment_none) then                  begin                    readchar;                    if c='*' then                     begin                       readchar;                       if c='$' then                        begin                          found:=2;                          inc_comment_level;                          current_commentstyle:=comment_oldtp;                        end                       else                        begin                          skipoldtpcomment(false);                          next_char_loaded:=true;                        end;                     end                    else                     next_char_loaded:=true;                  end                 else                  found:=0;               end;             '/' :               begin                 if (current_commentstyle=comment_none) then                  begin                    readchar;                    if c='/' then                     skipdelphicomment;                    next_char_loaded:=true;                  end                 else                  found:=0;               end;             else               found:=0;           end;           if next_char_loaded then             next_char_loaded:=false           else             readchar;         until (found=2);      end;{****************************************************************************                             Comment Handling****************************************************************************}    procedure tscannerfile.skipcomment(read_first_char:boolean);      begin        current_commentstyle:=comment_tp;        if read_first_char then          readchar;        inc_comment_level;      { handle compiler switches }        if (c='$') then         handledirectives;      { handle_switches can dec comment_level,  }        while (comment_level>0) do         begin           case c of            '{' :              inc_comment_level;            '}' :              dec_comment_level;            '*' :              { in iso mode, comments opened by a curly bracket can be closed by asterisk, round bracket }              if m_iso in current_settings.modeswitches then                begin                  readchar;                  if c=')' then                    dec_comment_level                  else                    continue;                end;            #10,#13 :              linebreak;            #26 :              begin                reload;                if (c=#26) and not assigned(inputfile.next) then                  end_of_file;                continue;              end;           end;           readchar;         end;        current_commentstyle:=comment_none;      end;    procedure tscannerfile.skipdelphicomment;      begin        current_commentstyle:=comment_delphi;        inc_comment_level;        readchar;        { this is not supported }        if c='$' then          Message(scan_w_wrong_styled_switch);        { skip comment }        while not (c in [#10,#13,#26]) do          readchar;        dec_comment_level;        current_commentstyle:=comment_none;      end;    procedure tscannerfile.skipoldtpcomment(read_first_char:boolean);      var        found : longint;      begin        current_commentstyle:=comment_oldtp;        inc_comment_level;        { only load a char if last already processed,          was cause of bug1634 PM }        if read_first_char then          readchar;      { this is now supported }        if (c='$') then         handledirectives;      { skip comment }        while (comment_level>0) do         begin           found:=0;           repeat             case c of               #26 :                 begin                   reload;                   if (c=#26) and not assigned(inputfile.next) then                     end_of_file;                   continue;                 end;               #10,#13 :                 begin                   if found=4 then                    inc_comment_level;                   linebreak;                   found:=0;                 end;               '*' :                 begin                   if found=3 then                    found:=4                   else                    begin                      if found=4 then                        inc_comment_level;                      found:=1;                    end;                 end;               ')' :                 begin                   if found in [1,4] then                    begin                      dec_comment_level;                      if comment_level=0 then                       found:=2                      else                       found:=0;                    end                   else                    found:=0;                 end;              '}' :                { in iso mode, comments opened by asterisk, round bracket can be closed by a curly bracket }                if m_iso in current_settings.modeswitches then                  begin                    dec_comment_level;                    if comment_level=0 then                      found:=2                    else                      found:=0;                  end;               '(' :                 begin                   if found=4 then                    inc_comment_level;                   found:=3;                 end;               else                 begin                   if found=4 then                    inc_comment_level;                   found:=0;                 end;             end;             readchar;           until (found=2);         end;        current_commentstyle:=comment_none;      end;    procedure tscannerfile.postprocessutf8multiline(len,quote_pos,quote_count : integer);    var      malformed : boolean;      start, i,stripcol,col,newlen : integer;      crlf : boolean;      tmp : tcompilerwidestring;      c : tcompilerwidechar;      file_pos : tfileposinfo;    begin      stripcol:=quote_pos;      malformed:=false;      newlen:=0;      col:=0;      start:=1;      initwidestring(tmp);      { Strip initial cr/lf }      Case current_settings.lineendingtype of        le_cr,le_lf : inc(start);        le_crlf : inc(start,2);        le_source :          begin          inc(start);          if (getcharwidestring(patternw,1)=13) and (getcharwidestring(patternw,start)=10) then            inc(start);          end;        le_platform : inc(start,length(target_info.newline));      end;      { we don't need the last added quotes }      dec(len,quote_count-1);      for I:=Start to len do        begin        c:=getcharwidestring(patternw,i);        inc(col);        if (col>stripcol) or (c=10) or (c=13) then          begin          inc(newlen);          concatwidestringchar(patternw,c);          end        else          begin          // if less spaces than in the last line, report error          if not (c in [9,32,11]) then            begin            if not malformed then              begin              malformed:=true;              message3(scan_e_improperly_indented_multiline_string,                      tostr(stripcol),                      tostr(multiline_start_line),                      tostr(multiline_start_column));              end;            end;          end;        if (c=10) or (c=13) then          col:=0;        end;      // remove last CR/LF      c:=getcharwidestring(tmp,newlen);      if (c=10) or (c=13) then        begin        Case current_settings.lineendingtype of          le_cr,le_lf : dec(newlen);          le_crlf : dec(newlen,2);          le_platform : dec(newlen,length(target_info.newline));          le_source :            begin            crlf:=getcharwidestring(tmp,newlen)=10;            dec(newlen);            if crlf and (newLen>0) and (getcharwidestring(tmp,newlen)=13) then              dec(newlen);            end;        end;        end;      tmp.len:=newLen;      donewidestring(patternw);      patternw:=tmp;    end;    procedure tscannerfile.postprocessmultiline(len,quote_pos,quote_count : integer);    var      malformed : boolean;      start, i,stripcol,col,newlen : integer;      crlf : boolean;      tmp : ansistring;      c : ansichar;      file_pos : tfileposinfo;    begin      stripcol:=quote_pos;      malformed:=false;      newlen:=0;      setlength(tmp,len-quote_count+1);      col:=0;      start:=1;      { Strip initial cr/lf }      Case current_settings.lineendingtype of        le_cr,le_lf : inc(start);        le_crlf : inc(start,2);        le_platform : inc(start,length(target_info.newline));        le_source :          begin          inc(start);          if (cstringPattern[1]=#13) and (cstringpattern[start]=#10) then            inc(start);          end;      end;      { we don't need the last added quotes }      dec(len,quote_count-1);      for I:=Start to len do        begin        c:=cstringpattern[i];        inc(col);        if (col>stripcol) or (c in [#10,#13]) then          begin          inc(newlen);          tmp[newlen]:=c;          end        else          begin          // if less spaces than in the last line, report error          if not (c in [#9,#32,#11]) then            begin            if not malformed then              begin              malformed:=true;              message3(scan_e_improperly_indented_multiline_string,                      tostr(stripcol),                      tostr(multiline_start_line),                      tostr(multiline_start_column));              end;            end;          end;        if c in [#10,#13] then          col:=0;        end;      // remove last CR/LF      if tmp[newlen] in [#10,#13] then        begin        Case current_settings.lineendingtype of          le_cr,le_lf : dec(newlen);          le_crlf : dec(newlen,2);          le_platform : dec(newlen,length(target_info.newline));          le_source :              begin              crlf:=tmp[newlen]=#10;              dec(newlen);              if crlf and (tmp[newlen]=#13) then                Dec(newlen);              end;        end;        end;      SetLength(tmp,newlen);      cstringpattern:=tmp;    end;    function tscannerfile.readstringconstant : boolean;    type       tQuoteStyle = (qsNone,qsBacktick,qsMultiQuote);    var      trimcount,m,code,len,quote_count,init_quote_count,whitespace_count,quote_col : integer;      style : tQuoteStyle;      iswidestring : boolean;      asciinr : string[33];      last_c : char;      whitespace_only, had_newline, first_multiline, backtick : boolean;      d : cardinal;      w : word;    label      quote_label;    begin      last_c :=#0;      trimcount:=0;      quote_col:=0;      whitespace_count:=0;      init_quote_count:=0;      had_newline:=false;      first_multiline:=false;      had_multiline_string:=in_multiline_string;      backtick:=(c='`');      if backtick then        style:=qsBacktick      else        style:=qsNone;      whitespace_only:=true;      in_multiline_string:=backtick;      quote_count:=0;      whitespace_only:=true;      if in_multiline_string then        begin          if not (m_multiline_strings in current_settings.modeswitches) then            Illegal_Char(c)          else            begin              multiline_start_line:=current_filepos.line;              multiline_start_column:=current_filepos.column;            end;        end;      len:=0;      cstringpattern:='';      iswidestring:=false;      if c='^' then       begin         readchar;         c:=upcase(c);         if (block_type in [bt_type,bt_const_type,bt_var_type]) or            (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or            (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then          begin            token:=_CARET;            exit(true);          end         else          begin            inc(len);            setlength(cstringpattern,256);            if c<#64 then              cstringpattern[len]:=chr(ord(c)+64)            else              cstringpattern[len]:=chr(ord(c)-64);            readchar;          end;       end;      repeat        case c of          '#' :            begin              readchar; { read # }              case c of                '$':                  begin                    readchar; { read leading $ }                    asciinr:='$';                    while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=7) do                      begin                        asciinr:=asciinr+c;                        readchar;                      end;                  end;                '&':                  begin                    readchar; { read leading $ }                    asciinr:='&';                    while (upcase(c) in ['0'..'7']) and (length(asciinr)<=8) do                      begin                        asciinr:=asciinr+c;                        readchar;                      end;                  end;                '%':                  begin                    readchar; { read leading $ }                    asciinr:='%';                    while (upcase(c) in ['0','1']) and (length(asciinr)<=22) do                      begin                        asciinr:=asciinr+c;                        readchar;                      end;                  end;                else                  begin                    asciinr:='';                    while (c in ['0'..'9']) and (length(asciinr)<=8) do                      begin                        asciinr:=asciinr+c;                        readchar;                      end;                  end;              end;              val(asciinr,m,code);              if (asciinr='') or (code<>0) then                Message(scan_e_illegal_char_const)              else if (m<0) or (m>255) or (length(asciinr)>3) then                begin                   if (m>=0) and (m<=$10FFFF) then                     begin                       if not iswidestring then                        begin                          if len>0 then                            ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)                          else                            ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);                          iswidestring:=true;                          len:=0;                        end;                       if m<=$FFFF then                         concatwidestringchar(patternw,tcompilerwidechar(m))                       else                         begin                           { split into surrogate pair }                           dec(m,$10000);                           concatwidestringchar(patternw,tcompilerwidechar((m shr 10) + $D800));                           concatwidestringchar(patternw,tcompilerwidechar((m and $3FF) + $DC00));                         end;                     end                   else                     Message(scan_e_illegal_char_const)                end              else if iswidestring then                concatwidestringchar(patternw,asciichar2unicode(char(m)))              else                begin                  if len>=length(cstringpattern) then                    setlength(cstringpattern,length(cstringpattern)+256);                  inc(len);                  cstringpattern[len]:=chr(m);                end;            end;          '''','`' :            begin              inc(quote_count);              had_multiline_string:=in_multiline_string;              if style<>qsMultiQuote then                begin                  in_multiline_string:=(c='`');                  if in_multiline_string then                    backtick:=true                  else                    style:=qsNone;                  first_multiline:=in_multiline_string and (last_c in [#0,#32,#61]);                end;              repeat                readchar;                quote_label:                  case c of                    #26 :                      end_of_file;                    #32,#9,#11 :                      begin                      inc(whitespace_count);                      if (had_newline or first_multiline) and backtick and                         (current_settings.whitespacetrimauto or                         (current_settings.whitespacetrimcount>0)) then                        begin                          if current_settings.whitespacetrimauto then                            trimcount:=multiline_start_column                          else                            trimcount:=current_settings.whitespacetrimcount;                          while (c in [#32,#9,#11]) and (trimcount>0) do                            begin                              readchar;                              dec(trimcount);                            end;                          had_newline:=false;                          first_multiline:=false;                          goto quote_label;                        end;                      end;                    #10,#13 :                      begin                      whitespace_only:=true;                      whitespace_count:=0;                      if not in_multiline_string then                        begin                          if had_multiline_string then                            Message2(scan_f_unterminated_multiline_string,                                     tostr(multiline_start_line),                                     tostr(multiline_start_column))                          else if (not backtick)                                   and ((quote_count>2) and ((quote_count mod 2)=1))                                   and (m_multiline_strings in current_settings.modeswitches) then                            begin                            style:=qsMultiQuote;                            init_quote_count:=quote_count;                            multiline_start_line:=current_filepos.line;                            multiline_start_column:=current_filepos.column;                            in_multiline_string:=true;                            had_multiline_string:=true;                            trimcount:=0;                            len:=0;                            if c=#13 then                              begin                              readchar;                              if c<>#10 then                                goto quote_label;                              end;                            end                          else                            Message(scan_f_string_exceeds_line);                        end;                      end;                    '''' :                      begin                      inc(quote_count);                      if not in_multiline_string then                        begin                          readchar;                          if c='''' then                            inc(quote_count)                          else                            break;                        end                      else if not backtick then                        if whitespace_only and (quote_count=init_quote_count) then                          begin                          in_multiline_string:=false;                          quote_col:=whitespace_count;                          readchar;                          break;                          end;                      end;                    '`' :                      if in_multiline_string and (style=qsBacktick) then                        begin                          readchar;                          if c<>'`' then                           break;                        whitespace_only:=false;                        end;                    else                      whitespace_only:=false;                      quote_count:=0;                    end;                first_multiline:=false;                { interpret as utf-8 string? }                if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then                  begin                    { convert existing string to an utf-8 string }                    if not iswidestring then                      begin                        if len>0 then                          ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)                        else                          ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);                        iswidestring:=true;                        len:=0;                      end;                    { four chars }                    if (ord(c) and $f0)=$f0 then                      begin                        { this always represents a surrogate pair, so                          read as 32-bit value and then split into                          the corresponding pair of two wchars }                        d:=ord(c) and $f;                        readchar;                        if (ord(c) and $c0)<>$80 then                          message(scan_e_utf8_malformed);                        d:=(d shl 6) or (ord(c) and $3f);                        readchar;                        if (ord(c) and $c0)<>$80 then                          message(scan_e_utf8_malformed);                        d:=(d shl 6) or (ord(c) and $3f);                        readchar;                        if (ord(c) and $c0)<>$80 then                          message(scan_e_utf8_malformed);                        d:=(d shl 6) or (ord(c) and $3f);                        if d<$10000 then                          message(scan_e_utf8_malformed);                        d:=d-$10000;                        { high surrogate }                        w:=$d800+(d shr 10);                        concatwidestringchar(patternw,w);                        { low surrogate }                        w:=$dc00+(d and $3ff);                        concatwidestringchar(patternw,w);                      end                    { three chars }                    else if (ord(c) and $e0)=$e0 then                      begin                        w:=ord(c) and $f;                        readchar;                        if (ord(c) and $c0)<>$80 then                          message(scan_e_utf8_malformed);                        w:=(w shl 6) or (ord(c) and $3f);                        readchar;                        if (ord(c) and $c0)<>$80 then                          message(scan_e_utf8_malformed);                        w:=(w shl 6) or (ord(c) and $3f);                        concatwidestringchar(patternw,w);                      end                    { two chars }                    else if (ord(c) and $c0)<>0 then                      begin                        w:=ord(c) and $1f;                        readchar;                        if (ord(c) and $c0)<>$80 then                          message(scan_e_utf8_malformed);                        w:=(w shl 6) or (ord(c) and $3f);                        concatwidestringchar(patternw,w);                      end                    { illegal }                    else if (ord(c) and $80)<>0 then                      message(scan_e_utf8_malformed)                    else                      concatwidestringchar(patternw,tcompilerwidechar(c))                  end                else if iswidestring then                  begin                    if in_multiline_string and (c in [#10,#13]) and (not ((c=#10) and (last_c=#13))) then                      begin                        if current_settings.sourcecodepage=CP_UTF8 then                          begin                            case current_settings.lineendingtype of                              le_cr :                                concatwidestringchar(patternw,ord(#13));                              le_crlf :                                begin                                  concatwidestringchar(patternw,ord(#13));                                  concatwidestringchar(patternw,ord(#10));                                end;                              le_lf :                                concatwidestringchar(patternw,ord(#10));                              le_platform :                                begin                                  if target_info.newline=#13 then                                    concatwidestringchar(patternw,ord(#13))                                  else if target_info.newline=#13#10 then                                    begin                                      concatwidestringchar(patternw,ord(#13));                                      concatwidestringchar(patternw,ord(#10));                                    end                                  else if target_info.newline=#10 then                                    concatwidestringchar(patternw,ord(#10));                                end;                              le_source :                                concatwidestringchar(patternw,ord(c));                            end;                          end                        else                          case current_settings.lineendingtype of                            le_cr :                              concatwidestringchar(patternw,asciichar2unicode(#13));                            le_crlf :                              begin                                concatwidestringchar(patternw,asciichar2unicode(#13));                                concatwidestringchar(patternw,asciichar2unicode(#10));                              end;                            le_lf :                              concatwidestringchar(patternw,asciichar2unicode(#10));                            le_platform :                              begin                                if target_info.newline=#13 then                                  concatwidestringchar(patternw,asciichar2unicode(#13))                                else if target_info.newline=#13#10 then                                  begin                                    concatwidestringchar(patternw,asciichar2unicode(#13));                                    concatwidestringchar(patternw,asciichar2unicode(#10));                                  end                                else if target_info.newline=#10 then                                  concatwidestringchar(patternw,asciichar2unicode(#10));                              end;                            le_source :                              concatwidestringchar(patternw,asciichar2unicode(c));                          end;                        had_newline:=true;                        inc(line_no);                      end                    else if not (in_multiline_string and (c in [#10,#13])) then                      begin                        if current_settings.sourcecodepage=CP_UTF8 then                          concatwidestringchar(patternw,ord(c))                        else                          concatwidestringchar(patternw,asciichar2unicode(c));                      end;                  end                else                  begin                     if in_multiline_string and (c in [#10,#13]) and (not ((c=#10) and (last_c=#13))) then                       begin                         if len>=length(cstringpattern) then                           setlength(cstringpattern,length(cstringpattern)+256);                         inc(len);                         case current_settings.lineendingtype of                           le_cr :                             cstringpattern[len]:=#13;                           le_crlf :                             begin                               cstringpattern[len]:=#13;                               inc(len);                               cstringpattern[len]:=#10;                             end;                           le_lf :                             cstringpattern[len]:=#10;                           le_platform :                             begin                               if target_info.newline=#13 then                                 cstringpattern[len]:=#13                               else if target_info.newline=#13#10 then                                 begin                                   cstringpattern[len]:=#13;                                   inc(len);                                   cstringpattern[len]:=#10;                                 end                               else if target_info.newline=#10 then                                 cstringpattern[len]:=#10;                             end;                           le_source :                             cstringpattern[len]:=c;                         end;                         had_newline:=true;                         inc(line_no);                       end                     else if not (in_multiline_string and (c in [#10,#13])) then                       begin                         if len>=length(cstringpattern) then                           setlength(cstringpattern,length(cstringpattern)+256);                         inc(len);                         cstringpattern[len]:=c;                       end;                  end;              last_c:=c;              until false;            end;          '^' :            begin              readchar;              c:=upcase(c);              if c<#64 then               c:=chr(ord(c)+64)              else               c:=chr(ord(c)-64);              if iswidestring then                concatwidestringchar(patternw,asciichar2unicode(c))              else                begin                  if len>=length(cstringpattern) then                    setlength(cstringpattern,length(cstringpattern)+256);                   inc(len);                   cstringpattern[len]:=c;                end;              readchar;            end;          else           break;        end;      last_c:=c;      until false;      { strings with length 1 become const chars }      if iswidestring then        begin          if had_multiline_string and not backtick then            begin            postprocessutf8multiline(len,quote_col,init_quote_count);            end;          if patternw.len=1 then            token:=_CWCHAR          else            token:=_CWSTRING;        end      else        begin          if had_multiline_string and not backtick then            begin            postprocessmultiline(len,quote_col,init_quote_count);            end          else            setlength(cstringpattern,len);          if length(cstringpattern)=1 then            begin              token:=_CCHAR;              pattern:=cstringpattern;            end          else            token:=_CSTRING;        end;      exit(true);    end;{****************************************************************************                               Token Scanner****************************************************************************}    procedure tscannerfile.readtoken(allowrecordtoken:boolean);      var        code    : integer;        d : cardinal;        len,        low,high,mid : longint;        w : word;        m       : longint;        mac     : tmacro;        firstdigitread: boolean;        had_newline,first_multiline : boolean;        trimcount : word;       label         exit_label;      begin        had_newline:=false;        first_multiline:=false;        flushpendingswitchesstate;        { record tokens? }        if allowrecordtoken and           assigned(recordtokenbuf) then          recordtoken;        { replay tokens? }        if assigned(replaytokenbuf) then          begin            replaytoken;            goto exit_label;          end;      { was there already a token read, then return that token }        if nexttoken<>NOTOKEN then         begin           setnexttoken;           goto exit_label;         end;      { Skip all spaces and comments }        repeat          case c of            '{' :              skipcomment(true);            #26 :              begin                reload;                if (c=#26) and not assigned(inputfile.next) then                  break;              end;            ' ',#9..#13 :              begin{$ifdef PREPROCWRITE}                if parapreprocess then                 begin                   if c=#10 then                    preprocfile.eolfound:=true                   else                    preprocfile.spacefound:=true;                 end;{$endif PREPROCWRITE}                skipspace;              end            else              break;          end;        until false;      { Save current token position, for EOF its already loaded }        if c<>#26 then          gettokenpos;      { Check first for a identifier/keyword, this is 20+% faster (PFV) }        if c in ['A'..'Z','a'..'z','_'] then         begin           readstring;           token:=_ID;           idtoken:=_ID;         { keyword or any other known token,           pattern is always uppercased }           if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then            begin              low:=ord(tokenidx^[length(pattern),pattern[1]].first);              high:=ord(tokenidx^[length(pattern),pattern[1]].last);              while low<high do               begin                 mid:=(high+low+1) shr 1;                 if pattern<tokeninfo^[ttoken(mid)].str then                  high:=mid-1                 else                  low:=mid;               end;              with tokeninfo^[ttoken(high)] do                if pattern=str then                  begin                    if (keyword*current_settings.modeswitches)<>[] then                      if op=NOTOKEN then                        token:=ttoken(high)                      else                        token:=op;                    idtoken:=ttoken(high);                  end;            end;         { Only process identifiers and not keywords }           if token=_ID then            begin            { this takes some time ... }              if (cs_support_macro in current_settings.moduleswitches) then               begin                 mac:=tmacro(search_macro(pattern));                 if assigned(mac) and (not mac.is_compiler_var) and mac.is_c_macro then                  begin                    if (yylexcount<max_macro_nesting) and (macro_nesting_depth<max_macro_nesting) then                     begin                       mac.is_used:=true;                       inc(yylexcount);                       substitutemacro(pattern,pchar(mac.buftext),mac.buflen,                         mac.fileinfo.line,mac.fileinfo.fileindex,false);                       { handle empty macros }                       if c=#0 then                         begin                           reload;                           { avoid macro nesting error in case of                             a sequence of empty macros, see #38802 }                           dec(yylexcount);                           readtoken(false);                         end                       else                         begin                           readtoken(false);                           { that's all folks }                           dec(yylexcount);                         end;                       exit;                     end                    else                     Message(scan_w_macro_too_deep);                  end;               end;            end;         { return token }           goto exit_label;         end        else         begin           idtoken:=_NOID;           case c of             '$' :               begin                 readnumber;                 token:=_INTCONST;                 goto exit_label;               end;             '%' :               begin                 if [m_fpc,m_delphi] * current_settings.modeswitches = [] then                  Illegal_Char(c)                 else                  begin                    readnumber;                    token:=_INTCONST;                    goto exit_label;                  end;               end;             '&' :               begin                 if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then                  begin                    readnumber;                    if length(pattern)=1 then                      begin                        { does really an identifier follow? }                        if not (c in ['_','A'..'Z','a'..'z']) then                          message2(scan_f_syn_expected,tokeninfo^[_ID].str,c);                        readstring;                        token:=_ID;                        idtoken:=_ID;                      end                    else                      token:=_INTCONST;                    goto exit_label;                  end                 else if m_mac in current_settings.modeswitches then                  begin                    readchar;                    token:=_AMPERSAND;                    goto exit_label;                  end                 else                  Illegal_Char(c);               end;             '0'..'9' :               begin                 readnumber;                 if (c in ['.','e','E']) then                  begin                  { first check for a . }                    if c='.' then                     begin                       cachenexttokenpos;                       readchar;                       { is it a .. from a range? }                       case c of                         '.' :                           begin                             readchar;                             token:=_INTCONST;                             nexttoken:=_POINTPOINT;                             goto exit_label;                           end;                         ')' :                           begin                             readchar;                             token:=_INTCONST;                             nexttoken:=_RECKKLAMMER;                             goto exit_label;                           end;                         '0'..'9' :                           begin                             { insert the number after the . }                             pattern:=pattern+'.';                             firstdigitread:=false;                             while (c in ['0'..'9']) or                              ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do                              begin                                if c<>'_' then                                  pattern:=pattern+c;                                readchar;                                firstdigitread:=true;                              end;                           end;                         else                           begin                             token:=_INTCONST;                             nexttoken:=_POINT;                             goto exit_label;                           end;                       end;                      end;                  { E can also follow after a point is scanned }                    if c in ['e','E'] then                     begin                       pattern:=pattern+'E';                       readchar;                       if c in ['-','+'] then                        begin                          pattern:=pattern+c;                          readchar;                        end;                       if not(c in ['0'..'9']) then                         Illegal_Char(c);                       firstdigitread:=false;                       while (c in ['0'..'9']) or                        ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do                        begin                          if c<>'_' then                          pattern:=pattern+c;                          readchar;                          firstdigitread:=true;                        end;                     end;                    token:=_REALNUMBER;                    goto exit_label;                  end;                 token:=_INTCONST;                 goto exit_label;               end;             ';' :               begin                 readchar;                 token:=_SEMICOLON;                 goto exit_label;               end;             '[' :               begin                 readchar;                 token:=_LECKKLAMMER;                 goto exit_label;               end;             ']' :               begin                 readchar;                 token:=_RECKKLAMMER;                 goto exit_label;               end;             '(' :               begin                 readchar;                 case c of                   '*' :                     begin                       skipoldtpcomment(true);                       readtoken(false);                       exit;                     end;                   '.' :                     begin                       readchar;                       token:=_LECKKLAMMER;                       goto exit_label;                     end;                 end;                 token:=_LKLAMMER;                 goto exit_label;               end;             ')' :               begin                 readchar;                 token:=_RKLAMMER;                 goto exit_label;               end;             '+' :               begin                 readchar;                 if c='=' then                  begin                    readchar;                    token:=_PLUSASN;                    goto exit_label;                  end;                 token:=_PLUS;                 goto exit_label;               end;             '-' :               begin                 readchar;                 if c='=' then                  begin                    readchar;                    token:=_MINUSASN;                    goto exit_label;                  end;                 token:=_MINUS;                 goto exit_label;               end;             ':' :               begin                 readchar;                 if c='=' then                  begin                    readchar;                    token:=_ASSIGNMENT;                    goto exit_label;                  end;                 token:=_COLON;                 goto exit_label;               end;             '*' :               begin                 readchar;                 if c='=' then                  begin                    readchar;                    token:=_STARASN;                  end                 else                  if c='*' then                   begin                     readchar;                     token:=_STARSTAR;                   end                 else                  token:=_STAR;                 goto exit_label;               end;             '/' :               begin                 readchar;                 case c of                   '=' :                     begin                       readchar;                       token:=_SLASHASN;                       goto exit_label;                     end;                   '/' :                     begin                       skipdelphicomment;                       readtoken(false);                       exit;                     end;                 end;                 token:=_SLASH;                 goto exit_label;               end;             '|' :               if m_mac in current_settings.modeswitches then                begin                  readchar;                  token:=_PIPE;                  goto exit_label;                end               else                Illegal_Char(c);             '=' :               begin                 readchar;                 token:=_EQ;                 goto exit_label;               end;             '.' :               begin                 readchar;                 case c of                   '.' :                     begin                       readchar;                       case c of                         '.' :                         begin                           readchar;                           token:=_POINTPOINTPOINT;                           goto exit_label;                         end;                       else                         begin                           token:=_POINTPOINT;                           goto exit_label;                         end;                       end;                     end;                   ')' :                     begin                       readchar;                       token:=_RECKKLAMMER;                       goto exit_label;                     end;                 end;                 token:=_POINT;                 goto exit_label;               end;             '@' :               begin                 readchar;                 token:=_KLAMMERAFFE;                 goto exit_label;               end;             ',' :               begin                 readchar;                 token:=_COMMA;                 goto exit_label;               end;             '''','#','^','`' :               begin                 readstringconstant;                 goto exit_label;               end;             '>' :               begin                 readchar;                 if (block_type in [bt_type,bt_var_type,bt_const_type]) then                   token:=_RSHARPBRACKET                 else                   begin                     case c of                       '=' :                         begin                           readchar;                           token:=_GTE;                           goto exit_label;                         end;                       '>' :                         begin                           readchar;                           token:=_OP_SHR;                           goto exit_label;                         end;                       '<' :                         begin { >< is for a symetric diff for sets }                           readchar;                           token:=_SYMDIF;                           goto exit_label;                         end;                     end;                     token:=_GT;                   end;                 goto exit_label;               end;             '<' :               begin                 readchar;                 if (block_type in [bt_type,bt_var_type,bt_const_type]) then                   token:=_LSHARPBRACKET                 else                   begin                     case c of                       '>' :                         begin                           readchar;                           token:=_NE;                           goto exit_label;                         end;                       '=' :                         begin                           readchar;                           token:=_LTE;                           goto exit_label;                         end;                       '<' :                         begin                           readchar;                           token:=_OP_SHL;                           goto exit_label;                         end;                     end;                     token:=_LT;                   end;                 goto exit_label;               end;             #26 :               begin                 token:=_EOF;                 checkpreprocstack;                 goto exit_label;               end;             else if inputfile.internally_generated_macro and                     (c in [internal_macro_escape_begin..internal_macro_escape_end]) then               begin                 token:=_ID;                 readstring;               end             else               Illegal_Char(c);           end;        end;exit_label:        lasttoken:=token;      end;    function tscannerfile.readpreproc:ttoken;      var        low,high,mid: longint;        optoken: ttoken;      begin         { Added the assignment to NOTOKEN below because I got a DFA uninitialized result           warning when building the compiler with -O3, which broke compilation with -Sew.           - Akira1364 }         readpreproc:=NOTOKEN;         skipspace;         case c of           '_',           'A'..'Z',           'a'..'z' :             begin               readstring;               optoken:=_ID;               if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then                begin                  low:=ord(tokenidx^[length(pattern),pattern[1]].first);                  high:=ord(tokenidx^[length(pattern),pattern[1]].last);                  while low<high do                   begin                     mid:=(high+low+1) shr 1;                     if pattern<tokeninfo^[ttoken(mid)].str then                      high:=mid-1                     else                      low:=mid;                   end;                  with tokeninfo^[ttoken(high)] do                    if pattern=str then                      begin                        if (keyword*current_settings.modeswitches)<>[] then                          if op=NOTOKEN then                            optoken:=ttoken(high)                          else                            optoken:=op;                      end;                  if not (optoken in preproc_operators) then                    optoken:=_ID;                end;               current_scanner.preproc_pattern:=pattern;               readpreproc:=optoken;             end;           '''','`' :             if not ((c='`') and (not (m_multiline_strings in current_settings.modeswitches))) then               begin                 readquotedstring;                 current_scanner.preproc_pattern:=cstringpattern;                 readpreproc:=_CSTRING;               end;           '0'..'9' :             begin               readnumber;               if (c in ['.','e','E']) then                 begin                   { first check for a . }                   if c='.' then                     begin                       readchar;                       if c in ['0'..'9'] then                         begin                           { insert the number after the . }                           pattern:=pattern+'.';                           while c in ['0'..'9'] do                             begin                               pattern:=pattern+c;                               readchar;                             end;                         end                       else                         Illegal_Char(c);                     end;                  { E can also follow after a point is scanned }                   if c in ['e','E'] then                     begin                       pattern:=pattern+'E';                       readchar;                       if c in ['-','+'] then                         begin                           pattern:=pattern+c;                           readchar;                         end;                       if not(c in ['0'..'9']) then                         Illegal_Char(c);                       while c in ['0'..'9'] do                         begin                           pattern:=pattern+c;                           readchar;                         end;                     end;                   readpreproc:=_REALNUMBER;                 end               else                 readpreproc:=_INTCONST;               current_scanner.preproc_pattern:=pattern;             end;           '$','%':             begin               readnumber;               current_scanner.preproc_pattern:=pattern;               readpreproc:=_INTCONST;             end;           '&' :             begin                readnumber;                if length(pattern)=1 then                  begin                    readstring;                    readpreproc:=_ID;                  end                else                  readpreproc:=_INTCONST;               current_scanner.preproc_pattern:=pattern;             end;           '.' :             begin               readchar;               readpreproc:=_POINT;             end;           ',' :             begin               readchar;               readpreproc:=_COMMA;             end;           '}' :             begin               readpreproc:=_END;             end;           '(' :             begin               readchar;               readpreproc:=_LKLAMMER;             end;           ')' :             begin               readchar;               readpreproc:=_RKLAMMER;             end;           '[' :             begin               readchar;               readpreproc:=_LECKKLAMMER;             end;           ']' :             begin               readchar;               readpreproc:=_RECKKLAMMER;             end;           '+' :             begin               readchar;               readpreproc:=_PLUS;             end;           '-' :             begin               readchar;               readpreproc:=_MINUS;             end;           '*' :             begin               readchar;               readpreproc:=_STAR;             end;           '/' :             begin               readchar;               readpreproc:=_SLASH;             end;           '=' :             begin               readchar;               readpreproc:=_EQ;             end;           '>' :             begin               readchar;               if c='=' then                 begin                   readchar;                   readpreproc:=_GTE;                 end               else                 readpreproc:=_GT;             end;           '<' :             begin               readchar;               case c of                 '>' :                   begin                     readchar;                     readpreproc:=_NE;                   end;                 '=' :                   begin                     readchar;                     readpreproc:=_LTE;                   end;                 else                   readpreproc:=_LT;               end;             end;           #26 :             begin               readpreproc:=_EOF;               checkpreprocstack;             end;           else             begin               Illegal_Char(c);               readpreproc:=NOTOKEN;             end;         end;      end;    function tscannerfile.readpreprocint(var value:int64;const place:string):boolean;      var        hs : texprvalue;      begin        hs:=preproc_comp_expr(nil);        if hs.isInt then          begin            value:=hs.asInt64;            result:=true;          end        else          begin            hs.error('Integer',place);            result:=false;          end;        hs.free;      end;    function tscannerfile.readpreprocset(conform_to:tsetdef;var value:tnormalset;const place:string):boolean;      var        hs : texprvalue;      begin        hs:=preproc_comp_expr(conform_to);        if hs.def.typ=setdef then          begin            value:=hs.asSet;            result:=true;          end        else          begin            hs.error('Set',place);            result:=false;          end;        hs.free;      end;    function tscannerfile.asmgetchar : char;      begin         readchar;         repeat           case c of             #26 :               begin                 reload;                 if (c=#26) and not assigned(inputfile.next) then                   end_of_file;                 continue;               end;             else               begin                 asmgetchar:=c;                 exit;               end;           end;         until false;      end;{$ifdef EXTDEBUG}    function tscannerfile.DumpPointer: string;      var        i: Integer;      begin        Result:='';        if inputpointer=nil then exit;        i:=0;        While (inputpointer[I]<>#0) and (i<200) do          inc(i);        Setlength(result,I);        move(inputpointer^,Result[1],I);        result:='<'+inttostr(inputstart)+'>'+result;      end;{$endif EXTDEBUG}{*****************************************************************************                                   Helpers*****************************************************************************}    procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);      begin        if dm in [directive_all, directive_turbo] then          tdirectiveitem.create(turbo_scannerdirectives,s,p);        if dm in [directive_all, directive_mac] then          tdirectiveitem.create(mac_scannerdirectives,s,p);      end;    procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);      begin        if dm in [directive_all, directive_turbo] then          tdirectiveitem.createcond(turbo_scannerdirectives,s,p);        if dm in [directive_all, directive_mac] then          tdirectiveitem.createcond(mac_scannerdirectives,s,p);      end;{*****************************************************************************                                Initialization*****************************************************************************}    procedure InitScanner;      begin        InitWideString(patternw);        turbo_scannerdirectives:=TFPHashObjectList.Create;        mac_scannerdirectives:=TFPHashObjectList.Create;        { Common directives and conditionals }        AddDirective('I',directive_all, @dir_include);        AddDirective('DEFINE',directive_all, @dir_define);        AddDirective('UNDEF',directive_all, @dir_undef);        AddConditional('IF',directive_all, @dir_if);        AddConditional('IFDEF',directive_all, @dir_ifdef);        AddConditional('IFNDEF',directive_all, @dir_ifndef);        AddConditional('ELSE',directive_all, @dir_else);        AddConditional('ELSEIF',directive_all, @dir_elseif);        AddConditional('ENDIF',directive_all, @dir_endif);        { Directives and conditionals for all modes except mode macpas}        AddDirective('INCLUDE',directive_turbo, @dir_include);        AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);        AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);        AddDirective('EXTENSION',directive_turbo, @dir_extension);        AddConditional('IFEND',directive_turbo, @dir_ifend);        AddConditional('IFOPT',directive_turbo, @dir_ifopt);        { Directives and conditionals for mode macpas: }        AddDirective('SETC',directive_mac, @dir_setc);        AddDirective('DEFINEC',directive_mac, @dir_definec);        AddDirective('UNDEFC',directive_mac, @dir_undef);        AddConditional('IFC',directive_mac, @dir_if);        AddConditional('ELSEC',directive_mac, @dir_else);        AddConditional('ELIFC',directive_mac, @dir_elseif);        AddConditional('ENDC',directive_mac, @dir_endif);      end;    procedure DoneScanner;      begin        turbo_scannerdirectives.Free;        mac_scannerdirectives.Free;        DoneWideString(patternw);      end;end.
 |