scanner.pas 215 KB

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