scanner.pas 180 KB

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