pscanner.pp 162 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851
  1. {
  2. This file is part of the Free Component Library
  3. Pascal source lexical scanner
  4. Copyright (c) 2003 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  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.
  11. **********************************************************************}
  12. unit PScanner;
  13. {$i fcl-passrc.inc}
  14. interface
  15. uses
  16. {$ifdef pas2js}
  17. js,
  18. {$IFDEF NODEJS}
  19. Node.FS,
  20. {$ENDIF}
  21. Types,
  22. {$endif}
  23. SysUtils, Classes;
  24. // message numbers
  25. const
  26. nErrInvalidCharacter = 1001;
  27. nErrOpenString = 1002;
  28. nErrIncludeFileNotFound = 1003;
  29. nErrIfXXXNestingLimitReached = 1004;
  30. nErrInvalidPPElse = 1005;
  31. nErrInvalidPPEndif = 1006;
  32. nLogOpeningFile = 1007;
  33. nLogLineNumber = 1008; // same as FPC
  34. nLogIFDefAccepted = 1009;
  35. nLogIFDefRejected = 1010;
  36. nLogIFNDefAccepted = 1011;
  37. nLogIFNDefRejected = 1012;
  38. nLogIFAccepted = 1013;
  39. nLogIFRejected = 1014;
  40. nLogIFOptAccepted = 1015;
  41. nLogIFOptRejected = 1016;
  42. nLogELSEIFAccepted = 1017;
  43. nLogELSEIFRejected = 1018;
  44. nErrInvalidMode = 1019;
  45. nErrInvalidModeSwitch = 1020;
  46. nErrXExpectedButYFound = 1021;
  47. nErrRangeCheck = 1022;
  48. nErrDivByZero = 1023;
  49. nErrOperandAndOperatorMismatch = 1024;
  50. nUserDefined = 1025;
  51. nLogMacroDefined = 1026; // FPC=3101
  52. nLogMacroUnDefined = 1027; // FPC=3102
  53. nWarnIllegalCompilerDirectiveX = 1028;
  54. nIllegalStateForWarnDirective = 1027;
  55. nErrIncludeLimitReached = 1028;
  56. nMisplacedGlobalCompilerSwitch = 1029;
  57. nLogMacroXSetToY = 1030;
  58. nInvalidDispatchFieldName = 1031;
  59. nErrWrongSwitchToggle = 1032;
  60. nNoResourceSupport = 1033;
  61. nResourceFileNotFound = 1034;
  62. nErrInvalidMultiLineLineEnding = 1035;
  63. nWarnIgnoringLinkLib = 1036;
  64. // resourcestring patterns of messages
  65. resourcestring
  66. SErrInvalidCharacter = 'Invalid character ''%s''';
  67. SErrOpenString = 'string exceeds end of line';
  68. SErrIncludeFileNotFound = 'Could not find include file ''%s''';
  69. SErrResourceFileNotFound = 'Could not find resource file ''%s''';
  70. SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
  71. SErrInvalidPPElse = '$ELSE without matching $IFxxx';
  72. SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
  73. SLogOpeningFile = 'Opening source file "%s".';
  74. SLogLineNumber = 'Reading line %d.';
  75. SLogIFDefAccepted = 'IFDEF %s found, accepting.';
  76. SLogIFDefRejected = 'IFDEF %s found, rejecting.';
  77. SLogIFNDefAccepted = 'IFNDEF %s found, accepting.';
  78. SLogIFNDefRejected = 'IFNDEF %s found, rejecting.';
  79. SLogIFAccepted = 'IF %s found, accepting.';
  80. SLogIFRejected = 'IF %s found, rejecting.';
  81. SLogIFOptAccepted = 'IFOpt %s found, accepting.';
  82. SLogIFOptRejected = 'IFOpt %s found, rejecting.';
  83. SLogELSEIFAccepted = 'ELSEIF %s found, accepting.';
  84. SLogELSEIFRejected = 'ELSEIF %s found, rejecting.';
  85. SErrInvalidMode = 'Invalid mode: "%s"';
  86. SErrInvalidModeSwitch = 'Invalid mode switch: "%s"';
  87. SErrXExpectedButYFound = '"%s" expected, but "%s" found';
  88. SErrRangeCheck = 'range check failed';
  89. SErrDivByZero = 'division by zero';
  90. SErrOperandAndOperatorMismatch = 'operand and operator mismatch';
  91. SUserDefined = 'User defined: "%s"';
  92. SLogMacroDefined = 'Macro defined: %s';
  93. SLogMacroUnDefined = 'Macro undefined: %s';
  94. SWarnIllegalCompilerDirectiveX = 'Illegal compiler directive "%s"';
  95. SIllegalStateForWarnDirective = 'Illegal state "%s" for $WARN directive';
  96. SErrIncludeLimitReached = 'Include file limit reached';
  97. SMisplacedGlobalCompilerSwitch = 'Misplaced global compiler switch, ignored';
  98. SLogMacroXSetToY = 'Macro %s set to %s';
  99. SInvalidDispatchFieldName = 'Invalid Dispatch field name';
  100. SErrWrongSwitchToggle = 'Wrong switch toggle, use ON/OFF or +/-';
  101. SNoResourceSupport = 'No support for resources of type "%s"';
  102. SErrInvalidMultiLineLineEnding = 'Invalid multilinestring line ending type: use one of CR/LF/CRLF/SOURCE/PLATFORM' ;
  103. SWarnIgnoringLinkLib = 'Ignoring LINKLIB directive %s -> %s (Options: %s)';
  104. type
  105. TMessageType = (
  106. mtFatal,
  107. mtError,
  108. mtWarning,
  109. mtNote,
  110. mtHint,
  111. mtInfo,
  112. mtDebug
  113. );
  114. TMessageTypes = set of TMessageType;
  115. TMessageArgs = array of string;
  116. TToken = (
  117. tkEOF,
  118. tkWhitespace,
  119. tkComment,
  120. tkIdentifier,
  121. tkString,
  122. tkNumber,
  123. tkChar, // ^A .. ^Z
  124. // Simple (one-character) tokens
  125. tkBraceOpen, // '('
  126. tkBraceClose, // ')'
  127. tkMul, // '*'
  128. tkPlus, // '+'
  129. tkComma, // ','
  130. tkMinus, // '-'
  131. tkDot, // '.'
  132. tkDivision, // '/'
  133. tkColon, // ':'
  134. tkSemicolon, // ';'
  135. tkLessThan, // '<'
  136. tkEqual, // '='
  137. tkGreaterThan, // '>'
  138. tkAt, // '@'
  139. tkSquaredBraceOpen, // '['
  140. tkSquaredBraceClose, // ']'
  141. tkCaret, // '^'
  142. tkBackslash, // '\'
  143. // Two-character tokens
  144. tkDotDot, // '..'
  145. tkAssign, // ':='
  146. tkNotEqual, // '<>'
  147. tkLessEqualThan, // '<='
  148. tkGreaterEqualThan, // '>='
  149. tkPower, // '**'
  150. tkSymmetricalDifference, // '><'
  151. tkAssignPlus, // +=
  152. tkAssignMinus, // -=
  153. tkAssignMul, // *=
  154. tkAssignDivision, // /=
  155. tkAtAt, // @@
  156. // Three-character tokens
  157. tkDotDotDot, // ... (mac mode)
  158. // Reserved words
  159. tkabsolute,
  160. tkand,
  161. tkarray,
  162. tkas,
  163. tkasm,
  164. tkbegin,
  165. tkbitpacked,
  166. tkcase,
  167. tkclass,
  168. tkconst,
  169. tkconstref,
  170. tkconstructor,
  171. tkdestructor,
  172. tkdispinterface,
  173. tkdiv,
  174. tkdo,
  175. tkdownto,
  176. tkelse,
  177. tkend,
  178. tkexcept,
  179. tkexports,
  180. tkfalse,
  181. tkfile,
  182. tkfinalization,
  183. tkfinally,
  184. tkfor,
  185. tkfunction,
  186. tkgeneric,
  187. tkgoto,
  188. tkif,
  189. tkimplementation,
  190. tkin,
  191. tkinherited,
  192. tkinitialization,
  193. tkinline,
  194. tkinterface,
  195. tkis,
  196. tklabel,
  197. tklibrary,
  198. tkmod,
  199. tknil,
  200. tknot,
  201. tkobjccategory,
  202. tkobjcclass,
  203. tkobjcprotocol,
  204. tkobject,
  205. tkof,
  206. tkoperator,
  207. tkor,
  208. tkotherwise,
  209. tkpacked,
  210. tkprocedure,
  211. tkprogram,
  212. tkproperty,
  213. tkraise,
  214. tkrecord,
  215. tkrepeat,
  216. tkResourceString,
  217. tkself,
  218. tkset,
  219. tkshl,
  220. tkshr,
  221. tkspecialize,
  222. // tkstring,
  223. tkthen,
  224. tkthreadvar,
  225. tkto,
  226. tktrue,
  227. tktry,
  228. tktype,
  229. tkunit,
  230. tkuntil,
  231. tkuses,
  232. tkvar,
  233. tkwhile,
  234. tkwith,
  235. tkxor,
  236. tkLineEnding,
  237. tkTab
  238. );
  239. TTokens = set of TToken;
  240. TModeSwitch = (
  241. msNone,
  242. { generic }
  243. msFpc, msObjfpc, msDelphi, msDelphiUnicode, msTP7, msMac, msIso, msExtpas, msGPC,
  244. { more specific }
  245. msClass, { delphi class model }
  246. msObjpas, { load objpas unit }
  247. msResult, { result in functions }
  248. msStringPchar, { pchar 2 string conversion }
  249. msCVarSupport, { cvar variable directive }
  250. msNestedComment, { nested comments }
  251. msTPProcVar, { tp style procvars (no @ needed) }
  252. msMacProcVar, { macpas style procvars }
  253. msRepeatForward, { repeating forward declarations is needed }
  254. msPointer2Procedure, { allows the assignement of pointers to
  255. procedure variables }
  256. msAutoDeref, { does auto dereferencing of struct. vars }
  257. msInitFinal, { initialization/finalization for units }
  258. msDefaultAnsistring, { ansistring turned on by default }
  259. msOut, { support the calling convention OUT }
  260. msDefaultPara, { support default parameters }
  261. msHintDirective, { support hint directives }
  262. msDuplicateNames, { allow locals/paras to have duplicate names of globals }
  263. msProperty, { allow properties }
  264. msDefaultInline, { allow inline proc directive }
  265. msExcept, { allow exception-related keywords }
  266. msObjectiveC1, { support interfacing with Objective-C (1.0) }
  267. msObjectiveC2, { support interfacing with Objective-C (2.0) }
  268. msNestedProcVars, { support nested procedural variables }
  269. msNonLocalGoto, { support non local gotos (like iso pascal) }
  270. msAdvancedRecords, { advanced record syntax with visibility sections, methods and properties }
  271. msISOLikeUnaryMinus, { unary minus like in iso pascal: same precedence level as binary minus/plus }
  272. msSystemCodePage, { use system codepage as compiler codepage by default, emit ansistrings with system codepage }
  273. msFinalFields, { allows declaring fields as "final", which means they must be initialised
  274. in the (class) constructor and are constant from then on (same as final
  275. fields in Java) }
  276. msDefaultUnicodestring, { makes the default string type in $h+ mode unicodestring rather than
  277. ansistring; similarly, char becomes unicodechar rather than ansichar }
  278. msTypeHelpers, { allows the declaration of "type helper" (non-Delphi) or "record helper"
  279. (Delphi) for primitive types }
  280. msCBlocks, { 'cblocks', support for http://en.wikipedia.org/wiki/Blocks_(C_language_extension) }
  281. msISOLikeIO, { I/O as it required by an ISO compatible compiler }
  282. msISOLikeProgramsPara, { program parameters as it required by an ISO compatible compiler }
  283. msISOLikeMod, { mod operation as it is required by an iso compatible compiler }
  284. msArrayOperators, { use Delphi compatible array operators instead of custom ones ("+") }
  285. msExternalClass, { Allow external class definitions }
  286. msPrefixedAttributes, { Allow attributes, disable proc modifier [] }
  287. msOmitRTTI, { treat class section 'published' as 'public' and typeinfo does not work on symbols declared with this switch }
  288. msMultiHelpers, { off=only one helper per type, on=all }
  289. msImplicitFunctionSpec, { implicit function specialization }
  290. msMultiLineStrings { Multiline strings }
  291. );
  292. TModeSwitches = Set of TModeSwitch;
  293. // switches, that can be 'on' or 'off'
  294. TBoolSwitch = (
  295. bsNone,
  296. bsAlign, // A align fields
  297. bsBoolEval, // B complete boolean evaluation
  298. bsAssertions, // C generate code for assertions
  299. bsDebugInfo, // D generate debuginfo (debug lines), OR: $description 'text'
  300. bsExtension, // E output file extension
  301. // F
  302. bsImportedData, // G
  303. bsLongStrings, // H String=AnsiString
  304. bsIOChecks, // I generate EInOutError
  305. bsWriteableConst, // J writable typed const
  306. // K
  307. bsLocalSymbols, // L generate local symbol information (debug, requires $D+)
  308. bsTypeInfo, // M allow published members OR $M minstacksize,maxstacksize
  309. // N
  310. bsOptimization, // O enable safe optimizations (-O1)
  311. bsOpenStrings, // P deprecated Delphi directive
  312. bsOverflowChecks, // Q or $OV
  313. bsRangeChecks, // R
  314. // S
  315. bsTypedAddress, // T enabled: @variable gives typed pointer, otherwise untyped pointer
  316. bsSafeDivide, // U
  317. bsVarStringChecks,// V strict shortstring checking, e.g. cannot pass shortstring[3] to shortstring
  318. bsStackframes, // W always generate stackframes (debugging)
  319. bsExtendedSyntax, // X deprecated Delphi directive
  320. bsReferenceInfo, // Y store for each identifier the declaration location
  321. // Z
  322. bsHints,
  323. bsNotes,
  324. bsWarnings,
  325. bsMacro,
  326. bsScopedEnums,
  327. bsObjectChecks, // check methods 'Self' and object type casts
  328. bsPointerMath, // pointer arithmetic
  329. bsGoto // support label and goto, set by {$goto on|off}
  330. );
  331. TBoolSwitches = set of TBoolSwitch;
  332. const
  333. LetterToBoolSwitch: array['A'..'Z'] of TBoolSwitch = (
  334. bsAlign, // A
  335. bsBoolEval, // B
  336. bsAssertions, // C
  337. bsDebugInfo, // D or $description
  338. bsExtension, // E
  339. bsNone, // F
  340. bsImportedData, // G
  341. bsLongStrings, // H
  342. bsIOChecks, // I or $include
  343. bsWriteableConst, // J
  344. bsNone, // K
  345. bsLocalSymbols, // L
  346. bsTypeInfo, // M or $M minstacksize,maxstacksize
  347. bsNone, // N
  348. bsOptimization, // O
  349. bsOpenStrings, // P
  350. bsOverflowChecks, // Q
  351. bsRangeChecks, // R or $resource
  352. bsNone, // S
  353. bsTypedAddress, // T
  354. bsSafeDivide, // U
  355. bsVarStringChecks,// V
  356. bsStackframes, // W
  357. bsExtendedSyntax, // X
  358. bsReferenceInfo, // Y
  359. bsNone // Z
  360. );
  361. bsAll = [low(TBoolSwitch)..high(TBoolSwitch)];
  362. bsFPCMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
  363. bsObjFPCMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
  364. bsDelphiMode: TBoolSwitches = [bsWriteableConst,bsGoto];
  365. bsDelphiUnicodeMode: TBoolSwitches = [bsWriteableConst,bsGoto];
  366. bsMacPasMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
  367. type
  368. TValueSwitch = (
  369. vsInterfaces,
  370. vsDispatchField,
  371. vsDispatchStrField
  372. );
  373. TValueSwitches = set of TValueSwitch;
  374. TValueSwitchArray = array[TValueSwitch] of string;
  375. const
  376. vsAllValueSwitches = [low(TValueSwitch)..high(TValueSwitch)];
  377. DefaultValueSwitches: array[TValueSwitch] of string = (
  378. 'com', // vsInterfaces
  379. 'Msg', // vsDispatchField
  380. 'MsgStr' // vsDispatchStrField
  381. );
  382. DefaultMaxIncludeStackDepth = 20;
  383. type
  384. TWarnMsgState = (
  385. wmsDefault,
  386. wmsOn,
  387. wmsOff,
  388. wmsError
  389. );
  390. type
  391. TTokenOption = (toForceCaret,toOperatorToken);
  392. TTokenOptions = Set of TTokenOption;
  393. { TMacroDef }
  394. TMacroDef = Class(TObject)
  395. Private
  396. FName: String;
  397. FValue: String;
  398. Public
  399. Constructor Create(Const AName,AValue : String);
  400. Property Name : String Read FName;
  401. Property Value : String Read FValue Write FValue;
  402. end;
  403. { TLineReader }
  404. TEOLStyle = (elPlatform,elSource,elLF,elCR,elCRLF);
  405. TLineReader = class
  406. Private
  407. FFilename: string;
  408. Protected
  409. EOLStyle : TEOLStyle;
  410. public
  411. constructor Create(const AFilename: string); virtual;
  412. function IsEOF: Boolean; virtual; abstract;
  413. function ReadLine: string; virtual; abstract;
  414. function LastEOLStyle: TEOLStyle; virtual;
  415. property Filename: string read FFilename;
  416. end;
  417. { TFileLineReader }
  418. TFileLineReader = class(TLineReader)
  419. private
  420. {$ifdef pas2js}
  421. {$else}
  422. FTextFile: Text;
  423. FFileOpened: Boolean;
  424. FBuffer : Array[0..4096-1] of byte;
  425. {$endif}
  426. public
  427. constructor Create(const AFilename: string); override;
  428. destructor Destroy; override;
  429. function IsEOF: Boolean; override;
  430. function ReadLine: string; override;
  431. end;
  432. { TStreamLineReader }
  433. TStreamLineReader = class(TLineReader)
  434. private
  435. FContent: String;
  436. FPos : Integer;
  437. public
  438. {$ifdef HasStreams}
  439. Procedure InitFromStream(AStream : TStream);
  440. {$endif}
  441. Procedure InitFromString(const s: string);
  442. function IsEOF: Boolean; override;
  443. function ReadLine: string; override;
  444. end;
  445. { TFileStreamLineReader }
  446. TFileStreamLineReader = class(TStreamLineReader)
  447. Public
  448. constructor Create(const AFilename: string); override;
  449. end;
  450. { TStringStreamLineReader }
  451. TStringStreamLineReader = class(TStreamLineReader)
  452. Public
  453. constructor Create(const AFilename: string; Const ASource: String); reintroduce;
  454. end;
  455. { TMacroReader }
  456. TMacroReader = Class(TStringStreamLineReader)
  457. private
  458. FCurCol: Integer;
  459. FCurRow: Integer;
  460. Public
  461. Property CurCol : Integer Read FCurCol Write FCurCol;
  462. Property CurRow : Integer Read FCurRow Write FCurRow;
  463. end;
  464. { TBaseFileResolver }
  465. TBaseFileResolver = class
  466. private
  467. FBaseDirectory: string;
  468. FMode: TModeSwitch;
  469. FModuleDirectory: string;
  470. FResourcePaths,
  471. FIncludePaths: TStringList;
  472. FStrictFileCase : Boolean;
  473. Protected
  474. function FindIncludeFileName(const aFilename: string): String; virtual; abstract;
  475. procedure SetBaseDirectory(AValue: string); virtual;
  476. procedure SetModuleDirectory(AValue: string); virtual;
  477. procedure SetStrictFileCase(AValue: Boolean); virtual;
  478. Property IncludePaths: TStringList Read FIncludePaths;
  479. Property ResourcePaths: TStringList Read FResourcePaths;
  480. public
  481. constructor Create; virtual;
  482. destructor Destroy; override;
  483. procedure AddIncludePath(const APath: string); virtual;
  484. procedure AddResourcePath(const APath: string); virtual;
  485. function FindResourceFileName(const AName: string): String; virtual; abstract;
  486. function FindSourceFile(const AName: string): TLineReader; virtual; abstract;
  487. function FindIncludeFile(const AName: string): TLineReader; virtual; abstract;
  488. property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; // e.g. current path of include file
  489. property Mode: TModeSwitch read FMode write FMode;
  490. property ModuleDirectory: string read FModuleDirectory write SetModuleDirectory; // e.g. path of module file
  491. property StrictFileCase : Boolean Read FStrictFileCase Write SetStrictFileCase;
  492. end;
  493. TBaseFileResolverClass = Class of TBaseFileResolver;
  494. {$IFDEF HASFS}
  495. { TFileResolver }
  496. TFileResolver = class(TBaseFileResolver)
  497. private
  498. {$ifdef HasStreams}
  499. FUseStreams: Boolean;
  500. {$endif}
  501. Protected
  502. function SearchLowUpCase(FN: string): string;
  503. Function FindIncludeFileName(const AName: string): String; override;
  504. Function CreateFileReader(Const AFileName : String) : TLineReader; virtual;
  505. Public
  506. function FindResourceFileName(const AFileName: string): String; override;
  507. function FindSourceFile(const AName: string): TLineReader; override;
  508. function FindIncludeFile(const AName: string): TLineReader; override;
  509. {$ifdef HasStreams}
  510. Property UseStreams : Boolean Read FUseStreams Write FUseStreams;
  511. {$endif}
  512. end;
  513. {$ENDIF}
  514. {$ifdef fpc}
  515. { TStreamResolver }
  516. TStreamResolver = class(TBaseFileResolver)
  517. Private
  518. FOwnsStreams: Boolean;
  519. FStreams : TStringList;
  520. function FindStream(const AName: string; ScanIncludes: Boolean): TStream;
  521. function FindStreamReader(const AName: string; ScanIncludes: Boolean): TLineReader;
  522. procedure SetOwnsStreams(AValue: Boolean);
  523. Protected
  524. function FindIncludeFileName(const aFilename: string): String; override;
  525. Public
  526. constructor Create; override;
  527. destructor Destroy; override;
  528. Procedure Clear;
  529. function FindResourceFileName(const AFileName: string): String; override;
  530. Procedure AddStream(Const AName : String; AStream : TStream);
  531. function FindSourceFile(const AName: string): TLineReader; override;
  532. function FindIncludeFile(const AName: string): TLineReader; override;
  533. Property OwnsStreams : Boolean Read FOwnsStreams write SetOwnsStreams;
  534. Property Streams: TStringList read FStreams;
  535. end;
  536. {$endif}
  537. const
  538. CondDirectiveBool: array[boolean] of string = (
  539. '0', // false
  540. '1' // true Note: True is <>'0'
  541. );
  542. MACDirectiveBool: array[boolean] of string = (
  543. 'FALSE', // false
  544. 'TRUE' // true Note: True is <>'0'
  545. );
  546. type
  547. TMaxPrecInt = {$ifdef fpc}int64{$else}NativeInt{$endif};
  548. TMaxFloat = {$ifdef fpc}extended{$else}double{$endif};
  549. TCondDirectiveEvaluator = class;
  550. TCEEvalVarEvent = function(Sender: TCondDirectiveEvaluator; Name: String; out Value: string): boolean of object;
  551. TCEEvalFunctionEvent = function(Sender: TCondDirectiveEvaluator; Name, Param: String; out Value: string): boolean of object;
  552. TCELogEvent = procedure(Sender: TCondDirectiveEvaluator; Args : Array of const) of object;
  553. { TCondDirectiveEvaluator - evaluate $IF expression }
  554. TCondDirectiveEvaluator = class
  555. private
  556. FOnEvalFunction: TCEEvalFunctionEvent;
  557. FOnEvalVariable: TCEEvalVarEvent;
  558. FOnLog: TCELogEvent;
  559. protected
  560. type
  561. TPrecedenceLevel = (
  562. ceplFirst, // tkNot
  563. ceplSecond, // *, /, div, mod, and, shl, shr
  564. ceplThird, // +, -, or, xor
  565. ceplFourth // =, <>, <, >, <=, >=
  566. );
  567. TStackItem = record
  568. Level: TPrecedenceLevel;
  569. Operathor: TToken;
  570. Operand: String;
  571. OperandPos: integer;
  572. end;
  573. protected
  574. {$ifdef UsePChar}
  575. FTokenStart: PChar;
  576. FTokenEnd: PChar;
  577. {$else}
  578. FTokenStart: integer; // position in Expression
  579. FTokenEnd: integer; // position in Expression
  580. {$endif}
  581. FToken: TToken;
  582. FStack: array of TStackItem;
  583. FStackTop: integer;
  584. function IsFalse(const Value: String): boolean; inline;
  585. function IsTrue(const Value: String): boolean; inline;
  586. function IsInteger(const Value: String; out i: TMaxPrecInt): boolean;
  587. function IsExtended(const Value: String; out e: TMaxFloat): boolean;
  588. procedure NextToken;
  589. procedure Log(aMsgType: TMessageType; aMsgNumber: integer;
  590. const aMsgFmt: String; const Args: array of const; MsgPos: integer = 0);
  591. procedure LogXExpectedButTokenFound(const X: String; ErrorPos: integer = 0);
  592. procedure ReadOperand(Skip: boolean = false); // unary operators plus one operand
  593. procedure ReadExpression; // binary operators
  594. procedure ResolveStack(MinStackLvl: integer; Level: TPrecedenceLevel;
  595. NewOperator: TToken);
  596. function GetTokenString: String;
  597. function GetStringLiteralValue: String; // read value of tkString
  598. procedure Push(const AnOperand: String; OperandPosition: integer);
  599. public
  600. Expression: String;
  601. MsgCurLine : Integer;
  602. MsgPos: integer;
  603. MsgNumber: integer;
  604. MsgType: TMessageType;
  605. MsgPattern: String; // Format parameter
  606. isMac : Boolean;
  607. constructor Create(aIsMac : Boolean = False);
  608. destructor Destroy; override;
  609. function Eval(const Expr: string): boolean;
  610. property OnEvalVariable: TCEEvalVarEvent read FOnEvalVariable write FOnEvalVariable;
  611. property OnEvalFunction: TCEEvalFunctionEvent read FOnEvalFunction write FOnEvalFunction;
  612. property OnLog: TCELogEvent read FOnLog write FOnLog;
  613. end;
  614. EScannerError = class(Exception);
  615. EFileNotFoundError = class(Exception);
  616. TPascalScannerPPSkipMode = (ppSkipNone, ppSkipIfBranch, ppSkipElseBranch, ppSkipAll);
  617. TPOption = (
  618. po_delphi, // DEPRECATED since fpc 3.1.1: Delphi mode: forbid nested comments
  619. po_KeepScannerError, // default: catch EScannerError and raise an EParserError instead
  620. po_CAssignments, // allow C-operators += -= *= /=
  621. po_ResolveStandardTypes, // search for 'longint', 'string', etc., do not use dummies, TPasResolver sets this to use its declarations
  622. po_AsmWhole, // store whole text between asm..end in TPasImplAsmStatement.Tokens
  623. po_NoOverloadedProcs, // do not create TPasOverloadedProc for procs with same name
  624. po_KeepClassForward, // disabled: delete class fowards when there is a class declaration
  625. po_ArrayRangeExpr, // enable: create TPasArrayType.IndexRange, disable: create TPasArrayType.Ranges
  626. po_SelfToken, // Self is a token. For backward compatibility.
  627. po_CheckModeSwitches, // error on unknown modeswitch with an error
  628. po_CheckCondFunction, // error on unknown function in conditional expression, default: return '0'
  629. po_StopOnErrorDirective, // error on user $Error, $message error|fatal
  630. po_ExtConstWithoutExpr, // allow typed const without expression in external class and with external modifier
  631. po_StopOnUnitInterface, // parse only a unit name and stop at interface keyword
  632. po_IgnoreUnknownResource,// Ignore resources for which no handler is registered.
  633. po_AsyncProcs, // allow async procedure modifier
  634. po_DisableResources // Disable resources altogether
  635. );
  636. TPOptions = set of TPOption;
  637. type
  638. TPasSourcePos = Record
  639. FileName: String;
  640. Row, Column: Cardinal;
  641. end;
  642. const
  643. DefPasSourcePos: TPasSourcePos = (Filename:''; Row:0; Column:0);
  644. type
  645. { TPascalScanner }
  646. TPScannerLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
  647. TPScannerLogEvent = (sleFile,sleLineNumber,sleConditionals,sleDirective);
  648. TPScannerLogEvents = Set of TPScannerLogEvent;
  649. TPScannerDirectiveEvent = procedure(Sender: TObject; Directive, Param: String; var Handled: boolean) of object;
  650. TPScannerCommentEvent = procedure(Sender: TObject; aComment : String) of object;
  651. TPScannerFormatPathEvent = function(const aPath: string): string of object;
  652. TPScannerWarnEvent = procedure(Sender: TObject; Identifier: string; State: TWarnMsgState; var Handled: boolean) of object;
  653. TPScannerModeDirective = procedure(Sender: TObject; NewMode: TModeSwitch; Before: boolean; var Handled: boolean) of object;
  654. TPScannerLinkLibEvent = procedure(Sender: TObject; Const aLibName,aLibAlias,aLibOptions : String; var Handled: boolean) of object;
  655. // aFileName: full filename (search is already done) aOptions: list of name:value pairs.
  656. TResourceHandler = Procedure (Sender : TObject; const aFileName : String; aOptions : TStrings) of object;
  657. TPasScannerTokenPos = {$ifdef UsePChar}PChar{$else}integer{$endif};
  658. TPascalScanner = class
  659. private
  660. type
  661. TResourceHandlerRecord = record
  662. Ext : String;
  663. Handler : TResourceHandler;
  664. end;
  665. TWarnMsgNumberState = record
  666. Number: integer;
  667. State: TWarnMsgState;
  668. end;
  669. TWarnMsgNumberStateArr = array of TWarnMsgNumberState;
  670. private
  671. FAllowedBoolSwitches: TBoolSwitches;
  672. FAllowedModeSwitches: TModeSwitches;
  673. FAllowedValueSwitches: TValueSwitches;
  674. FConditionEval: TCondDirectiveEvaluator;
  675. FCurModulename: string;
  676. FCurrentBoolSwitches: TBoolSwitches;
  677. FCurrentModeSwitches: TModeSwitches;
  678. FCurrentValueSwitches: TValueSwitchArray;
  679. FCurTokenPos: TPasSourcePos;
  680. FLastMsg: string;
  681. FLastMsgArgs: TMessageArgs;
  682. FLastMsgNumber: integer;
  683. FLastMsgPattern: string;
  684. FLastMsgType: TMessageType;
  685. FFileResolver: TBaseFileResolver;
  686. FCurSourceFile: TLineReader;
  687. FCurFilename: string;
  688. FCurRow: Integer;
  689. FCurColumnOffset: integer;
  690. FCurToken: TToken;
  691. FCurTokenString: string;
  692. FCurLine: string;
  693. FMaxIncludeStackDepth: integer;
  694. FModuleRow: Integer;
  695. FMacros: TStrings; // Objects are TMacroDef
  696. FDefines: TStrings;
  697. FMultilineLineFeedStyle: TEOLStyle;
  698. FMultilineLineTrimLeft: Integer;
  699. FNonTokens: TTokens;
  700. FOnComment: TPScannerCommentEvent;
  701. FOnDirective: TPScannerDirectiveEvent;
  702. FOnEvalFunction: TCEEvalFunctionEvent;
  703. FOnEvalVariable: TCEEvalVarEvent;
  704. FOnFormatPath: TPScannerFormatPathEvent;
  705. FOnLinkLib: TPScannerLinkLibEvent;
  706. FOnModeChanged: TPScannerModeDirective;
  707. FOnWarnDirective: TPScannerWarnEvent;
  708. FOptions: TPOptions;
  709. FLogEvents: TPScannerLogEvents;
  710. FOnLog: TPScannerLogHandler;
  711. FPreviousToken: TToken;
  712. FReadOnlyBoolSwitches: TBoolSwitches;
  713. FReadOnlyModeSwitches: TModeSwitches;
  714. FReadOnlyValueSwitches: TValueSwitches;
  715. FSkipComments: Boolean;
  716. FSkipGlobalSwitches: boolean;
  717. FSkipWhiteSpace: Boolean;
  718. FTokenOptions: TTokenOptions;
  719. FTokenPos: TPasScannerTokenPos; // position in FCurLine }
  720. FIncludeStack: TFPList;
  721. FFiles: TStrings;
  722. FWarnMsgStates: TWarnMsgNumberStateArr;
  723. FResourceHandlers : Array of TResourceHandlerRecord;
  724. // Preprocessor $IFxxx skipping data
  725. PPSkipMode: TPascalScannerPPSkipMode;
  726. PPIsSkipping: Boolean;
  727. PPSkipStackIndex: Integer;
  728. PPSkipModeStack: array[0..255] of TPascalScannerPPSkipMode;
  729. PPIsSkippingStack: array[0..255] of Boolean;
  730. function GetCurColumn: Integer;
  731. function GetCurrentValueSwitch(V: TValueSwitch): string;
  732. function GetForceCaret: Boolean;
  733. function GetMacrosOn: boolean;
  734. function IndexOfWarnMsgState(Number: integer; InsertPos: boolean): integer;
  735. function OnCondEvalFunction(Sender: TCondDirectiveEvaluator; Name,
  736. Param: String; out Value: string): boolean;
  737. procedure OnCondEvalLog(Sender: TCondDirectiveEvaluator; Args: array of const);
  738. function OnCondEvalVar(Sender: TCondDirectiveEvaluator; Name: String; out
  739. Value: string): boolean;
  740. procedure SetAllowedBoolSwitches(const AValue: TBoolSwitches);
  741. procedure SetAllowedModeSwitches(const AValue: TModeSwitches);
  742. procedure SetAllowedValueSwitches(const AValue: TValueSwitches);
  743. procedure SetMacrosOn(const AValue: boolean);
  744. procedure SetOptions(AValue: TPOptions);
  745. procedure SetReadOnlyBoolSwitches(const AValue: TBoolSwitches);
  746. procedure SetReadOnlyModeSwitches(const AValue: TModeSwitches);
  747. procedure SetReadOnlyValueSwitches(const AValue: TValueSwitches);
  748. protected
  749. // extension without initial dot (.)
  750. Function IndexOfResourceHandler(Const aExt : string) : Integer;
  751. Function FindResourceHandler(Const aExt : string) : TResourceHandler;
  752. function ReadIdentifier(const AParam: string): string;
  753. function FetchLine: boolean;
  754. procedure AddFile(aFilename: string); virtual;
  755. function GetMacroName(const Param: String): String;
  756. procedure SetCurMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const);
  757. Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Msg : String; SkipSourceInfo : Boolean = False);overload;
  758. Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
  759. procedure Error(MsgNumber: integer; const Msg: string);overload;
  760. procedure Error(MsgNumber: integer; const Fmt: string; Args: array of const);overload;
  761. procedure PushSkipMode;
  762. function GetMultiLineStringLineEnd(aReader: TLineReader): string;
  763. function MakeLibAlias(const LibFileName: String): string; virtual;
  764. function HandleDirective(const ADirectiveText: String): TToken; virtual;
  765. function HandleLetterDirective(Letter: char; Enable: boolean): TToken; virtual;
  766. procedure HandleBoolDirective(bs: TBoolSwitch; const Param: String); virtual;
  767. procedure DoHandleComment(Sender: TObject; const aComment : string); virtual;
  768. procedure DoHandleDirective(Sender: TObject; Directive, Param: String;
  769. var Handled: boolean); virtual;
  770. procedure HandleMultilineStringTrimLeft(const AParam : String);
  771. procedure HandleMultilineStringLineEnding(const AParam : string);
  772. procedure HandleIFDEF(const AParam: String);
  773. procedure HandleIFNDEF(const AParam: String);
  774. procedure HandleIFOPT(const AParam: String);
  775. procedure HandleIF(const AParam: String; aIsMac : Boolean);
  776. procedure HandleELSEIF(const AParam: String; aIsMac : Boolean);
  777. procedure HandleELSE(const AParam: String);
  778. procedure HandleENDIF(const AParam: String);
  779. procedure HandleDefine(Param: String); virtual;
  780. procedure HandleDispatchField(Param: String; vs: TValueSwitch); virtual;
  781. procedure HandleError(Param: String); virtual;
  782. procedure HandleMessageDirective(Param: String); virtual;
  783. procedure HandleIncludeFile(Param: String); virtual;
  784. procedure HandleIncludeString(Param: String); virtual;
  785. procedure HandleResource(Param : string); virtual;
  786. procedure HandleLinkLib(Param : string); virtual;
  787. procedure HandleOptimizations(Param : string); virtual;
  788. procedure DoHandleOptimization(OptName, OptValue: string); virtual;
  789. procedure HandleUnDefine(Param: String); virtual;
  790. function HandleInclude(const Param: String): TToken; virtual;
  791. procedure HandleMode(const Param: String); virtual;
  792. procedure HandleModeSwitch(const Param: String); virtual;
  793. function HandleMacro(AIndex: integer): TToken; virtual;
  794. procedure HandleInterfaces(const Param: String); virtual;
  795. procedure HandleWarn(Param: String); virtual;
  796. procedure HandleWarnIdentifier(Identifier, Value: String); virtual;
  797. procedure PushStackItem; virtual;
  798. procedure PopStackItem; virtual;
  799. function DoFetchTextToken: TToken;
  800. function DoFetchMultilineTextToken: TToken;
  801. function DoFetchToken: TToken;
  802. procedure ClearFiles;
  803. Procedure ClearMacros;
  804. Procedure SetCurToken(const AValue: TToken);
  805. Procedure SetCurTokenString(const AValue: string);
  806. procedure SetCurrentBoolSwitches(const AValue: TBoolSwitches); virtual;
  807. procedure SetCurrentModeSwitches(AValue: TModeSwitches); virtual;
  808. procedure SetCurrentValueSwitch(V: TValueSwitch; const AValue: string);
  809. procedure SetWarnMsgState(Number: integer; State: TWarnMsgState); virtual;
  810. function GetWarnMsgState(Number: integer): TWarnMsgState; virtual;
  811. function LogEvent(E : TPScannerLogEvent) : Boolean; inline;
  812. property TokenPos: TPasScannerTokenPos read FTokenPos write FTokenPos;
  813. public
  814. constructor Create(AFileResolver: TBaseFileResolver);
  815. destructor Destroy; override;
  816. // extension without initial dot (.), case insensitive
  817. Procedure RegisterResourceHandler(aExtension : String; aHandler : TResourceHandler); overload;
  818. Procedure RegisterResourceHandler(aExtensions : Array of String; aHandler : TResourceHandler); overload;
  819. procedure OpenFile(AFilename: string);
  820. procedure FinishedModule; virtual; // called by parser after end.
  821. function FormatPath(const aFilename: string): string; virtual;
  822. procedure SetNonToken(aToken : TToken);
  823. procedure UnsetNonToken(aToken : TToken);
  824. procedure SetTokenOption(aOption : TTokenoption);
  825. procedure UnSetTokenOption(aOption : TTokenoption);
  826. function CheckToken(aToken : TToken; const ATokenString : String) : TToken;
  827. function FetchToken: TToken;
  828. function ReadNonPascalTillEndToken(StopAtLineEnd: boolean): TToken; virtual;
  829. function AddDefine(const aName: String; Quiet: boolean = false): boolean;
  830. function RemoveDefine(const aName: String; Quiet: boolean = false): boolean;
  831. function UnDefine(const aName: String; Quiet: boolean = false): boolean; // check defines and macros
  832. function IsDefined(const aName: String): boolean; // check defines and macros
  833. function IfOpt(Letter: Char): boolean;
  834. function AddMacro(const aName, aValue: String; Quiet: boolean = false): boolean;
  835. function RemoveMacro(const aName: String; Quiet: boolean = false): boolean;
  836. procedure SetCompilerMode(S : String);
  837. function CurSourcePos: TPasSourcePos;
  838. function SetForceCaret(AValue : Boolean) : Boolean; // returns old state
  839. function IgnoreMsgType(MsgType: TMessageType): boolean; virtual;
  840. property FileResolver: TBaseFileResolver read FFileResolver;
  841. property Files: TStrings read FFiles;
  842. property CurSourceFile: TLineReader read FCurSourceFile;
  843. property CurFilename: string read FCurFilename;
  844. property CurModuleName: string read FCurModulename Write FCurModuleName;
  845. property CurLine: string read FCurLine;
  846. property CurRow: Integer read FCurRow;
  847. property CurColumn: Integer read GetCurColumn;
  848. property CurToken: TToken read FCurToken;
  849. property CurTokenString: string read FCurTokenString;
  850. property CurTokenPos: TPasSourcePos read FCurTokenPos;
  851. property PreviousToken : TToken Read FPreviousToken;
  852. property ModuleRow: Integer read FModuleRow;
  853. property NonTokens : TTokens Read FNonTokens;
  854. Property TokenOptions : TTokenOptions Read FTokenOptions Write FTokenOptions;
  855. property Defines: TStrings read FDefines;
  856. property Macros: TStrings read FMacros;
  857. property MacrosOn: boolean read GetMacrosOn write SetMacrosOn;
  858. property AllowedModeSwitches: TModeSwitches read FAllowedModeSwitches Write SetAllowedModeSwitches;
  859. property ReadOnlyModeSwitches: TModeSwitches read FReadOnlyModeSwitches Write SetReadOnlyModeSwitches;// always set, cannot be disabled
  860. property CurrentModeSwitches: TModeSwitches read FCurrentModeSwitches Write SetCurrentModeSwitches;
  861. property AllowedBoolSwitches: TBoolSwitches read FAllowedBoolSwitches Write SetAllowedBoolSwitches;
  862. property ReadOnlyBoolSwitches: TBoolSwitches read FReadOnlyBoolSwitches Write SetReadOnlyBoolSwitches;// cannot be changed by code
  863. property CurrentBoolSwitches: TBoolSwitches read FCurrentBoolSwitches Write SetCurrentBoolSwitches;
  864. property AllowedValueSwitches: TValueSwitches read FAllowedValueSwitches Write SetAllowedValueSwitches;
  865. property ReadOnlyValueSwitches: TValueSwitches read FReadOnlyValueSwitches Write SetReadOnlyValueSwitches;// cannot be changed by code
  866. property CurrentValueSwitch[V: TValueSwitch]: string read GetCurrentValueSwitch Write SetCurrentValueSwitch;
  867. property WarnMsgState[Number: integer]: TWarnMsgState read GetWarnMsgState write SetWarnMsgState;
  868. property Options : TPOptions read FOptions write SetOptions;
  869. property SkipWhiteSpace : Boolean Read FSkipWhiteSpace Write FSkipWhiteSpace;
  870. property SkipComments : Boolean Read FSkipComments Write FSkipComments;
  871. property SkipGlobalSwitches: Boolean read FSkipGlobalSwitches write FSkipGlobalSwitches;
  872. property MaxIncludeStackDepth: integer read FMaxIncludeStackDepth write FMaxIncludeStackDepth default DefaultMaxIncludeStackDepth;
  873. property ForceCaret : Boolean read GetForceCaret;
  874. Property MultilineLineFeedStyle : TEOLStyle Read FMultilineLineFeedStyle Write FMultilineLineFeedStyle;
  875. Property MultilineLineTrimLeft : Integer Read FMultilineLineTrimLeft Write FMultilineLineTrimLeft;
  876. property LogEvents : TPScannerLogEvents read FLogEvents write FLogEvents;
  877. property OnLog : TPScannerLogHandler read FOnLog write FOnLog;
  878. property OnFormatPath: TPScannerFormatPathEvent read FOnFormatPath write FOnFormatPath;
  879. property ConditionEval: TCondDirectiveEvaluator read FConditionEval;
  880. property OnEvalVariable: TCEEvalVarEvent read FOnEvalVariable write FOnEvalVariable;
  881. property OnEvalFunction: TCEEvalFunctionEvent read FOnEvalFunction write FOnEvalFunction;
  882. property OnWarnDirective: TPScannerWarnEvent read FOnWarnDirective write FOnWarnDirective;
  883. property OnModeChanged: TPScannerModeDirective read FOnModeChanged write FOnModeChanged; // set by TPasParser
  884. property OnDirective: TPScannerDirectiveEvent read FOnDirective write FOnDirective;
  885. property OnComment: TPScannerCommentEvent read FOnComment write FOnComment;
  886. Property OnLinkLib : TPScannerLinkLibEvent Read FOnLinkLib Write FOnLinkLib;
  887. property LastMsg: string read FLastMsg write FLastMsg;
  888. property LastMsgNumber: integer read FLastMsgNumber write FLastMsgNumber;
  889. property LastMsgType: TMessageType read FLastMsgType write FLastMsgType;
  890. property LastMsgPattern: string read FLastMsgPattern write FLastMsgPattern;
  891. property LastMsgArgs: TMessageArgs read FLastMsgArgs write FLastMsgArgs;
  892. end;
  893. const
  894. TokenInfos: array[TToken] of string = (
  895. 'EOF',
  896. 'Whitespace',
  897. 'Comment',
  898. 'Identifier',
  899. 'string',
  900. 'Number',
  901. 'Character',
  902. '(',
  903. ')',
  904. '*',
  905. '+',
  906. ',',
  907. '-',
  908. '.',
  909. '/',
  910. ':',
  911. ';',
  912. '<',
  913. '=',
  914. '>',
  915. '@',
  916. '[',
  917. ']',
  918. '^',
  919. '\',
  920. '..',
  921. ':=',
  922. '<>',
  923. '<=',
  924. '>=',
  925. '**',
  926. '><',
  927. '+=',
  928. '-=',
  929. '*=',
  930. '/=',
  931. '@@',
  932. '...',
  933. // Reserved words
  934. 'absolute',
  935. 'and',
  936. 'array',
  937. 'as',
  938. 'asm',
  939. 'begin',
  940. 'bitpacked',
  941. 'case',
  942. 'class',
  943. 'const',
  944. 'constref',
  945. 'constructor',
  946. 'destructor',
  947. 'dispinterface',
  948. 'div',
  949. 'do',
  950. 'downto',
  951. 'else',
  952. 'end',
  953. 'except',
  954. 'exports',
  955. 'false',
  956. 'file',
  957. 'finalization',
  958. 'finally',
  959. 'for',
  960. 'function',
  961. 'generic',
  962. 'goto',
  963. 'if',
  964. 'implementation',
  965. 'in',
  966. 'inherited',
  967. 'initialization',
  968. 'inline',
  969. 'interface',
  970. 'is',
  971. 'label',
  972. 'library',
  973. 'mod',
  974. 'nil',
  975. 'not',
  976. 'objccategory',
  977. 'objcclass',
  978. 'objcprotocol',
  979. 'object',
  980. 'of',
  981. 'operator',
  982. 'or',
  983. 'otherwise',
  984. 'packed',
  985. 'procedure',
  986. 'program',
  987. 'property',
  988. 'raise',
  989. 'record',
  990. 'repeat',
  991. 'resourcestring',
  992. 'self',
  993. 'set',
  994. 'shl',
  995. 'shr',
  996. 'specialize',
  997. // 'string',
  998. 'then',
  999. 'threadvar',
  1000. 'to',
  1001. 'true',
  1002. 'try',
  1003. 'type',
  1004. 'unit',
  1005. 'until',
  1006. 'uses',
  1007. 'var',
  1008. 'while',
  1009. 'with',
  1010. 'xor',
  1011. 'LineEnding',
  1012. 'Tab'
  1013. );
  1014. SModeSwitchNames : array[TModeSwitch] of string =
  1015. ( '', // msNone
  1016. '', // Fpc,
  1017. '', // Objfpc,
  1018. '', // Delphi,
  1019. '', // DelphiUnicode,
  1020. '', // TP7,
  1021. '', // Mac,
  1022. '', // Iso,
  1023. '', // Extpas,
  1024. '', // GPC,
  1025. { more specific }
  1026. 'CLASS',
  1027. 'OBJPAS',
  1028. 'RESULT',
  1029. 'PCHARTOSTRING',
  1030. 'CVAR',
  1031. 'NESTEDCOMMENTS',
  1032. 'CLASSICPROCVARS',
  1033. 'MACPROCVARS',
  1034. 'REPEATFORWARD',
  1035. 'POINTERTOPROCVAR',
  1036. 'AUTODEREF',
  1037. 'INITFINAL',
  1038. 'ANSISTRINGS',
  1039. 'OUT',
  1040. 'DEFAULTPARAMETERS',
  1041. 'HINTDIRECTIVE',
  1042. 'DUPLICATELOCALS',
  1043. 'PROPERTIES',
  1044. 'ALLOWINLINE',
  1045. 'EXCEPTIONS',
  1046. 'OBJECTIVEC1',
  1047. 'OBJECTIVEC2',
  1048. 'NESTEDPROCVARS',
  1049. 'NONLOCALGOTO',
  1050. 'ADVANCEDRECORDS',
  1051. 'ISOUNARYMINUS',
  1052. 'SYSTEMCODEPAGE',
  1053. 'FINALFIELDS',
  1054. 'UNICODESTRINGS',
  1055. 'TYPEHELPERS',
  1056. 'CBLOCKS',
  1057. 'ISOIO',
  1058. 'ISOPROGRAMPARAS',
  1059. 'ISOMOD',
  1060. 'ARRAYOPERATORS',
  1061. 'EXTERNALCLASS',
  1062. 'PREFIXEDATTRIBUTES',
  1063. 'OMITRTTI',
  1064. 'MULTIHELPERS',
  1065. 'IMPLICITFUNCTIONSPECIALIZATION',
  1066. 'MULTILINESTRINGS'
  1067. );
  1068. LetterSwitchNames: array['A'..'Z'] of string=(
  1069. 'ALIGN' // A align fields
  1070. ,'BOOLEVAL' // B complete boolean evaluation
  1071. ,'ASSERTIONS' // C generate code for assertions
  1072. ,'DEBUGINFO' // D generate debuginfo (debug lines), OR: $description 'text'
  1073. ,'EXTENSION' // E output file extension
  1074. ,'' // F
  1075. ,'IMPORTEDDATA' // G
  1076. ,'LONGSTRINGS' // H String=AnsiString
  1077. ,'IOCHECKS' // I generate EInOutError
  1078. ,'WRITEABLECONST' // J writable typed const
  1079. ,'' // K
  1080. ,'LOCALSYMBOLS' // L generate local symbol information (debug, requires $D+)
  1081. ,'TYPEINFO' // M allow published members OR $M minstacksize,maxstacksize
  1082. ,'' // N
  1083. ,'OPTIMIZATION' // O enable safe optimizations (-O1)
  1084. ,'OPENSTRINGS' // P deprecated Delphi directive
  1085. ,'OVERFLOWCHECKS' // Q
  1086. ,'RANGECHECKS' // R OR resource
  1087. ,'' // S
  1088. ,'TYPEDADDRESS' // T enabled: @variable gives typed pointer, otherwise untyped pointer
  1089. ,'SAFEDIVIDE' // U
  1090. ,'VARSTRINGCHECKS'// V strict shortstring checking, e.g. cannot pass shortstring[3] to shortstring
  1091. ,'STACKFRAMES' // W always generate stackframes (debugging)
  1092. ,'EXTENDEDSYNTAX' // X deprecated Delphi directive
  1093. ,'REFERENCEINFO' // Y store for each identifier the declaration location
  1094. ,'' // Z
  1095. );
  1096. BoolSwitchNames: array[TBoolSwitch] of string = (
  1097. // letter directives
  1098. 'None',
  1099. 'Align',
  1100. 'BoolEval',
  1101. 'Assertions',
  1102. 'DebugInfo',
  1103. 'Extension',
  1104. 'ImportedData',
  1105. 'LongStrings',
  1106. 'IOChecks',
  1107. 'WriteableConst',
  1108. 'LocalSymbols',
  1109. 'TypeInfo',
  1110. 'Optimization',
  1111. 'OpenStrings',
  1112. 'OverflowChecks',
  1113. 'RangeChecks',
  1114. 'TypedAddress',
  1115. 'SafeDivide',
  1116. 'VarStringChecks',
  1117. 'Stackframes',
  1118. 'ExtendedSyntax',
  1119. 'ReferenceInfo',
  1120. // other bool directives
  1121. 'Hints',
  1122. 'Notes',
  1123. 'Warnings',
  1124. 'Macro',
  1125. 'ScopedEnums',
  1126. 'ObjectChecks',
  1127. 'PointerMath',
  1128. 'Goto'
  1129. );
  1130. ValueSwitchNames: array[TValueSwitch] of string = (
  1131. 'Interfaces', // vsInterfaces
  1132. 'DispatchField', // vsDispatchField
  1133. 'DispatchStrField' // vsDispatchStrField
  1134. );
  1135. const
  1136. MessageTypeNames : Array[TMessageType] of string = (
  1137. 'Fatal','Error','Warning','Note','Hint','Info','Debug'
  1138. );
  1139. const
  1140. // all mode switches supported by FPC
  1141. msAllModeSwitches = [low(TModeSwitch)..High(TModeSwitch)];
  1142. AllLanguageModes = [msFPC..msGPC];
  1143. DelphiModeSwitches = [msDelphi,msClass,msObjpas,msResult,msStringPchar,
  1144. msPointer2Procedure,msAutoDeref,msTPProcVar,msInitFinal,msDefaultAnsistring,
  1145. msOut,msDefaultPara,msDuplicateNames,msHintDirective,
  1146. msProperty,msDefaultInline,msExcept,msAdvancedRecords,msTypeHelpers,
  1147. msPrefixedAttributes,msArrayOperators,msImplicitFunctionSpec
  1148. ];
  1149. DelphiUnicodeModeSwitches = delphimodeswitches + [msSystemCodePage,msDefaultUnicodestring];
  1150. // mode switches of $mode FPC, don't confuse with msAllModeSwitches
  1151. FPCModeSwitches = [msFpc,msStringPchar,msNestedComment,msRepeatForward,
  1152. msCVarSupport,msInitFinal,msHintDirective,msProperty,msDefaultInline];
  1153. //FPCBoolSwitches bsObjectChecks
  1154. OBJFPCModeSwitches = [msObjfpc,msClass,msObjpas,msResult,msStringPchar,msNestedComment,
  1155. msRepeatForward,msCVarSupport,msInitFinal,msOut,msDefaultPara,msHintDirective,
  1156. msProperty,msDefaultInline,msExcept];
  1157. TPModeSwitches = [msTP7,msTPProcVar,msDuplicateNames];
  1158. GPCModeSwitches = [msGPC,msTPProcVar];
  1159. MacModeSwitches = [msMac,msCVarSupport,msMacProcVar,msNestedProcVars,
  1160. msNonLocalGoto,msISOLikeUnaryMinus,msDefaultInline];
  1161. ISOModeSwitches = [msIso,msTPProcVar,msDuplicateNames,msNestedProcVars,
  1162. msNonLocalGoto,msISOLikeUnaryMinus,msISOLikeIO,msISOLikeProgramsPara,
  1163. msISOLikeMod];
  1164. ExtPasModeSwitches = [msExtpas,msTPProcVar,msDuplicateNames,msNestedProcVars,
  1165. msNonLocalGoto,msISOLikeUnaryMinus,msISOLikeIO,msISOLikeProgramsPara,
  1166. msISOLikeMod];
  1167. function StrToModeSwitch(aName: String): TModeSwitch;
  1168. function ModeSwitchesToStr(Switches: TModeSwitches): string;
  1169. function BoolSwitchesToStr(Switches: TBoolSwitches): string;
  1170. function FilenameIsAbsolute(const TheFilename: string):boolean;
  1171. function FilenameIsWinAbsolute(const TheFilename: string): boolean;
  1172. function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
  1173. function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
  1174. Function ExtractFilenameOnly(Const AFileName : String) : String;
  1175. procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of const);
  1176. function SafeFormat(const Fmt: string; Args: array of const): string;
  1177. implementation
  1178. const
  1179. IdentChars = ['0'..'9', 'A'..'Z', 'a'..'z','_'];
  1180. Digits = ['0'..'9'];
  1181. Letters = ['a'..'z','A'..'Z'];
  1182. HexDigits = ['0'..'9','a'..'f','A'..'F'];
  1183. Var
  1184. SortedTokens : array of TToken;
  1185. LowerCaseTokens : Array[ttoken] of String;
  1186. Function ExtractFilenameOnly(Const AFileName : String) : String;
  1187. begin
  1188. Result:=ChangeFileExt(ExtractFileName(aFileName),'');
  1189. end;
  1190. Procedure SortTokenInfo;
  1191. Var
  1192. tk: tToken;
  1193. I,J,K, l: integer;
  1194. begin
  1195. for tk:=Low(TToken) to High(ttoken) do
  1196. LowerCaseTokens[tk]:=LowerCase(TokenInfos[tk]);
  1197. SetLength(SortedTokens,Ord(tkXor)-Ord(tkAbsolute)+1);
  1198. I:=0;
  1199. for tk := tkAbsolute to tkXOR do
  1200. begin
  1201. SortedTokens[i]:=tk;
  1202. Inc(i);
  1203. end;
  1204. l:=Length(SortedTokens)-1;
  1205. k:=l shr 1;
  1206. while (k>0) do
  1207. begin
  1208. for i:=0 to l-k do
  1209. begin
  1210. j:=i;
  1211. while (J>=0) and (LowerCaseTokens[SortedTokens[J]]>LowerCaseTokens[SortedTokens[J+K]]) do
  1212. begin
  1213. tk:=SortedTokens[J];
  1214. SortedTokens[J]:=SortedTokens[J+K];
  1215. SortedTokens[J+K]:=tk;
  1216. if (J>K) then
  1217. Dec(J,K)
  1218. else
  1219. J := 0
  1220. end;
  1221. end;
  1222. K:=K shr 1;
  1223. end;
  1224. end;
  1225. function IndexOfToken(Const AToken : string) : Integer;
  1226. var
  1227. B,T,M : Integer;
  1228. N : String;
  1229. begin
  1230. B:=0;
  1231. T:=Length(SortedTokens)-1;
  1232. while (B<=T) do
  1233. begin
  1234. M:=(B+T) div 2;
  1235. N:=LowerCaseTokens[SortedTokens[M]];
  1236. if (AToken<N) then
  1237. T:=M-1
  1238. else if (AToken=N) then
  1239. Exit(M)
  1240. else
  1241. B:=M+1;
  1242. end;
  1243. Result:=-1;
  1244. end;
  1245. function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
  1246. Var
  1247. I : Integer;
  1248. begin
  1249. if (Length(SortedTokens)=0) then
  1250. SortTokenInfo;
  1251. I:=IndexOfToken(LowerCase(AToken));
  1252. Result:=I<>-1;
  1253. If Result then
  1254. T:=SortedTokens[I];
  1255. end;
  1256. procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of const);
  1257. var
  1258. i: Integer;
  1259. {$ifdef pas2js}
  1260. v: jsvalue;
  1261. {$endif}
  1262. begin
  1263. SetLength(MsgArgs, High(Args)-Low(Args)+1);
  1264. for i:=Low(Args) to High(Args) do
  1265. {$ifdef pas2js}
  1266. begin
  1267. v:=Args[i];
  1268. if isBoolean(v) then
  1269. MsgArgs[i] := BoolToStr(Boolean(v))
  1270. else if isString(v) then
  1271. MsgArgs[i] := String(v)
  1272. else if isNumber(v) then
  1273. begin
  1274. if IsInteger(v) then
  1275. MsgArgs[i] := str(NativeInt(v))
  1276. else
  1277. MsgArgs[i] := str(double(v));
  1278. end
  1279. else
  1280. MsgArgs[i]:='';
  1281. end;
  1282. {$else}
  1283. case Args[i].VType of
  1284. vtInteger: MsgArgs[i] := IntToStr(Args[i].VInteger);
  1285. vtBoolean: MsgArgs[i] := BoolToStr(Args[i].VBoolean);
  1286. vtChar: MsgArgs[i] := Args[i].VChar;
  1287. {$ifndef FPUNONE}
  1288. vtExtended: ; // Args[i].VExtended^;
  1289. {$ENDIF}
  1290. vtString: MsgArgs[i] := Args[i].VString^;
  1291. vtPointer: ; // Args[i].VPointer;
  1292. vtPChar: MsgArgs[i] := Args[i].VPChar;
  1293. vtObject: ; // Args[i].VObject;
  1294. vtClass: ; // Args[i].VClass;
  1295. vtWideChar: MsgArgs[i] := AnsiString(Args[i].VWideChar);
  1296. vtPWideChar: MsgArgs[i] := Args[i].VPWideChar;
  1297. vtAnsiString: MsgArgs[i] := AnsiString(Args[i].VAnsiString);
  1298. vtCurrency: ; // Args[i].VCurrency^);
  1299. vtVariant: ; // Args[i].VVariant^);
  1300. vtInterface: ; // Args[i].VInterface^);
  1301. vtWidestring: MsgArgs[i] := AnsiString(WideString(Args[i].VWideString));
  1302. vtInt64: MsgArgs[i] := IntToStr(Args[i].VInt64^);
  1303. vtQWord: MsgArgs[i] := IntToStr(Args[i].VQWord^);
  1304. vtUnicodeString:MsgArgs[i] := AnsiString(UnicodeString(Args[i].VUnicodeString));
  1305. end;
  1306. {$endif}
  1307. end;
  1308. function SafeFormat(const Fmt: string; Args: array of const): string;
  1309. var
  1310. MsgArgs: TMessageArgs;
  1311. i: Integer;
  1312. begin
  1313. try
  1314. Result:=Format(Fmt,Args);
  1315. except
  1316. Result:='';
  1317. MsgArgs:=nil;
  1318. CreateMsgArgs(MsgArgs,Args);
  1319. for i:=0 to length(MsgArgs)-1 do
  1320. begin
  1321. if i>0 then
  1322. Result:=Result+',';
  1323. Result:=Result+MsgArgs[i];
  1324. end;
  1325. Result:='{'+Fmt+'}['+Result+']';
  1326. end;
  1327. end;
  1328. type
  1329. TIncludeStackItem = class
  1330. SourceFile: TLineReader;
  1331. Filename: string;
  1332. Token: TToken;
  1333. TokenString: string;
  1334. Line: string;
  1335. Row: Integer;
  1336. ColumnOffset: integer;
  1337. TokenPos: {$ifdef UsePChar}PChar;{$else}integer; { position in Line }{$endif}
  1338. end;
  1339. function StrToModeSwitch(aName: String): TModeSwitch;
  1340. var
  1341. ms: TModeSwitch;
  1342. begin
  1343. aName:=UpperCase(aName);
  1344. if aName='' then exit(msNone);
  1345. for ms in TModeSwitch do
  1346. if SModeSwitchNames[ms]=aName then exit(ms);
  1347. Result:=msNone;
  1348. end;
  1349. function ModeSwitchesToStr(Switches: TModeSwitches): string;
  1350. var
  1351. ms: TModeSwitch;
  1352. begin
  1353. Result:='';
  1354. for ms in Switches do
  1355. Result:=Result+SModeSwitchNames[ms]+',';
  1356. Result:='['+LeftStr(Result,length(Result)-1)+']';
  1357. end;
  1358. function BoolSwitchesToStr(Switches: TBoolSwitches): string;
  1359. var
  1360. bs: TBoolSwitch;
  1361. begin
  1362. Result:='';
  1363. for bs in Switches do
  1364. Result:=Result+BoolSwitchNames[bs]+',';
  1365. Result:='['+LeftStr(Result,length(Result)-1)+']';
  1366. end;
  1367. function FilenameIsAbsolute(const TheFilename: string):boolean;
  1368. begin
  1369. {$IFDEF WINDOWS}
  1370. // windows
  1371. Result:=FilenameIsWinAbsolute(TheFilename);
  1372. {$ELSE}
  1373. // unix
  1374. Result:=FilenameIsUnixAbsolute(TheFilename);
  1375. {$ENDIF}
  1376. end;
  1377. function FilenameIsWinAbsolute(const TheFilename: string): boolean;
  1378. begin
  1379. Result:=((length(TheFilename)>=2) and (TheFilename[1] in ['A'..'Z','a'..'z'])
  1380. and (TheFilename[2]=':'))
  1381. or ((length(TheFilename)>=2)
  1382. and (TheFilename[1]='\') and (TheFilename[2]='\'));
  1383. end;
  1384. function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
  1385. begin
  1386. Result:=(TheFilename<>'') and (TheFilename[1]='/');
  1387. end;
  1388. { TCondDirectiveEvaluator }
  1389. // inline
  1390. function TCondDirectiveEvaluator.IsFalse(const Value: String): boolean;
  1391. begin
  1392. Result:=Value=CondDirectiveBool[false];
  1393. if (not Result) and isMac then
  1394. Result:=Value=MacDirectiveBool[false];
  1395. end;
  1396. // inline
  1397. function TCondDirectiveEvaluator.IsTrue(const Value: String): boolean;
  1398. begin
  1399. Result:=Value<>CondDirectiveBool[false];
  1400. if Result and isMac then
  1401. Result:=Value<>MacDirectiveBool[False];
  1402. end;
  1403. function TCondDirectiveEvaluator.IsInteger(const Value: String; out i: TMaxPrecInt
  1404. ): boolean;
  1405. var
  1406. Code: integer;
  1407. begin
  1408. val(Value,i,Code);
  1409. Result:=Code=0;
  1410. end;
  1411. function TCondDirectiveEvaluator.IsExtended(const Value: String; out e: TMaxFloat
  1412. ): boolean;
  1413. var
  1414. Code: integer;
  1415. begin
  1416. val(Value,e,Code);
  1417. Result:=Code=0;
  1418. end;
  1419. procedure TCondDirectiveEvaluator.NextToken;
  1420. const
  1421. IdentChars = ['a'..'z','A'..'Z','_','0'..'9'];
  1422. {$ifdef UsePChar}
  1423. function IsIdentifier(a,b: PChar): boolean;
  1424. var
  1425. ac: Char;
  1426. begin
  1427. repeat
  1428. ac:=a^;
  1429. if (ac in IdentChars) and (upcase(ac)=upcase(b^)) then
  1430. begin
  1431. inc(a);
  1432. inc(b);
  1433. end
  1434. else
  1435. begin
  1436. Result:=(not (ac in IdentChars)) and (not (b^ in IdentChars));
  1437. exit;
  1438. end;
  1439. until false;
  1440. end;
  1441. {$endif}
  1442. function ReadIdentifier: TToken;
  1443. begin
  1444. Result:=tkIdentifier;
  1445. {$ifdef UsePChar}
  1446. case FTokenEnd-FTokenStart of
  1447. 2:
  1448. if IsIdentifier(FTokenStart,'or') then
  1449. Result:=tkor;
  1450. 3:
  1451. if IsIdentifier(FTokenStart,'not') then
  1452. Result:=tknot
  1453. else if IsIdentifier(FTokenStart,'and') then
  1454. Result:=tkand
  1455. else if IsIdentifier(FTokenStart,'xor') then
  1456. Result:=tkxor
  1457. else if IsIdentifier(FTokenStart,'shl') then
  1458. Result:=tkshl
  1459. else if IsIdentifier(FTokenStart,'shr') then
  1460. Result:=tkshr
  1461. else if IsIdentifier(FTokenStart,'mod') then
  1462. Result:=tkmod
  1463. else if IsIdentifier(FTokenStart,'div') then
  1464. Result:=tkdiv;
  1465. end;
  1466. {$else}
  1467. case lowercase(copy(Expression,FTokenStart,FTokenEnd-FTokenStart)) of
  1468. 'or': Result:=tkor;
  1469. 'not': Result:=tknot;
  1470. 'and': Result:=tkand;
  1471. 'xor': Result:=tkxor;
  1472. 'shl': Result:=tkshl;
  1473. 'shr': Result:=tkshr;
  1474. 'mod': Result:=tkmod;
  1475. 'div': Result:=tkdiv;
  1476. end;
  1477. {$endif}
  1478. end;
  1479. {$ifndef UsePChar}
  1480. const
  1481. AllSpaces = [#9,#10,#13,' '];
  1482. Digits = ['0'..'9'];
  1483. HexDigits = ['0'..'9'];
  1484. var
  1485. l: integer;
  1486. Src: String;
  1487. {$endif}
  1488. begin
  1489. FTokenStart:=FTokenEnd;
  1490. // skip white space
  1491. {$ifdef UsePChar}
  1492. repeat
  1493. case FTokenStart^ of
  1494. #0:
  1495. if FTokenStart-PChar(Expression)>=length(Expression) then
  1496. begin
  1497. FToken:=tkEOF;
  1498. FTokenEnd:=FTokenStart;
  1499. exit;
  1500. end
  1501. else
  1502. inc(FTokenStart);
  1503. #9,#10,#13,' ':
  1504. inc(FTokenStart);
  1505. else break;
  1506. end;
  1507. until false;
  1508. {$else}
  1509. Src:=Expression;
  1510. l:=length(Src);
  1511. while (FTokenStart<=l) and (Src[FTokenStart] in AllSpaces) do
  1512. inc(FTokenStart);
  1513. if FTokenStart>l then
  1514. begin
  1515. FToken:=tkEOF;
  1516. FTokenEnd:=FTokenStart;
  1517. exit;
  1518. end;
  1519. {$endif}
  1520. // read token
  1521. FTokenEnd:=FTokenStart;
  1522. case {$ifdef UsePChar}FTokenEnd^{$else}Src[FTokenEnd]{$endif} of
  1523. 'a'..'z','A'..'Z','_':
  1524. begin
  1525. inc(FTokenEnd);
  1526. {$ifdef UsePChar}
  1527. while FTokenEnd^ in IdentChars do inc(FTokenEnd);
  1528. {$else}
  1529. while (FTokenEnd<=l) and (Src[FTokenEnd] in IdentChars) do inc(FTokenEnd);
  1530. {$endif}
  1531. FToken:=ReadIdentifier;
  1532. end;
  1533. '0'..'9':
  1534. begin
  1535. FToken:=tkNumber;
  1536. // examples: 1, 1.2, 1.2E3, 1E-2
  1537. inc(FTokenEnd);
  1538. {$ifdef UsePChar}
  1539. while FTokenEnd^ in Digits do inc(FTokenEnd);
  1540. if (FTokenEnd^='.') and (FTokenEnd[1]<>'.') then
  1541. begin
  1542. inc(FTokenEnd);
  1543. while FTokenEnd^ in Digits do inc(FTokenEnd);
  1544. end;
  1545. if FTokenEnd^ in ['e','E'] then
  1546. begin
  1547. inc(FTokenEnd);
  1548. if FTokenEnd^ in ['-','+'] then inc(FTokenEnd);
  1549. while FTokenEnd^ in Digits do inc(FTokenEnd);
  1550. end;
  1551. {$else}
  1552. while (FTokenEnd<=l) and (Src[FTokenEnd] in Digits) do inc(FTokenEnd);
  1553. if (FTokenEnd<=l) and (Src[FTokenEnd]='.')
  1554. and ((FTokenEnd=l) or (Src[FTokenEnd+1]<>'.')) then
  1555. begin
  1556. inc(FTokenEnd);
  1557. while (FTokenEnd<=l) and (Src[FTokenEnd] in Digits) do inc(FTokenEnd);
  1558. end;
  1559. if (FTokenEnd<=l) and (Src[FTokenEnd] in ['e','E']) then
  1560. begin
  1561. inc(FTokenEnd);
  1562. if (FTokenEnd<=l) and (Src[FTokenEnd] in ['-','+']) then inc(FTokenEnd);
  1563. while (FTokenEnd<=l) and (Src[FTokenEnd] in Digits) do inc(FTokenEnd);
  1564. end;
  1565. {$endif}
  1566. end;
  1567. '$':
  1568. begin
  1569. FToken:=tkNumber;
  1570. inc(FTokenEnd);
  1571. {$ifdef UsePChar}
  1572. while FTokenEnd^ in HexDigits do inc(FTokenEnd);
  1573. {$else}
  1574. while (FTokenEnd<=l) and (Src[FTokenEnd] in HexDigits) do inc(FTokenEnd);
  1575. {$endif}
  1576. end;
  1577. '%':
  1578. begin
  1579. FToken:=tkNumber;
  1580. {$ifdef UsePChar}
  1581. while FTokenEnd^ in ['0','1'] do inc(FTokenEnd);
  1582. {$else}
  1583. while (FTokenEnd<=l) and (Src[FTokenEnd] in ['0','1']) do inc(FTokenEnd);
  1584. {$endif}
  1585. end;
  1586. '(':
  1587. begin
  1588. FToken:=tkBraceOpen;
  1589. inc(FTokenEnd);
  1590. end;
  1591. ')':
  1592. begin
  1593. FToken:=tkBraceClose;
  1594. inc(FTokenEnd);
  1595. end;
  1596. '=':
  1597. begin
  1598. FToken:=tkEqual;
  1599. inc(FTokenEnd);
  1600. end;
  1601. '<':
  1602. begin
  1603. inc(FTokenEnd);
  1604. case {$ifdef UsePChar}FTokenEnd^{$else}copy(Src,FTokenEnd,1){$endif} of
  1605. '=':
  1606. begin
  1607. FToken:=tkLessEqualThan;
  1608. inc(FTokenEnd);
  1609. end;
  1610. '<':
  1611. begin
  1612. FToken:=tkshl;
  1613. inc(FTokenEnd);
  1614. end;
  1615. '>':
  1616. begin
  1617. FToken:=tkNotEqual;
  1618. inc(FTokenEnd);
  1619. end;
  1620. else
  1621. FToken:=tkLessThan;
  1622. end;
  1623. end;
  1624. '>':
  1625. begin
  1626. inc(FTokenEnd);
  1627. case {$ifdef UsePChar}FTokenEnd^{$else}copy(Src,FTokenEnd,1){$endif} of
  1628. '=':
  1629. begin
  1630. FToken:=tkGreaterEqualThan;
  1631. inc(FTokenEnd);
  1632. end;
  1633. '>':
  1634. begin
  1635. FToken:=tkshr;
  1636. inc(FTokenEnd);
  1637. end;
  1638. else
  1639. FToken:=tkGreaterThan;
  1640. end;
  1641. end;
  1642. '+':
  1643. begin
  1644. FToken:=tkPlus;
  1645. inc(FTokenEnd);
  1646. end;
  1647. '-':
  1648. begin
  1649. FToken:=tkMinus;
  1650. inc(FTokenEnd);
  1651. end;
  1652. '*':
  1653. begin
  1654. FToken:=tkMul;
  1655. inc(FTokenEnd);
  1656. end;
  1657. '/':
  1658. begin
  1659. FToken:=tkDivision;
  1660. inc(FTokenEnd);
  1661. end;
  1662. '''':
  1663. begin
  1664. FToken:=tkString;
  1665. repeat
  1666. inc(FTokenEnd);
  1667. {$ifdef UsePChar}
  1668. if FTokenEnd^='''' then
  1669. begin
  1670. inc(FTokenEnd);
  1671. if FTokenEnd^<>'''' then break;
  1672. end
  1673. else if FTokenEnd^ in [#0,#10,#13] then
  1674. Log(mtError,nErrOpenString,SErrOpenString,[]);
  1675. {$else}
  1676. if FTokenEnd>l then
  1677. Log(mtError,nErrOpenString,SErrOpenString,[]);
  1678. case Src[FTokenEnd] of
  1679. '''':
  1680. begin
  1681. inc(FTokenEnd);
  1682. if (FTokenEnd>l) or (Src[FTokenEnd]<>'''') then break;
  1683. end;
  1684. #10,#13:
  1685. Log(mtError,nErrOpenString,SErrOpenString,[]);
  1686. end;
  1687. {$endif}
  1688. until false;
  1689. end
  1690. else
  1691. FToken:=tkEOF;
  1692. end;
  1693. {$IFDEF VerbosePasDirectiveEval}
  1694. writeln('TCondDirectiveEvaluator.NextToken END Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
  1695. {$ENDIF}
  1696. end;
  1697. procedure TCondDirectiveEvaluator.Log(aMsgType: TMessageType;
  1698. aMsgNumber: integer; const aMsgFmt: String;
  1699. const Args: array of const;
  1700. MsgPos: integer);
  1701. begin
  1702. if MsgPos<1 then
  1703. MsgPos:=FTokenEnd{$ifdef UsePChar}-PChar(Expression)+1{$endif};
  1704. MsgType:=aMsgType;
  1705. MsgNumber:=aMsgNumber;
  1706. MsgPattern:=aMsgFmt;
  1707. if Assigned(OnLog) then
  1708. begin
  1709. OnLog(Self,Args);
  1710. if not (aMsgType in [mtError,mtFatal]) then exit;
  1711. end;
  1712. raise EScannerError.CreateFmt(MsgPattern+' at pos '+IntToStr(MsgPos)+' line '+IntToStr(MsgCurLine),Args);
  1713. end;
  1714. procedure TCondDirectiveEvaluator.LogXExpectedButTokenFound(const X: String;
  1715. ErrorPos: integer);
  1716. begin
  1717. Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
  1718. [X,TokenInfos[FToken]],ErrorPos);
  1719. end;
  1720. procedure TCondDirectiveEvaluator.ReadOperand(Skip: boolean);
  1721. { Read operand and put it on the stack
  1722. Examples:
  1723. Variable
  1724. not Variable
  1725. not not undefined Variable
  1726. defined(Variable)
  1727. !Variable
  1728. unicodestring
  1729. 123
  1730. $45
  1731. 'Abc'
  1732. (expression)
  1733. }
  1734. Function IsMacNoArgFunction(aName : string) : Boolean;
  1735. begin
  1736. Result:=SameText(aName,'DEFINED') or SameText(aName,'UNDEFINED');
  1737. end;
  1738. var
  1739. i: TMaxPrecInt;
  1740. e: extended;
  1741. S, aName, Param: String;
  1742. Code: integer;
  1743. NameStartP: {$ifdef UsePChar}PChar{$else}integer{$endif};
  1744. p, Lvl: integer;
  1745. begin
  1746. {$IFDEF VerbosePasDirectiveEval}
  1747. writeln('TCondDirectiveEvaluator.ReadOperand START Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken,BoolToStr(Skip,' SKIP',''));
  1748. {$ENDIF}
  1749. case FToken of
  1750. tknot:
  1751. begin
  1752. // boolean not
  1753. NextToken;
  1754. ReadOperand(Skip);
  1755. if not Skip then
  1756. FStack[FStackTop].Operand:=CondDirectiveBool[IsFalse(FStack[FStackTop].Operand)];
  1757. end;
  1758. tkMinus:
  1759. begin
  1760. // unary minus
  1761. NextToken;
  1762. ReadOperand(Skip);
  1763. if not Skip then
  1764. begin
  1765. i:=StrToInt64Def(FStack[FStackTop].Operand,0);
  1766. FStack[FStackTop].Operand:=IntToStr(-i);
  1767. end;
  1768. end;
  1769. tkPlus:
  1770. begin
  1771. // unary plus
  1772. NextToken;
  1773. ReadOperand(Skip);
  1774. if not Skip then
  1775. begin
  1776. i:=StrToInt64Def(FStack[FStackTop].Operand,0);
  1777. FStack[FStackTop].Operand:=IntToStr(i);
  1778. end;
  1779. end;
  1780. tkNumber:
  1781. begin
  1782. // number: convert to decimal
  1783. if not Skip then
  1784. begin
  1785. S:=GetTokenString;
  1786. val(S,i,Code);
  1787. if Code=0 then
  1788. begin
  1789. // integer
  1790. Push(IntToStr(i),FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif});
  1791. end
  1792. else
  1793. begin
  1794. val(S,e,Code);
  1795. if Code>0 then
  1796. Log(mtError,nErrRangeCheck,sErrRangeCheck,[]);
  1797. if e=0 then ;
  1798. // float
  1799. Push(S,FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif});
  1800. end;
  1801. end;
  1802. NextToken;
  1803. end;
  1804. tkString:
  1805. begin
  1806. // string literal
  1807. if not Skip then
  1808. Push(GetStringLiteralValue,FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif});
  1809. NextToken;
  1810. end;
  1811. tkIdentifier:
  1812. if Skip then
  1813. begin
  1814. aName:=GetTokenString;
  1815. NextToken;
  1816. // for macpas IFC we can have DEFINED A or DEFINED(A)...
  1817. if FToken=tkBraceOpen then
  1818. begin
  1819. // only one parameter is supported
  1820. NextToken;
  1821. if FToken=tkIdentifier then
  1822. NextToken;
  1823. if FToken<>tkBraceClose then
  1824. LogXExpectedButTokenFound(')');
  1825. NextToken;
  1826. end
  1827. else if (IsMac and IsMacNoArgFunction(aName)) then
  1828. begin
  1829. NextToken;
  1830. end;
  1831. end
  1832. else
  1833. begin
  1834. aName:=GetTokenString;
  1835. p:=FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif};
  1836. NextToken;
  1837. if FToken=tkBraceOpen then
  1838. begin
  1839. // function
  1840. NameStartP:=FTokenStart;
  1841. NextToken;
  1842. // only one parameter is supported
  1843. Param:='';
  1844. if FToken=tkIdentifier then
  1845. begin
  1846. Param:=GetTokenString;
  1847. NextToken;
  1848. end;
  1849. if FToken<>tkBraceClose then
  1850. LogXExpectedButTokenFound(')');
  1851. if not OnEvalFunction(Self,aName,Param,S) then
  1852. begin
  1853. FTokenStart:=NameStartP;
  1854. FTokenEnd:=FTokenStart+length(aName);
  1855. LogXExpectedButTokenFound('function');
  1856. end;
  1857. Push(S,p);
  1858. NextToken;
  1859. end
  1860. else if (IsMac and IsMacNoArgFunction(aName)) then
  1861. begin
  1862. if FToken<>tkIdentifier then
  1863. LogXExpectedButTokenFound('identifier');
  1864. aName:=GetTokenString;
  1865. Push(CondDirectiveBool[OnEvalVariable(Self,aName,S)],p);
  1866. NextToken;
  1867. end
  1868. else
  1869. begin
  1870. // variable
  1871. if OnEvalVariable(Self,aName,S) then
  1872. Push(S,p)
  1873. else
  1874. begin
  1875. // variable does not exist -> evaluates to false
  1876. Push(CondDirectiveBool[false],p);
  1877. end;
  1878. end;
  1879. end;
  1880. tkBraceOpen:
  1881. begin
  1882. NextToken;
  1883. if Skip then
  1884. begin
  1885. Lvl:=1;
  1886. repeat
  1887. case FToken of
  1888. tkEOF:
  1889. LogXExpectedButTokenFound(')');
  1890. tkBraceOpen: inc(Lvl);
  1891. tkBraceClose:
  1892. begin
  1893. dec(Lvl);
  1894. if Lvl=0 then break;
  1895. end;
  1896. else
  1897. // Do nothing, satisfy compiler
  1898. end;
  1899. NextToken;
  1900. until false;
  1901. end
  1902. else
  1903. begin
  1904. ReadExpression;
  1905. if FToken<>tkBraceClose then
  1906. LogXExpectedButTokenFound(')');
  1907. end;
  1908. NextToken;
  1909. end;
  1910. else
  1911. LogXExpectedButTokenFound('identifier');
  1912. end;
  1913. {$IFDEF VerbosePasDirectiveEval}
  1914. writeln('TCondDirectiveEvaluator.ReadOperand END Top=',FStackTop,' Value="',FStack[FStackTop].Operand,'" Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
  1915. {$ENDIF}
  1916. end;
  1917. procedure TCondDirectiveEvaluator.ReadExpression;
  1918. // read operand operator operand ... til tkEOF or tkBraceClose
  1919. var
  1920. OldStackTop: Integer;
  1921. procedure ReadBinary(Level: TPrecedenceLevel; NewOperator: TToken);
  1922. begin
  1923. ResolveStack(OldStackTop,Level,NewOperator);
  1924. NextToken;
  1925. ReadOperand;
  1926. end;
  1927. begin
  1928. OldStackTop:=FStackTop;
  1929. {$IFDEF VerbosePasDirectiveEval}
  1930. writeln('TCondDirectiveEvaluator.ReadExpression START Top=',FStackTop,' Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
  1931. {$ENDIF}
  1932. ReadOperand;
  1933. repeat
  1934. {$IFDEF VerbosePasDirectiveEval}
  1935. writeln('TCondDirectiveEvaluator.ReadExpression NEXT Top=',FStackTop,' Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
  1936. {$ENDIF}
  1937. case FToken of
  1938. tkEOF,tkBraceClose:
  1939. begin
  1940. ResolveStack(OldStackTop,high(TPrecedenceLevel),tkEOF);
  1941. exit;
  1942. end;
  1943. tkand:
  1944. begin
  1945. ResolveStack(OldStackTop,ceplSecond,tkand);
  1946. NextToken;
  1947. if (FStackTop=OldStackTop+1) and IsFalse(FStack[FStackTop].Operand) then
  1948. begin
  1949. // false and ...
  1950. // -> skip all "and"
  1951. repeat
  1952. ReadOperand(true);
  1953. if FToken<>tkand then break;
  1954. NextToken;
  1955. until false;
  1956. FStack[FStackTop].Operathor:=tkEOF;
  1957. end
  1958. else
  1959. ReadOperand;
  1960. end;
  1961. tkMul,tkDivision,tkdiv,tkmod,tkshl,tkshr:
  1962. ReadBinary(ceplSecond,FToken);
  1963. tkor:
  1964. begin
  1965. ResolveStack(OldStackTop,ceplThird,tkor);
  1966. NextToken;
  1967. if (FStackTop=OldStackTop+1) and IsTrue(FStack[FStackTop].Operand) then
  1968. begin
  1969. // true or ...
  1970. // -> skip all "and" and "or"
  1971. repeat
  1972. ReadOperand(true);
  1973. if not (FToken in [tkand,tkor]) then break;
  1974. NextToken;
  1975. until false;
  1976. FStack[FStackTop].Operathor:=tkEOF;
  1977. end
  1978. else
  1979. ReadOperand;
  1980. end;
  1981. tkPlus,tkMinus,tkxor:
  1982. ReadBinary(ceplThird,FToken);
  1983. tkEqual,tkNotEqual,tkLessThan,tkGreaterThan,tkLessEqualThan,tkGreaterEqualThan:
  1984. ReadBinary(ceplFourth,FToken);
  1985. else
  1986. LogXExpectedButTokenFound('operator');
  1987. end;
  1988. until false;
  1989. {$IFDEF VerbosePasDirectiveEval}
  1990. writeln('TCondDirectiveEvaluator.ReadExpression END Top=',FStackTop,' Value="',FStack[FStackTop].Operand,'" Token[',FTokenStart-PChar(Expression)+1,']=',GetTokenString,' ',FToken);
  1991. {$ENDIF}
  1992. end;
  1993. procedure TCondDirectiveEvaluator.ResolveStack(MinStackLvl: integer;
  1994. Level: TPrecedenceLevel; NewOperator: TToken);
  1995. var
  1996. A, B, R: String;
  1997. Op: TToken;
  1998. AInt, BInt: TMaxPrecInt;
  1999. AFloat, BFloat: extended;
  2000. BPos: Integer;
  2001. begin
  2002. // resolve all higher or equal level operations
  2003. // Note: the stack top contains operand B
  2004. // the stack second contains operand A and the operator between A and B
  2005. //writeln('TCondDirectiveEvaluator.ResolveStack FStackTop=',FStackTop,' MinStackLvl=',MinStackLvl);
  2006. //if FStackTop>MinStackLvl+1 then
  2007. // writeln(' FStack[FStackTop-1].Level=',FStack[FStackTop-1].Level,' Level=',Level);
  2008. while (FStackTop>MinStackLvl+1) and (FStack[FStackTop-1].Level<=Level) do
  2009. begin
  2010. // pop last operand and operator from stack
  2011. B:=FStack[FStackTop].Operand;
  2012. BPos:=FStack[FStackTop].OperandPos;
  2013. dec(FStackTop);
  2014. Op:=FStack[FStackTop].Operathor;
  2015. A:=FStack[FStackTop].Operand;
  2016. {$IFDEF VerbosePasDirectiveEval}
  2017. writeln(' ResolveStack Top=',FStackTop,' A="',A,'" ',Op,' B="',B,'"');
  2018. {$ENDIF}
  2019. {$IFOPT R+}{$DEFINE RangeChecking}{$ENDIF}
  2020. {$R+}
  2021. try
  2022. case Op of
  2023. tkand: // boolean and
  2024. R:=CondDirectiveBool[IsTrue(A) and IsTrue(B)];
  2025. tkor: // boolean or
  2026. R:=CondDirectiveBool[IsTrue(A) or IsTrue(B)];
  2027. tkxor: // boolean xor
  2028. R:=CondDirectiveBool[IsTrue(A) xor IsTrue(B)];
  2029. tkMul, tkdiv, tkmod, tkshl, tkshr, tkPlus, tkMinus:
  2030. if IsInteger(A,AInt) then
  2031. begin
  2032. if IsInteger(B,BInt) then
  2033. case Op of
  2034. tkMul: R:=IntToStr(AInt*BInt);
  2035. tkdiv: R:=IntToStr(AInt div BInt);
  2036. tkmod: R:=IntToStr(AInt mod BInt);
  2037. tkshl: R:=IntToStr(AInt shl BInt);
  2038. tkshr: R:=IntToStr(AInt shr BInt);
  2039. tkPlus: R:=IntToStr(AInt+BInt);
  2040. tkMinus: R:=IntToStr(AInt-BInt);
  2041. else
  2042. // Do nothing, satisfy compiler
  2043. end
  2044. else if IsExtended(B,BFloat) then
  2045. case Op of
  2046. tkMul: R:=FloatToStr(Extended(AInt)*BFloat);
  2047. tkPlus: R:=FloatToStr(Extended(AInt)+BFloat);
  2048. tkMinus: R:=FloatToStr(Extended(AInt)-BFloat);
  2049. else
  2050. LogXExpectedButTokenFound('integer',BPos);
  2051. end
  2052. else
  2053. LogXExpectedButTokenFound('integer',BPos);
  2054. end
  2055. else if IsExtended(A,AFloat) then
  2056. begin
  2057. if IsExtended(B,BFloat) then
  2058. case Op of
  2059. tkMul: R:=FloatToStr(AFloat*BFloat);
  2060. tkPlus: R:=FloatToStr(AFloat+BFloat);
  2061. tkMinus: R:=FloatToStr(AFloat-BFloat);
  2062. else
  2063. LogXExpectedButTokenFound('float',BPos);
  2064. end
  2065. else
  2066. LogXExpectedButTokenFound('float',BPos);
  2067. end
  2068. else
  2069. Log(mtError,nErrOperandAndOperatorMismatch,sErrOperandAndOperatorMismatch,[]);
  2070. tkDivision:
  2071. if IsExtended(A,AFloat) then
  2072. begin
  2073. if IsExtended(B,BFloat) then
  2074. R:=FloatToStr(AFloat/BFloat)
  2075. else
  2076. LogXExpectedButTokenFound('float',BPos);
  2077. end
  2078. else
  2079. Log(mtError,nErrOperandAndOperatorMismatch,sErrOperandAndOperatorMismatch,[]);
  2080. tkEqual,
  2081. tkNotEqual,
  2082. tkLessThan,tkGreaterThan,
  2083. tkLessEqualThan,tkGreaterEqualThan:
  2084. begin
  2085. if IsInteger(A,AInt) and IsInteger(B,BInt) then
  2086. case Op of
  2087. tkEqual: R:=CondDirectiveBool[AInt=BInt];
  2088. tkNotEqual: R:=CondDirectiveBool[AInt<>BInt];
  2089. tkLessThan: R:=CondDirectiveBool[AInt<BInt];
  2090. tkGreaterThan: R:=CondDirectiveBool[AInt>BInt];
  2091. tkLessEqualThan: R:=CondDirectiveBool[AInt<=BInt];
  2092. tkGreaterEqualThan: R:=CondDirectiveBool[AInt>=BInt];
  2093. else
  2094. // Do nothing, satisfy compiler
  2095. end
  2096. else if IsExtended(A,AFloat) and IsExtended(B,BFloat) then
  2097. case Op of
  2098. tkEqual: R:=CondDirectiveBool[AFloat=BFloat];
  2099. tkNotEqual: R:=CondDirectiveBool[AFloat<>BFloat];
  2100. tkLessThan: R:=CondDirectiveBool[AFloat<BFloat];
  2101. tkGreaterThan: R:=CondDirectiveBool[AFloat>BFloat];
  2102. tkLessEqualThan: R:=CondDirectiveBool[AFloat<=BFloat];
  2103. tkGreaterEqualThan: R:=CondDirectiveBool[AFloat>=BFloat];
  2104. else
  2105. // Do nothing, satisfy compiler
  2106. end
  2107. else
  2108. case Op of
  2109. tkEqual: R:=CondDirectiveBool[A=B];
  2110. tkNotEqual: R:=CondDirectiveBool[A<>B];
  2111. tkLessThan: R:=CondDirectiveBool[A<B];
  2112. tkGreaterThan: R:=CondDirectiveBool[A>B];
  2113. tkLessEqualThan: R:=CondDirectiveBool[A<=B];
  2114. tkGreaterEqualThan: R:=CondDirectiveBool[A>=B];
  2115. else
  2116. // Do nothing, satisfy compiler
  2117. end;
  2118. end;
  2119. else
  2120. Log(mtError,nErrOperandAndOperatorMismatch,sErrOperandAndOperatorMismatch,[]);
  2121. end;
  2122. except
  2123. on E: EDivByZero do
  2124. Log(mtError,nErrDivByZero,sErrDivByZero,[]);
  2125. on E: EZeroDivide do
  2126. Log(mtError,nErrDivByZero,sErrDivByZero,[]);
  2127. on E: EMathError do
  2128. Log(mtError,nErrRangeCheck,sErrRangeCheck+' '+E.Message,[]);
  2129. on E: EInterror do
  2130. Log(mtError,nErrRangeCheck,sErrRangeCheck+' '+E.Message,[]);
  2131. end;
  2132. {$IFNDEF RangeChecking}{$R-}{$UNDEF RangeChecking}{$ENDIF}
  2133. {$IFDEF VerbosePasDirectiveEval}
  2134. writeln(' ResolveStack Top=',FStackTop,' A="',A,'" ',Op,' B="',B,'" = "',R,'"');
  2135. {$ENDIF}
  2136. FStack[FStackTop].Operand:=R;
  2137. FStack[FStackTop].OperandPos:=BPos;
  2138. end;
  2139. FStack[FStackTop].Operathor:=NewOperator;
  2140. FStack[FStackTop].Level:=Level;
  2141. end;
  2142. function TCondDirectiveEvaluator.GetTokenString: String;
  2143. begin
  2144. Result:=copy(Expression,FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif},
  2145. FTokenEnd-FTokenStart);
  2146. end;
  2147. function TCondDirectiveEvaluator.GetStringLiteralValue: String;
  2148. var
  2149. {$ifdef UsePChar}
  2150. p, StartP: PChar;
  2151. {$else}
  2152. Src: string;
  2153. p, l, StartP: Integer;
  2154. {$endif}
  2155. begin
  2156. Result:='';
  2157. p:=FTokenStart;
  2158. {$ifdef UsePChar}
  2159. repeat
  2160. case p^ of
  2161. '''':
  2162. begin
  2163. inc(p);
  2164. StartP:=p;
  2165. repeat
  2166. case p^ of
  2167. #0: Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0']);
  2168. '''': break;
  2169. else inc(p);
  2170. end;
  2171. until false;
  2172. if p>StartP then
  2173. Result:=Result+copy(Expression,StartP-PChar(Expression)+1,p-StartP);
  2174. inc(p);
  2175. end;
  2176. else
  2177. Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0']);
  2178. end;
  2179. until false;
  2180. {$else}
  2181. Src:=Expression;
  2182. l:=length(Src);
  2183. repeat
  2184. if (p>l) or (Src[p]<>'''') then
  2185. Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0'])
  2186. else
  2187. begin
  2188. inc(p);
  2189. StartP:=p;
  2190. repeat
  2191. if p>l then
  2192. Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0'])
  2193. else if Src[p]='''' then
  2194. break
  2195. else
  2196. inc(p);
  2197. until false;
  2198. if p>StartP then
  2199. Result:=Result+copy(Expression,StartP,p-StartP);
  2200. inc(p);
  2201. end;
  2202. until false;
  2203. {$endif}
  2204. end;
  2205. procedure TCondDirectiveEvaluator.Push(const AnOperand: String;
  2206. OperandPosition: integer);
  2207. begin
  2208. inc(FStackTop);
  2209. if FStackTop>=length(FStack) then
  2210. SetLength(FStack,length(FStack)*2+4);
  2211. with FStack[FStackTop] do
  2212. begin
  2213. Operand:=AnOperand;
  2214. OperandPos:=OperandPosition;
  2215. Operathor:=tkEOF;
  2216. Level:=ceplFourth;
  2217. end;
  2218. {$IFDEF VerbosePasDirectiveEval}
  2219. writeln('TCondDirectiveEvaluator.Push Top=',FStackTop,' Operand="',AnOperand,'" Pos=',OperandPosition);
  2220. {$ENDIF}
  2221. end;
  2222. constructor TCondDirectiveEvaluator.Create(aIsMac: Boolean);
  2223. begin
  2224. IsMac:=aIsMac
  2225. end;
  2226. destructor TCondDirectiveEvaluator.Destroy;
  2227. begin
  2228. inherited Destroy;
  2229. end;
  2230. function TCondDirectiveEvaluator.Eval(const Expr: string): boolean;
  2231. begin
  2232. {$IFDEF VerbosePasDirectiveEval}
  2233. writeln('TCondDirectiveEvaluator.Eval Expr="',Expr,'"');
  2234. {$ENDIF}
  2235. Expression:=Expr;
  2236. MsgType:=mtInfo;
  2237. MsgNumber:=0;
  2238. MsgPattern:='';
  2239. if Expr='' then exit(false);
  2240. FTokenStart:={$ifdef UsePChar}PChar(Expr){$else}1{$endif};
  2241. FTokenEnd:=FTokenStart;
  2242. FStackTop:=-1;
  2243. NextToken;
  2244. ReadExpression;
  2245. Result:=IsTrue(FStack[0].Operand);
  2246. {$IFDEF VerbosePasDirectiveEval}
  2247. Writeln('COND Eval: ', Expr,' -> ',Result);
  2248. {$ENDIF}
  2249. end;
  2250. { TMacroDef }
  2251. constructor TMacroDef.Create(const AName, AValue: String);
  2252. begin
  2253. FName:=AName;
  2254. FValue:=AValue;
  2255. end;
  2256. { TLineReader }
  2257. constructor TLineReader.Create(const AFilename: string);
  2258. begin
  2259. FFileName:=AFileName;
  2260. if LineEnding=#13 then
  2261. {%H-}EOLStyle:=elCR
  2262. else if LineEnding=#13#10 then
  2263. {%H-}EOLStyle:=elCRLF
  2264. else
  2265. EOLStyle:=elLF
  2266. end;
  2267. function TLineReader.LastEOLStyle: TEOLStyle;
  2268. begin
  2269. Result:=EOLStyle;
  2270. end;
  2271. { ---------------------------------------------------------------------
  2272. TFileLineReader
  2273. ---------------------------------------------------------------------}
  2274. constructor TFileLineReader.Create(const AFilename: string);
  2275. begin
  2276. inherited Create(AFileName);
  2277. {$ifdef pas2js}
  2278. raise Exception.Create('ToDo TFileLineReader.Create');
  2279. {$else}
  2280. Assign(FTextFile, AFilename);
  2281. Reset(FTextFile);
  2282. SetTextBuf(FTextFile,FBuffer,SizeOf(FBuffer));
  2283. FFileOpened := true;
  2284. {$endif}
  2285. end;
  2286. destructor TFileLineReader.Destroy;
  2287. begin
  2288. {$ifdef pas2js}
  2289. // ToDo
  2290. {$else}
  2291. if FFileOpened then
  2292. Close(FTextFile);
  2293. {$endif}
  2294. inherited Destroy;
  2295. end;
  2296. function TFileLineReader.IsEOF: Boolean;
  2297. begin
  2298. {$ifdef pas2js}
  2299. Result:=true;// ToDo
  2300. {$else}
  2301. Result := EOF(FTextFile);
  2302. {$endif}
  2303. end;
  2304. function TFileLineReader.ReadLine: string;
  2305. begin
  2306. {$ifdef pas2js}
  2307. Result:='';// ToDo
  2308. {$else}
  2309. ReadLn(FTextFile, Result);
  2310. {$endif}
  2311. end;
  2312. { TStreamLineReader }
  2313. {$ifdef HasStreams}
  2314. Procedure TStreamLineReader.InitFromStream(AStream : TStream);
  2315. begin
  2316. SetLength(FContent,AStream.Size);
  2317. if FContent<>'' then
  2318. AStream.Read(FContent[1],length(FContent));
  2319. FPos:=0;
  2320. end;
  2321. {$endif}
  2322. procedure TStreamLineReader.InitFromString(const s: string);
  2323. begin
  2324. FContent:=s;
  2325. FPos:=0;
  2326. end;
  2327. function TStreamLineReader.IsEOF: Boolean;
  2328. begin
  2329. Result:=FPos>=Length(FContent);
  2330. end;
  2331. function TStreamLineReader.ReadLine: string;
  2332. Var
  2333. LPos : Integer;
  2334. EOL : Boolean;
  2335. begin
  2336. If isEOF then
  2337. exit('');
  2338. LPos:=FPos+1;
  2339. Repeat
  2340. Inc(FPos);
  2341. EOL:=(FContent[FPos] in [#10,#13]);
  2342. until isEOF or EOL;
  2343. If EOL then
  2344. begin
  2345. if FContent[FPOS]=#10 then
  2346. EOLSTYLE:=elLF
  2347. else
  2348. EOLStyle:=elCR;
  2349. Result:=Copy(FContent,LPos,FPos-LPos)
  2350. end
  2351. else
  2352. Result:=Copy(FContent,LPos,FPos-LPos+1);
  2353. If (not isEOF) and (FContent[FPos]=#13) and (FContent[FPos+1]=#10) then
  2354. begin
  2355. inc(FPos);
  2356. EOLStyle:=elCRLF;
  2357. end;
  2358. end;
  2359. { TFileStreamLineReader }
  2360. constructor TFileStreamLineReader.Create(const AFilename: string);
  2361. {$ifdef HasStreams}
  2362. Var
  2363. S : TFileStream;
  2364. {$endif}
  2365. begin
  2366. inherited Create(AFilename);
  2367. {$ifdef HasStreams}
  2368. S:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
  2369. try
  2370. InitFromStream(S);
  2371. finally
  2372. S.Free;
  2373. end;
  2374. {$else}
  2375. raise Exception.Create('TFileStreamLineReader.Create');
  2376. {$endif}
  2377. end;
  2378. { TStringStreamLineReader }
  2379. constructor TStringStreamLineReader.Create(const AFilename: string; const ASource: String);
  2380. begin
  2381. inherited Create(AFilename);
  2382. InitFromString(ASource);
  2383. end;
  2384. { ---------------------------------------------------------------------
  2385. TBaseFileResolver
  2386. ---------------------------------------------------------------------}
  2387. procedure TBaseFileResolver.SetBaseDirectory(AValue: string);
  2388. begin
  2389. AValue:=IncludeTrailingPathDelimiter(AValue);
  2390. if FBaseDirectory=AValue then Exit;
  2391. FBaseDirectory:=AValue;
  2392. end;
  2393. procedure TBaseFileResolver.SetModuleDirectory(AValue: string);
  2394. begin
  2395. AValue:=IncludeTrailingPathDelimiter(AValue);
  2396. if FModuleDirectory=AValue then Exit;
  2397. FModuleDirectory:=AValue;
  2398. end;
  2399. procedure TBaseFileResolver.SetStrictFileCase(AValue: Boolean);
  2400. begin
  2401. if FStrictFileCase=AValue then Exit;
  2402. FStrictFileCase:=AValue;
  2403. end;
  2404. constructor TBaseFileResolver.Create;
  2405. begin
  2406. inherited Create;
  2407. FIncludePaths := TStringList.Create;
  2408. FResourcePaths := TStringList.Create;
  2409. FMode:=msFPC;
  2410. end;
  2411. destructor TBaseFileResolver.Destroy;
  2412. begin
  2413. FResourcePaths.Free;
  2414. FIncludePaths.Free;
  2415. inherited Destroy;
  2416. end;
  2417. procedure TBaseFileResolver.AddIncludePath(const APath: string);
  2418. Var
  2419. FP : String;
  2420. begin
  2421. if (APath='') then
  2422. FIncludePaths.Add('./')
  2423. else
  2424. begin
  2425. {$IFDEF HASFS}
  2426. FP:=IncludeTrailingPathDelimiter(ExpandFileName(APath));
  2427. {$ELSE}
  2428. FP:=APath;
  2429. {$ENDIF}
  2430. FIncludePaths.Add(FP);
  2431. end;
  2432. end;
  2433. procedure TBaseFileResolver.AddResourcePath(const APath: string);
  2434. Var
  2435. FP : String;
  2436. begin
  2437. if (APath='') then
  2438. FResourcePaths.Add('./')
  2439. else
  2440. begin
  2441. {$IFDEF HASFS}
  2442. FP:=IncludeTrailingPathDelimiter(ExpandFileName(APath));
  2443. {$ELSE}
  2444. FP:=APath;
  2445. {$ENDIF}
  2446. FResourcePaths.Add(FP);
  2447. end;
  2448. end;
  2449. {$IFDEF HASFS}
  2450. { ---------------------------------------------------------------------
  2451. TFileResolver
  2452. ---------------------------------------------------------------------}
  2453. function TFileResolver.SearchLowUpCase(FN: string): string;
  2454. var
  2455. Dir: String;
  2456. begin
  2457. If FileExists(FN) then
  2458. Result:=FN
  2459. else if StrictFileCase then
  2460. Result:=''
  2461. else
  2462. begin
  2463. Dir:=ExtractFilePath(FN);
  2464. FN:=ExtractFileName(FN);
  2465. Result:=Dir+LowerCase(FN);
  2466. If FileExists(Result) then exit;
  2467. Result:=Dir+uppercase(Fn);
  2468. If FileExists(Result) then exit;
  2469. Result:='';
  2470. end;
  2471. end;
  2472. function TFileResolver.FindIncludeFileName(const AName: string): String;
  2473. Function FindInPath(FN : String) : String;
  2474. var
  2475. I : integer;
  2476. begin
  2477. Result:='';
  2478. // search in BaseDirectory (not in mode Delphi)
  2479. if (BaseDirectory<>'')
  2480. and ((ModuleDirectory='') or not (Mode in [msDelphi,msDelphiUnicode])) then
  2481. begin
  2482. Result:=SearchLowUpCase(BaseDirectory+FN);
  2483. if Result<>'' then exit;
  2484. end;
  2485. // search in ModuleDirectory
  2486. if (ModuleDirectory<>'') then
  2487. begin
  2488. Result:=SearchLowUpCase(ModuleDirectory+FN);
  2489. if Result<>'' then exit;
  2490. end;
  2491. // search in include paths
  2492. I:=0;
  2493. While (I<FIncludePaths.Count) do
  2494. begin
  2495. Result:=SearchLowUpCase(FIncludePaths[i]+FN);
  2496. if Result<>'' then exit;
  2497. Inc(I);
  2498. end;
  2499. end;
  2500. var
  2501. FN : string;
  2502. begin
  2503. Result := '';
  2504. // convert pathdelims to system
  2505. FN:=SetDirSeparators(AName);
  2506. If FilenameIsAbsolute(FN) then
  2507. begin
  2508. Result := SearchLowUpCase(FN);
  2509. if (Result='') and (ExtractFileExt(FN)='') then
  2510. begin
  2511. Result:=SearchLowUpCase(FN+'.inc');
  2512. if Result='' then
  2513. begin
  2514. Result:=SearchLowUpCase(FN+'.pp');
  2515. if Result='' then
  2516. Result:=SearchLowUpCase(FN+'.pas');
  2517. end;
  2518. end;
  2519. end
  2520. else
  2521. begin
  2522. // file name is relative
  2523. // search in include path
  2524. Result:=FindInPath(FN);
  2525. // No extension, try default extensions
  2526. if (Result='') and (ExtractFileExt(FN)='') then
  2527. begin
  2528. Result:=FindInPath(FN+'.inc');
  2529. if Result='' then
  2530. begin
  2531. Result:=FindInPath(FN+'.pp');
  2532. if Result='' then
  2533. Result:=FindInPath(FN+'.pas');
  2534. end;
  2535. end;
  2536. end;
  2537. end;
  2538. function TFileResolver.CreateFileReader(const AFileName: String): TLineReader;
  2539. begin
  2540. {$ifdef HasStreams}
  2541. If UseStreams then
  2542. Result:=TFileStreamLineReader.Create(AFileName)
  2543. else
  2544. {$endif}
  2545. Result:=TFileLineReader.Create(AFileName);
  2546. end;
  2547. function TFileResolver.FindResourceFileName(const AFileName: string): String;
  2548. Function FindInPath(FN : String) : String;
  2549. var
  2550. I : integer;
  2551. begin
  2552. Result:='';
  2553. I:=0;
  2554. While (Result='') and (I<FResourcePaths.Count) do
  2555. begin
  2556. Result:=SearchLowUpCase(FResourcePaths[i]+FN);
  2557. Inc(I);
  2558. end;
  2559. // search in BaseDirectory
  2560. if (Result='') and (BaseDirectory<>'') then
  2561. Result:=SearchLowUpCase(BaseDirectory+FN);
  2562. end;
  2563. var
  2564. FN : string;
  2565. begin
  2566. Result := '';
  2567. // convert pathdelims to system
  2568. FN:=SetDirSeparators(AFileName);
  2569. If FilenameIsAbsolute(FN) then
  2570. begin
  2571. Result := SearchLowUpCase(FN);
  2572. end
  2573. else
  2574. begin
  2575. // file name is relative
  2576. // search in include path
  2577. Result:=FindInPath(FN);
  2578. end;
  2579. end;
  2580. function TFileResolver.FindSourceFile(const AName: string): TLineReader;
  2581. begin
  2582. Result := nil;
  2583. if not FileExists(AName) then
  2584. Raise EFileNotFoundError.create(AName)
  2585. else
  2586. try
  2587. Result := CreateFileReader(AName)
  2588. except
  2589. Result := nil;
  2590. end;
  2591. end;
  2592. function TFileResolver.FindIncludeFile(const AName: string): TLineReader;
  2593. Var
  2594. FN : String;
  2595. begin
  2596. Result:=Nil;
  2597. FN:=FindIncludeFileName(AName);
  2598. If (FN<>'') then
  2599. try
  2600. Result := TFileLineReader.Create(FN);
  2601. except
  2602. Result:=Nil;
  2603. end;
  2604. end;
  2605. {$ENDIF}
  2606. {$ifdef fpc}
  2607. { TStreamResolver }
  2608. procedure TStreamResolver.SetOwnsStreams(AValue: Boolean);
  2609. begin
  2610. if FOwnsStreams=AValue then Exit;
  2611. FOwnsStreams:=AValue;
  2612. end;
  2613. function TStreamResolver.FindIncludeFileName(const aFilename: string): String;
  2614. begin
  2615. raise EFileNotFoundError.Create('TStreamResolver.FindIncludeFileName not supported '+aFilename);
  2616. Result:='';
  2617. end;
  2618. function TStreamResolver.FindResourceFileName(const AFileName: string): String;
  2619. begin
  2620. raise EFileNotFoundError.Create('TStreamResolver.FindResourceFileName not supported '+aFileName);
  2621. Result:='';
  2622. end;
  2623. constructor TStreamResolver.Create;
  2624. begin
  2625. Inherited;
  2626. FStreams:=TStringList.Create;
  2627. FStreams.Sorted:=True;
  2628. FStreams.Duplicates:=dupError;
  2629. end;
  2630. destructor TStreamResolver.Destroy;
  2631. begin
  2632. Clear;
  2633. FreeAndNil(FStreams);
  2634. inherited Destroy;
  2635. end;
  2636. procedure TStreamResolver.Clear;
  2637. Var
  2638. I : integer;
  2639. begin
  2640. if OwnsStreams then
  2641. begin
  2642. For I:=0 to FStreams.Count-1 do
  2643. Fstreams.Objects[i].Free;
  2644. end;
  2645. FStreams.Clear;
  2646. end;
  2647. procedure TStreamResolver.AddStream(const AName: String; AStream: TStream);
  2648. begin
  2649. FStreams.AddObject(AName,AStream);
  2650. end;
  2651. function TStreamResolver.FindStream(const AName: string; ScanIncludes : Boolean) : TStream;
  2652. Var
  2653. I,J : Integer;
  2654. FN : String;
  2655. begin
  2656. Result:=Nil;
  2657. I:=FStreams.IndexOf(AName);
  2658. If (I=-1) and ScanIncludes then
  2659. begin
  2660. J:=0;
  2661. While (I=-1) and (J<IncludePaths.Count-1) do
  2662. begin
  2663. FN:=IncludeTrailingPathDelimiter(IncludePaths[i])+AName;
  2664. I:=FStreams.IndexOf(FN);
  2665. Inc(J);
  2666. end;
  2667. end;
  2668. if (I=-1) and (BaseDirectory<>'') then
  2669. I:=FStreams.IndexOf(IncludeTrailingPathDelimiter(BaseDirectory)+aName);
  2670. If (I<>-1) then
  2671. Result:=FStreams.Objects[i] as TStream;
  2672. end;
  2673. function TStreamResolver.FindStreamReader(const AName: string; ScanIncludes : Boolean) : TLineReader;
  2674. Var
  2675. S : TStream;
  2676. SL : TStreamLineReader;
  2677. begin
  2678. Result:=Nil;
  2679. S:=FindStream(AName,ScanIncludes);
  2680. If (S<>Nil) then
  2681. begin
  2682. S.Position:=0;
  2683. SL:=TStreamLineReader.Create(AName);
  2684. try
  2685. SL.InitFromStream(S);
  2686. Result:=SL;
  2687. except
  2688. FreeAndNil(SL);
  2689. Raise;
  2690. end;
  2691. end;
  2692. end;
  2693. function TStreamResolver.FindSourceFile(const AName: string): TLineReader;
  2694. begin
  2695. Result:=FindStreamReader(AName,False);
  2696. end;
  2697. function TStreamResolver.FindIncludeFile(const AName: string): TLineReader;
  2698. begin
  2699. Result:=FindStreamReader(AName,True);
  2700. end;
  2701. {$endif}
  2702. { ---------------------------------------------------------------------
  2703. TPascalScanner
  2704. ---------------------------------------------------------------------}
  2705. constructor TPascalScanner.Create(AFileResolver: TBaseFileResolver);
  2706. Function CS : TStringList;
  2707. begin
  2708. Result:=TStringList.Create;
  2709. Result.Sorted:=True;
  2710. Result.Duplicates:=dupError;
  2711. end;
  2712. var
  2713. vs: TValueSwitch;
  2714. begin
  2715. inherited Create;
  2716. FFileResolver := AFileResolver;
  2717. FFiles:=TStringList.Create;
  2718. FIncludeStack := TFPList.Create;
  2719. FDefines := CS;
  2720. FMacros:=CS;
  2721. FMaxIncludeStackDepth:=DefaultMaxIncludeStackDepth;
  2722. FCurrentModeSwitches:=FPCModeSwitches;
  2723. FAllowedModeSwitches:=msAllModeSwitches;
  2724. FCurrentBoolSwitches:=bsFPCMode;
  2725. FAllowedBoolSwitches:=bsAll;
  2726. FAllowedValueSwitches:=vsAllValueSwitches;
  2727. for vs in TValueSwitch do
  2728. FCurrentValueSwitches[vs]:=DefaultValueSwitches[vs];
  2729. FConditionEval:=TCondDirectiveEvaluator.Create;
  2730. FConditionEval.OnLog:=@OnCondEvalLog;
  2731. FConditionEval.OnEvalVariable:=@OnCondEvalVar;
  2732. FConditionEval.OnEvalFunction:=@OnCondEvalFunction;
  2733. end;
  2734. destructor TPascalScanner.Destroy;
  2735. begin
  2736. FreeAndNil(FConditionEval);
  2737. ClearMacros;
  2738. FreeAndNil(FMacros);
  2739. FreeAndNil(FDefines);
  2740. ClearFiles;
  2741. FreeAndNil(FFiles);
  2742. FreeAndNil(FIncludeStack);
  2743. inherited Destroy;
  2744. end;
  2745. procedure TPascalScanner.RegisterResourceHandler(aExtension: String; aHandler: TResourceHandler);
  2746. Var
  2747. Idx: Integer;
  2748. begin
  2749. if (aExtension='') then
  2750. exit;
  2751. if (aExtension[1]='.') then
  2752. aExtension:=copy(aExtension,2,Length(aExtension)-1);
  2753. Idx:=IndexOfResourceHandler(lowerCase(aExtension));
  2754. if Idx=-1 then
  2755. begin
  2756. Idx:=Length(FResourceHandlers);
  2757. SetLength(FResourceHandlers,Idx+1);
  2758. FResourceHandlers[Idx].Ext:=LowerCase(aExtension);
  2759. end;
  2760. FResourceHandlers[Idx].handler:=aHandler;
  2761. end;
  2762. procedure TPascalScanner.RegisterResourceHandler(aExtensions: array of String; aHandler: TResourceHandler);
  2763. Var
  2764. S : String;
  2765. begin
  2766. For S in aExtensions do
  2767. RegisterResourceHandler(S,aHandler);
  2768. end;
  2769. procedure TPascalScanner.ClearFiles;
  2770. begin
  2771. // Dont' free the first element, because it is CurSourceFile
  2772. while FIncludeStack.Count > 1 do
  2773. begin
  2774. TBaseFileResolver(FIncludeStack[1]).{$ifdef pas2js}Destroy{$else}Free{$endif};
  2775. FIncludeStack.Delete(1);
  2776. end;
  2777. FIncludeStack.Clear;
  2778. FreeAndNil(FCurSourceFile);
  2779. FFiles.Clear;
  2780. FModuleRow:=0;
  2781. end;
  2782. procedure TPascalScanner.ClearMacros;
  2783. Var
  2784. I : Integer;
  2785. begin
  2786. For I:=0 to FMacros.Count-1 do
  2787. FMacros.Objects[i].{$ifdef pas2js}Destroy{$else}Free{$endif};
  2788. FMacros.Clear;
  2789. end;
  2790. procedure TPascalScanner.SetCurToken(const AValue: TToken);
  2791. begin
  2792. FCurToken:=AValue;
  2793. end;
  2794. procedure TPascalScanner.SetCurTokenString(const AValue: string);
  2795. begin
  2796. FCurTokenString:=AValue;
  2797. end;
  2798. procedure TPascalScanner.OpenFile(AFilename: string);
  2799. Var
  2800. aPath : String;
  2801. begin
  2802. Clearfiles;
  2803. FCurSourceFile := FileResolver.FindSourceFile(AFilename);
  2804. FCurFilename := AFilename;
  2805. AddFile(FCurFilename);
  2806. {$IFDEF HASFS}
  2807. aPath:=ExtractFilePath(FCurFilename);
  2808. if (aPath<>'') then
  2809. aPath:=IncludeTrailingPathDelimiter(aPath);
  2810. FileResolver.ModuleDirectory := aPath;
  2811. FileResolver.BaseDirectory := aPath;
  2812. {$ENDIF}
  2813. if LogEvent(sleFile) then
  2814. DoLog(mtInfo,nLogOpeningFile,SLogOpeningFile,[FormatPath(AFileName)],True);
  2815. end;
  2816. procedure TPascalScanner.FinishedModule;
  2817. begin
  2818. if (sleLineNumber in LogEvents)
  2819. and (not CurSourceFile.IsEOF)
  2820. and ((FCurRow Mod 100) > 0) then
  2821. DoLog(mtInfo,nLogLineNumber,SLogLineNumber,[CurRow],True);
  2822. end;
  2823. function TPascalScanner.FormatPath(const aFilename: string): string;
  2824. begin
  2825. if Assigned(OnFormatPath) then
  2826. Result:=OnFormatPath(aFilename)
  2827. else
  2828. Result:=aFilename;
  2829. end;
  2830. procedure TPascalScanner.SetNonToken(aToken: TToken);
  2831. begin
  2832. Include(FNonTokens,aToken);
  2833. end;
  2834. procedure TPascalScanner.UnsetNonToken(aToken: TToken);
  2835. begin
  2836. Exclude(FNonTokens,aToken);
  2837. end;
  2838. procedure TPascalScanner.SetTokenOption(aOption: TTokenoption);
  2839. begin
  2840. Include(FTokenOptions,aOption);
  2841. end;
  2842. procedure TPascalScanner.UnSetTokenOption(aOption: TTokenoption);
  2843. begin
  2844. Exclude(FTokenOptions,aOption);
  2845. end;
  2846. function TPascalScanner.CheckToken(aToken: TToken; const ATokenString: String): TToken;
  2847. begin
  2848. Result:=atoken;
  2849. if (aToken=tkIdentifier) and (CompareText(aTokenString,'operator')=0) then
  2850. if (toOperatorToken in TokenOptions) then
  2851. Result:=tkoperator;
  2852. end;
  2853. procedure TPascalScanner.PopStackItem;
  2854. var
  2855. IncludeStackItem: TIncludeStackItem;
  2856. begin
  2857. IncludeStackItem :=
  2858. TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
  2859. FIncludeStack.Delete(FIncludeStack.Count - 1);
  2860. CurSourceFile.{$ifdef pas2js}Destroy{$else}Free{$endif};
  2861. FCurSourceFile := IncludeStackItem.SourceFile;
  2862. FCurFilename := IncludeStackItem.Filename;
  2863. FileResolver.BaseDirectory:=ExtractFilePath(FCurFilename);
  2864. FCurToken := IncludeStackItem.Token;
  2865. FCurTokenString := IncludeStackItem.TokenString;
  2866. FCurLine := IncludeStackItem.Line;
  2867. FCurRow := IncludeStackItem.Row;
  2868. FCurColumnOffset := IncludeStackItem.ColumnOffset;
  2869. FTokenPos := IncludeStackItem.TokenPos;
  2870. IncludeStackItem.Free;
  2871. end;
  2872. function TPascalScanner.FetchToken: TToken;
  2873. begin
  2874. if Not (FCurToken in [tkWhiteSpace,tkLineEnding]) then
  2875. FPreviousToken:=FCurToken;
  2876. while true do
  2877. begin
  2878. Result := DoFetchToken;
  2879. Case FCurToken of
  2880. tkEOF:
  2881. begin
  2882. if FIncludeStack.Count > 0 then
  2883. begin
  2884. PopStackitem;
  2885. Result := FCurToken;
  2886. end
  2887. else
  2888. break;
  2889. end;
  2890. tkWhiteSpace,
  2891. tkLineEnding:
  2892. if not (FSkipWhiteSpace or PPIsSkipping) then
  2893. Break;
  2894. tkComment:
  2895. if not (FSkipComments or PPIsSkipping) then
  2896. Break;
  2897. tkSelf:
  2898. begin
  2899. if Not (po_selftoken in Options) then
  2900. begin
  2901. FCurToken:=tkIdentifier;
  2902. Result:=FCurToken;
  2903. end;
  2904. if not (FSkipComments or PPIsSkipping) then
  2905. Break;
  2906. end;
  2907. tkOperator:
  2908. begin
  2909. if Not (toOperatorToken in FTokenOptions) then
  2910. begin
  2911. FCurToken:=tkIdentifier;
  2912. Result:=FCurToken;
  2913. end;
  2914. if not (FSkipComments or PPIsSkipping) then
  2915. Break;
  2916. end;
  2917. else
  2918. if not PPIsSkipping then
  2919. break;
  2920. end; // Case
  2921. end;
  2922. // Writeln(Result, '(',CurTokenString,')');
  2923. end;
  2924. function TPascalScanner.ReadNonPascalTillEndToken(StopAtLineEnd: boolean
  2925. ): TToken;
  2926. var
  2927. StartPos: {$ifdef UsePChar}PChar{$else}integer{$endif};
  2928. {$ifndef UsePChar}
  2929. var
  2930. s: string;
  2931. l: integer;
  2932. {$endif}
  2933. Procedure Add;
  2934. var
  2935. AddLen: PtrInt;
  2936. {$ifdef UsePChar}
  2937. OldLen: Integer;
  2938. {$endif}
  2939. begin
  2940. AddLen:=FTokenPos-StartPos;
  2941. if AddLen=0 then
  2942. FCurTokenString:=''
  2943. else
  2944. begin
  2945. {$ifdef UsePChar}
  2946. OldLen:=length(FCurTokenString);
  2947. SetLength(FCurTokenString,OldLen+AddLen);
  2948. Move(StartPos^,PChar(PChar(FCurTokenString)+OldLen)^,AddLen);
  2949. {$else}
  2950. FCurTokenString:=FCurTokenString+copy(FCurLine,StartPos,AddLen);
  2951. {$endif}
  2952. StartPos:=FTokenPos;
  2953. end;
  2954. end;
  2955. function DoEndOfLine: boolean;
  2956. begin
  2957. Add;
  2958. if StopAtLineEnd then
  2959. begin
  2960. ReadNonPascalTillEndToken := tkLineEnding;
  2961. FCurToken := tkLineEnding;
  2962. FetchLine;
  2963. exit(true);
  2964. end;
  2965. if not FetchLine then
  2966. begin
  2967. ReadNonPascalTillEndToken := tkEOF;
  2968. FCurToken := tkEOF;
  2969. exit(true);
  2970. end;
  2971. {$ifndef UsePChar}
  2972. s:=FCurLine;
  2973. l:=length(s);
  2974. {$endif}
  2975. StartPos:=FTokenPos;
  2976. Result:=false;
  2977. end;
  2978. begin
  2979. Result:=tkEOF;
  2980. FCurTokenString := '';
  2981. StartPos:=FTokenPos;
  2982. {$ifndef UsePChar}
  2983. s:=FCurLine;
  2984. l:=length(s);
  2985. {$endif}
  2986. repeat
  2987. {$ifndef UsePChar}
  2988. if FTokenPos>l then
  2989. if DoEndOfLine then exit;
  2990. {$endif}
  2991. case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
  2992. {$ifdef UsePChar}
  2993. #0: // end of line
  2994. if DoEndOfLine then exit;
  2995. {$endif}
  2996. '''':
  2997. begin
  2998. // Notes:
  2999. // 1. Eventually there should be a mechanism to override parsing non-pascal
  3000. // 2. By default skip Pascal string literals, as this is more intuitive
  3001. // in IDEs with Pascal highlighters
  3002. inc(FTokenPos);
  3003. repeat
  3004. {$ifndef UsePChar}
  3005. if FTokenPos>l then
  3006. Error(nErrOpenString,SErrOpenString);
  3007. {$endif}
  3008. case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
  3009. {$ifdef UsePChar}
  3010. #0: Error(nErrOpenString,SErrOpenString);
  3011. {$endif}
  3012. '''':
  3013. begin
  3014. inc(FTokenPos);
  3015. break;
  3016. end;
  3017. #10,#13:
  3018. begin
  3019. // string literal missing closing apostroph
  3020. break;
  3021. end
  3022. else
  3023. inc(FTokenPos);
  3024. end;
  3025. until false;
  3026. end;
  3027. '/':
  3028. begin
  3029. inc(FTokenPos);
  3030. if {$ifdef UsePChar}FTokenPos^='/'{$else}(FTokenPos<=l) and (s[FTokenPos]='/'){$endif} then
  3031. begin
  3032. // skip Delphi comment //, see Note above
  3033. repeat
  3034. inc(FTokenPos);
  3035. until {$ifdef UsePChar}FTokenPos^ in [#0,#10,#13]{$else}(FTokenPos>l) or (s[FTokenPos] in [#10,#13]){$endif};
  3036. end;
  3037. end;
  3038. '0'..'9', 'A'..'Z', 'a'..'z','_':
  3039. begin
  3040. // number or identifier
  3041. if {$ifdef UsePChar}
  3042. (FTokenPos[0] in ['e','E'])
  3043. and (FTokenPos[1] in ['n','N'])
  3044. and (FTokenPos[2] in ['d','D'])
  3045. and not (FTokenPos[3] in IdentChars)
  3046. {$else}
  3047. (TJSString(copy(s,FTokenPos,3)).toLowerCase='end')
  3048. and ((FTokenPos+3>l) or not (s[FTokenPos+3] in IdentChars))
  3049. {$endif}
  3050. then
  3051. begin
  3052. // 'end' found
  3053. Add;
  3054. if FCurTokenString<>'' then
  3055. begin
  3056. // return characters in front of 'end'
  3057. Result:=tkWhitespace;
  3058. FCurToken:=Result;
  3059. exit;
  3060. end;
  3061. // return 'end'
  3062. Result := tkend;
  3063. {$ifdef UsePChar}
  3064. SetLength(FCurTokenString, 3);
  3065. Move(FTokenPos^, FCurTokenString[1], 3);
  3066. {$else}
  3067. FCurTokenString:=copy(s,FTokenPos,3);
  3068. {$endif}
  3069. inc(FTokenPos,3);
  3070. FCurToken := Result;
  3071. exit;
  3072. end
  3073. else
  3074. begin
  3075. // skip identifier
  3076. while {$ifdef UsePChar}FTokenPos[0] in IdentChars{$else}(FTokenPos<=l) and (s[FTokenPos] in IdentChars){$endif} do
  3077. inc(FTokenPos);
  3078. end;
  3079. end;
  3080. else
  3081. inc(FTokenPos);
  3082. end;
  3083. until false;
  3084. end;
  3085. procedure TPascalScanner.Error(MsgNumber: integer; const Msg: string);
  3086. begin
  3087. SetCurMsg(mtError,MsgNumber,Msg,[]);
  3088. raise EScannerError.CreateFmt('%s(%d,%d) Error: %s',
  3089. [FormatPath(CurFilename),CurRow,CurColumn,FLastMsg]);
  3090. end;
  3091. procedure TPascalScanner.Error(MsgNumber: integer; const Fmt: string;
  3092. Args: array of const);
  3093. begin
  3094. SetCurMsg(mtError,MsgNumber,Fmt,Args);
  3095. raise EScannerError.CreateFmt('%s(%d,%d) Error: %s',
  3096. [FormatPath(CurFilename),CurRow,CurColumn,FLastMsg]);
  3097. end;
  3098. function TPascalScanner.GetMultiLineStringLineEnd(aReader : TLineReader) : string;
  3099. Var
  3100. aLF : String;
  3101. aStyle: TEOLStyle;
  3102. begin
  3103. aStyle:=MultilineLineFeedStyle;
  3104. if aStyle=elSource then
  3105. aStyle:=aReader.LastEOLStyle;
  3106. case aStyle of
  3107. elCR : aLF:=#13;
  3108. elCRLF : aLF:=#13#10;
  3109. elLF : aLF:=#10;
  3110. elPlatform : alf:=sLineBreak;
  3111. else
  3112. aLF:=#10;
  3113. end;
  3114. Result:=aLF;
  3115. end;
  3116. function TPascalScanner.DoFetchMultilineTextToken:TToken;
  3117. var
  3118. StartPos,OldLength : Integer;
  3119. TokenStart : {$ifdef UsePChar}PChar{$else}integer{$endif};
  3120. {$ifndef UsePChar}
  3121. s: String;
  3122. l: integer;
  3123. {$endif}
  3124. Procedure AddToCurString(addLF : Boolean);
  3125. var
  3126. SectionLength,i : Integer;
  3127. aLF : String;
  3128. begin
  3129. i:=MultilineLineTrimLeft;
  3130. if I=-1 then
  3131. I:=StartPos+1;
  3132. if I>0 then
  3133. begin
  3134. While ({$ifdef UsePChar} TokenStart^{$ELSE}FCurLine[TokenStart]{$ENDIF} in [' ',#9]) and (TokenStart<=FTokenPos) and (I>0) do
  3135. begin
  3136. Inc(TokenStart);
  3137. Dec(I);
  3138. end;
  3139. end
  3140. else if I=-2 then
  3141. begin
  3142. While ({$ifdef UsePChar} TokenStart^{$ELSE}FCurLine[TokenStart]{$ENDIF} in [' ',#9]) and (TokenStart<=FTokenPos) do
  3143. Inc(TokenStart);
  3144. end;
  3145. SectionLength := FTokenPos - TokenStart+Ord(AddLF);
  3146. {$ifdef UsePChar}
  3147. SetLength(FCurTokenString, OldLength + SectionLength);
  3148. if SectionLength > 0 then
  3149. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  3150. {$else}
  3151. FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength);
  3152. {$endif}
  3153. if AddLF then
  3154. begin
  3155. alf:=GetMultiLineStringLineEnd(FCurSourceFile);
  3156. FCurTokenString:=FCurTokenString+aLF;
  3157. Inc(OldLength,Length(aLF));
  3158. end;
  3159. Inc(OldLength, SectionLength);
  3160. end;
  3161. begin
  3162. Result:=tkEOF;
  3163. OldLength:=0;
  3164. FCurTokenString := '';
  3165. {$ifndef UsePChar}
  3166. s:=FCurLine;
  3167. l:=length(s);
  3168. StartPos:=FTokenPos;
  3169. {$ELSE}
  3170. StartPos:=FTokenPos-PChar(FCurLine);
  3171. {$endif}
  3172. repeat
  3173. {$ifndef UsePChar}
  3174. if FTokenPos>l then break;
  3175. {$endif}
  3176. case {$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif} of
  3177. '^' :
  3178. begin
  3179. TokenStart := FTokenPos;
  3180. Inc(FTokenPos);
  3181. if {$ifdef UsePChar}FTokenPos[0] in Letters{$else}(FTokenPos<l) and (s[FTokenPos] in Letters){$endif} then
  3182. Inc(FTokenPos);
  3183. if Result=tkEOF then Result := tkChar else Result:=tkString;
  3184. end;
  3185. '#':
  3186. begin
  3187. TokenStart := FTokenPos;
  3188. Inc(FTokenPos);
  3189. if {$ifdef UsePChar}FTokenPos[0]='$'{$else}(FTokenPos<l) and (s[FTokenPos]='$'){$endif} then
  3190. begin
  3191. Inc(FTokenPos);
  3192. repeat
  3193. Inc(FTokenPos);
  3194. until {$ifdef UsePChar}not (FTokenPos[0] in HexDigits){$else}(FTokenPos>l) or not (s[FTokenPos] in HexDigits){$endif};
  3195. end else
  3196. repeat
  3197. Inc(FTokenPos);
  3198. until {$ifdef UsePChar}not (FTokenPos[0] in Digits){$else}(FTokenPos>l) or not (s[FTokenPos] in Digits){$endif};
  3199. if Result=tkEOF then Result := tkChar else Result:=tkString;
  3200. end;
  3201. '`':
  3202. begin
  3203. TokenStart := FTokenPos;
  3204. Inc(FTokenPos);
  3205. while true do
  3206. begin
  3207. if {$ifdef UsePChar}FTokenPos[0] = '`'{$else}(FTokenPos<=l) and (s[FTokenPos]=''''){$endif} then
  3208. if {$ifdef UsePChar}FTokenPos[1] = '`'{$else}(FTokenPos<l) and (s[FTokenPos+1]=''''){$endif} then
  3209. Inc(FTokenPos)
  3210. else
  3211. break;
  3212. if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
  3213. begin
  3214. FTokenPos:=FTokenPos-1;
  3215. AddToCurString(true);
  3216. // Writeln('Curtokenstring : >>',FCurTOkenString,'<<');
  3217. if not Self.FetchLine then
  3218. Error(nErrOpenString,SErrOpenString);
  3219. // Writeln('Current line is now : ',FCurLine);
  3220. {$ifndef UsePChar}
  3221. s:=FCurLine;
  3222. l:=length(s);
  3223. {$ELSE}
  3224. FTokenPos:=PChar(FCurLine);
  3225. {$endif}
  3226. TokenStart:=FTokenPos;
  3227. end
  3228. else
  3229. Inc(FTokenPos);
  3230. end;
  3231. Inc(FTokenPos);
  3232. Result := tkString;
  3233. end;
  3234. else
  3235. Break;
  3236. end;
  3237. AddToCurString(false);
  3238. until false;
  3239. if length(FCurTokenString)>1 then
  3240. begin
  3241. FCurTokenString[1]:='''';
  3242. FCurTokenString[Length(FCurTokenString)]:='''';
  3243. end;
  3244. end;
  3245. function TPascalScanner.DoFetchTextToken:TToken;
  3246. var
  3247. OldLength : Integer;
  3248. TokenStart : {$ifdef UsePChar}PChar{$else}integer{$endif};
  3249. SectionLength : Integer;
  3250. {$ifndef UsePChar}
  3251. s: String;
  3252. l: integer;
  3253. {$endif}
  3254. begin
  3255. Result:=tkEOF;
  3256. OldLength:=0;
  3257. FCurTokenString := '';
  3258. {$ifndef UsePChar}
  3259. s:=FCurLine;
  3260. l:=length(s);
  3261. {$endif}
  3262. repeat
  3263. {$ifndef UsePChar}
  3264. if FTokenPos>l then break;
  3265. {$endif}
  3266. case {$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif} of
  3267. '^' :
  3268. begin
  3269. TokenStart := FTokenPos;
  3270. Inc(FTokenPos);
  3271. if {$ifdef UsePChar}FTokenPos[0] in Letters{$else}(FTokenPos<l) and (s[FTokenPos] in Letters){$endif} then
  3272. Inc(FTokenPos);
  3273. if Result=tkEOF then Result := tkChar else Result:=tkString;
  3274. end;
  3275. '#':
  3276. begin
  3277. TokenStart := FTokenPos;
  3278. Inc(FTokenPos);
  3279. if {$ifdef UsePChar}FTokenPos[0]='$'{$else}(FTokenPos<l) and (s[FTokenPos]='$'){$endif} then
  3280. begin
  3281. Inc(FTokenPos);
  3282. repeat
  3283. Inc(FTokenPos);
  3284. until {$ifdef UsePChar}not (FTokenPos[0] in HexDigits){$else}(FTokenPos>l) or not (s[FTokenPos] in HexDigits){$endif};
  3285. end else
  3286. repeat
  3287. Inc(FTokenPos);
  3288. until {$ifdef UsePChar}not (FTokenPos[0] in Digits){$else}(FTokenPos>l) or not (s[FTokenPos] in Digits){$endif};
  3289. if Result=tkEOF then Result := tkChar else Result:=tkString;
  3290. end;
  3291. '''':
  3292. begin
  3293. TokenStart := FTokenPos;
  3294. Inc(FTokenPos);
  3295. while true do
  3296. begin
  3297. if {$ifdef UsePChar}FTokenPos[0] = ''''{$else}(FTokenPos<=l) and (s[FTokenPos]=''''){$endif} then
  3298. if {$ifdef UsePChar}FTokenPos[1] = ''''{$else}(FTokenPos<l) and (s[FTokenPos+1]=''''){$endif} then
  3299. Inc(FTokenPos)
  3300. else
  3301. break;
  3302. if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
  3303. Error(nErrOpenString,SErrOpenString);
  3304. Inc(FTokenPos);
  3305. end;
  3306. Inc(FTokenPos);
  3307. if ((FTokenPos - TokenStart)=3) then // 'z'
  3308. Result := tkChar
  3309. else
  3310. Result := tkString;
  3311. end;
  3312. else
  3313. Break;
  3314. end;
  3315. SectionLength := FTokenPos - TokenStart;
  3316. {$ifdef UsePChar}
  3317. SetLength(FCurTokenString, OldLength + SectionLength);
  3318. if SectionLength > 0 then
  3319. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  3320. {$else}
  3321. FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength);
  3322. {$endif}
  3323. Inc(OldLength, SectionLength);
  3324. until false;
  3325. end;
  3326. procedure TPascalScanner.PushStackItem;
  3327. Var
  3328. SI: TIncludeStackItem;
  3329. begin
  3330. if FIncludeStack.Count>=MaxIncludeStackDepth then
  3331. Error(nErrIncludeLimitReached,SErrIncludeLimitReached);
  3332. SI := TIncludeStackItem.Create;
  3333. SI.SourceFile := CurSourceFile;
  3334. SI.Filename := CurFilename;
  3335. SI.Token := CurToken;
  3336. SI.TokenString := CurTokenString;
  3337. SI.Line := CurLine;
  3338. SI.Row := CurRow;
  3339. SI.ColumnOffset := FCurColumnOffset;
  3340. SI.TokenPos := FTokenPos;
  3341. FIncludeStack.Add(SI);
  3342. FTokenPos:={$ifdef UsePChar}Nil{$else}-1{$endif};
  3343. FCurRow := 0;
  3344. FCurColumnOffset := 1;
  3345. end;
  3346. procedure TPascalScanner.HandleIncludeFile(Param: String);
  3347. var
  3348. NewSourceFile: TLineReader;
  3349. aFileName : string;
  3350. begin
  3351. Param:=Trim(Param);
  3352. if Length(Param)>1 then
  3353. begin
  3354. if (Param[1]='''') then
  3355. begin
  3356. if Param[length(Param)]<>'''' then
  3357. Error(nErrOpenString,SErrOpenString,[]);
  3358. Param:=copy(Param,2,length(Param)-2);
  3359. end;
  3360. end;
  3361. NewSourceFile := FileResolver.FindIncludeFile(Param);
  3362. if not Assigned(NewSourceFile) then
  3363. Error(nErrIncludeFileNotFound, SErrIncludeFileNotFound, [Param]);
  3364. PushStackItem;
  3365. FCurSourceFile:=NewSourceFile;
  3366. FCurFilename := Param;
  3367. if FCurSourceFile is TLineReader then
  3368. begin
  3369. aFileName:=TLineReader(FCurSourceFile).Filename;
  3370. FileResolver.BaseDirectory := ExtractFilePath(aFileName);
  3371. FCurFilename := aFileName; // nicer error messages
  3372. end;
  3373. AddFile(FCurFilename);
  3374. If LogEvent(sleFile) then
  3375. DoLog(mtInfo,nLogOpeningFile,SLogOpeningFile,[FormatPath(FCurFileName)],True);
  3376. end;
  3377. procedure TPascalScanner.HandleIncludeString(Param: String);
  3378. var
  3379. NewSourceFile: TLineReader;
  3380. aString,aLine: string;
  3381. begin
  3382. Param:=Trim(Param);
  3383. if Length(Param)>1 then
  3384. begin
  3385. if (Param[1]='''') then
  3386. begin
  3387. if Param[length(Param)]<>'''' then
  3388. Error(nErrOpenString,SErrOpenString,[]);
  3389. Param:=copy(Param,2,length(Param)-2);
  3390. end;
  3391. end;
  3392. NewSourceFile := FileResolver.FindIncludeFile(Param);
  3393. if not Assigned(NewSourceFile) then
  3394. Error(nErrIncludeFileNotFound, SErrIncludeFileNotFound, [Param]);
  3395. try
  3396. AString:='';
  3397. While not NewSourceFile.IsEOF Do
  3398. begin
  3399. ALine:=NewSourceFile.ReadLine;
  3400. if aString<>'' then
  3401. aString:=aString+GetMultiLineStringLineEnd(NewSourceFile);
  3402. AString:=aString+aLine;
  3403. end;
  3404. finally
  3405. NewSourceFile.Free;
  3406. end;
  3407. FCurTokenString:=''''+AString+'''';
  3408. FCurToken:=tkString;
  3409. end;
  3410. procedure TPascalScanner.HandleResource(Param: string);
  3411. Var
  3412. Ext,aFullFileName,aFilename,aOptions : String;
  3413. P: Integer;
  3414. H : TResourceHandler;
  3415. OptList : TStrings;
  3416. begin
  3417. aFilename:='';
  3418. aOptions:='';
  3419. P:=Pos(';',Param);
  3420. If P=0 then
  3421. aFileName:=Trim(Param)
  3422. else
  3423. begin
  3424. aFileName:=Trim(Copy(Param,1,P-1));
  3425. aOptions:=Copy(Param,P+1,Length(Param)-P);
  3426. end;
  3427. Ext:=ExtractFileExt(aFileName);
  3428. // Construct & find filename
  3429. If (ChangeFileExt(aFileName,'')='*') then
  3430. aFileName:=ChangeFileExt(ExtractFileName(CurFilename),Ext);
  3431. aFullFileName:=FileResolver.FindResourceFileName(aFileName);
  3432. if aFullFileName='' then
  3433. Error(nResourceFileNotFound,SErrResourceFileNotFound,[aFileName]);
  3434. // Check if we can find a handler.
  3435. if Ext<>'' then
  3436. Ext:=Copy(Ext,2,Length(Ext)-1);
  3437. H:=FindResourceHandler(LowerCase(Ext));
  3438. if (H=Nil) then
  3439. H:=FindResourceHandler('*');
  3440. if (H=Nil) then
  3441. begin
  3442. if not (po_IgnoreUnknownResource in Options) then
  3443. Error(nNoResourceSupport,SNoResourceSupport,[Ext]);
  3444. exit;
  3445. end;
  3446. // Let the handler take care of the rest.
  3447. OptList:=TStringList.Create;
  3448. try
  3449. OptList.NameValueSeparator:=':';
  3450. OptList.Delimiter:=';';
  3451. OptList.StrictDelimiter:=True;
  3452. OptList.DelimitedText:=aOptions;
  3453. H(Self,aFullFileName,OptList);
  3454. finally
  3455. OptList.Free;
  3456. end;
  3457. end;
  3458. Function TPascalScanner.MakeLibAlias(Const LibFileName : String): string;
  3459. Var
  3460. p,l,d : integer;
  3461. begin
  3462. l:=Length(LibFileName);
  3463. p:=l;
  3464. d:=0;
  3465. while (p>0) and not (LibFileName[p]='/') do
  3466. begin
  3467. if (LibFileName[p]='.') and (d=0) then
  3468. d:=p;
  3469. dec(P);
  3470. end;
  3471. if d=0 then
  3472. d:=l+1;
  3473. Result:=LowerCase(Copy(LibFileName,P+1,D-P-1));
  3474. for p:=1 to length(Result) do
  3475. if not (result[P] in ['a'..'z','A'..'Z','0'..'9','_']) then
  3476. Result[p]:='_';
  3477. end;
  3478. procedure TPascalScanner.HandleLinkLib(Param: string);
  3479. Var
  3480. P,L : Integer;
  3481. LibFileName,LibAlias,LibOptions : string;
  3482. IsHandled: Boolean;
  3483. Function NextWord : String;
  3484. Var
  3485. lp : integer;
  3486. begin
  3487. lP:=P;
  3488. while (lp<=l) and not (Param[lp] in [' ',#9,#10,#13]) do
  3489. inc(lp);
  3490. Result:=Copy(Param,P,lp-P);
  3491. P:=LP;
  3492. end;
  3493. Procedure DoSkipwhitespace;
  3494. begin
  3495. while (p<=l) and (Param[p] in [' ',#9,#10,#13]) do
  3496. inc(p);
  3497. end;
  3498. begin
  3499. Param:=Trim(Param);
  3500. L:=Length(Param);
  3501. P:=1;
  3502. LibFileName:=NextWord;
  3503. DoSkipWhiteSpace;
  3504. if P<=L then
  3505. LibAlias:=NextWord
  3506. else
  3507. LibAlias:=MakeLibAlias(LibFileName);
  3508. LibOptions:=Trim(Copy(Param,P,L-P+1));
  3509. IsHandled:=False;
  3510. if Assigned(OnLinkLib) then
  3511. OnLinkLib(Self,LibFileName,LibAlias,LibOptions,IsHandled);
  3512. if not IsHandled then
  3513. DoLog(mtNote,nWarnIgnoringLinkLib,SWarnIgnoringLinkLib,[LibFileName,LibAlias,LibOptions]);
  3514. end;
  3515. procedure TPascalScanner.HandleOptimizations(Param: string);
  3516. // $optimization A,B-,C+
  3517. var
  3518. p, StartP, l: Integer;
  3519. OptName, Value: String;
  3520. begin
  3521. p:=1;
  3522. l:=length(Param);
  3523. while p<=l do
  3524. begin
  3525. // read next flag
  3526. // skip whitespace
  3527. while (p<=l) and (Param[p] in [' ',#9,#10,#13]) do
  3528. inc(p);
  3529. // read name
  3530. StartP:=p;
  3531. while (p<=l) and (Param[p] in ['a'..'z','A'..'Z','0'..'9','_']) do
  3532. inc(p);
  3533. if p=StartP then
  3534. Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['optimization']);
  3535. OptName:=copy(Param,StartP,p-StartP);
  3536. if lowercase(LeftStr(OptName,2))='no' then
  3537. begin
  3538. Delete(OptName,1,2);
  3539. DoHandleOptimization(OptName,'-');
  3540. exit;
  3541. end;
  3542. // skip whitespace
  3543. while (p<=l) and (Param[p] in [' ',#9,#10,#13]) do
  3544. inc(p);
  3545. // read value
  3546. StartP:=p;
  3547. while (p<=l) and (Param[p]<>',') do
  3548. inc(p);
  3549. Value:=TrimRight(copy(Param,StartP,p-StartP));
  3550. DoHandleOptimization(OptName,Value);
  3551. inc(p);
  3552. end;
  3553. end;
  3554. procedure TPascalScanner.DoHandleOptimization(OptName, OptValue: string);
  3555. begin
  3556. // default: skip any optimization directive
  3557. if OptName='' then ;
  3558. if OptValue='' then ;
  3559. end;
  3560. function TPascalScanner.HandleMacro(AIndex : integer) : TToken;
  3561. Var
  3562. M : TMacroDef;
  3563. ML : TMacroReader;
  3564. OldRow, OldCol: Integer;
  3565. begin
  3566. OldRow:=CurRow;
  3567. OldCol:=CurColumn;
  3568. PushStackItem;
  3569. M:=FMacros.Objects[AIndex] as TMacroDef;
  3570. ML:=TMacroReader.Create(FCurFileName,M.Value);
  3571. ML.CurRow:=OldRow;
  3572. ML.CurCol:=OldCol-length(M.Name);
  3573. FCurSourceFile:=ML;
  3574. Result:=DoFetchToken;
  3575. // Writeln(Result,Curtoken);
  3576. end;
  3577. procedure TPascalScanner.HandleInterfaces(const Param: String);
  3578. var
  3579. s, NewValue: String;
  3580. p: SizeInt;
  3581. begin
  3582. if not (vsInterfaces in AllowedValueSwitches) then
  3583. Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['interfaces']);
  3584. s:=Uppercase(Param);
  3585. p:=Pos(' ',s);
  3586. if p>0 then
  3587. s:=LeftStr(s,p-1);
  3588. case s of
  3589. 'COM','DEFAULT': NewValue:='COM';
  3590. 'CORBA': NewValue:='CORBA';
  3591. else
  3592. Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['interfaces '+s]);
  3593. exit;
  3594. end;
  3595. if SameText(NewValue,CurrentValueSwitch[vsInterfaces]) then exit;
  3596. if vsInterfaces in ReadOnlyValueSwitches then
  3597. begin
  3598. Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['interfaces']);
  3599. exit;
  3600. end;
  3601. CurrentValueSwitch[vsInterfaces]:=NewValue;
  3602. end;
  3603. procedure TPascalScanner.HandleWarn(Param: String);
  3604. // $warn identifier on|off|default|error
  3605. var
  3606. p, StartPos: Integer;
  3607. Identifier, Value: String;
  3608. begin
  3609. p:=1;
  3610. while (p<=length(Param)) and (Param[p] in [' ',#9]) do inc(p);
  3611. StartPos:=p;
  3612. while (p<=length(Param)) and (Param[p] in ['a'..'z','A'..'Z','0'..'9','_']) do inc(p);
  3613. Identifier:=copy(Param,StartPos,p-StartPos);
  3614. while (p<=length(Param)) and (Param[p] in [' ',#9]) do inc(p);
  3615. StartPos:=p;
  3616. while (p<=length(Param)) and (Param[p] in ['a'..'z','A'..'Z','_']) do inc(p);
  3617. Value:=copy(Param,StartPos,p-StartPos);
  3618. HandleWarnIdentifier(Identifier,Value);
  3619. end;
  3620. procedure TPascalScanner.HandleWarnIdentifier(Identifier,
  3621. Value: String);
  3622. var
  3623. Number: LongInt;
  3624. State: TWarnMsgState;
  3625. Handled: Boolean;
  3626. begin
  3627. if Identifier='' then
  3628. Error(nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,['']);
  3629. if Value='' then
  3630. begin
  3631. DoLog(mtWarning,nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,['']);
  3632. exit;
  3633. end;
  3634. case lowercase(Value) of
  3635. 'on': State:=wmsOn;
  3636. 'off': State:=wmsOff;
  3637. 'default': State:=wmsDefault;
  3638. 'error': State:=wmsError;
  3639. else
  3640. DoLog(mtWarning,nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,[Value]);
  3641. exit;
  3642. end;
  3643. if Assigned(OnWarnDirective) then
  3644. begin
  3645. Handled:=false;
  3646. OnWarnDirective(Self,Identifier,State,Handled);
  3647. if Handled then
  3648. exit;
  3649. end;
  3650. if Identifier[1] in ['0'..'9'] then
  3651. begin
  3652. // fpc number
  3653. Number:=StrToIntDef(Identifier,-1);
  3654. if Number<0 then
  3655. begin
  3656. DoLog(mtWarning,nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,[Identifier]);
  3657. exit;
  3658. end;
  3659. SetWarnMsgState(Number,State);
  3660. end;
  3661. end;
  3662. procedure TPascalScanner.HandleDefine(Param: String);
  3663. Var
  3664. Index : Integer;
  3665. MName,MValue : String;
  3666. begin
  3667. Param := UpperCase(Param);
  3668. Index:=Pos(':=',Param);
  3669. If (Index=0) then
  3670. AddDefine(GetMacroName(Param))
  3671. else
  3672. begin
  3673. MValue:=Trim(Param);
  3674. MName:=Trim(Copy(MValue,1,Index-1));
  3675. Delete(MValue,1,Index+1);
  3676. AddMacro(MName,Trim(MValue));
  3677. end;
  3678. end;
  3679. procedure TPascalScanner.HandleDispatchField(Param: String; vs: TValueSwitch);
  3680. var
  3681. NewValue: String;
  3682. begin
  3683. if not (vs in AllowedValueSwitches) then
  3684. Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,[ValueSwitchNames[vs]]);
  3685. NewValue:=ReadIdentifier(Param);
  3686. if NewValue='-' then
  3687. NewValue:=''
  3688. else if not IsValidIdent(NewValue,false) then
  3689. DoLog(mtWarning,nInvalidDispatchFieldName,SInvalidDispatchFieldName,[]);
  3690. if SameText(NewValue,CurrentValueSwitch[vs]) then exit;
  3691. if vs in ReadOnlyValueSwitches then
  3692. begin
  3693. Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,[ValueSwitchNames[vs]]);
  3694. exit;
  3695. end;
  3696. CurrentValueSwitch[vs]:=NewValue;
  3697. end;
  3698. procedure TPascalScanner.HandleError(Param: String);
  3699. begin
  3700. if po_StopOnErrorDirective in Options then
  3701. Error(nUserDefined, SUserDefined,[Param])
  3702. else
  3703. DoLog(mtWarning,nUserDefined,SUserDefined+' error',[Param]);
  3704. end;
  3705. procedure TPascalScanner.HandleMessageDirective(Param: String);
  3706. var
  3707. p: Integer;
  3708. Kind: String;
  3709. MsgType: TMessageType;
  3710. begin
  3711. if Param='' then exit;
  3712. p:=1;
  3713. while (p<=length(Param)) and (Param[p] in ['a'..'z','A'..'Z']) do inc(p);
  3714. Kind:=LeftStr(Param,p-1);
  3715. MsgType:=mtHint;
  3716. case UpperCase(Kind) of
  3717. 'HINT': MsgType:=mtHint;
  3718. 'NOTE': MsgType:=mtNote;
  3719. 'WARN': MsgType:=mtWarning;
  3720. 'ERROR': MsgType:=mtError;
  3721. 'FATAL': MsgType:=mtFatal;
  3722. else
  3723. // $Message 'hint text'
  3724. p:=1;
  3725. end;
  3726. while (p<=length(Param)) and (Param[p] in [' ',#9]) do inc(p);
  3727. Delete(Param,1,p-1);
  3728. if MsgType in [mtFatal,mtError] then
  3729. HandleError(Param)
  3730. else
  3731. DoLog(MsgType,nUserDefined,SUserDefined,[Param]);
  3732. end;
  3733. procedure TPascalScanner.HandleUnDefine(Param: String);
  3734. begin
  3735. UnDefine(GetMacroName(Param));
  3736. end;
  3737. function TPascalScanner.HandleInclude(const Param: String): TToken;
  3738. begin
  3739. Result:=tkComment;
  3740. if (Param<>'') and (Param[1]='%') then
  3741. begin
  3742. FCurTokenString:=''''+Param+'''';
  3743. FCurToken:=tkString;
  3744. Result:=FCurToken;
  3745. end
  3746. else
  3747. HandleIncludeFile(Param);
  3748. end;
  3749. procedure TPascalScanner.HandleMode(const Param: String);
  3750. procedure SetMode(const LangMode: TModeSwitch;
  3751. const NewModeSwitches: TModeSwitches; IsDelphi: boolean;
  3752. const AddBoolSwitches: TBoolSwitches = [];
  3753. const RemoveBoolSwitches: TBoolSwitches = [];
  3754. UseOtherwise: boolean = true
  3755. );
  3756. var
  3757. Handled: Boolean;
  3758. begin
  3759. if not (LangMode in AllowedModeSwitches) then
  3760. Error(nErrInvalidMode,SErrInvalidMode,[Param]);
  3761. Handled:=false;
  3762. if Assigned(OnModeChanged) then
  3763. OnModeChanged(Self,LangMode,true,Handled);
  3764. if not Handled then
  3765. begin
  3766. CurrentModeSwitches:=(NewModeSwitches+ReadOnlyModeSwitches)*AllowedModeSwitches;
  3767. CurrentBoolSwitches:=CurrentBoolSwitches+(AddBoolSwitches*AllowedBoolSwitches)
  3768. -(RemoveBoolSwitches*AllowedBoolSwitches);
  3769. if IsDelphi then
  3770. FOptions:=FOptions+[po_delphi]
  3771. else
  3772. FOptions:=FOptions-[po_delphi];
  3773. if UseOtherwise then
  3774. UnsetNonToken(tkotherwise)
  3775. else
  3776. SetNonToken(tkotherwise);
  3777. end;
  3778. Handled:=false;
  3779. FileResolver.Mode:=LangMode;
  3780. if Assigned(OnModeChanged) then
  3781. OnModeChanged(Self,LangMode,false,Handled);
  3782. end;
  3783. Var
  3784. P : String;
  3785. begin
  3786. if SkipGlobalSwitches then
  3787. begin
  3788. DoLog(mtWarning,nMisplacedGlobalCompilerSwitch,SMisplacedGlobalCompilerSwitch,[]);
  3789. exit;
  3790. end;
  3791. P:=Trim(UpperCase(Param));
  3792. Case P of
  3793. 'FPC','DEFAULT':
  3794. begin
  3795. SetMode(msFpc,FPCModeSwitches,false,bsFPCMode);
  3796. SetNonToken(tkobjcclass);
  3797. SetNonToken(tkobjcprotocol);
  3798. SetNonToken(tkobjcCategory);
  3799. end;
  3800. 'OBJFPC':
  3801. begin
  3802. SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
  3803. UnsetNonToken(tkgeneric);
  3804. UnsetNonToken(tkspecialize);
  3805. SetNonToken(tkobjcclass);
  3806. SetNonToken(tkobjcprotocol);
  3807. SetNonToken(tkobjcCategory);
  3808. end;
  3809. 'DELPHI':
  3810. begin
  3811. SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
  3812. SetNonToken(tkgeneric);
  3813. SetNonToken(tkspecialize);
  3814. SetNonToken(tkobjcclass);
  3815. SetNonToken(tkobjcprotocol);
  3816. SetNonToken(tkobjcCategory);
  3817. end;
  3818. 'DELPHIUNICODE':
  3819. begin
  3820. SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
  3821. SetNonToken(tkgeneric);
  3822. SetNonToken(tkspecialize);
  3823. SetNonToken(tkobjcclass);
  3824. SetNonToken(tkobjcprotocol);
  3825. SetNonToken(tkobjcCategory);
  3826. end;
  3827. 'TP':
  3828. SetMode(msTP7,TPModeSwitches,false);
  3829. 'MACPAS':
  3830. SetMode(msMac,MacModeSwitches,false,bsMacPasMode);
  3831. 'ISO':
  3832. SetMode(msIso,ISOModeSwitches,false,[],[],false);
  3833. 'EXTENDEDPASCAL':
  3834. SetMode(msExtpas,ExtPasModeSwitches,false);
  3835. 'GPC':
  3836. SetMode(msGPC,GPCModeSwitches,false);
  3837. else
  3838. Error(nErrInvalidMode,SErrInvalidMode,[Param])
  3839. end;
  3840. end;
  3841. procedure TPascalScanner.HandleModeSwitch(const Param: String);
  3842. // $modeswitch param
  3843. // name, name-, name+, name off, name on, name- comment, name on comment
  3844. Var
  3845. MS : TModeSwitch;
  3846. MSN,PM : String;
  3847. p : Integer;
  3848. Enable: Boolean;
  3849. begin
  3850. Enable:=False;
  3851. PM:=Param;
  3852. p:=1;
  3853. while (p<=length(PM)) and (PM[p] in ['a'..'z','A'..'Z','_','0'..'9']) do
  3854. inc(p);
  3855. MSN:=LeftStr(PM,p-1);
  3856. Delete(PM,1,p-1);
  3857. MS:=StrToModeSwitch(MSN);
  3858. if (MS=msNone) or not (MS in AllowedModeSwitches) then
  3859. begin
  3860. if po_CheckModeSwitches in Options then
  3861. Error(nErrInvalidModeSwitch,SErrInvalidModeSwitch,[MSN])
  3862. else
  3863. DoLog(mtWarning,nErrInvalidModeSwitch,SErrInvalidModeSwitch,[MSN]);
  3864. exit; // ignore
  3865. end;
  3866. if PM='' then
  3867. Enable:=true
  3868. else
  3869. case PM[1] of
  3870. '+','-':
  3871. begin
  3872. Enable:=PM[1]='+';
  3873. p:=2;
  3874. if (p<=length(PM)) and not (PM[p] in [' ',#9]) then
  3875. Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
  3876. end;
  3877. ' ',#9:
  3878. begin
  3879. PM:=TrimLeft(PM);
  3880. if PM<>'' then
  3881. begin
  3882. p:=1;
  3883. while (p<=length(PM)) and (PM[p] in ['A'..'Z']) do inc(p);
  3884. if (p<=length(PM)) and not (PM[p] in [' ',#9]) then
  3885. Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
  3886. PM:=LeftStr(PM,p-1);
  3887. if PM='ON' then
  3888. Enable:=true
  3889. else if PM='OFF' then
  3890. Enable:=false
  3891. else
  3892. Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
  3893. end;
  3894. end;
  3895. else
  3896. Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
  3897. end;
  3898. if MS in CurrentModeSwitches=Enable then
  3899. exit; // no change
  3900. if MS in ReadOnlyModeSwitches then
  3901. begin
  3902. DoLog(mtWarning,nErrInvalidModeSwitch,SErrInvalidModeSwitch,[MSN]);
  3903. exit;
  3904. end;
  3905. if Enable then
  3906. CurrentModeSwitches:=CurrentModeSwitches+[MS]
  3907. else
  3908. CurrentModeSwitches:=CurrentModeSwitches-[MS];
  3909. end;
  3910. procedure TPascalScanner.PushSkipMode;
  3911. begin
  3912. if PPSkipStackIndex = High(PPSkipModeStack) then
  3913. Error(nErrIfXXXNestingLimitReached,SErrIfXXXNestingLimitReached);
  3914. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  3915. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  3916. Inc(PPSkipStackIndex);
  3917. end;
  3918. procedure TPascalScanner.HandleIFDEF(const AParam: String);
  3919. var
  3920. aName: String;
  3921. begin
  3922. PushSkipMode;
  3923. if PPIsSkipping then
  3924. PPSkipMode := ppSkipAll
  3925. else
  3926. begin
  3927. aName:=ReadIdentifier(AParam);
  3928. if IsDefined(aName) then
  3929. PPSkipMode := ppSkipElseBranch
  3930. else
  3931. begin
  3932. PPSkipMode := ppSkipIfBranch;
  3933. PPIsSkipping := true;
  3934. end;
  3935. If LogEvent(sleConditionals) then
  3936. if PPSkipMode=ppSkipElseBranch then
  3937. DoLog(mtInfo,nLogIFDefAccepted,sLogIFDefAccepted,[aName])
  3938. else
  3939. DoLog(mtInfo,nLogIFDefRejected,sLogIFDefRejected,[aName]);
  3940. end;
  3941. end;
  3942. procedure TPascalScanner.HandleIFNDEF(const AParam: String);
  3943. var
  3944. aName: String;
  3945. begin
  3946. PushSkipMode;
  3947. if PPIsSkipping then
  3948. PPSkipMode := ppSkipAll
  3949. else
  3950. begin
  3951. aName:=ReadIdentifier(AParam);
  3952. if IsDefined(aName) then
  3953. begin
  3954. PPSkipMode := ppSkipIfBranch;
  3955. PPIsSkipping := true;
  3956. end
  3957. else
  3958. PPSkipMode := ppSkipElseBranch;
  3959. If LogEvent(sleConditionals) then
  3960. if PPSkipMode=ppSkipElseBranch then
  3961. DoLog(mtInfo,nLogIFNDefAccepted,sLogIFNDefAccepted,[aName])
  3962. else
  3963. DoLog(mtInfo,nLogIFNDefRejected,sLogIFNDefRejected,[aName]);
  3964. end;
  3965. end;
  3966. procedure TPascalScanner.HandleIFOPT(const AParam: String);
  3967. begin
  3968. PushSkipMode;
  3969. if PPIsSkipping then
  3970. PPSkipMode := ppSkipAll
  3971. else
  3972. begin
  3973. if (length(AParam)<>2) or not (AParam[1] in ['a'..'z','A'..'Z'])
  3974. or not (AParam[2] in ['+','-']) then
  3975. Error(nErrXExpectedButYFound,sErrXExpectedButYFound,['letter[+|-]',AParam]);
  3976. if IfOpt(AParam[1])=(AParam[2]='+') then
  3977. PPSkipMode := ppSkipElseBranch
  3978. else
  3979. begin
  3980. PPSkipMode := ppSkipIfBranch;
  3981. PPIsSkipping := true;
  3982. end;
  3983. If LogEvent(sleConditionals) then
  3984. if PPSkipMode=ppSkipElseBranch then
  3985. DoLog(mtInfo,nLogIFOptAccepted,sLogIFOptAccepted,[AParam])
  3986. else
  3987. DoLog(mtInfo,nLogIFOptRejected,sLogIFOptRejected,[AParam]);
  3988. end;
  3989. end;
  3990. procedure TPascalScanner.HandleIF(const AParam: String; aIsMac: Boolean);
  3991. begin
  3992. PushSkipMode;
  3993. if PPIsSkipping then
  3994. PPSkipMode := ppSkipAll
  3995. else
  3996. begin
  3997. ConditionEval.MsgCurLine:=CurTokenPos.Row;
  3998. ConditionEval.isMac:=aIsMac;
  3999. if ConditionEval.Eval(AParam) then
  4000. PPSkipMode := ppSkipElseBranch
  4001. else
  4002. begin
  4003. PPSkipMode := ppSkipIfBranch;
  4004. PPIsSkipping := true;
  4005. end;
  4006. If LogEvent(sleConditionals) then
  4007. if PPSkipMode=ppSkipElseBranch then
  4008. DoLog(mtInfo,nLogIFAccepted,sLogIFAccepted,[AParam])
  4009. else
  4010. DoLog(mtInfo,nLogIFRejected,sLogIFRejected,[AParam]);
  4011. end;
  4012. end;
  4013. procedure TPascalScanner.HandleELSEIF(const AParam: String; aIsMac : Boolean);
  4014. begin
  4015. if PPSkipStackIndex = 0 then
  4016. Error(nErrInvalidPPElse,sErrInvalidPPElse);
  4017. if PPSkipMode = ppSkipIfBranch then
  4018. begin
  4019. ConditionEval.isMac:=aIsMac;
  4020. if ConditionEval.Eval(AParam) then
  4021. begin
  4022. PPSkipMode := ppSkipElseBranch;
  4023. PPIsSkipping := false;
  4024. end
  4025. else
  4026. PPIsSkipping := true;
  4027. If LogEvent(sleConditionals) then
  4028. if PPSkipMode=ppSkipElseBranch then
  4029. DoLog(mtInfo,nLogELSEIFAccepted,sLogELSEIFAccepted,[AParam])
  4030. else
  4031. DoLog(mtInfo,nLogELSEIFRejected,sLogELSEIFRejected,[AParam]);
  4032. end
  4033. else if PPSkipMode=ppSkipElseBranch then
  4034. begin
  4035. PPIsSkipping := true;
  4036. end;
  4037. end;
  4038. procedure TPascalScanner.HandleELSE(const AParam: String);
  4039. begin
  4040. if AParam='' then;
  4041. if PPSkipStackIndex = 0 then
  4042. Error(nErrInvalidPPElse,sErrInvalidPPElse);
  4043. if PPSkipMode = ppSkipIfBranch then
  4044. PPIsSkipping := false
  4045. else if PPSkipMode = ppSkipElseBranch then
  4046. PPIsSkipping := true;
  4047. end;
  4048. procedure TPascalScanner.HandleENDIF(const AParam: String);
  4049. begin
  4050. if AParam='' then;
  4051. if PPSkipStackIndex = 0 then
  4052. Error(nErrInvalidPPEndif,sErrInvalidPPEndif);
  4053. Dec(PPSkipStackIndex);
  4054. PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
  4055. PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
  4056. end;
  4057. function TPascalScanner.HandleDirective(const ADirectiveText: String): TToken;
  4058. Var
  4059. Directive,Param : String;
  4060. P : Integer;
  4061. Handled: Boolean;
  4062. procedure DoBoolDirective(bs: TBoolSwitch);
  4063. begin
  4064. if bs in AllowedBoolSwitches then
  4065. begin
  4066. Handled:=true;
  4067. HandleBoolDirective(bs,Param);
  4068. end
  4069. else
  4070. Handled:=false;
  4071. end;
  4072. begin
  4073. Result:=tkComment;
  4074. P:=Pos(' ',ADirectiveText);
  4075. If P=0 then
  4076. begin
  4077. P:=Pos(#9,ADirectiveText);
  4078. If P=0 then
  4079. P:=Length(ADirectiveText)+1;
  4080. end;
  4081. Directive:=Copy(ADirectiveText,2,P-2); // 1 is $
  4082. Param:=ADirectiveText;
  4083. Delete(Param,1,P);
  4084. {$IFDEF VerbosePasDirectiveEval}
  4085. Writeln('TPascalScanner.HandleDirective.Directive: "',Directive,'", Param : "',Param,'"');
  4086. {$ENDIF}
  4087. Case UpperCase(Directive) of
  4088. 'IFDEF':
  4089. HandleIFDEF(Param);
  4090. 'IFNDEF':
  4091. HandleIFNDEF(Param);
  4092. 'IFOPT':
  4093. HandleIFOPT(Param);
  4094. 'IFC',
  4095. 'IF':
  4096. HandleIF(Param,UpperCase(Directive)='IFC');
  4097. 'ELIFC',
  4098. 'ELSEIF':
  4099. HandleELSEIF(Param,UpperCase(Directive)='ELIFC');
  4100. 'ELSEC',
  4101. 'ELSE':
  4102. HandleELSE(Param);
  4103. 'ENDC',
  4104. 'ENDIF':
  4105. HandleENDIF(Param);
  4106. 'IFEND':
  4107. HandleENDIF(Param);
  4108. else
  4109. if PPIsSkipping then exit;
  4110. Handled:=false;
  4111. if (length(Directive)=2)
  4112. and (Directive[1] in ['a'..'z','A'..'Z'])
  4113. and (Directive[2] in ['-','+']) then
  4114. begin
  4115. Handled:=true;
  4116. Result:=HandleLetterDirective(Directive[1],Directive[2]='+');
  4117. end;
  4118. if not Handled then
  4119. begin
  4120. Handled:=true;
  4121. Param:=Trim(Param);
  4122. Case UpperCase(Directive) of
  4123. 'ASSERTIONS':
  4124. DoBoolDirective(bsAssertions);
  4125. 'DEFINE',
  4126. 'DEFINEC',
  4127. 'SETC':
  4128. HandleDefine(Param);
  4129. 'GOTO':
  4130. DoBoolDirective(bsGoto);
  4131. 'DIRECTIVEFIELD':
  4132. HandleDispatchField(Param,vsDispatchField);
  4133. 'DIRECTIVESTRFIELD':
  4134. HandleDispatchField(Param,vsDispatchStrField);
  4135. 'ERROR':
  4136. HandleError(Param);
  4137. 'HINT':
  4138. DoLog(mtHint,nUserDefined,SUserDefined,[Param]);
  4139. 'HINTS':
  4140. DoBoolDirective(bsHints);
  4141. 'I','INCLUDE':
  4142. Result:=HandleInclude(Param);
  4143. 'INCLUDESTRING','INCLUDESTRINGFILE':
  4144. begin
  4145. HandleIncludeString(Param);
  4146. Result:=tkString;
  4147. end;
  4148. 'INTERFACES':
  4149. HandleInterfaces(Param);
  4150. 'LONGSTRINGS':
  4151. DoBoolDirective(bsLongStrings);
  4152. 'LINKLIB':
  4153. HandleLinkLib(Param);
  4154. 'MACRO':
  4155. DoBoolDirective(bsMacro);
  4156. 'MESSAGE':
  4157. HandleMessageDirective(Param);
  4158. 'MODE':
  4159. HandleMode(Param);
  4160. 'MODESWITCH':
  4161. HandleModeSwitch(Param);
  4162. 'MULTILINESTRINGLINEENDING':
  4163. HandleMultilineStringLineEnding(Param);
  4164. 'MULTILINESTRINGTRIMLEFT':
  4165. HandleMultilineStringTrimLeft(Param);
  4166. 'NOTE':
  4167. DoLog(mtNote,nUserDefined,SUserDefined,[Param]);
  4168. 'NOTES':
  4169. DoBoolDirective(bsNotes);
  4170. 'OBJECTCHECKS':
  4171. DoBoolDirective(bsObjectChecks);
  4172. 'OPTIMIZATION':
  4173. HandleOptimizations(Param);
  4174. 'OVERFLOWCHECKS','OV':
  4175. DoBoolDirective(bsOverflowChecks);
  4176. 'POINTERMATH':
  4177. DoBoolDirective(bsPointerMath);
  4178. 'R' :
  4179. if not (po_DisableResources in Options) then
  4180. HandleResource(Param);
  4181. 'RANGECHECKS':
  4182. DoBoolDirective(bsRangeChecks);
  4183. 'SCOPEDENUMS':
  4184. DoBoolDirective(bsScopedEnums);
  4185. 'TYPEDADDRESS':
  4186. DoBoolDirective(bsTypedAddress);
  4187. 'TYPEINFO':
  4188. DoBoolDirective(bsTypeInfo);
  4189. 'UNDEF':
  4190. HandleUnDefine(Param);
  4191. 'WARN':
  4192. HandleWarn(Param);
  4193. 'WARNING':
  4194. DoLog(mtWarning,nUserDefined,SUserDefined,[Param]);
  4195. 'WARNINGS':
  4196. DoBoolDirective(bsWarnings);
  4197. 'WRITEABLECONST':
  4198. DoBoolDirective(bsWriteableConst);
  4199. 'ALIGN',
  4200. 'CALLING',
  4201. 'INLINE',
  4202. 'PACKRECORDS',
  4203. 'PACKENUM' : ;
  4204. else
  4205. Handled:=false;
  4206. end;
  4207. end;
  4208. DoHandleDirective(Self,Directive,Param,Handled);
  4209. if (not Handled) then
  4210. if LogEvent(sleDirective) then
  4211. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
  4212. [Directive]);
  4213. end;
  4214. end;
  4215. function TPascalScanner.HandleLetterDirective(Letter: char; Enable: boolean): TToken;
  4216. var
  4217. bs: TBoolSwitch;
  4218. begin
  4219. Result:=tkComment;
  4220. Letter:=upcase(Letter);
  4221. bs:=LetterToBoolSwitch[Letter];
  4222. if bs=bsNone then
  4223. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
  4224. [Letter]);
  4225. if not (bs in AllowedBoolSwitches) then
  4226. begin
  4227. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
  4228. [Letter]);
  4229. end;
  4230. if (bs in FCurrentBoolSwitches)<>Enable then
  4231. begin
  4232. if bs in FReadOnlyBoolSwitches then
  4233. begin
  4234. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
  4235. [Letter+BoolToStr(Enable,'+','-')]);
  4236. exit;
  4237. end;
  4238. if Enable then
  4239. begin
  4240. AddDefine(LetterSwitchNames[Letter]);
  4241. Include(FCurrentBoolSwitches,bs);
  4242. end
  4243. else
  4244. begin
  4245. UnDefine(LetterSwitchNames[Letter]);
  4246. Exclude(FCurrentBoolSwitches,bs);
  4247. end;
  4248. end;
  4249. end;
  4250. procedure TPascalScanner.HandleBoolDirective(bs: TBoolSwitch;
  4251. const Param: String);
  4252. var
  4253. NewValue: Boolean;
  4254. begin
  4255. if CompareText(Param,'on')=0 then
  4256. NewValue:=true
  4257. else if CompareText(Param,'off')=0 then
  4258. NewValue:=false
  4259. else
  4260. begin
  4261. NewValue:=True;// Fool compiler
  4262. Error(nErrXExpectedButYFound,SErrXExpectedButYFound,['on',Param]);
  4263. end;
  4264. if (bs in CurrentBoolSwitches)=NewValue then exit;
  4265. if bs in ReadOnlyBoolSwitches then
  4266. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
  4267. [BoolSwitchNames[bs]])
  4268. else if NewValue then
  4269. CurrentBoolSwitches:=CurrentBoolSwitches+[bs]
  4270. else
  4271. CurrentBoolSwitches:=CurrentBoolSwitches-[bs];
  4272. end;
  4273. procedure TPascalScanner.DoHandleComment(Sender: TObject; const aComment: string);
  4274. begin
  4275. if Assigned(OnComment) then
  4276. OnComment(Sender,aComment);
  4277. end;
  4278. procedure TPascalScanner.DoHandleDirective(Sender: TObject; Directive,
  4279. Param: String; var Handled: boolean);
  4280. begin
  4281. if Assigned(OnDirective) then
  4282. OnDirective(Sender,Directive,Param,Handled);
  4283. end;
  4284. procedure TPascalScanner.HandleMultilineStringTrimLeft(const AParam: String);
  4285. Var
  4286. S : String;
  4287. i : integer;
  4288. begin
  4289. S:=UpperCase(Trim(aParam));
  4290. Case UpperCase(S) of
  4291. 'ALL' : I:=-2;
  4292. 'AUTO' : I:=-1;
  4293. 'NONE' : I:=0;
  4294. else
  4295. If not TryStrToInt(S,I) then
  4296. I:=0;
  4297. end;
  4298. MultilineLineTrimLeft:=I;
  4299. end;
  4300. procedure TPascalScanner.HandleMultilineStringLineEnding(const AParam: string);
  4301. Var
  4302. S : TEOLStyle;
  4303. begin
  4304. Case UpperCase(Trim(aParam)) of
  4305. 'CR' : s:=elCR;
  4306. 'LF' : s:=elLF;
  4307. 'CRLF' : s:=elCRLF;
  4308. 'SOURCE' : s:=elSource;
  4309. 'PLATFORM' : s:=elPlatform;
  4310. else
  4311. Error(nErrInvalidMultiLineLineEnding,sErrInvalidMultiLineLineEnding);
  4312. end;
  4313. MultilineLineFeedStyle:=S;
  4314. end;
  4315. function TPascalScanner.DoFetchToken: TToken;
  4316. var
  4317. TokenStart: {$ifdef UsePChar}PChar{$else}integer{$endif};
  4318. i: TToken;
  4319. SectionLength, NestingLevel, Index: Integer;
  4320. {$ifdef UsePChar}
  4321. OldLength: integer;
  4322. Ch: Char;
  4323. LE: string[2];
  4324. {$else}
  4325. s: string;
  4326. l: integer;
  4327. {$endif}
  4328. procedure FetchCurTokenString; inline;
  4329. begin
  4330. {$ifdef UsePChar}
  4331. SetLength(FCurTokenString, SectionLength);
  4332. if SectionLength > 0 then
  4333. Move(TokenStart^, FCurTokenString[1], SectionLength);
  4334. {$else}
  4335. FCurTokenString:=copy(FCurLine,TokenStart,SectionLength);
  4336. {$endif}
  4337. end;
  4338. function FetchLocalLine: boolean; inline;
  4339. begin
  4340. Result:=FetchLine;
  4341. {$ifndef UsePChar}
  4342. if not Result then exit;
  4343. s:=FCurLine;
  4344. l:=length(s);
  4345. {$endif}
  4346. end;
  4347. begin
  4348. TokenStart:={$ifdef UsePChar}nil{$else}0{$endif};
  4349. Result:=tkLineEnding;
  4350. if FTokenPos {$ifdef UsePChar}= nil{$else}<1{$endif} then
  4351. if not FetchLine then
  4352. begin
  4353. Result := tkEOF;
  4354. FCurToken := Result;
  4355. exit;
  4356. end;
  4357. FCurTokenString := '';
  4358. FCurTokenPos.FileName:=CurFilename;
  4359. FCurTokenPos.Row:=CurRow;
  4360. FCurTokenPos.Column:=CurColumn;
  4361. {$ifndef UsePChar}
  4362. s:=FCurLine;
  4363. l:=length(s);
  4364. if FTokenPos>l then
  4365. begin
  4366. FetchLine;
  4367. Result := tkLineEnding;
  4368. FCurToken := Result;
  4369. exit;
  4370. end;
  4371. {$endif}
  4372. case {$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif} of
  4373. {$ifdef UsePChar}
  4374. #0: // Empty line
  4375. begin
  4376. FetchLine;
  4377. Result := tkLineEnding;
  4378. end;
  4379. {$endif}
  4380. ' ':
  4381. begin
  4382. Result := tkWhitespace;
  4383. repeat
  4384. Inc(FTokenPos);
  4385. if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
  4386. if not FetchLocalLine then
  4387. begin
  4388. FCurToken := Result;
  4389. exit;
  4390. end;
  4391. until not ({$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}=' ');
  4392. end;
  4393. #9:
  4394. begin
  4395. Result := tkTab;
  4396. repeat
  4397. Inc(FTokenPos);
  4398. if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
  4399. if not FetchLocalLine then
  4400. begin
  4401. FCurToken := Result;
  4402. exit;
  4403. end;
  4404. until not ({$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}=#9);
  4405. end;
  4406. '#', '''':
  4407. Result:=DoFetchTextToken;
  4408. '`' :
  4409. begin
  4410. If not (msMultiLineStrings in CurrentModeSwitches) then
  4411. Error(nErrInvalidCharacter, SErrInvalidCharacter,
  4412. [{$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}]);
  4413. Result:=DoFetchMultilineTextToken;
  4414. end;
  4415. '&':
  4416. begin
  4417. TokenStart := FTokenPos;
  4418. repeat
  4419. Inc(FTokenPos);
  4420. until {$ifdef UsePChar}not (FTokenPos[0] in ['0'..'7']){$else}(FTokenPos>l) or not (s[FTokenPos] in ['0'..'7']){$endif};
  4421. SectionLength := FTokenPos - TokenStart;
  4422. if (SectionLength=1)
  4423. and ({$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} in IdentChars) then
  4424. begin
  4425. // &Keyword
  4426. DoFetchToken();
  4427. Result:=tkIdentifier;
  4428. end
  4429. else
  4430. begin
  4431. FetchCurTokenString;
  4432. Result := tkNumber;
  4433. end;
  4434. end;
  4435. '$':
  4436. begin
  4437. TokenStart := FTokenPos;
  4438. repeat
  4439. Inc(FTokenPos);
  4440. until {$ifdef UsePChar}not (FTokenPos[0] in HexDigits){$else}(FTokenPos>l) or not (s[FTokenPos] in HexDigits){$endif};
  4441. SectionLength := FTokenPos - TokenStart;
  4442. FetchCurTokenString;
  4443. Result := tkNumber;
  4444. end;
  4445. '%':
  4446. begin
  4447. TokenStart := FTokenPos;
  4448. repeat
  4449. Inc(FTokenPos);
  4450. until {$ifdef UsePChar}not (FTokenPos[0] in ['0','1']){$else}(FTokenPos>l) or not (s[FTokenPos] in ['0','1']){$endif};
  4451. SectionLength := FTokenPos - TokenStart;
  4452. FetchCurTokenString;
  4453. Result := tkNumber;
  4454. end;
  4455. '(':
  4456. begin
  4457. Inc(FTokenPos);
  4458. if {$ifdef UsePChar}FTokenPos[0] = '.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then
  4459. begin
  4460. Inc(FTokenPos);
  4461. Result := tkSquaredBraceOpen;
  4462. end
  4463. else if {$ifdef UsePChar}FTokenPos[0] <> '*'{$else}(FTokenPos>l) or (s[FTokenPos]<>'*'){$endif} then
  4464. Result := tkBraceOpen
  4465. else
  4466. begin
  4467. {$ifdef UsePChar}
  4468. LE:=LineEnding;
  4469. {$endif}
  4470. // Old-style multi-line comment
  4471. Inc(FTokenPos);
  4472. TokenStart := FTokenPos;
  4473. FCurTokenString := '';
  4474. {$ifdef UsePChar}
  4475. OldLength := 0;
  4476. {$endif}
  4477. NestingLevel:=0;
  4478. repeat
  4479. if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
  4480. begin
  4481. SectionLength:=FTokenPos - TokenStart;
  4482. {$ifdef UsePChar}
  4483. SetLength(FCurTokenString, OldLength + SectionLength + length(LineEnding)); // Corrected JC
  4484. if SectionLength > 0 then
  4485. Move(TokenStart^, FCurTokenString[OldLength + 1],SectionLength);
  4486. Inc(OldLength, SectionLength);
  4487. for Ch in LE do
  4488. begin
  4489. Inc(OldLength);
  4490. FCurTokenString[OldLength] := Ch;
  4491. end;
  4492. {$else}
  4493. FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+LineEnding; // Corrected JC
  4494. {$endif}
  4495. if not FetchLocalLine then
  4496. begin
  4497. Result := tkEOF;
  4498. FCurToken := Result;
  4499. exit;
  4500. end;
  4501. TokenStart:=FTokenPos;
  4502. end
  4503. else if {$ifdef UsePChar}(FTokenPos[0] = '*') and (FTokenPos[1] = ')')
  4504. {$else}(FTokenPos<l) and (s[FTokenPos]='*') and (s[FTokenPos+1]=')'){$endif}
  4505. then begin
  4506. dec(NestingLevel);
  4507. if NestingLevel<0 then
  4508. break;
  4509. inc(FTokenPos,2);
  4510. end
  4511. else if (msNestedComment in CurrentModeSwitches)
  4512. and {$ifdef UsePChar}(FTokenPos[0] = '(') and (FTokenPos[1] = '*')
  4513. {$else}(FTokenPos<l) and (s[FTokenPos]='(') and (s[FTokenPos+1]='*'){$endif}
  4514. then begin
  4515. inc(FTokenPos,2);
  4516. Inc(NestingLevel);
  4517. end
  4518. else
  4519. Inc(FTokenPos);
  4520. until false;
  4521. SectionLength := FTokenPos - TokenStart;
  4522. {$ifdef UsePChar}
  4523. SetLength(FCurTokenString, OldLength + SectionLength);
  4524. if SectionLength > 0 then
  4525. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  4526. {$else}
  4527. FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength);
  4528. {$endif}
  4529. Inc(FTokenPos, 2);
  4530. Result := tkComment;
  4531. if Copy(CurTokenString,1,1)='$' then
  4532. Result := HandleDirective(CurTokenString)
  4533. else
  4534. DoHandleComment(Self,CurTokenString);
  4535. end;
  4536. end;
  4537. ')':
  4538. begin
  4539. Inc(FTokenPos);
  4540. Result := tkBraceClose;
  4541. end;
  4542. '*':
  4543. begin
  4544. Result:=tkMul;
  4545. Inc(FTokenPos);
  4546. if {$ifdef UsePChar}FTokenPos[0]='*'{$else}(FTokenPos<=l) and (s[FTokenPos]='*'){$endif} then
  4547. begin
  4548. Inc(FTokenPos);
  4549. Result := tkPower;
  4550. end
  4551. else if (po_CAssignments in options) then
  4552. begin
  4553. if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
  4554. begin
  4555. Inc(FTokenPos);
  4556. Result:=tkAssignMul;
  4557. end;
  4558. end;
  4559. end;
  4560. '+':
  4561. begin
  4562. Result:=tkPlus;
  4563. Inc(FTokenPos);
  4564. if (po_CAssignments in options) then
  4565. begin
  4566. if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
  4567. begin
  4568. Inc(FTokenPos);
  4569. Result:=tkAssignPlus;
  4570. end;
  4571. end
  4572. end;
  4573. ',':
  4574. begin
  4575. Inc(FTokenPos);
  4576. Result := tkComma;
  4577. end;
  4578. '-':
  4579. begin
  4580. Result := tkMinus;
  4581. Inc(FTokenPos);
  4582. if (po_CAssignments in options) then
  4583. begin
  4584. if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
  4585. begin
  4586. Inc(FTokenPos);
  4587. Result:=tkAssignMinus;
  4588. end;
  4589. end
  4590. end;
  4591. '.':
  4592. begin
  4593. Inc(FTokenPos);
  4594. if {$ifdef UsePChar}FTokenPos[0]=')'{$else}(FTokenPos<=l) and (s[FTokenPos]=')'){$endif} then
  4595. begin
  4596. Inc(FTokenPos);
  4597. Result := tkSquaredBraceClose;
  4598. end
  4599. else if {$ifdef UsePChar}FTokenPos[0]='.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then
  4600. begin
  4601. Inc(FTokenPos);
  4602. if {$ifdef UsePChar}FTokenPos[0]='.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then
  4603. begin
  4604. Inc(FTokenPos);
  4605. Result:=tkDotDotDot;
  4606. end
  4607. else
  4608. Result := tkDotDot;
  4609. end
  4610. else
  4611. Result := tkDot;
  4612. end;
  4613. '/':
  4614. begin
  4615. Result := tkDivision;
  4616. Inc(FTokenPos);
  4617. if {$ifdef UsePChar}FTokenPos[0]='/'{$else}(FTokenPos<=l) and (s[FTokenPos]='/'){$endif} then
  4618. begin
  4619. // Single-line comment
  4620. Inc(FTokenPos);
  4621. TokenStart := FTokenPos;
  4622. FCurTokenString := '';
  4623. while {$ifdef UsePChar}FTokenPos[0] <> #0{$else}(FTokenPos<=l) and (s[FTokenPos]<>#0){$endif} do
  4624. Inc(FTokenPos);
  4625. SectionLength := FTokenPos - TokenStart;
  4626. FetchCurTokenString;
  4627. // Handle macro which is //
  4628. if FCurSourceFile is TMacroReader then
  4629. begin
  4630. // exhaust till eof of macro stream
  4631. Repeat
  4632. I:=Fetchtoken;
  4633. until (i<>tkLineEnding);
  4634. FetchLocalLine;
  4635. end;
  4636. Result := tkComment;
  4637. end
  4638. else if (po_CAssignments in options) then
  4639. begin
  4640. if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
  4641. begin
  4642. Inc(FTokenPos);
  4643. Result:=tkAssignDivision;
  4644. end;
  4645. end
  4646. end;
  4647. '0'..'9':
  4648. begin
  4649. // 1, 12, 1.2, 1.2E3, 1.E2, 1E2, 1.2E-3, 1E+2 and .)
  4650. // beware of 1..2
  4651. TokenStart := FTokenPos;
  4652. repeat
  4653. Inc(FTokenPos);
  4654. until {$ifdef UsePChar}not (FTokenPos[0] in Digits){$else}(FTokenPos>l) or not (s[FTokenPos] in Digits){$endif};
  4655. if {$ifdef UsePChar}(FTokenPos[0]='.') and (FTokenPos[1]<>'.') and (FTokenPos[1]<>')'){$else}
  4656. (FTokenPos<=l) and (s[FTokenPos]='.') and ((FTokenPos=l) or ((s[FTokenPos+1]<>'.') and (s[FTokenPos+1]<>')'))){$endif}then
  4657. begin
  4658. inc(FTokenPos);
  4659. while {$ifdef UsePChar}FTokenPos[0] in Digits{$else}(FTokenPos<=l) and (s[FTokenPos] in Digits){$endif} do
  4660. Inc(FTokenPos);
  4661. end;
  4662. if {$ifdef UsePChar}FTokenPos[0] in ['e', 'E']{$else}(FTokenPos<=l) and (s[FTokenPos] in ['e', 'E']){$endif} then
  4663. begin
  4664. Inc(FTokenPos);
  4665. if {$ifdef UsePChar}FTokenPos[0] in ['-','+']{$else}(FTokenPos<=l) and (s[FTokenPos] in ['-','+']){$endif} then
  4666. inc(FTokenPos);
  4667. while {$ifdef UsePChar}FTokenPos[0] in Digits{$else}(FTokenPos<=l) and (s[FTokenPos] in Digits){$endif} do
  4668. Inc(FTokenPos);
  4669. end;
  4670. SectionLength := FTokenPos - TokenStart;
  4671. FetchCurTokenString;
  4672. Result := tkNumber;
  4673. end;
  4674. ':':
  4675. begin
  4676. Inc(FTokenPos);
  4677. if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
  4678. begin
  4679. Inc(FTokenPos);
  4680. Result := tkAssign;
  4681. end
  4682. else
  4683. Result := tkColon;
  4684. end;
  4685. ';':
  4686. begin
  4687. Inc(FTokenPos);
  4688. Result := tkSemicolon;
  4689. end;
  4690. '<':
  4691. begin
  4692. Inc(FTokenPos);
  4693. {$ifndef UsePChar}
  4694. if FTokenPos>l then
  4695. Result := tkLessThan
  4696. else
  4697. {$endif}
  4698. case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
  4699. '>':
  4700. begin
  4701. Inc(FTokenPos);
  4702. Result := tkNotEqual;
  4703. end;
  4704. '=':
  4705. begin
  4706. Inc(FTokenPos);
  4707. Result := tkLessEqualThan;
  4708. end;
  4709. '<':
  4710. begin
  4711. Inc(FTokenPos);
  4712. Result := tkshl;
  4713. end;
  4714. else
  4715. Result := tkLessThan;
  4716. end;
  4717. end;
  4718. '=':
  4719. begin
  4720. Inc(FTokenPos);
  4721. Result := tkEqual;
  4722. end;
  4723. '>':
  4724. begin
  4725. Inc(FTokenPos);
  4726. {$ifndef UsePChar}
  4727. if FTokenPos>l then
  4728. Result := tkGreaterThan
  4729. else
  4730. {$endif}
  4731. case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
  4732. '=':
  4733. begin
  4734. Inc(FTokenPos);
  4735. Result := tkGreaterEqualThan;
  4736. end;
  4737. '<':
  4738. begin
  4739. Inc(FTokenPos);
  4740. Result := tkSymmetricalDifference;
  4741. end;
  4742. '>':
  4743. begin
  4744. Inc(FTokenPos);
  4745. Result := tkshr;
  4746. end;
  4747. else
  4748. Result := tkGreaterThan;
  4749. end;
  4750. end;
  4751. '@':
  4752. begin
  4753. Inc(FTokenPos);
  4754. Result := tkAt;
  4755. if {$ifdef UsePChar}FTokenPos^='@'{$else}(FTokenPos<=l) and (s[FTokenPos]='@'){$endif} then
  4756. begin
  4757. Inc(FTokenPos);
  4758. Result:=tkAtAt;
  4759. end;
  4760. end;
  4761. '[':
  4762. begin
  4763. Inc(FTokenPos);
  4764. Result := tkSquaredBraceOpen;
  4765. end;
  4766. ']':
  4767. begin
  4768. Inc(FTokenPos);
  4769. Result := tkSquaredBraceClose;
  4770. end;
  4771. '^':
  4772. begin
  4773. if ForceCaret or PPisSkipping or
  4774. (PreviousToken in [tkeof,tkTab,tkLineEnding,tkComment,tkIdentifier,
  4775. tkNil,tkOperator,tkBraceClose,tkSquaredBraceClose,tkCaret]) then
  4776. begin
  4777. Inc(FTokenPos);
  4778. Result := tkCaret;
  4779. end
  4780. else
  4781. Result:=DoFetchTextToken;
  4782. end;
  4783. '\':
  4784. begin
  4785. Inc(FTokenPos);
  4786. Result := tkBackslash;
  4787. end;
  4788. '{': // Multi-line comment
  4789. begin
  4790. Inc(FTokenPos);
  4791. TokenStart := FTokenPos;
  4792. FCurTokenString := '';
  4793. {$ifdef UsePChar}
  4794. LE:=LineEnding;
  4795. OldLength := 0;
  4796. {$endif}
  4797. NestingLevel := 0;
  4798. repeat
  4799. if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
  4800. begin
  4801. SectionLength := FTokenPos - TokenStart;
  4802. {$ifdef UsePChar}
  4803. SetLength(FCurTokenString, OldLength + SectionLength + length(LineEnding)); // Corrected JC
  4804. if SectionLength > 0 then
  4805. Move(TokenStart^, FCurTokenString[OldLength + 1],SectionLength);
  4806. // Corrected JC: Append the correct lineending
  4807. Inc(OldLength, SectionLength);
  4808. for Ch in LE do
  4809. begin
  4810. Inc(OldLength);
  4811. FCurTokenString[OldLength] := Ch;
  4812. end;
  4813. {$else}
  4814. FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+LineEnding; // Corrected JC
  4815. {$endif}
  4816. if not FetchLocalLine then
  4817. begin
  4818. Result := tkEOF;
  4819. FCurToken := Result;
  4820. exit;
  4821. end;
  4822. TokenStart := FTokenPos;
  4823. end
  4824. else if {$ifdef UsePChar}(FTokenPos[0] = '}'){$else}(s[FTokenPos]='}'){$endif} then
  4825. begin
  4826. Dec(NestingLevel);
  4827. if NestingLevel<0 then
  4828. break;
  4829. Inc(FTokenPos);
  4830. end
  4831. else if {$ifdef UsePChar}(FTokenPos[0] = '{'){$else}(s[FTokenPos]='{'){$endif}
  4832. and (msNestedComment in CurrentModeSwitches) then
  4833. begin
  4834. inc(FTokenPos);
  4835. Inc(NestingLevel);
  4836. end
  4837. else
  4838. Inc(FTokenPos);
  4839. until false;
  4840. SectionLength := FTokenPos - TokenStart;
  4841. {$ifdef UsePChar}
  4842. SetLength(FCurTokenString, OldLength + SectionLength);
  4843. if SectionLength > 0 then
  4844. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  4845. {$else}
  4846. FCurTokenString:=FCurTokenString+copy(s,TokenStart,SectionLength);
  4847. {$endif}
  4848. Inc(FTokenPos);
  4849. Result := tkComment;
  4850. if (Copy(CurTokenString,1,1)='$') then
  4851. Result:=HandleDirective(CurTokenString)
  4852. else
  4853. DoHandleComment(Self, CurTokenString)
  4854. end;
  4855. 'A'..'Z', 'a'..'z', '_':
  4856. begin
  4857. TokenStart := FTokenPos;
  4858. repeat
  4859. Inc(FTokenPos);
  4860. until {$ifdef UsePChar}not (FTokenPos[0] in IdentChars){$else}(FTokenPos>l) or not (s[FTokenPos] in IdentChars){$endif};
  4861. SectionLength := FTokenPos - TokenStart;
  4862. FetchCurTokenString;
  4863. Result:=tkIdentifier;
  4864. for i:=tkAbsolute to tkXor do
  4865. begin
  4866. if (CompareText(CurTokenString, TokenInfos[i])=0) then
  4867. begin
  4868. Result:=I;
  4869. break;
  4870. end;
  4871. end;
  4872. if (Result<>tkIdentifier) and (Result in FNonTokens) then
  4873. Result:=tkIdentifier;
  4874. FCurToken := Result;
  4875. if MacrosOn then
  4876. begin
  4877. Index:=FMacros.IndexOf(CurTokenString);
  4878. if Index>=0 then
  4879. Result:=HandleMacro(Index);
  4880. end;
  4881. end;
  4882. else
  4883. if PPIsSkipping then
  4884. Inc(FTokenPos)
  4885. else
  4886. Error(nErrInvalidCharacter, SErrInvalidCharacter,
  4887. [{$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}]);
  4888. end;
  4889. FCurToken := Result;
  4890. end;
  4891. function TPascalScanner.LogEvent(E: TPScannerLogEvent): Boolean;
  4892. begin
  4893. Result:=E in FLogEvents;
  4894. end;
  4895. function TPascalScanner.GetCurColumn: Integer;
  4896. begin
  4897. If {$ifdef UsePChar}(FTokenPos<>Nil){$else}FTokenPos>0{$endif} then
  4898. Result := FTokenPos {$ifdef UsePChar}- PChar(CurLine){$else}-1{$endif} + FCurColumnOffset
  4899. else
  4900. Result := FCurColumnOffset;
  4901. end;
  4902. function TPascalScanner.GetCurrentValueSwitch(V: TValueSwitch): string;
  4903. begin
  4904. Result:=FCurrentValueSwitches[V];
  4905. end;
  4906. function TPascalScanner.GetForceCaret: Boolean;
  4907. begin
  4908. Result:=toForceCaret in FTokenOptions;
  4909. end;
  4910. function TPascalScanner.GetMacrosOn: boolean;
  4911. begin
  4912. Result:=bsMacro in FCurrentBoolSwitches;
  4913. end;
  4914. function TPascalScanner.IndexOfWarnMsgState(Number: integer; InsertPos: boolean
  4915. ): integer;
  4916. var
  4917. l, r, m, CurNumber: Integer;
  4918. begin
  4919. l:=0;
  4920. r:=length(FWarnMsgStates)-1;
  4921. m:=0;
  4922. while l<=r do
  4923. begin
  4924. m:=(l+r) div 2;
  4925. CurNumber:=FWarnMsgStates[m].Number;
  4926. if Number>CurNumber then
  4927. l:=m+1
  4928. else if Number<CurNumber then
  4929. r:=m-1
  4930. else
  4931. exit(m);
  4932. end;
  4933. if not InsertPos then
  4934. exit(-1);
  4935. if length(FWarnMsgStates)=0 then
  4936. exit(0);
  4937. if (m<length(FWarnMsgStates)) and (FWarnMsgStates[m].Number<=Number) then
  4938. inc(m);
  4939. Result:=m;
  4940. end;
  4941. function TPascalScanner.OnCondEvalFunction(Sender: TCondDirectiveEvaluator;
  4942. Name, Param: String; out Value: string): boolean;
  4943. begin
  4944. {$IFDEF VerbosePasDirectiveEval}
  4945. writeln('TPascalScanner.OnCondEvalFunction Func="',Name,'" Param="',Param,'"');
  4946. {$ENDIF}
  4947. if CompareText(Name,'defined')=0 then
  4948. begin
  4949. if not IsValidIdent(Param) then
  4950. Sender.Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
  4951. ['identifier',Param]);
  4952. Value:=CondDirectiveBool[IsDefined(Param)];
  4953. exit(true);
  4954. end
  4955. else if CompareText(Name,'undefined')=0 then
  4956. begin
  4957. if not IsValidIdent(Param) then
  4958. Sender.Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
  4959. ['identifier',Param]);
  4960. Value:=CondDirectiveBool[not IsDefined(Param)];
  4961. exit(true);
  4962. end
  4963. else if CompareText(Name,'option')=0 then
  4964. begin
  4965. if (length(Param)<>1) or not (Param[1] in ['a'..'z','A'..'Z']) then
  4966. Sender.Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
  4967. ['letter',Param]);
  4968. Value:=CondDirectiveBool[IfOpt(Param[1])];
  4969. exit(true);
  4970. end;
  4971. // last check user hook
  4972. if Assigned(OnEvalFunction) then
  4973. begin
  4974. Result:=OnEvalFunction(Sender,Name,Param,Value);
  4975. if not (po_CheckCondFunction in Options) then
  4976. begin
  4977. Value:='0';
  4978. Result:=true;
  4979. end;
  4980. exit;
  4981. end;
  4982. if (po_CheckCondFunction in Options) then
  4983. begin
  4984. Value:='';
  4985. Result:=false;
  4986. end
  4987. else
  4988. begin
  4989. Value:='0';
  4990. Result:=true;
  4991. end;
  4992. end;
  4993. procedure TPascalScanner.OnCondEvalLog(Sender: TCondDirectiveEvaluator;
  4994. Args: array of const);
  4995. Var
  4996. Msg : String;
  4997. begin
  4998. {$IFDEF VerbosePasDirectiveEval}
  4999. writeln('TPascalScanner.OnCondEvalLog "',Sender.MsgPattern,'"');
  5000. {$ENDIF}
  5001. // ToDo: move CurLine/CurRow to Sender.MsgPos
  5002. if Sender.MsgType<=mtError then
  5003. begin
  5004. SetCurMsg(Sender.MsgType,Sender.MsgNumber,Sender.MsgPattern,Args);
  5005. Msg:=Format('%s(%d,%d) : %s',[FormatPath(FCurFileName),CurRow,CurColumn,FLastMsg]);
  5006. raise EScannerError.Create(Msg);
  5007. end
  5008. else
  5009. DoLog(Sender.MsgType,Sender.MsgNumber,Sender.MsgPattern,Args,true);
  5010. end;
  5011. function TPascalScanner.OnCondEvalVar(Sender: TCondDirectiveEvaluator;
  5012. Name: String; out Value: string): boolean;
  5013. var
  5014. i: Integer;
  5015. M: TMacroDef;
  5016. begin
  5017. {$IFDEF VerbosePasDirectiveEval}
  5018. writeln('TPascalScanner.OnCondEvalVar "',Name,'"');
  5019. {$ENDIF}
  5020. // first check defines
  5021. if FDefines.IndexOf(Name)>=0 then
  5022. begin
  5023. Value:='1';
  5024. exit(true);
  5025. end;
  5026. // then check macros
  5027. i:=FMacros.IndexOf(Name);
  5028. if i>=0 then
  5029. begin
  5030. M:=FMacros.Objects[i] as TMacroDef;
  5031. Value:=M.Value;
  5032. exit(true);
  5033. end;
  5034. // last check user hook
  5035. if Assigned(OnEvalVariable) then
  5036. begin
  5037. Result:=OnEvalVariable(Sender,Name,Value);
  5038. exit;
  5039. end;
  5040. Value:='';
  5041. Result:=false;
  5042. end;
  5043. procedure TPascalScanner.SetAllowedBoolSwitches(const AValue: TBoolSwitches);
  5044. begin
  5045. if FAllowedBoolSwitches=AValue then Exit;
  5046. FAllowedBoolSwitches:=AValue;
  5047. end;
  5048. procedure TPascalScanner.SetAllowedModeSwitches(const AValue: TModeSwitches);
  5049. begin
  5050. if FAllowedModeSwitches=AValue then Exit;
  5051. FAllowedModeSwitches:=AValue;
  5052. CurrentModeSwitches:=FCurrentModeSwitches*AllowedModeSwitches;
  5053. end;
  5054. procedure TPascalScanner.SetAllowedValueSwitches(const AValue: TValueSwitches);
  5055. begin
  5056. if FAllowedValueSwitches=AValue then Exit;
  5057. FAllowedValueSwitches:=AValue;
  5058. end;
  5059. procedure TPascalScanner.SetCurrentBoolSwitches(const AValue: TBoolSwitches);
  5060. var
  5061. OldBS, Removed, Added: TBoolSwitches;
  5062. begin
  5063. if FCurrentBoolSwitches=AValue then Exit;
  5064. OldBS:=FCurrentBoolSwitches;
  5065. FCurrentBoolSwitches:=AValue;
  5066. Removed:=OldBS-FCurrentBoolSwitches;
  5067. Added:=FCurrentBoolSwitches-OldBS;
  5068. if bsGoto in Added then
  5069. begin
  5070. UnsetNonToken(tklabel);
  5071. UnsetNonToken(tkgoto);
  5072. end;
  5073. if bsGoto in Removed then
  5074. begin
  5075. SetNonToken(tklabel);
  5076. SetNonToken(tkgoto);
  5077. end;
  5078. end;
  5079. procedure TPascalScanner.SetCurrentModeSwitches(AValue: TModeSwitches);
  5080. var
  5081. Old, AddedMS, RemovedMS: TModeSwitches;
  5082. begin
  5083. AValue:=AValue*AllowedModeSwitches;
  5084. if FCurrentModeSwitches=AValue then Exit;
  5085. Old:=FCurrentModeSwitches;
  5086. FCurrentModeSwitches:=AValue;
  5087. AddedMS:=FCurrentModeSwitches-Old;
  5088. RemovedMS:=Old-FCurrentModeSwitches;
  5089. if msDefaultUnicodestring in AddedMS then
  5090. begin
  5091. AddDefine('UNICODE');
  5092. AddDefine('FPC_UNICODESTRINGS');
  5093. end
  5094. else if msDefaultUnicodestring in RemovedMS then
  5095. begin
  5096. UnDefine('UNICODE');
  5097. UnDefine('FPC_UNICODESTRINGS');
  5098. end;
  5099. if msDefaultAnsistring in AddedMS then
  5100. begin
  5101. AddDefine(LetterSwitchNames['H'],true);
  5102. Include(FCurrentBoolSwitches,bsLongStrings);
  5103. end
  5104. else if msDefaultAnsistring in RemovedMS then
  5105. begin
  5106. UnDefine(LetterSwitchNames['H'],true);
  5107. Exclude(FCurrentBoolSwitches,bsLongStrings);
  5108. end;
  5109. if ([msObjectiveC1,msObjectiveC2] * FCurrentModeSwitches) = [] then
  5110. begin
  5111. SetNonToken(tkobjcclass);
  5112. SetNonToken(tkobjcprotocol);
  5113. SetNonToken(tkobjccategory);
  5114. end
  5115. else
  5116. begin
  5117. UnSetNonToken(tkobjcclass);
  5118. UnSetNonToken(tkobjcprotocol);
  5119. UnSetNonToken(tkobjccategory);
  5120. end
  5121. end;
  5122. procedure TPascalScanner.SetCurrentValueSwitch(V: TValueSwitch;
  5123. const AValue: string);
  5124. begin
  5125. if not (V in AllowedValueSwitches) then exit;
  5126. if FCurrentValueSwitches[V]=AValue then exit;
  5127. FCurrentValueSwitches[V]:=AValue;
  5128. end;
  5129. procedure TPascalScanner.SetWarnMsgState(Number: integer; State: TWarnMsgState);
  5130. {$IFDEF EmulateArrayInsert}
  5131. procedure Delete(var A: TWarnMsgNumberStateArr; Index, Count: integer); overload;
  5132. var
  5133. i: Integer;
  5134. begin
  5135. if Index<0 then
  5136. Error(nErrDivByZero,'[20180627142123]');
  5137. if Index+Count>length(A) then
  5138. Error(nErrDivByZero,'[20180627142127]');
  5139. for i:=Index+Count to length(A)-1 do
  5140. A[i-Count]:=A[i];
  5141. SetLength(A,length(A)-Count);
  5142. end;
  5143. procedure Insert(Item: TWarnMsgNumberState; var A: TWarnMsgNumberStateArr; Index: integer); overload;
  5144. var
  5145. i: Integer;
  5146. begin
  5147. if Index<0 then
  5148. Error(nErrDivByZero,'[20180627142133]');
  5149. if Index>length(A) then
  5150. Error(nErrDivByZero,'[20180627142137]');
  5151. SetLength(A,length(A)+1);
  5152. for i:=length(A)-1 downto Index+1 do
  5153. A[i]:=A[i-1];
  5154. A[Index]:=Item;
  5155. end;
  5156. {$ENDIF}
  5157. var
  5158. i: Integer;
  5159. Item: TWarnMsgNumberState;
  5160. begin
  5161. i:=IndexOfWarnMsgState(Number,true);
  5162. if (i<length(FWarnMsgStates)) and (FWarnMsgStates[i].Number=Number) then
  5163. begin
  5164. // already exists
  5165. if State=wmsDefault then
  5166. Delete(FWarnMsgStates,i,1)
  5167. else
  5168. FWarnMsgStates[i].State:=State;
  5169. end
  5170. else if State<>wmsDefault then
  5171. begin
  5172. // new state
  5173. Item.Number:=Number;
  5174. Item.State:=State;
  5175. Insert(Item,FWarnMsgStates,i);
  5176. end;
  5177. end;
  5178. function TPascalScanner.GetWarnMsgState(Number: integer): TWarnMsgState;
  5179. var
  5180. i: Integer;
  5181. begin
  5182. i:=IndexOfWarnMsgState(Number,false);
  5183. if i<0 then
  5184. Result:=wmsDefault
  5185. else
  5186. Result:=FWarnMsgStates[i].State;
  5187. end;
  5188. procedure TPascalScanner.SetMacrosOn(const AValue: boolean);
  5189. begin
  5190. if AValue then
  5191. Include(FCurrentBoolSwitches,bsMacro)
  5192. else
  5193. Exclude(FCurrentBoolSwitches,bsMacro);
  5194. end;
  5195. procedure TPascalScanner.DoLog(MsgType: TMessageType; MsgNumber: integer;
  5196. const Msg: String; SkipSourceInfo: Boolean);
  5197. begin
  5198. DoLog(MsgType,MsgNumber,Msg,[],SkipSourceInfo);
  5199. end;
  5200. procedure TPascalScanner.DoLog(MsgType: TMessageType; MsgNumber: integer;
  5201. const Fmt: String; Args: array of const;
  5202. SkipSourceInfo: Boolean);
  5203. Var
  5204. Msg : String;
  5205. begin
  5206. if IgnoreMsgType(MsgType) then exit;
  5207. SetCurMsg(MsgType,MsgNumber,Fmt,Args);
  5208. If Assigned(FOnLog) then
  5209. begin
  5210. Msg:=MessageTypeNames[MsgType]+': ';
  5211. if SkipSourceInfo then
  5212. Msg:=Msg+FLastMsg
  5213. else
  5214. Msg:=Msg+Format('%s(%d,%d) : %s',[FormatPath(FCurFileName),CurRow,CurColumn,FLastMsg]);
  5215. FOnLog(Self,Msg);
  5216. end;
  5217. end;
  5218. procedure TPascalScanner.SetOptions(AValue: TPOptions);
  5219. Var
  5220. isModeSwitch : Boolean;
  5221. begin
  5222. if FOptions=AValue then Exit;
  5223. // Change of mode ?
  5224. IsModeSwitch:=(po_delphi in Avalue) <> (po_delphi in FOptions);
  5225. FOptions:=AValue;
  5226. if isModeSwitch then
  5227. if (po_delphi in FOptions) then
  5228. CurrentModeSwitches:=DelphiModeSwitches
  5229. else
  5230. CurrentModeSwitches:=FPCModeSwitches
  5231. end;
  5232. procedure TPascalScanner.SetReadOnlyBoolSwitches(const AValue: TBoolSwitches);
  5233. begin
  5234. if FReadOnlyBoolSwitches=AValue then Exit;
  5235. FReadOnlyBoolSwitches:=AValue;
  5236. end;
  5237. procedure TPascalScanner.SetReadOnlyModeSwitches(const AValue: TModeSwitches);
  5238. begin
  5239. if FReadOnlyModeSwitches=AValue then Exit;
  5240. FReadOnlyModeSwitches:=AValue;
  5241. FAllowedModeSwitches:=FAllowedModeSwitches+FReadOnlyModeSwitches;
  5242. FCurrentModeSwitches:=FCurrentModeSwitches+FReadOnlyModeSwitches;
  5243. end;
  5244. procedure TPascalScanner.SetReadOnlyValueSwitches(const AValue: TValueSwitches);
  5245. begin
  5246. if FReadOnlyValueSwitches=AValue then Exit;
  5247. FReadOnlyValueSwitches:=AValue;
  5248. end;
  5249. function TPascalScanner.IndexOfResourceHandler(const aExt: string): Integer;
  5250. begin
  5251. Result:=Length(FResourceHandlers)-1;
  5252. While (Result>=0) and (FResourceHandlers[Result].Ext<>aExt) do
  5253. Dec(Result);
  5254. end;
  5255. function TPascalScanner.FindResourceHandler(const aExt: string): TResourceHandler;
  5256. Var
  5257. Idx : Integer;
  5258. begin
  5259. Idx:=IndexOfResourceHandler(aExt);
  5260. if Idx=-1 then
  5261. Result:=Nil
  5262. else
  5263. Result:=FResourceHandlers[Idx].handler;
  5264. end;
  5265. function TPascalScanner.ReadIdentifier(const AParam: string): string;
  5266. var
  5267. p, l: Integer;
  5268. begin
  5269. p:=1;
  5270. l:=length(AParam);
  5271. while (p<=l) and (AParam[p] in IdentChars) do inc(p);
  5272. Result:=LeftStr(AParam,p-1);
  5273. end;
  5274. function TPascalScanner.FetchLine: boolean;
  5275. begin
  5276. if CurSourceFile.IsEOF then
  5277. begin
  5278. if {$ifdef UsePChar}FTokenPos<>nil{$else}FTokenPos>0{$endif} then
  5279. begin
  5280. FCurLine := '';
  5281. FTokenPos := {$ifdef UsePChar}nil{$else}-1{$endif};
  5282. inc(FCurRow); // set CurRow to last line+1
  5283. inc(FModuleRow);
  5284. FCurColumnOffset:=1;
  5285. end;
  5286. Result := false;
  5287. end else
  5288. begin
  5289. FCurLine := CurSourceFile.ReadLine;
  5290. FTokenPos := {$ifdef UsePChar}PChar(CurLine){$else}1{$endif};
  5291. Result := true;
  5292. {$ifdef UseAnsiStrings}
  5293. if (FCurRow = 0)
  5294. and (Length(CurLine) >= 3)
  5295. and (FTokenPos[0] = #$EF)
  5296. and (FTokenPos[1] = #$BB)
  5297. and (FTokenPos[2] = #$BF) then
  5298. // ignore UTF-8 Byte Order Mark
  5299. inc(FTokenPos, 3);
  5300. {$endif}
  5301. Inc(FCurRow);
  5302. inc(FModuleRow);
  5303. FCurColumnOffset:=1;
  5304. if (FCurSourceFile is TMacroReader) and (FCurRow=1) then
  5305. begin
  5306. FCurRow:=TMacroReader(FCurSourceFile).CurRow;
  5307. FCurColumnOffset:=TMacroReader(FCurSourceFile).CurCol;
  5308. end;
  5309. if LogEvent(sleLineNumber)
  5310. and (((FCurRow Mod 100) = 0)
  5311. or CurSourceFile.IsEOF) then
  5312. DoLog(mtInfo,nLogLineNumber,SLogLineNumber,[FCurRow],True); // log last line
  5313. end;
  5314. end;
  5315. procedure TPascalScanner.AddFile(aFilename: string);
  5316. var
  5317. i: Integer;
  5318. begin
  5319. for i:=0 to FFiles.Count-1 do
  5320. if FFiles[i]=aFilename then exit;
  5321. FFiles.Add(aFilename);
  5322. end;
  5323. function TPascalScanner.GetMacroName(const Param: String): String;
  5324. var
  5325. p: Integer;
  5326. begin
  5327. Result:=Trim(Param);
  5328. p:=1;
  5329. while (p<=length(Result)) and (Result[p] in ['a'..'z','A'..'Z','0'..'9','_']) do
  5330. inc(p);
  5331. SetLength(Result,p-1);
  5332. end;
  5333. procedure TPascalScanner.SetCurMsg(MsgType: TMessageType; MsgNumber: integer;
  5334. const Fmt: String; Args: array of const);
  5335. begin
  5336. FLastMsgType := MsgType;
  5337. FLastMsgNumber := MsgNumber;
  5338. FLastMsgPattern := Fmt;
  5339. FLastMsg := SafeFormat(Fmt,Args);
  5340. CreateMsgArgs(FLastMsgArgs,Args);
  5341. end;
  5342. function TPascalScanner.AddDefine(const aName: String; Quiet: boolean): boolean;
  5343. begin
  5344. If FDefines.IndexOf(aName)>=0 then exit(false);
  5345. Result:=true;
  5346. FDefines.Add(aName);
  5347. if (not Quiet) and LogEvent(sleConditionals) then
  5348. DoLog(mtInfo,nLogMacroDefined,sLogMacroDefined,[aName])
  5349. end;
  5350. function TPascalScanner.RemoveDefine(const aName: String; Quiet: boolean
  5351. ): boolean;
  5352. Var
  5353. I : Integer;
  5354. begin
  5355. I:=FDefines.IndexOf(aName);
  5356. if (I<0) then exit(false);
  5357. Result:=true;
  5358. FDefines.Delete(I);
  5359. if (not Quiet) and LogEvent(sleConditionals) then
  5360. DoLog(mtInfo,nLogMacroUnDefined,sLogMacroUnDefined,[aName])
  5361. end;
  5362. function TPascalScanner.UnDefine(const aName: String; Quiet: boolean): boolean;
  5363. begin
  5364. // Important: always call both, do not use OR
  5365. Result:=RemoveDefine(aName,Quiet);
  5366. if RemoveMacro(aName,Quiet) then Result:=true;
  5367. end;
  5368. function TPascalScanner.IsDefined(const aName: String): boolean;
  5369. begin
  5370. Result:=(FDefines.IndexOf(aName)>=0) or (FMacros.IndexOf(aName)>=0);
  5371. end;
  5372. function TPascalScanner.IfOpt(Letter: Char): boolean;
  5373. begin
  5374. Letter:=upcase(Letter);
  5375. Result:=(Letter in ['A'..'Z']) and (LetterSwitchNames[Letter]<>'')
  5376. and IsDefined(LetterSwitchNames[Letter]);
  5377. end;
  5378. function TPascalScanner.AddMacro(const aName, aValue: String; Quiet: boolean
  5379. ): boolean;
  5380. var
  5381. Index: Integer;
  5382. begin
  5383. Index:=FMacros.IndexOf(aName);
  5384. If (Index=-1) then
  5385. FMacros.AddObject(aName,TMacroDef.Create(aName,aValue))
  5386. else
  5387. begin
  5388. if TMacroDef(FMacros.Objects[Index]).Value=aValue then exit(false);
  5389. TMacroDef(FMacros.Objects[Index]).Value:=aValue;
  5390. end;
  5391. Result:=true;
  5392. if (not Quiet) and LogEvent(sleConditionals) then
  5393. DoLog(mtInfo,nLogMacroXSetToY,SLogMacroXSetToY,[aName,aValue])
  5394. end;
  5395. function TPascalScanner.RemoveMacro(const aName: String; Quiet: boolean
  5396. ): boolean;
  5397. var
  5398. Index: Integer;
  5399. begin
  5400. Index:=FMacros.IndexOf(aName);
  5401. if Index<0 then exit(false);
  5402. Result:=true;
  5403. TMacroDef(FMacros.Objects[Index]).{$ifdef pas2js}Destroy{$else}Free{$endif};
  5404. FMacros.Delete(Index);
  5405. if (not Quiet) and LogEvent(sleConditionals) then
  5406. DoLog(mtInfo,nLogMacroUnDefined,sLogMacroUnDefined,[aName])
  5407. end;
  5408. procedure TPascalScanner.SetCompilerMode(S: String);
  5409. begin
  5410. HandleMode(S);
  5411. end;
  5412. function TPascalScanner.CurSourcePos: TPasSourcePos;
  5413. begin
  5414. Result.FileName:=CurFilename;
  5415. Result.Row:=CurRow;
  5416. Result.Column:=CurColumn;
  5417. end;
  5418. function TPascalScanner.SetForceCaret(AValue: Boolean): Boolean;
  5419. begin
  5420. Result:=toForceCaret in FTokenOptions;
  5421. if aValue then
  5422. Include(FTokenOptions,toForceCaret)
  5423. else
  5424. Exclude(FTokenOptions,toForceCaret)
  5425. end;
  5426. function TPascalScanner.IgnoreMsgType(MsgType: TMessageType): boolean;
  5427. begin
  5428. Result:=false;
  5429. case MsgType of
  5430. mtWarning: if not (bsWarnings in FCurrentBoolSwitches) then exit(true);
  5431. mtNote: if not (bsNotes in FCurrentBoolSwitches) then exit(true);
  5432. mtHint: if not (bsHints in FCurrentBoolSwitches) then exit(true);
  5433. else
  5434. // Do nothing, satisfy compiler
  5435. end;
  5436. end;
  5437. end.