scanner.pas 136 KB

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