1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990 |
- {
- This file is part of the Free Component Library
- Pascal source lexical scanner
- Copyright (c) 2003 by
- Areca Systems GmbH / Sebastian Guenther, [email protected]
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit PScanner;
- {$mode objfpc}
- {$h+}
- {$ifdef fpc}
- {$define UsePChar}
- {$define UseAnsiStrings}
- {$define HasStreams}
- {$IF FPC_FULLVERSION<30101}
- {$define EmulateArrayInsert}
- {$endif}
- {$define HasFS}
- {$endif}
- {$IFDEF NODEJS}
- {$define HasFS}
- {$ENDIF}
- interface
- uses
- {$ifdef pas2js}
- js,
- {$IFDEF NODEJS}
- NodeJSFS,
- {$ENDIF}
- Types,
- {$endif}
- SysUtils, Classes;
- // message numbers
- const
- nErrInvalidCharacter = 1001;
- nErrOpenString = 1002;
- nErrIncludeFileNotFound = 1003;
- nErrIfXXXNestingLimitReached = 1004;
- nErrInvalidPPElse = 1005;
- nErrInvalidPPEndif = 1006;
- nLogOpeningFile = 1007;
- nLogLineNumber = 1008; // same as FPC
- nLogIFDefAccepted = 1009;
- nLogIFDefRejected = 1010;
- nLogIFNDefAccepted = 1011;
- nLogIFNDefRejected = 1012;
- nLogIFAccepted = 1013;
- nLogIFRejected = 1014;
- nLogIFOptAccepted = 1015;
- nLogIFOptRejected = 1016;
- nLogELSEIFAccepted = 1017;
- nLogELSEIFRejected = 1018;
- nErrInvalidMode = 1019;
- nErrInvalidModeSwitch = 1020;
- nErrXExpectedButYFound = 1021;
- nErrRangeCheck = 1022;
- nErrDivByZero = 1023;
- nErrOperandAndOperatorMismatch = 1024;
- nUserDefined = 1025;
- nLogMacroDefined = 1026; // FPC=3101
- nLogMacroUnDefined = 1027; // FPC=3102
- nWarnIllegalCompilerDirectiveX = 1028;
- nIllegalStateForWarnDirective = 1027;
- nErrIncludeLimitReached = 1028;
- nMisplacedGlobalCompilerSwitch = 1029;
- nLogMacroXSetToY = 1030;
- nInvalidDispatchFieldName = 1031;
- // resourcestring patterns of messages
- resourcestring
- SErrInvalidCharacter = 'Invalid character ''%s''';
- SErrOpenString = 'string exceeds end of line';
- SErrIncludeFileNotFound = 'Could not find include file ''%s''';
- SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
- SErrInvalidPPElse = '$ELSE without matching $IFxxx';
- SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
- SLogOpeningFile = 'Opening source file "%s".';
- SLogLineNumber = 'Reading line %d.';
- SLogIFDefAccepted = 'IFDEF %s found, accepting.';
- SLogIFDefRejected = 'IFDEF %s found, rejecting.';
- SLogIFNDefAccepted = 'IFNDEF %s found, accepting.';
- SLogIFNDefRejected = 'IFNDEF %s found, rejecting.';
- SLogIFAccepted = 'IF %s found, accepting.';
- SLogIFRejected = 'IF %s found, rejecting.';
- SLogIFOptAccepted = 'IFOpt %s found, accepting.';
- SLogIFOptRejected = 'IFOpt %s found, rejecting.';
- SLogELSEIFAccepted = 'ELSEIF %s found, accepting.';
- SLogELSEIFRejected = 'ELSEIF %s found, rejecting.';
- SErrInvalidMode = 'Invalid mode: "%s"';
- SErrInvalidModeSwitch = 'Invalid mode switch: "%s"';
- SErrXExpectedButYFound = '"%s" expected, but "%s" found';
- SErrRangeCheck = 'range check failed';
- SErrDivByZero = 'division by zero';
- SErrOperandAndOperatorMismatch = 'operand and operator mismatch';
- SUserDefined = 'User defined: "%s"';
- SLogMacroDefined = 'Macro defined: %s';
- SLogMacroUnDefined = 'Macro undefined: %s';
- SWarnIllegalCompilerDirectiveX = 'Illegal compiler directive "%s"';
- SIllegalStateForWarnDirective = 'Illegal state "%s" for $WARN directive';
- SErrIncludeLimitReached = 'Include file limit reached';
- SMisplacedGlobalCompilerSwitch = 'Misplaced global compiler switch, ignored';
- SLogMacroXSetToY = 'Macro %s set to %s';
- SInvalidDispatchFieldName = 'Invalid Dispatch field name';
- type
- TMessageType = (
- mtFatal,
- mtError,
- mtWarning,
- mtNote,
- mtHint,
- mtInfo,
- mtDebug
- );
- TMessageTypes = set of TMessageType;
- TMessageArgs = array of string;
- TToken = (
- tkEOF,
- tkWhitespace,
- tkComment,
- tkIdentifier,
- tkString,
- tkNumber,
- tkChar,
- // Simple (one-character) tokens
- tkBraceOpen, // '('
- tkBraceClose, // ')'
- tkMul, // '*'
- tkPlus, // '+'
- tkComma, // ','
- tkMinus, // '-'
- tkDot, // '.'
- tkDivision, // '/'
- tkColon, // ':'
- tkSemicolon, // ';'
- tkLessThan, // '<'
- tkEqual, // '='
- tkGreaterThan, // '>'
- tkAt, // '@'
- tkSquaredBraceOpen, // '['
- tkSquaredBraceClose, // ']'
- tkCaret, // '^'
- tkBackslash, // '\'
- // Two-character tokens
- tkDotDot, // '..'
- tkAssign, // ':='
- tkNotEqual, // '<>'
- tkLessEqualThan, // '<='
- tkGreaterEqualThan, // '>='
- tkPower, // '**'
- tkSymmetricalDifference, // '><'
- tkAssignPlus, // +=
- tkAssignMinus, // -=
- tkAssignMul, // *=
- tkAssignDivision, // /=
- tkAtAt, // @@
- // Reserved words
- tkabsolute,
- tkand,
- tkarray,
- tkas,
- tkasm,
- tkbegin,
- tkbitpacked,
- tkcase,
- tkclass,
- tkconst,
- tkconstref,
- tkconstructor,
- tkdestructor,
- tkdispinterface,
- tkdiv,
- tkdo,
- tkdownto,
- tkelse,
- tkend,
- tkexcept,
- tkexports,
- tkfalse,
- tkfile,
- tkfinalization,
- tkfinally,
- tkfor,
- tkfunction,
- tkgeneric,
- tkgoto,
- tkif,
- tkimplementation,
- tkin,
- tkinherited,
- tkinitialization,
- tkinline,
- tkinterface,
- tkis,
- tklabel,
- tklibrary,
- tkmod,
- tknil,
- tknot,
- tkobject,
- tkof,
- tkoperator,
- tkor,
- tkpacked,
- tkprocedure,
- tkprogram,
- tkproperty,
- tkraise,
- tkrecord,
- tkrepeat,
- tkResourceString,
- tkself,
- tkset,
- tkshl,
- tkshr,
- tkspecialize,
- // tkstring,
- tkthen,
- tkthreadvar,
- tkto,
- tktrue,
- tktry,
- tktype,
- tkunit,
- tkuntil,
- tkuses,
- tkvar,
- tkwhile,
- tkwith,
- tkxor,
- tkLineEnding,
- tkTab
- );
- TTokens = set of TToken;
- TModeSwitch = (
- msNone,
- { generic }
- msFpc, msObjfpc, msDelphi, msDelphiUnicode, msTP7, msMac, msIso, msExtpas, msGPC,
- { more specific }
- msClass, { delphi class model }
- msObjpas, { load objpas unit }
- msResult, { result in functions }
- msStringPchar, { pchar 2 string conversion }
- msCVarSupport, { cvar variable directive }
- msNestedComment, { nested comments }
- msTPProcVar, { tp style procvars (no @ needed) }
- msMacProcVar, { macpas style procvars }
- msRepeatForward, { repeating forward declarations is needed }
- msPointer2Procedure, { allows the assignement of pointers to
- procedure variables }
- msAutoDeref, { does auto dereferencing of struct. vars }
- msInitFinal, { initialization/finalization for units }
- msDefaultAnsistring, { ansistring turned on by default }
- msOut, { support the calling convention OUT }
- msDefaultPara, { support default parameters }
- msHintDirective, { support hint directives }
- msDuplicateNames, { allow locals/paras to have duplicate names of globals }
- msProperty, { allow properties }
- msDefaultInline, { allow inline proc directive }
- msExcept, { allow exception-related keywords }
- msObjectiveC1, { support interfacing with Objective-C (1.0) }
- msObjectiveC2, { support interfacing with Objective-C (2.0) }
- msNestedProcVars, { support nested procedural variables }
- msNonLocalGoto, { support non local gotos (like iso pascal) }
- msAdvancedRecords, { advanced record syntax with visibility sections, methods and properties }
- msISOLikeUnaryMinus, { unary minus like in iso pascal: same precedence level as binary minus/plus }
- msSystemCodePage, { use system codepage as compiler codepage by default, emit ansistrings with system codepage }
- msFinalFields, { allows declaring fields as "final", which means they must be initialised
- in the (class) constructor and are constant from then on (same as final
- fields in Java) }
- msDefaultUnicodestring, { makes the default string type in $h+ mode unicodestring rather than
- ansistring; similarly, char becomes unicodechar rather than ansichar }
- msTypeHelpers, { allows the declaration of "type helper" (non-Delphi) or "record helper"
- (Delphi) for primitive types }
- msCBlocks, { 'cblocks', support for http://en.wikipedia.org/wiki/Blocks_(C_language_extension) }
- msISOLikeIO, { I/O as it required by an ISO compatible compiler }
- msISOLikeProgramsPara, { program parameters as it required by an ISO compatible compiler }
- msISOLikeMod, { mod operation as it is required by an iso compatible compiler }
- msArrayOperators, { use Delphi compatible array operators instead of custom ones ("+") }
- msExternalClass, { Allow external class definitions }
- msPrefixedAttributes, { Allow attributes, disable proc modifier [] }
- msOmitRTTI, { treat class section 'published' as 'public' and typeinfo does not work on symbols declared with this switch }
- msMultiHelpers, { off=only one helper per type, on=all }
- msImplicitFunctionSpec { implicit function specialization }
- );
- TModeSwitches = Set of TModeSwitch;
- // switches, that can be 'on' or 'off'
- TBoolSwitch = (
- bsNone,
- bsAlign, // A align fields
- bsBoolEval, // B complete boolean evaluation
- bsAssertions, // C generate code for assertions
- bsDebugInfo, // D generate debuginfo (debug lines), OR: $description 'text'
- bsExtension, // E output file extension
- // F
- bsImportedData, // G
- bsLongStrings, // H String=AnsiString
- bsIOChecks, // I generate EInOutError
- bsWriteableConst, // J writable typed const
- // K
- bsLocalSymbols, // L generate local symbol information (debug, requires $D+)
- bsTypeInfo, // M allow published members OR $M minstacksize,maxstacksize
- // N
- bsOptimization, // O enable safe optimizations (-O1)
- bsOpenStrings, // P deprecated Delphi directive
- bsOverflowChecks, // Q or $OV
- bsRangeChecks, // R
- // S
- bsTypedAddress, // T enabled: @variable gives typed pointer, otherwise untyped pointer
- bsSafeDivide, // U
- bsVarStringChecks,// V strict shortstring checking, e.g. cannot pass shortstring[3] to shortstring
- bsStackframes, // W always generate stackframes (debugging)
- bsExtendedSyntax, // X deprecated Delphi directive
- bsReferenceInfo, // Y store for each identifier the declaration location
- // Z
- bsHints,
- bsNotes,
- bsWarnings,
- bsMacro,
- bsScopedEnums,
- bsObjectChecks, // check methods 'Self' and object type casts
- bsPointerMath, // pointer arithmetic
- bsGoto // support label and goto, set by {$goto on|off}
- );
- TBoolSwitches = set of TBoolSwitch;
- const
- LetterToBoolSwitch: array['A'..'Z'] of TBoolSwitch = (
- bsAlign, // A
- bsBoolEval, // B
- bsAssertions, // C
- bsDebugInfo, // D or $description
- bsExtension, // E
- bsNone, // F
- bsImportedData, // G
- bsLongStrings, // H
- bsIOChecks, // I or $include
- bsWriteableConst, // J
- bsNone, // K
- bsLocalSymbols, // L
- bsTypeInfo, // M or $M minstacksize,maxstacksize
- bsNone, // N
- bsOptimization, // O
- bsOpenStrings, // P
- bsOverflowChecks, // Q
- bsRangeChecks, // R or $resource
- bsNone, // S
- bsTypedAddress, // T
- bsSafeDivide, // U
- bsVarStringChecks,// V
- bsStackframes, // W
- bsExtendedSyntax, // X
- bsReferenceInfo, // Y
- bsNone // Z
- );
- bsAll = [low(TBoolSwitch)..high(TBoolSwitch)];
- bsFPCMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
- bsObjFPCMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
- bsDelphiMode: TBoolSwitches = [bsWriteableConst,bsGoto];
- bsDelphiUnicodeMode: TBoolSwitches = [bsWriteableConst,bsGoto];
- bsMacPasMode: TBoolSwitches = [bsPointerMath,bsWriteableConst];
- type
- TValueSwitch = (
- vsInterfaces,
- vsDispatchField,
- vsDispatchStrField
- );
- TValueSwitches = set of TValueSwitch;
- TValueSwitchArray = array[TValueSwitch] of string;
- const
- vsAllValueSwitches = [low(TValueSwitch)..high(TValueSwitch)];
- DefaultValueSwitches: array[TValueSwitch] of string = (
- 'com', // vsInterfaces
- 'Msg', // vsDispatchField
- 'MsgStr' // vsDispatchStrField
- );
- DefaultMaxIncludeStackDepth = 20;
- type
- TWarnMsgState = (
- wmsDefault,
- wmsOn,
- wmsOff,
- wmsError
- );
- type
- TTokenOption = (toForceCaret,toOperatorToken);
- TTokenOptions = Set of TTokenOption;
- { TMacroDef }
- TMacroDef = Class(TObject)
- Private
- FName: String;
- FValue: String;
- Public
- Constructor Create(Const AName,AValue : String);
- Property Name : String Read FName;
- Property Value : String Read FValue Write FValue;
- end;
- { TLineReader }
- TLineReader = class
- Private
- FFilename: string;
- public
- constructor Create(const AFilename: string); virtual;
- function IsEOF: Boolean; virtual; abstract;
- function ReadLine: string; virtual; abstract;
- property Filename: string read FFilename;
- end;
- { TFileLineReader }
- TFileLineReader = class(TLineReader)
- private
- {$ifdef pas2js}
- {$else}
- FTextFile: Text;
- FFileOpened: Boolean;
- FBuffer : Array[0..4096-1] of byte;
- {$endif}
- public
- constructor Create(const AFilename: string); override;
- destructor Destroy; override;
- function IsEOF: Boolean; override;
- function ReadLine: string; override;
- end;
- { TStreamLineReader }
- TStreamLineReader = class(TLineReader)
- private
- FContent: String;
- FPos : Integer;
- public
- {$ifdef HasStreams}
- Procedure InitFromStream(AStream : TStream);
- {$endif}
- Procedure InitFromString(const s: string);
- function IsEOF: Boolean; override;
- function ReadLine: string; override;
- end;
- { TFileStreamLineReader }
- TFileStreamLineReader = class(TStreamLineReader)
- Public
- constructor Create(const AFilename: string); override;
- end;
- { TStringStreamLineReader }
- TStringStreamLineReader = class(TStreamLineReader)
- Public
- constructor Create(const AFilename: string; Const ASource: String); reintroduce;
- end;
- { TMacroReader }
- TMacroReader = Class(TStringStreamLineReader)
- private
- FCurCol: Integer;
- FCurRow: Integer;
- Public
- Property CurCol : Integer Read FCurCol Write FCurCol;
- Property CurRow : Integer Read FCurRow Write FCurRow;
- end;
- { TBaseFileResolver }
- TBaseFileResolver = class
- private
- FBaseDirectory: string;
- FIncludePaths: TStringList;
- FStrictFileCase : Boolean;
- Protected
- function FindIncludeFileName(const aFilename: string): String; virtual; abstract;
- procedure SetBaseDirectory(AValue: string); virtual;
- procedure SetStrictFileCase(AValue: Boolean); virtual;
- Property IncludePaths: TStringList Read FIncludePaths;
- public
- constructor Create; virtual;
- destructor Destroy; override;
- procedure AddIncludePath(const APath: string); virtual;
- function FindSourceFile(const AName: string): TLineReader; virtual; abstract;
- function FindIncludeFile(const AName: string): TLineReader; virtual; abstract;
- Property StrictFileCase : Boolean Read FStrictFileCase Write SetStrictFileCase;
- property BaseDirectory: string read FBaseDirectory write SetBaseDirectory;
- end;
- TBaseFileResolverClass = Class of TBaseFileResolver;
- {$IFDEF HASFS}
- { TFileResolver }
- TFileResolver = class(TBaseFileResolver)
- private
- {$ifdef HasStreams}
- FUseStreams: Boolean;
- {$endif}
- Protected
- Function FindIncludeFileName(const AName: string): String; override;
- Function CreateFileReader(Const AFileName : String) : TLineReader; virtual;
- Public
- function FindSourceFile(const AName: string): TLineReader; override;
- function FindIncludeFile(const AName: string): TLineReader; override;
- {$ifdef HasStreams}
- Property UseStreams : Boolean Read FUseStreams Write FUseStreams;
- {$endif}
- end;
- {$ENDIF}
- {$ifdef fpc}
- { TStreamResolver }
- TStreamResolver = class(TBaseFileResolver)
- Private
- FOwnsStreams: Boolean;
- FStreams : TStringList;
- function FindStream(const AName: string; ScanIncludes: Boolean): TStream;
- function FindStreamReader(const AName: string; ScanIncludes: Boolean): TLineReader;
- procedure SetOwnsStreams(AValue: Boolean);
- Protected
- function FindIncludeFileName(const aFilename: string): String; override;
- Public
- constructor Create; override;
- destructor Destroy; override;
- Procedure Clear;
- Procedure AddStream(Const AName : String; AStream : TStream);
- function FindSourceFile(const AName: string): TLineReader; override;
- function FindIncludeFile(const AName: string): TLineReader; override;
- Property OwnsStreams : Boolean Read FOwnsStreams write SetOwnsStreams;
- Property Streams: TStringList read FStreams;
- end;
- {$endif}
- const
- CondDirectiveBool: array[boolean] of string = (
- '0', // false
- '1' // true Note: True is <>'0'
- );
- type
- TMaxPrecInt = {$ifdef fpc}int64{$else}NativeInt{$endif};
- TMaxFloat = {$ifdef fpc}extended{$else}double{$endif};
- TCondDirectiveEvaluator = class;
- TCEEvalVarEvent = function(Sender: TCondDirectiveEvaluator; Name: String; out Value: string): boolean of object;
- TCEEvalFunctionEvent = function(Sender: TCondDirectiveEvaluator; Name, Param: String; out Value: string): boolean of object;
- TCELogEvent = procedure(Sender: TCondDirectiveEvaluator; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif}) of object;
- { TCondDirectiveEvaluator - evaluate $IF expression }
- TCondDirectiveEvaluator = class
- private
- FOnEvalFunction: TCEEvalFunctionEvent;
- FOnEvalVariable: TCEEvalVarEvent;
- FOnLog: TCELogEvent;
- protected
- type
- TPrecedenceLevel = (
- ceplFirst, // tkNot
- ceplSecond, // *, /, div, mod, and, shl, shr
- ceplThird, // +, -, or, xor
- ceplFourth // =, <>, <, >, <=, >=
- );
- TStackItem = record
- Level: TPrecedenceLevel;
- Operathor: TToken;
- Operand: String;
- OperandPos: integer;
- end;
- protected
- {$ifdef UsePChar}
- FTokenStart: PChar;
- FTokenEnd: PChar;
- {$else}
- FTokenStart: integer; // position in Expression
- FTokenEnd: integer; // position in Expression
- {$endif}
- FToken: TToken;
- FStack: array of TStackItem;
- FStackTop: integer;
- function IsFalse(const Value: String): boolean; inline;
- function IsTrue(const Value: String): boolean; inline;
- function IsInteger(const Value: String; out i: TMaxPrecInt): boolean;
- function IsExtended(const Value: String; out e: TMaxFloat): boolean;
- procedure NextToken;
- procedure Log(aMsgType: TMessageType; aMsgNumber: integer;
- const aMsgFmt: String; const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}; MsgPos: integer = 0);
- procedure LogXExpectedButTokenFound(const X: String; ErrorPos: integer = 0);
- procedure ReadOperand(Skip: boolean = false); // unary operators plus one operand
- procedure ReadExpression; // binary operators
- procedure ResolveStack(MinStackLvl: integer; Level: TPrecedenceLevel;
- NewOperator: TToken);
- function GetTokenString: String;
- function GetStringLiteralValue: String; // read value of tkString
- procedure Push(const AnOperand: String; OperandPosition: integer);
- public
- Expression: String;
- MsgPos: integer;
- MsgNumber: integer;
- MsgType: TMessageType;
- MsgPattern: String; // Format parameter
- constructor Create;
- destructor Destroy; override;
- function Eval(const Expr: string): boolean;
- property OnEvalVariable: TCEEvalVarEvent read FOnEvalVariable write FOnEvalVariable;
- property OnEvalFunction: TCEEvalFunctionEvent read FOnEvalFunction write FOnEvalFunction;
- property OnLog: TCELogEvent read FOnLog write FOnLog;
- end;
- EScannerError = class(Exception);
- EFileNotFoundError = class(Exception);
- TPascalScannerPPSkipMode = (ppSkipNone, ppSkipIfBranch, ppSkipElseBranch, ppSkipAll);
- TPOption = (
- po_delphi, // DEPRECATED since fpc 3.1.1: Delphi mode: forbid nested comments
- po_KeepScannerError, // default: catch EScannerError and raise an EParserError instead
- po_CAssignments, // allow C-operators += -= *= /=
- po_ResolveStandardTypes, // search for 'longint', 'string', etc., do not use dummies, TPasResolver sets this to use its declarations
- po_AsmWhole, // store whole text between asm..end in TPasImplAsmStatement.Tokens
- po_NoOverloadedProcs, // do not create TPasOverloadedProc for procs with same name
- po_KeepClassForward, // disabled: delete class fowards when there is a class declaration
- po_ArrayRangeExpr, // enable: create TPasArrayType.IndexRange, disable: create TPasArrayType.Ranges
- po_SelfToken, // Self is a token. For backward compatibility.
- po_CheckModeSwitches, // error on unknown modeswitch with an error
- po_CheckCondFunction, // error on unknown function in conditional expression, default: return '0'
- po_StopOnErrorDirective, // error on user $Error, $message error|fatal
- po_ExtConstWithoutExpr, // allow typed const without expression in external class and with external modifier
- po_StopOnUnitInterface // parse only a unit name and stop at interface keyword
- );
- TPOptions = set of TPOption;
- type
- TPasSourcePos = Record
- FileName: String;
- Row, Column: Cardinal;
- end;
- const
- DefPasSourcePos: TPasSourcePos = (Filename:''; Row:0; Column:0);
- type
- { TPascalScanner }
- TPScannerLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
- TPScannerLogEvent = (sleFile,sleLineNumber,sleConditionals,sleDirective);
- TPScannerLogEvents = Set of TPScannerLogEvent;
- TPScannerDirectiveEvent = procedure(Sender: TObject; Directive, Param: String;
- var Handled: boolean) of object;
- TPScannerFormatPathEvent = function(const aPath: string): string of object;
- TPScannerWarnEvent = procedure(Sender: TObject; Identifier: string; State: TWarnMsgState; var Handled: boolean) of object;
- TPScannerModeDirective = procedure(Sender: TObject; NewMode: TModeSwitch; Before: boolean; var Handled: boolean) of object;
- TPasScannerTokenPos = {$ifdef UsePChar}PChar{$else}integer{$endif};
- TPascalScanner = class
- private
- type
- TWarnMsgNumberState = record
- Number: integer;
- State: TWarnMsgState;
- end;
- TWarnMsgNumberStateArr = array of TWarnMsgNumberState;
- private
- FAllowedBoolSwitches: TBoolSwitches;
- FAllowedModeSwitches: TModeSwitches;
- FAllowedValueSwitches: TValueSwitches;
- FConditionEval: TCondDirectiveEvaluator;
- FCurrentBoolSwitches: TBoolSwitches;
- FCurrentModeSwitches: TModeSwitches;
- FCurrentValueSwitches: TValueSwitchArray;
- FCurTokenPos: TPasSourcePos;
- FLastMsg: string;
- FLastMsgArgs: TMessageArgs;
- FLastMsgNumber: integer;
- FLastMsgPattern: string;
- FLastMsgType: TMessageType;
- FFileResolver: TBaseFileResolver;
- FCurSourceFile: TLineReader;
- FCurFilename: string;
- FCurRow: Integer;
- FCurColumnOffset: integer;
- FCurToken: TToken;
- FCurTokenString: string;
- FCurLine: string;
- FMaxIncludeStackDepth: integer;
- FModuleRow: Integer;
- FMacros: TStrings; // Objects are TMacroDef
- FDefines: TStrings;
- FNonTokens: TTokens;
- FOnDirective: TPScannerDirectiveEvent;
- FOnEvalFunction: TCEEvalFunctionEvent;
- FOnEvalVariable: TCEEvalVarEvent;
- FOnFormatPath: TPScannerFormatPathEvent;
- FOnModeChanged: TPScannerModeDirective;
- FOnWarnDirective: TPScannerWarnEvent;
- FOptions: TPOptions;
- FLogEvents: TPScannerLogEvents;
- FOnLog: TPScannerLogHandler;
- FPreviousToken: TToken;
- FReadOnlyBoolSwitches: TBoolSwitches;
- FReadOnlyModeSwitches: TModeSwitches;
- FReadOnlyValueSwitches: TValueSwitches;
- FSkipComments: Boolean;
- FSkipGlobalSwitches: boolean;
- FSkipWhiteSpace: Boolean;
- FTokenOptions: TTokenOptions;
- FTokenPos: TPasScannerTokenPos; // position in FCurLine }
- FIncludeStack: TFPList;
- FFiles: TStrings;
- FWarnMsgStates: TWarnMsgNumberStateArr;
- // Preprocessor $IFxxx skipping data
- PPSkipMode: TPascalScannerPPSkipMode;
- PPIsSkipping: Boolean;
- PPSkipStackIndex: Integer;
- PPSkipModeStack: array[0..255] of TPascalScannerPPSkipMode;
- PPIsSkippingStack: array[0..255] of Boolean;
- function GetCurColumn: Integer;
- function GetCurrentValueSwitch(V: TValueSwitch): string;
- function GetForceCaret: Boolean;
- function GetMacrosOn: boolean;
- function IndexOfWarnMsgState(Number: integer; InsertPos: boolean): integer;
- function OnCondEvalFunction(Sender: TCondDirectiveEvaluator; Name,
- Param: String; out Value: string): boolean;
- procedure OnCondEvalLog(Sender: TCondDirectiveEvaluator;
- Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- function OnCondEvalVar(Sender: TCondDirectiveEvaluator; Name: String; out
- Value: string): boolean;
- procedure SetAllowedBoolSwitches(const AValue: TBoolSwitches);
- procedure SetAllowedModeSwitches(const AValue: TModeSwitches);
- procedure SetAllowedValueSwitches(const AValue: TValueSwitches);
- procedure SetMacrosOn(const AValue: boolean);
- procedure SetOptions(AValue: TPOptions);
- procedure SetReadOnlyBoolSwitches(const AValue: TBoolSwitches);
- procedure SetReadOnlyModeSwitches(const AValue: TModeSwitches);
- procedure SetReadOnlyValueSwitches(const AValue: TValueSwitches);
- protected
- function ReadIdentifier(const AParam: string): string;
- function FetchLine: boolean;
- procedure AddFile(aFilename: string); virtual;
- function GetMacroName(const Param: String): String;
- procedure SetCurMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Msg : String; SkipSourceInfo : Boolean = False);overload;
- Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of {$ifdef pas2js}jsvalue{$else}const{$endif};SkipSourceInfo : Boolean = False);overload;
- procedure Error(MsgNumber: integer; const Msg: string);overload;
- procedure Error(MsgNumber: integer; const Fmt: string; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});overload;
- procedure PushSkipMode;
- function HandleDirective(const ADirectiveText: String): TToken; virtual;
- function HandleLetterDirective(Letter: char; Enable: boolean): TToken; virtual;
- procedure HandleBoolDirective(bs: TBoolSwitch; const Param: String); virtual;
- procedure DoHandleDirective(Sender: TObject; Directive, Param: String;
- var Handled: boolean); virtual;
- procedure HandleIFDEF(const AParam: String);
- procedure HandleIFNDEF(const AParam: String);
- procedure HandleIFOPT(const AParam: String);
- procedure HandleIF(const AParam: String);
- procedure HandleELSEIF(const AParam: String);
- procedure HandleELSE(const AParam: String);
- procedure HandleENDIF(const AParam: String);
- procedure HandleDefine(Param: String); virtual;
- procedure HandleDispatchField(Param: String; vs: TValueSwitch); virtual;
- procedure HandleError(Param: String); virtual;
- procedure HandleMessageDirective(Param: String); virtual;
- procedure HandleIncludeFile(Param: String); virtual;
- procedure HandleUnDefine(Param: String); virtual;
- function HandleInclude(const Param: String): TToken; virtual;
- procedure HandleMode(const Param: String); virtual;
- procedure HandleModeSwitch(const Param: String); virtual;
- function HandleMacro(AIndex: integer): TToken; virtual;
- procedure HandleInterfaces(const Param: String); virtual;
- procedure HandleWarn(Param: String); virtual;
- procedure HandleWarnIdentifier(Identifier, Value: String); virtual;
- procedure PushStackItem; virtual;
- function DoFetchTextToken: TToken;
- function DoFetchToken: TToken;
- procedure ClearFiles;
- Procedure ClearMacros;
- Procedure SetCurToken(const AValue: TToken);
- Procedure SetCurTokenString(const AValue: string);
- procedure SetCurrentBoolSwitches(const AValue: TBoolSwitches); virtual;
- procedure SetCurrentModeSwitches(AValue: TModeSwitches); virtual;
- procedure SetCurrentValueSwitch(V: TValueSwitch; const AValue: string);
- procedure SetWarnMsgState(Number: integer; State: TWarnMsgState); virtual;
- function GetWarnMsgState(Number: integer): TWarnMsgState; virtual;
- function LogEvent(E : TPScannerLogEvent) : Boolean; inline;
- property TokenPos: TPasScannerTokenPos read FTokenPos write FTokenPos;
- public
- constructor Create(AFileResolver: TBaseFileResolver);
- destructor Destroy; override;
- procedure OpenFile(AFilename: string);
- procedure FinishedModule; virtual; // called by parser after end.
- function FormatPath(const aFilename: string): string; virtual;
- procedure SetNonToken(aToken : TToken);
- procedure UnsetNonToken(aToken : TToken);
- procedure SetTokenOption(aOption : TTokenoption);
- procedure UnSetTokenOption(aOption : TTokenoption);
- function CheckToken(aToken : TToken; const ATokenString : String) : TToken;
- function FetchToken: TToken;
- function ReadNonPascalTillEndToken(StopAtLineEnd: boolean): TToken; virtual;
- function AddDefine(const aName: String; Quiet: boolean = false): boolean;
- function RemoveDefine(const aName: String; Quiet: boolean = false): boolean;
- function UnDefine(const aName: String; Quiet: boolean = false): boolean; // check defines and macros
- function IsDefined(const aName: String): boolean; // check defines and macros
- function IfOpt(Letter: Char): boolean;
- function AddMacro(const aName, aValue: String; Quiet: boolean = false): boolean;
- function RemoveMacro(const aName: String; Quiet: boolean = false): boolean;
- procedure SetCompilerMode(S : String);
- function CurSourcePos: TPasSourcePos;
- function SetForceCaret(AValue : Boolean) : Boolean; // returns old state
- function IgnoreMsgType(MsgType: TMessageType): boolean; virtual;
- property FileResolver: TBaseFileResolver read FFileResolver;
- property Files: TStrings read FFiles;
- property CurSourceFile: TLineReader read FCurSourceFile;
- property CurFilename: string read FCurFilename;
- property CurLine: string read FCurLine;
- property CurRow: Integer read FCurRow;
- property CurColumn: Integer read GetCurColumn;
- property CurToken: TToken read FCurToken;
- property CurTokenString: string read FCurTokenString;
- property CurTokenPos: TPasSourcePos read FCurTokenPos;
- property PreviousToken : TToken Read FPreviousToken;
- property ModuleRow: Integer read FModuleRow;
- property NonTokens : TTokens Read FNonTokens;
- Property TokenOptions : TTokenOptions Read FTokenOptions Write FTokenOptions;
- property Defines: TStrings read FDefines;
- property Macros: TStrings read FMacros;
- property MacrosOn: boolean read GetMacrosOn write SetMacrosOn;
- property OnDirective: TPScannerDirectiveEvent read FOnDirective write FOnDirective;
- property AllowedModeSwitches: TModeSwitches read FAllowedModeSwitches Write SetAllowedModeSwitches;
- property ReadOnlyModeSwitches: TModeSwitches read FReadOnlyModeSwitches Write SetReadOnlyModeSwitches;// always set, cannot be disabled
- property CurrentModeSwitches: TModeSwitches read FCurrentModeSwitches Write SetCurrentModeSwitches;
- property AllowedBoolSwitches: TBoolSwitches read FAllowedBoolSwitches Write SetAllowedBoolSwitches;
- property ReadOnlyBoolSwitches: TBoolSwitches read FReadOnlyBoolSwitches Write SetReadOnlyBoolSwitches;// cannot be changed by code
- property CurrentBoolSwitches: TBoolSwitches read FCurrentBoolSwitches Write SetCurrentBoolSwitches;
- property AllowedValueSwitches: TValueSwitches read FAllowedValueSwitches Write SetAllowedValueSwitches;
- property ReadOnlyValueSwitches: TValueSwitches read FReadOnlyValueSwitches Write SetReadOnlyValueSwitches;// cannot be changed by code
- property CurrentValueSwitch[V: TValueSwitch]: string read GetCurrentValueSwitch Write SetCurrentValueSwitch;
- property WarnMsgState[Number: integer]: TWarnMsgState read GetWarnMsgState write SetWarnMsgState;
- property Options : TPOptions read FOptions write SetOptions;
- property SkipWhiteSpace : Boolean Read FSkipWhiteSpace Write FSkipWhiteSpace;
- property SkipComments : Boolean Read FSkipComments Write FSkipComments;
- property SkipGlobalSwitches: Boolean read FSkipGlobalSwitches write FSkipGlobalSwitches;
- property MaxIncludeStackDepth: integer read FMaxIncludeStackDepth write FMaxIncludeStackDepth default DefaultMaxIncludeStackDepth;
- property ForceCaret : Boolean read GetForceCaret;
- property LogEvents : TPScannerLogEvents read FLogEvents write FLogEvents;
- property OnLog : TPScannerLogHandler read FOnLog write FOnLog;
- property OnFormatPath: TPScannerFormatPathEvent read FOnFormatPath write FOnFormatPath;
- property ConditionEval: TCondDirectiveEvaluator read FConditionEval;
- property OnEvalVariable: TCEEvalVarEvent read FOnEvalVariable write FOnEvalVariable;
- property OnEvalFunction: TCEEvalFunctionEvent read FOnEvalFunction write FOnEvalFunction;
- property OnWarnDirective: TPScannerWarnEvent read FOnWarnDirective write FOnWarnDirective;
- property OnModeChanged: TPScannerModeDirective read FOnModeChanged write FOnModeChanged; // set by TPasParser
- property LastMsg: string read FLastMsg write FLastMsg;
- property LastMsgNumber: integer read FLastMsgNumber write FLastMsgNumber;
- property LastMsgType: TMessageType read FLastMsgType write FLastMsgType;
- property LastMsgPattern: string read FLastMsgPattern write FLastMsgPattern;
- property LastMsgArgs: TMessageArgs read FLastMsgArgs write FLastMsgArgs;
- end;
- const
- TokenInfos: array[TToken] of string = (
- 'EOF',
- 'Whitespace',
- 'Comment',
- 'Identifier',
- 'string',
- 'Number',
- 'Character',
- '(',
- ')',
- '*',
- '+',
- ',',
- '-',
- '.',
- '/',
- ':',
- ';',
- '<',
- '=',
- '>',
- '@',
- '[',
- ']',
- '^',
- '\',
- '..',
- ':=',
- '<>',
- '<=',
- '>=',
- '**',
- '><',
- '+=',
- '-=',
- '*=',
- '/=',
- '@@',
- // Reserved words
- 'absolute',
- 'and',
- 'array',
- 'as',
- 'asm',
- 'begin',
- 'bitpacked',
- 'case',
- 'class',
- 'const',
- 'constref',
- 'constructor',
- 'destructor',
- 'dispinterface',
- 'div',
- 'do',
- 'downto',
- 'else',
- 'end',
- 'except',
- 'exports',
- 'false',
- 'file',
- 'finalization',
- 'finally',
- 'for',
- 'function',
- 'generic',
- 'goto',
- 'if',
- 'implementation',
- 'in',
- 'inherited',
- 'initialization',
- 'inline',
- 'interface',
- 'is',
- 'label',
- 'library',
- 'mod',
- 'nil',
- 'not',
- 'object',
- 'of',
- 'operator',
- 'or',
- 'packed',
- 'procedure',
- 'program',
- 'property',
- 'raise',
- 'record',
- 'repeat',
- 'resourcestring',
- 'self',
- 'set',
- 'shl',
- 'shr',
- 'specialize',
- // 'string',
- 'then',
- 'threadvar',
- 'to',
- 'true',
- 'try',
- 'type',
- 'unit',
- 'until',
- 'uses',
- 'var',
- 'while',
- 'with',
- 'xor',
- 'LineEnding',
- 'Tab'
- );
- SModeSwitchNames : array[TModeSwitch] of string =
- ( '', // msNone
- '', // Fpc,
- '', // Objfpc,
- '', // Delphi,
- '', // DelphiUnicode,
- '', // TP7,
- '', // Mac,
- '', // Iso,
- '', // Extpas,
- '', // GPC,
- { more specific }
- 'CLASS',
- 'OBJPAS',
- 'RESULT',
- 'PCHARTOSTRING',
- 'CVAR',
- 'NESTEDCOMMENTS',
- 'CLASSICPROCVARS',
- 'MACPROCVARS',
- 'REPEATFORWARD',
- 'POINTERTOPROCVAR',
- 'AUTODEREF',
- 'INITFINAL',
- 'ANSISTRINGS',
- 'OUT',
- 'DEFAULTPARAMETERS',
- 'HINTDIRECTIVE',
- 'DUPLICATELOCALS',
- 'PROPERTIES',
- 'ALLOWINLINE',
- 'EXCEPTIONS',
- 'OBJECTIVEC1',
- 'OBJECTIVEC2',
- 'NESTEDPROCVARS',
- 'NONLOCALGOTO',
- 'ADVANCEDRECORDS',
- 'ISOUNARYMINUS',
- 'SYSTEMCODEPAGE',
- 'FINALFIELDS',
- 'UNICODESTRINGS',
- 'TYPEHELPERS',
- 'CBLOCKS',
- 'ISOIO',
- 'ISOPROGRAMPARAS',
- 'ISOMOD',
- 'ARRAYOPERATORS',
- 'EXTERNALCLASS',
- 'PREFIXEDATTRIBUTES',
- 'OMITRTTI',
- 'MULTIHELPERS',
- 'IMPLICITFUNCTIONSPECIALIZATION'
- );
- LetterSwitchNames: array['A'..'Z'] of string=(
- 'ALIGN' // A align fields
- ,'BOOLEVAL' // B complete boolean evaluation
- ,'ASSERTIONS' // C generate code for assertions
- ,'DEBUGINFO' // D generate debuginfo (debug lines), OR: $description 'text'
- ,'EXTENSION' // E output file extension
- ,'' // F
- ,'IMPORTEDDATA' // G
- ,'LONGSTRINGS' // H String=AnsiString
- ,'IOCHECKS' // I generate EInOutError
- ,'WRITEABLECONST' // J writable typed const
- ,'' // K
- ,'LOCALSYMBOLS' // L generate local symbol information (debug, requires $D+)
- ,'TYPEINFO' // M allow published members OR $M minstacksize,maxstacksize
- ,'' // N
- ,'OPTIMIZATION' // O enable safe optimizations (-O1)
- ,'OPENSTRINGS' // P deprecated Delphi directive
- ,'OVERFLOWCHECKS' // Q
- ,'RANGECHECKS' // R OR resource
- ,'' // S
- ,'TYPEDADDRESS' // T enabled: @variable gives typed pointer, otherwise untyped pointer
- ,'SAFEDIVIDE' // U
- ,'VARSTRINGCHECKS'// V strict shortstring checking, e.g. cannot pass shortstring[3] to shortstring
- ,'STACKFRAMES' // W always generate stackframes (debugging)
- ,'EXTENDEDSYNTAX' // X deprecated Delphi directive
- ,'REFERENCEINFO' // Y store for each identifier the declaration location
- ,'' // Z
- );
- BoolSwitchNames: array[TBoolSwitch] of string = (
- // letter directives
- 'None',
- 'Align',
- 'BoolEval',
- 'Assertions',
- 'DebugInfo',
- 'Extension',
- 'ImportedData',
- 'LongStrings',
- 'IOChecks',
- 'WriteableConst',
- 'LocalSymbols',
- 'TypeInfo',
- 'Optimization',
- 'OpenStrings',
- 'OverflowChecks',
- 'RangeChecks',
- 'TypedAddress',
- 'SafeDivide',
- 'VarStringChecks',
- 'Stackframes',
- 'ExtendedSyntax',
- 'ReferenceInfo',
- // other bool directives
- 'Hints',
- 'Notes',
- 'Warnings',
- 'Macro',
- 'ScopedEnums',
- 'ObjectChecks',
- 'PointerMath',
- 'Goto'
- );
- ValueSwitchNames: array[TValueSwitch] of string = (
- 'Interfaces', // vsInterfaces
- 'DispatchField', // vsDispatchField
- 'DispatchStrField' // vsDispatchStrField
- );
- const
- AllLanguageModes = [msFPC,msObjFPC,msDelphi,msTP7,msMac,msISO,msExtPas];
- const
- MessageTypeNames : Array[TMessageType] of string = (
- 'Fatal','Error','Warning','Note','Hint','Info','Debug'
- );
- const
- // all mode switches supported by FPC
- msAllModeSwitches = [low(TModeSwitch)..High(TModeSwitch)];
- DelphiModeSwitches = [msDelphi,msClass,msObjpas,msResult,msStringPchar,
- msPointer2Procedure,msAutoDeref,msTPProcVar,msInitFinal,msDefaultAnsistring,
- msOut,msDefaultPara,msDuplicateNames,msHintDirective,
- msProperty,msDefaultInline,msExcept,msAdvancedRecords,msTypeHelpers,
- msPrefixedAttributes,msArrayOperators,msImplicitFunctionSpec
- ];
- DelphiUnicodeModeSwitches = delphimodeswitches + [msSystemCodePage,msDefaultUnicodestring];
- // mode switches of $mode FPC, don't confuse with msAllModeSwitches
- FPCModeSwitches = [msFpc,msStringPchar,msNestedComment,msRepeatForward,
- msCVarSupport,msInitFinal,msHintDirective,msProperty,msDefaultInline];
- //FPCBoolSwitches bsObjectChecks
- OBJFPCModeSwitches = [msObjfpc,msClass,msObjpas,msResult,msStringPchar,msNestedComment,
- msRepeatForward,msCVarSupport,msInitFinal,msOut,msDefaultPara,msHintDirective,
- msProperty,msDefaultInline,msExcept];
- TPModeSwitches = [msTP7,msTPProcVar,msDuplicateNames];
- GPCModeSwitches = [msGPC,msTPProcVar];
- MacModeSwitches = [msMac,msCVarSupport,msMacProcVar,msNestedProcVars,
- msNonLocalGoto,msISOLikeUnaryMinus,msDefaultInline];
- ISOModeSwitches = [msIso,msTPProcVar,msDuplicateNames,msNestedProcVars,
- msNonLocalGoto,msISOLikeUnaryMinus,msISOLikeIO,msISOLikeProgramsPara,
- msISOLikeMod];
- ExtPasModeSwitches = [msExtpas,msTPProcVar,msDuplicateNames,msNestedProcVars,
- msNonLocalGoto,msISOLikeUnaryMinus,msISOLikeIO,msISOLikeProgramsPara,
- msISOLikeMod];
- function StrToModeSwitch(aName: String): TModeSwitch;
- function ModeSwitchesToStr(Switches: TModeSwitches): string;
- function BoolSwitchesToStr(Switches: TBoolSwitches): string;
- function FilenameIsAbsolute(const TheFilename: string):boolean;
- function FilenameIsWinAbsolute(const TheFilename: string): boolean;
- function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
- function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
- Function ExtractFilenameOnly(Const AFileName : String) : String;
- procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- function SafeFormat(const Fmt: string; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): string;
- implementation
- const
- IdentChars = ['0'..'9', 'A'..'Z', 'a'..'z','_'];
- Digits = ['0'..'9'];
- Letters = ['a'..'z','A'..'Z'];
- HexDigits = ['0'..'9','a'..'f','A'..'F'];
- Var
- SortedTokens : array of TToken;
- LowerCaseTokens : Array[ttoken] of String;
- Function ExtractFilenameOnly(Const AFileName : String) : String;
- begin
- Result:=ChangeFileExt(ExtractFileName(aFileName),'');
- end;
- Procedure SortTokenInfo;
- Var
- tk: tToken;
- I,J,K, l: integer;
- begin
- for tk:=Low(TToken) to High(ttoken) do
- LowerCaseTokens[tk]:=LowerCase(TokenInfos[tk]);
- SetLength(SortedTokens,Ord(tkXor)-Ord(tkAbsolute)+1);
- I:=0;
- for tk := tkAbsolute to tkXOR do
- begin
- SortedTokens[i]:=tk;
- Inc(i);
- end;
- l:=Length(SortedTokens)-1;
- k:=l shr 1;
- while (k>0) do
- begin
- for i:=0 to l-k do
- begin
- j:=i;
- while (J>=0) and (LowerCaseTokens[SortedTokens[J]]>LowerCaseTokens[SortedTokens[J+K]]) do
- begin
- tk:=SortedTokens[J];
- SortedTokens[J]:=SortedTokens[J+K];
- SortedTokens[J+K]:=tk;
- if (J>K) then
- Dec(J,K)
- else
- J := 0
- end;
- end;
- K:=K shr 1;
- end;
- end;
- function IndexOfToken(Const AToken : string) : Integer;
- var
- B,T,M : Integer;
- N : String;
- begin
- B:=0;
- T:=Length(SortedTokens)-1;
- while (B<=T) do
- begin
- M:=(B+T) div 2;
- N:=LowerCaseTokens[SortedTokens[M]];
- if (AToken<N) then
- T:=M-1
- else if (AToken=N) then
- Exit(M)
- else
- B:=M+1;
- end;
- Result:=-1;
- end;
- function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
- Var
- I : Integer;
- begin
- if (Length(SortedTokens)=0) then
- SortTokenInfo;
- I:=IndexOfToken(LowerCase(AToken));
- Result:=I<>-1;
- If Result then
- T:=SortedTokens[I];
- end;
- procedure CreateMsgArgs(var MsgArgs: TMessageArgs; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- var
- i: Integer;
- {$ifdef pas2js}
- v: jsvalue;
- {$endif}
- begin
- SetLength(MsgArgs, High(Args)-Low(Args)+1);
- for i:=Low(Args) to High(Args) do
- {$ifdef pas2js}
- begin
- v:=Args[i];
- if isBoolean(v) then
- MsgArgs[i] := BoolToStr(Boolean(v))
- else if isString(v) then
- MsgArgs[i] := String(v)
- else if isNumber(v) then
- begin
- if IsInteger(v) then
- MsgArgs[i] := str(NativeInt(v))
- else
- MsgArgs[i] := str(double(v));
- end
- else
- MsgArgs[i]:='';
- end;
- {$else}
- case Args[i].VType of
- vtInteger: MsgArgs[i] := IntToStr(Args[i].VInteger);
- vtBoolean: MsgArgs[i] := BoolToStr(Args[i].VBoolean);
- vtChar: MsgArgs[i] := Args[i].VChar;
- {$ifndef FPUNONE}
- vtExtended: ; // Args[i].VExtended^;
- {$ENDIF}
- vtString: MsgArgs[i] := Args[i].VString^;
- vtPointer: ; // Args[i].VPointer;
- vtPChar: MsgArgs[i] := Args[i].VPChar;
- vtObject: ; // Args[i].VObject;
- vtClass: ; // Args[i].VClass;
- vtWideChar: MsgArgs[i] := AnsiString(Args[i].VWideChar);
- vtPWideChar: MsgArgs[i] := Args[i].VPWideChar;
- vtAnsiString: MsgArgs[i] := AnsiString(Args[i].VAnsiString);
- vtCurrency: ; // Args[i].VCurrency^);
- vtVariant: ; // Args[i].VVariant^);
- vtInterface: ; // Args[i].VInterface^);
- vtWidestring: MsgArgs[i] := AnsiString(WideString(Args[i].VWideString));
- vtInt64: MsgArgs[i] := IntToStr(Args[i].VInt64^);
- vtQWord: MsgArgs[i] := IntToStr(Args[i].VQWord^);
- vtUnicodeString:MsgArgs[i] := AnsiString(UnicodeString(Args[i].VUnicodeString));
- end;
- {$endif}
- end;
- function SafeFormat(const Fmt: string; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif}): string;
- var
- MsgArgs: TMessageArgs;
- i: Integer;
- begin
- try
- Result:=Format(Fmt,Args);
- except
- Result:='';
- MsgArgs:=nil;
- CreateMsgArgs(MsgArgs,Args);
- for i:=0 to length(MsgArgs)-1 do
- begin
- if i>0 then
- Result:=Result+',';
- Result:=Result+MsgArgs[i];
- end;
- Result:='{'+Fmt+'}['+Result+']';
- end;
- end;
- type
- TIncludeStackItem = class
- SourceFile: TLineReader;
- Filename: string;
- Token: TToken;
- TokenString: string;
- Line: string;
- Row: Integer;
- ColumnOffset: integer;
- TokenPos: {$ifdef UsePChar}PChar;{$else}integer; { position in Line }{$endif}
- end;
- function StrToModeSwitch(aName: String): TModeSwitch;
- var
- ms: TModeSwitch;
- begin
- aName:=UpperCase(aName);
- if aName='' then exit(msNone);
- for ms in TModeSwitch do
- if SModeSwitchNames[ms]=aName then exit(ms);
- Result:=msNone;
- end;
- function ModeSwitchesToStr(Switches: TModeSwitches): string;
- var
- ms: TModeSwitch;
- begin
- Result:='';
- for ms in Switches do
- Result:=Result+SModeSwitchNames[ms]+',';
- Result:='['+LeftStr(Result,length(Result)-1)+']';
- end;
- function BoolSwitchesToStr(Switches: TBoolSwitches): string;
- var
- bs: TBoolSwitch;
- begin
- Result:='';
- for bs in Switches do
- Result:=Result+BoolSwitchNames[bs]+',';
- Result:='['+LeftStr(Result,length(Result)-1)+']';
- end;
- function FilenameIsAbsolute(const TheFilename: string):boolean;
- begin
- {$IFDEF WINDOWS}
- // windows
- Result:=FilenameIsWinAbsolute(TheFilename);
- {$ELSE}
- // unix
- Result:=FilenameIsUnixAbsolute(TheFilename);
- {$ENDIF}
- end;
- function FilenameIsWinAbsolute(const TheFilename: string): boolean;
- begin
- Result:=((length(TheFilename)>=2) and (TheFilename[1] in ['A'..'Z','a'..'z'])
- and (TheFilename[2]=':'))
- or ((length(TheFilename)>=2)
- and (TheFilename[1]='\') and (TheFilename[2]='\'));
- end;
- function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
- begin
- Result:=(TheFilename<>'') and (TheFilename[1]='/');
- end;
- { TCondDirectiveEvaluator }
- // inline
- function TCondDirectiveEvaluator.IsFalse(const Value: String): boolean;
- begin
- Result:=Value=CondDirectiveBool[false];
- end;
- // inline
- function TCondDirectiveEvaluator.IsTrue(const Value: String): boolean;
- begin
- Result:=Value<>CondDirectiveBool[false];
- end;
- function TCondDirectiveEvaluator.IsInteger(const Value: String; out i: TMaxPrecInt
- ): boolean;
- var
- Code: integer;
- begin
- val(Value,i,Code);
- Result:=Code=0;
- end;
- function TCondDirectiveEvaluator.IsExtended(const Value: String; out e: TMaxFloat
- ): boolean;
- var
- Code: integer;
- begin
- val(Value,e,Code);
- Result:=Code=0;
- end;
- procedure TCondDirectiveEvaluator.NextToken;
- const
- IdentChars = ['a'..'z','A'..'Z','_','0'..'9'];
- {$ifdef UsePChar}
- function IsIdentifier(a,b: PChar): boolean;
- var
- ac: Char;
- begin
- repeat
- ac:=a^;
- if (ac in IdentChars) and (upcase(ac)=upcase(b^)) then
- begin
- inc(a);
- inc(b);
- end
- else
- begin
- Result:=(not (ac in IdentChars)) and (not (b^ in IdentChars));
- exit;
- end;
- until false;
- end;
- {$endif}
- function ReadIdentifier: TToken;
- begin
- Result:=tkIdentifier;
- {$ifdef UsePChar}
- case FTokenEnd-FTokenStart of
- 2:
- if IsIdentifier(FTokenStart,'or') then
- Result:=tkor;
- 3:
- if IsIdentifier(FTokenStart,'not') then
- Result:=tknot
- else if IsIdentifier(FTokenStart,'and') then
- Result:=tkand
- else if IsIdentifier(FTokenStart,'xor') then
- Result:=tkxor
- else if IsIdentifier(FTokenStart,'shl') then
- Result:=tkshl
- else if IsIdentifier(FTokenStart,'shr') then
- Result:=tkshr
- else if IsIdentifier(FTokenStart,'mod') then
- Result:=tkmod
- else if IsIdentifier(FTokenStart,'div') then
- Result:=tkdiv;
- end;
- {$else}
- case lowercase(copy(Expression,FTokenStart,FTokenEnd-FTokenStart)) of
- 'or': Result:=tkor;
- 'not': Result:=tknot;
- 'and': Result:=tkand;
- 'xor': Result:=tkxor;
- 'shl': Result:=tkshl;
- 'shr': Result:=tkshr;
- 'mod': Result:=tkmod;
- 'div': Result:=tkdiv;
- end;
- {$endif}
- end;
- {$ifndef UsePChar}
- const
- AllSpaces = [#9,#10,#13,' '];
- Digits = ['0'..'9'];
- HexDigits = ['0'..'9'];
- var
- l: integer;
- Src: String;
- {$endif}
- begin
- FTokenStart:=FTokenEnd;
- // skip white space
- {$ifdef UsePChar}
- repeat
- case FTokenStart^ of
- #0:
- if FTokenStart-PChar(Expression)>=length(Expression) then
- begin
- FToken:=tkEOF;
- FTokenEnd:=FTokenStart;
- exit;
- end
- else
- inc(FTokenStart);
- #9,#10,#13,' ':
- inc(FTokenStart);
- else break;
- end;
- until false;
- {$else}
- Src:=Expression;
- l:=length(Src);
- while (FTokenStart<=l) and (Src[FTokenStart] in AllSpaces) do
- inc(FTokenStart);
- if FTokenStart>l then
- begin
- FToken:=tkEOF;
- FTokenEnd:=FTokenStart;
- exit;
- end;
- {$endif}
- // read token
- FTokenEnd:=FTokenStart;
- case {$ifdef UsePChar}FTokenEnd^{$else}Src[FTokenEnd]{$endif} of
- 'a'..'z','A'..'Z','_':
- begin
- inc(FTokenEnd);
- {$ifdef UsePChar}
- while FTokenEnd^ in IdentChars do inc(FTokenEnd);
- {$else}
- while (FTokenEnd<=l) and (Src[FTokenEnd] in IdentChars) do inc(FTokenEnd);
- {$endif}
- FToken:=ReadIdentifier;
- end;
- '0'..'9':
- begin
- FToken:=tkNumber;
- // examples: 1, 1.2, 1.2E3, 1E-2
- inc(FTokenEnd);
- {$ifdef UsePChar}
- while FTokenEnd^ in Digits do inc(FTokenEnd);
- if (FTokenEnd^='.') and (FTokenEnd[1]<>'.') then
- begin
- inc(FTokenEnd);
- while FTokenEnd^ in Digits do inc(FTokenEnd);
- end;
- if FTokenEnd^ in ['e','E'] then
- begin
- inc(FTokenEnd);
- if FTokenEnd^ in ['-','+'] then inc(FTokenEnd);
- while FTokenEnd^ in Digits do inc(FTokenEnd);
- end;
- {$else}
- while (FTokenEnd<=l) and (Src[FTokenEnd] in Digits) do inc(FTokenEnd);
- if (FTokenEnd<=l) and (Src[FTokenEnd]='.')
- and ((FTokenEnd=l) or (Src[FTokenEnd+1]<>'.')) then
- begin
- inc(FTokenEnd);
- while (FTokenEnd<=l) and (Src[FTokenEnd] in Digits) do inc(FTokenEnd);
- end;
- if (FTokenEnd<=l) and (Src[FTokenEnd] in ['e','E']) then
- begin
- inc(FTokenEnd);
- if (FTokenEnd<=l) and (Src[FTokenEnd] in ['-','+']) then inc(FTokenEnd);
- while (FTokenEnd<=l) and (Src[FTokenEnd] in Digits) do inc(FTokenEnd);
- end;
- {$endif}
- end;
- '$':
- begin
- FToken:=tkNumber;
- {$ifdef UsePChar}
- while FTokenEnd^ in HexDigits do inc(FTokenEnd);
- {$else}
- while (FTokenEnd<=l) and (Src[FTokenEnd] in HexDigits) do inc(FTokenEnd);
- {$endif}
- end;
- '%':
- begin
- FToken:=tkNumber;
- {$ifdef UsePChar}
- while FTokenEnd^ in ['0','1'] do inc(FTokenEnd);
- {$else}
- while (FTokenEnd<=l) and (Src[FTokenEnd] in ['0','1']) do inc(FTokenEnd);
- {$endif}
- end;
- '(':
- begin
- FToken:=tkBraceOpen;
- inc(FTokenEnd);
- end;
- ')':
- begin
- FToken:=tkBraceClose;
- inc(FTokenEnd);
- end;
- '=':
- begin
- FToken:=tkEqual;
- inc(FTokenEnd);
- end;
- '<':
- begin
- inc(FTokenEnd);
- case {$ifdef UsePChar}FTokenEnd^{$else}copy(Src,FTokenEnd,1){$endif} of
- '=':
- begin
- FToken:=tkLessEqualThan;
- inc(FTokenEnd);
- end;
- '<':
- begin
- FToken:=tkshl;
- inc(FTokenEnd);
- end;
- '>':
- begin
- FToken:=tkNotEqual;
- inc(FTokenEnd);
- end;
- else
- FToken:=tkLessThan;
- end;
- end;
- '>':
- begin
- inc(FTokenEnd);
- case {$ifdef UsePChar}FTokenEnd^{$else}copy(Src,FTokenEnd,1){$endif} of
- '=':
- begin
- FToken:=tkGreaterEqualThan;
- inc(FTokenEnd);
- end;
- '>':
- begin
- FToken:=tkshr;
- inc(FTokenEnd);
- end;
- else
- FToken:=tkGreaterThan;
- end;
- end;
- '+':
- begin
- FToken:=tkPlus;
- inc(FTokenEnd);
- end;
- '-':
- begin
- FToken:=tkMinus;
- inc(FTokenEnd);
- end;
- '*':
- begin
- FToken:=tkMul;
- inc(FTokenEnd);
- end;
- '/':
- begin
- FToken:=tkDivision;
- inc(FTokenEnd);
- end;
- '''':
- begin
- FToken:=tkString;
- repeat
- inc(FTokenEnd);
- {$ifdef UsePChar}
- if FTokenEnd^='''' then
- begin
- inc(FTokenEnd);
- if FTokenEnd^<>'''' then break;
- end
- else if FTokenEnd^ in [#0,#10,#13] then
- Log(mtError,nErrOpenString,SErrOpenString,[]);
- {$else}
- if FTokenEnd>l then
- Log(mtError,nErrOpenString,SErrOpenString,[]);
- case Src[FTokenEnd] of
- '''':
- begin
- inc(FTokenEnd);
- if (FTokenEnd>l) or (Src[FTokenEnd]<>'''') then break;
- end;
- #10,#13:
- Log(mtError,nErrOpenString,SErrOpenString,[]);
- end;
- {$endif}
- until false;
- end
- else
- FToken:=tkEOF;
- end;
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.NextToken END Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
- {$ENDIF}
- end;
- procedure TCondDirectiveEvaluator.Log(aMsgType: TMessageType;
- aMsgNumber: integer; const aMsgFmt: String;
- const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
- MsgPos: integer);
- begin
- if MsgPos<1 then
- MsgPos:=FTokenEnd{$ifdef UsePChar}-PChar(Expression)+1{$endif};
- MsgType:=aMsgType;
- MsgNumber:=aMsgNumber;
- MsgPattern:=aMsgFmt;
- if Assigned(OnLog) then
- begin
- OnLog(Self,Args);
- if not (aMsgType in [mtError,mtFatal]) then exit;
- end;
- raise EScannerError.CreateFmt(MsgPattern+' at '+IntToStr(MsgPos),Args);
- end;
- procedure TCondDirectiveEvaluator.LogXExpectedButTokenFound(const X: String;
- ErrorPos: integer);
- begin
- Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
- [X,TokenInfos[FToken]],ErrorPos);
- end;
- procedure TCondDirectiveEvaluator.ReadOperand(Skip: boolean);
- { Read operand and put it on the stack
- Examples:
- Variable
- not Variable
- not not undefined Variable
- defined(Variable)
- !Variable
- unicodestring
- 123
- $45
- 'Abc'
- (expression)
- }
- var
- i: TMaxPrecInt;
- e: extended;
- S, aName, Param: String;
- Code: integer;
- NameStartP: {$ifdef UsePChar}PChar{$else}integer{$endif};
- p, Lvl: integer;
- begin
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.ReadOperand START Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken,BoolToStr(Skip,' SKIP',''));
- {$ENDIF}
- case FToken of
- tknot:
- begin
- // boolean not
- NextToken;
- ReadOperand(Skip);
- if not Skip then
- FStack[FStackTop].Operand:=CondDirectiveBool[IsFalse(FStack[FStackTop].Operand)];
- end;
- tkMinus:
- begin
- // unary minus
- NextToken;
- ReadOperand(Skip);
- if not Skip then
- begin
- i:=StrToInt64Def(FStack[FStackTop].Operand,0);
- FStack[FStackTop].Operand:=IntToStr(-i);
- end;
- end;
- tkPlus:
- begin
- // unary plus
- NextToken;
- ReadOperand(Skip);
- if not Skip then
- begin
- i:=StrToInt64Def(FStack[FStackTop].Operand,0);
- FStack[FStackTop].Operand:=IntToStr(i);
- end;
- end;
- tkNumber:
- begin
- // number: convert to decimal
- if not Skip then
- begin
- S:=GetTokenString;
- val(S,i,Code);
- if Code=0 then
- begin
- // integer
- Push(IntToStr(i),FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif});
- end
- else
- begin
- val(S,e,Code);
- if Code>0 then
- Log(mtError,nErrRangeCheck,sErrRangeCheck,[]);
- if e=0 then ;
- // float
- Push(S,FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif});
- end;
- end;
- NextToken;
- end;
- tkString:
- begin
- // string literal
- if not Skip then
- Push(GetStringLiteralValue,FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif});
- NextToken;
- end;
- tkIdentifier:
- if Skip then
- begin
- NextToken;
- if FToken=tkBraceOpen then
- begin
- // only one parameter is supported
- NextToken;
- if FToken=tkIdentifier then
- NextToken;
- if FToken<>tkBraceClose then
- LogXExpectedButTokenFound(')');
- NextToken;
- end;
- end
- else
- begin
- aName:=GetTokenString;
- p:=FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif};
- NextToken;
- if FToken=tkBraceOpen then
- begin
- // function
- NameStartP:=FTokenStart;
- NextToken;
- // only one parameter is supported
- Param:='';
- if FToken=tkIdentifier then
- begin
- Param:=GetTokenString;
- NextToken;
- end;
- if FToken<>tkBraceClose then
- LogXExpectedButTokenFound(')');
- if not OnEvalFunction(Self,aName,Param,S) then
- begin
- FTokenStart:=NameStartP;
- FTokenEnd:=FTokenStart+length(aName);
- LogXExpectedButTokenFound('function');
- end;
- Push(S,p);
- NextToken;
- end
- else
- begin
- // variable
- if OnEvalVariable(Self,aName,S) then
- Push(S,p)
- else
- begin
- // variable does not exist -> evaluates to false
- Push(CondDirectiveBool[false],p);
- end;
- end;
- end;
- tkBraceOpen:
- begin
- NextToken;
- if Skip then
- begin
- Lvl:=1;
- repeat
- case FToken of
- tkEOF:
- LogXExpectedButTokenFound(')');
- tkBraceOpen: inc(Lvl);
- tkBraceClose:
- begin
- dec(Lvl);
- if Lvl=0 then break;
- end;
- end;
- NextToken;
- until false;
- end
- else
- begin
- ReadExpression;
- if FToken<>tkBraceClose then
- LogXExpectedButTokenFound(')');
- end;
- NextToken;
- end;
- else
- LogXExpectedButTokenFound('identifier');
- end;
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.ReadOperand END Top=',FStackTop,' Value="',FStack[FStackTop].Operand,'" Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
- {$ENDIF}
- end;
- procedure TCondDirectiveEvaluator.ReadExpression;
- // read operand operator operand ... til tkEOF or tkBraceClose
- var
- OldStackTop: Integer;
- procedure ReadBinary(Level: TPrecedenceLevel; NewOperator: TToken);
- begin
- ResolveStack(OldStackTop,Level,NewOperator);
- NextToken;
- ReadOperand;
- end;
- begin
- OldStackTop:=FStackTop;
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.ReadExpression START Top=',FStackTop,' Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
- {$ENDIF}
- ReadOperand;
- repeat
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.ReadExpression NEXT Top=',FStackTop,' Token[',FTokenStart-PChar(Expression)+1,']="',GetTokenString,'" ',FToken);
- {$ENDIF}
- case FToken of
- tkEOF,tkBraceClose:
- begin
- ResolveStack(OldStackTop,high(TPrecedenceLevel),tkEOF);
- exit;
- end;
- tkand:
- begin
- ResolveStack(OldStackTop,ceplSecond,tkand);
- NextToken;
- if (FStackTop=OldStackTop+1) and IsFalse(FStack[FStackTop].Operand) then
- begin
- // false and ...
- // -> skip all "and"
- repeat
- ReadOperand(true);
- if FToken<>tkand then break;
- NextToken;
- until false;
- FStack[FStackTop].Operathor:=tkEOF;
- end
- else
- ReadOperand;
- end;
- tkMul,tkDivision,tkdiv,tkmod,tkshl,tkshr:
- ReadBinary(ceplSecond,FToken);
- tkor:
- begin
- ResolveStack(OldStackTop,ceplThird,tkor);
- NextToken;
- if (FStackTop=OldStackTop+1) and IsTrue(FStack[FStackTop].Operand) then
- begin
- // true or ...
- // -> skip all "and" and "or"
- repeat
- ReadOperand(true);
- if not (FToken in [tkand,tkor]) then break;
- NextToken;
- until false;
- FStack[FStackTop].Operathor:=tkEOF;
- end
- else
- ReadOperand;
- end;
- tkPlus,tkMinus,tkxor:
- ReadBinary(ceplThird,FToken);
- tkEqual,tkNotEqual,tkLessThan,tkGreaterThan,tkLessEqualThan,tkGreaterEqualThan:
- ReadBinary(ceplFourth,FToken);
- else
- LogXExpectedButTokenFound('operator');
- end;
- until false;
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.ReadExpression END Top=',FStackTop,' Value="',FStack[FStackTop].Operand,'" Token[',FTokenStart-PChar(Expression)+1,']=',GetTokenString,' ',FToken);
- {$ENDIF}
- end;
- procedure TCondDirectiveEvaluator.ResolveStack(MinStackLvl: integer;
- Level: TPrecedenceLevel; NewOperator: TToken);
- var
- A, B, R: String;
- Op: TToken;
- AInt, BInt: TMaxPrecInt;
- AFloat, BFloat: extended;
- BPos: Integer;
- begin
- // resolve all higher or equal level operations
- // Note: the stack top contains operand B
- // the stack second contains operand A and the operator between A and B
- //writeln('TCondDirectiveEvaluator.ResolveStack FStackTop=',FStackTop,' MinStackLvl=',MinStackLvl);
- //if FStackTop>MinStackLvl+1 then
- // writeln(' FStack[FStackTop-1].Level=',FStack[FStackTop-1].Level,' Level=',Level);
- while (FStackTop>MinStackLvl+1) and (FStack[FStackTop-1].Level<=Level) do
- begin
- // pop last operand and operator from stack
- B:=FStack[FStackTop].Operand;
- BPos:=FStack[FStackTop].OperandPos;
- dec(FStackTop);
- Op:=FStack[FStackTop].Operathor;
- A:=FStack[FStackTop].Operand;
- {$IFDEF VerbosePasDirectiveEval}
- writeln(' ResolveStack Top=',FStackTop,' A="',A,'" ',Op,' B="',B,'"');
- {$ENDIF}
- {$IFOPT R+}{$DEFINE RangeChecking}{$ENDIF}
- {$R+}
- try
- case Op of
- tkand: // boolean and
- R:=CondDirectiveBool[IsTrue(A) and IsTrue(B)];
- tkor: // boolean or
- R:=CondDirectiveBool[IsTrue(A) or IsTrue(B)];
- tkxor: // boolean xor
- R:=CondDirectiveBool[IsTrue(A) xor IsTrue(B)];
- tkMul, tkdiv, tkmod, tkshl, tkshr, tkPlus, tkMinus:
- if IsInteger(A,AInt) then
- begin
- if IsInteger(B,BInt) then
- case Op of
- tkMul: R:=IntToStr(AInt*BInt);
- tkdiv: R:=IntToStr(AInt div BInt);
- tkmod: R:=IntToStr(AInt mod BInt);
- tkshl: R:=IntToStr(AInt shl BInt);
- tkshr: R:=IntToStr(AInt shr BInt);
- tkPlus: R:=IntToStr(AInt+BInt);
- tkMinus: R:=IntToStr(AInt-BInt);
- end
- else if IsExtended(B,BFloat) then
- case Op of
- tkMul: R:=FloatToStr(Extended(AInt)*BFloat);
- tkPlus: R:=FloatToStr(Extended(AInt)+BFloat);
- tkMinus: R:=FloatToStr(Extended(AInt)-BFloat);
- else
- LogXExpectedButTokenFound('integer',BPos);
- end
- else
- LogXExpectedButTokenFound('integer',BPos);
- end
- else if IsExtended(A,AFloat) then
- begin
- if IsExtended(B,BFloat) then
- case Op of
- tkMul: R:=FloatToStr(AFloat*BFloat);
- tkPlus: R:=FloatToStr(AFloat+BFloat);
- tkMinus: R:=FloatToStr(AFloat-BFloat);
- else
- LogXExpectedButTokenFound('float',BPos);
- end
- else
- LogXExpectedButTokenFound('float',BPos);
- end
- else
- Log(mtError,nErrOperandAndOperatorMismatch,sErrOperandAndOperatorMismatch,[]);
- tkDivision:
- if IsExtended(A,AFloat) then
- begin
- if IsExtended(B,BFloat) then
- R:=FloatToStr(AFloat/BFloat)
- else
- LogXExpectedButTokenFound('float',BPos);
- end
- else
- Log(mtError,nErrOperandAndOperatorMismatch,sErrOperandAndOperatorMismatch,[]);
- tkEqual,
- tkNotEqual,
- tkLessThan,tkGreaterThan,
- tkLessEqualThan,tkGreaterEqualThan:
- begin
- if IsInteger(A,AInt) and IsInteger(B,BInt) then
- case Op of
- tkEqual: R:=CondDirectiveBool[AInt=BInt];
- tkNotEqual: R:=CondDirectiveBool[AInt<>BInt];
- tkLessThan: R:=CondDirectiveBool[AInt<BInt];
- tkGreaterThan: R:=CondDirectiveBool[AInt>BInt];
- tkLessEqualThan: R:=CondDirectiveBool[AInt<=BInt];
- tkGreaterEqualThan: R:=CondDirectiveBool[AInt>=BInt];
- end
- else if IsExtended(A,AFloat) and IsExtended(B,BFloat) then
- case Op of
- tkEqual: R:=CondDirectiveBool[AFloat=BFloat];
- tkNotEqual: R:=CondDirectiveBool[AFloat<>BFloat];
- tkLessThan: R:=CondDirectiveBool[AFloat<BFloat];
- tkGreaterThan: R:=CondDirectiveBool[AFloat>BFloat];
- tkLessEqualThan: R:=CondDirectiveBool[AFloat<=BFloat];
- tkGreaterEqualThan: R:=CondDirectiveBool[AFloat>=BFloat];
- end
- else
- case Op of
- tkEqual: R:=CondDirectiveBool[A=B];
- tkNotEqual: R:=CondDirectiveBool[A<>B];
- tkLessThan: R:=CondDirectiveBool[A<B];
- tkGreaterThan: R:=CondDirectiveBool[A>B];
- tkLessEqualThan: R:=CondDirectiveBool[A<=B];
- tkGreaterEqualThan: R:=CondDirectiveBool[A>=B];
- end;
- end;
- else
- Log(mtError,nErrOperandAndOperatorMismatch,sErrOperandAndOperatorMismatch,[]);
- end;
- except
- on E: EDivByZero do
- Log(mtError,nErrDivByZero,sErrDivByZero,[]);
- on E: EZeroDivide do
- Log(mtError,nErrDivByZero,sErrDivByZero,[]);
- on E: EMathError do
- Log(mtError,nErrRangeCheck,sErrRangeCheck+' '+E.Message,[]);
- on E: EInterror do
- Log(mtError,nErrRangeCheck,sErrRangeCheck+' '+E.Message,[]);
- end;
- {$IFNDEF RangeChecking}{$R-}{$UNDEF RangeChecking}{$ENDIF}
- {$IFDEF VerbosePasDirectiveEval}
- writeln(' ResolveStack Top=',FStackTop,' A="',A,'" ',Op,' B="',B,'" = "',R,'"');
- {$ENDIF}
- FStack[FStackTop].Operand:=R;
- FStack[FStackTop].OperandPos:=BPos;
- end;
- FStack[FStackTop].Operathor:=NewOperator;
- FStack[FStackTop].Level:=Level;
- end;
- function TCondDirectiveEvaluator.GetTokenString: String;
- begin
- Result:=copy(Expression,FTokenStart{$ifdef UsePChar}-PChar(Expression)+1{$endif},
- FTokenEnd-FTokenStart);
- end;
- function TCondDirectiveEvaluator.GetStringLiteralValue: String;
- var
- {$ifdef UsePChar}
- p, StartP: PChar;
- {$else}
- Src: string;
- p, l, StartP: Integer;
- {$endif}
- begin
- Result:='';
- p:=FTokenStart;
- {$ifdef UsePChar}
- repeat
- case p^ of
- '''':
- begin
- inc(p);
- StartP:=p;
- repeat
- case p^ of
- #0: Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0']);
- '''': break;
- else inc(p);
- end;
- until false;
- if p>StartP then
- Result:=Result+copy(Expression,StartP-PChar(Expression)+1,p-StartP);
- inc(p);
- end;
- else
- Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0']);
- end;
- until false;
- {$else}
- Src:=Expression;
- l:=length(Src);
- repeat
- if (p>l) or (Src[p]<>'''') then
- Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0'])
- else
- begin
- inc(p);
- StartP:=p;
- repeat
- if p>l then
- Log(mtError,nErrInvalidCharacter,SErrInvalidCharacter,['#0'])
- else if Src[p]='''' then
- break
- else
- inc(p);
- until false;
- if p>StartP then
- Result:=Result+copy(Expression,StartP,p-StartP);
- inc(p);
- end;
- until false;
- {$endif}
- end;
- procedure TCondDirectiveEvaluator.Push(const AnOperand: String;
- OperandPosition: integer);
- begin
- inc(FStackTop);
- if FStackTop>=length(FStack) then
- SetLength(FStack,length(FStack)*2+4);
- with FStack[FStackTop] do
- begin
- Operand:=AnOperand;
- OperandPos:=OperandPosition;
- Operathor:=tkEOF;
- Level:=ceplFourth;
- end;
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.Push Top=',FStackTop,' Operand="',AnOperand,'" Pos=',OperandPosition);
- {$ENDIF}
- end;
- constructor TCondDirectiveEvaluator.Create;
- begin
- end;
- destructor TCondDirectiveEvaluator.Destroy;
- begin
- inherited Destroy;
- end;
- function TCondDirectiveEvaluator.Eval(const Expr: string): boolean;
- begin
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TCondDirectiveEvaluator.Eval Expr="',Expr,'"');
- {$ENDIF}
- Expression:=Expr;
- MsgType:=mtInfo;
- MsgNumber:=0;
- MsgPattern:='';
- if Expr='' then exit(false);
- FTokenStart:={$ifdef UsePChar}PChar(Expr){$else}1{$endif};
- FTokenEnd:=FTokenStart;
- FStackTop:=-1;
- NextToken;
- ReadExpression;
- Result:=IsTrue(FStack[0].Operand);
- end;
- { TMacroDef }
- constructor TMacroDef.Create(const AName, AValue: String);
- begin
- FName:=AName;
- FValue:=AValue;
- end;
- { TLineReader }
- constructor TLineReader.Create(const AFilename: string);
- begin
- FFileName:=AFileName;
- end;
- { ---------------------------------------------------------------------
- TFileLineReader
- ---------------------------------------------------------------------}
- constructor TFileLineReader.Create(const AFilename: string);
- begin
- inherited Create(AFileName);
- {$ifdef pas2js}
- raise Exception.Create('ToDo TFileLineReader.Create');
- {$else}
- Assign(FTextFile, AFilename);
- Reset(FTextFile);
- SetTextBuf(FTextFile,FBuffer,SizeOf(FBuffer));
- FFileOpened := true;
- {$endif}
- end;
- destructor TFileLineReader.Destroy;
- begin
- {$ifdef pas2js}
- // ToDo
- {$else}
- if FFileOpened then
- Close(FTextFile);
- {$endif}
- inherited Destroy;
- end;
- function TFileLineReader.IsEOF: Boolean;
- begin
- {$ifdef pas2js}
- Result:=true;// ToDo
- {$else}
- Result := EOF(FTextFile);
- {$endif}
- end;
- function TFileLineReader.ReadLine: string;
- begin
- {$ifdef pas2js}
- Result:='';// ToDo
- {$else}
- ReadLn(FTextFile, Result);
- {$endif}
- end;
- { TStreamLineReader }
- {$ifdef HasStreams}
- Procedure TStreamLineReader.InitFromStream(AStream : TStream);
- begin
- SetLength(FContent,AStream.Size);
- if FContent<>'' then
- AStream.Read(FContent[1],length(FContent));
- FPos:=0;
- end;
- {$endif}
- procedure TStreamLineReader.InitFromString(const s: string);
- begin
- FContent:=s;
- FPos:=0;
- end;
- function TStreamLineReader.IsEOF: Boolean;
- begin
- Result:=FPos>=Length(FContent);
- end;
- function TStreamLineReader.ReadLine: string;
- Var
- LPos : Integer;
- EOL : Boolean;
- begin
- If isEOF then
- exit('');
- LPos:=FPos+1;
- Repeat
- Inc(FPos);
- EOL:=(FContent[FPos] in [#10,#13]);
- until isEOF or EOL;
- If EOL then
- Result:=Copy(FContent,LPos,FPos-LPos)
- else
- Result:=Copy(FContent,LPos,FPos-LPos+1);
- If (not isEOF) and (FContent[FPos]=#13) and (FContent[FPos+1]=#10) then
- inc(FPos);
- end;
- { TFileStreamLineReader }
- constructor TFileStreamLineReader.Create(const AFilename: string);
- {$ifdef HasStreams}
- Var
- S : TFileStream;
- {$endif}
- begin
- inherited Create(AFilename);
- {$ifdef HasStreams}
- S:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
- try
- InitFromStream(S);
- finally
- S.Free;
- end;
- {$else}
- raise Exception.Create('TFileStreamLineReader.Create');
- {$endif}
- end;
- { TStringStreamLineReader }
- constructor TStringStreamLineReader.Create(const AFilename: string; const ASource: String);
- begin
- inherited Create(AFilename);
- InitFromString(ASource);
- end;
- { ---------------------------------------------------------------------
- TBaseFileResolver
- ---------------------------------------------------------------------}
- procedure TBaseFileResolver.SetBaseDirectory(AValue: string);
- begin
- if FBaseDirectory=AValue then Exit;
- FBaseDirectory:=AValue;
- end;
- procedure TBaseFileResolver.SetStrictFileCase(AValue: Boolean);
- begin
- if FStrictFileCase=AValue then Exit;
- FStrictFileCase:=AValue;
- end;
- constructor TBaseFileResolver.Create;
- begin
- inherited Create;
- FIncludePaths := TStringList.Create;
- end;
- destructor TBaseFileResolver.Destroy;
- begin
- FIncludePaths.Free;
- inherited Destroy;
- end;
- procedure TBaseFileResolver.AddIncludePath(const APath: string);
- Var
- FP : String;
- begin
- if (APath='') then
- FIncludePaths.Add('./')
- else
- begin
- {$IFDEF HASFS}
- FP:=IncludeTrailingPathDelimiter(ExpandFileName(APath));
- {$ELSE}
- FP:=APath;
- {$ENDIF}
- FIncludePaths.Add(FP);
- end;
- end;
- {$IFDEF HASFS}
- { ---------------------------------------------------------------------
- TFileResolver
- ---------------------------------------------------------------------}
- function TFileResolver.FindIncludeFileName(const AName: string): String;
- function SearchLowUpCase(FN: string): string;
- var
- Dir: String;
- begin
- If FileExists(FN) then
- Result:=FN
- else if StrictFileCase then
- Result:=''
- else
- begin
- Dir:=ExtractFilePath(FN);
- FN:=ExtractFileName(FN);
- Result:=Dir+LowerCase(FN);
- If FileExists(Result) then exit;
- Result:=Dir+uppercase(Fn);
- If FileExists(Result) then exit;
- Result:='';
- end;
- end;
- Function FindInPath(FN : String) : String;
- var
- I : integer;
- begin
- Result:='';
- I:=0;
- While (Result='') and (I<FIncludePaths.Count) do
- begin
- Result:=SearchLowUpCase(FIncludePaths[i]+FN);
- Inc(I);
- end;
- // search in BaseDirectory
- if (Result='') and (BaseDirectory<>'') then
- Result:=SearchLowUpCase(BaseDirectory+FN);
- end;
- var
- i: Integer;
- FN : string;
- begin
- Result := '';
- // convert pathdelims to system
- FN:=SetDirSeparators(AName);
- If FilenameIsAbsolute(FN) then
- begin
- Result := SearchLowUpCase(FN);
- if (Result='') and (ExtractFileExt(FN)='') then
- begin
- Result:=SearchLowUpCase(FN+'.inc');
- if Result='' then
- begin
- Result:=SearchLowUpCase(FN+'.pp');
- if Result='' then
- Result:=SearchLowUpCase(FN+'.pas');
- end;
- end;
- end
- else
- begin
- // file name is relative
- // search in include path
- Result:=FindInPath(FN);
- // No extension, try default extensions
- if (Result='') and (ExtractFileExt(FN)='') then
- begin
- Result:=FindInPath(FN+'.inc');
- if Result='' then
- begin
- Result:=FindInPath(FN+'.pp');
- if Result='' then
- Result:=FindInPath(FN+'.pas');
- end;
- end;
- end;
- end;
- function TFileResolver.CreateFileReader(const AFileName: String): TLineReader;
- begin
- {$ifdef HasStreams}
- If UseStreams then
- Result:=TFileStreamLineReader.Create(AFileName)
- else
- {$endif}
- Result:=TFileLineReader.Create(AFileName);
- end;
- function TFileResolver.FindSourceFile(const AName: string): TLineReader;
- begin
- Result := nil;
- if not FileExists(AName) then
- Raise EFileNotFoundError.create(AName)
- else
- try
- Result := CreateFileReader(AName)
- except
- Result := nil;
- end;
- end;
- function TFileResolver.FindIncludeFile(const AName: string): TLineReader;
- Var
- FN : String;
- begin
- Result:=Nil;
- FN:=FindIncludeFileName(AName);
- If (FN<>'') then
- try
- Result := TFileLineReader.Create(FN);
- except
- Result:=Nil;
- end;
- end;
- {$ENDIF}
- {$ifdef fpc}
- { TStreamResolver }
- procedure TStreamResolver.SetOwnsStreams(AValue: Boolean);
- begin
- if FOwnsStreams=AValue then Exit;
- FOwnsStreams:=AValue;
- end;
- function TStreamResolver.FindIncludeFileName(const aFilename: string): String;
- begin
- raise EFileNotFoundError.Create('TStreamResolver.FindIncludeFileName not supported '+aFilename);
- Result:='';
- end;
- constructor TStreamResolver.Create;
- begin
- Inherited;
- FStreams:=TStringList.Create;
- FStreams.Sorted:=True;
- FStreams.Duplicates:=dupError;
- end;
- destructor TStreamResolver.Destroy;
- begin
- Clear;
- FreeAndNil(FStreams);
- inherited Destroy;
- end;
- procedure TStreamResolver.Clear;
- Var
- I : integer;
- begin
- if OwnsStreams then
- begin
- For I:=0 to FStreams.Count-1 do
- Fstreams.Objects[i].Free;
- end;
- FStreams.Clear;
- end;
- procedure TStreamResolver.AddStream(const AName: String; AStream: TStream);
- begin
- FStreams.AddObject(AName,AStream);
- end;
- function TStreamResolver.FindStream(const AName: string; ScanIncludes : Boolean) : TStream;
- Var
- I,J : Integer;
- FN : String;
- begin
- Result:=Nil;
- I:=FStreams.IndexOf(AName);
- If (I=-1) and ScanIncludes then
- begin
- J:=0;
- While (I=-1) and (J<IncludePaths.Count-1) do
- begin
- FN:=IncludeTrailingPathDelimiter(IncludePaths[i])+AName;
- I:=FStreams.IndexOf(FN);
- Inc(J);
- end;
- end;
- If (I<>-1) then
- Result:=FStreams.Objects[i] as TStream;
- end;
- function TStreamResolver.FindStreamReader(const AName: string; ScanIncludes : Boolean) : TLineReader;
- Var
- S : TStream;
- SL : TStreamLineReader;
- begin
- Result:=Nil;
- S:=FindStream(AName,ScanIncludes);
- If (S<>Nil) then
- begin
- S.Position:=0;
- SL:=TStreamLineReader.Create(AName);
- try
- SL.InitFromStream(S);
- Result:=SL;
- except
- FreeAndNil(SL);
- Raise;
- end;
- end;
- end;
- function TStreamResolver.FindSourceFile(const AName: string): TLineReader;
- begin
- Result:=FindStreamReader(AName,False);
- end;
- function TStreamResolver.FindIncludeFile(const AName: string): TLineReader;
- begin
- Result:=FindStreamReader(AName,True);
- end;
- {$endif}
- { ---------------------------------------------------------------------
- TPascalScanner
- ---------------------------------------------------------------------}
- constructor TPascalScanner.Create(AFileResolver: TBaseFileResolver);
- Function CS : TStringList;
- begin
- Result:=TStringList.Create;
- Result.Sorted:=True;
- Result.Duplicates:=dupError;
- end;
- var
- vs: TValueSwitch;
- begin
- inherited Create;
- FFileResolver := AFileResolver;
- FFiles:=TStringList.Create;
- FIncludeStack := TFPList.Create;
- FDefines := CS;
- FMacros:=CS;
- FMaxIncludeStackDepth:=DefaultMaxIncludeStackDepth;
- FCurrentModeSwitches:=FPCModeSwitches;
- FAllowedModeSwitches:=msAllModeSwitches;
- FCurrentBoolSwitches:=bsFPCMode;
- FAllowedBoolSwitches:=bsAll;
- FAllowedValueSwitches:=vsAllValueSwitches;
- for vs in TValueSwitch do
- FCurrentValueSwitches[vs]:=DefaultValueSwitches[vs];
- FConditionEval:=TCondDirectiveEvaluator.Create;
- FConditionEval.OnLog:=@OnCondEvalLog;
- FConditionEval.OnEvalVariable:=@OnCondEvalVar;
- FConditionEval.OnEvalFunction:=@OnCondEvalFunction;
- end;
- destructor TPascalScanner.Destroy;
- begin
- FreeAndNil(FConditionEval);
- ClearMacros;
- FreeAndNil(FMacros);
- FreeAndNil(FDefines);
- ClearFiles;
- FreeAndNil(FFiles);
- FreeAndNil(FIncludeStack);
- inherited Destroy;
- end;
- procedure TPascalScanner.ClearFiles;
- begin
- // Dont' free the first element, because it is CurSourceFile
- while FIncludeStack.Count > 1 do
- begin
- TBaseFileResolver(FIncludeStack[1]).{$ifdef pas2js}Destroy{$else}Free{$endif};
- FIncludeStack.Delete(1);
- end;
- FIncludeStack.Clear;
- FreeAndNil(FCurSourceFile);
- FFiles.Clear;
- FModuleRow:=0;
- end;
- procedure TPascalScanner.ClearMacros;
- Var
- I : Integer;
- begin
- For I:=0 to FMacros.Count-1 do
- FMacros.Objects[i].{$ifdef pas2js}Destroy{$else}Free{$endif};
- FMacros.Clear;
- end;
- procedure TPascalScanner.SetCurToken(const AValue: TToken);
- begin
- FCurToken:=AValue;
- end;
- procedure TPascalScanner.SetCurTokenString(const AValue: string);
- begin
- FCurTokenString:=AValue;
- end;
- procedure TPascalScanner.OpenFile(AFilename: string);
- begin
- Clearfiles;
- FCurSourceFile := FileResolver.FindSourceFile(AFilename);
- FCurFilename := AFilename;
- AddFile(FCurFilename);
- {$IFDEF HASFS}
- FileResolver.BaseDirectory := IncludeTrailingPathDelimiter(ExtractFilePath(FCurFilename));
- {$ENDIF}
- if LogEvent(sleFile) then
- DoLog(mtInfo,nLogOpeningFile,SLogOpeningFile,[FormatPath(AFileName)],True);
- end;
- procedure TPascalScanner.FinishedModule;
- begin
- if (sleLineNumber in LogEvents)
- and (not CurSourceFile.IsEOF)
- and ((FCurRow Mod 100) > 0) then
- DoLog(mtInfo,nLogLineNumber,SLogLineNumber,[CurRow],True);
- end;
- function TPascalScanner.FormatPath(const aFilename: string): string;
- begin
- if Assigned(OnFormatPath) then
- Result:=OnFormatPath(aFilename)
- else
- Result:=aFilename;
- end;
- procedure TPascalScanner.SetNonToken(aToken: TToken);
- begin
- Include(FNonTokens,aToken);
- end;
- procedure TPascalScanner.UnsetNonToken(aToken: TToken);
- begin
- Exclude(FNonTokens,aToken);
- end;
- procedure TPascalScanner.SetTokenOption(aOption: TTokenoption);
- begin
- Include(FTokenOptions,aOption);
- end;
- procedure TPascalScanner.UnSetTokenOption(aOption: TTokenoption);
- begin
- Exclude(FTokenOptions,aOption);
- end;
- function TPascalScanner.CheckToken(aToken: TToken; const ATokenString: String): TToken;
- begin
- Result:=atoken;
- if (aToken=tkIdentifier) and (CompareText(aTokenString,'operator')=0) then
- if (toOperatorToken in TokenOptions) then
- Result:=tkoperator;
- end;
- function TPascalScanner.FetchToken: TToken;
- var
- IncludeStackItem: TIncludeStackItem;
- begin
- FPreviousToken:=FCurToken;
- while true do
- begin
- Result := DoFetchToken;
- Case FCurToken of
- tkEOF:
- begin
- if FIncludeStack.Count > 0 then
- begin
- IncludeStackItem :=
- TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
- FIncludeStack.Delete(FIncludeStack.Count - 1);
- CurSourceFile.{$ifdef pas2js}Destroy{$else}Free{$endif};
- FCurSourceFile := IncludeStackItem.SourceFile;
- FCurFilename := IncludeStackItem.Filename;
- FCurToken := IncludeStackItem.Token;
- FCurTokenString := IncludeStackItem.TokenString;
- FCurLine := IncludeStackItem.Line;
- FCurRow := IncludeStackItem.Row;
- FCurColumnOffset := IncludeStackItem.ColumnOffset;
- FTokenPos := IncludeStackItem.TokenPos;
- IncludeStackItem.Free;
- Result := FCurToken;
- end
- else
- break;
- end;
- tkWhiteSpace,
- tkLineEnding:
- if not (FSkipWhiteSpace or PPIsSkipping) then
- Break;
- tkComment:
- if not (FSkipComments or PPIsSkipping) then
- Break;
- tkSelf:
- begin
- if Not (po_selftoken in Options) then
- begin
- FCurToken:=tkIdentifier;
- Result:=FCurToken;
- end;
- if not (FSkipComments or PPIsSkipping) then
- Break;
- end;
- tkOperator:
- begin
- if Not (toOperatorToken in FTokenOptions) then
- begin
- FCurToken:=tkIdentifier;
- Result:=FCurToken;
- end;
- if not (FSkipComments or PPIsSkipping) then
- Break;
- end;
- else
- if not PPIsSkipping then
- break;
- end; // Case
- end;
- // Writeln(Result, '(',CurTokenString,')');
- end;
- function TPascalScanner.ReadNonPascalTillEndToken(StopAtLineEnd: boolean
- ): TToken;
- var
- StartPos: {$ifdef UsePChar}PChar{$else}integer{$endif};
- {$ifndef UsePChar}
- var
- s: string;
- l: integer;
- {$endif}
- Procedure Add;
- var
- AddLen: PtrInt;
- {$ifdef UsePChar}
- OldLen: Integer;
- {$endif}
- begin
- AddLen:=FTokenPos-StartPos;
- if AddLen=0 then
- FCurTokenString:=''
- else
- begin
- {$ifdef UsePChar}
- OldLen:=length(FCurTokenString);
- SetLength(FCurTokenString,OldLen+AddLen);
- Move(StartPos^,PChar(PChar(FCurTokenString)+OldLen)^,AddLen);
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,StartPos,AddLen);
- {$endif}
- StartPos:=FTokenPos;
- end;
- end;
- function DoEndOfLine: boolean;
- begin
- Add;
- if StopAtLineEnd then
- begin
- ReadNonPascalTillEndToken := tkLineEnding;
- FCurToken := tkLineEnding;
- FetchLine;
- exit(true);
- end;
- if not FetchLine then
- begin
- ReadNonPascalTillEndToken := tkEOF;
- FCurToken := tkEOF;
- exit(true);
- end;
- {$ifndef UsePChar}
- s:=FCurLine;
- l:=length(s);
- {$endif}
- StartPos:=FTokenPos;
- Result:=false;
- end;
- begin
- FCurTokenString := '';
- StartPos:=FTokenPos;
- {$ifndef UsePChar}
- s:=FCurLine;
- l:=length(s);
- {$endif}
- repeat
- {$ifndef UsePChar}
- if FTokenPos>l then
- if DoEndOfLine then exit;
- {$endif}
- case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
- {$ifdef UsePChar}
- #0: // end of line
- if DoEndOfLine then exit;
- {$endif}
- '''':
- begin
- // Notes:
- // 1. Eventually there should be a mechanism to override parsing non-pascal
- // 2. By default skip Pascal string literals, as this is more intuitive
- // in IDEs with Pascal highlighters
- inc(FTokenPos);
- repeat
- {$ifndef UsePChar}
- if FTokenPos>l then
- Error(nErrOpenString,SErrOpenString);
- {$endif}
- case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
- {$ifdef UsePChar}
- #0: Error(nErrOpenString,SErrOpenString);
- {$endif}
- '''':
- begin
- inc(FTokenPos);
- break;
- end;
- #10,#13:
- begin
- // string literal missing closing apostroph
- break;
- end
- else
- inc(FTokenPos);
- end;
- until false;
- end;
- '/':
- begin
- inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos^='/'{$else}(FTokenPos<=l) and (s[FTokenPos]='/'){$endif} then
- begin
- // skip Delphi comment //, see Note above
- repeat
- inc(FTokenPos);
- until {$ifdef UsePChar}FTokenPos^ in [#0,#10,#13]{$else}(FTokenPos>l) or (s[FTokenPos] in [#10,#13]){$endif};
- end;
- end;
- '0'..'9', 'A'..'Z', 'a'..'z','_':
- begin
- // number or identifier
- if {$ifdef UsePChar}
- (FTokenPos[0] in ['e','E'])
- and (FTokenPos[1] in ['n','N'])
- and (FTokenPos[2] in ['d','D'])
- and not (FTokenPos[3] in IdentChars)
- {$else}
- (TJSString(copy(s,FTokenPos,3)).toLowerCase='end')
- and ((FTokenPos+3>l) or not (s[FTokenPos+3] in IdentChars))
- {$endif}
- then
- begin
- // 'end' found
- Add;
- if FCurTokenString<>'' then
- begin
- // return characters in front of 'end'
- Result:=tkWhitespace;
- FCurToken:=Result;
- exit;
- end;
- // return 'end'
- Result := tkend;
- {$ifdef UsePChar}
- SetLength(FCurTokenString, 3);
- Move(FTokenPos^, FCurTokenString[1], 3);
- {$else}
- FCurTokenString:=copy(s,FTokenPos,3);
- {$endif}
- inc(FTokenPos,3);
- FCurToken := Result;
- exit;
- end
- else
- begin
- // skip identifier
- while {$ifdef UsePChar}FTokenPos[0] in IdentChars{$else}(FTokenPos<=l) and (s[FTokenPos] in IdentChars){$endif} do
- inc(FTokenPos);
- end;
- end;
- else
- inc(FTokenPos);
- end;
- until false;
- end;
- procedure TPascalScanner.Error(MsgNumber: integer; const Msg: string);
- begin
- SetCurMsg(mtError,MsgNumber,Msg,[]);
- raise EScannerError.CreateFmt('%s(%d,%d) Error: %s',
- [FormatPath(CurFilename),CurRow,CurColumn,FLastMsg]);
- end;
- procedure TPascalScanner.Error(MsgNumber: integer; const Fmt: string;
- Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- begin
- SetCurMsg(mtError,MsgNumber,Fmt,Args);
- raise EScannerError.CreateFmt('%s(%d,%d) Error: %s',
- [FormatPath(CurFilename),CurRow,CurColumn,FLastMsg]);
- end;
- function TPascalScanner.DoFetchTextToken:TToken;
- var
- OldLength : Integer;
- TokenStart : {$ifdef UsePChar}PChar{$else}integer{$endif};
- SectionLength : Integer;
- {$ifndef UsePChar}
- s: String;
- l: integer;
- {$endif}
- begin
- Result:=tkEOF;
- OldLength:=0;
- FCurTokenString := '';
- {$ifndef UsePChar}
- s:=FCurLine;
- l:=length(s);
- {$endif}
- repeat
- {$ifndef UsePChar}
- if FTokenPos>l then break;
- {$endif}
- case {$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif} of
- '^' :
- begin
- TokenStart := FTokenPos;
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0] in Letters{$else}(FTokenPos<l) and (s[FTokenPos] in Letters){$endif} then
- Inc(FTokenPos);
- if Result=tkEOF then Result := tkChar else Result:=tkString;
- end;
- '#':
- begin
- TokenStart := FTokenPos;
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0]='$'{$else}(FTokenPos<l) and (s[FTokenPos]='$'){$endif} then
- begin
- Inc(FTokenPos);
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in HexDigits){$else}(FTokenPos>l) or not (s[FTokenPos] in HexDigits){$endif};
- end else
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in Digits){$else}(FTokenPos>l) or not (s[FTokenPos] in Digits){$endif};
- if Result=tkEOF then Result := tkChar else Result:=tkString;
- end;
- '''':
- begin
- TokenStart := FTokenPos;
- Inc(FTokenPos);
- while true do
- begin
- if {$ifdef UsePChar}FTokenPos[0] = ''''{$else}(FTokenPos<=l) and (s[FTokenPos]=''''){$endif} then
- if {$ifdef UsePChar}FTokenPos[1] = ''''{$else}(FTokenPos<l) and (s[FTokenPos+1]=''''){$endif} then
- Inc(FTokenPos)
- else
- break;
- if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
- Error(nErrOpenString,SErrOpenString);
- Inc(FTokenPos);
- end;
- Inc(FTokenPos);
- if ((FTokenPos - TokenStart)=3) then // 'z'
- Result := tkChar
- else
- Result := tkString;
- end;
- else
- Break;
- end;
- SectionLength := FTokenPos - TokenStart;
- {$ifdef UsePChar}
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength);
- {$endif}
- Inc(OldLength, SectionLength);
- until false;
- end;
- procedure TPascalScanner.PushStackItem;
- Var
- SI: TIncludeStackItem;
- begin
- if FIncludeStack.Count>=MaxIncludeStackDepth then
- Error(nErrIncludeLimitReached,SErrIncludeLimitReached);
- SI := TIncludeStackItem.Create;
- SI.SourceFile := CurSourceFile;
- SI.Filename := CurFilename;
- SI.Token := CurToken;
- SI.TokenString := CurTokenString;
- SI.Line := CurLine;
- SI.Row := CurRow;
- SI.ColumnOffset := FCurColumnOffset;
- SI.TokenPos := FTokenPos;
- FIncludeStack.Add(SI);
- FTokenPos:={$ifdef UsePChar}Nil{$else}-1{$endif};
- FCurRow := 0;
- FCurColumnOffset := 1;
- end;
- procedure TPascalScanner.HandleIncludeFile(Param: String);
- var
- NewSourceFile: TLineReader;
- begin
- if Length(Param)>1 then
- begin
- if (Param[1]='''') then
- begin
- if Param[length(Param)]<>'''' then
- Error(nErrOpenString,SErrOpenString,[]);
- Param:=copy(Param,2,length(Param)-2);
- end;
- end;
- NewSourceFile := FileResolver.FindIncludeFile(Param);
- if not Assigned(NewSourceFile) then
- Error(nErrIncludeFileNotFound, SErrIncludeFileNotFound, [Param]);
- PushStackItem;
- FCurSourceFile:=NewSourceFile;
- FCurFilename := Param;
- if FCurSourceFile is TFileLineReader then
- FCurFilename := TFileLineReader(FCurSourceFile).Filename; // nicer error messages
- AddFile(FCurFilename);
- If LogEvent(sleFile) then
- DoLog(mtInfo,nLogOpeningFile,SLogOpeningFile,[FormatPath(FCurFileName)],True);
- end;
- function TPascalScanner.HandleMacro(AIndex : integer) : TToken;
- Var
- M : TMacroDef;
- ML : TMacroReader;
- OldRow, OldCol: Integer;
- begin
- OldRow:=CurRow;
- OldCol:=CurColumn;
- PushStackItem;
- M:=FMacros.Objects[AIndex] as TMacroDef;
- ML:=TMacroReader.Create(FCurFileName,M.Value);
- ML.CurRow:=OldRow;
- ML.CurCol:=OldCol-length(M.Name);
- FCurSourceFile:=ML;
- Result:=DoFetchToken;
- // Writeln(Result,Curtoken);
- end;
- procedure TPascalScanner.HandleInterfaces(const Param: String);
- var
- s, NewValue: String;
- p: SizeInt;
- begin
- if not (vsInterfaces in AllowedValueSwitches) then
- Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['interfaces']);
- s:=Uppercase(Param);
- p:=Pos(' ',s);
- if p>0 then
- s:=LeftStr(s,p-1);
- case s of
- 'COM','DEFAULT': NewValue:='COM';
- 'CORBA': NewValue:='CORBA';
- else
- Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['interfaces '+s]);
- exit;
- end;
- if SameText(NewValue,CurrentValueSwitch[vsInterfaces]) then exit;
- if vsInterfaces in ReadOnlyValueSwitches then
- begin
- Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['interfaces']);
- exit;
- end;
- CurrentValueSwitch[vsInterfaces]:=NewValue;
- end;
- procedure TPascalScanner.HandleWarn(Param: String);
- // $warn identifier on|off|default|error
- var
- p, StartPos: Integer;
- Identifier, Value: String;
- begin
- p:=1;
- while (p<=length(Param)) and (Param[p] in [' ',#9]) do inc(p);
- StartPos:=p;
- while (p<=length(Param)) and (Param[p] in ['a'..'z','A'..'Z','0'..'9','_']) do inc(p);
- Identifier:=copy(Param,StartPos,p-StartPos);
- while (p<=length(Param)) and (Param[p] in [' ',#9]) do inc(p);
- StartPos:=p;
- while (p<=length(Param)) and (Param[p] in ['a'..'z','A'..'Z','_']) do inc(p);
- Value:=copy(Param,StartPos,p-StartPos);
- HandleWarnIdentifier(Identifier,Value);
- end;
- procedure TPascalScanner.HandleWarnIdentifier(Identifier,
- Value: String);
- var
- Number: LongInt;
- State: TWarnMsgState;
- Handled: Boolean;
- begin
- if Identifier='' then
- Error(nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,['']);
- if Value='' then
- begin
- DoLog(mtWarning,nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,['']);
- exit;
- end;
- case lowercase(Value) of
- 'on': State:=wmsOn;
- 'off': State:=wmsOff;
- 'default': State:=wmsDefault;
- 'error': State:=wmsError;
- else
- DoLog(mtWarning,nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,[Value]);
- exit;
- end;
- if Assigned(OnWarnDirective) then
- begin
- Handled:=false;
- OnWarnDirective(Self,Identifier,State,Handled);
- if Handled then
- exit;
- end;
- if Identifier[1] in ['0'..'9'] then
- begin
- // fpc number
- Number:=StrToIntDef(Identifier,-1);
- if Number<0 then
- begin
- DoLog(mtWarning,nIllegalStateForWarnDirective,SIllegalStateForWarnDirective,[Identifier]);
- exit;
- end;
- SetWarnMsgState(Number,State);
- end;
- end;
- procedure TPascalScanner.HandleDefine(Param: String);
- Var
- Index : Integer;
- MName,MValue : String;
- begin
- Param := UpperCase(Param);
- Index:=Pos(':=',Param);
- If (Index=0) then
- AddDefine(GetMacroName(Param))
- else
- begin
- MValue:=Trim(Param);
- MName:=Trim(Copy(MValue,1,Index-1));
- Delete(MValue,1,Index+1);
- AddMacro(MName,MValue);
- end;
- end;
- procedure TPascalScanner.HandleDispatchField(Param: String; vs: TValueSwitch);
- var
- NewValue: String;
- begin
- if not (vs in AllowedValueSwitches) then
- Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,[ValueSwitchNames[vs]]);
- NewValue:=ReadIdentifier(Param);
- if NewValue='-' then
- NewValue:=''
- else if not IsValidIdent(NewValue,false) then
- DoLog(mtWarning,nInvalidDispatchFieldName,SInvalidDispatchFieldName,[]);
- if SameText(NewValue,CurrentValueSwitch[vs]) then exit;
- if vs in ReadOnlyValueSwitches then
- begin
- Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,[ValueSwitchNames[vs]]);
- exit;
- end;
- CurrentValueSwitch[vs]:=NewValue;
- end;
- procedure TPascalScanner.HandleError(Param: String);
- begin
- if po_StopOnErrorDirective in Options then
- Error(nUserDefined, SUserDefined,[Param])
- else
- DoLog(mtWarning,nUserDefined,SUserDefined+' error',[Param]);
- end;
- procedure TPascalScanner.HandleMessageDirective(Param: String);
- var
- p: Integer;
- Kind: String;
- MsgType: TMessageType;
- begin
- if Param='' then exit;
- p:=1;
- while (p<=length(Param)) and (Param[p] in ['a'..'z','A'..'Z']) do inc(p);
- Kind:=LeftStr(Param,p-1);
- MsgType:=mtHint;
- case UpperCase(Kind) of
- 'HINT': MsgType:=mtHint;
- 'NOTE': MsgType:=mtNote;
- 'WARN': MsgType:=mtWarning;
- 'ERROR': MsgType:=mtError;
- 'FATAL': MsgType:=mtFatal;
- else
- // $Message 'hint text'
- p:=1;
- end;
- while (p<=length(Param)) and (Param[p] in [' ',#9]) do inc(p);
- Delete(Param,1,p-1);
- if MsgType in [mtFatal,mtError] then
- HandleError(Param)
- else
- DoLog(MsgType,nUserDefined,SUserDefined,[Param]);
- end;
- procedure TPascalScanner.HandleUnDefine(Param: String);
- begin
- UnDefine(GetMacroName(Param));
- end;
- function TPascalScanner.HandleInclude(const Param: String): TToken;
- begin
- Result:=tkComment;
- if (Param<>'') and (Param[1]='%') then
- begin
- FCurTokenString:=''''+Param+'''';
- FCurToken:=tkString;
- Result:=FCurToken;
- end
- else
- HandleIncludeFile(Param);
- end;
- procedure TPascalScanner.HandleMode(const Param: String);
- procedure SetMode(const LangMode: TModeSwitch;
- const NewModeSwitches: TModeSwitches; IsDelphi: boolean;
- const AddBoolSwitches: TBoolSwitches = [];
- const RemoveBoolSwitches: TBoolSwitches = []
- );
- var
- Handled: Boolean;
- begin
- if not (LangMode in AllowedModeSwitches) then
- Error(nErrInvalidMode,SErrInvalidMode,[Param]);
- Handled:=false;
- if Assigned(OnModeChanged) then
- OnModeChanged(Self,LangMode,true,Handled);
- if not Handled then
- begin
- CurrentModeSwitches:=(NewModeSwitches+ReadOnlyModeSwitches)*AllowedModeSwitches;
- CurrentBoolSwitches:=CurrentBoolSwitches+(AddBoolSwitches*AllowedBoolSwitches)
- -(RemoveBoolSwitches*AllowedBoolSwitches);
- if IsDelphi then
- FOptions:=FOptions+[po_delphi]
- else
- FOptions:=FOptions-[po_delphi];
- end;
- Handled:=false;
- if Assigned(OnModeChanged) then
- OnModeChanged(Self,LangMode,false,Handled);
- end;
- Var
- P : String;
- begin
- if SkipGlobalSwitches then
- begin
- DoLog(mtWarning,nMisplacedGlobalCompilerSwitch,SMisplacedGlobalCompilerSwitch,[]);
- exit;
- end;
- P:=UpperCase(Param);
- Case P of
- 'FPC','DEFAULT':
- SetMode(msFpc,FPCModeSwitches,false,bsFPCMode);
- 'OBJFPC':
- begin
- SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
- UnsetNonToken(tkgeneric);
- UnsetNonToken(tkspecialize);
- end;
- 'DELPHI':
- begin
- SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
- SetNonToken(tkgeneric);
- SetNonToken(tkspecialize);
- end;
- 'DELPHIUNICODE':
- begin
- SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
- SetNonToken(tkgeneric);
- SetNonToken(tkspecialize);
- end;
- 'TP':
- SetMode(msTP7,TPModeSwitches,false);
- 'MACPAS':
- SetMode(msMac,MacModeSwitches,false,bsMacPasMode);
- 'ISO':
- SetMode(msIso,ISOModeSwitches,false);
- 'EXTENDED':
- SetMode(msExtpas,ExtPasModeSwitches,false);
- 'GPC':
- SetMode(msGPC,GPCModeSwitches,false);
- else
- Error(nErrInvalidMode,SErrInvalidMode,[Param])
- end;
- end;
- procedure TPascalScanner.HandleModeSwitch(const Param: String);
- Var
- MS : TModeSwitch;
- MSN,PM : String;
- P : Integer;
- begin
- MSN:=Uppercase(Param);
- P:=Pos(' ',MSN);
- if P<>0 then
- begin
- PM:=Trim(Copy(MSN,P+1,Length(MSN)-P));
- MSN:=Copy(MSN,1,P-1);
- end;
- MS:=StrToModeSwitch(MSN);
- if (MS=msNone) or not (MS in AllowedModeSwitches) then
- begin
- if po_CheckModeSwitches in Options then
- Error(nErrInvalidModeSwitch,SErrInvalidModeSwitch,[Param])
- else
- exit; // ignore
- end;
- if (PM='-') or (PM='OFF') then
- begin
- if MS in ReadOnlyModeSwitches then
- Error(nErrInvalidModeSwitch,SErrInvalidModeSwitch,[Param]);
- CurrentModeSwitches:=CurrentModeSwitches-[MS]
- end
- else
- CurrentModeSwitches:=CurrentModeSwitches+[MS];
- end;
- procedure TPascalScanner.PushSkipMode;
- begin
- if PPSkipStackIndex = High(PPSkipModeStack) then
- Error(nErrIfXXXNestingLimitReached,SErrIfXXXNestingLimitReached);
- PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
- PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
- Inc(PPSkipStackIndex);
- end;
- procedure TPascalScanner.HandleIFDEF(const AParam: String);
- var
- aName: String;
- begin
- PushSkipMode;
- if PPIsSkipping then
- PPSkipMode := ppSkipAll
- else
- begin
- aName:=ReadIdentifier(AParam);
- if IsDefined(aName) then
- PPSkipMode := ppSkipElseBranch
- else
- begin
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(mtInfo,nLogIFDefAccepted,sLogIFDefAccepted,[aName])
- else
- DoLog(mtInfo,nLogIFDefRejected,sLogIFDefRejected,[aName]);
- end;
- end;
- procedure TPascalScanner.HandleIFNDEF(const AParam: String);
- var
- aName: String;
- begin
- PushSkipMode;
- if PPIsSkipping then
- PPSkipMode := ppSkipAll
- else
- begin
- aName:=ReadIdentifier(AParam);
- if IsDefined(aName) then
- begin
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end
- else
- PPSkipMode := ppSkipElseBranch;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(mtInfo,nLogIFNDefAccepted,sLogIFNDefAccepted,[aName])
- else
- DoLog(mtInfo,nLogIFNDefRejected,sLogIFNDefRejected,[aName]);
- end;
- end;
- procedure TPascalScanner.HandleIFOPT(const AParam: String);
- begin
- PushSkipMode;
- if PPIsSkipping then
- PPSkipMode := ppSkipAll
- else
- begin
- if (length(AParam)<>2) or not (AParam[1] in ['a'..'z','A'..'Z'])
- or not (AParam[2] in ['+','-']) then
- Error(nErrXExpectedButYFound,sErrXExpectedButYFound,['letter[+|-]',AParam]);
- if IfOpt(AParam[1])=(AParam[2]='+') then
- PPSkipMode := ppSkipElseBranch
- else
- begin
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(mtInfo,nLogIFOptAccepted,sLogIFOptAccepted,[AParam])
- else
- DoLog(mtInfo,nLogIFOptRejected,sLogIFOptRejected,[AParam]);
- end;
- end;
- procedure TPascalScanner.HandleIF(const AParam: String);
- begin
- PushSkipMode;
- if PPIsSkipping then
- PPSkipMode := ppSkipAll
- else
- begin
- if ConditionEval.Eval(AParam) then
- PPSkipMode := ppSkipElseBranch
- else
- begin
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(mtInfo,nLogIFAccepted,sLogIFAccepted,[AParam])
- else
- DoLog(mtInfo,nLogIFRejected,sLogIFRejected,[AParam]);
- end;
- end;
- procedure TPascalScanner.HandleELSEIF(const AParam: String);
- begin
- if PPSkipStackIndex = 0 then
- Error(nErrInvalidPPElse,sErrInvalidPPElse);
- if PPSkipMode = ppSkipIfBranch then
- begin
- if ConditionEval.Eval(AParam) then
- begin
- PPSkipMode := ppSkipElseBranch;
- PPIsSkipping := false;
- end
- else
- PPIsSkipping := true;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(mtInfo,nLogELSEIFAccepted,sLogELSEIFAccepted,[AParam])
- else
- DoLog(mtInfo,nLogELSEIFRejected,sLogELSEIFRejected,[AParam]);
- end
- else if PPSkipMode=ppSkipElseBranch then
- begin
- PPIsSkipping := true;
- end;
- end;
- procedure TPascalScanner.HandleELSE(const AParam: String);
- begin
- if AParam='' then;
- if PPSkipStackIndex = 0 then
- Error(nErrInvalidPPElse,sErrInvalidPPElse);
- if PPSkipMode = ppSkipIfBranch then
- PPIsSkipping := false
- else if PPSkipMode = ppSkipElseBranch then
- PPIsSkipping := true;
- end;
- procedure TPascalScanner.HandleENDIF(const AParam: String);
- begin
- if AParam='' then;
- if PPSkipStackIndex = 0 then
- Error(nErrInvalidPPEndif,sErrInvalidPPEndif);
- Dec(PPSkipStackIndex);
- PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
- PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
- end;
- function TPascalScanner.HandleDirective(const ADirectiveText: String): TToken;
- Var
- Directive,Param : String;
- P : Integer;
- Handled: Boolean;
- procedure DoBoolDirective(bs: TBoolSwitch);
- begin
- if bs in AllowedBoolSwitches then
- begin
- Handled:=true;
- HandleBoolDirective(bs,Param);
- end
- else
- Handled:=false;
- end;
- begin
- Result:=tkComment;
- P:=Pos(' ',ADirectiveText);
- If P=0 then
- P:=Length(ADirectiveText)+1;
- Directive:=Copy(ADirectiveText,2,P-2); // 1 is $
- Param:=ADirectiveText;
- Delete(Param,1,P);
- {$IFDEF VerbosePasDirectiveEval}
- Writeln('TPascalScanner.HandleDirective.Directive: "',Directive,'", Param : "',Param,'"');
- {$ENDIF}
- Case UpperCase(Directive) of
- 'IFDEF':
- HandleIFDEF(Param);
- 'IFNDEF':
- HandleIFNDEF(Param);
- 'IFOPT':
- HandleIFOPT(Param);
- 'IF':
- HandleIF(Param);
- 'ELSEIF':
- HandleELSEIF(Param);
- 'ELSE':
- HandleELSE(Param);
- 'ENDIF':
- HandleENDIF(Param);
- 'IFEND':
- HandleENDIF(Param);
- else
- if PPIsSkipping then exit;
- Handled:=false;
- if (length(Directive)=2)
- and (Directive[1] in ['a'..'z','A'..'Z'])
- and (Directive[2] in ['-','+']) then
- begin
- Handled:=true;
- Result:=HandleLetterDirective(Directive[1],Directive[2]='+');
- end;
- if not Handled then
- begin
- Handled:=true;
- Case UpperCase(Directive) of
- 'ASSERTIONS':
- DoBoolDirective(bsAssertions);
- 'DEFINE':
- HandleDefine(Param);
- 'GOTO':
- DoBoolDirective(bsGoto);
- 'DIRECTIVEFIELD':
- HandleDispatchField(Param,vsDispatchField);
- 'DIRECTIVESTRFIELD':
- HandleDispatchField(Param,vsDispatchStrField);
- 'ERROR':
- HandleError(Param);
- 'HINT':
- DoLog(mtHint,nUserDefined,SUserDefined,[Param]);
- 'HINTS':
- DoBoolDirective(bsHints);
- 'I','INCLUDE':
- Result:=HandleInclude(Param);
- 'INTERFACES':
- HandleInterfaces(Param);
- 'LONGSTRINGS':
- DoBoolDirective(bsLongStrings);
- 'MACRO':
- DoBoolDirective(bsMacro);
- 'MESSAGE':
- HandleMessageDirective(Param);
- 'MODE':
- HandleMode(Param);
- 'MODESWITCH':
- HandleModeSwitch(Param);
- 'NOTE':
- DoLog(mtNote,nUserDefined,SUserDefined,[Param]);
- 'NOTES':
- DoBoolDirective(bsNotes);
- 'OBJECTCHECKS':
- DoBoolDirective(bsObjectChecks);
- 'OVERFLOWCHECKS','OV':
- DoBoolDirective(bsOverflowChecks);
- 'POINTERMATH':
- DoBoolDirective(bsPointerMath);
- 'RANGECHECKS':
- DoBoolDirective(bsRangeChecks);
- 'SCOPEDENUMS':
- DoBoolDirective(bsScopedEnums);
- 'TYPEDADDRESS':
- DoBoolDirective(bsTypedAddress);
- 'TYPEINFO':
- DoBoolDirective(bsTypeInfo);
- 'UNDEF':
- HandleUnDefine(Param);
- 'WARN':
- HandleWarn(Param);
- 'WARNING':
- DoLog(mtWarning,nUserDefined,SUserDefined,[Param]);
- 'WARNINGS':
- DoBoolDirective(bsWarnings);
- 'WRITEABLECONST':
- DoBoolDirective(bsWriteableConst);
- else
- Handled:=false;
- end;
- end;
- DoHandleDirective(Self,Directive,Param,Handled);
- if (not Handled) then
- if LogEvent(sleDirective) then
- DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
- [Directive]);
- end;
- end;
- function TPascalScanner.HandleLetterDirective(Letter: char; Enable: boolean): TToken;
- var
- bs: TBoolSwitch;
- begin
- Result:=tkComment;
- Letter:=upcase(Letter);
- bs:=LetterToBoolSwitch[Letter];
- if bs=bsNone then
- DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
- [Letter]);
- if not (bs in AllowedBoolSwitches) then
- begin
- DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
- [Letter]);
- end;
- if (bs in FCurrentBoolSwitches)<>Enable then
- begin
- if bs in FReadOnlyBoolSwitches then
- begin
- DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
- [Letter+BoolToStr(Enable,'+','-')]);
- exit;
- end;
- if Enable then
- begin
- AddDefine(LetterSwitchNames[Letter]);
- Include(FCurrentBoolSwitches,bs);
- end
- else
- begin
- UnDefine(LetterSwitchNames[Letter]);
- Exclude(FCurrentBoolSwitches,bs);
- end;
- end;
- end;
- procedure TPascalScanner.HandleBoolDirective(bs: TBoolSwitch;
- const Param: String);
- var
- NewValue: Boolean;
- begin
- if CompareText(Param,'on')=0 then
- NewValue:=true
- else if CompareText(Param,'off')=0 then
- NewValue:=false
- else
- Error(nErrXExpectedButYFound,SErrXExpectedButYFound,['on',Param]);
- if (bs in CurrentBoolSwitches)=NewValue then exit;
- if bs in ReadOnlyBoolSwitches then
- DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,
- [BoolSwitchNames[bs]])
- else if NewValue then
- CurrentBoolSwitches:=CurrentBoolSwitches+[bs]
- else
- CurrentBoolSwitches:=CurrentBoolSwitches-[bs];
- end;
- procedure TPascalScanner.DoHandleDirective(Sender: TObject; Directive,
- Param: String; var Handled: boolean);
- begin
- if Assigned(OnDirective) then
- OnDirective(Self,Directive,Param,Handled);
- end;
- function TPascalScanner.DoFetchToken: TToken;
- var
- TokenStart: {$ifdef UsePChar}PChar{$else}integer{$endif};
- i: TToken;
- SectionLength, NestingLevel, Index: Integer;
- {$ifdef UsePChar}
- OldLength: integer;
- {$else}
- s: string;
- l: integer;
- {$endif}
- procedure FetchCurTokenString; inline;
- begin
- {$ifdef UsePChar}
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- {$else}
- FCurTokenString:=copy(FCurLine,TokenStart,SectionLength);
- {$endif}
- end;
- function FetchLocalLine: boolean; inline;
- begin
- Result:=FetchLine;
- {$ifndef UsePChar}
- if not Result then exit;
- s:=FCurLine;
- l:=length(s);
- {$endif}
- end;
- begin
- Result:=tkLineEnding;
- if FTokenPos {$ifdef UsePChar}= nil{$else}<1{$endif} then
- if not FetchLine then
- begin
- Result := tkEOF;
- FCurToken := Result;
- exit;
- end;
- FCurTokenString := '';
- FCurTokenPos.FileName:=CurFilename;
- FCurTokenPos.Row:=CurRow;
- FCurTokenPos.Column:=CurColumn;
- {$ifndef UsePChar}
- s:=FCurLine;
- l:=length(s);
- if FTokenPos>l then
- begin
- FetchLine;
- Result := tkLineEnding;
- FCurToken := Result;
- exit;
- end;
- {$endif}
- case {$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif} of
- {$ifdef UsePChar}
- #0: // Empty line
- begin
- FetchLine;
- Result := tkLineEnding;
- end;
- {$endif}
- ' ':
- begin
- Result := tkWhitespace;
- repeat
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
- if not FetchLocalLine then
- begin
- FCurToken := Result;
- exit;
- end;
- until not ({$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}=' ');
- end;
- #9:
- begin
- Result := tkTab;
- repeat
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
- if not FetchLocalLine then
- begin
- FCurToken := Result;
- exit;
- end;
- until not ({$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}=#9);
- end;
- '#', '''':
- Result:=DoFetchTextToken;
- '&':
- begin
- TokenStart := FTokenPos;
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in ['0'..'7']){$else}(FTokenPos>l) or not (s[FTokenPos] in ['0'..'7']){$endif};
- SectionLength := FTokenPos - TokenStart;
- if (SectionLength=1)
- and ({$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} in IdentChars) then
- begin
- // &Keyword
- DoFetchToken();
- Result:=tkIdentifier;
- end
- else
- begin
- FetchCurTokenString;
- Result := tkNumber;
- end;
- end;
- '$':
- begin
- TokenStart := FTokenPos;
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in HexDigits){$else}(FTokenPos>l) or not (s[FTokenPos] in HexDigits){$endif};
- SectionLength := FTokenPos - TokenStart;
- FetchCurTokenString;
- Result := tkNumber;
- end;
- '%':
- begin
- TokenStart := FTokenPos;
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in ['0','1']){$else}(FTokenPos>l) or not (s[FTokenPos] in ['0','1']){$endif};
- SectionLength := FTokenPos - TokenStart;
- FetchCurTokenString;
- Result := tkNumber;
- end;
- '(':
- begin
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0] <> '*'{$else}(FTokenPos>l) or (s[FTokenPos]<>'*'){$endif} then
- Result := tkBraceOpen
- else
- begin
- // Old-style multi-line comment
- Inc(FTokenPos);
- TokenStart := FTokenPos;
- FCurTokenString := '';
- {$ifdef UsePChar}
- OldLength := 0;
- {$endif}
- NestingLevel:=0;
- repeat
- if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
- begin
- SectionLength:=FTokenPos - TokenStart;
- {$ifdef UsePChar}
- SetLength(FCurTokenString, OldLength + SectionLength+1); // +1 for #10
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- Inc(OldLength, SectionLength+1);
- FCurTokenString[OldLength] := #10;
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+#10;
- {$endif}
- if not FetchLocalLine then
- begin
- Result := tkEOF;
- FCurToken := Result;
- exit;
- end;
- TokenStart:=FTokenPos;
- end
- else if {$ifdef UsePChar}(FTokenPos[0] = '*') and (FTokenPos[1] = ')')
- {$else}(FTokenPos<l) and (s[FTokenPos]='*') and (s[FTokenPos+1]=')'){$endif}
- then begin
- dec(NestingLevel);
- if NestingLevel<0 then
- break;
- inc(FTokenPos,2);
- end
- else if (msNestedComment in CurrentModeSwitches)
- and {$ifdef UsePChar}(FTokenPos[0] = '(') and (FTokenPos[1] = '*')
- {$else}(FTokenPos<l) and (s[FTokenPos]='(') and (s[FTokenPos+1]='*'){$endif}
- then begin
- inc(FTokenPos,2);
- Inc(NestingLevel);
- end
- else
- Inc(FTokenPos);
- until false;
- SectionLength := FTokenPos - TokenStart;
- {$ifdef UsePChar}
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength);
- {$endif}
- Inc(FTokenPos, 2);
- Result := tkComment;
- if Copy(CurTokenString,1,1)='$' then
- Result := HandleDirective(CurTokenString);
- end;
- end;
- ')':
- begin
- Inc(FTokenPos);
- Result := tkBraceClose;
- end;
- '*':
- begin
- Result:=tkMul;
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0]='*'{$else}(FTokenPos<=l) and (s[FTokenPos]='*'){$endif} then
- begin
- Inc(FTokenPos);
- Result := tkPower;
- end
- else if (po_CAssignments in options) then
- begin
- if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
- begin
- Inc(FTokenPos);
- Result:=tkAssignMul;
- end;
- end;
- end;
- '+':
- begin
- Result:=tkPlus;
- Inc(FTokenPos);
- if (po_CAssignments in options) then
- begin
- if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
- begin
- Inc(FTokenPos);
- Result:=tkAssignPlus;
- end;
- end
- end;
- ',':
- begin
- Inc(FTokenPos);
- Result := tkComma;
- end;
- '-':
- begin
- Result := tkMinus;
- Inc(FTokenPos);
- if (po_CAssignments in options) then
- begin
- if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
- begin
- Inc(FTokenPos);
- Result:=tkAssignMinus;
- end;
- end
- end;
- '.':
- begin
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0]='.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then
- begin
- Inc(FTokenPos);
- Result := tkDotDot;
- end
- else
- Result := tkDot;
- end;
- '/':
- begin
- Result := tkDivision;
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0]='/'{$else}(FTokenPos<=l) and (s[FTokenPos]='/'){$endif} then
- begin
- // Single-line comment
- Inc(FTokenPos);
- TokenStart := FTokenPos;
- FCurTokenString := '';
- while {$ifdef UsePChar}FTokenPos[0] <> #0{$else}(FTokenPos<=l) and (s[FTokenPos]<>#0){$endif} do
- Inc(FTokenPos);
- SectionLength := FTokenPos - TokenStart;
- FetchCurTokenString;
- // Handle macro which is //
- if FCurSourceFile is TMacroReader then
- begin
- // exhaust till eof of macro stream
- Repeat
- I:=Fetchtoken;
- until (i<>tkLineEnding);
- FetchLocalLine;
- end;
- Result := tkComment;
- end
- else if (po_CAssignments in options) then
- begin
- if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
- begin
- Inc(FTokenPos);
- Result:=tkAssignDivision;
- end;
- end
- end;
- '0'..'9':
- begin
- // 1, 12, 1.2, 1.2E3, 1.E2, 1E2, 1.2E-3, 1E+2
- // beware of 1..2
- TokenStart := FTokenPos;
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in Digits){$else}(FTokenPos>l) or not (s[FTokenPos] in Digits){$endif};
- if {$ifdef UsePChar}(FTokenPos[0]='.') and (FTokenPos[1]<>'.'){$else}
- (FTokenPos<=l) and (s[FTokenPos]='.') and ((FTokenPos=l) or (s[FTokenPos+1]<>'.')){$endif}then
- begin
- inc(FTokenPos);
- while {$ifdef UsePChar}FTokenPos[0] in Digits{$else}(FTokenPos<=l) and (s[FTokenPos] in Digits){$endif} do
- Inc(FTokenPos);
- end;
- if {$ifdef UsePChar}FTokenPos[0] in ['e', 'E']{$else}(FTokenPos<=l) and (s[FTokenPos] in ['e', 'E']){$endif} then
- begin
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0] in ['-','+']{$else}(FTokenPos<=l) and (s[FTokenPos] in ['-','+']){$endif} then
- inc(FTokenPos);
- while {$ifdef UsePChar}FTokenPos[0] in Digits{$else}(FTokenPos<=l) and (s[FTokenPos] in Digits){$endif} do
- Inc(FTokenPos);
- end;
- SectionLength := FTokenPos - TokenStart;
- FetchCurTokenString;
- Result := tkNumber;
- end;
- ':':
- begin
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0]='='{$else}(FTokenPos<=l) and (s[FTokenPos]='='){$endif} then
- begin
- Inc(FTokenPos);
- Result := tkAssign;
- end
- else
- Result := tkColon;
- end;
- ';':
- begin
- Inc(FTokenPos);
- Result := tkSemicolon;
- end;
- '<':
- begin
- Inc(FTokenPos);
- {$ifndef UsePChar}
- if FTokenPos>l then
- Result := tkLessThan
- else
- {$endif}
- case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
- '>':
- begin
- Inc(FTokenPos);
- Result := tkNotEqual;
- end;
- '=':
- begin
- Inc(FTokenPos);
- Result := tkLessEqualThan;
- end;
- '<':
- begin
- Inc(FTokenPos);
- Result := tkshl;
- end;
- else
- Result := tkLessThan;
- end;
- end;
- '=':
- begin
- Inc(FTokenPos);
- Result := tkEqual;
- end;
- '>':
- begin
- Inc(FTokenPos);
- {$ifndef UsePChar}
- if FTokenPos>l then
- Result := tkGreaterThan
- else
- {$endif}
- case {$ifdef UsePChar}FTokenPos^{$else}s[FTokenPos]{$endif} of
- '=':
- begin
- Inc(FTokenPos);
- Result := tkGreaterEqualThan;
- end;
- '<':
- begin
- Inc(FTokenPos);
- Result := tkSymmetricalDifference;
- end;
- '>':
- begin
- Inc(FTokenPos);
- Result := tkshr;
- end;
- else
- Result := tkGreaterThan;
- end;
- end;
- '@':
- begin
- Inc(FTokenPos);
- Result := tkAt;
- if {$ifdef UsePChar}FTokenPos^='@'{$else}(FTokenPos<=l) and (s[FTokenPos]='@'){$endif} then
- begin
- Inc(FTokenPos);
- Result:=tkAtAt;
- end;
- end;
- '[':
- begin
- Inc(FTokenPos);
- Result := tkSquaredBraceOpen;
- end;
- ']':
- begin
- Inc(FTokenPos);
- Result := tkSquaredBraceClose;
- end;
- '^':
- begin
- if ForceCaret or PPisSkipping or
- (PreviousToken in [tkeof,tkTab,tkLineEnding,tkComment,tkIdentifier,
- tkNil,tkOperator,tkBraceClose,tkSquaredBraceClose,tkCaret,
- tkWhitespace]) then
- begin
- Inc(FTokenPos);
- Result := tkCaret;
- end
- else
- Result:=DoFetchTextToken;
- end;
- '\':
- begin
- Inc(FTokenPos);
- Result := tkBackslash;
- end;
- '{': // Multi-line comment
- begin
- Inc(FTokenPos);
- TokenStart := FTokenPos;
- FCurTokenString := '';
- {$ifdef UsePChar}
- OldLength := 0;
- {$endif}
- NestingLevel := 0;
- repeat
- if {$ifdef UsePChar}FTokenPos[0] = #0{$else}FTokenPos>l{$endif} then
- begin
- SectionLength := FTokenPos - TokenStart;
- {$ifdef UsePChar}
- SetLength(FCurTokenString, OldLength + SectionLength+1); // +1 for the #10
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1],SectionLength);
- Inc(OldLength, SectionLength+1);
- FCurTokenString[OldLength] := #10;
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+#10;
- {$endif}
- if not FetchLocalLine then
- begin
- Result := tkEOF;
- FCurToken := Result;
- exit;
- end;
- TokenStart := FTokenPos;
- end
- else if {$ifdef UsePChar}(FTokenPos[0] = '}'){$else}(s[FTokenPos]='}'){$endif} then
- begin
- Dec(NestingLevel);
- if NestingLevel<0 then
- break;
- Inc(FTokenPos);
- end
- else if {$ifdef UsePChar}(FTokenPos[0] = '{'){$else}(s[FTokenPos]='{'){$endif}
- and (msNestedComment in CurrentModeSwitches) then
- begin
- inc(FTokenPos);
- Inc(NestingLevel);
- end
- else
- Inc(FTokenPos);
- until false;
- SectionLength := FTokenPos - TokenStart;
- {$ifdef UsePChar}
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- {$else}
- FCurTokenString:=FCurTokenString+copy(s,TokenStart,SectionLength);
- {$endif}
- Inc(FTokenPos);
- Result := tkComment;
- if (Copy(CurTokenString,1,1)='$') then
- Result:=HandleDirective(CurTokenString);
- end;
- 'A'..'Z', 'a'..'z', '_':
- begin
- TokenStart := FTokenPos;
- repeat
- Inc(FTokenPos);
- until {$ifdef UsePChar}not (FTokenPos[0] in IdentChars){$else}(FTokenPos>l) or not (s[FTokenPos] in IdentChars){$endif};
- SectionLength := FTokenPos - TokenStart;
- FetchCurTokenString;
- Result:=tkIdentifier;
- for i:=tkAbsolute to tkXor do
- begin
- if (CompareText(CurTokenString, TokenInfos[i])=0) then
- begin
- Result:=I;
- break;
- end;
- end;
- if (Result<>tkIdentifier) and (Result in FNonTokens) then
- Result:=tkIdentifier;
- FCurToken := Result;
- if MacrosOn then
- begin
- Index:=FMacros.IndexOf(CurTokenString);
- if Index>=0 then
- Result:=HandleMacro(Index);
- end;
- end;
- else
- if PPIsSkipping then
- Inc(FTokenPos)
- else
- Error(nErrInvalidCharacter, SErrInvalidCharacter,
- [{$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}]);
- end;
- FCurToken := Result;
- end;
- function TPascalScanner.LogEvent(E: TPScannerLogEvent): Boolean;
- begin
- Result:=E in FLogEvents;
- end;
- function TPascalScanner.GetCurColumn: Integer;
- begin
- If {$ifdef UsePChar}(FTokenPos<>Nil){$else}FTokenPos>0{$endif} then
- Result := FTokenPos {$ifdef UsePChar}- PChar(CurLine){$else}-1{$endif} + FCurColumnOffset
- else
- Result := FCurColumnOffset;
- end;
- function TPascalScanner.GetCurrentValueSwitch(V: TValueSwitch): string;
- begin
- Result:=FCurrentValueSwitches[V];
- end;
- function TPascalScanner.GetForceCaret: Boolean;
- begin
- Result:=toForceCaret in FTokenOptions;
- end;
- function TPascalScanner.GetMacrosOn: boolean;
- begin
- Result:=bsMacro in FCurrentBoolSwitches;
- end;
- function TPascalScanner.IndexOfWarnMsgState(Number: integer; InsertPos: boolean
- ): integer;
- var
- l, r, m, CurNumber: Integer;
- begin
- l:=0;
- r:=length(FWarnMsgStates)-1;
- m:=0;
- while l<=r do
- begin
- m:=(l+r) div 2;
- CurNumber:=FWarnMsgStates[m].Number;
- if Number>CurNumber then
- l:=m+1
- else if Number<CurNumber then
- r:=m-1
- else
- exit(m);
- end;
- if not InsertPos then
- exit(-1);
- if length(FWarnMsgStates)=0 then
- exit(0);
- if (m<length(FWarnMsgStates)) and (FWarnMsgStates[m].Number<=Number) then
- inc(m);
- Result:=m;
- end;
- function TPascalScanner.OnCondEvalFunction(Sender: TCondDirectiveEvaluator;
- Name, Param: String; out Value: string): boolean;
- begin
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TPascalScanner.OnCondEvalFunction Func="',Name,'" Param="',Param,'"');
- {$ENDIF}
- if CompareText(Name,'defined')=0 then
- begin
- if not IsValidIdent(Param) then
- Sender.Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
- ['identifier',Param]);
- Value:=CondDirectiveBool[IsDefined(Param)];
- exit(true);
- end
- else if CompareText(Name,'undefined')=0 then
- begin
- if not IsValidIdent(Param) then
- Sender.Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
- ['identifier',Param]);
- Value:=CondDirectiveBool[not IsDefined(Param)];
- exit(true);
- end
- else if CompareText(Name,'option')=0 then
- begin
- if (length(Param)<>1) or not (Param[1] in ['a'..'z','A'..'Z']) then
- Sender.Log(mtError,nErrXExpectedButYFound,SErrXExpectedButYFound,
- ['letter',Param]);
- Value:=CondDirectiveBool[IfOpt(Param[1])];
- exit(true);
- end;
- // last check user hook
- if Assigned(OnEvalFunction) then
- begin
- Result:=OnEvalFunction(Sender,Name,Param,Value);
- if not (po_CheckCondFunction in Options) then
- begin
- Value:='0';
- Result:=true;
- end;
- exit;
- end;
- if (po_CheckCondFunction in Options) then
- begin
- Value:='';
- Result:=false;
- end
- else
- begin
- Value:='0';
- Result:=true;
- end;
- end;
- procedure TPascalScanner.OnCondEvalLog(Sender: TCondDirectiveEvaluator;
- Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- begin
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TPascalScanner.OnCondEvalLog "',Sender.MsgPattern,'"');
- {$ENDIF}
- // ToDo: move CurLine/CurRow to Sender.MsgPos
- if Sender.MsgType<=mtError then
- begin
- SetCurMsg(Sender.MsgType,Sender.MsgNumber,Sender.MsgPattern,Args);
- raise EScannerError.Create(FLastMsg);
- end
- else
- DoLog(Sender.MsgType,Sender.MsgNumber,Sender.MsgPattern,Args,true);
- end;
- function TPascalScanner.OnCondEvalVar(Sender: TCondDirectiveEvaluator;
- Name: String; out Value: string): boolean;
- var
- i: Integer;
- M: TMacroDef;
- begin
- {$IFDEF VerbosePasDirectiveEval}
- writeln('TPascalScanner.OnCondEvalVar "',Name,'"');
- {$ENDIF}
- // first check defines
- if FDefines.IndexOf(Name)>=0 then
- begin
- Value:='1';
- exit(true);
- end;
- // then check macros
- i:=FMacros.IndexOf(Name);
- if i>=0 then
- begin
- M:=FMacros.Objects[i] as TMacroDef;
- Value:=M.Value;
- exit(true);
- end;
- // last check user hook
- if Assigned(OnEvalVariable) then
- begin
- Result:=OnEvalVariable(Sender,Name,Value);
- exit;
- end;
- Value:='';
- Result:=false;
- end;
- procedure TPascalScanner.SetAllowedBoolSwitches(const AValue: TBoolSwitches);
- begin
- if FAllowedBoolSwitches=AValue then Exit;
- FAllowedBoolSwitches:=AValue;
- end;
- procedure TPascalScanner.SetAllowedModeSwitches(const AValue: TModeSwitches);
- begin
- if FAllowedModeSwitches=AValue then Exit;
- FAllowedModeSwitches:=AValue;
- CurrentModeSwitches:=FCurrentModeSwitches*AllowedModeSwitches;
- end;
- procedure TPascalScanner.SetAllowedValueSwitches(const AValue: TValueSwitches);
- begin
- if FAllowedValueSwitches=AValue then Exit;
- FAllowedValueSwitches:=AValue;
- end;
- procedure TPascalScanner.SetCurrentBoolSwitches(const AValue: TBoolSwitches);
- var
- OldBS, Removed, Added: TBoolSwitches;
- begin
- if FCurrentBoolSwitches=AValue then Exit;
- OldBS:=FCurrentBoolSwitches;
- FCurrentBoolSwitches:=AValue;
- Removed:=OldBS-FCurrentBoolSwitches;
- Added:=FCurrentBoolSwitches-OldBS;
- if bsGoto in Added then
- begin
- UnsetNonToken(tklabel);
- UnsetNonToken(tkgoto);
- end;
- if bsGoto in Removed then
- begin
- SetNonToken(tklabel);
- SetNonToken(tkgoto);
- end;
- end;
- procedure TPascalScanner.SetCurrentModeSwitches(AValue: TModeSwitches);
- var
- Old, AddedMS, RemovedMS: TModeSwitches;
- begin
- AValue:=AValue*AllowedModeSwitches;
- if FCurrentModeSwitches=AValue then Exit;
- Old:=FCurrentModeSwitches;
- FCurrentModeSwitches:=AValue;
- AddedMS:=FCurrentModeSwitches-Old;
- RemovedMS:=Old-FCurrentModeSwitches;
- if msDefaultUnicodestring in AddedMS then
- begin
- AddDefine('UNICODE');
- AddDefine('FPC_UNICODESTRINGS');
- end
- else if msDefaultUnicodestring in RemovedMS then
- begin
- UnDefine('UNICODE');
- UnDefine('FPC_UNICODESTRINGS');
- end;
- if msDefaultAnsistring in AddedMS then
- begin
- AddDefine(LetterSwitchNames['H'],true);
- Include(FCurrentBoolSwitches,bsLongStrings);
- end
- else if msDefaultAnsistring in RemovedMS then
- begin
- UnDefine(LetterSwitchNames['H'],true);
- Exclude(FCurrentBoolSwitches,bsLongStrings);
- end;
- end;
- procedure TPascalScanner.SetCurrentValueSwitch(V: TValueSwitch;
- const AValue: string);
- begin
- if not (V in AllowedValueSwitches) then exit;
- if FCurrentValueSwitches[V]=AValue then exit;
- FCurrentValueSwitches[V]:=AValue;
- end;
- procedure TPascalScanner.SetWarnMsgState(Number: integer; State: TWarnMsgState);
- {$IFDEF EmulateArrayInsert}
- procedure Delete(var A: TWarnMsgNumberStateArr; Index, Count: integer); overload;
- var
- i: Integer;
- begin
- if Index<0 then
- Error(nErrDivByZero,'[20180627142123]');
- if Index+Count>length(A) then
- Error(nErrDivByZero,'[20180627142127]');
- for i:=Index+Count to length(A)-1 do
- A[i-Count]:=A[i];
- SetLength(A,length(A)-Count);
- end;
- procedure Insert(Item: TWarnMsgNumberState; var A: TWarnMsgNumberStateArr; Index: integer); overload;
- var
- i: Integer;
- begin
- if Index<0 then
- Error(nErrDivByZero,'[20180627142133]');
- if Index>length(A) then
- Error(nErrDivByZero,'[20180627142137]');
- SetLength(A,length(A)+1);
- for i:=length(A)-1 downto Index+1 do
- A[i]:=A[i-1];
- A[Index]:=Item;
- end;
- {$ENDIF}
- var
- i: Integer;
- Item: TWarnMsgNumberState;
- begin
- i:=IndexOfWarnMsgState(Number,true);
- if (i<length(FWarnMsgStates)) and (FWarnMsgStates[i].Number=Number) then
- begin
- // already exists
- if State=wmsDefault then
- Delete(FWarnMsgStates,i,1)
- else
- FWarnMsgStates[i].State:=State;
- end
- else if State<>wmsDefault then
- begin
- // new state
- Item.Number:=Number;
- Item.State:=State;
- Insert(Item,FWarnMsgStates,i);
- end;
- end;
- function TPascalScanner.GetWarnMsgState(Number: integer): TWarnMsgState;
- var
- i: Integer;
- begin
- i:=IndexOfWarnMsgState(Number,false);
- if i<0 then
- Result:=wmsDefault
- else
- Result:=FWarnMsgStates[i].State;
- end;
- procedure TPascalScanner.SetMacrosOn(const AValue: boolean);
- begin
- if AValue then
- Include(FCurrentBoolSwitches,bsMacro)
- else
- Exclude(FCurrentBoolSwitches,bsMacro);
- end;
- procedure TPascalScanner.DoLog(MsgType: TMessageType; MsgNumber: integer;
- const Msg: String; SkipSourceInfo: Boolean);
- begin
- DoLog(MsgType,MsgNumber,Msg,[],SkipSourceInfo);
- end;
- procedure TPascalScanner.DoLog(MsgType: TMessageType; MsgNumber: integer;
- const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
- SkipSourceInfo: Boolean);
- Var
- Msg : String;
- begin
- if IgnoreMsgType(MsgType) then exit;
- SetCurMsg(MsgType,MsgNumber,Fmt,Args);
- If Assigned(FOnLog) then
- begin
- Msg:=MessageTypeNames[MsgType]+': ';
- if SkipSourceInfo then
- Msg:=Msg+FLastMsg
- else
- Msg:=Msg+Format('%s(%d,%d) : %s',[FormatPath(FCurFileName),CurRow,CurColumn,FLastMsg]);
- FOnLog(Self,Msg);
- end;
- end;
- procedure TPascalScanner.SetOptions(AValue: TPOptions);
- Var
- isModeSwitch : Boolean;
- begin
- if FOptions=AValue then Exit;
- // Change of mode ?
- IsModeSwitch:=(po_delphi in Avalue) <> (po_delphi in FOptions);
- FOptions:=AValue;
- if isModeSwitch then
- if (po_delphi in FOptions) then
- CurrentModeSwitches:=DelphiModeSwitches
- else
- CurrentModeSwitches:=FPCModeSwitches
- end;
- procedure TPascalScanner.SetReadOnlyBoolSwitches(const AValue: TBoolSwitches);
- begin
- if FReadOnlyBoolSwitches=AValue then Exit;
- FReadOnlyBoolSwitches:=AValue;
- end;
- procedure TPascalScanner.SetReadOnlyModeSwitches(const AValue: TModeSwitches);
- begin
- if FReadOnlyModeSwitches=AValue then Exit;
- FReadOnlyModeSwitches:=AValue;
- FAllowedModeSwitches:=FAllowedModeSwitches+FReadOnlyModeSwitches;
- FCurrentModeSwitches:=FCurrentModeSwitches+FReadOnlyModeSwitches;
- end;
- procedure TPascalScanner.SetReadOnlyValueSwitches(const AValue: TValueSwitches);
- begin
- if FReadOnlyValueSwitches=AValue then Exit;
- FReadOnlyValueSwitches:=AValue;
- end;
- function TPascalScanner.ReadIdentifier(const AParam: string): string;
- var
- p, l: Integer;
- begin
- p:=1;
- l:=length(AParam);
- while (p<=l) and (AParam[p] in IdentChars) do inc(p);
- Result:=LeftStr(AParam,p-1);
- end;
- function TPascalScanner.FetchLine: boolean;
- begin
- if CurSourceFile.IsEOF then
- begin
- if {$ifdef UsePChar}FTokenPos<>nil{$else}FTokenPos>0{$endif} then
- begin
- FCurLine := '';
- FTokenPos := {$ifdef UsePChar}nil{$else}-1{$endif};
- inc(FCurRow); // set CurRow to last line+1
- inc(FModuleRow);
- FCurColumnOffset:=1;
- end;
- Result := false;
- end else
- begin
- FCurLine := CurSourceFile.ReadLine;
- FTokenPos := {$ifdef UsePChar}PChar(CurLine){$else}1{$endif};
- Result := true;
- {$ifdef UseAnsiStrings}
- if (FCurRow = 0)
- and (Length(CurLine) >= 3)
- and (FTokenPos[0] = #$EF)
- and (FTokenPos[1] = #$BB)
- and (FTokenPos[2] = #$BF) then
- // ignore UTF-8 Byte Order Mark
- inc(FTokenPos, 3);
- {$endif}
- Inc(FCurRow);
- inc(FModuleRow);
- FCurColumnOffset:=1;
- if (FCurSourceFile is TMacroReader) and (FCurRow=1) then
- begin
- FCurRow:=TMacroReader(FCurSourceFile).CurRow;
- FCurColumnOffset:=TMacroReader(FCurSourceFile).CurCol;
- end;
- if LogEvent(sleLineNumber)
- and (((FCurRow Mod 100) = 0)
- or CurSourceFile.IsEOF) then
- DoLog(mtInfo,nLogLineNumber,SLogLineNumber,[FCurRow],True); // log last line
- end;
- end;
- procedure TPascalScanner.AddFile(aFilename: string);
- var
- i: Integer;
- begin
- for i:=0 to FFiles.Count-1 do
- if FFiles[i]=aFilename then exit;
- FFiles.Add(aFilename);
- end;
- function TPascalScanner.GetMacroName(const Param: String): String;
- var
- p: Integer;
- begin
- Result:=Trim(Param);
- p:=1;
- while (p<=length(Result)) and (Result[p] in ['a'..'z','A'..'Z','0'..'9','_']) do
- inc(p);
- SetLength(Result,p-1);
- end;
- procedure TPascalScanner.SetCurMsg(MsgType: TMessageType; MsgNumber: integer;
- const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
- begin
- FLastMsgType := MsgType;
- FLastMsgNumber := MsgNumber;
- FLastMsgPattern := Fmt;
- FLastMsg := SafeFormat(Fmt,Args);
- CreateMsgArgs(FLastMsgArgs,Args);
- end;
- function TPascalScanner.AddDefine(const aName: String; Quiet: boolean): boolean;
- begin
- If FDefines.IndexOf(aName)>=0 then exit(false);
- Result:=true;
- FDefines.Add(aName);
- if (not Quiet) and LogEvent(sleConditionals) then
- DoLog(mtInfo,nLogMacroDefined,sLogMacroDefined,[aName])
- end;
- function TPascalScanner.RemoveDefine(const aName: String; Quiet: boolean
- ): boolean;
- Var
- I : Integer;
- begin
- I:=FDefines.IndexOf(aName);
- if (I<0) then exit(false);
- Result:=true;
- FDefines.Delete(I);
- if (not Quiet) and LogEvent(sleConditionals) then
- DoLog(mtInfo,nLogMacroUnDefined,sLogMacroUnDefined,[aName])
- end;
- function TPascalScanner.UnDefine(const aName: String; Quiet: boolean): boolean;
- begin
- // Important: always call both, do not use OR
- Result:=RemoveDefine(aName,Quiet);
- if RemoveMacro(aName,Quiet) then Result:=true;
- end;
- function TPascalScanner.IsDefined(const aName: String): boolean;
- begin
- Result:=(FDefines.IndexOf(aName)>=0) or (FMacros.IndexOf(aName)>=0);
- end;
- function TPascalScanner.IfOpt(Letter: Char): boolean;
- begin
- Letter:=upcase(Letter);
- Result:=(Letter in ['A'..'Z']) and (LetterSwitchNames[Letter]<>'')
- and IsDefined(LetterSwitchNames[Letter]);
- end;
- function TPascalScanner.AddMacro(const aName, aValue: String; Quiet: boolean
- ): boolean;
- var
- Index: Integer;
- begin
- Index:=FMacros.IndexOf(aName);
- If (Index=-1) then
- FMacros.AddObject(aName,TMacroDef.Create(aName,aValue))
- else
- begin
- if TMacroDef(FMacros.Objects[Index]).Value=aValue then exit(false);
- TMacroDef(FMacros.Objects[Index]).Value:=aValue;
- end;
- Result:=true;
- if (not Quiet) and LogEvent(sleConditionals) then
- DoLog(mtInfo,nLogMacroXSetToY,SLogMacroXSetToY,[aName,aValue])
- end;
- function TPascalScanner.RemoveMacro(const aName: String; Quiet: boolean
- ): boolean;
- var
- Index: Integer;
- begin
- Index:=FMacros.IndexOf(aName);
- if Index<0 then exit(false);
- Result:=true;
- TMacroDef(FMacros.Objects[Index]).{$ifdef pas2js}Destroy{$else}Free{$endif};
- FMacros.Delete(Index);
- if (not Quiet) and LogEvent(sleConditionals) then
- DoLog(mtInfo,nLogMacroUnDefined,sLogMacroUnDefined,[aName])
- end;
- procedure TPascalScanner.SetCompilerMode(S: String);
- begin
- HandleMode(S);
- end;
- function TPascalScanner.CurSourcePos: TPasSourcePos;
- begin
- Result.FileName:=CurFilename;
- Result.Row:=CurRow;
- Result.Column:=CurColumn;
- end;
- function TPascalScanner.SetForceCaret(AValue: Boolean): Boolean;
- begin
- Result:=toForceCaret in FTokenOptions;
- if aValue then
- Include(FTokenOptions,toForceCaret)
- else
- Exclude(FTokenOptions,toForceCaret)
- end;
- function TPascalScanner.IgnoreMsgType(MsgType: TMessageType): boolean;
- begin
- case MsgType of
- mtWarning: if not (bsWarnings in FCurrentBoolSwitches) then exit(true);
- mtNote: if not (bsNotes in FCurrentBoolSwitches) then exit(true);
- mtHint: if not (bsHints in FCurrentBoolSwitches) then exit(true);
- end;
- Result:=false;
- end;
- end.
|