scanner.pas 130 KB

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