pscanner.pp 139 KB

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