pscanner.pp 184 KB

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