scanner.pas 122 KB

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