scanner.pas 106 KB

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