scanner.pas 160 KB

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