scanner.pas 147 KB

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