12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777 |
- {
- 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;
- {$i fcl-passrc.inc}
- interface
- uses
- {$ifdef pas2js}
- js,
- {$IFDEF NODEJS}
- Node.FS,
- {$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;
- nErrWrongSwitchToggle = 1032;
- nNoResourceSupport = 1033;
- nResourceFileNotFound = 1034;
- nErrInvalidMultiLineLineEnding = 1035;
- // resourcestring patterns of messages
- resourcestring
- SErrInvalidCharacter = 'Invalid character ''%s''';
- SErrOpenString = 'string exceeds end of line';
- SErrIncludeFileNotFound = 'Could not find include file ''%s''';
- SErrResourceFileNotFound = 'Could not find resource 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';
- SErrWrongSwitchToggle = 'Wrong switch toggle, use ON/OFF or +/-';
- SNoResourceSupport = 'No support for resources of type "%s"';
- SErrInvalidMultiLineLineEnding = 'Invalid multilinestring line ending type: use one of CR/LF/CRLF/SOURCE/PLATFORM' ;
- 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, // ^A .. ^Z
- // 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, // @@
- // Three-character tokens
- tkDotDotDot, // ... (mac mode)
- // 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,
- tkobjccategory,
- tkobjcclass,
- tkobjcprotocol,
- tkobject,
- tkof,
- tkoperator,
- tkor,
- tkotherwise,
- 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 }
- msMultiLineStrings { Multiline strings }
- );
- 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 }
- TEOLStyle = (elPlatform,elSource,elLF,elCR,elCRLF);
- TLineReader = class
- Private
- FFilename: string;
- Protected
- EOLStyle : TEOLStyle;
- public
- constructor Create(const AFilename: string); virtual;
- function IsEOF: Boolean; virtual; abstract;
- function ReadLine: string; virtual; abstract;
- function LastEOLStyle: TEOLStyle; virtual;
- 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;
- FMode: TModeSwitch;
- FModuleDirectory: string;
- FResourcePaths,
- FIncludePaths: TStringList;
- FStrictFileCase : Boolean;
- Protected
- function FindIncludeFileName(const aFilename: string): String; virtual; abstract;
- procedure SetBaseDirectory(AValue: string); virtual;
- procedure SetModuleDirectory(AValue: string); virtual;
- procedure SetStrictFileCase(AValue: Boolean); virtual;
- Property IncludePaths: TStringList Read FIncludePaths;
- Property ResourcePaths: TStringList Read FResourcePaths;
- public
- constructor Create; virtual;
- destructor Destroy; override;
- procedure AddIncludePath(const APath: string); virtual;
- procedure AddResourcePath(const APath: string); virtual;
- function FindResourceFileName(const AName: string): String; virtual; abstract;
- function FindSourceFile(const AName: string): TLineReader; virtual; abstract;
- function FindIncludeFile(const AName: string): TLineReader; virtual; abstract;
- property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; // e.g. current path of include file
- property Mode: TModeSwitch read FMode write FMode;
- property ModuleDirectory: string read FModuleDirectory write SetModuleDirectory; // e.g. path of module file
- property StrictFileCase : Boolean Read FStrictFileCase Write SetStrictFileCase;
- end;
- TBaseFileResolverClass = Class of TBaseFileResolver;
- {$IFDEF HASFS}
- { TFileResolver }
- TFileResolver = class(TBaseFileResolver)
- private
- {$ifdef HasStreams}
- FUseStreams: Boolean;
- {$endif}
- Protected
- function SearchLowUpCase(FN: string): string;
- Function FindIncludeFileName(const AName: string): String; override;
- Function CreateFileReader(Const AFileName : String) : TLineReader; virtual;
- Public
- function FindResourceFileName(const AFileName: string): String; override;
- 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;
- function FindResourceFileName(const AFileName: string): String; override;
- 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'
- );
- MACDirectiveBool: array[boolean] of string = (
- 'FALSE', // false
- 'TRUE' // 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 const) 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 const; 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;
- MsgCurLine : Integer;
- MsgPos: integer;
- MsgNumber: integer;
- MsgType: TMessageType;
- MsgPattern: String; // Format parameter
- isMac : Boolean;
- constructor Create(aIsMac : Boolean = False);
- 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
- po_IgnoreUnknownResource,// Ignore resources for which no handler is registered.
- po_AsyncProcs, // allow async procedure modifier
- po_DisableResources // Disable resources altogether
- );
- 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;
- TPScannerCommentEvent = procedure(Sender: TObject; aComment : String) 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;
- // aFileName: full filename (search is already done) aOptions: list of name:value pairs.
- TResourceHandler = Procedure (Sender : TObject; const aFileName : String; aOptions : TStrings) of object;
- TPasScannerTokenPos = {$ifdef UsePChar}PChar{$else}integer{$endif};
- TPascalScanner = class
- private
- type
- TResourceHandlerRecord = record
- Ext : String;
- Handler : TResourceHandler;
- end;
- TWarnMsgNumberState = record
- Number: integer;
- State: TWarnMsgState;
- end;
- TWarnMsgNumberStateArr = array of TWarnMsgNumberState;
- private
- FAllowedBoolSwitches: TBoolSwitches;
- FAllowedModeSwitches: TModeSwitches;
- FAllowedValueSwitches: TValueSwitches;
- FConditionEval: TCondDirectiveEvaluator;
- FCurModulename: string;
- 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;
- FMultilineLineFeedStyle: TEOLStyle;
- FMultilineLineTrimLeft: Integer;
- FNonTokens: TTokens;
- FOnComment: TPScannerCommentEvent;
- 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;
- FResourceHandlers : Array of TResourceHandlerRecord;
- // 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 const);
- 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
- // extension without initial dot (.)
- Function IndexOfResourceHandler(Const aExt : string) : Integer;
- Function FindResourceHandler(Const aExt : string) : TResourceHandler;
- 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 const);
- 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 const;SkipSourceInfo : Boolean = False);overload;
- procedure Error(MsgNumber: integer; const Msg: string);overload;
- procedure Error(MsgNumber: integer; const Fmt: string; Args: array of const);overload;
- procedure PushSkipMode;
- function GetMultiLineStringLineEnd(aReader: TLineReader): string;
- function HandleDirective(const ADirectiveText: String): TToken; virtual;
- function HandleLetterDirective(Letter: char; Enable: boolean): TToken; virtual;
- procedure HandleBoolDirective(bs: TBoolSwitch; const Param: String); virtual;
- procedure DoHandleComment(Sender: TObject; const aComment : string); virtual;
- procedure DoHandleDirective(Sender: TObject; Directive, Param: String;
- var Handled: boolean); virtual;
- procedure HandleMultilineStringTrimLeft(const AParam : String);
- procedure HandleMultilineStringLineEnding(const AParam : string);
- procedure HandleIFDEF(const AParam: String);
- procedure HandleIFNDEF(const AParam: String);
- procedure HandleIFOPT(const AParam: String);
- procedure HandleIF(const AParam: String; aIsMac : Boolean);
- procedure HandleELSEIF(const AParam: String; aIsMac : Boolean);
- 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 HandleIncludeString(Param: String); virtual;
- procedure HandleResource(Param : string); virtual;
- procedure HandleOptimizations(Param : string); virtual;
- procedure DoHandleOptimization(OptName, OptValue: 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;
- procedure PopStackItem; virtual;
- function DoFetchTextToken: TToken;
- function DoFetchMultilineTextToken: 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;
- // extension without initial dot (.), case insensitive
- Procedure RegisterResourceHandler(aExtension : String; aHandler : TResourceHandler); overload;
- Procedure RegisterResourceHandler(aExtensions : Array of String; aHandler : TResourceHandler); overload;
- 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 CurModuleName: string read FCurModulename Write FCurModuleName;
- 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 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 MultilineLineFeedStyle : TEOLStyle Read FMultilineLineFeedStyle Write FMultilineLineFeedStyle;
- Property MultilineLineTrimLeft : Integer Read FMultilineLineTrimLeft Write FMultilineLineTrimLeft;
- 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 OnDirective: TPScannerDirectiveEvent read FOnDirective write FOnDirective;
- property OnComment: TPScannerCommentEvent read FOnComment write FOnComment;
- 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',
- 'objccategory',
- 'objcclass',
- 'objcprotocol',
- 'object',
- 'of',
- 'operator',
- 'or',
- 'otherwise',
- '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',
- 'MULTILINESTRINGS'
- );
- 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
- MessageTypeNames : Array[TMessageType] of string = (
- 'Fatal','Error','Warning','Note','Hint','Info','Debug'
- );
- const
- // all mode switches supported by FPC
- msAllModeSwitches = [low(TModeSwitch)..High(TModeSwitch)];
- AllLanguageModes = [msFPC..msGPC];
- 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 const);
- function SafeFormat(const Fmt: string; Args: array of const): 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 const);
- 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 const): 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];
- if (not Result) and isMac then
- Result:=Value=MacDirectiveBool[false];
- end;
- // inline
- function TCondDirectiveEvaluator.IsTrue(const Value: String): boolean;
- begin
- Result:=Value<>CondDirectiveBool[false];
- if Result and isMac then
- Result:=Value<>MacDirectiveBool[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;
- inc(FTokenEnd);
- {$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 const;
- 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 pos '+IntToStr(MsgPos)+' line '+IntToStr(MsgCurLine),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)
- }
- Function IsMacNoArgFunction(aName : string) : Boolean;
- begin
- Result:=SameText(aName,'DEFINED') or SameText(aName,'UNDEFINED');
- end;
- 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
- aName:=GetTokenString;
- NextToken;
- // for macpas IFC we can have DEFINED A or DEFINED(A)...
- if FToken=tkBraceOpen then
- begin
- // only one parameter is supported
- NextToken;
- if FToken=tkIdentifier then
- NextToken;
- if FToken<>tkBraceClose then
- LogXExpectedButTokenFound(')');
- NextToken;
- end
- else if (IsMac and IsMacNoArgFunction(aName)) then
- begin
- 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 if (IsMac and IsMacNoArgFunction(aName)) then
- begin
- if FToken<>tkIdentifier then
- LogXExpectedButTokenFound('identifier');
- aName:=GetTokenString;
- Push(CondDirectiveBool[OnEvalVariable(Self,aName,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;
- else
- // Do nothing, satisfy compiler
- 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);
- else
- // Do nothing, satisfy compiler
- 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];
- else
- // Do nothing, satisfy compiler
- 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];
- else
- // Do nothing, satisfy compiler
- 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];
- else
- // Do nothing, satisfy compiler
- 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(aIsMac: Boolean);
- begin
- IsMac:=aIsMac
- 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);
- {$IFDEF VerbosePasDirectiveEval}
- Writeln('COND Eval: ', Expr,' -> ',Result);
- {$ENDIF}
- 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;
- if LineEnding=#13 then
- {%H-}EOLStyle:=elCR
- else if LineEnding=#13#10 then
- {%H-}EOLStyle:=elCRLF
- else
- EOLStyle:=elLF
- end;
- function TLineReader.LastEOLStyle: TEOLStyle;
- begin
- Result:=EOLStyle;
- 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
- begin
- if FContent[FPOS]=#10 then
- EOLSTYLE:=elLF
- else
- EOLStyle:=elCR;
- Result:=Copy(FContent,LPos,FPos-LPos)
- end
- else
- Result:=Copy(FContent,LPos,FPos-LPos+1);
- If (not isEOF) and (FContent[FPos]=#13) and (FContent[FPos+1]=#10) then
- begin
- inc(FPos);
- EOLStyle:=elCRLF;
- end;
- 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
- AValue:=IncludeTrailingPathDelimiter(AValue);
- if FBaseDirectory=AValue then Exit;
- FBaseDirectory:=AValue;
- end;
- procedure TBaseFileResolver.SetModuleDirectory(AValue: string);
- begin
- AValue:=IncludeTrailingPathDelimiter(AValue);
- if FModuleDirectory=AValue then Exit;
- FModuleDirectory:=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;
- FResourcePaths := TStringList.Create;
- FMode:=msFPC;
- end;
- destructor TBaseFileResolver.Destroy;
- begin
- FResourcePaths.Free;
- 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;
- procedure TBaseFileResolver.AddResourcePath(const APath: string);
- Var
- FP : String;
- begin
- if (APath='') then
- FResourcePaths.Add('./')
- else
- begin
- {$IFDEF HASFS}
- FP:=IncludeTrailingPathDelimiter(ExpandFileName(APath));
- {$ELSE}
- FP:=APath;
- {$ENDIF}
- FResourcePaths.Add(FP);
- end;
- end;
- {$IFDEF HASFS}
- { ---------------------------------------------------------------------
- TFileResolver
- ---------------------------------------------------------------------}
- function TFileResolver.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 TFileResolver.FindIncludeFileName(const AName: string): String;
- Function FindInPath(FN : String) : String;
- var
- I : integer;
- begin
- Result:='';
- // search in BaseDirectory (not in mode Delphi)
- if (BaseDirectory<>'')
- and ((ModuleDirectory='') or not (Mode in [msDelphi,msDelphiUnicode])) then
- begin
- Result:=SearchLowUpCase(BaseDirectory+FN);
- if Result<>'' then exit;
- end;
- // search in ModuleDirectory
- if (ModuleDirectory<>'') then
- begin
- Result:=SearchLowUpCase(ModuleDirectory+FN);
- if Result<>'' then exit;
- end;
- // search in include paths
- I:=0;
- While (I<FIncludePaths.Count) do
- begin
- Result:=SearchLowUpCase(FIncludePaths[i]+FN);
- if Result<>'' then exit;
- Inc(I);
- end;
- end;
- var
- 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.FindResourceFileName(const AFileName: string): String;
- Function FindInPath(FN : String) : String;
- var
- I : integer;
- begin
- Result:='';
- I:=0;
- While (Result='') and (I<FResourcePaths.Count) do
- begin
- Result:=SearchLowUpCase(FResourcePaths[i]+FN);
- Inc(I);
- end;
- // search in BaseDirectory
- if (Result='') and (BaseDirectory<>'') then
- Result:=SearchLowUpCase(BaseDirectory+FN);
- end;
- var
- FN : string;
- begin
- Result := '';
- // convert pathdelims to system
- FN:=SetDirSeparators(AFileName);
- If FilenameIsAbsolute(FN) then
- begin
- Result := SearchLowUpCase(FN);
- end
- else
- begin
- // file name is relative
- // search in include path
- Result:=FindInPath(FN);
- end;
- 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;
- function TStreamResolver.FindResourceFileName(const AFileName: string): String;
- begin
- raise EFileNotFoundError.Create('TStreamResolver.FindResourceFileName 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) and (BaseDirectory<>'') then
- I:=FStreams.IndexOf(IncludeTrailingPathDelimiter(BaseDirectory)+aName);
- 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.RegisterResourceHandler(aExtension: String; aHandler: TResourceHandler);
- Var
- Idx: Integer;
- begin
- if (aExtension='') then
- exit;
- if (aExtension[1]='.') then
- aExtension:=copy(aExtension,2,Length(aExtension)-1);
- Idx:=IndexOfResourceHandler(lowerCase(aExtension));
- if Idx=-1 then
- begin
- Idx:=Length(FResourceHandlers);
- SetLength(FResourceHandlers,Idx+1);
- FResourceHandlers[Idx].Ext:=LowerCase(aExtension);
- end;
- FResourceHandlers[Idx].handler:=aHandler;
- end;
- procedure TPascalScanner.RegisterResourceHandler(aExtensions: array of String; aHandler: TResourceHandler);
- Var
- S : String;
- begin
- For S in aExtensions do
- RegisterResourceHandler(S,aHandler);
- 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);
- Var
- aPath : String;
- begin
- Clearfiles;
- FCurSourceFile := FileResolver.FindSourceFile(AFilename);
- FCurFilename := AFilename;
- AddFile(FCurFilename);
- {$IFDEF HASFS}
- aPath:=ExtractFilePath(FCurFilename);
- if (aPath<>'') then
- aPath:=IncludeTrailingPathDelimiter(aPath);
- FileResolver.ModuleDirectory := aPath;
- FileResolver.BaseDirectory := aPath;
- {$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;
- procedure TPascalScanner.PopStackItem;
- var
- IncludeStackItem: TIncludeStackItem;
- 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;
- FileResolver.BaseDirectory:=ExtractFilePath(FCurFilename);
- FCurToken := IncludeStackItem.Token;
- FCurTokenString := IncludeStackItem.TokenString;
- FCurLine := IncludeStackItem.Line;
- FCurRow := IncludeStackItem.Row;
- FCurColumnOffset := IncludeStackItem.ColumnOffset;
- FTokenPos := IncludeStackItem.TokenPos;
- IncludeStackItem.Free;
- end;
- function TPascalScanner.FetchToken: TToken;
- begin
- if Not (FCurToken in [tkWhiteSpace,tkLineEnding]) then
- FPreviousToken:=FCurToken;
- while true do
- begin
- Result := DoFetchToken;
- Case FCurToken of
- tkEOF:
- begin
- if FIncludeStack.Count > 0 then
- begin
- PopStackitem;
- 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
- Result:=tkEOF;
- 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 const);
- begin
- SetCurMsg(mtError,MsgNumber,Fmt,Args);
- raise EScannerError.CreateFmt('%s(%d,%d) Error: %s',
- [FormatPath(CurFilename),CurRow,CurColumn,FLastMsg]);
- end;
- function TPascalScanner.GetMultiLineStringLineEnd(aReader : TLineReader) : string;
- Var
- aLF : String;
- aStyle: TEOLStyle;
- begin
- aStyle:=MultilineLineFeedStyle;
- if aStyle=elSource then
- aStyle:=aReader.LastEOLStyle;
- case aStyle of
- elCR : aLF:=#13;
- elCRLF : aLF:=#13#10;
- elLF : aLF:=#10;
- elPlatform : alf:=sLineBreak;
- else
- aLF:=#10;
- end;
- Result:=aLF;
- end;
- function TPascalScanner.DoFetchMultilineTextToken:TToken;
- var
- StartPos,OldLength : Integer;
- TokenStart : {$ifdef UsePChar}PChar{$else}integer{$endif};
- {$ifndef UsePChar}
- s: String;
- l: integer;
- {$endif}
- Procedure AddToCurString(addLF : Boolean);
- var
- SectionLength,i : Integer;
- aLF : String;
- begin
- i:=MultilineLineTrimLeft;
- if I=-1 then
- I:=StartPos+1;
- if I>0 then
- begin
- While ({$ifdef UsePChar} TokenStart^{$ELSE}FCurLine[TokenStart]{$ENDIF} in [' ',#9]) and (TokenStart<=FTokenPos) and (I>0) do
- begin
- Inc(TokenStart);
- Dec(I);
- end;
- end
- else if I=-2 then
- begin
- While ({$ifdef UsePChar} TokenStart^{$ELSE}FCurLine[TokenStart]{$ENDIF} in [' ',#9]) and (TokenStart<=FTokenPos) do
- Inc(TokenStart);
- end;
- SectionLength := FTokenPos - TokenStart+Ord(AddLF);
- {$ifdef UsePChar}
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength);
- {$endif}
- if AddLF then
- begin
- alf:=GetMultiLineStringLineEnd(FCurSourceFile);
- FCurTokenString:=FCurTokenString+aLF;
- Inc(OldLength,Length(aLF));
- end;
- Inc(OldLength, SectionLength);
- end;
- begin
- Result:=tkEOF;
- OldLength:=0;
- FCurTokenString := '';
- {$ifndef UsePChar}
- s:=FCurLine;
- l:=length(s);
- StartPos:=FTokenPos;
- {$ELSE}
- StartPos:=FTokenPos-PChar(FCurLine);
- {$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
- begin
- FTokenPos:=FTokenPos-1;
- AddToCurString(true);
- // Writeln('Curtokenstring : >>',FCurTOkenString,'<<');
- if not Self.FetchLine then
- Error(nErrOpenString,SErrOpenString);
- // Writeln('Current line is now : ',FCurLine);
- {$ifndef UsePChar}
- s:=FCurLine;
- l:=length(s);
- {$ELSE}
- FTokenPos:=PChar(FCurLine);
- {$endif}
- TokenStart:=FTokenPos;
- end
- else
- Inc(FTokenPos);
- end;
- Inc(FTokenPos);
- Result := tkString;
- end;
- else
- Break;
- end;
- AddToCurString(false);
- until false;
- if length(FCurTokenString)>1 then
- begin
- FCurTokenString[1]:='''';
- FCurTokenString[Length(FCurTokenString)]:='''';
- end;
- 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;
- aFileName : string;
- begin
- Param:=Trim(Param);
- 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 TLineReader then
- begin
- aFileName:=TLineReader(FCurSourceFile).Filename;
- FileResolver.BaseDirectory := ExtractFilePath(aFileName);
- FCurFilename := aFileName; // nicer error messages
- end;
- AddFile(FCurFilename);
- If LogEvent(sleFile) then
- DoLog(mtInfo,nLogOpeningFile,SLogOpeningFile,[FormatPath(FCurFileName)],True);
- end;
- procedure TPascalScanner.HandleIncludeString(Param: String);
- var
- NewSourceFile: TLineReader;
- aString,aLine: string;
- begin
- Param:=Trim(Param);
- 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]);
- try
- AString:='';
- While not NewSourceFile.IsEOF Do
- begin
- ALine:=NewSourceFile.ReadLine;
- if aString<>'' then
- aString:=aString+GetMultiLineStringLineEnd(NewSourceFile);
- AString:=aString+aLine;
- end;
- finally
- NewSourceFile.Free;
- end;
- FCurTokenString:=''''+AString+'''';
- FCurToken:=tkString;
- end;
- procedure TPascalScanner.HandleResource(Param: string);
- Var
- Ext,aFullFileName,aFilename,aOptions : String;
- P: Integer;
- H : TResourceHandler;
- OptList : TStrings;
- begin
- aFilename:='';
- aOptions:='';
- P:=Pos(';',Param);
- If P=0 then
- aFileName:=Trim(Param)
- else
- begin
- aFileName:=Trim(Copy(Param,1,P-1));
- aOptions:=Copy(Param,P+1,Length(Param)-P);
- end;
- Ext:=ExtractFileExt(aFileName);
- // Construct & find filename
- If (ChangeFileExt(aFileName,'')='*') then
- aFileName:=ChangeFileExt(ExtractFileName(CurFilename),Ext);
- aFullFileName:=FileResolver.FindResourceFileName(aFileName);
- if aFullFileName='' then
- Error(nResourceFileNotFound,SErrResourceFileNotFound,[aFileName]);
- // Check if we can find a handler.
- if Ext<>'' then
- Ext:=Copy(Ext,2,Length(Ext)-1);
- H:=FindResourceHandler(LowerCase(Ext));
- if (H=Nil) then
- H:=FindResourceHandler('*');
- if (H=Nil) then
- begin
- if not (po_IgnoreUnknownResource in Options) then
- Error(nNoResourceSupport,SNoResourceSupport,[Ext]);
- exit;
- end;
- // Let the handler take care of the rest.
- OptList:=TStringList.Create;
- try
- OptList.NameValueSeparator:=':';
- OptList.Delimiter:=';';
- OptList.StrictDelimiter:=True;
- OptList.DelimitedText:=aOptions;
- H(Self,aFullFileName,OptList);
- finally
- OptList.Free;
- end;
- end;
- procedure TPascalScanner.HandleOptimizations(Param: string);
- // $optimization A,B-,C+
- var
- p, StartP, l: Integer;
- OptName, Value: String;
- begin
- p:=1;
- l:=length(Param);
- while p<=l do
- begin
- // read next flag
- // skip whitespace
- while (p<=l) and (Param[p] in [' ',#9,#10,#13]) do
- inc(p);
- // read name
- StartP:=p;
- while (p<=l) and (Param[p] in ['a'..'z','A'..'Z','0'..'9','_']) do
- inc(p);
- if p=StartP then
- Error(nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['optimization']);
- OptName:=copy(Param,StartP,p-StartP);
- if lowercase(LeftStr(OptName,2))='no' then
- begin
- Delete(OptName,1,2);
- DoHandleOptimization(OptName,'-');
- exit;
- end;
- // skip whitespace
- while (p<=l) and (Param[p] in [' ',#9,#10,#13]) do
- inc(p);
- // read value
- StartP:=p;
- while (p<=l) and (Param[p]<>',') do
- inc(p);
- Value:=TrimRight(copy(Param,StartP,p-StartP));
- DoHandleOptimization(OptName,Value);
- inc(p);
- end;
- end;
- procedure TPascalScanner.DoHandleOptimization(OptName, OptValue: string);
- begin
- // default: skip any optimization directive
- if OptName='' then ;
- if OptValue='' then ;
- 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,Trim(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 = [];
- UseOtherwise: boolean = true
- );
- 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];
- if UseOtherwise then
- UnsetNonToken(tkotherwise)
- else
- SetNonToken(tkotherwise);
- end;
- Handled:=false;
- FileResolver.Mode:=LangMode;
- 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:=Trim(UpperCase(Param));
- Case P of
- 'FPC','DEFAULT':
- begin
- SetMode(msFpc,FPCModeSwitches,false,bsFPCMode);
- SetNonToken(tkobjcclass);
- SetNonToken(tkobjcprotocol);
- SetNonToken(tkobjcCategory);
- end;
- 'OBJFPC':
- begin
- SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
- UnsetNonToken(tkgeneric);
- UnsetNonToken(tkspecialize);
- SetNonToken(tkobjcclass);
- SetNonToken(tkobjcprotocol);
- SetNonToken(tkobjcCategory);
- end;
- 'DELPHI':
- begin
- SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
- SetNonToken(tkgeneric);
- SetNonToken(tkspecialize);
- SetNonToken(tkobjcclass);
- SetNonToken(tkobjcprotocol);
- SetNonToken(tkobjcCategory);
- end;
- 'DELPHIUNICODE':
- begin
- SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
- SetNonToken(tkgeneric);
- SetNonToken(tkspecialize);
- SetNonToken(tkobjcclass);
- SetNonToken(tkobjcprotocol);
- SetNonToken(tkobjcCategory);
- end;
- 'TP':
- SetMode(msTP7,TPModeSwitches,false);
- 'MACPAS':
- SetMode(msMac,MacModeSwitches,false,bsMacPasMode);
- 'ISO':
- SetMode(msIso,ISOModeSwitches,false,[],[],false);
- 'EXTENDEDPASCAL':
- SetMode(msExtpas,ExtPasModeSwitches,false);
- 'GPC':
- SetMode(msGPC,GPCModeSwitches,false);
- else
- Error(nErrInvalidMode,SErrInvalidMode,[Param])
- end;
- end;
- procedure TPascalScanner.HandleModeSwitch(const Param: String);
- // $modeswitch param
- // name, name-, name+, name off, name on, name- comment, name on comment
- Var
- MS : TModeSwitch;
- MSN,PM : String;
- p : Integer;
- Enable: Boolean;
- begin
- Enable:=False;
- PM:=Param;
- p:=1;
- while (p<=length(PM)) and (PM[p] in ['a'..'z','A'..'Z','_','0'..'9']) do
- inc(p);
- MSN:=LeftStr(PM,p-1);
- Delete(PM,1,p-1);
- MS:=StrToModeSwitch(MSN);
- if (MS=msNone) or not (MS in AllowedModeSwitches) then
- begin
- if po_CheckModeSwitches in Options then
- Error(nErrInvalidModeSwitch,SErrInvalidModeSwitch,[MSN])
- else
- DoLog(mtWarning,nErrInvalidModeSwitch,SErrInvalidModeSwitch,[MSN]);
- exit; // ignore
- end;
- if PM='' then
- Enable:=true
- else
- case PM[1] of
- '+','-':
- begin
- Enable:=PM[1]='+';
- p:=2;
- if (p<=length(PM)) and not (PM[p] in [' ',#9]) then
- Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
- end;
- ' ',#9:
- begin
- PM:=TrimLeft(PM);
- if PM<>'' then
- begin
- p:=1;
- while (p<=length(PM)) and (PM[p] in ['A'..'Z']) do inc(p);
- if (p<=length(PM)) and not (PM[p] in [' ',#9]) then
- Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
- PM:=LeftStr(PM,p-1);
- if PM='ON' then
- Enable:=true
- else if PM='OFF' then
- Enable:=false
- else
- Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
- end;
- end;
- else
- Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
- end;
- if MS in CurrentModeSwitches=Enable then
- exit; // no change
- if MS in ReadOnlyModeSwitches then
- begin
- DoLog(mtWarning,nErrInvalidModeSwitch,SErrInvalidModeSwitch,[MSN]);
- exit;
- end;
- if Enable then
- CurrentModeSwitches:=CurrentModeSwitches+[MS]
- 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; aIsMac: Boolean);
- begin
- PushSkipMode;
- if PPIsSkipping then
- PPSkipMode := ppSkipAll
- else
- begin
- ConditionEval.MsgCurLine:=CurTokenPos.Row;
- ConditionEval.isMac:=aIsMac;
- 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; aIsMac : Boolean);
- begin
- if PPSkipStackIndex = 0 then
- Error(nErrInvalidPPElse,sErrInvalidPPElse);
- if PPSkipMode = ppSkipIfBranch then
- begin
- ConditionEval.isMac:=aIsMac;
- 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
- begin
- P:=Pos(#9,ADirectiveText);
- If P=0 then
- P:=Length(ADirectiveText)+1;
- end;
- 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);
- 'IFC',
- 'IF':
- HandleIF(Param,UpperCase(Directive)='IFC');
- 'ELIFC',
- 'ELSEIF':
- HandleELSEIF(Param,UpperCase(Directive)='ELIFC');
- 'ELSEC',
- 'ELSE':
- HandleELSE(Param);
- 'ENDC',
- '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;
- Param:=Trim(Param);
- Case UpperCase(Directive) of
- 'ASSERTIONS':
- DoBoolDirective(bsAssertions);
- 'DEFINE',
- 'DEFINEC',
- 'SETC':
- 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);
- 'INCLUDESTRING','INCLUDESTRINGFILE':
- begin
- HandleIncludeString(Param);
- Result:=tkString;
- end;
- 'INTERFACES':
- HandleInterfaces(Param);
- 'LONGSTRINGS':
- DoBoolDirective(bsLongStrings);
- 'MACRO':
- DoBoolDirective(bsMacro);
- 'MESSAGE':
- HandleMessageDirective(Param);
- 'MODE':
- HandleMode(Param);
- 'MODESWITCH':
- HandleModeSwitch(Param);
- 'MULTILINESTRINGLINEENDING':
- HandleMultilineStringLineEnding(Param);
- 'MULTILINESTRINGTRIMLEFT':
- HandleMultilineStringTrimLeft(Param);
- 'NOTE':
- DoLog(mtNote,nUserDefined,SUserDefined,[Param]);
- 'NOTES':
- DoBoolDirective(bsNotes);
- 'OBJECTCHECKS':
- DoBoolDirective(bsObjectChecks);
- 'OPTIMIZATION':
- HandleOptimizations(Param);
- 'OVERFLOWCHECKS','OV':
- DoBoolDirective(bsOverflowChecks);
- 'POINTERMATH':
- DoBoolDirective(bsPointerMath);
- 'R' :
- if not (po_DisableResources in Options) then
- HandleResource(Param);
- '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);
- 'ALIGN',
- 'CALLING',
- 'INLINE',
- 'PACKRECORDS',
- 'PACKENUM' : ;
- 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
- begin
- NewValue:=True;// Fool compiler
- Error(nErrXExpectedButYFound,SErrXExpectedButYFound,['on',Param]);
- end;
- 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.DoHandleComment(Sender: TObject; const aComment: string);
- begin
- if Assigned(OnComment) then
- OnComment(Sender,aComment);
- end;
- procedure TPascalScanner.DoHandleDirective(Sender: TObject; Directive,
- Param: String; var Handled: boolean);
- begin
- if Assigned(OnDirective) then
- OnDirective(Sender,Directive,Param,Handled);
- end;
- procedure TPascalScanner.HandleMultilineStringTrimLeft(const AParam: String);
- Var
- S : String;
- i : integer;
- begin
- S:=UpperCase(Trim(aParam));
- Case UpperCase(S) of
- 'ALL' : I:=-2;
- 'AUTO' : I:=-1;
- 'NONE' : I:=0;
- else
- If not TryStrToInt(S,I) then
- I:=0;
- end;
- MultilineLineTrimLeft:=I;
- end;
- procedure TPascalScanner.HandleMultilineStringLineEnding(const AParam: string);
- Var
- S : TEOLStyle;
- begin
- Case UpperCase(Trim(aParam)) of
- 'CR' : s:=elCR;
- 'LF' : s:=elLF;
- 'CRLF' : s:=elCRLF;
- 'SOURCE' : s:=elSource;
- 'PLATFORM' : s:=elPlatform;
- else
- Error(nErrInvalidMultiLineLineEnding,sErrInvalidMultiLineLineEnding);
- end;
- MultilineLineFeedStyle:=S;
- end;
- function TPascalScanner.DoFetchToken: TToken;
- var
- TokenStart: {$ifdef UsePChar}PChar{$else}integer{$endif};
- i: TToken;
- SectionLength, NestingLevel, Index: Integer;
- {$ifdef UsePChar}
- OldLength: integer;
- Ch: Char;
- LE: string[2];
- {$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
- TokenStart:={$ifdef UsePChar}nil{$else}0{$endif};
- 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
- If not (msMultiLineStrings in CurrentModeSwitches) then
- Error(nErrInvalidCharacter, SErrInvalidCharacter,
- [{$ifdef UsePChar}FTokenPos[0]{$else}s[FTokenPos]{$endif}]);
- Result:=DoFetchMultilineTextToken;
- end;
- '&':
- 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) and (s[FTokenPos]='.'){$endif} then
- begin
- Inc(FTokenPos);
- Result := tkSquaredBraceOpen;
- end
- else if {$ifdef UsePChar}FTokenPos[0] <> '*'{$else}(FTokenPos>l) or (s[FTokenPos]<>'*'){$endif} then
- Result := tkBraceOpen
- else
- begin
- {$ifdef UsePChar}
- LE:=LineEnding;
- {$endif}
- // 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 + length(LineEnding)); // Corrected JC
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1],SectionLength);
- Inc(OldLength, SectionLength);
- for Ch in LE do
- begin
- Inc(OldLength);
- FCurTokenString[OldLength] := Ch;
- end;
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+LineEnding; // Corrected JC
- {$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)
- else
- DoHandleComment(Self,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 := tkSquaredBraceClose;
- end
- else if {$ifdef UsePChar}FTokenPos[0]='.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then
- begin
- Inc(FTokenPos);
- if {$ifdef UsePChar}FTokenPos[0]='.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then
- begin
- Inc(FTokenPos);
- Result:=tkDotDotDot;
- end
- else
- 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 and .)
- // 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]<>'.') and (FTokenPos[1]<>')'){$else}
- (FTokenPos<=l) and (s[FTokenPos]='.') and ((FTokenPos=l) or ((s[FTokenPos+1]<>'.') and (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]) 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}
- LE:=LineEnding;
- 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 + length(LineEnding)); // Corrected JC
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1],SectionLength);
- // Corrected JC: Append the correct lineending
- Inc(OldLength, SectionLength);
- for Ch in LE do
- begin
- Inc(OldLength);
- FCurTokenString[OldLength] := Ch;
- end;
- {$else}
- FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+LineEnding; // Corrected JC
- {$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)
- else
- DoHandleComment(Self, 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 const);
- Var
- Msg : String;
- 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);
- Msg:=Format('%s(%d,%d) : %s',[FormatPath(FCurFileName),CurRow,CurColumn,FLastMsg]);
- raise EScannerError.Create(Msg);
- 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;
- if ([msObjectiveC1,msObjectiveC2] * FCurrentModeSwitches) = [] then
- begin
- SetNonToken(tkobjcclass);
- SetNonToken(tkobjcprotocol);
- SetNonToken(tkobjccategory);
- end
- else
- begin
- UnSetNonToken(tkobjcclass);
- UnSetNonToken(tkobjcprotocol);
- UnSetNonToken(tkobjccategory);
- 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 const;
- 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.IndexOfResourceHandler(const aExt: string): Integer;
- begin
- Result:=Length(FResourceHandlers)-1;
- While (Result>=0) and (FResourceHandlers[Result].Ext<>aExt) do
- Dec(Result);
- end;
- function TPascalScanner.FindResourceHandler(const aExt: string): TResourceHandler;
- Var
- Idx : Integer;
- begin
- Idx:=IndexOfResourceHandler(aExt);
- if Idx=-1 then
- Result:=Nil
- else
- Result:=FResourceHandlers[Idx].handler;
- 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 const);
- 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
- Result:=false;
- 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);
- else
- // Do nothing, satisfy compiler
- end;
- end;
- end.
|