scanner.pas 127 KB

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