scanner.pas 182 KB

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