scanner.pas 140 KB

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