scanner.pas 140 KB

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