scanner.pas 216 KB

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