scanner.pas 127 KB

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