scanner.pas 141 KB

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