pscanner.pp 160 KB

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