scanner.pas 182 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538
  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. { error values }
  1163. constnone:
  1164. result:='';
  1165. else
  1166. internalerror(2013112801);
  1167. end;
  1168. end;
  1169. destructor texprvalue.destroy;
  1170. begin
  1171. case consttyp of
  1172. conststring,
  1173. constresourcestring :
  1174. freemem(pchar(value.valueptr),value.len+1);
  1175. constwstring :
  1176. donewidestring(pcompilerwidestring(value.valueptr));
  1177. constreal :
  1178. dispose(pbestreal(value.valueptr));
  1179. constset :
  1180. dispose(pnormalset(value.valueptr));
  1181. constguid :
  1182. dispose(pguid(value.valueptr));
  1183. constord,
  1184. { error values }
  1185. constnone:
  1186. ;
  1187. else
  1188. internalerror(2013112802);
  1189. end;
  1190. inherited destroy;
  1191. end;
  1192. const
  1193. 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];
  1194. function preproc_comp_expr:texprvalue;
  1195. function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean):texprvalue; forward;
  1196. procedure preproc_consume(t:ttoken);
  1197. begin
  1198. if t<>current_scanner.preproc_token then
  1199. Message(scan_e_preproc_syntax_error);
  1200. current_scanner.preproc_token:=current_scanner.readpreproc;
  1201. end;
  1202. function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;out tokentoconsume:ttoken):boolean;
  1203. var
  1204. hmodule: tmodule;
  1205. ns:ansistring;
  1206. nssym:tsym;
  1207. begin
  1208. result:=false;
  1209. tokentoconsume:=_ID;
  1210. if assigned(srsym) and (srsym.typ in [unitsym,namespacesym]) then
  1211. begin
  1212. if not(srsym.owner.symtabletype in [staticsymtable,globalsymtable]) then
  1213. internalerror(200501154);
  1214. { only allow unit.symbol access if the name was
  1215. found in the current module
  1216. we can use iscurrentunit because generic specializations does not
  1217. change current_unit variable }
  1218. hmodule:=find_module_from_symtable(srsym.Owner);
  1219. if not Assigned(hmodule) then
  1220. internalerror(201001120);
  1221. if hmodule.unit_index=current_filepos.moduleindex then
  1222. begin
  1223. preproc_consume(_POINT);
  1224. current_scanner.skipspace;
  1225. if srsym.typ=namespacesym then
  1226. begin
  1227. ns:=srsym.name;
  1228. nssym:=srsym;
  1229. while assigned(srsym) and (srsym.typ=namespacesym) do
  1230. begin
  1231. { we have a namespace. the next identifier should be either a namespace or a unit }
  1232. searchsym_in_module(hmodule,ns+'.'+current_scanner.preproc_pattern,srsym,srsymtable);
  1233. if assigned(srsym) and (srsym.typ in [namespacesym,unitsym]) then
  1234. begin
  1235. ns:=ns+'.'+current_scanner.preproc_pattern;
  1236. nssym:=srsym;
  1237. preproc_consume(_ID);
  1238. current_scanner.skipspace;
  1239. preproc_consume(_POINT);
  1240. current_scanner.skipspace;
  1241. end;
  1242. end;
  1243. { check if there is a hidden unit with this pattern in the namespace }
  1244. if not assigned(srsym) and
  1245. assigned(nssym) and (nssym.typ=namespacesym) and assigned(tnamespacesym(nssym).unitsym) then
  1246. srsym:=tnamespacesym(nssym).unitsym;
  1247. if assigned(srsym) and (srsym.typ<>unitsym) then
  1248. internalerror(201108260);
  1249. if not assigned(srsym) then
  1250. begin
  1251. result:=true;
  1252. srsymtable:=nil;
  1253. exit;
  1254. end;
  1255. end;
  1256. case current_scanner.preproc_token of
  1257. _ID:
  1258. { system.char? (char=widechar comes from the implicit
  1259. uuchar unit -> override) }
  1260. if (current_scanner.preproc_pattern='CHAR') and
  1261. (tmodule(tunitsym(srsym).module).globalsymtable=systemunit) then
  1262. begin
  1263. if m_default_unicodestring in current_settings.modeswitches then
  1264. searchsym_in_module(tunitsym(srsym).module,'WIDECHAR',srsym,srsymtable)
  1265. else
  1266. searchsym_in_module(tunitsym(srsym).module,'ANSICHAR',srsym,srsymtable)
  1267. end
  1268. else
  1269. searchsym_in_module(tunitsym(srsym).module,current_scanner.preproc_pattern,srsym,srsymtable);
  1270. _STRING:
  1271. begin
  1272. { system.string? }
  1273. if tmodule(tunitsym(srsym).module).globalsymtable=systemunit then
  1274. begin
  1275. if cs_refcountedstrings in current_settings.localswitches then
  1276. begin
  1277. if m_default_unicodestring in current_settings.modeswitches then
  1278. searchsym_in_module(tunitsym(srsym).module,'UNICODESTRING',srsym,srsymtable)
  1279. else
  1280. searchsym_in_module(tunitsym(srsym).module,'ANSISTRING',srsym,srsymtable)
  1281. end
  1282. else
  1283. searchsym_in_module(tunitsym(srsym).module,'SHORTSTRING',srsym,srsymtable);
  1284. tokentoconsume:=_STRING;
  1285. end;
  1286. end
  1287. end;
  1288. end
  1289. else
  1290. begin
  1291. srsym:=nil;
  1292. srsymtable:=nil;
  1293. end;
  1294. result:=true;
  1295. end;
  1296. end;
  1297. procedure try_consume_nestedsym(var srsym:tsym;var srsymtable:TSymtable);
  1298. var
  1299. def:tdef;
  1300. tokentoconsume:ttoken;
  1301. found:boolean;
  1302. begin
  1303. found:=try_consume_unitsym(srsym,srsymtable,tokentoconsume);
  1304. if found then
  1305. begin
  1306. preproc_consume(tokentoconsume);
  1307. current_scanner.skipspace;
  1308. end;
  1309. while (current_scanner.preproc_token=_POINT) do
  1310. begin
  1311. if assigned(srsym)and(srsym.typ=typesym) then
  1312. begin
  1313. def:=ttypesym(srsym).typedef;
  1314. if is_class_or_object(def) or is_record(def) or is_java_class_or_interface(def) then
  1315. begin
  1316. preproc_consume(_POINT);
  1317. current_scanner.skipspace;
  1318. if def.typ=objectdef then
  1319. found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,[ssf_search_helper])
  1320. else
  1321. found:=searchsym_in_record(trecorddef(def),current_scanner.preproc_pattern,srsym,srsymtable);
  1322. if not found then
  1323. begin
  1324. Message1(sym_e_id_not_found,current_scanner.preproc_pattern);
  1325. exit;
  1326. end;
  1327. preproc_consume(_ID);
  1328. current_scanner.skipspace;
  1329. end
  1330. else
  1331. begin
  1332. Message(sym_e_type_must_be_rec_or_object_or_class);
  1333. exit;
  1334. end;
  1335. end
  1336. else
  1337. begin
  1338. Message(type_e_type_id_expected);
  1339. exit;
  1340. end;
  1341. end;
  1342. end;
  1343. function preproc_substitutedtoken(searchstr:string;eval:Boolean):texprvalue;
  1344. { Currently this parses identifiers as well as numbers.
  1345. The result from this procedure can either be that the token
  1346. itself is a value, or that it is a compile time variable/macro,
  1347. which then is substituted for another value (for macros
  1348. recursivelly substituted).}
  1349. var
  1350. hs: string;
  1351. mac: tmacro;
  1352. macrocount,
  1353. len: integer;
  1354. begin
  1355. if not eval then
  1356. begin
  1357. result:=texprvalue.create_str(searchstr);
  1358. exit;
  1359. end;
  1360. mac:=nil;
  1361. { Substitue macros and compiler variables with their content/value.
  1362. For real macros also do recursive substitution. }
  1363. macrocount:=0;
  1364. repeat
  1365. mac:=tmacro(search_macro(searchstr));
  1366. inc(macrocount);
  1367. if macrocount>max_macro_nesting then
  1368. begin
  1369. Message(scan_w_macro_too_deep);
  1370. break;
  1371. end;
  1372. if assigned(mac) and mac.defined then
  1373. if assigned(mac.buftext) then
  1374. begin
  1375. if mac.buflen>255 then
  1376. begin
  1377. len:=255;
  1378. Message(scan_w_macro_cut_after_255_chars);
  1379. end
  1380. else
  1381. len:=mac.buflen;
  1382. hs[0]:=char(len);
  1383. move(mac.buftext^,hs[1],len);
  1384. searchstr:=upcase(hs);
  1385. mac.is_used:=true;
  1386. end
  1387. else
  1388. begin
  1389. Message1(scan_e_error_macro_lacks_value,searchstr);
  1390. break;
  1391. end
  1392. else
  1393. break;
  1394. if mac.is_compiler_var then
  1395. break;
  1396. until false;
  1397. { At this point, result do contain the value. Do some decoding and
  1398. determine the type.}
  1399. result:=texprvalue.try_parse_number(searchstr);
  1400. if not assigned(result) then
  1401. begin
  1402. if assigned(mac) and (searchstr='FALSE') then
  1403. result:=texprvalue.create_bool(false)
  1404. else if assigned(mac) and (searchstr='TRUE') then
  1405. result:=texprvalue.create_bool(true)
  1406. else if (m_mac in current_settings.modeswitches) and
  1407. (not assigned(mac) or not mac.defined) and
  1408. (macrocount = 1) then
  1409. begin
  1410. {Errors in mode mac is issued here. For non macpas modes there is
  1411. more liberty, but the error will eventually be caught at a later stage.}
  1412. Message1(scan_e_error_macro_undefined,searchstr);
  1413. result:=texprvalue.create_str(searchstr); { just to have something }
  1414. end
  1415. else
  1416. result:=texprvalue.create_str(searchstr);
  1417. end;
  1418. end;
  1419. function preproc_factor(eval: Boolean):texprvalue;
  1420. var
  1421. hs,countstr,storedpattern: string;
  1422. mac: tmacro;
  1423. srsym : tsym;
  1424. srsymtable : TSymtable;
  1425. hdef : TDef;
  1426. l : longint;
  1427. hasKlammer: Boolean;
  1428. exprvalue:texprvalue;
  1429. ns:tnormalset;
  1430. begin
  1431. result:=nil;
  1432. hasKlammer:=false;
  1433. if current_scanner.preproc_token=_ID then
  1434. begin
  1435. if current_scanner.preproc_pattern='DEFINED' then
  1436. begin
  1437. preproc_consume(_ID);
  1438. current_scanner.skipspace;
  1439. if current_scanner.preproc_token =_LKLAMMER then
  1440. begin
  1441. preproc_consume(_LKLAMMER);
  1442. current_scanner.skipspace;
  1443. hasKlammer:= true;
  1444. end
  1445. else if (m_mac in current_settings.modeswitches) then
  1446. hasKlammer:= false
  1447. else
  1448. Message(scan_e_error_in_preproc_expr);
  1449. if current_scanner.preproc_token =_ID then
  1450. begin
  1451. hs := current_scanner.preproc_pattern;
  1452. mac := tmacro(search_macro(hs));
  1453. if assigned(mac) and mac.defined then
  1454. begin
  1455. result:=texprvalue.create_bool(true);
  1456. mac.is_used:=true;
  1457. end
  1458. else
  1459. result:=texprvalue.create_bool(false);
  1460. preproc_consume(_ID);
  1461. current_scanner.skipspace;
  1462. end
  1463. else
  1464. Message(scan_e_error_in_preproc_expr);
  1465. if hasKlammer then
  1466. if current_scanner.preproc_token =_RKLAMMER then
  1467. preproc_consume(_RKLAMMER)
  1468. else
  1469. Message(scan_e_error_in_preproc_expr);
  1470. end
  1471. else
  1472. if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='UNDEFINED') then
  1473. begin
  1474. preproc_consume(_ID);
  1475. current_scanner.skipspace;
  1476. if current_scanner.preproc_token =_ID then
  1477. begin
  1478. hs := current_scanner.preproc_pattern;
  1479. mac := tmacro(search_macro(hs));
  1480. if assigned(mac) then
  1481. begin
  1482. result:=texprvalue.create_bool(false);
  1483. mac.is_used:=true;
  1484. end
  1485. else
  1486. result:=texprvalue.create_bool(true);
  1487. preproc_consume(_ID);
  1488. current_scanner.skipspace;
  1489. end
  1490. else
  1491. Message(scan_e_error_in_preproc_expr);
  1492. end
  1493. else
  1494. if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='OPTION') then
  1495. begin
  1496. preproc_consume(_ID);
  1497. current_scanner.skipspace;
  1498. if current_scanner.preproc_token =_LKLAMMER then
  1499. begin
  1500. preproc_consume(_LKLAMMER);
  1501. current_scanner.skipspace;
  1502. end
  1503. else
  1504. Message(scan_e_error_in_preproc_expr);
  1505. if not (current_scanner.preproc_token = _ID) then
  1506. Message(scan_e_error_in_preproc_expr);
  1507. hs:=current_scanner.preproc_pattern;
  1508. if (length(hs) > 1) then
  1509. {This is allowed in Metrowerks Pascal}
  1510. Message(scan_e_error_in_preproc_expr)
  1511. else
  1512. begin
  1513. if CheckSwitch(hs[1],'+') then
  1514. result:=texprvalue.create_bool(true)
  1515. else
  1516. result:=texprvalue.create_bool(false);
  1517. end;
  1518. preproc_consume(_ID);
  1519. current_scanner.skipspace;
  1520. if current_scanner.preproc_token =_RKLAMMER then
  1521. preproc_consume(_RKLAMMER)
  1522. else
  1523. Message(scan_e_error_in_preproc_expr);
  1524. end
  1525. else
  1526. if current_scanner.preproc_pattern='SIZEOF' then
  1527. begin
  1528. preproc_consume(_ID);
  1529. current_scanner.skipspace;
  1530. if current_scanner.preproc_token =_LKLAMMER then
  1531. begin
  1532. preproc_consume(_LKLAMMER);
  1533. current_scanner.skipspace;
  1534. end
  1535. else
  1536. Message(scan_e_preproc_syntax_error);
  1537. storedpattern:=current_scanner.preproc_pattern;
  1538. preproc_consume(_ID);
  1539. current_scanner.skipspace;
  1540. if eval then
  1541. if searchsym(storedpattern,srsym,srsymtable) then
  1542. begin
  1543. try_consume_nestedsym(srsym,srsymtable);
  1544. l:=0;
  1545. if assigned(srsym) then
  1546. case srsym.typ of
  1547. staticvarsym,
  1548. localvarsym,
  1549. paravarsym :
  1550. l:=tabstractvarsym(srsym).getsize;
  1551. typesym:
  1552. l:=ttypesym(srsym).typedef.size;
  1553. else
  1554. Message(scan_e_error_in_preproc_expr);
  1555. end;
  1556. result:=texprvalue.create_int(l);
  1557. end
  1558. else
  1559. Message1(sym_e_id_not_found,storedpattern);
  1560. if current_scanner.preproc_token =_RKLAMMER then
  1561. preproc_consume(_RKLAMMER)
  1562. else
  1563. Message(scan_e_preproc_syntax_error);
  1564. end
  1565. else
  1566. if current_scanner.preproc_pattern='HIGH' then
  1567. begin
  1568. preproc_consume(_ID);
  1569. current_scanner.skipspace;
  1570. if current_scanner.preproc_token =_LKLAMMER then
  1571. begin
  1572. preproc_consume(_LKLAMMER);
  1573. current_scanner.skipspace;
  1574. end
  1575. else
  1576. Message(scan_e_preproc_syntax_error);
  1577. storedpattern:=current_scanner.preproc_pattern;
  1578. preproc_consume(_ID);
  1579. current_scanner.skipspace;
  1580. if eval then
  1581. if searchsym(storedpattern,srsym,srsymtable) then
  1582. begin
  1583. try_consume_nestedsym(srsym,srsymtable);
  1584. hdef:=nil;
  1585. hs:='';
  1586. l:=0;
  1587. if assigned(srsym) then
  1588. case srsym.typ of
  1589. staticvarsym,
  1590. localvarsym,
  1591. paravarsym :
  1592. hdef:=tabstractvarsym(srsym).vardef;
  1593. typesym:
  1594. hdef:=ttypesym(srsym).typedef;
  1595. else
  1596. Message(scan_e_error_in_preproc_expr);
  1597. end;
  1598. if assigned(hdef) then
  1599. begin
  1600. if hdef.typ=setdef then
  1601. hdef:=tsetdef(hdef).elementdef;
  1602. case hdef.typ of
  1603. orddef:
  1604. with torddef(hdef).high do
  1605. if signed then
  1606. result:=texprvalue.create_int(svalue)
  1607. else
  1608. result:=texprvalue.create_uint(uvalue);
  1609. enumdef:
  1610. result:=texprvalue.create_int(tenumdef(hdef).maxval);
  1611. arraydef:
  1612. if is_open_array(hdef) or is_array_of_const(hdef) or is_dynamic_array(hdef) then
  1613. Message(type_e_mismatch)
  1614. else
  1615. result:=texprvalue.create_int(tarraydef(hdef).highrange);
  1616. stringdef:
  1617. if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then
  1618. Message(type_e_mismatch)
  1619. else
  1620. result:=texprvalue.create_int(tstringdef(hdef).len);
  1621. else
  1622. Message(type_e_mismatch);
  1623. end;
  1624. end;
  1625. end
  1626. else
  1627. Message1(sym_e_id_not_found,storedpattern);
  1628. if current_scanner.preproc_token =_RKLAMMER then
  1629. preproc_consume(_RKLAMMER)
  1630. else
  1631. Message(scan_e_preproc_syntax_error);
  1632. end
  1633. else
  1634. if current_scanner.preproc_pattern='DECLARED' then
  1635. begin
  1636. preproc_consume(_ID);
  1637. current_scanner.skipspace;
  1638. if current_scanner.preproc_token =_LKLAMMER then
  1639. begin
  1640. preproc_consume(_LKLAMMER);
  1641. current_scanner.skipspace;
  1642. end
  1643. else
  1644. Message(scan_e_error_in_preproc_expr);
  1645. if current_scanner.preproc_token =_ID then
  1646. begin
  1647. hs := upper(current_scanner.preproc_pattern);
  1648. preproc_consume(_ID);
  1649. current_scanner.skipspace;
  1650. if current_scanner.preproc_token in [_LT,_LSHARPBRACKET] then
  1651. begin
  1652. l:=1;
  1653. preproc_consume(current_scanner.preproc_token);
  1654. current_scanner.skipspace;
  1655. while current_scanner.preproc_token=_COMMA do
  1656. begin
  1657. inc(l);
  1658. preproc_consume(_COMMA);
  1659. current_scanner.skipspace;
  1660. end;
  1661. if not (current_scanner.preproc_token in [_GT,_RSHARPBRACKET]) then
  1662. Message(scan_e_error_in_preproc_expr)
  1663. else
  1664. preproc_consume(current_scanner.preproc_token);
  1665. str(l,countstr);
  1666. hs:=hs+'$'+countstr;
  1667. end
  1668. else
  1669. { special case: <> }
  1670. if current_scanner.preproc_token=_NE then
  1671. begin
  1672. hs:=hs+'$1';
  1673. preproc_consume(_NE);
  1674. end;
  1675. current_scanner.skipspace;
  1676. if searchsym(hs,srsym,srsymtable) then
  1677. begin
  1678. { TSomeGeneric<...> also adds a TSomeGeneric symbol }
  1679. if (sp_generic_dummy in srsym.symoptions) and
  1680. (srsym.typ=typesym) and
  1681. (
  1682. { mode delphi}
  1683. (ttypesym(srsym).typedef.typ in [undefineddef,errordef]) or
  1684. { non-delphi modes }
  1685. (df_generic in ttypesym(srsym).typedef.defoptions)
  1686. ) then
  1687. result:=texprvalue.create_bool(false)
  1688. else
  1689. result:=texprvalue.create_bool(true);
  1690. end
  1691. else
  1692. result:=texprvalue.create_bool(false);
  1693. end
  1694. else
  1695. Message(scan_e_error_in_preproc_expr);
  1696. if current_scanner.preproc_token =_RKLAMMER then
  1697. preproc_consume(_RKLAMMER)
  1698. else
  1699. Message(scan_e_error_in_preproc_expr);
  1700. end
  1701. else
  1702. if current_scanner.preproc_pattern='ORD' then
  1703. begin
  1704. preproc_consume(_ID);
  1705. current_scanner.skipspace;
  1706. if current_scanner.preproc_token =_LKLAMMER then
  1707. begin
  1708. preproc_consume(_LKLAMMER);
  1709. current_scanner.skipspace;
  1710. end
  1711. else
  1712. Message(scan_e_preproc_syntax_error);
  1713. exprvalue:=preproc_factor(eval);
  1714. if eval then
  1715. begin
  1716. if is_ordinal(exprvalue.def) then
  1717. result:=texprvalue.create_int(exprvalue.asInt)
  1718. else
  1719. begin
  1720. exprvalue.error('Ordinal','ORD');
  1721. result:=texprvalue.create_int(0);
  1722. end;
  1723. end
  1724. else
  1725. result:=texprvalue.create_int(0);
  1726. exprvalue.free;
  1727. if current_scanner.preproc_token =_RKLAMMER then
  1728. preproc_consume(_RKLAMMER)
  1729. else
  1730. Message(scan_e_error_in_preproc_expr);
  1731. end
  1732. else
  1733. if current_scanner.preproc_pattern='NOT' then
  1734. begin
  1735. preproc_consume(_ID);
  1736. exprvalue:=preproc_factor(eval);
  1737. if eval then
  1738. result:=exprvalue.evaluate(nil,_OP_NOT)
  1739. else
  1740. result:=texprvalue.create_bool(false); {Just to have something}
  1741. exprvalue.free;
  1742. end
  1743. else
  1744. if (current_scanner.preproc_pattern='TRUE') then
  1745. begin
  1746. result:=texprvalue.create_bool(true);
  1747. preproc_consume(_ID);
  1748. end
  1749. else
  1750. if (current_scanner.preproc_pattern='FALSE') then
  1751. begin
  1752. result:=texprvalue.create_bool(false);
  1753. preproc_consume(_ID);
  1754. end
  1755. else
  1756. begin
  1757. storedpattern:=current_scanner.preproc_pattern;
  1758. preproc_consume(_ID);
  1759. current_scanner.skipspace;
  1760. { first look for a macros/int/float }
  1761. result:=preproc_substitutedtoken(storedpattern,eval);
  1762. if eval and (result.consttyp=conststring) then
  1763. if searchsym(storedpattern,srsym,srsymtable) then
  1764. begin
  1765. try_consume_nestedsym(srsym,srsymtable);
  1766. if assigned(srsym) then
  1767. case srsym.typ of
  1768. constsym:
  1769. begin
  1770. result.free;
  1771. result:=texprvalue.create_const(tconstsym(srsym));
  1772. end;
  1773. enumsym:
  1774. begin
  1775. result.free;
  1776. result:=texprvalue.create_int(tenumsym(srsym).value);
  1777. end;
  1778. end;
  1779. end;
  1780. end
  1781. end
  1782. else if current_scanner.preproc_token =_LKLAMMER then
  1783. begin
  1784. preproc_consume(_LKLAMMER);
  1785. result:=preproc_sub_expr(opcompare,eval);
  1786. preproc_consume(_RKLAMMER);
  1787. end
  1788. else if current_scanner.preproc_token = _LECKKLAMMER then
  1789. begin
  1790. preproc_consume(_LECKKLAMMER);
  1791. ns:=[];
  1792. while current_scanner.preproc_token in [_ID,_INTCONST] do
  1793. begin
  1794. exprvalue:=preproc_factor(eval);
  1795. include(ns,exprvalue.asInt);
  1796. if current_scanner.preproc_token = _COMMA then
  1797. preproc_consume(_COMMA);
  1798. end;
  1799. // TODO Add check of setElemType
  1800. preproc_consume(_RECKKLAMMER);
  1801. result:=texprvalue.create_set(ns);
  1802. end
  1803. else if current_scanner.preproc_token = _INTCONST then
  1804. begin
  1805. result:=texprvalue.try_parse_number(current_scanner.preproc_pattern);
  1806. if not assigned(result) then
  1807. begin
  1808. Message(parser_e_invalid_integer);
  1809. result:=texprvalue.create_int(1);
  1810. end;
  1811. preproc_consume(_INTCONST);
  1812. end
  1813. else if current_scanner.preproc_token = _REALNUMBER then
  1814. begin
  1815. result:=texprvalue.try_parse_real(current_scanner.preproc_pattern);
  1816. if not assigned(result) then
  1817. begin
  1818. Message(parser_e_error_in_real);
  1819. result:=texprvalue.create_real(1.0);
  1820. end;
  1821. preproc_consume(_REALNUMBER);
  1822. end
  1823. else
  1824. Message(scan_e_error_in_preproc_expr);
  1825. if not assigned(result) then
  1826. result:=texprvalue.create_error;
  1827. end;
  1828. function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean): texprvalue;
  1829. var
  1830. hs1,hs2: texprvalue;
  1831. op: ttoken;
  1832. begin
  1833. if pred_level=highest_precedence then
  1834. result:=preproc_factor(eval)
  1835. else
  1836. result:=preproc_sub_expr(succ(pred_level),eval);
  1837. repeat
  1838. op:=current_scanner.preproc_token;
  1839. if (op in preproc_operators) and
  1840. (op in operator_levels[pred_level]) then
  1841. begin
  1842. hs1:=result;
  1843. preproc_consume(op);
  1844. if (op=_OP_OR) and hs1.isBoolean and hs1.asBool then
  1845. begin
  1846. { stop evaluation the rest of expression }
  1847. result:=texprvalue.create_bool(true);
  1848. if pred_level=highest_precedence then
  1849. hs2:=preproc_factor(false)
  1850. else
  1851. hs2:=preproc_sub_expr(succ(pred_level),false);
  1852. end
  1853. else if (op=_OP_AND) and hs1.isBoolean and not hs1.asBool then
  1854. begin
  1855. { stop evaluation the rest of expression }
  1856. result:=texprvalue.create_bool(false);
  1857. if pred_level=highest_precedence then
  1858. hs2:=preproc_factor(false)
  1859. else
  1860. hs2:=preproc_sub_expr(succ(pred_level),false);
  1861. end
  1862. else
  1863. begin
  1864. if pred_level=highest_precedence then
  1865. hs2:=preproc_factor(eval)
  1866. else
  1867. hs2:=preproc_sub_expr(succ(pred_level),eval);
  1868. if eval then
  1869. result:=hs1.evaluate(hs2,op)
  1870. else
  1871. result:=texprvalue.create_bool(false); {Just to have something}
  1872. end;
  1873. hs1.free;
  1874. hs2.free;
  1875. end
  1876. else
  1877. break;
  1878. until false;
  1879. end;
  1880. begin
  1881. current_scanner.skipspace;
  1882. { start preproc expression scanner }
  1883. current_scanner.preproc_token:=current_scanner.readpreproc;
  1884. preproc_comp_expr:=preproc_sub_expr(opcompare,true);
  1885. end;
  1886. function boolean_compile_time_expr(var valuedescr: string): Boolean;
  1887. var
  1888. hs: texprvalue;
  1889. begin
  1890. hs:=preproc_comp_expr;
  1891. if hs.isBoolean then
  1892. result:=hs.asBool
  1893. else
  1894. begin
  1895. hs.error('Boolean', 'IF or ELSEIF');
  1896. result:=false;
  1897. end;
  1898. valuedescr:=hs.asStr;
  1899. hs.free;
  1900. end;
  1901. procedure dir_if;
  1902. begin
  1903. current_scanner.ifpreprocstack(pp_if,@boolean_compile_time_expr, scan_c_if_found);
  1904. end;
  1905. procedure dir_elseif;
  1906. begin
  1907. current_scanner.elseifpreprocstack(@boolean_compile_time_expr);
  1908. end;
  1909. procedure dir_define_impl(macstyle: boolean);
  1910. var
  1911. hs : string;
  1912. bracketcount : longint;
  1913. mac : tmacro;
  1914. macropos : longint;
  1915. macrobuffer : pmacrobuffer;
  1916. begin
  1917. current_scanner.skipspace;
  1918. hs:=current_scanner.readid;
  1919. mac:=tmacro(search_macro(hs));
  1920. if not assigned(mac) or (mac.owner <> current_module.localmacrosymtable) then
  1921. begin
  1922. mac:=tmacro.create(hs);
  1923. mac.defined:=true;
  1924. current_module.localmacrosymtable.insert(mac);
  1925. end
  1926. else
  1927. begin
  1928. mac.defined:=true;
  1929. mac.is_compiler_var:=false;
  1930. { delete old definition }
  1931. if assigned(mac.buftext) then
  1932. begin
  1933. freemem(mac.buftext,mac.buflen);
  1934. mac.buftext:=nil;
  1935. end;
  1936. end;
  1937. Message1(parser_c_macro_defined,mac.name);
  1938. mac.is_used:=true;
  1939. if (cs_support_macro in current_settings.moduleswitches) then
  1940. begin
  1941. current_scanner.skipspace;
  1942. if not macstyle then
  1943. begin
  1944. { may be a macro? }
  1945. if c <> ':' then
  1946. exit;
  1947. current_scanner.readchar;
  1948. if c <> '=' then
  1949. exit;
  1950. current_scanner.readchar;
  1951. current_scanner.skipspace;
  1952. end;
  1953. { key words are never substituted }
  1954. if is_keyword(hs) then
  1955. Message(scan_e_keyword_cant_be_a_macro);
  1956. new(macrobuffer);
  1957. macropos:=0;
  1958. { parse macro, brackets are counted so it's possible
  1959. to have a $ifdef etc. in the macro }
  1960. bracketcount:=0;
  1961. repeat
  1962. case c of
  1963. '}' :
  1964. if (bracketcount=0) then
  1965. break
  1966. else
  1967. dec(bracketcount);
  1968. '{' :
  1969. inc(bracketcount);
  1970. #10,#13 :
  1971. current_scanner.linebreak;
  1972. #26 :
  1973. current_scanner.end_of_file;
  1974. end;
  1975. macrobuffer^[macropos]:=c;
  1976. inc(macropos);
  1977. if macropos>=maxmacrolen then
  1978. Message(scan_f_macro_buffer_overflow);
  1979. current_scanner.readchar;
  1980. until false;
  1981. { free buffer of macro ?}
  1982. if assigned(mac.buftext) then
  1983. freemem(mac.buftext,mac.buflen);
  1984. { get new mem }
  1985. getmem(mac.buftext,macropos);
  1986. mac.buflen:=macropos;
  1987. { copy the text }
  1988. move(macrobuffer^,mac.buftext^,macropos);
  1989. dispose(macrobuffer);
  1990. end
  1991. else
  1992. begin
  1993. { check if there is an assignment, then we need to give a
  1994. warning }
  1995. current_scanner.skipspace;
  1996. if c=':' then
  1997. begin
  1998. current_scanner.readchar;
  1999. if c='=' then
  2000. Message(scan_w_macro_support_turned_off);
  2001. end;
  2002. end;
  2003. end;
  2004. procedure dir_define;
  2005. begin
  2006. dir_define_impl(false);
  2007. end;
  2008. procedure dir_definec;
  2009. begin
  2010. dir_define_impl(true);
  2011. end;
  2012. procedure dir_setc;
  2013. var
  2014. hs : string;
  2015. mac : tmacro;
  2016. l : longint;
  2017. w : integer;
  2018. exprvalue: texprvalue;
  2019. begin
  2020. current_scanner.skipspace;
  2021. hs:=current_scanner.readid;
  2022. mac:=tmacro(search_macro(hs));
  2023. if not assigned(mac) or
  2024. (mac.owner <> current_module.localmacrosymtable) then
  2025. begin
  2026. mac:=tmacro.create(hs);
  2027. mac.defined:=true;
  2028. mac.is_compiler_var:=true;
  2029. current_module.localmacrosymtable.insert(mac);
  2030. end
  2031. else
  2032. begin
  2033. mac.defined:=true;
  2034. mac.is_compiler_var:=true;
  2035. { delete old definition }
  2036. if assigned(mac.buftext) then
  2037. begin
  2038. freemem(mac.buftext,mac.buflen);
  2039. mac.buftext:=nil;
  2040. end;
  2041. end;
  2042. Message1(parser_c_macro_defined,mac.name);
  2043. mac.is_used:=true;
  2044. { key words are never substituted }
  2045. if is_keyword(hs) then
  2046. Message(scan_e_keyword_cant_be_a_macro);
  2047. { macro assignment can be both := and = }
  2048. current_scanner.skipspace;
  2049. if c=':' then
  2050. current_scanner.readchar;
  2051. if c='=' then
  2052. begin
  2053. current_scanner.readchar;
  2054. exprvalue:=preproc_comp_expr;
  2055. if not is_boolean(exprvalue.def) and
  2056. not is_integer(exprvalue.def) then
  2057. exprvalue.error('Boolean, Integer', 'SETC');
  2058. hs:=exprvalue.asStr;
  2059. if length(hs) <> 0 then
  2060. begin
  2061. {If we are absolutely shure it is boolean, translate
  2062. to TRUE/FALSE to increase possibility to do future type check}
  2063. if exprvalue.isBoolean then
  2064. begin
  2065. if exprvalue.asBool then
  2066. hs:='TRUE'
  2067. else
  2068. hs:='FALSE';
  2069. end;
  2070. Message2(parser_c_macro_set_to,mac.name,hs);
  2071. { free buffer of macro ?}
  2072. if assigned(mac.buftext) then
  2073. freemem(mac.buftext,mac.buflen);
  2074. { get new mem }
  2075. getmem(mac.buftext,length(hs));
  2076. mac.buflen:=length(hs);
  2077. { copy the text }
  2078. move(hs[1],mac.buftext^,mac.buflen);
  2079. end
  2080. else
  2081. Message(scan_e_preproc_syntax_error);
  2082. exprvalue.free;
  2083. end
  2084. else
  2085. Message(scan_e_preproc_syntax_error);
  2086. end;
  2087. procedure dir_undef;
  2088. var
  2089. hs : string;
  2090. mac : tmacro;
  2091. begin
  2092. current_scanner.skipspace;
  2093. hs:=current_scanner.readid;
  2094. mac:=tmacro(search_macro(hs));
  2095. if not assigned(mac) or
  2096. (mac.owner <> current_module.localmacrosymtable) then
  2097. begin
  2098. mac:=tmacro.create(hs);
  2099. mac.defined:=false;
  2100. current_module.localmacrosymtable.insert(mac);
  2101. end
  2102. else
  2103. begin
  2104. mac.defined:=false;
  2105. mac.is_compiler_var:=false;
  2106. { delete old definition }
  2107. if assigned(mac.buftext) then
  2108. begin
  2109. freemem(mac.buftext,mac.buflen);
  2110. mac.buftext:=nil;
  2111. end;
  2112. end;
  2113. Message1(parser_c_macro_undefined,mac.name);
  2114. mac.is_used:=true;
  2115. end;
  2116. procedure dir_include;
  2117. function findincludefile(const path,name:TCmdStr;var foundfile:TCmdStr):boolean;
  2118. var
  2119. found : boolean;
  2120. hpath : TCmdStr;
  2121. begin
  2122. (* look for the include file
  2123. If path was absolute and specified as part of {$I } then
  2124. 1. specified path
  2125. else
  2126. 1. path of current inputfile,current dir
  2127. 2. local includepath
  2128. 3. global includepath
  2129. -- Check mantis #13461 before changing this *)
  2130. found:=false;
  2131. foundfile:='';
  2132. hpath:='';
  2133. if path_absolute(path) then
  2134. begin
  2135. found:=FindFile(name,path,true,foundfile);
  2136. end
  2137. else
  2138. begin
  2139. hpath:=current_scanner.inputfile.path+';'+CurDirRelPath(source_info);
  2140. found:=FindFile(path+name, hpath,true,foundfile);
  2141. if not found then
  2142. found:=current_module.localincludesearchpath.FindFile(path+name,true,foundfile);
  2143. if not found then
  2144. found:=includesearchpath.FindFile(path+name,true,foundfile);
  2145. end;
  2146. result:=found;
  2147. end;
  2148. var
  2149. foundfile : TCmdStr;
  2150. path,
  2151. name,
  2152. hs : tpathstr;
  2153. args : string;
  2154. hp : tinputfile;
  2155. found : boolean;
  2156. macroIsString : boolean;
  2157. begin
  2158. current_scanner.skipspace;
  2159. args:=current_scanner.readcomment;
  2160. hs:=GetToken(args,' ');
  2161. if hs='' then
  2162. exit;
  2163. if (hs[1]='%') then
  2164. begin
  2165. { case insensitive }
  2166. hs:=upper(hs);
  2167. { remove %'s }
  2168. Delete(hs,1,1);
  2169. if hs[length(hs)]='%' then
  2170. Delete(hs,length(hs),1);
  2171. { save old }
  2172. path:=hs;
  2173. { first check for internal macros }
  2174. macroIsString:=true;
  2175. if hs='TIME' then
  2176. hs:=gettimestr
  2177. else
  2178. if hs='DATE' then
  2179. hs:=getdatestr
  2180. else
  2181. if hs='FILE' then
  2182. hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex)
  2183. else
  2184. if hs='LINE' then
  2185. hs:=tostr(current_filepos.line)
  2186. else
  2187. if hs='LINENUM' then
  2188. begin
  2189. hs:=tostr(current_filepos.line);
  2190. macroIsString:=false;
  2191. end
  2192. else
  2193. if hs='FPCVERSION' then
  2194. hs:=version_string
  2195. else
  2196. if hs='FPCDATE' then
  2197. hs:=date_string
  2198. else
  2199. if hs='FPCTARGET' then
  2200. hs:=target_cpu_string
  2201. else
  2202. if hs='FPCTARGETCPU' then
  2203. hs:=target_cpu_string
  2204. else
  2205. if hs='FPCTARGETOS' then
  2206. hs:=target_info.shortname
  2207. else
  2208. hs:=GetEnvironmentVariable(hs);
  2209. if hs='' then
  2210. Message1(scan_w_include_env_not_found,path);
  2211. { make it a stringconst }
  2212. if macroIsString then
  2213. hs:=''''+hs+'''';
  2214. current_scanner.substitutemacro(path,@hs[1],length(hs),
  2215. current_scanner.line_no,current_scanner.inputfile.ref_index);
  2216. end
  2217. else
  2218. begin
  2219. hs:=FixFileName(hs);
  2220. path:=ExtractFilePath(hs);
  2221. name:=ExtractFileName(hs);
  2222. { Special case for Delphi compatibility: '*' has to be replaced
  2223. by the file name of the current source file. }
  2224. if (length(name)>=1) and
  2225. (name[1]='*') then
  2226. name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);
  2227. { try to find the file }
  2228. found:=findincludefile(path,name,foundfile);
  2229. if (not found) and (ExtractFileExt(name)='') then
  2230. begin
  2231. { try default extensions .inc , .pp and .pas }
  2232. if (not found) then
  2233. found:=findincludefile(path,ChangeFileExt(name,'.inc'),foundfile);
  2234. if (not found) then
  2235. found:=findincludefile(path,ChangeFileExt(name,sourceext),foundfile);
  2236. if (not found) then
  2237. found:=findincludefile(path,ChangeFileExt(name,pasext),foundfile);
  2238. end;
  2239. if current_scanner.inputfilecount<max_include_nesting then
  2240. begin
  2241. inc(current_scanner.inputfilecount);
  2242. { we need to reread the current char }
  2243. dec(current_scanner.inputpointer);
  2244. { shutdown current file }
  2245. current_scanner.tempcloseinputfile;
  2246. { load new file }
  2247. hp:=do_openinputfile(foundfile);
  2248. hp.inc_path:=path;
  2249. current_scanner.addfile(hp);
  2250. current_module.sourcefiles.register_file(hp);
  2251. if (not found) then
  2252. Message1(scan_f_cannot_open_includefile,hs);
  2253. if (not current_scanner.openinputfile) then
  2254. Message1(scan_f_cannot_open_includefile,hs);
  2255. Message1(scan_t_start_include_file,current_scanner.inputfile.path+current_scanner.inputfile.name);
  2256. current_scanner.reload;
  2257. end
  2258. else
  2259. Message(scan_f_include_deep_ten);
  2260. end;
  2261. end;
  2262. {*****************************************************************************
  2263. Preprocessor writing
  2264. *****************************************************************************}
  2265. {$ifdef PREPROCWRITE}
  2266. constructor tpreprocfile.create(const fn:string);
  2267. begin
  2268. { open outputfile }
  2269. assign(f,fn);
  2270. {$push}{$I-}
  2271. rewrite(f);
  2272. {$pop}
  2273. if ioresult<>0 then
  2274. Comment(V_Fatal,'can''t create file '+fn);
  2275. getmem(buf,preprocbufsize);
  2276. settextbuf(f,buf^,preprocbufsize);
  2277. { reset }
  2278. eolfound:=false;
  2279. spacefound:=false;
  2280. end;
  2281. destructor tpreprocfile.destroy;
  2282. begin
  2283. close(f);
  2284. freemem(buf,preprocbufsize);
  2285. end;
  2286. procedure tpreprocfile.add(const s:string);
  2287. begin
  2288. write(f,s);
  2289. end;
  2290. procedure tpreprocfile.addspace;
  2291. begin
  2292. if eolfound then
  2293. begin
  2294. writeln(f,'');
  2295. eolfound:=false;
  2296. spacefound:=false;
  2297. end
  2298. else
  2299. if spacefound then
  2300. begin
  2301. write(f,' ');
  2302. spacefound:=false;
  2303. end;
  2304. end;
  2305. {$endif PREPROCWRITE}
  2306. {*****************************************************************************
  2307. TPreProcStack
  2308. *****************************************************************************}
  2309. constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
  2310. begin
  2311. accept:=a;
  2312. typ:=atyp;
  2313. next:=n;
  2314. end;
  2315. {*****************************************************************************
  2316. TReplayStack
  2317. *****************************************************************************}
  2318. constructor treplaystack.Create(atoken:ttoken;asettings:tsettings;
  2319. atokenbuf:tdynamicarray;anext:treplaystack);
  2320. begin
  2321. token:=atoken;
  2322. settings:=asettings;
  2323. tokenbuf:=atokenbuf;
  2324. next:=anext;
  2325. end;
  2326. {*****************************************************************************
  2327. TDirectiveItem
  2328. *****************************************************************************}
  2329. constructor TDirectiveItem.Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  2330. begin
  2331. inherited Create(AList,n);
  2332. is_conditional:=false;
  2333. proc:=p;
  2334. end;
  2335. constructor TDirectiveItem.CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  2336. begin
  2337. inherited Create(AList,n);
  2338. is_conditional:=true;
  2339. proc:=p;
  2340. end;
  2341. {****************************************************************************
  2342. TSCANNERFILE
  2343. ****************************************************************************}
  2344. constructor tscannerfile.create(const fn:string; is_macro: boolean = false);
  2345. begin
  2346. inputfile:=do_openinputfile(fn);
  2347. if is_macro then
  2348. inputfile.is_macro:=true;
  2349. if assigned(current_module) then
  2350. current_module.sourcefiles.register_file(inputfile);
  2351. { reset localinput }
  2352. c:=#0;
  2353. inputbuffer:=nil;
  2354. inputpointer:=nil;
  2355. inputstart:=0;
  2356. { reset scanner }
  2357. preprocstack:=nil;
  2358. replaystack:=nil;
  2359. comment_level:=0;
  2360. yylexcount:=0;
  2361. block_type:=bt_general;
  2362. line_no:=0;
  2363. lastlinepos:=0;
  2364. lasttokenpos:=0;
  2365. nexttokenpos:=0;
  2366. lasttoken:=NOTOKEN;
  2367. nexttoken:=NOTOKEN;
  2368. lastasmgetchar:=#0;
  2369. ignoredirectives:=TFPHashList.Create;
  2370. in_asm_string:=false;
  2371. end;
  2372. procedure tscannerfile.firstfile;
  2373. begin
  2374. { load block }
  2375. if not openinputfile then
  2376. Message1(scan_f_cannot_open_input,inputfile.name);
  2377. reload;
  2378. end;
  2379. destructor tscannerfile.destroy;
  2380. begin
  2381. if assigned(current_module) and
  2382. (current_module.state=ms_compiled) and
  2383. (status.errorcount=0) then
  2384. checkpreprocstack
  2385. else
  2386. begin
  2387. while assigned(preprocstack) do
  2388. poppreprocstack;
  2389. end;
  2390. while assigned(replaystack) do
  2391. popreplaystack;
  2392. if not inputfile.closed then
  2393. closeinputfile;
  2394. if inputfile.is_macro then
  2395. inputfile.free;
  2396. ignoredirectives.free;
  2397. end;
  2398. function tscannerfile.openinputfile:boolean;
  2399. begin
  2400. openinputfile:=inputfile.open;
  2401. { load buffer }
  2402. inputbuffer:=inputfile.buf;
  2403. inputpointer:=inputfile.buf;
  2404. inputstart:=inputfile.bufstart;
  2405. { line }
  2406. line_no:=0;
  2407. lastlinepos:=0;
  2408. lasttokenpos:=0;
  2409. nexttokenpos:=0;
  2410. end;
  2411. procedure tscannerfile.closeinputfile;
  2412. begin
  2413. inputfile.close;
  2414. { reset buffer }
  2415. inputbuffer:=nil;
  2416. inputpointer:=nil;
  2417. inputstart:=0;
  2418. { reset line }
  2419. line_no:=0;
  2420. lastlinepos:=0;
  2421. lasttokenpos:=0;
  2422. nexttokenpos:=0;
  2423. end;
  2424. function tscannerfile.tempopeninputfile:boolean;
  2425. begin
  2426. tempopeninputfile:=false;
  2427. if inputfile.is_macro then
  2428. exit;
  2429. tempopeninputfile:=inputfile.tempopen;
  2430. { reload buffer }
  2431. inputbuffer:=inputfile.buf;
  2432. inputpointer:=inputfile.buf;
  2433. inputstart:=inputfile.bufstart;
  2434. end;
  2435. procedure tscannerfile.tempcloseinputfile;
  2436. begin
  2437. if inputfile.closed or inputfile.is_macro then
  2438. exit;
  2439. inputfile.setpos(inputstart+(inputpointer-inputbuffer));
  2440. inputfile.tempclose;
  2441. { reset buffer }
  2442. inputbuffer:=nil;
  2443. inputpointer:=nil;
  2444. inputstart:=0;
  2445. end;
  2446. procedure tscannerfile.saveinputfile;
  2447. begin
  2448. inputfile.saveinputpointer:=inputpointer;
  2449. inputfile.savelastlinepos:=lastlinepos;
  2450. inputfile.saveline_no:=line_no;
  2451. end;
  2452. procedure tscannerfile.restoreinputfile;
  2453. begin
  2454. inputbuffer:=inputfile.buf;
  2455. inputpointer:=inputfile.saveinputpointer;
  2456. lastlinepos:=inputfile.savelastlinepos;
  2457. line_no:=inputfile.saveline_no;
  2458. if not inputfile.is_macro then
  2459. parser_current_file:=inputfile.name;
  2460. end;
  2461. procedure tscannerfile.nextfile;
  2462. var
  2463. to_dispose : tinputfile;
  2464. begin
  2465. if assigned(inputfile.next) then
  2466. begin
  2467. if inputfile.is_macro then
  2468. to_dispose:=inputfile
  2469. else
  2470. begin
  2471. to_dispose:=nil;
  2472. dec(inputfilecount);
  2473. end;
  2474. { we can allways close the file, no ? }
  2475. inputfile.close;
  2476. inputfile:=inputfile.next;
  2477. if assigned(to_dispose) then
  2478. to_dispose.free;
  2479. restoreinputfile;
  2480. end;
  2481. end;
  2482. procedure tscannerfile.startrecordtokens(buf:tdynamicarray);
  2483. begin
  2484. if not assigned(buf) then
  2485. internalerror(200511172);
  2486. if assigned(recordtokenbuf) then
  2487. internalerror(200511173);
  2488. recordtokenbuf:=buf;
  2489. fillchar(last_settings,sizeof(last_settings),0);
  2490. last_message:=nil;
  2491. fillchar(last_filepos,sizeof(last_filepos),0);
  2492. end;
  2493. procedure tscannerfile.stoprecordtokens;
  2494. begin
  2495. if not assigned(recordtokenbuf) then
  2496. internalerror(200511174);
  2497. recordtokenbuf:=nil;
  2498. end;
  2499. procedure tscannerfile.writetoken(t : ttoken);
  2500. var
  2501. b : byte;
  2502. begin
  2503. if ord(t)>$7f then
  2504. begin
  2505. b:=(ord(t) shr 8) or $80;
  2506. recordtokenbuf.write(b,1);
  2507. end;
  2508. b:=ord(t) and $ff;
  2509. recordtokenbuf.write(b,1);
  2510. end;
  2511. procedure tscannerfile.tokenwritesizeint(val : asizeint);
  2512. begin
  2513. {$ifdef FPC_BIG_ENDIAN}
  2514. val:=swapendian(val);
  2515. {$endif}
  2516. recordtokenbuf.write(val,sizeof(asizeint));
  2517. end;
  2518. procedure tscannerfile.tokenwritelongint(val : longint);
  2519. begin
  2520. {$ifdef FPC_BIG_ENDIAN}
  2521. val:=swapendian(val);
  2522. {$endif}
  2523. recordtokenbuf.write(val,sizeof(longint));
  2524. end;
  2525. procedure tscannerfile.tokenwriteshortint(val : shortint);
  2526. begin
  2527. recordtokenbuf.write(val,sizeof(shortint));
  2528. end;
  2529. procedure tscannerfile.tokenwriteword(val : word);
  2530. begin
  2531. {$ifdef FPC_BIG_ENDIAN}
  2532. val:=swapendian(val);
  2533. {$endif}
  2534. recordtokenbuf.write(val,sizeof(word));
  2535. end;
  2536. procedure tscannerfile.tokenwritelongword(val : longword);
  2537. begin
  2538. {$ifdef FPC_BIG_ENDIAN}
  2539. val:=swapendian(val);
  2540. {$endif}
  2541. recordtokenbuf.write(val,sizeof(longword));
  2542. end;
  2543. function tscannerfile.tokenreadsizeint : asizeint;
  2544. var
  2545. val : asizeint;
  2546. begin
  2547. replaytokenbuf.read(val,sizeof(asizeint));
  2548. {$ifdef FPC_BIG_ENDIAN}
  2549. val:=swapendian(val);
  2550. {$endif}
  2551. result:=val;
  2552. end;
  2553. function tscannerfile.tokenreadlongword : longword;
  2554. var
  2555. val : longword;
  2556. begin
  2557. replaytokenbuf.read(val,sizeof(longword));
  2558. {$ifdef FPC_BIG_ENDIAN}
  2559. val:=swapendian(val);
  2560. {$endif}
  2561. result:=val;
  2562. end;
  2563. function tscannerfile.tokenreadlongint : longint;
  2564. var
  2565. val : longint;
  2566. begin
  2567. replaytokenbuf.read(val,sizeof(longint));
  2568. {$ifdef FPC_BIG_ENDIAN}
  2569. val:=swapendian(val);
  2570. {$endif}
  2571. result:=val;
  2572. end;
  2573. function tscannerfile.tokenreadshortint : shortint;
  2574. var
  2575. val : shortint;
  2576. begin
  2577. replaytokenbuf.read(val,sizeof(shortint));
  2578. result:=val;
  2579. end;
  2580. function tscannerfile.tokenreadbyte : byte;
  2581. var
  2582. val : byte;
  2583. begin
  2584. replaytokenbuf.read(val,sizeof(byte));
  2585. result:=val;
  2586. end;
  2587. function tscannerfile.tokenreadsmallint : smallint;
  2588. var
  2589. val : smallint;
  2590. begin
  2591. replaytokenbuf.read(val,sizeof(smallint));
  2592. {$ifdef FPC_BIG_ENDIAN}
  2593. val:=swapendian(val);
  2594. {$endif}
  2595. result:=val;
  2596. end;
  2597. function tscannerfile.tokenreadword : word;
  2598. var
  2599. val : word;
  2600. begin
  2601. replaytokenbuf.read(val,sizeof(word));
  2602. {$ifdef FPC_BIG_ENDIAN}
  2603. val:=swapendian(val);
  2604. {$endif}
  2605. result:=val;
  2606. end;
  2607. function tscannerfile.tokenreadenum(size : longint) : longword;
  2608. begin
  2609. if size=1 then
  2610. result:=tokenreadbyte
  2611. else if size=2 then
  2612. result:=tokenreadword
  2613. else if size=4 then
  2614. result:=tokenreadlongword
  2615. else
  2616. internalerror(2013112901);
  2617. end;
  2618. procedure tscannerfile.tokenreadset(var b;size : longint);
  2619. {$ifdef FPC_BIG_ENDIAN}
  2620. var
  2621. i : longint;
  2622. {$endif}
  2623. begin
  2624. replaytokenbuf.read(b,size);
  2625. {$ifdef FPC_BIG_ENDIAN}
  2626. for i:=0 to size-1 do
  2627. Pbyte(@b)[i]:=reverse_byte(Pbyte(@b)[i]);
  2628. {$endif}
  2629. end;
  2630. procedure tscannerfile.tokenwriteenum(var b;size : longint);
  2631. begin
  2632. recordtokenbuf.write(b,size);
  2633. end;
  2634. procedure tscannerfile.tokenwriteset(var b;size : longint);
  2635. {$ifdef FPC_BIG_ENDIAN}
  2636. var
  2637. i: longint;
  2638. tmpset: array[0..31] of byte;
  2639. {$endif}
  2640. begin
  2641. {$ifdef FPC_BIG_ENDIAN}
  2642. { satisfy DFA because it assumes that size may be 0 and doesn't know that
  2643. recordtokenbuf.write wouldn't use tmpset in that case }
  2644. tmpset[0]:=0;
  2645. for i:=0 to size-1 do
  2646. tmpset[i]:=reverse_byte(Pbyte(@b)[i]);
  2647. recordtokenbuf.write(tmpset,size);
  2648. {$else}
  2649. recordtokenbuf.write(b,size);
  2650. {$endif}
  2651. end;
  2652. procedure tscannerfile.tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
  2653. { This procedure
  2654. needs to be changed whenever
  2655. globals.tsettings type is changed,
  2656. the problem is that no error will appear
  2657. before tests with generics are tested. PM }
  2658. var
  2659. startpos, endpos : longword;
  2660. begin
  2661. { WARNING all those fields need to be in the correct
  2662. order otherwise cross_endian PPU reading will fail }
  2663. startpos:=replaytokenbuf.pos;
  2664. with asettings do
  2665. begin
  2666. alignment.procalign:=tokenreadlongint;
  2667. alignment.loopalign:=tokenreadlongint;
  2668. alignment.jumpalign:=tokenreadlongint;
  2669. alignment.constalignmin:=tokenreadlongint;
  2670. alignment.constalignmax:=tokenreadlongint;
  2671. alignment.varalignmin:=tokenreadlongint;
  2672. alignment.varalignmax:=tokenreadlongint;
  2673. alignment.localalignmin:=tokenreadlongint;
  2674. alignment.localalignmax:=tokenreadlongint;
  2675. alignment.recordalignmin:=tokenreadlongint;
  2676. alignment.recordalignmax:=tokenreadlongint;
  2677. alignment.maxCrecordalign:=tokenreadlongint;
  2678. tokenreadset(globalswitches,sizeof(globalswitches));
  2679. tokenreadset(targetswitches,sizeof(targetswitches));
  2680. tokenreadset(moduleswitches,sizeof(moduleswitches));
  2681. tokenreadset(localswitches,sizeof(localswitches));
  2682. tokenreadset(modeswitches,sizeof(modeswitches));
  2683. tokenreadset(optimizerswitches,sizeof(optimizerswitches));
  2684. tokenreadset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
  2685. tokenreadset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
  2686. tokenreadset(debugswitches,sizeof(debugswitches));
  2687. { 0: old behaviour for sets <=256 elements
  2688. >0: round to this size }
  2689. setalloc:=tokenreadshortint;
  2690. packenum:=tokenreadshortint;
  2691. packrecords:=tokenreadshortint;
  2692. maxfpuregisters:=tokenreadshortint;
  2693. cputype:=tcputype(tokenreadenum(sizeof(tcputype)));
  2694. optimizecputype:=tcputype(tokenreadenum(sizeof(tcputype)));
  2695. fputype:=tfputype(tokenreadenum(sizeof(tfputype)));
  2696. asmmode:=tasmmode(tokenreadenum(sizeof(tasmmode)));
  2697. interfacetype:=tinterfacetypes(tokenreadenum(sizeof(tinterfacetypes)));
  2698. defproccall:=tproccalloption(tokenreadenum(sizeof(tproccalloption)));
  2699. { tstringencoding is word type,
  2700. thus this should be OK here }
  2701. sourcecodepage:=tstringEncoding(tokenreadword);
  2702. minfpconstprec:=tfloattype(tokenreadenum(sizeof(tfloattype)));
  2703. disabledircache:=boolean(tokenreadbyte);
  2704. {$if defined(ARM) or defined(AVR) or defined(MIPSEL)}
  2705. controllertype:=tcontrollertype(tokenreadenum(sizeof(tcontrollertype)));
  2706. {$endif defined(ARM) or defined(AVR) or DEFINED(MIPSEL)}
  2707. endpos:=replaytokenbuf.pos;
  2708. if endpos-startpos<>expected_size then
  2709. Comment(V_Error,'Wrong size of Settings read-in');
  2710. end;
  2711. end;
  2712. procedure tscannerfile.tokenwritesettings(var asettings : tsettings; var size : asizeint);
  2713. { This procedure
  2714. needs to be changed whenever
  2715. globals.tsettings type is changed,
  2716. the problem is that no error will appear
  2717. before tests with generics are tested. PM }
  2718. var
  2719. sizepos, startpos, endpos : longword;
  2720. begin
  2721. { WARNING all those fields need to be in the correct
  2722. order otherwise cross_endian PPU reading will fail }
  2723. sizepos:=recordtokenbuf.pos;
  2724. size:=0;
  2725. tokenwritesizeint(size);
  2726. startpos:=recordtokenbuf.pos;
  2727. with asettings do
  2728. begin
  2729. tokenwritelongint(alignment.procalign);
  2730. tokenwritelongint(alignment.loopalign);
  2731. tokenwritelongint(alignment.jumpalign);
  2732. tokenwritelongint(alignment.constalignmin);
  2733. tokenwritelongint(alignment.constalignmax);
  2734. tokenwritelongint(alignment.varalignmin);
  2735. tokenwritelongint(alignment.varalignmax);
  2736. tokenwritelongint(alignment.localalignmin);
  2737. tokenwritelongint(alignment.localalignmax);
  2738. tokenwritelongint(alignment.recordalignmin);
  2739. tokenwritelongint(alignment.recordalignmax);
  2740. tokenwritelongint(alignment.maxCrecordalign);
  2741. tokenwriteset(globalswitches,sizeof(globalswitches));
  2742. tokenwriteset(targetswitches,sizeof(targetswitches));
  2743. tokenwriteset(moduleswitches,sizeof(moduleswitches));
  2744. tokenwriteset(localswitches,sizeof(localswitches));
  2745. tokenwriteset(modeswitches,sizeof(modeswitches));
  2746. tokenwriteset(optimizerswitches,sizeof(optimizerswitches));
  2747. tokenwriteset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
  2748. tokenwriteset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
  2749. tokenwriteset(debugswitches,sizeof(debugswitches));
  2750. { 0: old behaviour for sets <=256 elements
  2751. >0: round to this size }
  2752. tokenwriteshortint(setalloc);
  2753. tokenwriteshortint(packenum);
  2754. tokenwriteshortint(packrecords);
  2755. tokenwriteshortint(maxfpuregisters);
  2756. tokenwriteenum(cputype,sizeof(tcputype));
  2757. tokenwriteenum(optimizecputype,sizeof(tcputype));
  2758. tokenwriteenum(fputype,sizeof(tfputype));
  2759. tokenwriteenum(asmmode,sizeof(tasmmode));
  2760. tokenwriteenum(interfacetype,sizeof(tinterfacetypes));
  2761. tokenwriteenum(defproccall,sizeof(tproccalloption));
  2762. { tstringencoding is word type,
  2763. thus this should be OK here }
  2764. tokenwriteword(sourcecodepage);
  2765. tokenwriteenum(minfpconstprec,sizeof(tfloattype));
  2766. recordtokenbuf.write(byte(disabledircache),1);
  2767. {$if defined(ARM) or defined(AVR) or defined(MIPSEL)}
  2768. tokenwriteenum(controllertype,sizeof(tcontrollertype));
  2769. {$endif defined(ARM) or defined(AVR) or defined(MIPSEL)}
  2770. endpos:=recordtokenbuf.pos;
  2771. size:=endpos-startpos;
  2772. recordtokenbuf.seek(sizepos);
  2773. tokenwritesizeint(size);
  2774. recordtokenbuf.seek(endpos);
  2775. end;
  2776. end;
  2777. procedure tscannerfile.recordtoken;
  2778. var
  2779. t : ttoken;
  2780. s : tspecialgenerictoken;
  2781. len,msgnb,copy_size : asizeint;
  2782. val : longint;
  2783. b : byte;
  2784. pmsg : pmessagestaterecord;
  2785. begin
  2786. if not assigned(recordtokenbuf) then
  2787. internalerror(200511176);
  2788. t:=_GENERICSPECIALTOKEN;
  2789. { settings changed? }
  2790. { last field pmessage is handled separately below in
  2791. ST_LOADMESSAGES }
  2792. if CompareByte(current_settings,last_settings,
  2793. sizeof(current_settings)-sizeof(pointer))<>0 then
  2794. begin
  2795. { use a special token to record it }
  2796. s:=ST_LOADSETTINGS;
  2797. writetoken(t);
  2798. recordtokenbuf.write(s,1);
  2799. copy_size:=sizeof(current_settings)-sizeof(pointer);
  2800. tokenwritesettings(current_settings,copy_size);
  2801. last_settings:=current_settings;
  2802. end;
  2803. if current_settings.pmessage<>last_message then
  2804. begin
  2805. { use a special token to record it }
  2806. s:=ST_LOADMESSAGES;
  2807. writetoken(t);
  2808. recordtokenbuf.write(s,1);
  2809. msgnb:=0;
  2810. pmsg:=current_settings.pmessage;
  2811. while assigned(pmsg) do
  2812. begin
  2813. if msgnb=high(asizeint) then
  2814. { Too many messages }
  2815. internalerror(2011090401);
  2816. inc(msgnb);
  2817. pmsg:=pmsg^.next;
  2818. end;
  2819. tokenwritesizeint(msgnb);
  2820. pmsg:=current_settings.pmessage;
  2821. while assigned(pmsg) do
  2822. begin
  2823. { What about endianess here?}
  2824. { SB: this is handled by tokenreadlongint }
  2825. val:=pmsg^.value;
  2826. tokenwritelongint(val);
  2827. val:=ord(pmsg^.state);
  2828. tokenwritelongint(val);
  2829. pmsg:=pmsg^.next;
  2830. end;
  2831. last_message:=current_settings.pmessage;
  2832. end;
  2833. { file pos changes? }
  2834. if current_tokenpos.line<>last_filepos.line then
  2835. begin
  2836. s:=ST_LINE;
  2837. writetoken(t);
  2838. recordtokenbuf.write(s,1);
  2839. tokenwritelongint(current_tokenpos.line);
  2840. last_filepos.line:=current_tokenpos.line;
  2841. end;
  2842. if current_tokenpos.column<>last_filepos.column then
  2843. begin
  2844. s:=ST_COLUMN;
  2845. writetoken(t);
  2846. { can the column be written packed? }
  2847. if current_tokenpos.column<$80 then
  2848. begin
  2849. b:=$80 or current_tokenpos.column;
  2850. recordtokenbuf.write(b,1);
  2851. end
  2852. else
  2853. begin
  2854. recordtokenbuf.write(s,1);
  2855. tokenwriteword(current_tokenpos.column);
  2856. end;
  2857. last_filepos.column:=current_tokenpos.column;
  2858. end;
  2859. if current_tokenpos.fileindex<>last_filepos.fileindex then
  2860. begin
  2861. s:=ST_FILEINDEX;
  2862. writetoken(t);
  2863. recordtokenbuf.write(s,1);
  2864. tokenwriteword(current_tokenpos.fileindex);
  2865. last_filepos.fileindex:=current_tokenpos.fileindex;
  2866. end;
  2867. writetoken(token);
  2868. if token<>_GENERICSPECIALTOKEN then
  2869. writetoken(idtoken);
  2870. case token of
  2871. _CWCHAR,
  2872. _CWSTRING :
  2873. begin
  2874. tokenwritesizeint(patternw^.len);
  2875. if patternw^.len>0 then
  2876. recordtokenbuf.write(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
  2877. end;
  2878. _CSTRING:
  2879. begin
  2880. len:=length(cstringpattern);
  2881. tokenwritesizeint(len);
  2882. if len>0 then
  2883. recordtokenbuf.write(cstringpattern[1],len);
  2884. end;
  2885. _CCHAR,
  2886. _INTCONST,
  2887. _REALNUMBER :
  2888. begin
  2889. { pexpr.pas messes with pattern in case of negative integer consts,
  2890. see around line 2562 the comment of JM; remove the - before recording it
  2891. (FK)
  2892. }
  2893. if (token=_INTCONST) and (pattern[1]='-') then
  2894. delete(pattern,1,1);
  2895. recordtokenbuf.write(pattern[0],1);
  2896. recordtokenbuf.write(pattern[1],length(pattern));
  2897. end;
  2898. _ID :
  2899. begin
  2900. recordtokenbuf.write(orgpattern[0],1);
  2901. recordtokenbuf.write(orgpattern[1],length(orgpattern));
  2902. end;
  2903. end;
  2904. end;
  2905. procedure tscannerfile.startreplaytokens(buf:tdynamicarray);
  2906. begin
  2907. if not assigned(buf) then
  2908. internalerror(200511175);
  2909. { save current token }
  2910. if token in [_CWCHAR,_CWSTRING,_CCHAR,_CSTRING,_INTCONST,_REALNUMBER,_ID] then
  2911. internalerror(200511178);
  2912. replaystack:=treplaystack.create(token,current_settings,
  2913. replaytokenbuf,replaystack);
  2914. if assigned(inputpointer) then
  2915. dec(inputpointer);
  2916. { install buffer }
  2917. replaytokenbuf:=buf;
  2918. { reload next token }
  2919. replaytokenbuf.seek(0);
  2920. replaytoken;
  2921. end;
  2922. function tscannerfile.readtoken: ttoken;
  2923. var
  2924. b,b2 : byte;
  2925. begin
  2926. replaytokenbuf.read(b,1);
  2927. if (b and $80)<>0 then
  2928. begin
  2929. replaytokenbuf.read(b2,1);
  2930. result:=ttoken(((b and $7f) shl 8) or b2);
  2931. end
  2932. else
  2933. result:=ttoken(b);
  2934. end;
  2935. procedure tscannerfile.replaytoken;
  2936. var
  2937. wlen,mesgnb,copy_size : asizeint;
  2938. specialtoken : tspecialgenerictoken;
  2939. i : byte;
  2940. pmsg,prevmsg : pmessagestaterecord;
  2941. begin
  2942. if not assigned(replaytokenbuf) then
  2943. internalerror(200511177);
  2944. { End of replay buffer? Then load the next char from the file again }
  2945. if replaytokenbuf.pos>=replaytokenbuf.size then
  2946. begin
  2947. token:=replaystack.token;
  2948. replaytokenbuf:=replaystack.tokenbuf;
  2949. { restore compiler settings }
  2950. current_settings:=replaystack.settings;
  2951. popreplaystack;
  2952. if assigned(inputpointer) then
  2953. begin
  2954. c:=inputpointer^;
  2955. inc(inputpointer);
  2956. end;
  2957. exit;
  2958. end;
  2959. repeat
  2960. { load token from the buffer }
  2961. token:=readtoken;
  2962. if token<>_GENERICSPECIALTOKEN then
  2963. idtoken:=readtoken
  2964. else
  2965. idtoken:=_NOID;
  2966. case token of
  2967. _CWCHAR,
  2968. _CWSTRING :
  2969. begin
  2970. wlen:=tokenreadsizeint;
  2971. setlengthwidestring(patternw,wlen);
  2972. if wlen>0 then
  2973. replaytokenbuf.read(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
  2974. orgpattern:='';
  2975. pattern:='';
  2976. cstringpattern:='';
  2977. end;
  2978. _CSTRING:
  2979. begin
  2980. wlen:=tokenreadsizeint;
  2981. if wlen>0 then
  2982. begin
  2983. setlength(cstringpattern,wlen);
  2984. replaytokenbuf.read(cstringpattern[1],wlen);
  2985. end
  2986. else
  2987. cstringpattern:='';
  2988. orgpattern:='';
  2989. pattern:='';
  2990. end;
  2991. _CCHAR,
  2992. _INTCONST,
  2993. _REALNUMBER :
  2994. begin
  2995. replaytokenbuf.read(pattern[0],1);
  2996. replaytokenbuf.read(pattern[1],length(pattern));
  2997. orgpattern:='';
  2998. end;
  2999. _ID :
  3000. begin
  3001. replaytokenbuf.read(orgpattern[0],1);
  3002. replaytokenbuf.read(orgpattern[1],length(orgpattern));
  3003. pattern:=upper(orgpattern);
  3004. end;
  3005. _GENERICSPECIALTOKEN:
  3006. begin
  3007. replaytokenbuf.read(specialtoken,1);
  3008. { packed column? }
  3009. if (ord(specialtoken) and $80)<>0 then
  3010. begin
  3011. current_tokenpos.column:=ord(specialtoken) and $7f;
  3012. current_filepos:=current_tokenpos;
  3013. end
  3014. else
  3015. case specialtoken of
  3016. ST_LOADSETTINGS:
  3017. begin
  3018. copy_size:=tokenreadsizeint;
  3019. //if copy_size <> sizeof(current_settings)-sizeof(pointer) then
  3020. // internalerror(2011090501);
  3021. {
  3022. replaytokenbuf.read(current_settings,copy_size);
  3023. }
  3024. tokenreadsettings(current_settings,copy_size);
  3025. end;
  3026. ST_LOADMESSAGES:
  3027. begin
  3028. current_settings.pmessage:=nil;
  3029. mesgnb:=tokenreadsizeint;
  3030. if mesgnb>0 then
  3031. Comment(V_Error,'Message recordind not yet supported');
  3032. prevmsg:=nil;
  3033. for i:=1 to mesgnb do
  3034. begin
  3035. new(pmsg);
  3036. if i=1 then
  3037. current_settings.pmessage:=pmsg
  3038. else
  3039. prevmsg^.next:=pmsg;
  3040. pmsg^.value:=tokenreadlongint;
  3041. pmsg^.state:=tmsgstate(tokenreadlongint);
  3042. pmsg^.next:=nil;
  3043. prevmsg:=pmsg;
  3044. end;
  3045. end;
  3046. ST_LINE:
  3047. begin
  3048. current_tokenpos.line:=tokenreadlongint;
  3049. current_filepos:=current_tokenpos;
  3050. end;
  3051. ST_COLUMN:
  3052. begin
  3053. current_tokenpos.column:=tokenreadword;
  3054. current_filepos:=current_tokenpos;
  3055. end;
  3056. ST_FILEINDEX:
  3057. begin
  3058. current_tokenpos.fileindex:=tokenreadword;
  3059. current_filepos:=current_tokenpos;
  3060. end;
  3061. else
  3062. internalerror(2006103010);
  3063. end;
  3064. continue;
  3065. end;
  3066. end;
  3067. break;
  3068. until false;
  3069. end;
  3070. procedure tscannerfile.addfile(hp:tinputfile);
  3071. begin
  3072. saveinputfile;
  3073. { add to list }
  3074. hp.next:=inputfile;
  3075. inputfile:=hp;
  3076. { load new inputfile }
  3077. restoreinputfile;
  3078. end;
  3079. procedure tscannerfile.reload;
  3080. begin
  3081. with inputfile do
  3082. begin
  3083. { when nothing more to read then leave immediatly, so we
  3084. don't change the current_filepos and leave it point to the last
  3085. char }
  3086. if (c=#26) and (not assigned(next)) then
  3087. exit;
  3088. repeat
  3089. { still more to read?, then change the #0 to a space so its seen
  3090. as a seperator, this can't be used for macro's which can change
  3091. the place of the #0 in the buffer with tempopen }
  3092. if (c=#0) and (bufsize>0) and
  3093. not(inputfile.is_macro) and
  3094. (inputpointer-inputbuffer<bufsize) then
  3095. begin
  3096. c:=' ';
  3097. inc(inputpointer);
  3098. exit;
  3099. end;
  3100. { can we read more from this file ? }
  3101. if (c<>#26) and (not endoffile) then
  3102. begin
  3103. readbuf;
  3104. inputpointer:=buf;
  3105. inputbuffer:=buf;
  3106. inputstart:=bufstart;
  3107. { first line? }
  3108. if line_no=0 then
  3109. begin
  3110. c:=inputpointer^;
  3111. { eat utf-8 signature? }
  3112. if (ord(inputpointer^)=$ef) and
  3113. (ord((inputpointer+1)^)=$bb) and
  3114. (ord((inputpointer+2)^)=$bf) then
  3115. begin
  3116. (* we don't support including files with an UTF-8 bom
  3117. inside another file that wasn't encoded as UTF-8
  3118. already (we don't support {$codepage xxx} switches in
  3119. the middle of a file either) *)
  3120. if (current_settings.sourcecodepage<>CP_UTF8) and
  3121. not current_module.in_global then
  3122. Message(scanner_f_illegal_utf8_bom);
  3123. inc(inputpointer,3);
  3124. message(scan_c_switching_to_utf8);
  3125. current_settings.sourcecodepage:=CP_UTF8;
  3126. include(current_settings.moduleswitches,cs_explicit_codepage);
  3127. end;
  3128. line_no:=1;
  3129. if cs_asm_source in current_settings.globalswitches then
  3130. inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);
  3131. end;
  3132. end
  3133. else
  3134. begin
  3135. { load eof position in tokenpos/current_filepos }
  3136. gettokenpos;
  3137. { close file }
  3138. closeinputfile;
  3139. { no next module, than EOF }
  3140. if not assigned(inputfile.next) then
  3141. begin
  3142. c:=#26;
  3143. exit;
  3144. end;
  3145. { load next file and reopen it }
  3146. nextfile;
  3147. tempopeninputfile;
  3148. { status }
  3149. Message1(scan_t_back_in,inputfile.name);
  3150. end;
  3151. { load next char }
  3152. c:=inputpointer^;
  3153. inc(inputpointer);
  3154. until c<>#0; { if also end, then reload again }
  3155. end;
  3156. end;
  3157. procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint);
  3158. var
  3159. hp : tinputfile;
  3160. begin
  3161. { save old postion }
  3162. dec(inputpointer);
  3163. tempcloseinputfile;
  3164. { create macro 'file' }
  3165. { use special name to dispose after !! }
  3166. hp:=do_openinputfile('_Macro_.'+macname);
  3167. addfile(hp);
  3168. with inputfile do
  3169. begin
  3170. setmacro(p,len);
  3171. { local buffer }
  3172. inputbuffer:=buf;
  3173. inputpointer:=buf;
  3174. inputstart:=bufstart;
  3175. ref_index:=fileindex;
  3176. end;
  3177. { reset line }
  3178. line_no:=line;
  3179. lastlinepos:=0;
  3180. lasttokenpos:=0;
  3181. nexttokenpos:=0;
  3182. { load new c }
  3183. c:=inputpointer^;
  3184. inc(inputpointer);
  3185. end;
  3186. procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
  3187. begin
  3188. tokenpos:=inputstart+(inputpointer-inputbuffer);
  3189. filepos.line:=line_no;
  3190. filepos.column:=tokenpos-lastlinepos;
  3191. filepos.fileindex:=inputfile.ref_index;
  3192. filepos.moduleindex:=current_module.unit_index;
  3193. end;
  3194. procedure tscannerfile.gettokenpos;
  3195. { load the values of tokenpos and lasttokenpos }
  3196. begin
  3197. do_gettokenpos(lasttokenpos,current_tokenpos);
  3198. current_filepos:=current_tokenpos;
  3199. end;
  3200. procedure tscannerfile.cachenexttokenpos;
  3201. begin
  3202. do_gettokenpos(nexttokenpos,next_filepos);
  3203. end;
  3204. procedure tscannerfile.setnexttoken;
  3205. begin
  3206. token:=nexttoken;
  3207. nexttoken:=NOTOKEN;
  3208. lasttokenpos:=nexttokenpos;
  3209. current_tokenpos:=next_filepos;
  3210. current_filepos:=current_tokenpos;
  3211. nexttokenpos:=0;
  3212. end;
  3213. procedure tscannerfile.savetokenpos;
  3214. begin
  3215. oldlasttokenpos:=lasttokenpos;
  3216. oldcurrent_filepos:=current_filepos;
  3217. oldcurrent_tokenpos:=current_tokenpos;
  3218. end;
  3219. procedure tscannerfile.restoretokenpos;
  3220. begin
  3221. lasttokenpos:=oldlasttokenpos;
  3222. current_filepos:=oldcurrent_filepos;
  3223. current_tokenpos:=oldcurrent_tokenpos;
  3224. end;
  3225. procedure tscannerfile.inc_comment_level;
  3226. begin
  3227. if (m_nested_comment in current_settings.modeswitches) then
  3228. inc(comment_level)
  3229. else
  3230. comment_level:=1;
  3231. if (comment_level>1) then
  3232. begin
  3233. savetokenpos;
  3234. gettokenpos; { update for warning }
  3235. Message1(scan_w_comment_level,tostr(comment_level));
  3236. restoretokenpos;
  3237. end;
  3238. end;
  3239. procedure tscannerfile.dec_comment_level;
  3240. begin
  3241. if (m_nested_comment in current_settings.modeswitches) then
  3242. dec(comment_level)
  3243. else
  3244. comment_level:=0;
  3245. end;
  3246. procedure tscannerfile.linebreak;
  3247. var
  3248. cur : char;
  3249. begin
  3250. with inputfile do
  3251. begin
  3252. if (byte(inputpointer^)=0) and not(endoffile) then
  3253. begin
  3254. cur:=c;
  3255. reload;
  3256. if byte(cur)+byte(c)<>23 then
  3257. dec(inputpointer);
  3258. end
  3259. else
  3260. begin
  3261. { Support all combination of #10 and #13 as line break }
  3262. if (byte(inputpointer^)+byte(c)=23) then
  3263. inc(inputpointer);
  3264. end;
  3265. { Always return #10 as line break }
  3266. c:=#10;
  3267. { increase line counters }
  3268. lastlinepos:=inputstart+(inputpointer-inputbuffer);
  3269. inc(line_no);
  3270. { update linebuffer }
  3271. if cs_asm_source in current_settings.globalswitches then
  3272. inputfile.setline(line_no,lastlinepos);
  3273. { update for status and call the show status routine,
  3274. but don't touch current_filepos ! }
  3275. savetokenpos;
  3276. gettokenpos; { update for v_status }
  3277. inc(status.compiledlines);
  3278. ShowStatus;
  3279. restoretokenpos;
  3280. end;
  3281. end;
  3282. procedure tscannerfile.illegal_char(c:char);
  3283. var
  3284. s : string;
  3285. begin
  3286. if c in [#32..#255] then
  3287. s:=''''+c+''''
  3288. else
  3289. s:='#'+tostr(ord(c));
  3290. Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
  3291. end;
  3292. procedure tscannerfile.end_of_file;
  3293. begin
  3294. checkpreprocstack;
  3295. Message(scan_f_end_of_file);
  3296. end;
  3297. {-------------------------------------------
  3298. IF Conditional Handling
  3299. -------------------------------------------}
  3300. procedure tscannerfile.checkpreprocstack;
  3301. begin
  3302. { check for missing ifdefs }
  3303. while assigned(preprocstack) do
  3304. begin
  3305. Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
  3306. preprocstack.owner.inputfile.name,tostr(preprocstack.line_nb));
  3307. poppreprocstack;
  3308. end;
  3309. end;
  3310. procedure tscannerfile.poppreprocstack;
  3311. var
  3312. hp : tpreprocstack;
  3313. begin
  3314. if assigned(preprocstack) then
  3315. begin
  3316. Message1(scan_c_endif_found,preprocstack.name);
  3317. hp:=preprocstack.next;
  3318. preprocstack.free;
  3319. preprocstack:=hp;
  3320. end
  3321. else
  3322. Message(scan_e_endif_without_if);
  3323. end;
  3324. procedure tscannerfile.ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  3325. var
  3326. condition: Boolean;
  3327. valuedescr: String;
  3328. begin
  3329. if (preprocstack=nil) or preprocstack.accept then
  3330. condition:=compile_time_predicate(valuedescr)
  3331. else
  3332. begin
  3333. condition:= false;
  3334. valuedescr:= '';
  3335. end;
  3336. preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
  3337. preprocstack.name:=valuedescr;
  3338. preprocstack.line_nb:=line_no;
  3339. preprocstack.owner:=self;
  3340. if preprocstack.accept then
  3341. Message2(messid,preprocstack.name,'accepted')
  3342. else
  3343. Message2(messid,preprocstack.name,'rejected');
  3344. end;
  3345. procedure tscannerfile.elsepreprocstack;
  3346. begin
  3347. if assigned(preprocstack) and
  3348. (preprocstack.typ<>pp_else) then
  3349. begin
  3350. if (preprocstack.typ=pp_elseif) then
  3351. preprocstack.accept:=false
  3352. else
  3353. if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
  3354. preprocstack.accept:=not preprocstack.accept;
  3355. preprocstack.typ:=pp_else;
  3356. preprocstack.line_nb:=line_no;
  3357. if preprocstack.accept then
  3358. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3359. else
  3360. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3361. end
  3362. else
  3363. Message(scan_e_endif_without_if);
  3364. end;
  3365. procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  3366. var
  3367. valuedescr: String;
  3368. begin
  3369. if assigned(preprocstack) and
  3370. (preprocstack.typ in [pp_if,pp_elseif]) then
  3371. begin
  3372. { when the branch is accepted we use pp_elseif so we know that
  3373. all the next branches need to be rejected. when this branch is still
  3374. not accepted then leave it at pp_if }
  3375. if (preprocstack.typ=pp_elseif) then
  3376. preprocstack.accept:=false
  3377. else if (preprocstack.typ=pp_if) and preprocstack.accept then
  3378. begin
  3379. preprocstack.accept:=false;
  3380. preprocstack.typ:=pp_elseif;
  3381. end
  3382. else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
  3383. and compile_time_predicate(valuedescr) then
  3384. begin
  3385. preprocstack.name:=valuedescr;
  3386. preprocstack.accept:=true;
  3387. preprocstack.typ:=pp_elseif;
  3388. end;
  3389. preprocstack.line_nb:=line_no;
  3390. if preprocstack.accept then
  3391. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3392. else
  3393. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3394. end
  3395. else
  3396. Message(scan_e_endif_without_if);
  3397. end;
  3398. procedure tscannerfile.popreplaystack;
  3399. var
  3400. hp : treplaystack;
  3401. begin
  3402. if assigned(replaystack) then
  3403. begin
  3404. hp:=replaystack.next;
  3405. replaystack.free;
  3406. replaystack:=hp;
  3407. end;
  3408. end;
  3409. procedure tscannerfile.handleconditional(p:tdirectiveitem);
  3410. begin
  3411. savetokenpos;
  3412. repeat
  3413. current_scanner.gettokenpos;
  3414. Message1(scan_d_handling_switch,'$'+p.name);
  3415. p.proc();
  3416. { accept the text ? }
  3417. if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
  3418. break
  3419. else
  3420. begin
  3421. current_scanner.gettokenpos;
  3422. Message(scan_c_skipping_until);
  3423. repeat
  3424. current_scanner.skipuntildirective;
  3425. if not (m_mac in current_settings.modeswitches) then
  3426. p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))
  3427. else
  3428. p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));
  3429. until assigned(p) and (p.is_conditional);
  3430. current_scanner.gettokenpos;
  3431. end;
  3432. until false;
  3433. restoretokenpos;
  3434. end;
  3435. procedure tscannerfile.handledirectives;
  3436. var
  3437. t : tdirectiveitem;
  3438. hs : string;
  3439. begin
  3440. gettokenpos;
  3441. readchar; {Remove the $}
  3442. hs:=readid;
  3443. { handle empty directive }
  3444. if hs='' then
  3445. begin
  3446. Message1(scan_w_illegal_switch,'$');
  3447. exit;
  3448. end;
  3449. {$ifdef PREPROCWRITE}
  3450. if parapreprocess then
  3451. begin
  3452. t:=Get_Directive(hs);
  3453. if not(is_conditional(t) or (t=_DIR_DEFINE) or (t=_DIR_UNDEF)) then
  3454. begin
  3455. preprocfile^.AddSpace;
  3456. preprocfile^.Add('{$'+hs+current_scanner.readcomment+'}');
  3457. exit;
  3458. end;
  3459. end;
  3460. {$endif PREPROCWRITE}
  3461. { skip this directive? }
  3462. if (ignoredirectives.find(hs)<>nil) then
  3463. begin
  3464. if (comment_level>0) then
  3465. readcomment;
  3466. { we've read the whole comment }
  3467. aktcommentstyle:=comment_none;
  3468. exit;
  3469. end;
  3470. { Check for compiler switches }
  3471. while (length(hs)=1) and (c in ['-','+']) do
  3472. begin
  3473. Message1(scan_d_handling_switch,'$'+hs+c);
  3474. HandleSwitch(hs[1],c);
  3475. current_scanner.readchar; {Remove + or -}
  3476. if c=',' then
  3477. begin
  3478. current_scanner.readchar; {Remove , }
  3479. { read next switch, support $v+,$+}
  3480. hs:=current_scanner.readid;
  3481. if (hs='') then
  3482. begin
  3483. if (c='$') and (m_fpc in current_settings.modeswitches) then
  3484. begin
  3485. current_scanner.readchar; { skip $ }
  3486. hs:=current_scanner.readid;
  3487. end;
  3488. if (hs='') then
  3489. Message1(scan_w_illegal_directive,'$'+c);
  3490. end;
  3491. end
  3492. else
  3493. hs:='';
  3494. end;
  3495. { directives may follow switches after a , }
  3496. if hs<>'' then
  3497. begin
  3498. if not (m_mac in current_settings.modeswitches) then
  3499. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  3500. else
  3501. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  3502. if assigned(t) then
  3503. begin
  3504. if t.is_conditional then
  3505. handleconditional(t)
  3506. else
  3507. begin
  3508. Message1(scan_d_handling_switch,'$'+hs);
  3509. t.proc();
  3510. end;
  3511. end
  3512. else
  3513. begin
  3514. current_scanner.ignoredirectives.Add(hs,nil);
  3515. Message1(scan_w_illegal_directive,'$'+hs);
  3516. end;
  3517. { conditionals already read the comment }
  3518. if (current_scanner.comment_level>0) then
  3519. current_scanner.readcomment;
  3520. { we've read the whole comment }
  3521. aktcommentstyle:=comment_none;
  3522. end;
  3523. end;
  3524. procedure tscannerfile.readchar;
  3525. begin
  3526. c:=inputpointer^;
  3527. if c=#0 then
  3528. reload
  3529. else
  3530. inc(inputpointer);
  3531. end;
  3532. procedure tscannerfile.readstring;
  3533. var
  3534. i : longint;
  3535. err : boolean;
  3536. begin
  3537. err:=false;
  3538. i:=0;
  3539. repeat
  3540. case c of
  3541. '_',
  3542. '0'..'9',
  3543. 'A'..'Z' :
  3544. begin
  3545. if i<255 then
  3546. begin
  3547. inc(i);
  3548. orgpattern[i]:=c;
  3549. pattern[i]:=c;
  3550. end
  3551. else
  3552. begin
  3553. if not err then
  3554. begin
  3555. Message(scan_e_string_exceeds_255_chars);
  3556. err:=true;
  3557. end;
  3558. end;
  3559. c:=inputpointer^;
  3560. inc(inputpointer);
  3561. end;
  3562. 'a'..'z' :
  3563. begin
  3564. if i<255 then
  3565. begin
  3566. inc(i);
  3567. orgpattern[i]:=c;
  3568. pattern[i]:=chr(ord(c)-32)
  3569. end
  3570. else
  3571. begin
  3572. if not err then
  3573. begin
  3574. Message(scan_e_string_exceeds_255_chars);
  3575. err:=true;
  3576. end;
  3577. end;
  3578. c:=inputpointer^;
  3579. inc(inputpointer);
  3580. end;
  3581. #0 :
  3582. reload;
  3583. else
  3584. break;
  3585. end;
  3586. until false;
  3587. orgpattern[0]:=chr(i);
  3588. pattern[0]:=chr(i);
  3589. end;
  3590. procedure tscannerfile.readnumber;
  3591. var
  3592. base,
  3593. i : longint;
  3594. begin
  3595. case c of
  3596. '%' :
  3597. begin
  3598. readchar;
  3599. base:=2;
  3600. pattern[1]:='%';
  3601. i:=1;
  3602. end;
  3603. '&' :
  3604. begin
  3605. readchar;
  3606. base:=8;
  3607. pattern[1]:='&';
  3608. i:=1;
  3609. end;
  3610. '$' :
  3611. begin
  3612. readchar;
  3613. base:=16;
  3614. pattern[1]:='$';
  3615. i:=1;
  3616. end;
  3617. else
  3618. begin
  3619. base:=10;
  3620. i:=0;
  3621. end;
  3622. end;
  3623. while ((base>=10) and (c in ['0'..'9'])) or
  3624. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  3625. ((base=8) and (c in ['0'..'7'])) or
  3626. ((base=2) and (c in ['0'..'1'])) do
  3627. begin
  3628. if i<255 then
  3629. begin
  3630. inc(i);
  3631. pattern[i]:=c;
  3632. end;
  3633. readchar;
  3634. end;
  3635. pattern[0]:=chr(i);
  3636. end;
  3637. function tscannerfile.readid:string;
  3638. begin
  3639. readstring;
  3640. readid:=pattern;
  3641. end;
  3642. function tscannerfile.readval:longint;
  3643. var
  3644. l : longint;
  3645. w : integer;
  3646. begin
  3647. readnumber;
  3648. val(pattern,l,w);
  3649. readval:=l;
  3650. end;
  3651. function tscannerfile.readcomment:string;
  3652. var
  3653. i : longint;
  3654. begin
  3655. i:=0;
  3656. repeat
  3657. case c of
  3658. '{' :
  3659. begin
  3660. if aktcommentstyle=comment_tp then
  3661. inc_comment_level;
  3662. end;
  3663. '}' :
  3664. begin
  3665. if aktcommentstyle=comment_tp then
  3666. begin
  3667. readchar;
  3668. dec_comment_level;
  3669. if comment_level=0 then
  3670. break
  3671. else
  3672. continue;
  3673. end;
  3674. end;
  3675. '*' :
  3676. begin
  3677. if aktcommentstyle=comment_oldtp then
  3678. begin
  3679. readchar;
  3680. if c=')' then
  3681. begin
  3682. readchar;
  3683. dec_comment_level;
  3684. break;
  3685. end
  3686. else
  3687. { Add both characters !!}
  3688. if (i<255) then
  3689. begin
  3690. inc(i);
  3691. readcomment[i]:='*';
  3692. if (i<255) then
  3693. begin
  3694. inc(i);
  3695. readcomment[i]:=c;
  3696. end;
  3697. end;
  3698. end
  3699. else
  3700. { Not old TP comment, so add...}
  3701. begin
  3702. if (i<255) then
  3703. begin
  3704. inc(i);
  3705. readcomment[i]:='*';
  3706. end;
  3707. end;
  3708. end;
  3709. #10,#13 :
  3710. linebreak;
  3711. #26 :
  3712. end_of_file;
  3713. else
  3714. begin
  3715. if (i<255) then
  3716. begin
  3717. inc(i);
  3718. readcomment[i]:=c;
  3719. end;
  3720. end;
  3721. end;
  3722. readchar;
  3723. until false;
  3724. readcomment[0]:=chr(i);
  3725. end;
  3726. function tscannerfile.readquotedstring:string;
  3727. var
  3728. i : longint;
  3729. msgwritten : boolean;
  3730. begin
  3731. i:=0;
  3732. msgwritten:=false;
  3733. if (c='''') then
  3734. begin
  3735. repeat
  3736. readchar;
  3737. case c of
  3738. #26 :
  3739. end_of_file;
  3740. #10,#13 :
  3741. Message(scan_f_string_exceeds_line);
  3742. '''' :
  3743. begin
  3744. readchar;
  3745. if c<>'''' then
  3746. break;
  3747. end;
  3748. end;
  3749. if i<255 then
  3750. begin
  3751. inc(i);
  3752. result[i]:=c;
  3753. end
  3754. else
  3755. begin
  3756. if not msgwritten then
  3757. begin
  3758. Message(scan_e_string_exceeds_255_chars);
  3759. msgwritten:=true;
  3760. end;
  3761. end;
  3762. until false;
  3763. end;
  3764. result[0]:=chr(i);
  3765. end;
  3766. function tscannerfile.readstate:char;
  3767. var
  3768. state : char;
  3769. begin
  3770. state:=' ';
  3771. if c=' ' then
  3772. begin
  3773. current_scanner.skipspace;
  3774. current_scanner.readid;
  3775. if pattern='ON' then
  3776. state:='+'
  3777. else
  3778. if pattern='OFF' then
  3779. state:='-';
  3780. end
  3781. else
  3782. state:=c;
  3783. if not (state in ['+','-']) then
  3784. Message(scan_e_wrong_switch_toggle);
  3785. readstate:=state;
  3786. end;
  3787. function tscannerfile.readstatedefault:char;
  3788. var
  3789. state : char;
  3790. begin
  3791. state:=' ';
  3792. if c=' ' then
  3793. begin
  3794. current_scanner.skipspace;
  3795. current_scanner.readid;
  3796. if pattern='ON' then
  3797. state:='+'
  3798. else
  3799. if pattern='OFF' then
  3800. state:='-'
  3801. else
  3802. if pattern='DEFAULT' then
  3803. state:='*';
  3804. end
  3805. else
  3806. state:=c;
  3807. if not (state in ['+','-','*']) then
  3808. Message(scan_e_wrong_switch_toggle_default);
  3809. readstatedefault:=state;
  3810. end;
  3811. procedure tscannerfile.skipspace;
  3812. begin
  3813. repeat
  3814. case c of
  3815. #26 :
  3816. begin
  3817. reload;
  3818. if (c=#26) and not assigned(inputfile.next) then
  3819. break;
  3820. continue;
  3821. end;
  3822. #10,
  3823. #13 :
  3824. linebreak;
  3825. #9,#11,#12,' ' :
  3826. ;
  3827. else
  3828. break;
  3829. end;
  3830. readchar;
  3831. until false;
  3832. end;
  3833. procedure tscannerfile.skipuntildirective;
  3834. var
  3835. found : longint;
  3836. next_char_loaded : boolean;
  3837. begin
  3838. found:=0;
  3839. next_char_loaded:=false;
  3840. repeat
  3841. case c of
  3842. #10,
  3843. #13 :
  3844. linebreak;
  3845. #26 :
  3846. begin
  3847. reload;
  3848. if (c=#26) and not assigned(inputfile.next) then
  3849. end_of_file;
  3850. continue;
  3851. end;
  3852. '{' :
  3853. begin
  3854. if (aktcommentstyle in [comment_tp,comment_none]) then
  3855. begin
  3856. aktcommentstyle:=comment_tp;
  3857. if (comment_level=0) then
  3858. found:=1;
  3859. inc_comment_level;
  3860. end;
  3861. end;
  3862. '*' :
  3863. begin
  3864. if (aktcommentstyle=comment_oldtp) then
  3865. begin
  3866. readchar;
  3867. if c=')' then
  3868. begin
  3869. dec_comment_level;
  3870. found:=0;
  3871. aktcommentstyle:=comment_none;
  3872. end
  3873. else
  3874. next_char_loaded:=true;
  3875. end
  3876. else
  3877. found := 0;
  3878. end;
  3879. '}' :
  3880. begin
  3881. if (aktcommentstyle=comment_tp) then
  3882. begin
  3883. dec_comment_level;
  3884. if (comment_level=0) then
  3885. aktcommentstyle:=comment_none;
  3886. found:=0;
  3887. end;
  3888. end;
  3889. '$' :
  3890. begin
  3891. if found=1 then
  3892. found:=2;
  3893. end;
  3894. '''' :
  3895. if (aktcommentstyle=comment_none) then
  3896. begin
  3897. repeat
  3898. readchar;
  3899. case c of
  3900. #26 :
  3901. end_of_file;
  3902. #10,#13 :
  3903. break;
  3904. '''' :
  3905. begin
  3906. readchar;
  3907. if c<>'''' then
  3908. begin
  3909. next_char_loaded:=true;
  3910. break;
  3911. end;
  3912. end;
  3913. end;
  3914. until false;
  3915. end;
  3916. '(' :
  3917. begin
  3918. if (aktcommentstyle=comment_none) then
  3919. begin
  3920. readchar;
  3921. if c='*' then
  3922. begin
  3923. readchar;
  3924. if c='$' then
  3925. begin
  3926. found:=2;
  3927. inc_comment_level;
  3928. aktcommentstyle:=comment_oldtp;
  3929. end
  3930. else
  3931. begin
  3932. skipoldtpcomment;
  3933. next_char_loaded:=true;
  3934. end;
  3935. end
  3936. else
  3937. next_char_loaded:=true;
  3938. end
  3939. else
  3940. found:=0;
  3941. end;
  3942. '/' :
  3943. begin
  3944. if (aktcommentstyle=comment_none) then
  3945. begin
  3946. readchar;
  3947. if c='/' then
  3948. skipdelphicomment;
  3949. next_char_loaded:=true;
  3950. end
  3951. else
  3952. found:=0;
  3953. end;
  3954. else
  3955. found:=0;
  3956. end;
  3957. if next_char_loaded then
  3958. next_char_loaded:=false
  3959. else
  3960. readchar;
  3961. until (found=2);
  3962. end;
  3963. {****************************************************************************
  3964. Comment Handling
  3965. ****************************************************************************}
  3966. procedure tscannerfile.skipcomment;
  3967. begin
  3968. aktcommentstyle:=comment_tp;
  3969. readchar;
  3970. inc_comment_level;
  3971. { handle compiler switches }
  3972. if (c='$') then
  3973. handledirectives;
  3974. { handle_switches can dec comment_level, }
  3975. while (comment_level>0) do
  3976. begin
  3977. case c of
  3978. '{' :
  3979. inc_comment_level;
  3980. '}' :
  3981. dec_comment_level;
  3982. #10,#13 :
  3983. linebreak;
  3984. #26 :
  3985. begin
  3986. reload;
  3987. if (c=#26) and not assigned(inputfile.next) then
  3988. end_of_file;
  3989. continue;
  3990. end;
  3991. end;
  3992. readchar;
  3993. end;
  3994. aktcommentstyle:=comment_none;
  3995. end;
  3996. procedure tscannerfile.skipdelphicomment;
  3997. begin
  3998. aktcommentstyle:=comment_delphi;
  3999. inc_comment_level;
  4000. readchar;
  4001. { this is not supported }
  4002. if c='$' then
  4003. Message(scan_w_wrong_styled_switch);
  4004. { skip comment }
  4005. while not (c in [#10,#13,#26]) do
  4006. readchar;
  4007. dec_comment_level;
  4008. aktcommentstyle:=comment_none;
  4009. end;
  4010. procedure tscannerfile.skipoldtpcomment;
  4011. var
  4012. found : longint;
  4013. begin
  4014. aktcommentstyle:=comment_oldtp;
  4015. inc_comment_level;
  4016. { only load a char if last already processed,
  4017. was cause of bug1634 PM }
  4018. if c=#0 then
  4019. readchar;
  4020. { this is now supported }
  4021. if (c='$') then
  4022. handledirectives;
  4023. { skip comment }
  4024. while (comment_level>0) do
  4025. begin
  4026. found:=0;
  4027. repeat
  4028. case c of
  4029. #26 :
  4030. begin
  4031. reload;
  4032. if (c=#26) and not assigned(inputfile.next) then
  4033. end_of_file;
  4034. continue;
  4035. end;
  4036. #10,#13 :
  4037. begin
  4038. if found=4 then
  4039. inc_comment_level;
  4040. linebreak;
  4041. found:=0;
  4042. end;
  4043. '*' :
  4044. begin
  4045. if found=3 then
  4046. found:=4
  4047. else
  4048. found:=1;
  4049. end;
  4050. ')' :
  4051. begin
  4052. if found in [1,4] then
  4053. begin
  4054. dec_comment_level;
  4055. if comment_level=0 then
  4056. found:=2
  4057. else
  4058. found:=0;
  4059. end
  4060. else
  4061. found:=0;
  4062. end;
  4063. '(' :
  4064. begin
  4065. if found=4 then
  4066. inc_comment_level;
  4067. found:=3;
  4068. end;
  4069. else
  4070. begin
  4071. if found=4 then
  4072. inc_comment_level;
  4073. found:=0;
  4074. end;
  4075. end;
  4076. readchar;
  4077. until (found=2);
  4078. end;
  4079. aktcommentstyle:=comment_none;
  4080. end;
  4081. {****************************************************************************
  4082. Token Scanner
  4083. ****************************************************************************}
  4084. procedure tscannerfile.readtoken(allowrecordtoken:boolean);
  4085. var
  4086. code : integer;
  4087. len,
  4088. low,high,mid : longint;
  4089. w : word;
  4090. m : longint;
  4091. mac : tmacro;
  4092. asciinr : string[33];
  4093. iswidestring : boolean;
  4094. label
  4095. exit_label;
  4096. begin
  4097. flushpendingswitchesstate;
  4098. { record tokens? }
  4099. if allowrecordtoken and
  4100. assigned(recordtokenbuf) then
  4101. recordtoken;
  4102. { replay tokens? }
  4103. if assigned(replaytokenbuf) then
  4104. begin
  4105. replaytoken;
  4106. goto exit_label;
  4107. end;
  4108. { was there already a token read, then return that token }
  4109. if nexttoken<>NOTOKEN then
  4110. begin
  4111. setnexttoken;
  4112. goto exit_label;
  4113. end;
  4114. { Skip all spaces and comments }
  4115. repeat
  4116. case c of
  4117. '{' :
  4118. skipcomment;
  4119. #26 :
  4120. begin
  4121. reload;
  4122. if (c=#26) and not assigned(inputfile.next) then
  4123. break;
  4124. end;
  4125. ' ',#9..#13 :
  4126. begin
  4127. {$ifdef PREPROCWRITE}
  4128. if parapreprocess then
  4129. begin
  4130. if c=#10 then
  4131. preprocfile.eolfound:=true
  4132. else
  4133. preprocfile.spacefound:=true;
  4134. end;
  4135. {$endif PREPROCWRITE}
  4136. skipspace;
  4137. end
  4138. else
  4139. break;
  4140. end;
  4141. until false;
  4142. { Save current token position, for EOF its already loaded }
  4143. if c<>#26 then
  4144. gettokenpos;
  4145. { Check first for a identifier/keyword, this is 20+% faster (PFV) }
  4146. if c in ['A'..'Z','a'..'z','_'] then
  4147. begin
  4148. readstring;
  4149. token:=_ID;
  4150. idtoken:=_ID;
  4151. { keyword or any other known token,
  4152. pattern is always uppercased }
  4153. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  4154. begin
  4155. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  4156. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  4157. while low<high do
  4158. begin
  4159. mid:=(high+low+1) shr 1;
  4160. if pattern<tokeninfo^[ttoken(mid)].str then
  4161. high:=mid-1
  4162. else
  4163. low:=mid;
  4164. end;
  4165. with tokeninfo^[ttoken(high)] do
  4166. if pattern=str then
  4167. begin
  4168. if (keyword*current_settings.modeswitches)<>[] then
  4169. if op=NOTOKEN then
  4170. token:=ttoken(high)
  4171. else
  4172. token:=op;
  4173. idtoken:=ttoken(high);
  4174. end;
  4175. end;
  4176. { Only process identifiers and not keywords }
  4177. if token=_ID then
  4178. begin
  4179. { this takes some time ... }
  4180. if (cs_support_macro in current_settings.moduleswitches) then
  4181. begin
  4182. mac:=tmacro(search_macro(pattern));
  4183. if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
  4184. begin
  4185. if yylexcount<max_macro_nesting then
  4186. begin
  4187. mac.is_used:=true;
  4188. inc(yylexcount);
  4189. substitutemacro(pattern,mac.buftext,mac.buflen,
  4190. mac.fileinfo.line,mac.fileinfo.fileindex);
  4191. { handle empty macros }
  4192. if c=#0 then
  4193. reload;
  4194. readtoken(false);
  4195. { that's all folks }
  4196. dec(yylexcount);
  4197. exit;
  4198. end
  4199. else
  4200. Message(scan_w_macro_too_deep);
  4201. end;
  4202. end;
  4203. end;
  4204. { return token }
  4205. goto exit_label;
  4206. end
  4207. else
  4208. begin
  4209. idtoken:=_NOID;
  4210. case c of
  4211. '$' :
  4212. begin
  4213. readnumber;
  4214. token:=_INTCONST;
  4215. goto exit_label;
  4216. end;
  4217. '%' :
  4218. begin
  4219. if not(m_fpc in current_settings.modeswitches) then
  4220. Illegal_Char(c)
  4221. else
  4222. begin
  4223. readnumber;
  4224. token:=_INTCONST;
  4225. goto exit_label;
  4226. end;
  4227. end;
  4228. '&' :
  4229. begin
  4230. if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then
  4231. begin
  4232. readnumber;
  4233. if length(pattern)=1 then
  4234. begin
  4235. { does really an identifier follow? }
  4236. if not (c in ['_','A'..'Z','a'..'z']) then
  4237. message2(scan_f_syn_expected,tokeninfo^[_ID].str,c);
  4238. readstring;
  4239. token:=_ID;
  4240. idtoken:=_ID;
  4241. end
  4242. else
  4243. token:=_INTCONST;
  4244. goto exit_label;
  4245. end
  4246. else if m_mac in current_settings.modeswitches then
  4247. begin
  4248. readchar;
  4249. token:=_AMPERSAND;
  4250. goto exit_label;
  4251. end
  4252. else
  4253. Illegal_Char(c);
  4254. end;
  4255. '0'..'9' :
  4256. begin
  4257. readnumber;
  4258. if (c in ['.','e','E']) then
  4259. begin
  4260. { first check for a . }
  4261. if c='.' then
  4262. begin
  4263. cachenexttokenpos;
  4264. readchar;
  4265. { is it a .. from a range? }
  4266. case c of
  4267. '.' :
  4268. begin
  4269. readchar;
  4270. token:=_INTCONST;
  4271. nexttoken:=_POINTPOINT;
  4272. goto exit_label;
  4273. end;
  4274. ')' :
  4275. begin
  4276. readchar;
  4277. token:=_INTCONST;
  4278. nexttoken:=_RECKKLAMMER;
  4279. goto exit_label;
  4280. end;
  4281. '0'..'9' :
  4282. begin
  4283. { insert the number after the . }
  4284. pattern:=pattern+'.';
  4285. while c in ['0'..'9'] do
  4286. begin
  4287. pattern:=pattern+c;
  4288. readchar;
  4289. end;
  4290. end;
  4291. else
  4292. begin
  4293. token:=_INTCONST;
  4294. nexttoken:=_POINT;
  4295. goto exit_label;
  4296. end;
  4297. end;
  4298. end;
  4299. { E can also follow after a point is scanned }
  4300. if c in ['e','E'] then
  4301. begin
  4302. pattern:=pattern+'E';
  4303. readchar;
  4304. if c in ['-','+'] then
  4305. begin
  4306. pattern:=pattern+c;
  4307. readchar;
  4308. end;
  4309. if not(c in ['0'..'9']) then
  4310. Illegal_Char(c);
  4311. while c in ['0'..'9'] do
  4312. begin
  4313. pattern:=pattern+c;
  4314. readchar;
  4315. end;
  4316. end;
  4317. token:=_REALNUMBER;
  4318. goto exit_label;
  4319. end;
  4320. token:=_INTCONST;
  4321. goto exit_label;
  4322. end;
  4323. ';' :
  4324. begin
  4325. readchar;
  4326. token:=_SEMICOLON;
  4327. goto exit_label;
  4328. end;
  4329. '[' :
  4330. begin
  4331. readchar;
  4332. token:=_LECKKLAMMER;
  4333. goto exit_label;
  4334. end;
  4335. ']' :
  4336. begin
  4337. readchar;
  4338. token:=_RECKKLAMMER;
  4339. goto exit_label;
  4340. end;
  4341. '(' :
  4342. begin
  4343. readchar;
  4344. case c of
  4345. '*' :
  4346. begin
  4347. c:=#0;{Signal skipoldtpcomment to reload a char }
  4348. skipoldtpcomment;
  4349. readtoken(false);
  4350. exit;
  4351. end;
  4352. '.' :
  4353. begin
  4354. readchar;
  4355. token:=_LECKKLAMMER;
  4356. goto exit_label;
  4357. end;
  4358. end;
  4359. token:=_LKLAMMER;
  4360. goto exit_label;
  4361. end;
  4362. ')' :
  4363. begin
  4364. readchar;
  4365. token:=_RKLAMMER;
  4366. goto exit_label;
  4367. end;
  4368. '+' :
  4369. begin
  4370. readchar;
  4371. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4372. begin
  4373. readchar;
  4374. token:=_PLUSASN;
  4375. goto exit_label;
  4376. end;
  4377. token:=_PLUS;
  4378. goto exit_label;
  4379. end;
  4380. '-' :
  4381. begin
  4382. readchar;
  4383. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4384. begin
  4385. readchar;
  4386. token:=_MINUSASN;
  4387. goto exit_label;
  4388. end;
  4389. token:=_MINUS;
  4390. goto exit_label;
  4391. end;
  4392. ':' :
  4393. begin
  4394. readchar;
  4395. if c='=' then
  4396. begin
  4397. readchar;
  4398. token:=_ASSIGNMENT;
  4399. goto exit_label;
  4400. end;
  4401. token:=_COLON;
  4402. goto exit_label;
  4403. end;
  4404. '*' :
  4405. begin
  4406. readchar;
  4407. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4408. begin
  4409. readchar;
  4410. token:=_STARASN;
  4411. end
  4412. else
  4413. if c='*' then
  4414. begin
  4415. readchar;
  4416. token:=_STARSTAR;
  4417. end
  4418. else
  4419. token:=_STAR;
  4420. goto exit_label;
  4421. end;
  4422. '/' :
  4423. begin
  4424. readchar;
  4425. case c of
  4426. '=' :
  4427. begin
  4428. if (cs_support_c_operators in current_settings.moduleswitches) then
  4429. begin
  4430. readchar;
  4431. token:=_SLASHASN;
  4432. goto exit_label;
  4433. end;
  4434. end;
  4435. '/' :
  4436. begin
  4437. skipdelphicomment;
  4438. readtoken(false);
  4439. exit;
  4440. end;
  4441. end;
  4442. token:=_SLASH;
  4443. goto exit_label;
  4444. end;
  4445. '|' :
  4446. if m_mac in current_settings.modeswitches then
  4447. begin
  4448. readchar;
  4449. token:=_PIPE;
  4450. goto exit_label;
  4451. end
  4452. else
  4453. Illegal_Char(c);
  4454. '=' :
  4455. begin
  4456. readchar;
  4457. token:=_EQ;
  4458. goto exit_label;
  4459. end;
  4460. '.' :
  4461. begin
  4462. readchar;
  4463. case c of
  4464. '.' :
  4465. begin
  4466. readchar;
  4467. case c of
  4468. '.' :
  4469. begin
  4470. readchar;
  4471. token:=_POINTPOINTPOINT;
  4472. goto exit_label;
  4473. end;
  4474. else
  4475. begin
  4476. token:=_POINTPOINT;
  4477. goto exit_label;
  4478. end;
  4479. end;
  4480. end;
  4481. ')' :
  4482. begin
  4483. readchar;
  4484. token:=_RECKKLAMMER;
  4485. goto exit_label;
  4486. end;
  4487. end;
  4488. token:=_POINT;
  4489. goto exit_label;
  4490. end;
  4491. '@' :
  4492. begin
  4493. readchar;
  4494. token:=_KLAMMERAFFE;
  4495. goto exit_label;
  4496. end;
  4497. ',' :
  4498. begin
  4499. readchar;
  4500. token:=_COMMA;
  4501. goto exit_label;
  4502. end;
  4503. '''','#','^' :
  4504. begin
  4505. len:=0;
  4506. cstringpattern:='';
  4507. iswidestring:=false;
  4508. if c='^' then
  4509. begin
  4510. readchar;
  4511. c:=upcase(c);
  4512. if (block_type in [bt_type,bt_const_type,bt_var_type]) or
  4513. (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or
  4514. (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
  4515. begin
  4516. token:=_CARET;
  4517. goto exit_label;
  4518. end
  4519. else
  4520. begin
  4521. inc(len);
  4522. setlength(cstringpattern,256);
  4523. if c<#64 then
  4524. cstringpattern[len]:=chr(ord(c)+64)
  4525. else
  4526. cstringpattern[len]:=chr(ord(c)-64);
  4527. readchar;
  4528. end;
  4529. end;
  4530. repeat
  4531. case c of
  4532. '#' :
  4533. begin
  4534. readchar; { read # }
  4535. case c of
  4536. '$':
  4537. begin
  4538. readchar; { read leading $ }
  4539. asciinr:='$';
  4540. while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=5) do
  4541. begin
  4542. asciinr:=asciinr+c;
  4543. readchar;
  4544. end;
  4545. end;
  4546. '&':
  4547. begin
  4548. readchar; { read leading $ }
  4549. asciinr:='&';
  4550. while (upcase(c) in ['0'..'7']) and (length(asciinr)<=7) do
  4551. begin
  4552. asciinr:=asciinr+c;
  4553. readchar;
  4554. end;
  4555. end;
  4556. '%':
  4557. begin
  4558. readchar; { read leading $ }
  4559. asciinr:='%';
  4560. while (upcase(c) in ['0','1']) and (length(asciinr)<=17) do
  4561. begin
  4562. asciinr:=asciinr+c;
  4563. readchar;
  4564. end;
  4565. end;
  4566. else
  4567. begin
  4568. asciinr:='';
  4569. while (c in ['0'..'9']) and (length(asciinr)<=5) do
  4570. begin
  4571. asciinr:=asciinr+c;
  4572. readchar;
  4573. end;
  4574. end;
  4575. end;
  4576. val(asciinr,m,code);
  4577. if (asciinr='') or (code<>0) then
  4578. Message(scan_e_illegal_char_const)
  4579. else if (m<0) or (m>255) or (length(asciinr)>3) then
  4580. begin
  4581. if (m>=0) and (m<=65535) then
  4582. begin
  4583. if not iswidestring then
  4584. begin
  4585. if len>0 then
  4586. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  4587. else
  4588. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  4589. iswidestring:=true;
  4590. len:=0;
  4591. end;
  4592. concatwidestringchar(patternw,tcompilerwidechar(m));
  4593. end
  4594. else
  4595. Message(scan_e_illegal_char_const)
  4596. end
  4597. else if iswidestring then
  4598. concatwidestringchar(patternw,asciichar2unicode(char(m)))
  4599. else
  4600. begin
  4601. if len>=length(cstringpattern) then
  4602. setlength(cstringpattern,length(cstringpattern)+256);
  4603. inc(len);
  4604. cstringpattern[len]:=chr(m);
  4605. end;
  4606. end;
  4607. '''' :
  4608. begin
  4609. repeat
  4610. readchar;
  4611. case c of
  4612. #26 :
  4613. end_of_file;
  4614. #10,#13 :
  4615. Message(scan_f_string_exceeds_line);
  4616. '''' :
  4617. begin
  4618. readchar;
  4619. if c<>'''' then
  4620. break;
  4621. end;
  4622. end;
  4623. { interpret as utf-8 string? }
  4624. if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then
  4625. begin
  4626. { convert existing string to an utf-8 string }
  4627. if not iswidestring then
  4628. begin
  4629. if len>0 then
  4630. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  4631. else
  4632. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  4633. iswidestring:=true;
  4634. len:=0;
  4635. end;
  4636. { four or more chars aren't handled }
  4637. if (ord(c) and $f0)=$f0 then
  4638. message(scan_e_utf8_bigger_than_65535)
  4639. { three chars }
  4640. else if (ord(c) and $e0)=$e0 then
  4641. begin
  4642. w:=ord(c) and $f;
  4643. readchar;
  4644. if (ord(c) and $c0)<>$80 then
  4645. message(scan_e_utf8_malformed);
  4646. w:=(w shl 6) or (ord(c) and $3f);
  4647. readchar;
  4648. if (ord(c) and $c0)<>$80 then
  4649. message(scan_e_utf8_malformed);
  4650. w:=(w shl 6) or (ord(c) and $3f);
  4651. concatwidestringchar(patternw,w);
  4652. end
  4653. { two chars }
  4654. else if (ord(c) and $c0)<>0 then
  4655. begin
  4656. w:=ord(c) and $1f;
  4657. readchar;
  4658. if (ord(c) and $c0)<>$80 then
  4659. message(scan_e_utf8_malformed);
  4660. w:=(w shl 6) or (ord(c) and $3f);
  4661. concatwidestringchar(patternw,w);
  4662. end
  4663. { illegal }
  4664. else if (ord(c) and $80)<>0 then
  4665. message(scan_e_utf8_malformed)
  4666. else
  4667. concatwidestringchar(patternw,tcompilerwidechar(c))
  4668. end
  4669. else if iswidestring then
  4670. begin
  4671. if current_settings.sourcecodepage=CP_UTF8 then
  4672. concatwidestringchar(patternw,ord(c))
  4673. else
  4674. concatwidestringchar(patternw,asciichar2unicode(c))
  4675. end
  4676. else
  4677. begin
  4678. if len>=length(cstringpattern) then
  4679. setlength(cstringpattern,length(cstringpattern)+256);
  4680. inc(len);
  4681. cstringpattern[len]:=c;
  4682. end;
  4683. until false;
  4684. end;
  4685. '^' :
  4686. begin
  4687. readchar;
  4688. c:=upcase(c);
  4689. if c<#64 then
  4690. c:=chr(ord(c)+64)
  4691. else
  4692. c:=chr(ord(c)-64);
  4693. if iswidestring then
  4694. concatwidestringchar(patternw,asciichar2unicode(c))
  4695. else
  4696. begin
  4697. if len>=length(cstringpattern) then
  4698. setlength(cstringpattern,length(cstringpattern)+256);
  4699. inc(len);
  4700. cstringpattern[len]:=c;
  4701. end;
  4702. readchar;
  4703. end;
  4704. else
  4705. break;
  4706. end;
  4707. until false;
  4708. { strings with length 1 become const chars }
  4709. if iswidestring then
  4710. begin
  4711. if patternw^.len=1 then
  4712. token:=_CWCHAR
  4713. else
  4714. token:=_CWSTRING;
  4715. end
  4716. else
  4717. begin
  4718. setlength(cstringpattern,len);
  4719. if length(cstringpattern)=1 then
  4720. begin
  4721. token:=_CCHAR;
  4722. pattern:=cstringpattern;
  4723. end
  4724. else
  4725. token:=_CSTRING;
  4726. end;
  4727. goto exit_label;
  4728. end;
  4729. '>' :
  4730. begin
  4731. readchar;
  4732. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  4733. token:=_RSHARPBRACKET
  4734. else
  4735. begin
  4736. case c of
  4737. '=' :
  4738. begin
  4739. readchar;
  4740. token:=_GTE;
  4741. goto exit_label;
  4742. end;
  4743. '>' :
  4744. begin
  4745. readchar;
  4746. token:=_OP_SHR;
  4747. goto exit_label;
  4748. end;
  4749. '<' :
  4750. begin { >< is for a symetric diff for sets }
  4751. readchar;
  4752. token:=_SYMDIF;
  4753. goto exit_label;
  4754. end;
  4755. end;
  4756. token:=_GT;
  4757. end;
  4758. goto exit_label;
  4759. end;
  4760. '<' :
  4761. begin
  4762. readchar;
  4763. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  4764. token:=_LSHARPBRACKET
  4765. else
  4766. begin
  4767. case c of
  4768. '>' :
  4769. begin
  4770. readchar;
  4771. token:=_NE;
  4772. goto exit_label;
  4773. end;
  4774. '=' :
  4775. begin
  4776. readchar;
  4777. token:=_LTE;
  4778. goto exit_label;
  4779. end;
  4780. '<' :
  4781. begin
  4782. readchar;
  4783. token:=_OP_SHL;
  4784. goto exit_label;
  4785. end;
  4786. end;
  4787. token:=_LT;
  4788. end;
  4789. goto exit_label;
  4790. end;
  4791. #26 :
  4792. begin
  4793. token:=_EOF;
  4794. checkpreprocstack;
  4795. goto exit_label;
  4796. end;
  4797. else
  4798. Illegal_Char(c);
  4799. end;
  4800. end;
  4801. exit_label:
  4802. lasttoken:=token;
  4803. end;
  4804. function tscannerfile.readpreproc:ttoken;
  4805. var
  4806. low,high,mid: longint;
  4807. optoken: ttoken;
  4808. begin
  4809. skipspace;
  4810. case c of
  4811. '_',
  4812. 'A'..'Z',
  4813. 'a'..'z' :
  4814. begin
  4815. readstring;
  4816. optoken:=_ID;
  4817. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  4818. begin
  4819. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  4820. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  4821. while low<high do
  4822. begin
  4823. mid:=(high+low+1) shr 1;
  4824. if pattern<tokeninfo^[ttoken(mid)].str then
  4825. high:=mid-1
  4826. else
  4827. low:=mid;
  4828. end;
  4829. with tokeninfo^[ttoken(high)] do
  4830. if pattern=str then
  4831. begin
  4832. if (keyword*current_settings.modeswitches)<>[] then
  4833. if op=NOTOKEN then
  4834. optoken:=ttoken(high)
  4835. else
  4836. optoken:=op;
  4837. end;
  4838. if not (optoken in preproc_operators) then
  4839. optoken:=_ID;
  4840. end;
  4841. current_scanner.preproc_pattern:=pattern;
  4842. readpreproc:=optoken;
  4843. end;
  4844. '0'..'9' :
  4845. begin
  4846. readnumber;
  4847. if (c in ['.','e','E']) then
  4848. begin
  4849. { first check for a . }
  4850. if c='.' then
  4851. begin
  4852. readchar;
  4853. if c in ['0'..'9'] then
  4854. begin
  4855. { insert the number after the . }
  4856. pattern:=pattern+'.';
  4857. while c in ['0'..'9'] do
  4858. begin
  4859. pattern:=pattern+c;
  4860. readchar;
  4861. end;
  4862. end
  4863. else
  4864. Illegal_Char(c);
  4865. end;
  4866. { E can also follow after a point is scanned }
  4867. if c in ['e','E'] then
  4868. begin
  4869. pattern:=pattern+'E';
  4870. readchar;
  4871. if c in ['-','+'] then
  4872. begin
  4873. pattern:=pattern+c;
  4874. readchar;
  4875. end;
  4876. if not(c in ['0'..'9']) then
  4877. Illegal_Char(c);
  4878. while c in ['0'..'9'] do
  4879. begin
  4880. pattern:=pattern+c;
  4881. readchar;
  4882. end;
  4883. end;
  4884. readpreproc:=_REALNUMBER;
  4885. end
  4886. else
  4887. readpreproc:=_INTCONST;
  4888. current_scanner.preproc_pattern:=pattern;
  4889. end;
  4890. '$','%':
  4891. begin
  4892. readnumber;
  4893. current_scanner.preproc_pattern:=pattern;
  4894. readpreproc:=_INTCONST;
  4895. end;
  4896. '&' :
  4897. begin
  4898. readnumber;
  4899. if length(pattern)=1 then
  4900. begin
  4901. readstring;
  4902. readpreproc:=_ID;
  4903. end
  4904. else
  4905. readpreproc:=_INTCONST;
  4906. current_scanner.preproc_pattern:=pattern;
  4907. end;
  4908. '.' :
  4909. begin
  4910. readchar;
  4911. readpreproc:=_POINT;
  4912. end;
  4913. ',' :
  4914. begin
  4915. readchar;
  4916. readpreproc:=_COMMA;
  4917. end;
  4918. '}' :
  4919. begin
  4920. readpreproc:=_END;
  4921. end;
  4922. '(' :
  4923. begin
  4924. readchar;
  4925. readpreproc:=_LKLAMMER;
  4926. end;
  4927. ')' :
  4928. begin
  4929. readchar;
  4930. readpreproc:=_RKLAMMER;
  4931. end;
  4932. '[' :
  4933. begin
  4934. readchar;
  4935. readpreproc:=_LECKKLAMMER;
  4936. end;
  4937. ']' :
  4938. begin
  4939. readchar;
  4940. readpreproc:=_RECKKLAMMER;
  4941. end;
  4942. '+' :
  4943. begin
  4944. readchar;
  4945. readpreproc:=_PLUS;
  4946. end;
  4947. '-' :
  4948. begin
  4949. readchar;
  4950. readpreproc:=_MINUS;
  4951. end;
  4952. '*' :
  4953. begin
  4954. readchar;
  4955. readpreproc:=_STAR;
  4956. end;
  4957. '/' :
  4958. begin
  4959. readchar;
  4960. readpreproc:=_SLASH;
  4961. end;
  4962. '=' :
  4963. begin
  4964. readchar;
  4965. readpreproc:=_EQ;
  4966. end;
  4967. '>' :
  4968. begin
  4969. readchar;
  4970. if c='=' then
  4971. begin
  4972. readchar;
  4973. readpreproc:=_GTE;
  4974. end
  4975. else
  4976. readpreproc:=_GT;
  4977. end;
  4978. '<' :
  4979. begin
  4980. readchar;
  4981. case c of
  4982. '>' :
  4983. begin
  4984. readchar;
  4985. readpreproc:=_NE;
  4986. end;
  4987. '=' :
  4988. begin
  4989. readchar;
  4990. readpreproc:=_LTE;
  4991. end;
  4992. else
  4993. readpreproc:=_LT;
  4994. end;
  4995. end;
  4996. #26 :
  4997. begin
  4998. readpreproc:=_EOF;
  4999. checkpreprocstack;
  5000. end;
  5001. else
  5002. begin
  5003. Illegal_Char(c);
  5004. readpreproc:=NOTOKEN;
  5005. end;
  5006. end;
  5007. end;
  5008. function tscannerfile.asmgetcharstart : char;
  5009. begin
  5010. { return first the character already
  5011. available in c }
  5012. lastasmgetchar:=c;
  5013. result:=asmgetchar;
  5014. end;
  5015. function tscannerfile.asmgetchar : char;
  5016. begin
  5017. if lastasmgetchar<>#0 then
  5018. begin
  5019. c:=lastasmgetchar;
  5020. lastasmgetchar:=#0;
  5021. end
  5022. else
  5023. readchar;
  5024. if in_asm_string then
  5025. begin
  5026. asmgetchar:=c;
  5027. exit;
  5028. end;
  5029. repeat
  5030. case c of
  5031. // the { ... } is used in ARM assembler to define register sets, so we can't used
  5032. // it as comment, either (* ... *), /* ... */ or // ... should be used instead.
  5033. // But compiler directives {$...} are allowed in ARM assembler.
  5034. '{' :
  5035. begin
  5036. {$ifdef arm}
  5037. readchar;
  5038. dec(inputpointer);
  5039. if c<>'$' then
  5040. begin
  5041. asmgetchar:='{';
  5042. exit;
  5043. end
  5044. else
  5045. {$endif arm}
  5046. skipcomment;
  5047. end;
  5048. #10,#13 :
  5049. begin
  5050. linebreak;
  5051. asmgetchar:=c;
  5052. exit;
  5053. end;
  5054. #26 :
  5055. begin
  5056. reload;
  5057. if (c=#26) and not assigned(inputfile.next) then
  5058. end_of_file;
  5059. continue;
  5060. end;
  5061. '/' :
  5062. begin
  5063. readchar;
  5064. if c='/' then
  5065. skipdelphicomment
  5066. else
  5067. begin
  5068. asmgetchar:='/';
  5069. lastasmgetchar:=c;
  5070. exit;
  5071. end;
  5072. end;
  5073. '(' :
  5074. begin
  5075. readchar;
  5076. if c='*' then
  5077. begin
  5078. c:=#0;{Signal skipoldtpcomment to reload a char }
  5079. skipoldtpcomment;
  5080. end
  5081. else
  5082. begin
  5083. asmgetchar:='(';
  5084. lastasmgetchar:=c;
  5085. exit;
  5086. end;
  5087. end;
  5088. else
  5089. begin
  5090. asmgetchar:=c;
  5091. exit;
  5092. end;
  5093. end;
  5094. until false;
  5095. end;
  5096. {*****************************************************************************
  5097. Helpers
  5098. *****************************************************************************}
  5099. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5100. begin
  5101. if dm in [directive_all, directive_turbo] then
  5102. tdirectiveitem.create(turbo_scannerdirectives,s,p);
  5103. if dm in [directive_all, directive_mac] then
  5104. tdirectiveitem.create(mac_scannerdirectives,s,p);
  5105. end;
  5106. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5107. begin
  5108. if dm in [directive_all, directive_turbo] then
  5109. tdirectiveitem.createcond(turbo_scannerdirectives,s,p);
  5110. if dm in [directive_all, directive_mac] then
  5111. tdirectiveitem.createcond(mac_scannerdirectives,s,p);
  5112. end;
  5113. {*****************************************************************************
  5114. Initialization
  5115. *****************************************************************************}
  5116. procedure InitScanner;
  5117. begin
  5118. InitWideString(patternw);
  5119. turbo_scannerdirectives:=TFPHashObjectList.Create;
  5120. mac_scannerdirectives:=TFPHashObjectList.Create;
  5121. { Common directives and conditionals }
  5122. AddDirective('I',directive_all, @dir_include);
  5123. AddDirective('DEFINE',directive_all, @dir_define);
  5124. AddDirective('UNDEF',directive_all, @dir_undef);
  5125. AddConditional('IF',directive_all, @dir_if);
  5126. AddConditional('IFDEF',directive_all, @dir_ifdef);
  5127. AddConditional('IFNDEF',directive_all, @dir_ifndef);
  5128. AddConditional('ELSE',directive_all, @dir_else);
  5129. AddConditional('ELSEIF',directive_all, @dir_elseif);
  5130. AddConditional('ENDIF',directive_all, @dir_endif);
  5131. { Directives and conditionals for all modes except mode macpas}
  5132. AddDirective('INCLUDE',directive_turbo, @dir_include);
  5133. AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
  5134. AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
  5135. AddDirective('EXTENSION',directive_turbo, @dir_extension);
  5136. AddConditional('IFEND',directive_turbo, @dir_endif);
  5137. AddConditional('IFOPT',directive_turbo, @dir_ifopt);
  5138. { Directives and conditionals for mode macpas: }
  5139. AddDirective('SETC',directive_mac, @dir_setc);
  5140. AddDirective('DEFINEC',directive_mac, @dir_definec);
  5141. AddDirective('UNDEFC',directive_mac, @dir_undef);
  5142. AddConditional('IFC',directive_mac, @dir_if);
  5143. AddConditional('ELSEC',directive_mac, @dir_else);
  5144. AddConditional('ELIFC',directive_mac, @dir_elseif);
  5145. AddConditional('ENDC',directive_mac, @dir_endif);
  5146. end;
  5147. procedure DoneScanner;
  5148. begin
  5149. turbo_scannerdirectives.Free;
  5150. mac_scannerdirectives.Free;
  5151. DoneWideString(patternw);
  5152. end;
  5153. end.