scanner.pas 118 KB

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