scanner.pas 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457
  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. If path was specified as part of {$I } then
  973. 1. specified path (expanded with path of inputfile if relative)
  974. else
  975. 1. path of current inputfile,current dir
  976. 2. local includepath
  977. 3. global includepath }
  978. found:=false;
  979. foundfile:='';
  980. hpath:='';
  981. if path<>'' then
  982. begin
  983. if not path_absolute(path) then
  984. hpath:=current_scanner.inputfile.path^+path
  985. else
  986. hpath:=path;
  987. found:=FindFile(name+ext, hpath,foundfile);
  988. end
  989. else
  990. begin
  991. hpath:=current_scanner.inputfile.path^+';'+CurDirRelPath(source_info);
  992. found:=FindFile(name+ext, hpath,foundfile);
  993. if not found then
  994. found:=current_module.localincludesearchpath.FindFile(name+ext,foundfile);
  995. if not found then
  996. found:=includesearchpath.FindFile(name+ext,foundfile);
  997. end;
  998. findincludefile:=found;
  999. end;
  1000. var
  1001. args,
  1002. foundfile,
  1003. hs : string;
  1004. path : dirstr;
  1005. name : namestr;
  1006. ext : extstr;
  1007. hp : tinputfile;
  1008. found : boolean;
  1009. begin
  1010. current_scanner.skipspace;
  1011. args:=current_scanner.readcomment;
  1012. hs:=GetToken(args,' ');
  1013. if hs='' then
  1014. exit;
  1015. if (hs[1]='%') then
  1016. begin
  1017. { case insensitive }
  1018. hs:=upper(hs);
  1019. { remove %'s }
  1020. Delete(hs,1,1);
  1021. if hs[length(hs)]='%' then
  1022. Delete(hs,length(hs),1);
  1023. { save old }
  1024. path:=hs;
  1025. { first check for internal macros }
  1026. if hs='TIME' then
  1027. hs:=gettimestr
  1028. else
  1029. if hs='DATE' then
  1030. hs:=getdatestr
  1031. else
  1032. if hs='FILE' then
  1033. hs:=current_module.sourcefiles.get_file_name(aktfilepos.fileindex)
  1034. else
  1035. if hs='LINE' then
  1036. hs:=tostr(aktfilepos.line)
  1037. else
  1038. if hs='FPCVERSION' then
  1039. hs:=version_string
  1040. else
  1041. if hs='FPCTARGET' then
  1042. hs:=target_cpu_string
  1043. else
  1044. if hs='FPCTARGETCPU' then
  1045. hs:=target_cpu_string
  1046. else
  1047. if hs='FPCTARGETOS' then
  1048. hs:=target_info.shortname
  1049. else
  1050. hs:=getenv(hs);
  1051. if hs='' then
  1052. Message1(scan_w_include_env_not_found,path);
  1053. { make it a stringconst }
  1054. hs:=''''+hs+'''';
  1055. current_scanner.insertmacro(path,@hs[1],length(hs),
  1056. current_scanner.line_no,current_scanner.inputfile.ref_index);
  1057. end
  1058. else
  1059. begin
  1060. hs:=FixFileName(hs);
  1061. fsplit(hs,path,name,ext);
  1062. { try to find the file }
  1063. found:=findincludefile(path,name,ext,foundfile);
  1064. if (ext='') then
  1065. begin
  1066. { try default extensions .inc , .pp and .pas }
  1067. if (not found) then
  1068. found:=findincludefile(path,name,'.inc',foundfile);
  1069. if (not found) then
  1070. found:=findincludefile(path,name,sourceext,foundfile);
  1071. if (not found) then
  1072. found:=findincludefile(path,name,pasext,foundfile);
  1073. end;
  1074. if current_scanner.inputfilecount<max_include_nesting then
  1075. begin
  1076. inc(current_scanner.inputfilecount);
  1077. { we need to reread the current char }
  1078. dec(current_scanner.inputpointer);
  1079. { shutdown current file }
  1080. current_scanner.tempcloseinputfile;
  1081. { load new file }
  1082. hp:=do_openinputfile(foundfile);
  1083. current_scanner.addfile(hp);
  1084. current_module.sourcefiles.register_file(hp);
  1085. if (not found) then
  1086. Message1(scan_f_cannot_open_includefile,hs);
  1087. if (not current_scanner.openinputfile) then
  1088. Message1(scan_f_cannot_open_includefile,hs);
  1089. Message1(scan_t_start_include_file,current_scanner.inputfile.path^+current_scanner.inputfile.name^);
  1090. current_scanner.reload;
  1091. end
  1092. else
  1093. Message(scan_f_include_deep_ten);
  1094. end;
  1095. end;
  1096. {*****************************************************************************
  1097. Preprocessor writting
  1098. *****************************************************************************}
  1099. {$ifdef PREPROCWRITE}
  1100. constructor tpreprocfile.create(const fn:string);
  1101. begin
  1102. { open outputfile }
  1103. assign(f,fn);
  1104. {$I-}
  1105. rewrite(f);
  1106. {$I+}
  1107. if ioresult<>0 then
  1108. Comment(V_Fatal,'can''t create file '+fn);
  1109. getmem(buf,preprocbufsize);
  1110. settextbuf(f,buf^,preprocbufsize);
  1111. { reset }
  1112. eolfound:=false;
  1113. spacefound:=false;
  1114. end;
  1115. destructor tpreprocfile.destroy;
  1116. begin
  1117. close(f);
  1118. freemem(buf,preprocbufsize);
  1119. end;
  1120. procedure tpreprocfile.add(const s:string);
  1121. begin
  1122. write(f,s);
  1123. end;
  1124. procedure tpreprocfile.addspace;
  1125. begin
  1126. if eolfound then
  1127. begin
  1128. writeln(f,'');
  1129. eolfound:=false;
  1130. spacefound:=false;
  1131. end
  1132. else
  1133. if spacefound then
  1134. begin
  1135. write(f,' ');
  1136. spacefound:=false;
  1137. end;
  1138. end;
  1139. {$endif PREPROCWRITE}
  1140. {*****************************************************************************
  1141. TPreProcStack
  1142. *****************************************************************************}
  1143. constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
  1144. begin
  1145. accept:=a;
  1146. typ:=atyp;
  1147. next:=n;
  1148. end;
  1149. {*****************************************************************************
  1150. TDirectiveItem
  1151. *****************************************************************************}
  1152. constructor TDirectiveItem.Create(const n:string;p:tdirectiveproc);
  1153. begin
  1154. inherited CreateName(n);
  1155. is_conditional:=false;
  1156. proc:=p;
  1157. end;
  1158. constructor TDirectiveItem.CreateCond(const n:string;p:tdirectiveproc);
  1159. begin
  1160. inherited CreateName(n);
  1161. is_conditional:=true;
  1162. proc:=p;
  1163. end;
  1164. {****************************************************************************
  1165. TSCANNERFILE
  1166. ****************************************************************************}
  1167. constructor tscannerfile.create(const fn:string);
  1168. begin
  1169. inputfile:=do_openinputfile(fn);
  1170. if assigned(current_module) then
  1171. current_module.sourcefiles.register_file(inputfile);
  1172. { reset localinput }
  1173. inputbuffer:=nil;
  1174. inputpointer:=nil;
  1175. inputstart:=0;
  1176. { reset scanner }
  1177. preprocstack:=nil;
  1178. comment_level:=0;
  1179. yylexcount:=0;
  1180. block_type:=bt_general;
  1181. line_no:=0;
  1182. lastlinepos:=0;
  1183. lasttokenpos:=0;
  1184. lasttoken:=NOTOKEN;
  1185. nexttoken:=NOTOKEN;
  1186. lastasmgetchar:=#0;
  1187. ignoredirectives:=TStringList.Create;
  1188. in_asm_string:=false;
  1189. end;
  1190. procedure tscannerfile.firstfile;
  1191. begin
  1192. { load block }
  1193. if not openinputfile then
  1194. Message1(scan_f_cannot_open_input,inputfile.name^);
  1195. reload;
  1196. end;
  1197. destructor tscannerfile.destroy;
  1198. begin
  1199. if assigned(current_module) and
  1200. (current_module.state=ms_compiled) and
  1201. (status.errorcount=0) then
  1202. checkpreprocstack
  1203. else
  1204. begin
  1205. while assigned(preprocstack) do
  1206. poppreprocstack;
  1207. end;
  1208. if not inputfile.closed then
  1209. closeinputfile;
  1210. ignoredirectives.free;
  1211. end;
  1212. function tscannerfile.openinputfile:boolean;
  1213. begin
  1214. openinputfile:=inputfile.open;
  1215. { load buffer }
  1216. inputbuffer:=inputfile.buf;
  1217. inputpointer:=inputfile.buf;
  1218. inputstart:=inputfile.bufstart;
  1219. { line }
  1220. line_no:=0;
  1221. lastlinepos:=0;
  1222. lasttokenpos:=0;
  1223. end;
  1224. procedure tscannerfile.closeinputfile;
  1225. begin
  1226. inputfile.close;
  1227. { reset buffer }
  1228. inputbuffer:=nil;
  1229. inputpointer:=nil;
  1230. inputstart:=0;
  1231. { reset line }
  1232. line_no:=0;
  1233. lastlinepos:=0;
  1234. lasttokenpos:=0;
  1235. end;
  1236. function tscannerfile.tempopeninputfile:boolean;
  1237. begin
  1238. if inputfile.is_macro then
  1239. exit;
  1240. tempopeninputfile:=inputfile.tempopen;
  1241. { reload buffer }
  1242. inputbuffer:=inputfile.buf;
  1243. inputpointer:=inputfile.buf;
  1244. inputstart:=inputfile.bufstart;
  1245. end;
  1246. procedure tscannerfile.tempcloseinputfile;
  1247. begin
  1248. if inputfile.closed or inputfile.is_macro then
  1249. exit;
  1250. inputfile.setpos(inputstart+(inputpointer-inputbuffer));
  1251. inputfile.tempclose;
  1252. { reset buffer }
  1253. inputbuffer:=nil;
  1254. inputpointer:=nil;
  1255. inputstart:=0;
  1256. end;
  1257. procedure tscannerfile.saveinputfile;
  1258. begin
  1259. inputfile.saveinputpointer:=inputpointer;
  1260. inputfile.savelastlinepos:=lastlinepos;
  1261. inputfile.saveline_no:=line_no;
  1262. end;
  1263. procedure tscannerfile.restoreinputfile;
  1264. begin
  1265. inputpointer:=inputfile.saveinputpointer;
  1266. lastlinepos:=inputfile.savelastlinepos;
  1267. line_no:=inputfile.saveline_no;
  1268. if not inputfile.is_macro then
  1269. parser_current_file:=inputfile.name^;
  1270. end;
  1271. procedure tscannerfile.nextfile;
  1272. var
  1273. to_dispose : tinputfile;
  1274. begin
  1275. if assigned(inputfile.next) then
  1276. begin
  1277. if inputfile.is_macro then
  1278. to_dispose:=inputfile
  1279. else
  1280. begin
  1281. to_dispose:=nil;
  1282. dec(inputfilecount);
  1283. end;
  1284. { we can allways close the file, no ? }
  1285. inputfile.close;
  1286. inputfile:=inputfile.next;
  1287. if assigned(to_dispose) then
  1288. to_dispose.free;
  1289. restoreinputfile;
  1290. end;
  1291. end;
  1292. procedure tscannerfile.addfile(hp:tinputfile);
  1293. begin
  1294. saveinputfile;
  1295. { add to list }
  1296. hp.next:=inputfile;
  1297. inputfile:=hp;
  1298. { load new inputfile }
  1299. restoreinputfile;
  1300. end;
  1301. procedure tscannerfile.reload;
  1302. begin
  1303. with inputfile do
  1304. begin
  1305. { when nothing more to read then leave immediatly, so we
  1306. don't change the aktfilepos and leave it point to the last
  1307. char }
  1308. if (c=#26) and (not assigned(next)) then
  1309. exit;
  1310. repeat
  1311. { still more to read?, then change the #0 to a space so its seen
  1312. as a seperator, this can't be used for macro's which can change
  1313. the place of the #0 in the buffer with tempopen }
  1314. if (c=#0) and (bufsize>0) and
  1315. not(inputfile.is_macro) and
  1316. (inputpointer-inputbuffer<bufsize) then
  1317. begin
  1318. c:=' ';
  1319. inc(inputpointer);
  1320. exit;
  1321. end;
  1322. { can we read more from this file ? }
  1323. if (c<>#26) and (not endoffile) then
  1324. begin
  1325. readbuf;
  1326. inputpointer:=buf;
  1327. inputbuffer:=buf;
  1328. inputstart:=bufstart;
  1329. { first line? }
  1330. if line_no=0 then
  1331. begin
  1332. c:=inputpointer^;
  1333. { eat utf-8 signature? }
  1334. if (ord(inputpointer^)=$ef) and
  1335. (ord((inputpointer+1)^)=$bb) and
  1336. (ord((inputpointer+2)^)=$bf) then
  1337. begin
  1338. inc(inputpointer,3);
  1339. message(scan_c_switching_to_utf8);
  1340. aktsourcecodepage:='utf8';
  1341. end;
  1342. line_no:=1;
  1343. if cs_asm_source in aktglobalswitches then
  1344. inputfile.setline(line_no,bufstart);
  1345. end;
  1346. end
  1347. else
  1348. begin
  1349. { load eof position in tokenpos/aktfilepos }
  1350. gettokenpos;
  1351. { close file }
  1352. closeinputfile;
  1353. { no next module, than EOF }
  1354. if not assigned(inputfile.next) then
  1355. begin
  1356. c:=#26;
  1357. exit;
  1358. end;
  1359. { load next file and reopen it }
  1360. nextfile;
  1361. tempopeninputfile;
  1362. { status }
  1363. Message1(scan_t_back_in,inputfile.name^);
  1364. end;
  1365. { load next char }
  1366. c:=inputpointer^;
  1367. inc(inputpointer);
  1368. until c<>#0; { if also end, then reload again }
  1369. end;
  1370. end;
  1371. procedure tscannerfile.insertmacro(const macname:string;p:pchar;len,line,fileindex:longint);
  1372. var
  1373. hp : tinputfile;
  1374. begin
  1375. { save old postion }
  1376. dec(inputpointer);
  1377. tempcloseinputfile;
  1378. { create macro 'file' }
  1379. { use special name to dispose after !! }
  1380. hp:=do_openinputfile('_Macro_.'+macname);
  1381. addfile(hp);
  1382. with inputfile do
  1383. begin
  1384. setmacro(p,len);
  1385. { local buffer }
  1386. inputbuffer:=buf;
  1387. inputpointer:=buf;
  1388. inputstart:=bufstart;
  1389. ref_index:=fileindex;
  1390. end;
  1391. { reset line }
  1392. line_no:=line;
  1393. lastlinepos:=0;
  1394. lasttokenpos:=0;
  1395. { load new c }
  1396. c:=inputpointer^;
  1397. inc(inputpointer);
  1398. end;
  1399. procedure tscannerfile.gettokenpos;
  1400. { load the values of tokenpos and lasttokenpos }
  1401. begin
  1402. lasttokenpos:=inputstart+(inputpointer-inputbuffer);
  1403. akttokenpos.line:=line_no;
  1404. akttokenpos.column:=lasttokenpos-lastlinepos;
  1405. akttokenpos.fileindex:=inputfile.ref_index;
  1406. aktfilepos:=akttokenpos;
  1407. end;
  1408. procedure tscannerfile.inc_comment_level;
  1409. var
  1410. oldaktfilepos : tfileposinfo;
  1411. begin
  1412. if (m_nested_comment in aktmodeswitches) then
  1413. inc(comment_level)
  1414. else
  1415. comment_level:=1;
  1416. if (comment_level>1) then
  1417. begin
  1418. oldaktfilepos:=aktfilepos;
  1419. gettokenpos; { update for warning }
  1420. Message1(scan_w_comment_level,tostr(comment_level));
  1421. aktfilepos:=oldaktfilepos;
  1422. end;
  1423. end;
  1424. procedure tscannerfile.dec_comment_level;
  1425. begin
  1426. if (m_nested_comment in aktmodeswitches) then
  1427. dec(comment_level)
  1428. else
  1429. comment_level:=0;
  1430. end;
  1431. procedure tscannerfile.linebreak;
  1432. var
  1433. cur : char;
  1434. oldtokenpos,
  1435. oldaktfilepos : tfileposinfo;
  1436. begin
  1437. with inputfile do
  1438. begin
  1439. if (byte(inputpointer^)=0) and not(endoffile) then
  1440. begin
  1441. cur:=c;
  1442. reload;
  1443. if byte(cur)+byte(c)<>23 then
  1444. dec(inputpointer);
  1445. end
  1446. else
  1447. begin
  1448. { Support all combination of #10 and #13 as line break }
  1449. if (byte(inputpointer^)+byte(c)=23) then
  1450. inc(inputpointer);
  1451. end;
  1452. { Always return #10 as line break }
  1453. c:=#10;
  1454. { increase line counters }
  1455. lastlinepos:=bufstart+(inputpointer-inputbuffer);
  1456. inc(line_no);
  1457. { update linebuffer }
  1458. if cs_asm_source in aktglobalswitches then
  1459. inputfile.setline(line_no,lastlinepos);
  1460. { update for status and call the show status routine,
  1461. but don't touch aktfilepos ! }
  1462. oldaktfilepos:=aktfilepos;
  1463. oldtokenpos:=akttokenpos;
  1464. gettokenpos; { update for v_status }
  1465. inc(status.compiledlines);
  1466. ShowStatus;
  1467. aktfilepos:=oldaktfilepos;
  1468. akttokenpos:=oldtokenpos;
  1469. end;
  1470. end;
  1471. procedure tscannerfile.illegal_char(c:char);
  1472. var
  1473. s : string;
  1474. begin
  1475. if c in [#32..#255] then
  1476. s:=''''+c+''''
  1477. else
  1478. s:='#'+tostr(ord(c));
  1479. Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
  1480. end;
  1481. procedure tscannerfile.end_of_file;
  1482. begin
  1483. checkpreprocstack;
  1484. Message(scan_f_end_of_file);
  1485. end;
  1486. {-------------------------------------------
  1487. IF Conditional Handling
  1488. -------------------------------------------}
  1489. procedure tscannerfile.checkpreprocstack;
  1490. begin
  1491. { check for missing ifdefs }
  1492. while assigned(preprocstack) do
  1493. begin
  1494. Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
  1495. preprocstack.owner.inputfile.name^,tostr(preprocstack.line_nb));
  1496. poppreprocstack;
  1497. end;
  1498. end;
  1499. procedure tscannerfile.poppreprocstack;
  1500. var
  1501. hp : tpreprocstack;
  1502. begin
  1503. if assigned(preprocstack) then
  1504. begin
  1505. Message1(scan_c_endif_found,preprocstack.name);
  1506. hp:=preprocstack.next;
  1507. preprocstack.free;
  1508. preprocstack:=hp;
  1509. end
  1510. else
  1511. Message(scan_e_endif_without_if);
  1512. end;
  1513. procedure tscannerfile.ifpreprocstack(atyp : preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  1514. var
  1515. condition: Boolean;
  1516. valuedescr: String;
  1517. begin
  1518. if (preprocstack=nil) or preprocstack.accept then
  1519. condition:= compile_time_predicate(valuedescr)
  1520. else
  1521. begin
  1522. condition:= false;
  1523. valuedescr:= '';
  1524. end;
  1525. preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
  1526. preprocstack.name:=valuedescr;
  1527. preprocstack.line_nb:=line_no;
  1528. preprocstack.owner:=self;
  1529. if preprocstack.accept then
  1530. Message2(messid,preprocstack.name,'accepted')
  1531. else
  1532. Message2(messid,preprocstack.name,'rejected');
  1533. end;
  1534. procedure tscannerfile.elsepreprocstack;
  1535. var
  1536. valuedescr: String;
  1537. begin
  1538. if assigned(preprocstack) and
  1539. (preprocstack.typ<>pp_else) then
  1540. begin
  1541. if (preprocstack.typ=pp_elseif) then
  1542. preprocstack.accept:=false
  1543. else
  1544. if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
  1545. preprocstack.accept:=not preprocstack.accept;
  1546. preprocstack.typ:=pp_else;
  1547. preprocstack.line_nb:=line_no;
  1548. if preprocstack.accept then
  1549. Message2(scan_c_else_found,preprocstack.name,'accepted')
  1550. else
  1551. Message2(scan_c_else_found,preprocstack.name,'rejected');
  1552. end
  1553. else
  1554. Message(scan_e_endif_without_if);
  1555. end;
  1556. procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  1557. var
  1558. valuedescr: String;
  1559. begin
  1560. if assigned(preprocstack) and
  1561. (preprocstack.typ in [pp_if,pp_elseif]) then
  1562. begin
  1563. { when the branch is accepted we use pp_elseif so we know that
  1564. all the next branches need to be rejected. when this branch is still
  1565. not accepted then leave it at pp_if }
  1566. if (preprocstack.typ=pp_elseif) then
  1567. preprocstack.accept:=false
  1568. else if (preprocstack.typ=pp_if) and preprocstack.accept then
  1569. begin
  1570. preprocstack.accept:=false;
  1571. preprocstack.typ:=pp_elseif;
  1572. end
  1573. else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
  1574. and compile_time_predicate(valuedescr) then
  1575. begin
  1576. preprocstack.name:=valuedescr;
  1577. preprocstack.accept:=true;
  1578. preprocstack.typ:=pp_elseif;
  1579. end;
  1580. preprocstack.line_nb:=line_no;
  1581. if preprocstack.accept then
  1582. Message2(scan_c_else_found,preprocstack.name,'accepted')
  1583. else
  1584. Message2(scan_c_else_found,preprocstack.name,'rejected');
  1585. end
  1586. else
  1587. Message(scan_e_endif_without_if);
  1588. end;
  1589. procedure tscannerfile.handleconditional(p:tdirectiveitem);
  1590. var
  1591. oldaktfilepos : tfileposinfo;
  1592. begin
  1593. oldaktfilepos:=aktfilepos;
  1594. repeat
  1595. current_scanner.gettokenpos;
  1596. p.proc();
  1597. { accept the text ? }
  1598. if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
  1599. break
  1600. else
  1601. begin
  1602. current_scanner.gettokenpos;
  1603. Message(scan_c_skipping_until);
  1604. repeat
  1605. current_scanner.skipuntildirective;
  1606. if not (m_mac in aktmodeswitches) then
  1607. p:=tdirectiveitem(turbo_scannerdirectives.search(current_scanner.readid))
  1608. else
  1609. p:=tdirectiveitem(mac_scannerdirectives.search(current_scanner.readid));
  1610. until assigned(p) and (p.is_conditional);
  1611. current_scanner.gettokenpos;
  1612. Message1(scan_d_handling_switch,'$'+p.name);
  1613. end;
  1614. until false;
  1615. aktfilepos:=oldaktfilepos;
  1616. end;
  1617. procedure tscannerfile.handledirectives;
  1618. var
  1619. t : tdirectiveitem;
  1620. hs : string;
  1621. begin
  1622. gettokenpos;
  1623. readchar; {Remove the $}
  1624. hs:=readid;
  1625. {$ifdef PREPROCWRITE}
  1626. if parapreprocess then
  1627. begin
  1628. t:=Get_Directive(hs);
  1629. if not(is_conditional(t) or (t=_DIR_DEFINE) or (t=_DIR_UNDEF)) then
  1630. begin
  1631. preprocfile^.AddSpace;
  1632. preprocfile^.Add('{$'+hs+current_scanner.readcomment+'}');
  1633. exit;
  1634. end;
  1635. end;
  1636. {$endif PREPROCWRITE}
  1637. { skip this directive? }
  1638. if (ignoredirectives.find(hs)<>nil) then
  1639. begin
  1640. if (comment_level>0) then
  1641. readcomment;
  1642. { we've read the whole comment }
  1643. aktcommentstyle:=comment_none;
  1644. exit;
  1645. end;
  1646. if hs='' then
  1647. begin
  1648. Message1(scan_w_illegal_switch,'$'+hs);
  1649. end;
  1650. { Check for compiler switches }
  1651. while (length(hs)=1) and (c in ['-','+']) do
  1652. begin
  1653. HandleSwitch(hs[1],c);
  1654. current_scanner.readchar; {Remove + or -}
  1655. if c=',' then
  1656. begin
  1657. current_scanner.readchar; {Remove , }
  1658. { read next switch, support $v+,$+}
  1659. hs:=current_scanner.readid;
  1660. if (hs='') then
  1661. begin
  1662. if (c='$') and (m_fpc in aktmodeswitches) then
  1663. begin
  1664. current_scanner.readchar; { skip $ }
  1665. hs:=current_scanner.readid;
  1666. end;
  1667. if (hs='') then
  1668. Message1(scan_w_illegal_directive,'$'+c);
  1669. end
  1670. else
  1671. Message1(scan_d_handling_switch,'$'+hs);
  1672. end
  1673. else
  1674. hs:='';
  1675. end;
  1676. { directives may follow switches after a , }
  1677. if hs<>'' then
  1678. begin
  1679. if not (m_mac in aktmodeswitches) then
  1680. t:=tdirectiveitem(turbo_scannerdirectives.search(hs))
  1681. else
  1682. t:=tdirectiveitem(mac_scannerdirectives.search(hs));
  1683. if assigned(t) then
  1684. begin
  1685. if t.is_conditional then
  1686. handleconditional(t)
  1687. else
  1688. begin
  1689. Message1(scan_d_handling_switch,'$'+hs);
  1690. t.proc();
  1691. end;
  1692. end
  1693. else
  1694. begin
  1695. current_scanner.ignoredirectives.insert(hs);
  1696. Message1(scan_w_illegal_directive,'$'+hs);
  1697. end;
  1698. { conditionals already read the comment }
  1699. if (current_scanner.comment_level>0) then
  1700. current_scanner.readcomment;
  1701. { we've read the whole comment }
  1702. aktcommentstyle:=comment_none;
  1703. end;
  1704. end;
  1705. procedure tscannerfile.readchar;
  1706. begin
  1707. c:=inputpointer^;
  1708. if c=#0 then
  1709. reload
  1710. else
  1711. inc(inputpointer);
  1712. end;
  1713. procedure tscannerfile.readstring;
  1714. var
  1715. i : longint;
  1716. err : boolean;
  1717. begin
  1718. err:=false;
  1719. i:=0;
  1720. repeat
  1721. case c of
  1722. '_',
  1723. '0'..'9',
  1724. 'A'..'Z' :
  1725. begin
  1726. if i<255 then
  1727. begin
  1728. inc(i);
  1729. orgpattern[i]:=c;
  1730. pattern[i]:=c;
  1731. end
  1732. else
  1733. begin
  1734. if not err then
  1735. begin
  1736. Message(scan_e_string_exceeds_255_chars);
  1737. err:=true;
  1738. end;
  1739. end;
  1740. c:=inputpointer^;
  1741. inc(inputpointer);
  1742. end;
  1743. 'a'..'z' :
  1744. begin
  1745. if i<255 then
  1746. begin
  1747. inc(i);
  1748. orgpattern[i]:=c;
  1749. pattern[i]:=chr(ord(c)-32)
  1750. end
  1751. else
  1752. begin
  1753. if not err then
  1754. begin
  1755. Message(scan_e_string_exceeds_255_chars);
  1756. err:=true;
  1757. end;
  1758. end;
  1759. c:=inputpointer^;
  1760. inc(inputpointer);
  1761. end;
  1762. #0 :
  1763. reload;
  1764. else
  1765. break;
  1766. end;
  1767. until false;
  1768. orgpattern[0]:=chr(i);
  1769. pattern[0]:=chr(i);
  1770. end;
  1771. procedure tscannerfile.readnumber;
  1772. var
  1773. base,
  1774. i : longint;
  1775. begin
  1776. case c of
  1777. '%' :
  1778. begin
  1779. readchar;
  1780. base:=2;
  1781. pattern[1]:='%';
  1782. i:=1;
  1783. end;
  1784. '&' :
  1785. begin
  1786. readchar;
  1787. base:=8;
  1788. pattern[1]:='&';
  1789. i:=1;
  1790. end;
  1791. '$' :
  1792. begin
  1793. readchar;
  1794. base:=16;
  1795. pattern[1]:='$';
  1796. i:=1;
  1797. end;
  1798. else
  1799. begin
  1800. base:=10;
  1801. i:=0;
  1802. end;
  1803. end;
  1804. while ((base>=10) and (c in ['0'..'9'])) or
  1805. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  1806. ((base=8) and (c in ['0'..'7'])) or
  1807. ((base=2) and (c in ['0'..'1'])) do
  1808. begin
  1809. if i<255 then
  1810. begin
  1811. inc(i);
  1812. pattern[i]:=c;
  1813. end;
  1814. readchar;
  1815. end;
  1816. pattern[0]:=chr(i);
  1817. end;
  1818. function tscannerfile.readid:string;
  1819. begin
  1820. readstring;
  1821. readid:=pattern;
  1822. end;
  1823. function tscannerfile.readval:longint;
  1824. var
  1825. l : longint;
  1826. w : integer;
  1827. begin
  1828. readnumber;
  1829. val(pattern,l,w);
  1830. readval:=l;
  1831. end;
  1832. function tscannerfile.readval_asstring:string;
  1833. begin
  1834. readnumber;
  1835. readval_asstring:=pattern;
  1836. end;
  1837. function tscannerfile.readcomment:string;
  1838. var
  1839. i : longint;
  1840. begin
  1841. i:=0;
  1842. repeat
  1843. case c of
  1844. '{' :
  1845. begin
  1846. if aktcommentstyle=comment_tp then
  1847. inc_comment_level;
  1848. end;
  1849. '}' :
  1850. begin
  1851. if aktcommentstyle=comment_tp then
  1852. begin
  1853. readchar;
  1854. dec_comment_level;
  1855. if comment_level=0 then
  1856. break
  1857. else
  1858. continue;
  1859. end;
  1860. end;
  1861. '*' :
  1862. begin
  1863. if aktcommentstyle=comment_oldtp then
  1864. begin
  1865. readchar;
  1866. if c=')' then
  1867. begin
  1868. readchar;
  1869. dec_comment_level;
  1870. break;
  1871. end
  1872. else
  1873. { Add both characters !!}
  1874. if (i<255) then
  1875. begin
  1876. inc(i);
  1877. readcomment[i]:='*';
  1878. if (i<255) then
  1879. begin
  1880. inc(i);
  1881. readcomment[i]:='*';
  1882. end;
  1883. end;
  1884. end
  1885. else
  1886. { Not old TP comment, so add...}
  1887. begin
  1888. if (i<255) then
  1889. begin
  1890. inc(i);
  1891. readcomment[i]:='*';
  1892. end;
  1893. end;
  1894. end;
  1895. #10,#13 :
  1896. linebreak;
  1897. #26 :
  1898. end_of_file;
  1899. else
  1900. begin
  1901. if (i<255) then
  1902. begin
  1903. inc(i);
  1904. readcomment[i]:=c;
  1905. end;
  1906. end;
  1907. end;
  1908. readchar;
  1909. until false;
  1910. readcomment[0]:=chr(i);
  1911. end;
  1912. function tscannerfile.readquotedstring:string;
  1913. var
  1914. i : longint;
  1915. msgwritten : boolean;
  1916. begin
  1917. i:=0;
  1918. msgwritten:=false;
  1919. if (c='''') then
  1920. begin
  1921. repeat
  1922. readchar;
  1923. case c of
  1924. #26 :
  1925. end_of_file;
  1926. #10,#13 :
  1927. Message(scan_f_string_exceeds_line);
  1928. '''' :
  1929. begin
  1930. readchar;
  1931. if c<>'''' then
  1932. break;
  1933. end;
  1934. end;
  1935. if i<255 then
  1936. begin
  1937. inc(i);
  1938. result[i]:=c;
  1939. end
  1940. else
  1941. begin
  1942. if not msgwritten then
  1943. begin
  1944. Message(scan_e_string_exceeds_255_chars);
  1945. msgwritten:=true;
  1946. end;
  1947. end;
  1948. until false;
  1949. end;
  1950. result[0]:=chr(i);
  1951. end;
  1952. function tscannerfile.readstate:char;
  1953. var
  1954. state : char;
  1955. begin
  1956. state:=' ';
  1957. if c=' ' then
  1958. begin
  1959. current_scanner.skipspace;
  1960. current_scanner.readid;
  1961. if pattern='ON' then
  1962. state:='+'
  1963. else
  1964. if pattern='OFF' then
  1965. state:='-';
  1966. end
  1967. else
  1968. state:=c;
  1969. if not (state in ['+','-']) then
  1970. Message(scan_e_wrong_switch_toggle);
  1971. readstate:=state;
  1972. end;
  1973. function tscannerfile.readstatedefault:char;
  1974. var
  1975. state : char;
  1976. begin
  1977. state:=' ';
  1978. if c=' ' then
  1979. begin
  1980. current_scanner.skipspace;
  1981. current_scanner.readid;
  1982. if pattern='ON' then
  1983. state:='+'
  1984. else
  1985. if pattern='OFF' then
  1986. state:='-'
  1987. else
  1988. if pattern='DEFAULT' then
  1989. state:='*';
  1990. end
  1991. else
  1992. state:=c;
  1993. if not (state in ['+','-','*']) then
  1994. Message(scan_e_wrong_switch_toggle_default);
  1995. readstatedefault:=state;
  1996. end;
  1997. procedure tscannerfile.skipspace;
  1998. begin
  1999. repeat
  2000. case c of
  2001. #26 :
  2002. begin
  2003. reload;
  2004. if (c=#26) and not assigned(inputfile.next) then
  2005. break;
  2006. continue;
  2007. end;
  2008. #10,
  2009. #13 :
  2010. linebreak;
  2011. #9,#11,#12,' ' :
  2012. ;
  2013. else
  2014. break;
  2015. end;
  2016. readchar;
  2017. until false;
  2018. end;
  2019. procedure tscannerfile.skipuntildirective;
  2020. var
  2021. found : longint;
  2022. next_char_loaded : boolean;
  2023. begin
  2024. found:=0;
  2025. next_char_loaded:=false;
  2026. repeat
  2027. case c of
  2028. #10,
  2029. #13 :
  2030. linebreak;
  2031. #26 :
  2032. begin
  2033. reload;
  2034. if (c=#26) and not assigned(inputfile.next) then
  2035. end_of_file;
  2036. continue;
  2037. end;
  2038. '{' :
  2039. begin
  2040. if (aktcommentstyle in [comment_tp,comment_none]) then
  2041. begin
  2042. aktcommentstyle:=comment_tp;
  2043. if (comment_level=0) then
  2044. found:=1;
  2045. inc_comment_level;
  2046. end;
  2047. end;
  2048. '*' :
  2049. begin
  2050. if (aktcommentstyle=comment_oldtp) then
  2051. begin
  2052. readchar;
  2053. if c=')' then
  2054. begin
  2055. dec_comment_level;
  2056. found:=0;
  2057. aktcommentstyle:=comment_none;
  2058. end
  2059. else
  2060. next_char_loaded:=true;
  2061. end
  2062. else
  2063. found := 0;
  2064. end;
  2065. '}' :
  2066. begin
  2067. if (aktcommentstyle=comment_tp) then
  2068. begin
  2069. dec_comment_level;
  2070. if (comment_level=0) then
  2071. aktcommentstyle:=comment_none;
  2072. found:=0;
  2073. end;
  2074. end;
  2075. '$' :
  2076. begin
  2077. if found=1 then
  2078. found:=2;
  2079. end;
  2080. '''' :
  2081. if (aktcommentstyle=comment_none) then
  2082. begin
  2083. repeat
  2084. readchar;
  2085. case c of
  2086. #26 :
  2087. end_of_file;
  2088. #10,#13 :
  2089. break;
  2090. '''' :
  2091. begin
  2092. readchar;
  2093. if c<>'''' then
  2094. begin
  2095. next_char_loaded:=true;
  2096. break;
  2097. end;
  2098. end;
  2099. end;
  2100. until false;
  2101. end;
  2102. '(' :
  2103. begin
  2104. if (aktcommentstyle=comment_none) then
  2105. begin
  2106. readchar;
  2107. if c='*' then
  2108. begin
  2109. readchar;
  2110. if c='$' then
  2111. begin
  2112. found:=2;
  2113. inc_comment_level;
  2114. aktcommentstyle:=comment_oldtp;
  2115. end
  2116. else
  2117. begin
  2118. skipoldtpcomment;
  2119. next_char_loaded:=true;
  2120. end;
  2121. end
  2122. else
  2123. next_char_loaded:=true;
  2124. end
  2125. else
  2126. found:=0;
  2127. end;
  2128. '/' :
  2129. begin
  2130. if (aktcommentstyle=comment_none) then
  2131. begin
  2132. readchar;
  2133. if c='/' then
  2134. skipdelphicomment;
  2135. next_char_loaded:=true;
  2136. end
  2137. else
  2138. found:=0;
  2139. end;
  2140. else
  2141. found:=0;
  2142. end;
  2143. if next_char_loaded then
  2144. next_char_loaded:=false
  2145. else
  2146. readchar;
  2147. until (found=2);
  2148. end;
  2149. {****************************************************************************
  2150. Comment Handling
  2151. ****************************************************************************}
  2152. procedure tscannerfile.skipcomment;
  2153. begin
  2154. aktcommentstyle:=comment_tp;
  2155. readchar;
  2156. inc_comment_level;
  2157. { handle compiler switches }
  2158. if (c='$') then
  2159. handledirectives;
  2160. { handle_switches can dec comment_level, }
  2161. while (comment_level>0) do
  2162. begin
  2163. case c of
  2164. '{' :
  2165. inc_comment_level;
  2166. '}' :
  2167. dec_comment_level;
  2168. #10,#13 :
  2169. linebreak;
  2170. #26 :
  2171. begin
  2172. reload;
  2173. if (c=#26) and not assigned(inputfile.next) then
  2174. end_of_file;
  2175. continue;
  2176. end;
  2177. end;
  2178. readchar;
  2179. end;
  2180. aktcommentstyle:=comment_none;
  2181. end;
  2182. procedure tscannerfile.skipdelphicomment;
  2183. begin
  2184. aktcommentstyle:=comment_delphi;
  2185. inc_comment_level;
  2186. readchar;
  2187. { this is not supported }
  2188. if c='$' then
  2189. Message(scan_w_wrong_styled_switch);
  2190. { skip comment }
  2191. while not (c in [#10,#13,#26]) do
  2192. readchar;
  2193. dec_comment_level;
  2194. aktcommentstyle:=comment_none;
  2195. end;
  2196. procedure tscannerfile.skipoldtpcomment;
  2197. var
  2198. found : longint;
  2199. begin
  2200. aktcommentstyle:=comment_oldtp;
  2201. inc_comment_level;
  2202. { only load a char if last already processed,
  2203. was cause of bug1634 PM }
  2204. if c=#0 then
  2205. readchar;
  2206. { this is now supported }
  2207. if (c='$') then
  2208. handledirectives;
  2209. { skip comment }
  2210. while (comment_level>0) do
  2211. begin
  2212. found:=0;
  2213. repeat
  2214. case c of
  2215. #26 :
  2216. begin
  2217. reload;
  2218. if (c=#26) and not assigned(inputfile.next) then
  2219. end_of_file;
  2220. continue;
  2221. end;
  2222. #10,#13 :
  2223. linebreak;
  2224. '*' :
  2225. begin
  2226. if found=3 then
  2227. found:=4
  2228. else
  2229. found:=1;
  2230. end;
  2231. ')' :
  2232. begin
  2233. if found in [1,4] then
  2234. begin
  2235. dec_comment_level;
  2236. if comment_level=0 then
  2237. found:=2
  2238. else
  2239. found:=0;
  2240. end;
  2241. end;
  2242. '(' :
  2243. begin
  2244. if found=4 then
  2245. inc_comment_level;
  2246. found:=3;
  2247. end;
  2248. else
  2249. begin
  2250. if found=4 then
  2251. inc_comment_level;
  2252. found:=0;
  2253. end;
  2254. end;
  2255. readchar;
  2256. until (found=2);
  2257. end;
  2258. aktcommentstyle:=comment_none;
  2259. end;
  2260. {****************************************************************************
  2261. Token Scanner
  2262. ****************************************************************************}
  2263. procedure tscannerfile.readtoken;
  2264. var
  2265. code : integer;
  2266. len,
  2267. low,high,mid : longint;
  2268. w : word;
  2269. m : longint;
  2270. mac : tmacro;
  2271. asciinr : string[6];
  2272. msgwritten,
  2273. iswidestring : boolean;
  2274. label
  2275. exit_label;
  2276. begin
  2277. if localswitcheschanged then
  2278. begin
  2279. aktlocalswitches:=nextaktlocalswitches;
  2280. localswitcheschanged:=false;
  2281. end;
  2282. { was there already a token read, then return that token }
  2283. if nexttoken<>NOTOKEN then
  2284. begin
  2285. token:=nexttoken;
  2286. nexttoken:=NOTOKEN;
  2287. goto exit_label;
  2288. end;
  2289. { Skip all spaces and comments }
  2290. repeat
  2291. case c of
  2292. '{' :
  2293. skipcomment;
  2294. #26 :
  2295. begin
  2296. reload;
  2297. if (c=#26) and not assigned(inputfile.next) then
  2298. break;
  2299. end;
  2300. ' ',#9..#13 :
  2301. begin
  2302. {$ifdef PREPROCWRITE}
  2303. if parapreprocess then
  2304. begin
  2305. if c=#10 then
  2306. preprocfile.eolfound:=true
  2307. else
  2308. preprocfile.spacefound:=true;
  2309. end;
  2310. {$endif PREPROCWRITE}
  2311. skipspace;
  2312. end
  2313. else
  2314. break;
  2315. end;
  2316. until false;
  2317. { Save current token position, for EOF its already loaded }
  2318. if c<>#26 then
  2319. gettokenpos;
  2320. { Check first for a identifier/keyword, this is 20+% faster (PFV) }
  2321. if c in ['A'..'Z','a'..'z','_'] then
  2322. begin
  2323. readstring;
  2324. token:=_ID;
  2325. idtoken:=_ID;
  2326. { keyword or any other known token,
  2327. pattern is always uppercased }
  2328. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  2329. begin
  2330. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  2331. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  2332. while low<high do
  2333. begin
  2334. mid:=(high+low+1) shr 1;
  2335. if pattern<tokeninfo^[ttoken(mid)].str then
  2336. high:=mid-1
  2337. else
  2338. low:=mid;
  2339. end;
  2340. with tokeninfo^[ttoken(high)] do
  2341. if pattern=str then
  2342. begin
  2343. if keyword in aktmodeswitches then
  2344. if op=NOTOKEN then
  2345. token:=ttoken(high)
  2346. else
  2347. token:=op;
  2348. idtoken:=ttoken(high);
  2349. end;
  2350. end;
  2351. { Only process identifiers and not keywords }
  2352. if token=_ID then
  2353. begin
  2354. { this takes some time ... }
  2355. if (cs_support_macro in aktmoduleswitches) then
  2356. begin
  2357. mac:=tmacro(search_macro(pattern));
  2358. if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
  2359. begin
  2360. if yylexcount<max_macro_nesting then
  2361. begin
  2362. mac.is_used:=true;
  2363. inc(yylexcount);
  2364. insertmacro(pattern,mac.buftext,mac.buflen,
  2365. mac.fileinfo.line,mac.fileinfo.fileindex);
  2366. { handle empty macros }
  2367. if c=#0 then
  2368. reload;
  2369. readtoken;
  2370. { that's all folks }
  2371. dec(yylexcount);
  2372. exit;
  2373. end
  2374. else
  2375. Message(scan_w_macro_too_deep);
  2376. end;
  2377. end;
  2378. end;
  2379. { return token }
  2380. goto exit_label;
  2381. end
  2382. else
  2383. begin
  2384. idtoken:=_NOID;
  2385. case c of
  2386. '$' :
  2387. begin
  2388. readnumber;
  2389. token:=_INTCONST;
  2390. goto exit_label;
  2391. end;
  2392. '%' :
  2393. begin
  2394. if not(m_fpc in aktmodeswitches) then
  2395. Illegal_Char(c)
  2396. else
  2397. begin
  2398. readnumber;
  2399. token:=_INTCONST;
  2400. goto exit_label;
  2401. end;
  2402. end;
  2403. '&' :
  2404. begin
  2405. if m_fpc in aktmodeswitches then
  2406. begin
  2407. readnumber;
  2408. token:=_INTCONST;
  2409. goto exit_label;
  2410. end
  2411. else if m_mac in aktmodeswitches then
  2412. begin
  2413. readchar;
  2414. token:=_AMPERSAND;
  2415. goto exit_label;
  2416. end
  2417. else
  2418. Illegal_Char(c);
  2419. end;
  2420. '0'..'9' :
  2421. begin
  2422. readnumber;
  2423. if (c in ['.','e','E']) then
  2424. begin
  2425. { first check for a . }
  2426. if c='.' then
  2427. begin
  2428. readchar;
  2429. { is it a .. from a range? }
  2430. case c of
  2431. '.' :
  2432. begin
  2433. readchar;
  2434. token:=_INTCONST;
  2435. nexttoken:=_POINTPOINT;
  2436. goto exit_label;
  2437. end;
  2438. ')' :
  2439. begin
  2440. readchar;
  2441. token:=_INTCONST;
  2442. nexttoken:=_RECKKLAMMER;
  2443. goto exit_label;
  2444. end;
  2445. end;
  2446. { insert the number after the . }
  2447. pattern:=pattern+'.';
  2448. while c in ['0'..'9'] do
  2449. begin
  2450. pattern:=pattern+c;
  2451. readchar;
  2452. end;
  2453. end;
  2454. { E can also follow after a point is scanned }
  2455. if c in ['e','E'] then
  2456. begin
  2457. pattern:=pattern+'E';
  2458. readchar;
  2459. if c in ['-','+'] then
  2460. begin
  2461. pattern:=pattern+c;
  2462. readchar;
  2463. end;
  2464. if not(c in ['0'..'9']) then
  2465. Illegal_Char(c);
  2466. while c in ['0'..'9'] do
  2467. begin
  2468. pattern:=pattern+c;
  2469. readchar;
  2470. end;
  2471. end;
  2472. token:=_REALNUMBER;
  2473. goto exit_label;
  2474. end;
  2475. token:=_INTCONST;
  2476. goto exit_label;
  2477. end;
  2478. ';' :
  2479. begin
  2480. readchar;
  2481. token:=_SEMICOLON;
  2482. goto exit_label;
  2483. end;
  2484. '[' :
  2485. begin
  2486. readchar;
  2487. token:=_LECKKLAMMER;
  2488. goto exit_label;
  2489. end;
  2490. ']' :
  2491. begin
  2492. readchar;
  2493. token:=_RECKKLAMMER;
  2494. goto exit_label;
  2495. end;
  2496. '(' :
  2497. begin
  2498. readchar;
  2499. case c of
  2500. '*' :
  2501. begin
  2502. c:=#0;{Signal skipoldtpcomment to reload a char }
  2503. skipoldtpcomment;
  2504. readtoken;
  2505. exit;
  2506. end;
  2507. '.' :
  2508. begin
  2509. readchar;
  2510. token:=_LECKKLAMMER;
  2511. goto exit_label;
  2512. end;
  2513. end;
  2514. token:=_LKLAMMER;
  2515. goto exit_label;
  2516. end;
  2517. ')' :
  2518. begin
  2519. readchar;
  2520. token:=_RKLAMMER;
  2521. goto exit_label;
  2522. end;
  2523. '+' :
  2524. begin
  2525. readchar;
  2526. if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
  2527. begin
  2528. readchar;
  2529. token:=_PLUSASN;
  2530. goto exit_label;
  2531. end;
  2532. token:=_PLUS;
  2533. goto exit_label;
  2534. end;
  2535. '-' :
  2536. begin
  2537. readchar;
  2538. if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
  2539. begin
  2540. readchar;
  2541. token:=_MINUSASN;
  2542. goto exit_label;
  2543. end;
  2544. token:=_MINUS;
  2545. goto exit_label;
  2546. end;
  2547. ':' :
  2548. begin
  2549. readchar;
  2550. if c='=' then
  2551. begin
  2552. readchar;
  2553. token:=_ASSIGNMENT;
  2554. goto exit_label;
  2555. end;
  2556. token:=_COLON;
  2557. goto exit_label;
  2558. end;
  2559. '*' :
  2560. begin
  2561. readchar;
  2562. if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
  2563. begin
  2564. readchar;
  2565. token:=_STARASN;
  2566. end
  2567. else
  2568. if c='*' then
  2569. begin
  2570. readchar;
  2571. token:=_STARSTAR;
  2572. end
  2573. else
  2574. token:=_STAR;
  2575. goto exit_label;
  2576. end;
  2577. '/' :
  2578. begin
  2579. readchar;
  2580. case c of
  2581. '=' :
  2582. begin
  2583. if (cs_support_c_operators in aktmoduleswitches) then
  2584. begin
  2585. readchar;
  2586. token:=_SLASHASN;
  2587. goto exit_label;
  2588. end;
  2589. end;
  2590. '/' :
  2591. begin
  2592. skipdelphicomment;
  2593. readtoken;
  2594. exit;
  2595. end;
  2596. end;
  2597. token:=_SLASH;
  2598. goto exit_label;
  2599. end;
  2600. '|' :
  2601. if m_mac in aktmodeswitches then
  2602. begin
  2603. readchar;
  2604. token:=_PIPE;
  2605. goto exit_label;
  2606. end
  2607. else
  2608. Illegal_Char(c);
  2609. '=' :
  2610. begin
  2611. readchar;
  2612. token:=_EQUAL;
  2613. goto exit_label;
  2614. end;
  2615. '.' :
  2616. begin
  2617. readchar;
  2618. case c of
  2619. '.' :
  2620. begin
  2621. readchar;
  2622. case c of
  2623. '.' :
  2624. begin
  2625. readchar;
  2626. token:=_POINTPOINTPOINT;
  2627. goto exit_label;
  2628. end;
  2629. else
  2630. begin
  2631. token:=_POINTPOINT;
  2632. goto exit_label;
  2633. end;
  2634. end;
  2635. end;
  2636. ')' :
  2637. begin
  2638. readchar;
  2639. token:=_RECKKLAMMER;
  2640. goto exit_label;
  2641. end;
  2642. end;
  2643. token:=_POINT;
  2644. goto exit_label;
  2645. end;
  2646. '@' :
  2647. begin
  2648. readchar;
  2649. token:=_KLAMMERAFFE;
  2650. goto exit_label;
  2651. end;
  2652. ',' :
  2653. begin
  2654. readchar;
  2655. token:=_COMMA;
  2656. goto exit_label;
  2657. end;
  2658. '''','#','^' :
  2659. begin
  2660. len:=0;
  2661. msgwritten:=false;
  2662. pattern:='';
  2663. iswidestring:=false;
  2664. if c='^' then
  2665. begin
  2666. readchar;
  2667. c:=upcase(c);
  2668. if (block_type=bt_type) or
  2669. (lasttoken=_ID) or (lasttoken=_NIL) or
  2670. (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
  2671. begin
  2672. token:=_CARET;
  2673. goto exit_label;
  2674. end
  2675. else
  2676. begin
  2677. inc(len);
  2678. if c<#64 then
  2679. pattern[len]:=chr(ord(c)+64)
  2680. else
  2681. pattern[len]:=chr(ord(c)-64);
  2682. readchar;
  2683. end;
  2684. end;
  2685. repeat
  2686. case c of
  2687. '#' :
  2688. begin
  2689. readchar; { read # }
  2690. if c='$' then
  2691. begin
  2692. readchar; { read leading $ }
  2693. asciinr:='$';
  2694. while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<6) do
  2695. begin
  2696. asciinr:=asciinr+c;
  2697. readchar;
  2698. end;
  2699. end
  2700. else
  2701. begin
  2702. asciinr:='';
  2703. while (c in ['0'..'9']) and (length(asciinr)<6) do
  2704. begin
  2705. asciinr:=asciinr+c;
  2706. readchar;
  2707. end;
  2708. end;
  2709. val(asciinr,m,code);
  2710. if (asciinr='') or (code<>0) then
  2711. Message(scan_e_illegal_char_const)
  2712. else if (m<0) or (m>255) or (length(asciinr)>3) then
  2713. begin
  2714. if (m>=0) and (m<=65535) then
  2715. begin
  2716. if not iswidestring then
  2717. begin
  2718. ascii2unicode(@pattern[1],len,patternw);
  2719. iswidestring:=true;
  2720. len:=0;
  2721. end;
  2722. concatwidestringchar(patternw,tcompilerwidechar(m));
  2723. end
  2724. else
  2725. Message(scan_e_illegal_char_const)
  2726. end
  2727. else if iswidestring then
  2728. concatwidestringchar(patternw,asciichar2unicode(char(m)))
  2729. else
  2730. begin
  2731. if len<255 then
  2732. begin
  2733. inc(len);
  2734. pattern[len]:=chr(m);
  2735. end
  2736. else
  2737. begin
  2738. if not msgwritten then
  2739. begin
  2740. Message(scan_e_string_exceeds_255_chars);
  2741. msgwritten:=true;
  2742. end;
  2743. end;
  2744. end;
  2745. end;
  2746. '''' :
  2747. begin
  2748. repeat
  2749. readchar;
  2750. case c of
  2751. #26 :
  2752. end_of_file;
  2753. #10,#13 :
  2754. Message(scan_f_string_exceeds_line);
  2755. '''' :
  2756. begin
  2757. readchar;
  2758. if c<>'''' then
  2759. break;
  2760. end;
  2761. end;
  2762. { interpret as utf-8 string? }
  2763. if (ord(c)>=$80) and (aktsourcecodepage='utf8') then
  2764. begin
  2765. { convert existing string to an utf-8 string }
  2766. if not iswidestring then
  2767. begin
  2768. ascii2unicode(@pattern[1],len,patternw);
  2769. iswidestring:=true;
  2770. len:=0;
  2771. end;
  2772. { four or more chars aren't handled }
  2773. if (ord(c) and $f0)=$f0 then
  2774. message(scan_e_utf8_bigger_than_65535)
  2775. { three chars }
  2776. else if (ord(c) and $e0)=$e0 then
  2777. begin
  2778. w:=ord(c) and $f;
  2779. readchar;
  2780. if (ord(c) and $c0)<>$80 then
  2781. message(scan_e_utf8_malformed);
  2782. w:=(w shl 6) or (ord(c) and $3f);
  2783. readchar;
  2784. if (ord(c) and $c0)<>$80 then
  2785. message(scan_e_utf8_malformed);
  2786. w:=(w shl 6) or (ord(c) and $3f);
  2787. concatwidestringchar(patternw,w);
  2788. end
  2789. { two chars }
  2790. else if (ord(c) and $c0)<>0 then
  2791. begin
  2792. w:=ord(c) and $1f;
  2793. readchar;
  2794. if (ord(c) and $c0)<>$80 then
  2795. message(scan_e_utf8_malformed);
  2796. w:=(w shl 6) or (ord(c) and $3f);
  2797. concatwidestringchar(patternw,w);
  2798. end
  2799. { illegal }
  2800. else if (ord(c) and $80)<>0 then
  2801. message(scan_e_utf8_malformed)
  2802. else
  2803. concatwidestringchar(patternw,tcompilerwidechar(c))
  2804. end
  2805. else if iswidestring then
  2806. begin
  2807. if aktsourcecodepage='utf8' then
  2808. concatwidestringchar(patternw,ord(c))
  2809. else
  2810. concatwidestringchar(patternw,asciichar2unicode(c))
  2811. end
  2812. else
  2813. begin
  2814. if len<255 then
  2815. begin
  2816. inc(len);
  2817. pattern[len]:=c;
  2818. end
  2819. else
  2820. begin
  2821. if not msgwritten then
  2822. begin
  2823. Message(scan_e_string_exceeds_255_chars);
  2824. msgwritten:=true;
  2825. end;
  2826. end;
  2827. end;
  2828. until false;
  2829. end;
  2830. '^' :
  2831. begin
  2832. readchar;
  2833. c:=upcase(c);
  2834. if c<#64 then
  2835. c:=chr(ord(c)+64)
  2836. else
  2837. c:=chr(ord(c)-64);
  2838. if iswidestring then
  2839. concatwidestringchar(patternw,asciichar2unicode(c))
  2840. else
  2841. begin
  2842. if len<255 then
  2843. begin
  2844. inc(len);
  2845. pattern[len]:=c;
  2846. end
  2847. else
  2848. begin
  2849. if not msgwritten then
  2850. begin
  2851. Message(scan_e_string_exceeds_255_chars);
  2852. msgwritten:=true;
  2853. end;
  2854. end;
  2855. end;
  2856. readchar;
  2857. end;
  2858. else
  2859. break;
  2860. end;
  2861. until false;
  2862. { strings with length 1 become const chars }
  2863. if iswidestring then
  2864. begin
  2865. if patternw^.len=1 then
  2866. token:=_CWCHAR
  2867. else
  2868. token:=_CWSTRING;
  2869. end
  2870. else
  2871. begin
  2872. pattern[0]:=chr(len);
  2873. if len=1 then
  2874. token:=_CCHAR
  2875. else
  2876. token:=_CSTRING;
  2877. end;
  2878. goto exit_label;
  2879. end;
  2880. '>' :
  2881. begin
  2882. readchar;
  2883. case c of
  2884. '=' :
  2885. begin
  2886. readchar;
  2887. token:=_GTE;
  2888. goto exit_label;
  2889. end;
  2890. '>' :
  2891. begin
  2892. readchar;
  2893. token:=_OP_SHR;
  2894. goto exit_label;
  2895. end;
  2896. '<' :
  2897. begin { >< is for a symetric diff for sets }
  2898. readchar;
  2899. token:=_SYMDIF;
  2900. goto exit_label;
  2901. end;
  2902. end;
  2903. token:=_GT;
  2904. goto exit_label;
  2905. end;
  2906. '<' :
  2907. begin
  2908. readchar;
  2909. case c of
  2910. '>' :
  2911. begin
  2912. readchar;
  2913. token:=_UNEQUAL;
  2914. goto exit_label;
  2915. end;
  2916. '=' :
  2917. begin
  2918. readchar;
  2919. token:=_LTE;
  2920. goto exit_label;
  2921. end;
  2922. '<' :
  2923. begin
  2924. readchar;
  2925. token:=_OP_SHL;
  2926. goto exit_label;
  2927. end;
  2928. end;
  2929. token:=_LT;
  2930. goto exit_label;
  2931. end;
  2932. #26 :
  2933. begin
  2934. token:=_EOF;
  2935. checkpreprocstack;
  2936. goto exit_label;
  2937. end;
  2938. else
  2939. Illegal_Char(c);
  2940. end;
  2941. end;
  2942. exit_label:
  2943. lasttoken:=token;
  2944. end;
  2945. function tscannerfile.readpreproc:ttoken;
  2946. begin
  2947. skipspace;
  2948. case c of
  2949. '_',
  2950. 'A'..'Z',
  2951. 'a'..'z' :
  2952. begin
  2953. current_scanner.preproc_pattern:=readid;
  2954. readpreproc:=_ID;
  2955. end;
  2956. '0'..'9' :
  2957. begin
  2958. current_scanner.preproc_pattern:=readval_asstring;
  2959. { realnumber? }
  2960. if c='.' then
  2961. begin
  2962. readchar;
  2963. while c in ['0'..'9'] do
  2964. begin
  2965. current_scanner.preproc_pattern:=current_scanner.preproc_pattern+c;
  2966. readchar;
  2967. end;
  2968. end;
  2969. readpreproc:=_ID;
  2970. end;
  2971. '$','%','&' :
  2972. begin
  2973. current_scanner.preproc_pattern:=readval_asstring;
  2974. readpreproc:=_ID;
  2975. end;
  2976. ',' :
  2977. begin
  2978. readchar;
  2979. readpreproc:=_COMMA;
  2980. end;
  2981. '}' :
  2982. begin
  2983. readpreproc:=_END;
  2984. end;
  2985. '(' :
  2986. begin
  2987. readchar;
  2988. readpreproc:=_LKLAMMER;
  2989. end;
  2990. ')' :
  2991. begin
  2992. readchar;
  2993. readpreproc:=_RKLAMMER;
  2994. end;
  2995. '[' :
  2996. begin
  2997. readchar;
  2998. readpreproc:=_LECKKLAMMER;
  2999. end;
  3000. ']' :
  3001. begin
  3002. readchar;
  3003. readpreproc:=_RECKKLAMMER;
  3004. end;
  3005. '+' :
  3006. begin
  3007. readchar;
  3008. readpreproc:=_PLUS;
  3009. end;
  3010. '-' :
  3011. begin
  3012. readchar;
  3013. readpreproc:=_MINUS;
  3014. end;
  3015. '*' :
  3016. begin
  3017. readchar;
  3018. readpreproc:=_STAR;
  3019. end;
  3020. '/' :
  3021. begin
  3022. readchar;
  3023. readpreproc:=_SLASH;
  3024. end;
  3025. '=' :
  3026. begin
  3027. readchar;
  3028. readpreproc:=_EQUAL;
  3029. end;
  3030. '>' :
  3031. begin
  3032. readchar;
  3033. if c='=' then
  3034. begin
  3035. readchar;
  3036. readpreproc:=_GTE;
  3037. end
  3038. else
  3039. readpreproc:=_GT;
  3040. end;
  3041. '<' :
  3042. begin
  3043. readchar;
  3044. case c of
  3045. '>' :
  3046. begin
  3047. readchar;
  3048. readpreproc:=_UNEQUAL;
  3049. end;
  3050. '=' :
  3051. begin
  3052. readchar;
  3053. readpreproc:=_LTE;
  3054. end;
  3055. else
  3056. readpreproc:=_LT;
  3057. end;
  3058. end;
  3059. #26 :
  3060. begin
  3061. readpreproc:=_EOF;
  3062. checkpreprocstack;
  3063. end;
  3064. else
  3065. Illegal_Char(c);
  3066. end;
  3067. end;
  3068. function tscannerfile.asmgetcharstart : char;
  3069. begin
  3070. { return first the character already
  3071. available in c }
  3072. lastasmgetchar:=c;
  3073. result:=asmgetchar;
  3074. end;
  3075. function tscannerfile.asmgetchar : char;
  3076. begin
  3077. if lastasmgetchar<>#0 then
  3078. begin
  3079. c:=lastasmgetchar;
  3080. lastasmgetchar:=#0;
  3081. end
  3082. else
  3083. readchar;
  3084. if in_asm_string then
  3085. begin
  3086. asmgetchar:=c;
  3087. exit;
  3088. end;
  3089. repeat
  3090. case c of
  3091. {$ifndef arm}
  3092. // the { ... } is used in ARM assembler to define register sets, so we can't used
  3093. // it as comment, either (* ... *), /* ... */ or // ... should be used instead
  3094. '{' :
  3095. skipcomment;
  3096. {$endif arm}
  3097. #10,#13 :
  3098. begin
  3099. linebreak;
  3100. asmgetchar:=c;
  3101. exit;
  3102. end;
  3103. #26 :
  3104. begin
  3105. reload;
  3106. if (c=#26) and not assigned(inputfile.next) then
  3107. end_of_file;
  3108. continue;
  3109. end;
  3110. '/' :
  3111. begin
  3112. readchar;
  3113. if c='/' then
  3114. skipdelphicomment
  3115. else
  3116. begin
  3117. asmgetchar:='/';
  3118. lastasmgetchar:=c;
  3119. exit;
  3120. end;
  3121. end;
  3122. '(' :
  3123. begin
  3124. readchar;
  3125. if c='*' then
  3126. begin
  3127. c:=#0;{Signal skipoldtpcomment to reload a char }
  3128. skipoldtpcomment;
  3129. end
  3130. else
  3131. begin
  3132. asmgetchar:='(';
  3133. lastasmgetchar:=c;
  3134. exit;
  3135. end;
  3136. end;
  3137. else
  3138. begin
  3139. asmgetchar:=c;
  3140. exit;
  3141. end;
  3142. end;
  3143. until false;
  3144. end;
  3145. {*****************************************************************************
  3146. Helpers
  3147. *****************************************************************************}
  3148. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  3149. begin
  3150. if dm in [directive_all, directive_turbo] then
  3151. turbo_scannerdirectives.insert(tdirectiveitem.create(s,p));
  3152. if dm in [directive_all, directive_mac] then
  3153. mac_scannerdirectives.insert(tdirectiveitem.create(s,p));
  3154. end;
  3155. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  3156. begin
  3157. if dm in [directive_all, directive_turbo] then
  3158. turbo_scannerdirectives.insert(tdirectiveitem.createcond(s,p));
  3159. if dm in [directive_all, directive_mac] then
  3160. mac_scannerdirectives.insert(tdirectiveitem.createcond(s,p));
  3161. end;
  3162. {*****************************************************************************
  3163. Initialization
  3164. *****************************************************************************}
  3165. procedure InitScanner;
  3166. begin
  3167. InitWideString(patternw);
  3168. turbo_scannerdirectives:=TDictionary.Create;
  3169. mac_scannerdirectives:=TDictionary.Create;
  3170. { Common directives and conditionals }
  3171. AddDirective('I',directive_all, @dir_include);
  3172. AddDirective('DEFINE',directive_all, @dir_define);
  3173. AddDirective('UNDEF',directive_all, @dir_undef);
  3174. AddConditional('IF',directive_all, @dir_if);
  3175. AddConditional('IFDEF',directive_all, @dir_ifdef);
  3176. AddConditional('IFNDEF',directive_all, @dir_ifndef);
  3177. AddConditional('ELSE',directive_all, @dir_else);
  3178. AddConditional('ELSEIF',directive_all, @dir_elseif);
  3179. AddConditional('ENDIF',directive_all, @dir_endif);
  3180. { Directives and conditionals for all modes except mode macpas}
  3181. AddDirective('INCLUDE',directive_turbo, @dir_include);
  3182. AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
  3183. AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
  3184. AddDirective('EXTENSION',directive_turbo, @dir_extension);
  3185. AddConditional('IFEND',directive_turbo, @dir_endif);
  3186. AddConditional('IFOPT',directive_turbo, @dir_ifopt);
  3187. { Directives and conditionals for mode macpas: }
  3188. AddDirective('SETC',directive_mac, @dir_setc);
  3189. AddDirective('DEFINEC',directive_mac, @dir_define);
  3190. AddDirective('UNDEFC',directive_mac, @dir_undef);
  3191. AddConditional('IFC',directive_mac, @dir_if);
  3192. AddConditional('ELSEC',directive_mac, @dir_else);
  3193. AddConditional('ELIFC',directive_mac, @dir_elseif);
  3194. AddConditional('ENDC',directive_mac, @dir_endif);
  3195. end;
  3196. procedure DoneScanner;
  3197. begin
  3198. turbo_scannerdirectives.Free;
  3199. mac_scannerdirectives.Free;
  3200. DoneWideString(patternw);
  3201. end;
  3202. end.