scanner.pas 118 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768
  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='FPCTARGET' then
  1316. hs:=target_cpu_string
  1317. else
  1318. if hs='FPCTARGETCPU' then
  1319. hs:=target_cpu_string
  1320. else
  1321. if hs='FPCTARGETOS' then
  1322. hs:=target_info.shortname
  1323. else
  1324. hs:=getenv(hs);
  1325. if hs='' then
  1326. Message1(scan_w_include_env_not_found,path);
  1327. { make it a stringconst }
  1328. hs:=''''+hs+'''';
  1329. current_scanner.insertmacro(path,@hs[1],length(hs),
  1330. current_scanner.line_no,current_scanner.inputfile.ref_index);
  1331. end
  1332. else
  1333. begin
  1334. hs:=FixFileName(hs);
  1335. fsplit(hs,path,name,ext);
  1336. { try to find the file }
  1337. found:=findincludefile(path,name,ext,foundfile);
  1338. if (ext='') then
  1339. begin
  1340. { try default extensions .inc , .pp and .pas }
  1341. if (not found) then
  1342. found:=findincludefile(path,name,'.inc',foundfile);
  1343. if (not found) then
  1344. found:=findincludefile(path,name,sourceext,foundfile);
  1345. if (not found) then
  1346. found:=findincludefile(path,name,pasext,foundfile);
  1347. end;
  1348. if current_scanner.inputfilecount<max_include_nesting then
  1349. begin
  1350. inc(current_scanner.inputfilecount);
  1351. { we need to reread the current char }
  1352. dec(current_scanner.inputpointer);
  1353. { shutdown current file }
  1354. current_scanner.tempcloseinputfile;
  1355. { load new file }
  1356. hp:=do_openinputfile(foundfile);
  1357. current_scanner.addfile(hp);
  1358. current_module.sourcefiles.register_file(hp);
  1359. if (not found) then
  1360. Message1(scan_f_cannot_open_includefile,hs);
  1361. if (not current_scanner.openinputfile) then
  1362. Message1(scan_f_cannot_open_includefile,hs);
  1363. Message1(scan_t_start_include_file,current_scanner.inputfile.path^+current_scanner.inputfile.name^);
  1364. current_scanner.reload;
  1365. end
  1366. else
  1367. Message(scan_f_include_deep_ten);
  1368. end;
  1369. end;
  1370. {*****************************************************************************
  1371. Preprocessor writting
  1372. *****************************************************************************}
  1373. {$ifdef PREPROCWRITE}
  1374. constructor tpreprocfile.create(const fn:string);
  1375. begin
  1376. { open outputfile }
  1377. assign(f,fn);
  1378. {$I-}
  1379. rewrite(f);
  1380. {$I+}
  1381. if ioresult<>0 then
  1382. Comment(V_Fatal,'can''t create file '+fn);
  1383. getmem(buf,preprocbufsize);
  1384. settextbuf(f,buf^,preprocbufsize);
  1385. { reset }
  1386. eolfound:=false;
  1387. spacefound:=false;
  1388. end;
  1389. destructor tpreprocfile.destroy;
  1390. begin
  1391. close(f);
  1392. freemem(buf,preprocbufsize);
  1393. end;
  1394. procedure tpreprocfile.add(const s:string);
  1395. begin
  1396. write(f,s);
  1397. end;
  1398. procedure tpreprocfile.addspace;
  1399. begin
  1400. if eolfound then
  1401. begin
  1402. writeln(f,'');
  1403. eolfound:=false;
  1404. spacefound:=false;
  1405. end
  1406. else
  1407. if spacefound then
  1408. begin
  1409. write(f,' ');
  1410. spacefound:=false;
  1411. end;
  1412. end;
  1413. {$endif PREPROCWRITE}
  1414. {*****************************************************************************
  1415. TPreProcStack
  1416. *****************************************************************************}
  1417. constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
  1418. begin
  1419. accept:=a;
  1420. typ:=atyp;
  1421. next:=n;
  1422. end;
  1423. {*****************************************************************************
  1424. TDirectiveItem
  1425. *****************************************************************************}
  1426. constructor TDirectiveItem.Create(const n:string;p:tdirectiveproc);
  1427. begin
  1428. inherited CreateName(n);
  1429. is_conditional:=false;
  1430. proc:=p;
  1431. end;
  1432. constructor TDirectiveItem.CreateCond(const n:string;p:tdirectiveproc);
  1433. begin
  1434. inherited CreateName(n);
  1435. is_conditional:=true;
  1436. proc:=p;
  1437. end;
  1438. {****************************************************************************
  1439. TSCANNERFILE
  1440. ****************************************************************************}
  1441. constructor tscannerfile.create(const fn:string);
  1442. begin
  1443. inputfile:=do_openinputfile(fn);
  1444. if assigned(current_module) then
  1445. current_module.sourcefiles.register_file(inputfile);
  1446. { reset localinput }
  1447. inputbuffer:=nil;
  1448. inputpointer:=nil;
  1449. inputstart:=0;
  1450. { reset scanner }
  1451. preprocstack:=nil;
  1452. comment_level:=0;
  1453. yylexcount:=0;
  1454. block_type:=bt_general;
  1455. line_no:=0;
  1456. lastlinepos:=0;
  1457. lasttokenpos:=0;
  1458. lasttoken:=NOTOKEN;
  1459. nexttoken:=NOTOKEN;
  1460. lastasmgetchar:=#0;
  1461. ignoredirectives:=TStringList.Create;
  1462. in_asm_string:=false;
  1463. end;
  1464. procedure tscannerfile.firstfile;
  1465. begin
  1466. { load block }
  1467. if not openinputfile then
  1468. Message1(scan_f_cannot_open_input,inputfile.name^);
  1469. reload;
  1470. end;
  1471. destructor tscannerfile.destroy;
  1472. begin
  1473. if assigned(current_module) and
  1474. (current_module.state=ms_compiled) and
  1475. (status.errorcount=0) then
  1476. checkpreprocstack
  1477. else
  1478. begin
  1479. while assigned(preprocstack) do
  1480. poppreprocstack;
  1481. end;
  1482. if not inputfile.closed then
  1483. closeinputfile;
  1484. ignoredirectives.free;
  1485. end;
  1486. function tscannerfile.openinputfile:boolean;
  1487. begin
  1488. openinputfile:=inputfile.open;
  1489. { load buffer }
  1490. inputbuffer:=inputfile.buf;
  1491. inputpointer:=inputfile.buf;
  1492. inputstart:=inputfile.bufstart;
  1493. { line }
  1494. line_no:=0;
  1495. lastlinepos:=0;
  1496. lasttokenpos:=0;
  1497. end;
  1498. procedure tscannerfile.closeinputfile;
  1499. begin
  1500. inputfile.close;
  1501. { reset buffer }
  1502. inputbuffer:=nil;
  1503. inputpointer:=nil;
  1504. inputstart:=0;
  1505. { reset line }
  1506. line_no:=0;
  1507. lastlinepos:=0;
  1508. lasttokenpos:=0;
  1509. end;
  1510. function tscannerfile.tempopeninputfile:boolean;
  1511. begin
  1512. if inputfile.is_macro then
  1513. exit;
  1514. tempopeninputfile:=inputfile.tempopen;
  1515. { reload buffer }
  1516. inputbuffer:=inputfile.buf;
  1517. inputpointer:=inputfile.buf;
  1518. inputstart:=inputfile.bufstart;
  1519. end;
  1520. procedure tscannerfile.tempcloseinputfile;
  1521. begin
  1522. if inputfile.closed or inputfile.is_macro then
  1523. exit;
  1524. inputfile.setpos(inputstart+(inputpointer-inputbuffer));
  1525. inputfile.tempclose;
  1526. { reset buffer }
  1527. inputbuffer:=nil;
  1528. inputpointer:=nil;
  1529. inputstart:=0;
  1530. end;
  1531. procedure tscannerfile.saveinputfile;
  1532. begin
  1533. inputfile.saveinputpointer:=inputpointer;
  1534. inputfile.savelastlinepos:=lastlinepos;
  1535. inputfile.saveline_no:=line_no;
  1536. end;
  1537. procedure tscannerfile.restoreinputfile;
  1538. begin
  1539. inputpointer:=inputfile.saveinputpointer;
  1540. lastlinepos:=inputfile.savelastlinepos;
  1541. line_no:=inputfile.saveline_no;
  1542. if not inputfile.is_macro then
  1543. parser_current_file:=inputfile.name^;
  1544. end;
  1545. procedure tscannerfile.nextfile;
  1546. var
  1547. to_dispose : tinputfile;
  1548. begin
  1549. if assigned(inputfile.next) then
  1550. begin
  1551. if inputfile.is_macro then
  1552. to_dispose:=inputfile
  1553. else
  1554. begin
  1555. to_dispose:=nil;
  1556. dec(inputfilecount);
  1557. end;
  1558. { we can allways close the file, no ? }
  1559. inputfile.close;
  1560. inputfile:=inputfile.next;
  1561. if assigned(to_dispose) then
  1562. to_dispose.free;
  1563. restoreinputfile;
  1564. end;
  1565. end;
  1566. procedure tscannerfile.addfile(hp:tinputfile);
  1567. begin
  1568. saveinputfile;
  1569. { add to list }
  1570. hp.next:=inputfile;
  1571. inputfile:=hp;
  1572. { load new inputfile }
  1573. restoreinputfile;
  1574. end;
  1575. procedure tscannerfile.reload;
  1576. begin
  1577. with inputfile do
  1578. begin
  1579. { when nothing more to read then leave immediatly, so we
  1580. don't change the aktfilepos and leave it point to the last
  1581. char }
  1582. if (c=#26) and (not assigned(next)) then
  1583. exit;
  1584. repeat
  1585. { still more to read?, then change the #0 to a space so its seen
  1586. as a seperator, this can't be used for macro's which can change
  1587. the place of the #0 in the buffer with tempopen }
  1588. if (c=#0) and (bufsize>0) and
  1589. not(inputfile.is_macro) and
  1590. (inputpointer-inputbuffer<bufsize) then
  1591. begin
  1592. c:=' ';
  1593. inc(inputpointer);
  1594. exit;
  1595. end;
  1596. { can we read more from this file ? }
  1597. if (c<>#26) and (not endoffile) then
  1598. begin
  1599. readbuf;
  1600. inputpointer:=buf;
  1601. inputbuffer:=buf;
  1602. inputstart:=bufstart;
  1603. { first line? }
  1604. if line_no=0 then
  1605. begin
  1606. c:=inputpointer^;
  1607. { eat utf-8 signature? }
  1608. if (ord(inputpointer^)=$ef) and
  1609. (ord((inputpointer+1)^)=$bb) and
  1610. (ord((inputpointer+2)^)=$bf) then
  1611. begin
  1612. inc(inputpointer,3);
  1613. message(scan_c_switching_to_utf8);
  1614. aktsourcecodepage:='utf8';
  1615. end;
  1616. line_no:=1;
  1617. if cs_asm_source in aktglobalswitches then
  1618. inputfile.setline(line_no,bufstart);
  1619. end;
  1620. end
  1621. else
  1622. begin
  1623. { load eof position in tokenpos/aktfilepos }
  1624. gettokenpos;
  1625. { close file }
  1626. closeinputfile;
  1627. { no next module, than EOF }
  1628. if not assigned(inputfile.next) then
  1629. begin
  1630. c:=#26;
  1631. exit;
  1632. end;
  1633. { load next file and reopen it }
  1634. nextfile;
  1635. tempopeninputfile;
  1636. { status }
  1637. Message1(scan_t_back_in,inputfile.name^);
  1638. end;
  1639. { load next char }
  1640. c:=inputpointer^;
  1641. inc(inputpointer);
  1642. until c<>#0; { if also end, then reload again }
  1643. end;
  1644. end;
  1645. procedure tscannerfile.insertmacro(const macname:string;p:pchar;len,line,fileindex:longint);
  1646. var
  1647. hp : tinputfile;
  1648. begin
  1649. { save old postion }
  1650. dec(inputpointer);
  1651. tempcloseinputfile;
  1652. { create macro 'file' }
  1653. { use special name to dispose after !! }
  1654. hp:=do_openinputfile('_Macro_.'+macname);
  1655. addfile(hp);
  1656. with inputfile do
  1657. begin
  1658. setmacro(p,len);
  1659. { local buffer }
  1660. inputbuffer:=buf;
  1661. inputpointer:=buf;
  1662. inputstart:=bufstart;
  1663. ref_index:=fileindex;
  1664. end;
  1665. { reset line }
  1666. line_no:=line;
  1667. lastlinepos:=0;
  1668. lasttokenpos:=0;
  1669. { load new c }
  1670. c:=inputpointer^;
  1671. inc(inputpointer);
  1672. end;
  1673. procedure tscannerfile.gettokenpos;
  1674. { load the values of tokenpos and lasttokenpos }
  1675. begin
  1676. lasttokenpos:=inputstart+(inputpointer-inputbuffer);
  1677. akttokenpos.line:=line_no;
  1678. akttokenpos.column:=lasttokenpos-lastlinepos;
  1679. akttokenpos.fileindex:=inputfile.ref_index;
  1680. aktfilepos:=akttokenpos;
  1681. end;
  1682. procedure tscannerfile.inc_comment_level;
  1683. var
  1684. oldaktfilepos : tfileposinfo;
  1685. begin
  1686. if (m_nested_comment in aktmodeswitches) then
  1687. inc(comment_level)
  1688. else
  1689. comment_level:=1;
  1690. if (comment_level>1) then
  1691. begin
  1692. oldaktfilepos:=aktfilepos;
  1693. gettokenpos; { update for warning }
  1694. Message1(scan_w_comment_level,tostr(comment_level));
  1695. aktfilepos:=oldaktfilepos;
  1696. end;
  1697. end;
  1698. procedure tscannerfile.dec_comment_level;
  1699. begin
  1700. if (m_nested_comment in aktmodeswitches) then
  1701. dec(comment_level)
  1702. else
  1703. comment_level:=0;
  1704. end;
  1705. procedure tscannerfile.linebreak;
  1706. var
  1707. cur : char;
  1708. oldtokenpos,
  1709. oldaktfilepos : tfileposinfo;
  1710. begin
  1711. with inputfile do
  1712. begin
  1713. if (byte(inputpointer^)=0) and not(endoffile) then
  1714. begin
  1715. cur:=c;
  1716. reload;
  1717. if byte(cur)+byte(c)<>23 then
  1718. dec(inputpointer);
  1719. end
  1720. else
  1721. begin
  1722. { Support all combination of #10 and #13 as line break }
  1723. if (byte(inputpointer^)+byte(c)=23) then
  1724. inc(inputpointer);
  1725. end;
  1726. { Always return #10 as line break }
  1727. c:=#10;
  1728. { increase line counters }
  1729. lastlinepos:=bufstart+(inputpointer-inputbuffer);
  1730. inc(line_no);
  1731. { update linebuffer }
  1732. if cs_asm_source in aktglobalswitches then
  1733. inputfile.setline(line_no,lastlinepos);
  1734. { update for status and call the show status routine,
  1735. but don't touch aktfilepos ! }
  1736. oldaktfilepos:=aktfilepos;
  1737. oldtokenpos:=akttokenpos;
  1738. gettokenpos; { update for v_status }
  1739. inc(status.compiledlines);
  1740. ShowStatus;
  1741. aktfilepos:=oldaktfilepos;
  1742. akttokenpos:=oldtokenpos;
  1743. end;
  1744. end;
  1745. procedure tscannerfile.illegal_char(c:char);
  1746. var
  1747. s : string;
  1748. begin
  1749. if c in [#32..#255] then
  1750. s:=''''+c+''''
  1751. else
  1752. s:='#'+tostr(ord(c));
  1753. Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
  1754. end;
  1755. procedure tscannerfile.end_of_file;
  1756. begin
  1757. checkpreprocstack;
  1758. Message(scan_f_end_of_file);
  1759. end;
  1760. {-------------------------------------------
  1761. IF Conditional Handling
  1762. -------------------------------------------}
  1763. procedure tscannerfile.checkpreprocstack;
  1764. begin
  1765. { check for missing ifdefs }
  1766. while assigned(preprocstack) do
  1767. begin
  1768. Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
  1769. preprocstack.owner.inputfile.name^,tostr(preprocstack.line_nb));
  1770. poppreprocstack;
  1771. end;
  1772. end;
  1773. procedure tscannerfile.poppreprocstack;
  1774. var
  1775. hp : tpreprocstack;
  1776. begin
  1777. if assigned(preprocstack) then
  1778. begin
  1779. Message1(scan_c_endif_found,preprocstack.name);
  1780. hp:=preprocstack.next;
  1781. preprocstack.free;
  1782. preprocstack:=hp;
  1783. end
  1784. else
  1785. Message(scan_e_endif_without_if);
  1786. end;
  1787. procedure tscannerfile.ifpreprocstack(atyp : preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  1788. var
  1789. condition: Boolean;
  1790. valuedescr: String;
  1791. begin
  1792. if (preprocstack=nil) or preprocstack.accept then
  1793. condition:= compile_time_predicate(valuedescr)
  1794. else
  1795. begin
  1796. condition:= false;
  1797. valuedescr:= '';
  1798. end;
  1799. preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
  1800. preprocstack.name:=valuedescr;
  1801. preprocstack.line_nb:=line_no;
  1802. preprocstack.owner:=self;
  1803. if preprocstack.accept then
  1804. Message2(messid,preprocstack.name,'accepted')
  1805. else
  1806. Message2(messid,preprocstack.name,'rejected');
  1807. end;
  1808. procedure tscannerfile.elsepreprocstack;
  1809. begin
  1810. if assigned(preprocstack) and
  1811. (preprocstack.typ<>pp_else) then
  1812. begin
  1813. if (preprocstack.typ=pp_elseif) then
  1814. preprocstack.accept:=false
  1815. else
  1816. if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
  1817. preprocstack.accept:=not preprocstack.accept;
  1818. preprocstack.typ:=pp_else;
  1819. preprocstack.line_nb:=line_no;
  1820. if preprocstack.accept then
  1821. Message2(scan_c_else_found,preprocstack.name,'accepted')
  1822. else
  1823. Message2(scan_c_else_found,preprocstack.name,'rejected');
  1824. end
  1825. else
  1826. Message(scan_e_endif_without_if);
  1827. end;
  1828. procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  1829. var
  1830. valuedescr: String;
  1831. begin
  1832. if assigned(preprocstack) and
  1833. (preprocstack.typ in [pp_if,pp_elseif]) then
  1834. begin
  1835. { when the branch is accepted we use pp_elseif so we know that
  1836. all the next branches need to be rejected. when this branch is still
  1837. not accepted then leave it at pp_if }
  1838. if (preprocstack.typ=pp_elseif) then
  1839. preprocstack.accept:=false
  1840. else if (preprocstack.typ=pp_if) and preprocstack.accept then
  1841. begin
  1842. preprocstack.accept:=false;
  1843. preprocstack.typ:=pp_elseif;
  1844. end
  1845. else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
  1846. and compile_time_predicate(valuedescr) then
  1847. begin
  1848. preprocstack.name:=valuedescr;
  1849. preprocstack.accept:=true;
  1850. preprocstack.typ:=pp_elseif;
  1851. end;
  1852. preprocstack.line_nb:=line_no;
  1853. if preprocstack.accept then
  1854. Message2(scan_c_else_found,preprocstack.name,'accepted')
  1855. else
  1856. Message2(scan_c_else_found,preprocstack.name,'rejected');
  1857. end
  1858. else
  1859. Message(scan_e_endif_without_if);
  1860. end;
  1861. procedure tscannerfile.handleconditional(p:tdirectiveitem);
  1862. var
  1863. oldaktfilepos : tfileposinfo;
  1864. begin
  1865. oldaktfilepos:=aktfilepos;
  1866. repeat
  1867. current_scanner.gettokenpos;
  1868. p.proc();
  1869. { accept the text ? }
  1870. if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
  1871. break
  1872. else
  1873. begin
  1874. current_scanner.gettokenpos;
  1875. Message(scan_c_skipping_until);
  1876. repeat
  1877. current_scanner.skipuntildirective;
  1878. if not (m_mac in aktmodeswitches) then
  1879. p:=tdirectiveitem(turbo_scannerdirectives.search(current_scanner.readid))
  1880. else
  1881. p:=tdirectiveitem(mac_scannerdirectives.search(current_scanner.readid));
  1882. until assigned(p) and (p.is_conditional);
  1883. current_scanner.gettokenpos;
  1884. Message1(scan_d_handling_switch,'$'+p.name);
  1885. end;
  1886. until false;
  1887. aktfilepos:=oldaktfilepos;
  1888. end;
  1889. procedure tscannerfile.handledirectives;
  1890. var
  1891. t : tdirectiveitem;
  1892. hs : string;
  1893. begin
  1894. gettokenpos;
  1895. readchar; {Remove the $}
  1896. hs:=readid;
  1897. {$ifdef PREPROCWRITE}
  1898. if parapreprocess then
  1899. begin
  1900. t:=Get_Directive(hs);
  1901. if not(is_conditional(t) or (t=_DIR_DEFINE) or (t=_DIR_UNDEF)) then
  1902. begin
  1903. preprocfile^.AddSpace;
  1904. preprocfile^.Add('{$'+hs+current_scanner.readcomment+'}');
  1905. exit;
  1906. end;
  1907. end;
  1908. {$endif PREPROCWRITE}
  1909. { skip this directive? }
  1910. if (ignoredirectives.find(hs)<>nil) then
  1911. begin
  1912. if (comment_level>0) then
  1913. readcomment;
  1914. { we've read the whole comment }
  1915. aktcommentstyle:=comment_none;
  1916. exit;
  1917. end;
  1918. if hs='' then
  1919. begin
  1920. Message1(scan_w_illegal_switch,'$'+hs);
  1921. end;
  1922. { Check for compiler switches }
  1923. while (length(hs)=1) and (c in ['-','+']) do
  1924. begin
  1925. HandleSwitch(hs[1],c);
  1926. current_scanner.readchar; {Remove + or -}
  1927. if c=',' then
  1928. begin
  1929. current_scanner.readchar; {Remove , }
  1930. { read next switch, support $v+,$+}
  1931. hs:=current_scanner.readid;
  1932. if (hs='') then
  1933. begin
  1934. if (c='$') and (m_fpc in aktmodeswitches) then
  1935. begin
  1936. current_scanner.readchar; { skip $ }
  1937. hs:=current_scanner.readid;
  1938. end;
  1939. if (hs='') then
  1940. Message1(scan_w_illegal_directive,'$'+c);
  1941. end
  1942. else
  1943. Message1(scan_d_handling_switch,'$'+hs);
  1944. end
  1945. else
  1946. hs:='';
  1947. end;
  1948. { directives may follow switches after a , }
  1949. if hs<>'' then
  1950. begin
  1951. if not (m_mac in aktmodeswitches) then
  1952. t:=tdirectiveitem(turbo_scannerdirectives.search(hs))
  1953. else
  1954. t:=tdirectiveitem(mac_scannerdirectives.search(hs));
  1955. if assigned(t) then
  1956. begin
  1957. if t.is_conditional then
  1958. handleconditional(t)
  1959. else
  1960. begin
  1961. Message1(scan_d_handling_switch,'$'+hs);
  1962. t.proc();
  1963. end;
  1964. end
  1965. else
  1966. begin
  1967. current_scanner.ignoredirectives.insert(hs);
  1968. Message1(scan_w_illegal_directive,'$'+hs);
  1969. end;
  1970. { conditionals already read the comment }
  1971. if (current_scanner.comment_level>0) then
  1972. current_scanner.readcomment;
  1973. { we've read the whole comment }
  1974. aktcommentstyle:=comment_none;
  1975. end;
  1976. end;
  1977. procedure tscannerfile.readchar;
  1978. begin
  1979. c:=inputpointer^;
  1980. if c=#0 then
  1981. reload
  1982. else
  1983. inc(inputpointer);
  1984. end;
  1985. procedure tscannerfile.readstring;
  1986. var
  1987. i : longint;
  1988. err : boolean;
  1989. begin
  1990. err:=false;
  1991. i:=0;
  1992. repeat
  1993. case c of
  1994. '_',
  1995. '0'..'9',
  1996. 'A'..'Z' :
  1997. begin
  1998. if i<255 then
  1999. begin
  2000. inc(i);
  2001. orgpattern[i]:=c;
  2002. pattern[i]:=c;
  2003. end
  2004. else
  2005. begin
  2006. if not err then
  2007. begin
  2008. Message(scan_e_string_exceeds_255_chars);
  2009. err:=true;
  2010. end;
  2011. end;
  2012. c:=inputpointer^;
  2013. inc(inputpointer);
  2014. end;
  2015. 'a'..'z' :
  2016. begin
  2017. if i<255 then
  2018. begin
  2019. inc(i);
  2020. orgpattern[i]:=c;
  2021. pattern[i]:=chr(ord(c)-32)
  2022. end
  2023. else
  2024. begin
  2025. if not err then
  2026. begin
  2027. Message(scan_e_string_exceeds_255_chars);
  2028. err:=true;
  2029. end;
  2030. end;
  2031. c:=inputpointer^;
  2032. inc(inputpointer);
  2033. end;
  2034. #0 :
  2035. reload;
  2036. else
  2037. break;
  2038. end;
  2039. until false;
  2040. orgpattern[0]:=chr(i);
  2041. pattern[0]:=chr(i);
  2042. end;
  2043. procedure tscannerfile.readnumber;
  2044. var
  2045. base,
  2046. i : longint;
  2047. begin
  2048. case c of
  2049. '%' :
  2050. begin
  2051. readchar;
  2052. base:=2;
  2053. pattern[1]:='%';
  2054. i:=1;
  2055. end;
  2056. '&' :
  2057. begin
  2058. readchar;
  2059. base:=8;
  2060. pattern[1]:='&';
  2061. i:=1;
  2062. end;
  2063. '$' :
  2064. begin
  2065. readchar;
  2066. base:=16;
  2067. pattern[1]:='$';
  2068. i:=1;
  2069. end;
  2070. else
  2071. begin
  2072. base:=10;
  2073. i:=0;
  2074. end;
  2075. end;
  2076. while ((base>=10) and (c in ['0'..'9'])) or
  2077. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  2078. ((base=8) and (c in ['0'..'7'])) or
  2079. ((base=2) and (c in ['0'..'1'])) do
  2080. begin
  2081. if i<255 then
  2082. begin
  2083. inc(i);
  2084. pattern[i]:=c;
  2085. end;
  2086. readchar;
  2087. end;
  2088. pattern[0]:=chr(i);
  2089. end;
  2090. function tscannerfile.readid:string;
  2091. begin
  2092. readstring;
  2093. readid:=pattern;
  2094. end;
  2095. function tscannerfile.readval:longint;
  2096. var
  2097. l : longint;
  2098. w : integer;
  2099. begin
  2100. readnumber;
  2101. val(pattern,l,w);
  2102. readval:=l;
  2103. end;
  2104. function tscannerfile.readval_asstring:string;
  2105. begin
  2106. readnumber;
  2107. readval_asstring:=pattern;
  2108. end;
  2109. function tscannerfile.readcomment:string;
  2110. var
  2111. i : longint;
  2112. begin
  2113. i:=0;
  2114. repeat
  2115. case c of
  2116. '{' :
  2117. begin
  2118. if aktcommentstyle=comment_tp then
  2119. inc_comment_level;
  2120. end;
  2121. '}' :
  2122. begin
  2123. if aktcommentstyle=comment_tp then
  2124. begin
  2125. readchar;
  2126. dec_comment_level;
  2127. if comment_level=0 then
  2128. break
  2129. else
  2130. continue;
  2131. end;
  2132. end;
  2133. '*' :
  2134. begin
  2135. if aktcommentstyle=comment_oldtp then
  2136. begin
  2137. readchar;
  2138. if c=')' then
  2139. begin
  2140. readchar;
  2141. dec_comment_level;
  2142. break;
  2143. end
  2144. else
  2145. { Add both characters !!}
  2146. if (i<255) then
  2147. begin
  2148. inc(i);
  2149. readcomment[i]:='*';
  2150. if (i<255) then
  2151. begin
  2152. inc(i);
  2153. readcomment[i]:='*';
  2154. end;
  2155. end;
  2156. end
  2157. else
  2158. { Not old TP comment, so add...}
  2159. begin
  2160. if (i<255) then
  2161. begin
  2162. inc(i);
  2163. readcomment[i]:='*';
  2164. end;
  2165. end;
  2166. end;
  2167. #10,#13 :
  2168. linebreak;
  2169. #26 :
  2170. end_of_file;
  2171. else
  2172. begin
  2173. if (i<255) then
  2174. begin
  2175. inc(i);
  2176. readcomment[i]:=c;
  2177. end;
  2178. end;
  2179. end;
  2180. readchar;
  2181. until false;
  2182. readcomment[0]:=chr(i);
  2183. end;
  2184. function tscannerfile.readquotedstring:string;
  2185. var
  2186. i : longint;
  2187. msgwritten : boolean;
  2188. begin
  2189. i:=0;
  2190. msgwritten:=false;
  2191. if (c='''') then
  2192. begin
  2193. repeat
  2194. readchar;
  2195. case c of
  2196. #26 :
  2197. end_of_file;
  2198. #10,#13 :
  2199. Message(scan_f_string_exceeds_line);
  2200. '''' :
  2201. begin
  2202. readchar;
  2203. if c<>'''' then
  2204. break;
  2205. end;
  2206. end;
  2207. if i<255 then
  2208. begin
  2209. inc(i);
  2210. result[i]:=c;
  2211. end
  2212. else
  2213. begin
  2214. if not msgwritten then
  2215. begin
  2216. Message(scan_e_string_exceeds_255_chars);
  2217. msgwritten:=true;
  2218. end;
  2219. end;
  2220. until false;
  2221. end;
  2222. result[0]:=chr(i);
  2223. end;
  2224. function tscannerfile.readstate:char;
  2225. var
  2226. state : char;
  2227. begin
  2228. state:=' ';
  2229. if c=' ' then
  2230. begin
  2231. current_scanner.skipspace;
  2232. current_scanner.readid;
  2233. if pattern='ON' then
  2234. state:='+'
  2235. else
  2236. if pattern='OFF' then
  2237. state:='-';
  2238. end
  2239. else
  2240. state:=c;
  2241. if not (state in ['+','-']) then
  2242. Message(scan_e_wrong_switch_toggle);
  2243. readstate:=state;
  2244. end;
  2245. function tscannerfile.readstatedefault:char;
  2246. var
  2247. state : char;
  2248. begin
  2249. state:=' ';
  2250. if c=' ' then
  2251. begin
  2252. current_scanner.skipspace;
  2253. current_scanner.readid;
  2254. if pattern='ON' then
  2255. state:='+'
  2256. else
  2257. if pattern='OFF' then
  2258. state:='-'
  2259. else
  2260. if pattern='DEFAULT' then
  2261. state:='*';
  2262. end
  2263. else
  2264. state:=c;
  2265. if not (state in ['+','-','*']) then
  2266. Message(scan_e_wrong_switch_toggle_default);
  2267. readstatedefault:=state;
  2268. end;
  2269. procedure tscannerfile.skipspace;
  2270. begin
  2271. repeat
  2272. case c of
  2273. #26 :
  2274. begin
  2275. reload;
  2276. if (c=#26) and not assigned(inputfile.next) then
  2277. break;
  2278. continue;
  2279. end;
  2280. #10,
  2281. #13 :
  2282. linebreak;
  2283. #9,#11,#12,' ' :
  2284. ;
  2285. else
  2286. break;
  2287. end;
  2288. readchar;
  2289. until false;
  2290. end;
  2291. procedure tscannerfile.skipuntildirective;
  2292. var
  2293. found : longint;
  2294. next_char_loaded : boolean;
  2295. begin
  2296. found:=0;
  2297. next_char_loaded:=false;
  2298. repeat
  2299. case c of
  2300. #10,
  2301. #13 :
  2302. linebreak;
  2303. #26 :
  2304. begin
  2305. reload;
  2306. if (c=#26) and not assigned(inputfile.next) then
  2307. end_of_file;
  2308. continue;
  2309. end;
  2310. '{' :
  2311. begin
  2312. if (aktcommentstyle in [comment_tp,comment_none]) then
  2313. begin
  2314. aktcommentstyle:=comment_tp;
  2315. if (comment_level=0) then
  2316. found:=1;
  2317. inc_comment_level;
  2318. end;
  2319. end;
  2320. '*' :
  2321. begin
  2322. if (aktcommentstyle=comment_oldtp) then
  2323. begin
  2324. readchar;
  2325. if c=')' then
  2326. begin
  2327. dec_comment_level;
  2328. found:=0;
  2329. aktcommentstyle:=comment_none;
  2330. end
  2331. else
  2332. next_char_loaded:=true;
  2333. end
  2334. else
  2335. found := 0;
  2336. end;
  2337. '}' :
  2338. begin
  2339. if (aktcommentstyle=comment_tp) then
  2340. begin
  2341. dec_comment_level;
  2342. if (comment_level=0) then
  2343. aktcommentstyle:=comment_none;
  2344. found:=0;
  2345. end;
  2346. end;
  2347. '$' :
  2348. begin
  2349. if found=1 then
  2350. found:=2;
  2351. end;
  2352. '''' :
  2353. if (aktcommentstyle=comment_none) then
  2354. begin
  2355. repeat
  2356. readchar;
  2357. case c of
  2358. #26 :
  2359. end_of_file;
  2360. #10,#13 :
  2361. break;
  2362. '''' :
  2363. begin
  2364. readchar;
  2365. if c<>'''' then
  2366. begin
  2367. next_char_loaded:=true;
  2368. break;
  2369. end;
  2370. end;
  2371. end;
  2372. until false;
  2373. end;
  2374. '(' :
  2375. begin
  2376. if (aktcommentstyle=comment_none) then
  2377. begin
  2378. readchar;
  2379. if c='*' then
  2380. begin
  2381. readchar;
  2382. if c='$' then
  2383. begin
  2384. found:=2;
  2385. inc_comment_level;
  2386. aktcommentstyle:=comment_oldtp;
  2387. end
  2388. else
  2389. begin
  2390. skipoldtpcomment;
  2391. next_char_loaded:=true;
  2392. end;
  2393. end
  2394. else
  2395. next_char_loaded:=true;
  2396. end
  2397. else
  2398. found:=0;
  2399. end;
  2400. '/' :
  2401. begin
  2402. if (aktcommentstyle=comment_none) then
  2403. begin
  2404. readchar;
  2405. if c='/' then
  2406. skipdelphicomment;
  2407. next_char_loaded:=true;
  2408. end
  2409. else
  2410. found:=0;
  2411. end;
  2412. else
  2413. found:=0;
  2414. end;
  2415. if next_char_loaded then
  2416. next_char_loaded:=false
  2417. else
  2418. readchar;
  2419. until (found=2);
  2420. end;
  2421. {****************************************************************************
  2422. Comment Handling
  2423. ****************************************************************************}
  2424. procedure tscannerfile.skipcomment;
  2425. begin
  2426. aktcommentstyle:=comment_tp;
  2427. readchar;
  2428. inc_comment_level;
  2429. { handle compiler switches }
  2430. if (c='$') then
  2431. handledirectives;
  2432. { handle_switches can dec comment_level, }
  2433. while (comment_level>0) do
  2434. begin
  2435. case c of
  2436. '{' :
  2437. inc_comment_level;
  2438. '}' :
  2439. dec_comment_level;
  2440. #10,#13 :
  2441. linebreak;
  2442. #26 :
  2443. begin
  2444. reload;
  2445. if (c=#26) and not assigned(inputfile.next) then
  2446. end_of_file;
  2447. continue;
  2448. end;
  2449. end;
  2450. readchar;
  2451. end;
  2452. aktcommentstyle:=comment_none;
  2453. end;
  2454. procedure tscannerfile.skipdelphicomment;
  2455. begin
  2456. aktcommentstyle:=comment_delphi;
  2457. inc_comment_level;
  2458. readchar;
  2459. { this is not supported }
  2460. if c='$' then
  2461. Message(scan_w_wrong_styled_switch);
  2462. { skip comment }
  2463. while not (c in [#10,#13,#26]) do
  2464. readchar;
  2465. dec_comment_level;
  2466. aktcommentstyle:=comment_none;
  2467. end;
  2468. procedure tscannerfile.skipoldtpcomment;
  2469. var
  2470. found : longint;
  2471. begin
  2472. aktcommentstyle:=comment_oldtp;
  2473. inc_comment_level;
  2474. { only load a char if last already processed,
  2475. was cause of bug1634 PM }
  2476. if c=#0 then
  2477. readchar;
  2478. { this is now supported }
  2479. if (c='$') then
  2480. handledirectives;
  2481. { skip comment }
  2482. while (comment_level>0) do
  2483. begin
  2484. found:=0;
  2485. repeat
  2486. case c of
  2487. #26 :
  2488. begin
  2489. reload;
  2490. if (c=#26) and not assigned(inputfile.next) then
  2491. end_of_file;
  2492. continue;
  2493. end;
  2494. #10,#13 :
  2495. linebreak;
  2496. '*' :
  2497. begin
  2498. if found=3 then
  2499. found:=4
  2500. else
  2501. found:=1;
  2502. end;
  2503. ')' :
  2504. begin
  2505. if found in [1,4] then
  2506. begin
  2507. dec_comment_level;
  2508. if comment_level=0 then
  2509. found:=2
  2510. else
  2511. found:=0;
  2512. end;
  2513. end;
  2514. '(' :
  2515. begin
  2516. if found=4 then
  2517. inc_comment_level;
  2518. found:=3;
  2519. end;
  2520. else
  2521. begin
  2522. if found=4 then
  2523. inc_comment_level;
  2524. found:=0;
  2525. end;
  2526. end;
  2527. readchar;
  2528. until (found=2);
  2529. end;
  2530. aktcommentstyle:=comment_none;
  2531. end;
  2532. {****************************************************************************
  2533. Token Scanner
  2534. ****************************************************************************}
  2535. procedure tscannerfile.readtoken;
  2536. var
  2537. code : integer;
  2538. len,
  2539. low,high,mid : longint;
  2540. w : word;
  2541. m : longint;
  2542. mac : tmacro;
  2543. asciinr : string[6];
  2544. msgwritten,
  2545. iswidestring : boolean;
  2546. label
  2547. exit_label;
  2548. begin
  2549. if localswitcheschanged then
  2550. begin
  2551. aktlocalswitches:=nextaktlocalswitches;
  2552. localswitcheschanged:=false;
  2553. end;
  2554. { was there already a token read, then return that token }
  2555. if nexttoken<>NOTOKEN then
  2556. begin
  2557. token:=nexttoken;
  2558. nexttoken:=NOTOKEN;
  2559. goto exit_label;
  2560. end;
  2561. { Skip all spaces and comments }
  2562. repeat
  2563. case c of
  2564. '{' :
  2565. skipcomment;
  2566. #26 :
  2567. begin
  2568. reload;
  2569. if (c=#26) and not assigned(inputfile.next) then
  2570. break;
  2571. end;
  2572. ' ',#9..#13 :
  2573. begin
  2574. {$ifdef PREPROCWRITE}
  2575. if parapreprocess then
  2576. begin
  2577. if c=#10 then
  2578. preprocfile.eolfound:=true
  2579. else
  2580. preprocfile.spacefound:=true;
  2581. end;
  2582. {$endif PREPROCWRITE}
  2583. skipspace;
  2584. end
  2585. else
  2586. break;
  2587. end;
  2588. until false;
  2589. { Save current token position, for EOF its already loaded }
  2590. if c<>#26 then
  2591. gettokenpos;
  2592. { Check first for a identifier/keyword, this is 20+% faster (PFV) }
  2593. if c in ['A'..'Z','a'..'z','_'] then
  2594. begin
  2595. readstring;
  2596. token:=_ID;
  2597. idtoken:=_ID;
  2598. { keyword or any other known token,
  2599. pattern is always uppercased }
  2600. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  2601. begin
  2602. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  2603. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  2604. while low<high do
  2605. begin
  2606. mid:=(high+low+1) shr 1;
  2607. if pattern<tokeninfo^[ttoken(mid)].str then
  2608. high:=mid-1
  2609. else
  2610. low:=mid;
  2611. end;
  2612. with tokeninfo^[ttoken(high)] do
  2613. if pattern=str then
  2614. begin
  2615. if keyword in aktmodeswitches then
  2616. if op=NOTOKEN then
  2617. token:=ttoken(high)
  2618. else
  2619. token:=op;
  2620. idtoken:=ttoken(high);
  2621. end;
  2622. end;
  2623. { Only process identifiers and not keywords }
  2624. if token=_ID then
  2625. begin
  2626. { this takes some time ... }
  2627. if (cs_support_macro in aktmoduleswitches) then
  2628. begin
  2629. mac:=tmacro(search_macro(pattern));
  2630. if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
  2631. begin
  2632. if yylexcount<max_macro_nesting then
  2633. begin
  2634. mac.is_used:=true;
  2635. inc(yylexcount);
  2636. insertmacro(pattern,mac.buftext,mac.buflen,
  2637. mac.fileinfo.line,mac.fileinfo.fileindex);
  2638. { handle empty macros }
  2639. if c=#0 then
  2640. reload;
  2641. readtoken;
  2642. { that's all folks }
  2643. dec(yylexcount);
  2644. exit;
  2645. end
  2646. else
  2647. Message(scan_w_macro_too_deep);
  2648. end;
  2649. end;
  2650. end;
  2651. { return token }
  2652. goto exit_label;
  2653. end
  2654. else
  2655. begin
  2656. idtoken:=_NOID;
  2657. case c of
  2658. '$' :
  2659. begin
  2660. readnumber;
  2661. token:=_INTCONST;
  2662. goto exit_label;
  2663. end;
  2664. '%' :
  2665. begin
  2666. if not(m_fpc in aktmodeswitches) then
  2667. Illegal_Char(c)
  2668. else
  2669. begin
  2670. readnumber;
  2671. token:=_INTCONST;
  2672. goto exit_label;
  2673. end;
  2674. end;
  2675. '&' :
  2676. begin
  2677. if m_fpc in aktmodeswitches then
  2678. begin
  2679. readnumber;
  2680. token:=_INTCONST;
  2681. goto exit_label;
  2682. end
  2683. else if m_mac in aktmodeswitches then
  2684. begin
  2685. readchar;
  2686. token:=_AMPERSAND;
  2687. goto exit_label;
  2688. end
  2689. else
  2690. Illegal_Char(c);
  2691. end;
  2692. '0'..'9' :
  2693. begin
  2694. readnumber;
  2695. if (c in ['.','e','E']) then
  2696. begin
  2697. { first check for a . }
  2698. if c='.' then
  2699. begin
  2700. readchar;
  2701. { is it a .. from a range? }
  2702. case c of
  2703. '.' :
  2704. begin
  2705. readchar;
  2706. token:=_INTCONST;
  2707. nexttoken:=_POINTPOINT;
  2708. goto exit_label;
  2709. end;
  2710. ')' :
  2711. begin
  2712. readchar;
  2713. token:=_INTCONST;
  2714. nexttoken:=_RECKKLAMMER;
  2715. goto exit_label;
  2716. end;
  2717. end;
  2718. { insert the number after the . }
  2719. pattern:=pattern+'.';
  2720. while c in ['0'..'9'] do
  2721. begin
  2722. pattern:=pattern+c;
  2723. readchar;
  2724. end;
  2725. end;
  2726. { E can also follow after a point is scanned }
  2727. if c in ['e','E'] then
  2728. begin
  2729. pattern:=pattern+'E';
  2730. readchar;
  2731. if c in ['-','+'] then
  2732. begin
  2733. pattern:=pattern+c;
  2734. readchar;
  2735. end;
  2736. if not(c in ['0'..'9']) then
  2737. Illegal_Char(c);
  2738. while c in ['0'..'9'] do
  2739. begin
  2740. pattern:=pattern+c;
  2741. readchar;
  2742. end;
  2743. end;
  2744. token:=_REALNUMBER;
  2745. goto exit_label;
  2746. end;
  2747. token:=_INTCONST;
  2748. goto exit_label;
  2749. end;
  2750. ';' :
  2751. begin
  2752. readchar;
  2753. token:=_SEMICOLON;
  2754. goto exit_label;
  2755. end;
  2756. '[' :
  2757. begin
  2758. readchar;
  2759. token:=_LECKKLAMMER;
  2760. goto exit_label;
  2761. end;
  2762. ']' :
  2763. begin
  2764. readchar;
  2765. token:=_RECKKLAMMER;
  2766. goto exit_label;
  2767. end;
  2768. '(' :
  2769. begin
  2770. readchar;
  2771. case c of
  2772. '*' :
  2773. begin
  2774. c:=#0;{Signal skipoldtpcomment to reload a char }
  2775. skipoldtpcomment;
  2776. readtoken;
  2777. exit;
  2778. end;
  2779. '.' :
  2780. begin
  2781. readchar;
  2782. token:=_LECKKLAMMER;
  2783. goto exit_label;
  2784. end;
  2785. end;
  2786. token:=_LKLAMMER;
  2787. goto exit_label;
  2788. end;
  2789. ')' :
  2790. begin
  2791. readchar;
  2792. token:=_RKLAMMER;
  2793. goto exit_label;
  2794. end;
  2795. '+' :
  2796. begin
  2797. readchar;
  2798. if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
  2799. begin
  2800. readchar;
  2801. token:=_PLUSASN;
  2802. goto exit_label;
  2803. end;
  2804. token:=_PLUS;
  2805. goto exit_label;
  2806. end;
  2807. '-' :
  2808. begin
  2809. readchar;
  2810. if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
  2811. begin
  2812. readchar;
  2813. token:=_MINUSASN;
  2814. goto exit_label;
  2815. end;
  2816. token:=_MINUS;
  2817. goto exit_label;
  2818. end;
  2819. ':' :
  2820. begin
  2821. readchar;
  2822. if c='=' then
  2823. begin
  2824. readchar;
  2825. token:=_ASSIGNMENT;
  2826. goto exit_label;
  2827. end;
  2828. token:=_COLON;
  2829. goto exit_label;
  2830. end;
  2831. '*' :
  2832. begin
  2833. readchar;
  2834. if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
  2835. begin
  2836. readchar;
  2837. token:=_STARASN;
  2838. end
  2839. else
  2840. if c='*' then
  2841. begin
  2842. readchar;
  2843. token:=_STARSTAR;
  2844. end
  2845. else
  2846. token:=_STAR;
  2847. goto exit_label;
  2848. end;
  2849. '/' :
  2850. begin
  2851. readchar;
  2852. case c of
  2853. '=' :
  2854. begin
  2855. if (cs_support_c_operators in aktmoduleswitches) then
  2856. begin
  2857. readchar;
  2858. token:=_SLASHASN;
  2859. goto exit_label;
  2860. end;
  2861. end;
  2862. '/' :
  2863. begin
  2864. skipdelphicomment;
  2865. readtoken;
  2866. exit;
  2867. end;
  2868. end;
  2869. token:=_SLASH;
  2870. goto exit_label;
  2871. end;
  2872. '|' :
  2873. if m_mac in aktmodeswitches then
  2874. begin
  2875. readchar;
  2876. token:=_PIPE;
  2877. goto exit_label;
  2878. end
  2879. else
  2880. Illegal_Char(c);
  2881. '=' :
  2882. begin
  2883. readchar;
  2884. token:=_EQUAL;
  2885. goto exit_label;
  2886. end;
  2887. '.' :
  2888. begin
  2889. readchar;
  2890. case c of
  2891. '.' :
  2892. begin
  2893. readchar;
  2894. case c of
  2895. '.' :
  2896. begin
  2897. readchar;
  2898. token:=_POINTPOINTPOINT;
  2899. goto exit_label;
  2900. end;
  2901. else
  2902. begin
  2903. token:=_POINTPOINT;
  2904. goto exit_label;
  2905. end;
  2906. end;
  2907. end;
  2908. ')' :
  2909. begin
  2910. readchar;
  2911. token:=_RECKKLAMMER;
  2912. goto exit_label;
  2913. end;
  2914. end;
  2915. token:=_POINT;
  2916. goto exit_label;
  2917. end;
  2918. '@' :
  2919. begin
  2920. readchar;
  2921. token:=_KLAMMERAFFE;
  2922. goto exit_label;
  2923. end;
  2924. ',' :
  2925. begin
  2926. readchar;
  2927. token:=_COMMA;
  2928. goto exit_label;
  2929. end;
  2930. '''','#','^' :
  2931. begin
  2932. len:=0;
  2933. msgwritten:=false;
  2934. pattern:='';
  2935. iswidestring:=false;
  2936. if c='^' then
  2937. begin
  2938. readchar;
  2939. c:=upcase(c);
  2940. if (block_type=bt_type) or
  2941. (lasttoken=_ID) or (lasttoken=_NIL) or
  2942. (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
  2943. begin
  2944. token:=_CARET;
  2945. goto exit_label;
  2946. end
  2947. else
  2948. begin
  2949. inc(len);
  2950. if c<#64 then
  2951. pattern[len]:=chr(ord(c)+64)
  2952. else
  2953. pattern[len]:=chr(ord(c)-64);
  2954. readchar;
  2955. end;
  2956. end;
  2957. repeat
  2958. case c of
  2959. '#' :
  2960. begin
  2961. readchar; { read # }
  2962. if c='$' then
  2963. begin
  2964. readchar; { read leading $ }
  2965. asciinr:='$';
  2966. while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<6) do
  2967. begin
  2968. asciinr:=asciinr+c;
  2969. readchar;
  2970. end;
  2971. end
  2972. else
  2973. begin
  2974. asciinr:='';
  2975. while (c in ['0'..'9']) and (length(asciinr)<6) do
  2976. begin
  2977. asciinr:=asciinr+c;
  2978. readchar;
  2979. end;
  2980. end;
  2981. val(asciinr,m,code);
  2982. if (asciinr='') or (code<>0) then
  2983. Message(scan_e_illegal_char_const)
  2984. else if (m<0) or (m>255) or (length(asciinr)>3) then
  2985. begin
  2986. if (m>=0) and (m<=65535) then
  2987. begin
  2988. if not iswidestring then
  2989. begin
  2990. ascii2unicode(@pattern[1],len,patternw);
  2991. iswidestring:=true;
  2992. len:=0;
  2993. end;
  2994. concatwidestringchar(patternw,tcompilerwidechar(m));
  2995. end
  2996. else
  2997. Message(scan_e_illegal_char_const)
  2998. end
  2999. else if iswidestring then
  3000. concatwidestringchar(patternw,asciichar2unicode(char(m)))
  3001. else
  3002. begin
  3003. if len<255 then
  3004. begin
  3005. inc(len);
  3006. pattern[len]:=chr(m);
  3007. end
  3008. else
  3009. begin
  3010. if not msgwritten then
  3011. begin
  3012. Message(scan_e_string_exceeds_255_chars);
  3013. msgwritten:=true;
  3014. end;
  3015. end;
  3016. end;
  3017. end;
  3018. '''' :
  3019. begin
  3020. repeat
  3021. readchar;
  3022. case c of
  3023. #26 :
  3024. end_of_file;
  3025. #10,#13 :
  3026. Message(scan_f_string_exceeds_line);
  3027. '''' :
  3028. begin
  3029. readchar;
  3030. if c<>'''' then
  3031. break;
  3032. end;
  3033. end;
  3034. { interpret as utf-8 string? }
  3035. if (ord(c)>=$80) and (aktsourcecodepage='utf8') then
  3036. begin
  3037. { convert existing string to an utf-8 string }
  3038. if not iswidestring then
  3039. begin
  3040. ascii2unicode(@pattern[1],len,patternw);
  3041. iswidestring:=true;
  3042. len:=0;
  3043. end;
  3044. { four or more chars aren't handled }
  3045. if (ord(c) and $f0)=$f0 then
  3046. message(scan_e_utf8_bigger_than_65535)
  3047. { three chars }
  3048. else if (ord(c) and $e0)=$e0 then
  3049. begin
  3050. w:=ord(c) and $f;
  3051. readchar;
  3052. if (ord(c) and $c0)<>$80 then
  3053. message(scan_e_utf8_malformed);
  3054. w:=(w shl 6) or (ord(c) and $3f);
  3055. readchar;
  3056. if (ord(c) and $c0)<>$80 then
  3057. message(scan_e_utf8_malformed);
  3058. w:=(w shl 6) or (ord(c) and $3f);
  3059. concatwidestringchar(patternw,w);
  3060. end
  3061. { two chars }
  3062. else if (ord(c) and $c0)<>0 then
  3063. begin
  3064. w:=ord(c) and $1f;
  3065. readchar;
  3066. if (ord(c) and $c0)<>$80 then
  3067. message(scan_e_utf8_malformed);
  3068. w:=(w shl 6) or (ord(c) and $3f);
  3069. concatwidestringchar(patternw,w);
  3070. end
  3071. { illegal }
  3072. else if (ord(c) and $80)<>0 then
  3073. message(scan_e_utf8_malformed)
  3074. else
  3075. concatwidestringchar(patternw,tcompilerwidechar(c))
  3076. end
  3077. else if iswidestring then
  3078. begin
  3079. if aktsourcecodepage='utf8' then
  3080. concatwidestringchar(patternw,ord(c))
  3081. else
  3082. concatwidestringchar(patternw,asciichar2unicode(c))
  3083. end
  3084. else
  3085. begin
  3086. if len<255 then
  3087. begin
  3088. inc(len);
  3089. pattern[len]:=c;
  3090. end
  3091. else
  3092. begin
  3093. if not msgwritten then
  3094. begin
  3095. Message(scan_e_string_exceeds_255_chars);
  3096. msgwritten:=true;
  3097. end;
  3098. end;
  3099. end;
  3100. until false;
  3101. end;
  3102. '^' :
  3103. begin
  3104. readchar;
  3105. c:=upcase(c);
  3106. if c<#64 then
  3107. c:=chr(ord(c)+64)
  3108. else
  3109. c:=chr(ord(c)-64);
  3110. if iswidestring then
  3111. concatwidestringchar(patternw,asciichar2unicode(c))
  3112. else
  3113. begin
  3114. if len<255 then
  3115. begin
  3116. inc(len);
  3117. pattern[len]:=c;
  3118. end
  3119. else
  3120. begin
  3121. if not msgwritten then
  3122. begin
  3123. Message(scan_e_string_exceeds_255_chars);
  3124. msgwritten:=true;
  3125. end;
  3126. end;
  3127. end;
  3128. readchar;
  3129. end;
  3130. else
  3131. break;
  3132. end;
  3133. until false;
  3134. { strings with length 1 become const chars }
  3135. if iswidestring then
  3136. begin
  3137. if patternw^.len=1 then
  3138. token:=_CWCHAR
  3139. else
  3140. token:=_CWSTRING;
  3141. end
  3142. else
  3143. begin
  3144. pattern[0]:=chr(len);
  3145. if len=1 then
  3146. token:=_CCHAR
  3147. else
  3148. token:=_CSTRING;
  3149. end;
  3150. goto exit_label;
  3151. end;
  3152. '>' :
  3153. begin
  3154. readchar;
  3155. case c of
  3156. '=' :
  3157. begin
  3158. readchar;
  3159. token:=_GTE;
  3160. goto exit_label;
  3161. end;
  3162. '>' :
  3163. begin
  3164. readchar;
  3165. token:=_OP_SHR;
  3166. goto exit_label;
  3167. end;
  3168. '<' :
  3169. begin { >< is for a symetric diff for sets }
  3170. readchar;
  3171. token:=_SYMDIF;
  3172. goto exit_label;
  3173. end;
  3174. end;
  3175. token:=_GT;
  3176. goto exit_label;
  3177. end;
  3178. '<' :
  3179. begin
  3180. readchar;
  3181. case c of
  3182. '>' :
  3183. begin
  3184. readchar;
  3185. token:=_UNEQUAL;
  3186. goto exit_label;
  3187. end;
  3188. '=' :
  3189. begin
  3190. readchar;
  3191. token:=_LTE;
  3192. goto exit_label;
  3193. end;
  3194. '<' :
  3195. begin
  3196. readchar;
  3197. token:=_OP_SHL;
  3198. goto exit_label;
  3199. end;
  3200. end;
  3201. token:=_LT;
  3202. goto exit_label;
  3203. end;
  3204. #26 :
  3205. begin
  3206. token:=_EOF;
  3207. checkpreprocstack;
  3208. goto exit_label;
  3209. end;
  3210. else
  3211. Illegal_Char(c);
  3212. end;
  3213. end;
  3214. exit_label:
  3215. lasttoken:=token;
  3216. end;
  3217. function tscannerfile.readpreproc:ttoken;
  3218. begin
  3219. skipspace;
  3220. case c of
  3221. '_',
  3222. 'A'..'Z',
  3223. 'a'..'z' :
  3224. begin
  3225. current_scanner.preproc_pattern:=readid;
  3226. readpreproc:=_ID;
  3227. end;
  3228. '0'..'9' :
  3229. begin
  3230. current_scanner.preproc_pattern:=readval_asstring;
  3231. { realnumber? }
  3232. if c='.' then
  3233. begin
  3234. readchar;
  3235. while c in ['0'..'9'] do
  3236. begin
  3237. current_scanner.preproc_pattern:=current_scanner.preproc_pattern+c;
  3238. readchar;
  3239. end;
  3240. end;
  3241. readpreproc:=_ID;
  3242. end;
  3243. '$','%','&' :
  3244. begin
  3245. current_scanner.preproc_pattern:=readval_asstring;
  3246. readpreproc:=_ID;
  3247. end;
  3248. ',' :
  3249. begin
  3250. readchar;
  3251. readpreproc:=_COMMA;
  3252. end;
  3253. '}' :
  3254. begin
  3255. readpreproc:=_END;
  3256. end;
  3257. '(' :
  3258. begin
  3259. readchar;
  3260. readpreproc:=_LKLAMMER;
  3261. end;
  3262. ')' :
  3263. begin
  3264. readchar;
  3265. readpreproc:=_RKLAMMER;
  3266. end;
  3267. '[' :
  3268. begin
  3269. readchar;
  3270. readpreproc:=_LECKKLAMMER;
  3271. end;
  3272. ']' :
  3273. begin
  3274. readchar;
  3275. readpreproc:=_RECKKLAMMER;
  3276. end;
  3277. '+' :
  3278. begin
  3279. readchar;
  3280. readpreproc:=_PLUS;
  3281. end;
  3282. '-' :
  3283. begin
  3284. readchar;
  3285. readpreproc:=_MINUS;
  3286. end;
  3287. '*' :
  3288. begin
  3289. readchar;
  3290. readpreproc:=_STAR;
  3291. end;
  3292. '/' :
  3293. begin
  3294. readchar;
  3295. readpreproc:=_SLASH;
  3296. end;
  3297. '=' :
  3298. begin
  3299. readchar;
  3300. readpreproc:=_EQUAL;
  3301. end;
  3302. '>' :
  3303. begin
  3304. readchar;
  3305. if c='=' then
  3306. begin
  3307. readchar;
  3308. readpreproc:=_GTE;
  3309. end
  3310. else
  3311. readpreproc:=_GT;
  3312. end;
  3313. '<' :
  3314. begin
  3315. readchar;
  3316. case c of
  3317. '>' :
  3318. begin
  3319. readchar;
  3320. readpreproc:=_UNEQUAL;
  3321. end;
  3322. '=' :
  3323. begin
  3324. readchar;
  3325. readpreproc:=_LTE;
  3326. end;
  3327. else
  3328. readpreproc:=_LT;
  3329. end;
  3330. end;
  3331. #26 :
  3332. begin
  3333. readpreproc:=_EOF;
  3334. checkpreprocstack;
  3335. end;
  3336. else
  3337. Illegal_Char(c);
  3338. end;
  3339. end;
  3340. function tscannerfile.asmgetcharstart : char;
  3341. begin
  3342. { return first the character already
  3343. available in c }
  3344. lastasmgetchar:=c;
  3345. result:=asmgetchar;
  3346. end;
  3347. function tscannerfile.asmgetchar : char;
  3348. begin
  3349. if lastasmgetchar<>#0 then
  3350. begin
  3351. c:=lastasmgetchar;
  3352. lastasmgetchar:=#0;
  3353. end
  3354. else
  3355. readchar;
  3356. if in_asm_string then
  3357. begin
  3358. asmgetchar:=c;
  3359. exit;
  3360. end;
  3361. repeat
  3362. case c of
  3363. {$ifndef arm}
  3364. // the { ... } is used in ARM assembler to define register sets, so we can't used
  3365. // it as comment, either (* ... *), /* ... */ or // ... should be used instead
  3366. '{' :
  3367. skipcomment;
  3368. {$endif arm}
  3369. #10,#13 :
  3370. begin
  3371. linebreak;
  3372. asmgetchar:=c;
  3373. exit;
  3374. end;
  3375. #26 :
  3376. begin
  3377. reload;
  3378. if (c=#26) and not assigned(inputfile.next) then
  3379. end_of_file;
  3380. continue;
  3381. end;
  3382. '/' :
  3383. begin
  3384. readchar;
  3385. if c='/' then
  3386. skipdelphicomment
  3387. else
  3388. begin
  3389. asmgetchar:='/';
  3390. lastasmgetchar:=c;
  3391. exit;
  3392. end;
  3393. end;
  3394. '(' :
  3395. begin
  3396. readchar;
  3397. if c='*' then
  3398. begin
  3399. c:=#0;{Signal skipoldtpcomment to reload a char }
  3400. skipoldtpcomment;
  3401. end
  3402. else
  3403. begin
  3404. asmgetchar:='(';
  3405. lastasmgetchar:=c;
  3406. exit;
  3407. end;
  3408. end;
  3409. else
  3410. begin
  3411. asmgetchar:=c;
  3412. exit;
  3413. end;
  3414. end;
  3415. until false;
  3416. end;
  3417. {*****************************************************************************
  3418. Helpers
  3419. *****************************************************************************}
  3420. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  3421. begin
  3422. if dm in [directive_all, directive_turbo] then
  3423. turbo_scannerdirectives.insert(tdirectiveitem.create(s,p));
  3424. if dm in [directive_all, directive_mac] then
  3425. mac_scannerdirectives.insert(tdirectiveitem.create(s,p));
  3426. end;
  3427. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  3428. begin
  3429. if dm in [directive_all, directive_turbo] then
  3430. turbo_scannerdirectives.insert(tdirectiveitem.createcond(s,p));
  3431. if dm in [directive_all, directive_mac] then
  3432. mac_scannerdirectives.insert(tdirectiveitem.createcond(s,p));
  3433. end;
  3434. {*****************************************************************************
  3435. Initialization
  3436. *****************************************************************************}
  3437. procedure InitScanner;
  3438. begin
  3439. InitWideString(patternw);
  3440. turbo_scannerdirectives:=TDictionary.Create;
  3441. mac_scannerdirectives:=TDictionary.Create;
  3442. { Common directives and conditionals }
  3443. AddDirective('I',directive_all, @dir_include);
  3444. AddDirective('DEFINE',directive_all, @dir_define);
  3445. AddDirective('UNDEF',directive_all, @dir_undef);
  3446. AddConditional('IF',directive_all, @dir_if);
  3447. AddConditional('IFDEF',directive_all, @dir_ifdef);
  3448. AddConditional('IFNDEF',directive_all, @dir_ifndef);
  3449. AddConditional('ELSE',directive_all, @dir_else);
  3450. AddConditional('ELSEIF',directive_all, @dir_elseif);
  3451. AddConditional('ENDIF',directive_all, @dir_endif);
  3452. { Directives and conditionals for all modes except mode macpas}
  3453. AddDirective('INCLUDE',directive_turbo, @dir_include);
  3454. AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
  3455. AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
  3456. AddDirective('EXTENSION',directive_turbo, @dir_extension);
  3457. AddConditional('IFEND',directive_turbo, @dir_endif);
  3458. AddConditional('IFOPT',directive_turbo, @dir_ifopt);
  3459. { Directives and conditionals for mode macpas: }
  3460. AddDirective('SETC',directive_mac, @dir_setc);
  3461. AddDirective('DEFINEC',directive_mac, @dir_definec);
  3462. AddDirective('UNDEFC',directive_mac, @dir_undef);
  3463. AddConditional('IFC',directive_mac, @dir_if);
  3464. AddConditional('ELSEC',directive_mac, @dir_else);
  3465. AddConditional('ELIFC',directive_mac, @dir_elseif);
  3466. AddConditional('ENDC',directive_mac, @dir_endif);
  3467. end;
  3468. procedure DoneScanner;
  3469. begin
  3470. turbo_scannerdirectives.Free;
  3471. mac_scannerdirectives.Free;
  3472. DoneWideString(patternw);
  3473. end;
  3474. end.