scanner.pas 117 KB

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