scanner.pas 198 KB

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