scanner.pas 118 KB

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