scanner.pas 156 KB

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