scanner.pas 160 KB

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