scanner.pas 202 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the scanner part and handling of the switches
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  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. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit scanner;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,
  22. globtype,globals,constexp,version,tokens,
  23. verbose,comphook,
  24. finput,
  25. widestr;
  26. const
  27. max_include_nesting=32;
  28. max_macro_nesting=16;
  29. preprocbufsize=32*1024;
  30. { when parsing an internally generated macro, if an identifier is
  31. prefixed with this constant then it will always be interpreted as a
  32. unit name (to avoid clashes with user-specified parameter or field
  33. names duplicated in internally generated code) }
  34. internal_macro_escape_unit_namespace_name = #1;
  35. internal_macro_escape_begin = internal_macro_escape_unit_namespace_name;
  36. internal_macro_escape_end = internal_macro_escape_unit_namespace_name;
  37. type
  38. tcommentstyle = (comment_none,comment_tp,comment_oldtp,comment_delphi,comment_c);
  39. tscannerfile = class;
  40. preproctyp = (pp_ifdef,pp_ifndef,pp_if,pp_ifopt,pp_else,pp_elseif);
  41. tpreprocstack = class
  42. typ,
  43. { stores the preproctyp of the last (else)if(ndef) directive
  44. so we can check properly for ifend when legacyifend is on }
  45. iftyp : preproctyp;
  46. accept : boolean;
  47. next : tpreprocstack;
  48. name : TIDString;
  49. line_nb : longint;
  50. fileindex : longint;
  51. constructor Create(atyp:preproctyp;a:boolean;n:tpreprocstack);
  52. end;
  53. tdirectiveproc=procedure;
  54. tdirectiveitem = class(TFPHashObject)
  55. public
  56. is_conditional : boolean;
  57. proc : tdirectiveproc;
  58. constructor Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  59. constructor CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  60. end;
  61. // stack for replay buffers
  62. treplaystack = class
  63. token : ttoken;
  64. idtoken : ttoken;
  65. orgpattern,
  66. pattern : string;
  67. cstringpattern: ansistring;
  68. patternw : pcompilerwidestring;
  69. settings : tsettings;
  70. tokenbuf : tdynamicarray;
  71. tokenbuf_needs_swapping : boolean;
  72. next : treplaystack;
  73. constructor Create(atoken: ttoken;aidtoken:ttoken;
  74. const aorgpattern,apattern:string;const acstringpattern:ansistring;
  75. apatternw:pcompilerwidestring;asettings:tsettings;
  76. atokenbuf:tdynamicarray;change_endian:boolean;anext:treplaystack);
  77. destructor destroy;override;
  78. end;
  79. tcompile_time_predicate = function(var valuedescr: String) : Boolean;
  80. tspecialgenerictoken =
  81. (ST_LOADSETTINGS,
  82. ST_LINE,
  83. ST_COLUMN,
  84. ST_FILEINDEX,
  85. ST_LOADMESSAGES);
  86. { tscannerfile }
  87. tscannerfile = class
  88. private
  89. procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
  90. procedure cachenexttokenpos;
  91. procedure setnexttoken;
  92. procedure savetokenpos;
  93. procedure restoretokenpos;
  94. procedure writetoken(t: ttoken);
  95. function readtoken : ttoken;
  96. public
  97. inputfile : tinputfile; { current inputfile list }
  98. inputfilecount : longint;
  99. inputbuffer, { input buffer }
  100. inputpointer : pchar;
  101. inputstart : longint;
  102. line_no, { line }
  103. lastlinepos : longint;
  104. lasttokenpos,
  105. nexttokenpos : longint; { token }
  106. lasttoken,
  107. nexttoken : ttoken;
  108. oldlasttokenpos : longint; { temporary saving/restoring tokenpos }
  109. oldcurrent_filepos,
  110. oldcurrent_tokenpos : tfileposinfo;
  111. replaytokenbuf,
  112. recordtokenbuf : tdynamicarray;
  113. { last settings we stored }
  114. last_settings : tsettings;
  115. last_message : pmessagestaterecord;
  116. { last filepos we stored }
  117. last_filepos,
  118. { if nexttoken<>NOTOKEN, then nexttokenpos holds its filepos }
  119. next_filepos : tfileposinfo;
  120. { current macro nesting depth }
  121. macro_nesting_depth,
  122. comment_level,
  123. yylexcount : longint;
  124. ignoredirectives : TFPHashList; { ignore directives, used to give warnings only once }
  125. preprocstack : tpreprocstack;
  126. replaystack : treplaystack;
  127. preproc_pattern : string;
  128. preproc_token : ttoken;
  129. { true, if we are parsing preprocessor expressions }
  130. in_preproc_comp_expr : boolean;
  131. { true if tokens must be converted to opposite endianess}
  132. change_endian_for_replay : boolean;
  133. constructor Create(const fn:string; is_macro: boolean = false);
  134. destructor Destroy;override;
  135. { File buffer things }
  136. function openinputfile:boolean;
  137. procedure closeinputfile;
  138. function tempopeninputfile:boolean;
  139. procedure tempcloseinputfile;
  140. procedure saveinputfile;
  141. procedure restoreinputfile;
  142. procedure firstfile;
  143. procedure nextfile;
  144. procedure addfile(hp:tinputfile);
  145. procedure reload;
  146. { replaces current token with the text in p }
  147. procedure substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);
  148. { Scanner things }
  149. procedure gettokenpos;
  150. procedure inc_comment_level;
  151. procedure dec_comment_level;
  152. procedure illegal_char(c:char);
  153. procedure end_of_file;
  154. procedure checkpreprocstack;
  155. procedure poppreprocstack;
  156. procedure ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  157. procedure elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  158. procedure elsepreprocstack;
  159. procedure popreplaystack;
  160. function replay_stack_depth:longint;
  161. procedure handleconditional(p:tdirectiveitem);
  162. procedure handledirectives;
  163. procedure linebreak;
  164. procedure recordtoken;
  165. procedure startrecordtokens(buf:tdynamicarray);
  166. procedure stoprecordtokens;
  167. function is_recording_tokens:boolean;
  168. procedure replaytoken;
  169. procedure startreplaytokens(buf:tdynamicarray; change_endian:boolean);
  170. { bit length asizeint is target depend }
  171. procedure tokenwritesizeint(val : asizeint);
  172. procedure tokenwritelongint(val : longint);
  173. procedure tokenwritelongword(val : longword);
  174. procedure tokenwriteword(val : word);
  175. procedure tokenwriteshortint(val : shortint);
  176. procedure tokenwriteset(var b;size : longint);
  177. procedure tokenwriteenum(var b;size : longint);
  178. function tokenreadsizeint : asizeint;
  179. procedure tokenwritesettings(var asettings : tsettings; var size : asizeint);
  180. { longword/longint are 32 bits on all targets }
  181. { word/smallint are 16-bits on all targest }
  182. function tokenreadlongword : longword;
  183. function tokenreadword : word;
  184. function tokenreadlongint : longint;
  185. function tokenreadsmallint : smallint;
  186. { short int is one a signed byte }
  187. function tokenreadshortint : shortint;
  188. function tokenreadbyte : byte;
  189. { This one takes the set size as an parameter }
  190. procedure tokenreadset(var b;size : longint);
  191. function tokenreadenum(size : longint) : longword;
  192. procedure tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
  193. procedure readchar;
  194. procedure readstring;
  195. procedure readnumber;
  196. function readid:string;
  197. function readval:longint;
  198. function readcomment(include_special_char: boolean = false):string;
  199. function readquotedstring:string;
  200. function readstate:char;
  201. function readoptionalstate(fallback:char):char;
  202. function readstatedefault:char;
  203. procedure skipspace;
  204. procedure skipuntildirective;
  205. procedure skipcomment(read_first_char:boolean);
  206. procedure skipdelphicomment;
  207. procedure skipoldtpcomment(read_first_char:boolean);
  208. procedure readtoken(allowrecordtoken:boolean);
  209. function readpreproc:ttoken;
  210. function readpreprocint(var value:int64;const place:string):boolean;
  211. function asmgetchar:char;
  212. end;
  213. {$ifdef PREPROCWRITE}
  214. tpreprocfile=class
  215. f : text;
  216. buf : pointer;
  217. spacefound,
  218. eolfound : boolean;
  219. constructor create(const fn:string);
  220. destructor destroy; override;
  221. procedure Add(const s:string);
  222. procedure AddSpace;
  223. end;
  224. {$endif PREPROCWRITE}
  225. var
  226. { read strings }
  227. c : char;
  228. orgpattern,
  229. pattern : string;
  230. cstringpattern : ansistring;
  231. patternw : pcompilerwidestring;
  232. { token }
  233. token, { current token being parsed }
  234. idtoken : ttoken; { holds the token if the pattern is a known word }
  235. current_scanner : tscannerfile; { current scanner in use }
  236. current_commentstyle : tcommentstyle; { needed to use read_comment from directives }
  237. {$ifdef PREPROCWRITE}
  238. preprocfile : tpreprocfile; { used with only preprocessing }
  239. {$endif PREPROCWRITE}
  240. type
  241. tdirectivemode = (directive_all, directive_turbo, directive_mac);
  242. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  243. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  244. procedure InitScanner;
  245. procedure DoneScanner;
  246. { To be called when the language mode is finally determined }
  247. Function SetCompileMode(const s:string; changeInit: boolean):boolean;
  248. Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
  249. procedure SetAppType(NewAppType:tapptype);
  250. implementation
  251. uses
  252. SysUtils,
  253. cutils,cfileutl,
  254. systems,
  255. switches,
  256. symbase,symtable,symtype,symsym,symconst,symdef,defutil,
  257. { This is needed for tcputype }
  258. cpuinfo,
  259. fmodule,fppu,
  260. { this is needed for $I %CURRENTROUTINE%}
  261. procinfo;
  262. var
  263. { dictionaries with the supported directives }
  264. turbo_scannerdirectives : TFPHashObjectList; { for other modes }
  265. mac_scannerdirectives : TFPHashObjectList; { for mode mac }
  266. {*****************************************************************************
  267. Helper routines
  268. *****************************************************************************}
  269. const
  270. { use any special name that is an invalid file name to avoid problems }
  271. preprocstring : array [preproctyp] of string[7]
  272. = ('$IFDEF','$IFNDEF','$IF','$IFOPT','$ELSE','$ELSEIF');
  273. function is_keyword(const s:string):boolean;
  274. var
  275. low,high,mid : longint;
  276. begin
  277. if not (length(s) in [tokenlenmin..tokenlenmax]) or
  278. not (s[1] in ['a'..'z','A'..'Z']) then
  279. begin
  280. is_keyword:=false;
  281. exit;
  282. end;
  283. low:=ord(tokenidx^[length(s),s[1]].first);
  284. high:=ord(tokenidx^[length(s),s[1]].last);
  285. while low<high do
  286. begin
  287. mid:=(high+low+1) shr 1;
  288. if pattern<tokeninfo^[ttoken(mid)].str then
  289. high:=mid-1
  290. else
  291. low:=mid;
  292. end;
  293. is_keyword:=(pattern=tokeninfo^[ttoken(high)].str) and
  294. ((tokeninfo^[ttoken(high)].keyword*current_settings.modeswitches)<>[]);
  295. end;
  296. Procedure HandleModeSwitches(switch: tmodeswitch; changeInit: boolean);
  297. begin
  298. { turn ansi/unicodestrings on by default ? (only change when this
  299. particular setting is changed, so that a random modeswitch won't
  300. change the state of $h+/$h-) }
  301. if switch in [m_none,m_default_ansistring,m_default_unicodestring] then
  302. begin
  303. if ([m_default_ansistring,m_default_unicodestring]*current_settings.modeswitches)<>[] then
  304. begin
  305. { can't have both ansistring and unicodestring as default }
  306. if switch=m_default_ansistring then
  307. begin
  308. exclude(current_settings.modeswitches,m_default_unicodestring);
  309. if changeinit then
  310. exclude(init_settings.modeswitches,m_default_unicodestring);
  311. end
  312. else if switch=m_default_unicodestring then
  313. begin
  314. exclude(current_settings.modeswitches,m_default_ansistring);
  315. if changeinit then
  316. exclude(init_settings.modeswitches,m_default_ansistring);
  317. end;
  318. { enable $h+ }
  319. include(current_settings.localswitches,cs_refcountedstrings);
  320. if changeinit then
  321. include(init_settings.localswitches,cs_refcountedstrings);
  322. if m_default_unicodestring in current_settings.modeswitches then
  323. begin
  324. def_system_macro('FPC_UNICODESTRINGS');
  325. def_system_macro('UNICODE');
  326. end;
  327. end
  328. else
  329. begin
  330. exclude(current_settings.localswitches,cs_refcountedstrings);
  331. if changeinit then
  332. exclude(init_settings.localswitches,cs_refcountedstrings);
  333. undef_system_macro('FPC_UNICODESTRINGS');
  334. undef_system_macro('UNICODE');
  335. end;
  336. end;
  337. { turn inline on by default ? }
  338. if switch in [m_none,m_default_inline] then
  339. begin
  340. if (m_default_inline in current_settings.modeswitches) then
  341. begin
  342. include(current_settings.localswitches,cs_do_inline);
  343. if changeinit then
  344. include(init_settings.localswitches,cs_do_inline);
  345. end
  346. else
  347. begin
  348. exclude(current_settings.localswitches,cs_do_inline);
  349. if changeinit then
  350. exclude(init_settings.localswitches,cs_do_inline);
  351. end;
  352. end;
  353. { turn on system codepage by default }
  354. if switch in [m_none,m_systemcodepage] then
  355. begin
  356. { both m_systemcodepage and specifying a code page via -FcXXX or
  357. "$codepage XXX" change current_settings.sourcecodepage. If
  358. we used -FcXXX and then have a sourcefile with "$mode objfpc",
  359. this routine will be called to disable m_systemcodepage (to ensure
  360. it's off in case it would have been set on the command line, or
  361. by a previous mode(switch).
  362. In that case, we have to ensure that we don't overwrite
  363. current_settings.sourcecodepage, as that would cancel out the
  364. -FcXXX. This is why we use two separate module switches
  365. (cs_explicit_codepage and cs_system_codepage) for the same setting
  366. (current_settings.sourcecodepage)
  367. }
  368. if m_systemcodepage in current_settings.modeswitches then
  369. begin
  370. { m_systemcodepage gets enabled -> disable any -FcXXX and
  371. "codepage XXX" settings (exclude cs_explicit_codepage), and
  372. overwrite the sourcecode page }
  373. current_settings.sourcecodepage:=DefaultSystemCodePage;
  374. if (current_settings.sourcecodepage<>CP_UTF8) and not cpavailable(current_settings.sourcecodepage) then
  375. begin
  376. Message2(scan_w_unavailable_system_codepage,IntToStr(current_settings.sourcecodepage),IntToStr(default_settings.sourcecodepage));
  377. current_settings.sourcecodepage:=default_settings.sourcecodepage;
  378. end;
  379. exclude(current_settings.moduleswitches,cs_explicit_codepage);
  380. include(current_settings.moduleswitches,cs_system_codepage);
  381. if changeinit then
  382. begin
  383. init_settings.sourcecodepage:=current_settings.sourcecodepage;
  384. exclude(init_settings.moduleswitches,cs_explicit_codepage);
  385. include(init_settings.moduleswitches,cs_system_codepage);
  386. end;
  387. end
  388. else
  389. begin
  390. { m_systemcodepage gets disabled -> reset sourcecodepage only if
  391. cs_explicit_codepage is not set (it may be set in the scenario
  392. where -FcXXX was passed on the command line and then "$mode
  393. fpc" is used, because then the caller of this routine will
  394. set the "$mode fpc" modeswitches (which don't include
  395. m_systemcodepage) and call this routine with m_none).
  396. Or it can happen if -FcXXX was passed, and the sourcefile
  397. contains "$modeswitch systemcodepage-" statement.
  398. Since we unset cs_system_codepage if m_systemcodepage gets
  399. activated, we will revert to the default code page if you
  400. set a source file code page, then enable the systemcode page
  401. and finally disable it again. We don't keep a stack of
  402. settings, by design. The only thing we have to ensure is that
  403. disabling m_systemcodepage if it wasn't on in the first place
  404. doesn't overwrite the sourcecodepage }
  405. exclude(current_settings.moduleswitches,cs_system_codepage);
  406. if not(cs_explicit_codepage in current_settings.moduleswitches) then
  407. current_settings.sourcecodepage:=default_settings.sourcecodepage;
  408. if changeinit then
  409. begin
  410. exclude(init_settings.moduleswitches,cs_system_codepage);
  411. if not(cs_explicit_codepage in init_settings.moduleswitches) then
  412. init_settings.sourcecodepage:=default_settings.sourcecodepage;
  413. end;
  414. end;
  415. end;
  416. {$ifdef i8086}
  417. { enable cs_force_far_calls when m_nested_procvars is enabled }
  418. if switch=m_nested_procvars then
  419. begin
  420. include(current_settings.localswitches,cs_force_far_calls);
  421. if changeinit then
  422. include(init_settings.localswitches,cs_force_far_calls);
  423. end;
  424. {$endif i8086}
  425. end;
  426. Function SetCompileMode(const s:string; changeInit: boolean):boolean;
  427. var
  428. b : boolean;
  429. oldmodeswitches : tmodeswitches;
  430. begin
  431. oldmodeswitches:=current_settings.modeswitches;
  432. b:=true;
  433. if s='DEFAULT' then
  434. current_settings.modeswitches:=fpcmodeswitches
  435. else
  436. if s='DELPHI' then
  437. current_settings.modeswitches:=delphimodeswitches
  438. else
  439. if s='DELPHIUNICODE' then
  440. current_settings.modeswitches:=delphiunicodemodeswitches
  441. else
  442. if s='TP' then
  443. current_settings.modeswitches:=tpmodeswitches
  444. else
  445. if s='FPC' then begin
  446. current_settings.modeswitches:=fpcmodeswitches;
  447. { TODO: enable this for 2.3/2.9 }
  448. // include(current_settings.localswitches, cs_typed_addresses);
  449. end else
  450. if s='OBJFPC' then begin
  451. current_settings.modeswitches:=objfpcmodeswitches;
  452. { TODO: enable this for 2.3/2.9 }
  453. // include(current_settings.localswitches, cs_typed_addresses);
  454. end
  455. {$ifdef gpc_mode}
  456. else if s='GPC' then
  457. current_settings.modeswitches:=gpcmodeswitches
  458. {$endif}
  459. else
  460. if s='MACPAS' then
  461. current_settings.modeswitches:=macmodeswitches
  462. else
  463. if s='ISO' then
  464. current_settings.modeswitches:=isomodeswitches
  465. else
  466. if s='EXTENDEDPASCAL' then
  467. current_settings.modeswitches:=extpasmodeswitches
  468. else
  469. b:=false;
  470. {$ifdef jvm}
  471. { enable final fields by default for the JVM targets }
  472. include(current_settings.modeswitches,m_final_fields);
  473. {$endif jvm}
  474. if b and changeInit then
  475. init_settings.modeswitches := current_settings.modeswitches;
  476. if b then
  477. begin
  478. { resolve all postponed switch changes }
  479. flushpendingswitchesstate;
  480. HandleModeSwitches(m_none,changeinit);
  481. { turn on bitpacking and case checking for mode macpas and iso pascal,
  482. as well as extended pascal }
  483. if ([m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then
  484. begin
  485. include(current_settings.localswitches,cs_bitpacking);
  486. include(current_settings.localswitches,cs_check_all_case_coverage);
  487. if changeinit then
  488. begin
  489. include(init_settings.localswitches,cs_bitpacking);
  490. include(init_settings.localswitches,cs_check_all_case_coverage);
  491. end;
  492. end;
  493. { support goto/label by default in delphi/tp7/mac/iso/extpas modes }
  494. if ([m_delphi,m_tp7,m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then
  495. begin
  496. include(current_settings.moduleswitches,cs_support_goto);
  497. if changeinit then
  498. include(init_settings.moduleswitches,cs_support_goto);
  499. end;
  500. { support pointer math by default in fpc/objfpc modes }
  501. if ([m_fpc,m_objfpc] * current_settings.modeswitches <> []) then
  502. begin
  503. include(current_settings.localswitches,cs_pointermath);
  504. if changeinit then
  505. include(init_settings.localswitches,cs_pointermath);
  506. end
  507. else
  508. begin
  509. exclude(current_settings.localswitches,cs_pointermath);
  510. if changeinit then
  511. exclude(init_settings.localswitches,cs_pointermath);
  512. end;
  513. { Default enum and set packing for delphi/tp7 }
  514. if (m_tp7 in current_settings.modeswitches) or
  515. (m_delphi in current_settings.modeswitches) then
  516. begin
  517. current_settings.packenum:=1;
  518. current_settings.setalloc:=1;
  519. end
  520. else if (m_mac in current_settings.modeswitches) then
  521. { compatible with Metrowerks Pascal }
  522. current_settings.packenum:=2
  523. else
  524. current_settings.packenum:=4;
  525. if changeinit then
  526. begin
  527. init_settings.packenum:=current_settings.packenum;
  528. init_settings.setalloc:=current_settings.setalloc;
  529. end;
  530. {$if defined(i386) or defined(i8086)}
  531. { Default to intel assembler for delphi/tp7 on i386/i8086 }
  532. if (m_delphi in current_settings.modeswitches) or
  533. (m_tp7 in current_settings.modeswitches) then
  534. begin
  535. {$ifdef i8086}
  536. current_settings.asmmode:=asmmode_i8086_intel;
  537. {$else i8086}
  538. current_settings.asmmode:=asmmode_i386_intel;
  539. {$endif i8086}
  540. if changeinit then
  541. init_settings.asmmode:=current_settings.asmmode;
  542. end;
  543. {$endif i386 or i8086}
  544. { Exception support explicitly turned on (mainly for macpas, to }
  545. { compensate for lack of interprocedural goto support) }
  546. if (cs_support_exceptions in current_settings.globalswitches) then
  547. include(current_settings.modeswitches,m_except);
  548. { Default strict string var checking in TP/Delphi modes }
  549. if ([m_delphi,m_tp7] * current_settings.modeswitches <> []) then
  550. begin
  551. include(current_settings.localswitches,cs_strict_var_strings);
  552. if changeinit then
  553. include(init_settings.localswitches,cs_strict_var_strings);
  554. end;
  555. { in delphi mode, excess precision is by default on }
  556. if ([m_delphi] * current_settings.modeswitches <> []) then
  557. begin
  558. include(current_settings.localswitches,cs_excessprecision);
  559. if changeinit then
  560. include(init_settings.localswitches,cs_excessprecision);
  561. end;
  562. {$ifdef i8086}
  563. { Do not force far calls in the TP mode by default, force it in other modes }
  564. if (m_tp7 in current_settings.modeswitches) then
  565. begin
  566. exclude(current_settings.localswitches,cs_force_far_calls);
  567. if changeinit then
  568. exclude(init_settings.localswitches,cs_force_far_calls);
  569. end
  570. else
  571. begin
  572. include(current_settings.localswitches,cs_force_far_calls);
  573. if changeinit then
  574. include(init_settings.localswitches,cs_force_far_calls);
  575. end;
  576. {$endif i8086}
  577. { Undefine old symbol }
  578. if (m_delphi in oldmodeswitches) then
  579. undef_system_macro('FPC_DELPHI')
  580. else if (m_tp7 in oldmodeswitches) then
  581. undef_system_macro('FPC_TP')
  582. else if (m_objfpc in oldmodeswitches) then
  583. undef_system_macro('FPC_OBJFPC')
  584. {$ifdef gpc_mode}
  585. else if (m_gpc in oldmodeswitches) then
  586. undef_system_macro('FPC_GPC')
  587. {$endif}
  588. else if (m_mac in oldmodeswitches) then
  589. undef_system_macro('FPC_MACPAS')
  590. else if (m_iso in oldmodeswitches) then
  591. undef_system_macro('FPC_ISO')
  592. else if (m_extpas in oldmodeswitches) then
  593. undef_system_macro('FPC_EXTENDEDPASCAL');
  594. { define new symbol in delphi,objfpc,tp,gpc,macpas mode }
  595. if (m_delphi in current_settings.modeswitches) then
  596. def_system_macro('FPC_DELPHI')
  597. else if (m_tp7 in current_settings.modeswitches) then
  598. def_system_macro('FPC_TP')
  599. else if (m_objfpc in current_settings.modeswitches) then
  600. def_system_macro('FPC_OBJFPC')
  601. {$ifdef gpc_mode}
  602. else if (m_gpc in current_settings.modeswitches) then
  603. def_system_macro('FPC_GPC')
  604. {$endif}
  605. else if (m_mac in current_settings.modeswitches) then
  606. def_system_macro('FPC_MACPAS')
  607. else if (m_iso in current_settings.modeswitches) then
  608. def_system_macro('FPC_ISO')
  609. else if (m_extpas in current_settings.modeswitches) then
  610. def_system_macro('FPC_EXTENDEDPASCAL');
  611. end;
  612. SetCompileMode:=b;
  613. end;
  614. Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
  615. var
  616. i : tmodeswitch;
  617. doinclude : boolean;
  618. begin
  619. s:=upper(s);
  620. { on/off? }
  621. doinclude:=true;
  622. case s[length(s)] of
  623. '+':
  624. s:=copy(s,1,length(s)-1);
  625. '-':
  626. begin
  627. s:=copy(s,1,length(s)-1);
  628. doinclude:=false;
  629. end;
  630. end;
  631. Result:=false;
  632. for i:=m_class to high(tmodeswitch) do
  633. if s=modeswitchstr[i] then
  634. begin
  635. { Objective-C is currently only supported for Darwin targets }
  636. if doinclude and
  637. (i in [m_objectivec1,m_objectivec2]) and
  638. not(target_info.system in systems_objc_supported) then
  639. begin
  640. Message1(option_unsupported_target_for_feature,'Objective-C');
  641. break;
  642. end;
  643. { Blocks supported? }
  644. if doinclude and
  645. (i = m_blocks) and
  646. not(target_info.system in systems_blocks_supported) then
  647. begin
  648. Message1(option_unsupported_target_for_feature,'Blocks');
  649. break;
  650. end;
  651. if changeInit then
  652. current_settings.modeswitches:=init_settings.modeswitches;
  653. Result:=true;
  654. if doinclude then
  655. begin
  656. include(current_settings.modeswitches,i);
  657. { Objective-C 2.0 support implies 1.0 support }
  658. if (i=m_objectivec2) then
  659. include(current_settings.modeswitches,m_objectivec1);
  660. if (i in [m_objectivec1,m_objectivec2]) then
  661. include(current_settings.modeswitches,m_class);
  662. end
  663. else
  664. begin
  665. exclude(current_settings.modeswitches,i);
  666. { Objective-C 2.0 support implies 1.0 support }
  667. if (i=m_objectivec2) then
  668. exclude(current_settings.modeswitches,m_objectivec1);
  669. if (i in [m_objectivec1,m_objectivec2]) and
  670. ([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then
  671. exclude(current_settings.modeswitches,m_class);
  672. end;
  673. { set other switches depending on changed mode switch }
  674. HandleModeSwitches(i,changeinit);
  675. if changeInit then
  676. init_settings.modeswitches:=current_settings.modeswitches;
  677. break;
  678. end;
  679. end;
  680. procedure SetAppType(NewAppType:tapptype);
  681. begin
  682. {$ifdef i8086}
  683. if (target_info.system in [system_i8086_msdos,system_i8086_embedded]) and (apptype<>NewAppType) then
  684. begin
  685. if NewAppType=app_com then
  686. begin
  687. targetinfos[target_info.system]^.exeext:='.com';
  688. target_info.exeext:='.com';
  689. end
  690. else
  691. begin
  692. targetinfos[target_info.system]^.exeext:='.exe';
  693. target_info.exeext:='.exe';
  694. end;
  695. end;
  696. {$endif i8086}
  697. {$ifdef m68k}
  698. if target_info.system in [system_m68k_atari] then
  699. case NewAppType of
  700. app_cui:
  701. begin
  702. targetinfos[target_info.system]^.exeext:='.ttp';
  703. target_info.exeext:='.ttp';
  704. end;
  705. app_gui:
  706. begin
  707. targetinfos[target_info.system]^.exeext:='.prg';
  708. target_info.exeext:='.prg';
  709. end;
  710. else
  711. ;
  712. end;
  713. {$endif m68k}
  714. if apptype in [app_cui,app_com] then
  715. undef_system_macro('CONSOLE');
  716. apptype:=NewAppType;
  717. if apptype in [app_cui,app_com] then
  718. def_system_macro('CONSOLE');
  719. end;
  720. {*****************************************************************************
  721. Conditional Directives
  722. *****************************************************************************}
  723. procedure dir_else;
  724. begin
  725. current_scanner.elsepreprocstack;
  726. end;
  727. procedure dir_endif;
  728. begin
  729. if (cs_legacyifend in current_settings.localswitches) and
  730. (current_scanner.preprocstack.typ<>pp_ifdef) and (current_scanner.preprocstack.typ<>pp_ifndef) and
  731. not((current_scanner.preprocstack.typ=pp_else) and (current_scanner.preprocstack.iftyp in [pp_ifdef,pp_ifndef])) then
  732. Message(scan_e_unexpected_endif);
  733. current_scanner.poppreprocstack;
  734. end;
  735. procedure dir_ifend;
  736. begin
  737. if (cs_legacyifend in current_settings.localswitches) and
  738. (current_scanner.preprocstack.typ<>pp_elseif) and (current_scanner.preprocstack.typ<>pp_if) and
  739. not((current_scanner.preprocstack.typ=pp_else) and (current_scanner.preprocstack.iftyp in [pp_if,pp_elseif])) then
  740. Message(scan_e_unexpected_ifend);
  741. current_scanner.poppreprocstack;
  742. end;
  743. function isdef(var valuedescr: String): Boolean;
  744. var
  745. hs : string;
  746. begin
  747. current_scanner.skipspace;
  748. hs:=current_scanner.readid;
  749. valuedescr:= hs;
  750. if hs='' then
  751. Message(scan_e_error_in_preproc_expr);
  752. isdef:=defined_macro(hs);
  753. end;
  754. procedure dir_ifdef;
  755. begin
  756. current_scanner.ifpreprocstack(pp_ifdef,@isdef,scan_c_ifdef_found);
  757. end;
  758. function isnotdef(var valuedescr: String): Boolean;
  759. var
  760. hs : string;
  761. begin
  762. current_scanner.skipspace;
  763. hs:=current_scanner.readid;
  764. valuedescr:= hs;
  765. if hs='' then
  766. Message(scan_e_error_in_preproc_expr);
  767. isnotdef:=not defined_macro(hs);
  768. end;
  769. procedure dir_ifndef;
  770. begin
  771. current_scanner.ifpreprocstack(pp_ifndef,@isnotdef,scan_c_ifndef_found);
  772. end;
  773. function opt_check(var valuedescr: String): Boolean;
  774. var
  775. hs : string;
  776. state : char;
  777. begin
  778. opt_check:= false;
  779. current_scanner.skipspace;
  780. hs:=current_scanner.readid;
  781. valuedescr:= hs;
  782. if (length(hs)>1) then
  783. Message1(scan_w_illegal_switch,hs)
  784. else
  785. begin
  786. state:=current_scanner.ReadState;
  787. if state in ['-','+'] then
  788. opt_check:=CheckSwitch(hs[1],state)
  789. else
  790. Message(scan_e_error_in_preproc_expr);
  791. end;
  792. end;
  793. procedure dir_ifopt;
  794. begin
  795. flushpendingswitchesstate;
  796. current_scanner.ifpreprocstack(pp_ifopt,@opt_check,scan_c_ifopt_found);
  797. end;
  798. procedure dir_libprefix;
  799. var
  800. s : string;
  801. begin
  802. current_scanner.skipspace;
  803. if c <> '''' then
  804. Message2(scan_f_syn_expected, '''', c);
  805. s := current_scanner.readquotedstring;
  806. stringdispose(outputprefix);
  807. outputprefix := stringdup(s);
  808. with current_module do
  809. setfilename(paramfn, paramallowoutput);
  810. end;
  811. procedure dir_libsuffix;
  812. var
  813. s : string;
  814. begin
  815. current_scanner.skipspace;
  816. if c <> '''' then
  817. Message2(scan_f_syn_expected, '''', c);
  818. s := current_scanner.readquotedstring;
  819. stringdispose(outputsuffix);
  820. outputsuffix := stringdup(s);
  821. with current_module do
  822. setfilename(paramfn, paramallowoutput);
  823. end;
  824. procedure dir_extension;
  825. var
  826. s : string;
  827. begin
  828. current_scanner.skipspace;
  829. if c <> '''' then
  830. Message2(scan_f_syn_expected, '''', c);
  831. s := current_scanner.readquotedstring;
  832. if OutputFileName='' then
  833. OutputFileName:=InputFileName;
  834. OutputFileName:=ChangeFileExt(OutputFileName,'.'+s);
  835. with current_module do
  836. setfilename(paramfn, paramallowoutput);
  837. end;
  838. {
  839. Compile time expression type check
  840. ----------------------------------
  841. Each subexpression returns its type to the caller, which then can
  842. do type check. Since data types of compile time expressions is
  843. not well defined, the type system does a best effort. The drawback is
  844. that some errors might not be detected.
  845. Instead of returning a particular data type, a set of possible data types
  846. are returned. This way ambigouos types can be handled. For instance a
  847. value of 1 can be both a boolean and and integer.
  848. Booleans
  849. --------
  850. The following forms of boolean values are supported:
  851. * C coded, that is 0 is false, non-zero is true.
  852. * TRUE/FALSE for mac style compile time variables
  853. Thus boolean mac compile time variables are always stored as TRUE/FALSE.
  854. When a compile time expression is evaluated, they are then translated
  855. to C coded booleans (0/1), to simplify for the expression evaluator.
  856. Note that this scheme then also of support mac compile time variables which
  857. are 0/1 but with a boolean meaning.
  858. The TRUE/FALSE format is new from 22 august 2005, but the above scheme
  859. means that units which is not recompiled, and thus stores
  860. compile time variables as the old format (0/1), continue to work.
  861. Short circuit evaluation
  862. ------------------------
  863. For this to work, the part of a compile time expression which is short
  864. circuited, should not be evaluated, while it still should be parsed.
  865. Therefor there is a parameter eval, telling whether evaluation is needed.
  866. In case not, the value returned can be arbitrary.
  867. }
  868. type
  869. { texprvalue }
  870. texprvalue = class
  871. private
  872. { we can't use built-in defs since they
  873. may be not created at the moment }
  874. class var
  875. sintdef,uintdef,booldef,strdef,setdef,realdef: tdef;
  876. class constructor createdefs;
  877. class destructor destroydefs;
  878. public
  879. consttyp: tconsttyp;
  880. value: tconstvalue;
  881. def: tdef;
  882. constructor create_const(c:tconstsym);
  883. constructor create_error;
  884. constructor create_ord(v: Tconstexprint);
  885. constructor create_int(v: int64);
  886. constructor create_uint(v: qword);
  887. constructor create_bool(b: boolean);
  888. constructor create_str(const s: string);
  889. constructor create_set(ns: tnormalset);
  890. constructor create_real(r: bestreal);
  891. class function try_parse_number(const s:string):texprvalue; static;
  892. class function try_parse_real(const s:string):texprvalue; static;
  893. function evaluate(v:texprvalue;op:ttoken):texprvalue;
  894. procedure error(expecteddef, place: string);
  895. function isBoolean: Boolean;
  896. function isInt: Boolean;
  897. function asBool: Boolean;
  898. function asInt: Integer;
  899. function asInt64: Int64;
  900. function asStr: String;
  901. destructor destroy; override;
  902. end;
  903. class constructor texprvalue.createdefs;
  904. begin
  905. { do not use corddef etc here: this code is executed before those
  906. variables are initialised. Since these types are only used for
  907. compile-time evaluation of conditional expressions, it doesn't matter
  908. that we use the base types instead of the cpu-specific ones. }
  909. sintdef:=torddef.create(s64bit,low(int64),high(int64),false);
  910. uintdef:=torddef.create(u64bit,low(qword),high(qword),false);
  911. booldef:=torddef.create(pasbool1,0,1,false);
  912. strdef:=tstringdef.createansi(0,false);
  913. setdef:=tsetdef.create(sintdef,0,255,false);
  914. realdef:=tfloatdef.create(s80real,false);
  915. end;
  916. class destructor texprvalue.destroydefs;
  917. begin
  918. setdef.free;
  919. sintdef.free;
  920. uintdef.free;
  921. booldef.free;
  922. strdef.free;
  923. realdef.free;
  924. end;
  925. constructor texprvalue.create_const(c: tconstsym);
  926. begin
  927. consttyp:=c.consttyp;
  928. def:=c.constdef;
  929. case consttyp of
  930. conststring,
  931. constresourcestring:
  932. begin
  933. value.len:=c.value.len;
  934. getmem(value.valueptr,value.len+1);
  935. move(c.value.valueptr^,value.valueptr^,value.len+1);
  936. end;
  937. constwstring:
  938. begin
  939. initwidestring(value.valueptr);
  940. copywidestring(c.value.valueptr,value.valueptr);
  941. end;
  942. constreal:
  943. begin
  944. new(pbestreal(value.valueptr));
  945. pbestreal(value.valueptr)^:=pbestreal(c.value.valueptr)^;
  946. end;
  947. constset:
  948. begin
  949. new(pnormalset(value.valueptr));
  950. pnormalset(value.valueptr)^:=pnormalset(c.value.valueptr)^;
  951. end;
  952. constguid:
  953. begin
  954. new(pguid(value.valueptr));
  955. pguid(value.valueptr)^:=pguid(c.value.valueptr)^;
  956. end;
  957. else
  958. value:=c.value;
  959. end;
  960. end;
  961. constructor texprvalue.create_error;
  962. begin
  963. fillchar(value,sizeof(value),#0);
  964. consttyp:=constnone;
  965. def:=generrordef;
  966. end;
  967. constructor texprvalue.create_ord(v: Tconstexprint);
  968. begin
  969. fillchar(value,sizeof(value),#0);
  970. consttyp:=constord;
  971. value.valueord:=v;
  972. if v.signed then
  973. def:=sintdef
  974. else
  975. def:=uintdef;
  976. end;
  977. constructor texprvalue.create_int(v: int64);
  978. begin
  979. fillchar(value,sizeof(value),#0);
  980. consttyp:=constord;
  981. value.valueord:=v;
  982. def:=sintdef;
  983. end;
  984. constructor texprvalue.create_uint(v: qword);
  985. begin
  986. fillchar(value,sizeof(value),#0);
  987. consttyp:=constord;
  988. value.valueord:=v;
  989. def:=uintdef;
  990. end;
  991. constructor texprvalue.create_bool(b: boolean);
  992. begin
  993. fillchar(value,sizeof(value),#0);
  994. consttyp:=constord;
  995. value.valueord:=ord(b);
  996. def:=booldef;
  997. end;
  998. constructor texprvalue.create_str(const s: string);
  999. var
  1000. sp: pansichar;
  1001. len: integer;
  1002. begin
  1003. fillchar(value,sizeof(value),#0);
  1004. consttyp:=conststring;
  1005. len:=length(s);
  1006. getmem(sp,len+1);
  1007. move(s[1],sp^,len+1);
  1008. value.valueptr:=sp;
  1009. value.len:=len;
  1010. def:=strdef;
  1011. end;
  1012. constructor texprvalue.create_set(ns: tnormalset);
  1013. begin
  1014. fillchar(value,sizeof(value),#0);
  1015. consttyp:=constset;
  1016. new(pnormalset(value.valueptr));
  1017. pnormalset(value.valueptr)^:=ns;
  1018. def:=setdef;
  1019. end;
  1020. constructor texprvalue.create_real(r: bestreal);
  1021. begin
  1022. fillchar(value,sizeof(value),#0);
  1023. consttyp:=constreal;
  1024. new(pbestreal(value.valueptr));
  1025. pbestreal(value.valueptr)^:=r;
  1026. def:=realdef;
  1027. end;
  1028. class function texprvalue.try_parse_number(const s:string):texprvalue;
  1029. var
  1030. ic: int64;
  1031. qc: qword;
  1032. code: integer;
  1033. begin
  1034. { try int64 }
  1035. val(s,ic,code);
  1036. if code=0 then
  1037. result:=texprvalue.create_int(ic)
  1038. else
  1039. begin
  1040. { try qword }
  1041. val(s,qc,code);
  1042. if code=0 then
  1043. result:=texprvalue.create_uint(qc)
  1044. else
  1045. result:=try_parse_real(s);
  1046. end;
  1047. end;
  1048. class function texprvalue.try_parse_real(const s:string):texprvalue;
  1049. var
  1050. d: bestreal;
  1051. code: integer;
  1052. begin
  1053. val(s,d,code);
  1054. if code=0 then
  1055. result:=texprvalue.create_real(d)
  1056. else
  1057. result:=nil;
  1058. end;
  1059. function texprvalue.evaluate(v:texprvalue;op:ttoken):texprvalue;
  1060. function check_compatible: boolean;
  1061. begin
  1062. result:=(
  1063. (is_ordinal(v.def) or is_fpu(v.def)) and
  1064. (is_ordinal(def) or is_fpu(def))
  1065. ) or
  1066. (is_stringlike(v.def) and is_stringlike(def));
  1067. if not result then
  1068. Message2(type_e_incompatible_types,def.typename,v.def.typename);
  1069. end;
  1070. var
  1071. lv,rv: tconstexprint;
  1072. lvd,rvd: bestreal;
  1073. lvs,rvs: string;
  1074. begin
  1075. case op of
  1076. _OP_IN:
  1077. begin
  1078. if not is_set(v.def) then
  1079. begin
  1080. v.error('Set', 'IN');
  1081. result:=texprvalue.create_error;
  1082. end
  1083. else
  1084. if not is_ordinal(def) then
  1085. begin
  1086. error('Ordinal', 'IN');
  1087. result:=texprvalue.create_error;
  1088. end
  1089. else
  1090. if value.valueord.signed then
  1091. result:=texprvalue.create_bool(value.valueord.svalue in pnormalset(v.value.valueptr)^)
  1092. else
  1093. result:=texprvalue.create_bool(value.valueord.uvalue in pnormalset(v.value.valueptr)^);
  1094. end;
  1095. _OP_NOT:
  1096. begin
  1097. if isBoolean then
  1098. result:=texprvalue.create_bool(not asBool)
  1099. else if is_ordinal(def) then
  1100. begin
  1101. result:=texprvalue.create_ord(value.valueord);
  1102. result.def:=def;
  1103. calc_not_ordvalue(result.value.valueord,result.def);
  1104. end
  1105. else
  1106. begin
  1107. error('Boolean', 'NOT');
  1108. result:=texprvalue.create_error;
  1109. end;
  1110. end;
  1111. _OP_OR:
  1112. begin
  1113. if isBoolean then
  1114. if v.isBoolean then
  1115. result:=texprvalue.create_bool(asBool or v.asBool)
  1116. else
  1117. begin
  1118. v.error('Boolean','OR');
  1119. result:=texprvalue.create_error;
  1120. end
  1121. else if is_ordinal(def) then
  1122. if is_ordinal(v.def) then
  1123. result:=texprvalue.create_ord(value.valueord or v.value.valueord)
  1124. else
  1125. begin
  1126. v.error('Ordinal','OR');
  1127. result:=texprvalue.create_error;
  1128. end
  1129. else
  1130. begin
  1131. error('Boolean','OR');
  1132. result:=texprvalue.create_error;
  1133. end;
  1134. end;
  1135. _OP_XOR:
  1136. begin
  1137. if isBoolean then
  1138. if v.isBoolean then
  1139. result:=texprvalue.create_bool(asBool xor v.asBool)
  1140. else
  1141. begin
  1142. v.error('Boolean','XOR');
  1143. result:=texprvalue.create_error;
  1144. end
  1145. else if is_ordinal(def) then
  1146. if is_ordinal(v.def) then
  1147. result:=texprvalue.create_ord(value.valueord xor v.value.valueord)
  1148. else
  1149. begin
  1150. v.error('Ordinal','XOR');
  1151. result:=texprvalue.create_error;
  1152. end
  1153. else
  1154. begin
  1155. error('Boolean','XOR');
  1156. result:=texprvalue.create_error;
  1157. end;
  1158. end;
  1159. _OP_AND:
  1160. begin
  1161. if isBoolean then
  1162. if v.isBoolean then
  1163. result:=texprvalue.create_bool(asBool and v.asBool)
  1164. else
  1165. begin
  1166. v.error('Boolean','AND');
  1167. result:=texprvalue.create_error;
  1168. end
  1169. else if is_ordinal(def) then
  1170. if is_ordinal(v.def) then
  1171. result:=texprvalue.create_ord(value.valueord and v.value.valueord)
  1172. else
  1173. begin
  1174. v.error('Ordinal','AND');
  1175. result:=texprvalue.create_error;
  1176. end
  1177. else
  1178. begin
  1179. error('Boolean','AND');
  1180. result:=texprvalue.create_error;
  1181. end;
  1182. end;
  1183. _EQ,_NE,_LT,_GT,_GTE,_LTE,_PLUS,_MINUS,_STAR,_SLASH,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR:
  1184. if check_compatible then
  1185. begin
  1186. if (is_ordinal(def) and is_ordinal(v.def)) then
  1187. begin
  1188. lv:=value.valueord;
  1189. rv:=v.value.valueord;
  1190. case op of
  1191. _EQ:
  1192. result:=texprvalue.create_bool(lv=rv);
  1193. _NE:
  1194. result:=texprvalue.create_bool(lv<>rv);
  1195. _LT:
  1196. result:=texprvalue.create_bool(lv<rv);
  1197. _GT:
  1198. result:=texprvalue.create_bool(lv>rv);
  1199. _GTE:
  1200. result:=texprvalue.create_bool(lv>=rv);
  1201. _LTE:
  1202. result:=texprvalue.create_bool(lv<=rv);
  1203. _PLUS:
  1204. result:=texprvalue.create_ord(lv+rv);
  1205. _MINUS:
  1206. result:=texprvalue.create_ord(lv-rv);
  1207. _STAR:
  1208. result:=texprvalue.create_ord(lv*rv);
  1209. _SLASH:
  1210. result:=texprvalue.create_real(lv/rv);
  1211. _OP_DIV:
  1212. result:=texprvalue.create_ord(lv div rv);
  1213. _OP_MOD:
  1214. result:=texprvalue.create_ord(lv mod rv);
  1215. _OP_SHL:
  1216. result:=texprvalue.create_ord(lv shl rv);
  1217. _OP_SHR:
  1218. result:=texprvalue.create_ord(lv shr rv);
  1219. else
  1220. begin
  1221. { actually we should never get here but this avoids a warning }
  1222. Message(parser_e_illegal_expression);
  1223. result:=texprvalue.create_error;
  1224. end;
  1225. end;
  1226. end
  1227. else
  1228. if (is_fpu(def) or is_ordinal(def)) and
  1229. (is_fpu(v.def) or is_ordinal(v.def)) then
  1230. begin
  1231. if is_fpu(def) then
  1232. lvd:=pbestreal(value.valueptr)^
  1233. else
  1234. lvd:=value.valueord;
  1235. if is_fpu(v.def) then
  1236. rvd:=pbestreal(v.value.valueptr)^
  1237. else
  1238. rvd:=v.value.valueord;
  1239. case op of
  1240. _EQ:
  1241. result:=texprvalue.create_bool(lvd=rvd);
  1242. _NE:
  1243. result:=texprvalue.create_bool(lvd<>rvd);
  1244. _LT:
  1245. result:=texprvalue.create_bool(lvd<rvd);
  1246. _GT:
  1247. result:=texprvalue.create_bool(lvd>rvd);
  1248. _GTE:
  1249. result:=texprvalue.create_bool(lvd>=rvd);
  1250. _LTE:
  1251. result:=texprvalue.create_bool(lvd<=rvd);
  1252. _PLUS:
  1253. result:=texprvalue.create_real(lvd+rvd);
  1254. _MINUS:
  1255. result:=texprvalue.create_real(lvd-rvd);
  1256. _STAR:
  1257. result:=texprvalue.create_real(lvd*rvd);
  1258. _SLASH:
  1259. result:=texprvalue.create_real(lvd/rvd);
  1260. else
  1261. begin
  1262. Message(parser_e_illegal_expression);
  1263. result:=texprvalue.create_error;
  1264. end;
  1265. end;
  1266. end
  1267. else
  1268. begin
  1269. lvs:=asStr;
  1270. rvs:=v.asStr;
  1271. case op of
  1272. _EQ:
  1273. result:=texprvalue.create_bool(lvs=rvs);
  1274. _NE:
  1275. result:=texprvalue.create_bool(lvs<>rvs);
  1276. _LT:
  1277. result:=texprvalue.create_bool(lvs<rvs);
  1278. _GT:
  1279. result:=texprvalue.create_bool(lvs>rvs);
  1280. _GTE:
  1281. result:=texprvalue.create_bool(lvs>=rvs);
  1282. _LTE:
  1283. result:=texprvalue.create_bool(lvs<=rvs);
  1284. _PLUS:
  1285. result:=texprvalue.create_str(lvs+rvs);
  1286. else
  1287. begin
  1288. Message(parser_e_illegal_expression);
  1289. result:=texprvalue.create_error;
  1290. end;
  1291. end;
  1292. end;
  1293. end
  1294. else
  1295. result:=texprvalue.create_error;
  1296. else
  1297. result:=texprvalue.create_error;
  1298. end;
  1299. end;
  1300. procedure texprvalue.error(expecteddef, place: string);
  1301. begin
  1302. Message3(scan_e_compile_time_typeerror,
  1303. expecteddef,
  1304. def.typename,
  1305. place
  1306. );
  1307. end;
  1308. function texprvalue.isBoolean: Boolean;
  1309. var
  1310. i: int64;
  1311. begin
  1312. result:=is_boolean(def);
  1313. if not result and is_integer(def) then
  1314. begin
  1315. i:=asInt64;
  1316. result:=(i=0)or(i=1);
  1317. end;
  1318. end;
  1319. function texprvalue.isInt: Boolean;
  1320. begin
  1321. result:=is_integer(def);
  1322. end;
  1323. function texprvalue.asBool: Boolean;
  1324. begin
  1325. result:=value.valueord<>0;
  1326. end;
  1327. function texprvalue.asInt: Integer;
  1328. begin
  1329. result:=value.valueord.svalue;
  1330. end;
  1331. function texprvalue.asInt64: Int64;
  1332. begin
  1333. result:=value.valueord.svalue;
  1334. end;
  1335. function texprvalue.asStr: String;
  1336. var
  1337. b:byte;
  1338. begin
  1339. case consttyp of
  1340. constord:
  1341. result:=tostr(value.valueord);
  1342. conststring,
  1343. constresourcestring:
  1344. SetString(result,pchar(value.valueptr),value.len);
  1345. constreal:
  1346. str(pbestreal(value.valueptr)^,result);
  1347. constset:
  1348. begin
  1349. result:=',';
  1350. for b:=0 to 255 do
  1351. if b in pconstset(value.valueptr)^ then
  1352. result:=result+tostr(b)+',';
  1353. end;
  1354. { error values }
  1355. constnone:
  1356. result:='';
  1357. else
  1358. internalerror(2013112801);
  1359. end;
  1360. end;
  1361. destructor texprvalue.destroy;
  1362. begin
  1363. case consttyp of
  1364. conststring,
  1365. constresourcestring :
  1366. freemem(value.valueptr,value.len+1);
  1367. constwstring :
  1368. donewidestring(pcompilerwidestring(value.valueptr));
  1369. constreal :
  1370. dispose(pbestreal(value.valueptr));
  1371. constset :
  1372. dispose(pnormalset(value.valueptr));
  1373. constguid :
  1374. dispose(pguid(value.valueptr));
  1375. constord,
  1376. { error values }
  1377. constnone:
  1378. ;
  1379. else
  1380. internalerror(2013112802);
  1381. end;
  1382. inherited destroy;
  1383. end;
  1384. const
  1385. preproc_operators=[_EQ,_NE,_LT,_GT,_LTE,_GTE,_MINUS,_PLUS,_STAR,_SLASH,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR,_OP_IN,_OP_AND,_OP_OR,_OP_XOR];
  1386. function preproc_comp_expr:texprvalue;
  1387. function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean):texprvalue; forward;
  1388. procedure preproc_consume(t:ttoken);
  1389. begin
  1390. if t<>current_scanner.preproc_token then
  1391. Message(scan_e_preproc_syntax_error);
  1392. current_scanner.preproc_token:=current_scanner.readpreproc;
  1393. end;
  1394. function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;out tokentoconsume:ttoken):boolean;
  1395. var
  1396. hmodule: tmodule;
  1397. ns:ansistring;
  1398. nssym:tsym;
  1399. begin
  1400. result:=false;
  1401. tokentoconsume:=_ID;
  1402. if assigned(srsym) and (srsym.typ in [unitsym,namespacesym]) then
  1403. begin
  1404. if not(srsym.owner.symtabletype in [staticsymtable,globalsymtable]) then
  1405. internalerror(200501154);
  1406. { only allow unit.symbol access if the name was
  1407. found in the current module
  1408. we can use iscurrentunit because generic specializations does not
  1409. change current_unit variable }
  1410. hmodule:=find_module_from_symtable(srsym.Owner);
  1411. if not Assigned(hmodule) then
  1412. internalerror(201001120);
  1413. if hmodule.unit_index=current_filepos.moduleindex then
  1414. begin
  1415. preproc_consume(_POINT);
  1416. current_scanner.skipspace;
  1417. if srsym.typ=namespacesym then
  1418. begin
  1419. ns:=srsym.name;
  1420. nssym:=srsym;
  1421. while assigned(srsym) and (srsym.typ=namespacesym) do
  1422. begin
  1423. { we have a namespace. the next identifier should be either a namespace or a unit }
  1424. searchsym_in_module(hmodule,ns+'.'+current_scanner.preproc_pattern,srsym,srsymtable);
  1425. if assigned(srsym) and (srsym.typ in [namespacesym,unitsym]) then
  1426. begin
  1427. ns:=ns+'.'+current_scanner.preproc_pattern;
  1428. nssym:=srsym;
  1429. preproc_consume(_ID);
  1430. current_scanner.skipspace;
  1431. preproc_consume(_POINT);
  1432. current_scanner.skipspace;
  1433. end;
  1434. end;
  1435. { check if there is a hidden unit with this pattern in the namespace }
  1436. if not assigned(srsym) and
  1437. assigned(nssym) and (nssym.typ=namespacesym) and assigned(tnamespacesym(nssym).unitsym) then
  1438. srsym:=tnamespacesym(nssym).unitsym;
  1439. if assigned(srsym) and (srsym.typ<>unitsym) then
  1440. internalerror(201108260);
  1441. if not assigned(srsym) then
  1442. begin
  1443. result:=true;
  1444. srsymtable:=nil;
  1445. exit;
  1446. end;
  1447. end;
  1448. case current_scanner.preproc_token of
  1449. _ID:
  1450. { system.char? (char=widechar comes from the implicit
  1451. uuchar unit -> override) }
  1452. if (current_scanner.preproc_pattern='CHAR') and
  1453. (tmodule(tunitsym(srsym).module).globalsymtable=systemunit) then
  1454. begin
  1455. if m_default_unicodestring in current_settings.modeswitches then
  1456. searchsym_in_module(tunitsym(srsym).module,'WIDECHAR',srsym,srsymtable)
  1457. else
  1458. searchsym_in_module(tunitsym(srsym).module,'ANSICHAR',srsym,srsymtable)
  1459. end
  1460. else
  1461. searchsym_in_module(tunitsym(srsym).module,current_scanner.preproc_pattern,srsym,srsymtable);
  1462. _STRING:
  1463. begin
  1464. { system.string? }
  1465. if tmodule(tunitsym(srsym).module).globalsymtable=systemunit then
  1466. begin
  1467. if cs_refcountedstrings in current_settings.localswitches then
  1468. begin
  1469. if m_default_unicodestring in current_settings.modeswitches then
  1470. searchsym_in_module(tunitsym(srsym).module,'UNICODESTRING',srsym,srsymtable)
  1471. else
  1472. searchsym_in_module(tunitsym(srsym).module,'ANSISTRING',srsym,srsymtable)
  1473. end
  1474. else
  1475. searchsym_in_module(tunitsym(srsym).module,'SHORTSTRING',srsym,srsymtable);
  1476. tokentoconsume:=_STRING;
  1477. end;
  1478. end
  1479. else
  1480. ;
  1481. end;
  1482. end
  1483. else
  1484. begin
  1485. srsym:=nil;
  1486. srsymtable:=nil;
  1487. end;
  1488. result:=true;
  1489. end;
  1490. end;
  1491. procedure try_consume_nestedsym(var srsym:tsym;var srsymtable:TSymtable);
  1492. var
  1493. def:tdef;
  1494. tokentoconsume:ttoken;
  1495. found:boolean;
  1496. begin
  1497. found:=try_consume_unitsym(srsym,srsymtable,tokentoconsume);
  1498. if found then
  1499. begin
  1500. preproc_consume(tokentoconsume);
  1501. current_scanner.skipspace;
  1502. end;
  1503. while (current_scanner.preproc_token=_POINT) do
  1504. begin
  1505. if assigned(srsym)and(srsym.typ=typesym) then
  1506. begin
  1507. def:=ttypesym(srsym).typedef;
  1508. if is_class_or_object(def) or is_record(def) or is_java_class_or_interface(def) then
  1509. begin
  1510. preproc_consume(_POINT);
  1511. current_scanner.skipspace;
  1512. if def.typ=objectdef then
  1513. found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,[ssf_search_helper])
  1514. else
  1515. found:=searchsym_in_record(trecorddef(def),current_scanner.preproc_pattern,srsym,srsymtable);
  1516. if not found then
  1517. begin
  1518. Message1(sym_e_id_not_found,current_scanner.preproc_pattern);
  1519. exit;
  1520. end;
  1521. preproc_consume(_ID);
  1522. current_scanner.skipspace;
  1523. end
  1524. else
  1525. begin
  1526. Message(sym_e_type_must_be_rec_or_object_or_class);
  1527. exit;
  1528. end;
  1529. end
  1530. else
  1531. begin
  1532. Message(type_e_type_id_expected);
  1533. exit;
  1534. end;
  1535. end;
  1536. end;
  1537. function preproc_substitutedtoken(const basesearchstr:string;eval:Boolean):texprvalue;
  1538. { Currently this parses identifiers as well as numbers.
  1539. The result from this procedure can either be that the token
  1540. itself is a value, or that it is a compile time variable/macro,
  1541. which then is substituted for another value (for macros
  1542. recursivelly substituted).}
  1543. var
  1544. hs: string;
  1545. mac: tmacro;
  1546. macrocount,
  1547. len: integer;
  1548. foundmacro: boolean;
  1549. searchstr: pshortstring;
  1550. searchstr2store: string;
  1551. begin
  1552. if not eval then
  1553. begin
  1554. result:=texprvalue.create_str(basesearchstr);
  1555. exit;
  1556. end;
  1557. searchstr := @basesearchstr;
  1558. mac:=nil;
  1559. foundmacro:=false;
  1560. { Substitue macros and compiler variables with their content/value.
  1561. For real macros also do recursive substitution. }
  1562. macrocount:=0;
  1563. repeat
  1564. mac:=tmacro(search_macro(searchstr^));
  1565. inc(macrocount);
  1566. if macrocount>max_macro_nesting then
  1567. begin
  1568. Message(scan_w_macro_too_deep);
  1569. break;
  1570. end;
  1571. if assigned(mac) and mac.defined then
  1572. if assigned(mac.buftext) then
  1573. begin
  1574. if mac.buflen>255 then
  1575. begin
  1576. len:=255;
  1577. Message(scan_w_macro_cut_after_255_chars);
  1578. end
  1579. else
  1580. len:=mac.buflen;
  1581. hs[0]:=char(len);
  1582. move(mac.buftext^,hs[1],len);
  1583. searchstr2store:=upcase(hs);
  1584. searchstr:=@searchstr2store;
  1585. mac.is_used:=true;
  1586. foundmacro:=true;
  1587. end
  1588. else
  1589. begin
  1590. Message1(scan_e_error_macro_lacks_value,searchstr^);
  1591. break;
  1592. end
  1593. else
  1594. break;
  1595. if mac.is_compiler_var then
  1596. break;
  1597. until false;
  1598. { At this point, result do contain the value. Do some decoding and
  1599. determine the type.}
  1600. result:=texprvalue.try_parse_number(searchstr^);
  1601. if not assigned(result) then
  1602. begin
  1603. if foundmacro and (searchstr^='FALSE') then
  1604. result:=texprvalue.create_bool(false)
  1605. else if foundmacro and (searchstr^='TRUE') then
  1606. result:=texprvalue.create_bool(true)
  1607. else if (m_mac in current_settings.modeswitches) and
  1608. (not assigned(mac) or not mac.defined) and
  1609. (macrocount = 1) then
  1610. begin
  1611. {Errors in mode mac is issued here. For non macpas modes there is
  1612. more liberty, but the error will eventually be caught at a later stage.}
  1613. Message1(scan_e_error_macro_undefined,searchstr^);
  1614. result:=texprvalue.create_str(searchstr^); { just to have something }
  1615. end
  1616. else
  1617. result:=texprvalue.create_str(searchstr^);
  1618. end;
  1619. end;
  1620. function preproc_factor(eval: Boolean):texprvalue;
  1621. var
  1622. hs,countstr,storedpattern: string;
  1623. mac: tmacro;
  1624. srsym : tsym;
  1625. srsymtable : TSymtable;
  1626. hdef : TDef;
  1627. l : longint;
  1628. hasKlammer: Boolean;
  1629. exprvalue:texprvalue;
  1630. ns:tnormalset;
  1631. begin
  1632. result:=nil;
  1633. hasKlammer:=false;
  1634. if current_scanner.preproc_token=_ID then
  1635. begin
  1636. if current_scanner.preproc_pattern='DEFINED' then
  1637. begin
  1638. preproc_consume(_ID);
  1639. current_scanner.skipspace;
  1640. if current_scanner.preproc_token =_LKLAMMER then
  1641. begin
  1642. preproc_consume(_LKLAMMER);
  1643. current_scanner.skipspace;
  1644. hasKlammer:= true;
  1645. end
  1646. else if (m_mac in current_settings.modeswitches) then
  1647. hasKlammer:= false
  1648. else
  1649. Message(scan_e_error_in_preproc_expr);
  1650. if current_scanner.preproc_token =_ID then
  1651. begin
  1652. hs := current_scanner.preproc_pattern;
  1653. mac := tmacro(search_macro(hs));
  1654. if assigned(mac) and mac.defined then
  1655. begin
  1656. result:=texprvalue.create_bool(true);
  1657. mac.is_used:=true;
  1658. end
  1659. else
  1660. result:=texprvalue.create_bool(false);
  1661. preproc_consume(_ID);
  1662. current_scanner.skipspace;
  1663. end
  1664. else
  1665. Message(scan_e_error_in_preproc_expr);
  1666. if hasKlammer then
  1667. if current_scanner.preproc_token =_RKLAMMER then
  1668. preproc_consume(_RKLAMMER)
  1669. else
  1670. Message(scan_e_error_in_preproc_expr);
  1671. end
  1672. else
  1673. if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='UNDEFINED') then
  1674. begin
  1675. preproc_consume(_ID);
  1676. current_scanner.skipspace;
  1677. if current_scanner.preproc_token =_ID then
  1678. begin
  1679. hs := current_scanner.preproc_pattern;
  1680. mac := tmacro(search_macro(hs));
  1681. if assigned(mac) then
  1682. begin
  1683. result:=texprvalue.create_bool(false);
  1684. mac.is_used:=true;
  1685. end
  1686. else
  1687. result:=texprvalue.create_bool(true);
  1688. preproc_consume(_ID);
  1689. current_scanner.skipspace;
  1690. end
  1691. else
  1692. Message(scan_e_error_in_preproc_expr);
  1693. end
  1694. else
  1695. if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='OPTION') then
  1696. begin
  1697. preproc_consume(_ID);
  1698. current_scanner.skipspace;
  1699. if current_scanner.preproc_token =_LKLAMMER then
  1700. begin
  1701. preproc_consume(_LKLAMMER);
  1702. current_scanner.skipspace;
  1703. end
  1704. else
  1705. Message(scan_e_error_in_preproc_expr);
  1706. if not (current_scanner.preproc_token = _ID) then
  1707. Message(scan_e_error_in_preproc_expr);
  1708. hs:=current_scanner.preproc_pattern;
  1709. if (length(hs) > 1) then
  1710. {This is allowed in Metrowerks Pascal}
  1711. Message(scan_e_error_in_preproc_expr)
  1712. else
  1713. begin
  1714. if CheckSwitch(hs[1],'+') then
  1715. result:=texprvalue.create_bool(true)
  1716. else
  1717. result:=texprvalue.create_bool(false);
  1718. end;
  1719. preproc_consume(_ID);
  1720. current_scanner.skipspace;
  1721. if current_scanner.preproc_token =_RKLAMMER then
  1722. preproc_consume(_RKLAMMER)
  1723. else
  1724. Message(scan_e_error_in_preproc_expr);
  1725. end
  1726. else
  1727. if current_scanner.preproc_pattern='SIZEOF' then
  1728. begin
  1729. preproc_consume(_ID);
  1730. current_scanner.skipspace;
  1731. if current_scanner.preproc_token =_LKLAMMER then
  1732. begin
  1733. preproc_consume(_LKLAMMER);
  1734. current_scanner.skipspace;
  1735. end
  1736. else
  1737. Message(scan_e_preproc_syntax_error);
  1738. storedpattern:=current_scanner.preproc_pattern;
  1739. preproc_consume(_ID);
  1740. current_scanner.skipspace;
  1741. if eval then
  1742. if searchsym(storedpattern,srsym,srsymtable) then
  1743. begin
  1744. try_consume_nestedsym(srsym,srsymtable);
  1745. l:=0;
  1746. if assigned(srsym) then
  1747. case srsym.typ of
  1748. staticvarsym,
  1749. localvarsym,
  1750. paravarsym :
  1751. l:=tabstractvarsym(srsym).getsize;
  1752. typesym:
  1753. l:=ttypesym(srsym).typedef.size;
  1754. else
  1755. Message(scan_e_error_in_preproc_expr);
  1756. end;
  1757. result:=texprvalue.create_int(l);
  1758. end
  1759. else
  1760. Message1(sym_e_id_not_found,storedpattern);
  1761. if current_scanner.preproc_token =_RKLAMMER then
  1762. preproc_consume(_RKLAMMER)
  1763. else
  1764. Message(scan_e_preproc_syntax_error);
  1765. end
  1766. else
  1767. if current_scanner.preproc_pattern='HIGH' then
  1768. begin
  1769. preproc_consume(_ID);
  1770. current_scanner.skipspace;
  1771. if current_scanner.preproc_token =_LKLAMMER then
  1772. begin
  1773. preproc_consume(_LKLAMMER);
  1774. current_scanner.skipspace;
  1775. end
  1776. else
  1777. Message(scan_e_preproc_syntax_error);
  1778. storedpattern:=current_scanner.preproc_pattern;
  1779. preproc_consume(_ID);
  1780. current_scanner.skipspace;
  1781. if eval then
  1782. if searchsym(storedpattern,srsym,srsymtable) then
  1783. begin
  1784. try_consume_nestedsym(srsym,srsymtable);
  1785. hdef:=nil;
  1786. hs:='';
  1787. l:=0;
  1788. if assigned(srsym) then
  1789. case srsym.typ of
  1790. staticvarsym,
  1791. localvarsym,
  1792. paravarsym :
  1793. hdef:=tabstractvarsym(srsym).vardef;
  1794. typesym:
  1795. hdef:=ttypesym(srsym).typedef;
  1796. else
  1797. Message(scan_e_error_in_preproc_expr);
  1798. end;
  1799. if assigned(hdef) then
  1800. begin
  1801. if hdef.typ=setdef then
  1802. hdef:=tsetdef(hdef).elementdef;
  1803. case hdef.typ of
  1804. orddef:
  1805. with torddef(hdef).high do
  1806. if signed then
  1807. result:=texprvalue.create_int(svalue)
  1808. else
  1809. result:=texprvalue.create_uint(uvalue);
  1810. enumdef:
  1811. result:=texprvalue.create_int(tenumdef(hdef).maxval);
  1812. arraydef:
  1813. if is_open_array(hdef) or is_array_of_const(hdef) or is_dynamic_array(hdef) then
  1814. Message(type_e_mismatch)
  1815. else
  1816. result:=texprvalue.create_int(tarraydef(hdef).highrange);
  1817. stringdef:
  1818. if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then
  1819. Message(type_e_mismatch)
  1820. else
  1821. result:=texprvalue.create_int(tstringdef(hdef).len);
  1822. else
  1823. Message(type_e_mismatch);
  1824. end;
  1825. end;
  1826. end
  1827. else
  1828. Message1(sym_e_id_not_found,storedpattern);
  1829. if current_scanner.preproc_token =_RKLAMMER then
  1830. preproc_consume(_RKLAMMER)
  1831. else
  1832. Message(scan_e_preproc_syntax_error);
  1833. end
  1834. else
  1835. if current_scanner.preproc_pattern='DECLARED' then
  1836. begin
  1837. preproc_consume(_ID);
  1838. current_scanner.skipspace;
  1839. if current_scanner.preproc_token =_LKLAMMER then
  1840. begin
  1841. preproc_consume(_LKLAMMER);
  1842. current_scanner.skipspace;
  1843. end
  1844. else
  1845. Message(scan_e_error_in_preproc_expr);
  1846. if current_scanner.preproc_token =_ID then
  1847. begin
  1848. hs := upper(current_scanner.preproc_pattern);
  1849. preproc_consume(_ID);
  1850. current_scanner.skipspace;
  1851. if current_scanner.preproc_token in [_LT,_LSHARPBRACKET] then
  1852. begin
  1853. l:=1;
  1854. preproc_consume(current_scanner.preproc_token);
  1855. current_scanner.skipspace;
  1856. while current_scanner.preproc_token=_COMMA do
  1857. begin
  1858. inc(l);
  1859. preproc_consume(_COMMA);
  1860. current_scanner.skipspace;
  1861. end;
  1862. if not (current_scanner.preproc_token in [_GT,_RSHARPBRACKET]) then
  1863. Message(scan_e_error_in_preproc_expr)
  1864. else
  1865. preproc_consume(current_scanner.preproc_token);
  1866. str(l,countstr);
  1867. hs:=hs+'$'+countstr;
  1868. end
  1869. else
  1870. { special case: <> }
  1871. if current_scanner.preproc_token=_NE then
  1872. begin
  1873. hs:=hs+'$1';
  1874. preproc_consume(_NE);
  1875. end;
  1876. current_scanner.skipspace;
  1877. if searchsym(hs,srsym,srsymtable) then
  1878. begin
  1879. { TSomeGeneric<...> also adds a TSomeGeneric symbol }
  1880. if (sp_generic_dummy in srsym.symoptions) and
  1881. (srsym.typ=typesym) and
  1882. (
  1883. { mode delphi}
  1884. (ttypesym(srsym).typedef.typ in [undefineddef,errordef]) or
  1885. { non-delphi modes }
  1886. (df_generic in ttypesym(srsym).typedef.defoptions)
  1887. ) then
  1888. result:=texprvalue.create_bool(false)
  1889. else
  1890. result:=texprvalue.create_bool(true);
  1891. end
  1892. else
  1893. result:=texprvalue.create_bool(false);
  1894. end
  1895. else
  1896. Message(scan_e_error_in_preproc_expr);
  1897. if current_scanner.preproc_token =_RKLAMMER then
  1898. preproc_consume(_RKLAMMER)
  1899. else
  1900. Message(scan_e_error_in_preproc_expr);
  1901. end
  1902. else
  1903. if current_scanner.preproc_pattern='ORD' then
  1904. begin
  1905. preproc_consume(_ID);
  1906. current_scanner.skipspace;
  1907. if current_scanner.preproc_token =_LKLAMMER then
  1908. begin
  1909. preproc_consume(_LKLAMMER);
  1910. current_scanner.skipspace;
  1911. end
  1912. else
  1913. Message(scan_e_preproc_syntax_error);
  1914. exprvalue:=preproc_factor(eval);
  1915. if eval then
  1916. begin
  1917. if is_ordinal(exprvalue.def) then
  1918. result:=texprvalue.create_int(exprvalue.asInt)
  1919. else
  1920. begin
  1921. exprvalue.error('Ordinal','ORD');
  1922. result:=texprvalue.create_int(0);
  1923. end;
  1924. end
  1925. else
  1926. result:=texprvalue.create_int(0);
  1927. exprvalue.free;
  1928. if current_scanner.preproc_token =_RKLAMMER then
  1929. preproc_consume(_RKLAMMER)
  1930. else
  1931. Message(scan_e_error_in_preproc_expr);
  1932. end
  1933. else
  1934. if current_scanner.preproc_pattern='NOT' then
  1935. begin
  1936. preproc_consume(_ID);
  1937. exprvalue:=preproc_factor(eval);
  1938. if eval then
  1939. result:=exprvalue.evaluate(nil,_OP_NOT)
  1940. else
  1941. result:=texprvalue.create_bool(false); {Just to have something}
  1942. exprvalue.free;
  1943. end
  1944. else
  1945. if (current_scanner.preproc_pattern='TRUE') then
  1946. begin
  1947. result:=texprvalue.create_bool(true);
  1948. preproc_consume(_ID);
  1949. end
  1950. else
  1951. if (current_scanner.preproc_pattern='FALSE') then
  1952. begin
  1953. result:=texprvalue.create_bool(false);
  1954. preproc_consume(_ID);
  1955. end
  1956. else
  1957. begin
  1958. storedpattern:=current_scanner.preproc_pattern;
  1959. preproc_consume(_ID);
  1960. current_scanner.skipspace;
  1961. { first look for a macros/int/float }
  1962. result:=preproc_substitutedtoken(storedpattern,eval);
  1963. if eval and (result.consttyp=conststring) then
  1964. begin
  1965. if searchsym(storedpattern,srsym,srsymtable) then
  1966. begin
  1967. try_consume_nestedsym(srsym,srsymtable);
  1968. if assigned(srsym) then
  1969. case srsym.typ of
  1970. constsym:
  1971. begin
  1972. result.free;
  1973. result:=texprvalue.create_const(tconstsym(srsym));
  1974. end;
  1975. enumsym:
  1976. begin
  1977. result.free;
  1978. result:=texprvalue.create_int(tenumsym(srsym).value);
  1979. end;
  1980. else
  1981. ;
  1982. end;
  1983. end
  1984. end
  1985. { skip id(<expr>) if expression must not be evaluated }
  1986. else if not(eval) and (result.consttyp=conststring) then
  1987. begin
  1988. if current_scanner.preproc_token =_LKLAMMER then
  1989. begin
  1990. preproc_consume(_LKLAMMER);
  1991. current_scanner.skipspace;
  1992. result:=preproc_factor(false);
  1993. if current_scanner.preproc_token =_RKLAMMER then
  1994. preproc_consume(_RKLAMMER)
  1995. else
  1996. Message(scan_e_error_in_preproc_expr);
  1997. end;
  1998. end;
  1999. end
  2000. end
  2001. else if current_scanner.preproc_token =_LKLAMMER then
  2002. begin
  2003. preproc_consume(_LKLAMMER);
  2004. result:=preproc_sub_expr(opcompare,eval);
  2005. preproc_consume(_RKLAMMER);
  2006. end
  2007. else if current_scanner.preproc_token = _LECKKLAMMER then
  2008. begin
  2009. preproc_consume(_LECKKLAMMER);
  2010. ns:=[];
  2011. while current_scanner.preproc_token in [_ID,_INTCONST] do
  2012. begin
  2013. exprvalue:=preproc_factor(eval);
  2014. include(ns,exprvalue.asInt);
  2015. if current_scanner.preproc_token = _COMMA then
  2016. preproc_consume(_COMMA);
  2017. end;
  2018. // TODO Add check of setElemType
  2019. preproc_consume(_RECKKLAMMER);
  2020. result:=texprvalue.create_set(ns);
  2021. end
  2022. else if current_scanner.preproc_token = _INTCONST then
  2023. begin
  2024. result:=texprvalue.try_parse_number(current_scanner.preproc_pattern);
  2025. if not assigned(result) then
  2026. begin
  2027. Message(parser_e_invalid_integer);
  2028. result:=texprvalue.create_int(1);
  2029. end;
  2030. preproc_consume(_INTCONST);
  2031. end
  2032. else if current_scanner.preproc_token = _CSTRING then
  2033. begin
  2034. result:=texprvalue.create_str(current_scanner.preproc_pattern);
  2035. preproc_consume(_CSTRING);
  2036. end
  2037. else if current_scanner.preproc_token = _REALNUMBER then
  2038. begin
  2039. result:=texprvalue.try_parse_real(current_scanner.preproc_pattern);
  2040. if not assigned(result) then
  2041. begin
  2042. Message(parser_e_error_in_real);
  2043. result:=texprvalue.create_real(1.0);
  2044. end;
  2045. preproc_consume(_REALNUMBER);
  2046. end
  2047. else
  2048. Message(scan_e_error_in_preproc_expr);
  2049. if not assigned(result) then
  2050. result:=texprvalue.create_error;
  2051. end;
  2052. function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean): texprvalue;
  2053. var
  2054. hs1,hs2: texprvalue;
  2055. op: ttoken;
  2056. begin
  2057. if pred_level=highest_precedence then
  2058. result:=preproc_factor(eval)
  2059. else
  2060. result:=preproc_sub_expr(succ(pred_level),eval);
  2061. repeat
  2062. op:=current_scanner.preproc_token;
  2063. if (op in preproc_operators) and
  2064. (op in operator_levels[pred_level]) then
  2065. begin
  2066. hs1:=result;
  2067. preproc_consume(op);
  2068. if (op=_OP_OR) and hs1.isBoolean and hs1.asBool then
  2069. begin
  2070. { stop evaluation the rest of expression }
  2071. result:=texprvalue.create_bool(true);
  2072. if pred_level=highest_precedence then
  2073. hs2:=preproc_factor(false)
  2074. else
  2075. hs2:=preproc_sub_expr(succ(pred_level),false);
  2076. end
  2077. else if (op=_OP_AND) and hs1.isBoolean and not hs1.asBool then
  2078. begin
  2079. { stop evaluation the rest of expression }
  2080. result:=texprvalue.create_bool(false);
  2081. if pred_level=highest_precedence then
  2082. hs2:=preproc_factor(false)
  2083. else
  2084. hs2:=preproc_sub_expr(succ(pred_level),false);
  2085. end
  2086. else
  2087. begin
  2088. if pred_level=highest_precedence then
  2089. hs2:=preproc_factor(eval)
  2090. else
  2091. hs2:=preproc_sub_expr(succ(pred_level),eval);
  2092. if eval then
  2093. result:=hs1.evaluate(hs2,op)
  2094. else
  2095. result:=texprvalue.create_bool(false); {Just to have something}
  2096. end;
  2097. hs1.free;
  2098. hs2.free;
  2099. end
  2100. else
  2101. break;
  2102. until false;
  2103. end;
  2104. begin
  2105. current_scanner.in_preproc_comp_expr:=true;
  2106. current_scanner.skipspace;
  2107. { start preproc expression scanner }
  2108. current_scanner.preproc_token:=current_scanner.readpreproc;
  2109. preproc_comp_expr:=preproc_sub_expr(opcompare,true);
  2110. current_scanner.in_preproc_comp_expr:=false;
  2111. end;
  2112. function boolean_compile_time_expr(var valuedescr: string): Boolean;
  2113. var
  2114. hs: texprvalue;
  2115. begin
  2116. hs:=preproc_comp_expr;
  2117. if hs.isBoolean then
  2118. result:=hs.asBool
  2119. else
  2120. begin
  2121. hs.error('Boolean', 'IF or ELSEIF');
  2122. result:=false;
  2123. end;
  2124. valuedescr:=hs.asStr;
  2125. hs.free;
  2126. end;
  2127. procedure dir_if;
  2128. begin
  2129. current_scanner.ifpreprocstack(pp_if,@boolean_compile_time_expr, scan_c_if_found);
  2130. end;
  2131. procedure dir_elseif;
  2132. begin
  2133. current_scanner.elseifpreprocstack(@boolean_compile_time_expr);
  2134. end;
  2135. procedure dir_define_impl(macstyle: boolean);
  2136. var
  2137. hs : string;
  2138. bracketcount : longint;
  2139. mac : tmacro;
  2140. macropos : longint;
  2141. macrobuffer : pmacrobuffer;
  2142. begin
  2143. current_scanner.skipspace;
  2144. hs:=current_scanner.readid;
  2145. if hs='' then
  2146. begin
  2147. Message(scan_e_emptymacroname);
  2148. exit;
  2149. end;
  2150. mac:=tmacro(search_macro(hs));
  2151. if not assigned(mac) or (mac.owner <> current_module.localmacrosymtable) then
  2152. begin
  2153. mac:=tmacro.create(hs);
  2154. mac.defined:=true;
  2155. current_module.localmacrosymtable.insertsym(mac);
  2156. end
  2157. else
  2158. begin
  2159. mac.defined:=true;
  2160. mac.is_compiler_var:=false;
  2161. { delete old definition }
  2162. if assigned(mac.buftext) then
  2163. begin
  2164. freemem(mac.buftext,mac.buflen);
  2165. mac.buftext:=nil;
  2166. end;
  2167. end;
  2168. Message1(parser_c_macro_defined,mac.name);
  2169. mac.is_used:=true;
  2170. if (cs_support_macro in current_settings.moduleswitches) then
  2171. begin
  2172. current_scanner.skipspace;
  2173. if not macstyle then
  2174. begin
  2175. { may be a macro? }
  2176. if c <> ':' then
  2177. exit;
  2178. current_scanner.readchar;
  2179. if c <> '=' then
  2180. exit;
  2181. current_scanner.readchar;
  2182. current_scanner.skipspace;
  2183. end;
  2184. { key words are never substituted }
  2185. if is_keyword(hs) then
  2186. Message(scan_e_keyword_cant_be_a_macro);
  2187. new(macrobuffer);
  2188. macropos:=0;
  2189. { parse macro, brackets are counted so it's possible
  2190. to have a $ifdef etc. in the macro }
  2191. bracketcount:=0;
  2192. repeat
  2193. case c of
  2194. '}' :
  2195. if (bracketcount=0) then
  2196. break
  2197. else
  2198. dec(bracketcount);
  2199. '{' :
  2200. inc(bracketcount);
  2201. #10,#13 :
  2202. current_scanner.linebreak;
  2203. #26 :
  2204. current_scanner.end_of_file;
  2205. end;
  2206. macrobuffer^[macropos]:=c;
  2207. inc(macropos);
  2208. if macropos>=maxmacrolen then
  2209. Message(scan_f_macro_buffer_overflow);
  2210. current_scanner.readchar;
  2211. until false;
  2212. { free buffer of macro ?}
  2213. if assigned(mac.buftext) then
  2214. freemem(mac.buftext,mac.buflen);
  2215. { get new mem }
  2216. getmem(mac.buftext,macropos);
  2217. mac.buflen:=macropos;
  2218. { copy the text }
  2219. move(macrobuffer^,mac.buftext^,macropos);
  2220. dispose(macrobuffer);
  2221. end
  2222. else
  2223. begin
  2224. { check if there is an assignment, then we need to give a
  2225. warning }
  2226. current_scanner.skipspace;
  2227. if c=':' then
  2228. begin
  2229. current_scanner.readchar;
  2230. if c='=' then
  2231. Message(scan_w_macro_support_turned_off);
  2232. end;
  2233. end;
  2234. end;
  2235. procedure dir_define;
  2236. begin
  2237. dir_define_impl(false);
  2238. end;
  2239. procedure dir_definec;
  2240. begin
  2241. dir_define_impl(true);
  2242. end;
  2243. procedure dir_setc;
  2244. var
  2245. hs : string;
  2246. mac : tmacro;
  2247. exprvalue: texprvalue;
  2248. begin
  2249. current_scanner.skipspace;
  2250. hs:=current_scanner.readid;
  2251. mac:=tmacro(search_macro(hs));
  2252. if not assigned(mac) or
  2253. (mac.owner <> current_module.localmacrosymtable) then
  2254. begin
  2255. mac:=tmacro.create(hs);
  2256. mac.defined:=true;
  2257. mac.is_compiler_var:=true;
  2258. current_module.localmacrosymtable.insertsym(mac);
  2259. end
  2260. else
  2261. begin
  2262. mac.defined:=true;
  2263. mac.is_compiler_var:=true;
  2264. { delete old definition }
  2265. if assigned(mac.buftext) then
  2266. begin
  2267. freemem(mac.buftext,mac.buflen);
  2268. mac.buftext:=nil;
  2269. end;
  2270. end;
  2271. Message1(parser_c_macro_defined,mac.name);
  2272. mac.is_used:=true;
  2273. { key words are never substituted }
  2274. if is_keyword(hs) then
  2275. Message(scan_e_keyword_cant_be_a_macro);
  2276. { macro assignment can be both := and = }
  2277. current_scanner.skipspace;
  2278. if c=':' then
  2279. current_scanner.readchar;
  2280. if c='=' then
  2281. begin
  2282. current_scanner.readchar;
  2283. exprvalue:=preproc_comp_expr;
  2284. if not is_boolean(exprvalue.def) and
  2285. not is_integer(exprvalue.def) then
  2286. exprvalue.error('Boolean, Integer', 'SETC');
  2287. hs:=exprvalue.asStr;
  2288. if length(hs) <> 0 then
  2289. begin
  2290. {If we are absolutely shure it is boolean, translate
  2291. to TRUE/FALSE to increase possibility to do future type check}
  2292. if exprvalue.isBoolean then
  2293. begin
  2294. if exprvalue.asBool then
  2295. hs:='TRUE'
  2296. else
  2297. hs:='FALSE';
  2298. end;
  2299. Message2(parser_c_macro_set_to,mac.name,hs);
  2300. { free buffer of macro ?}
  2301. if assigned(mac.buftext) then
  2302. freemem(mac.buftext,mac.buflen);
  2303. { get new mem }
  2304. getmem(mac.buftext,length(hs));
  2305. mac.buflen:=length(hs);
  2306. { copy the text }
  2307. move(hs[1],mac.buftext^,mac.buflen);
  2308. end
  2309. else
  2310. Message(scan_e_preproc_syntax_error);
  2311. exprvalue.free;
  2312. end
  2313. else
  2314. Message(scan_e_preproc_syntax_error);
  2315. end;
  2316. procedure dir_undef;
  2317. var
  2318. hs : string;
  2319. mac : tmacro;
  2320. begin
  2321. current_scanner.skipspace;
  2322. hs:=current_scanner.readid;
  2323. mac:=tmacro(search_macro(hs));
  2324. if not assigned(mac) or
  2325. (mac.owner <> current_module.localmacrosymtable) then
  2326. begin
  2327. mac:=tmacro.create(hs);
  2328. mac.defined:=false;
  2329. current_module.localmacrosymtable.insertsym(mac);
  2330. end
  2331. else
  2332. begin
  2333. mac.defined:=false;
  2334. mac.is_compiler_var:=false;
  2335. { delete old definition }
  2336. if assigned(mac.buftext) then
  2337. begin
  2338. freemem(mac.buftext,mac.buflen);
  2339. mac.buftext:=nil;
  2340. end;
  2341. end;
  2342. Message1(parser_c_macro_undefined,mac.name);
  2343. mac.is_used:=true;
  2344. end;
  2345. procedure dir_include;
  2346. function findincludefile(const path,name:TCmdStr;var foundfile:TCmdStr):boolean;
  2347. var
  2348. found : boolean;
  2349. hpath : TCmdStr;
  2350. begin
  2351. (* look for the include file
  2352. If path was absolute and specified as part of {$I } then
  2353. 1. specified path
  2354. else
  2355. 1. path of current inputfile,current dir
  2356. 2. local includepath
  2357. 3. global includepath
  2358. -- Check mantis #13461 before changing this *)
  2359. found:=false;
  2360. foundfile:='';
  2361. hpath:='';
  2362. if path_absolute(path) then
  2363. begin
  2364. found:=FindFile(name,path,true,foundfile);
  2365. end
  2366. else
  2367. begin
  2368. hpath:=current_scanner.inputfile.path+';'+CurDirRelPath(source_info);
  2369. found:=FindFile(path+name, hpath,true,foundfile);
  2370. if not found then
  2371. found:=current_module.localincludesearchpath.FindFile(path+name,true,foundfile);
  2372. if not found then
  2373. found:=includesearchpath.FindFile(path+name,true,foundfile);
  2374. end;
  2375. result:=found;
  2376. end;
  2377. var
  2378. foundfile : TCmdStr;
  2379. path,
  2380. name,
  2381. hs : tpathstr;
  2382. args : string;
  2383. hp : tinputfile;
  2384. found : boolean;
  2385. macroIsString : boolean;
  2386. begin
  2387. current_scanner.skipspace;
  2388. args:=current_scanner.readcomment;
  2389. hs:=GetToken(args,' ');
  2390. if hs='' then
  2391. exit;
  2392. if (hs[1]='%') then
  2393. begin
  2394. { case insensitive }
  2395. hs:=upper(hs);
  2396. { remove %'s }
  2397. Delete(hs,1,1);
  2398. if hs[length(hs)]='%' then
  2399. Delete(hs,length(hs),1);
  2400. { save old }
  2401. path:=hs;
  2402. { first check for internal macros }
  2403. macroIsString:=true;
  2404. case hs of
  2405. 'TIME':
  2406. if timestr<>'' then
  2407. hs:=timestr
  2408. else
  2409. hs:=gettimestr;
  2410. 'DATE':
  2411. if datestr<>'' then
  2412. hs:=datestr
  2413. else
  2414. hs:=getdatestr;
  2415. 'DATEYEAR':
  2416. begin
  2417. hs:=tostr(startsystime.Year);
  2418. macroIsString:=false;
  2419. end;
  2420. 'DATEMONTH':
  2421. begin
  2422. hs:=tostr(startsystime.Month);
  2423. macroIsString:=false;
  2424. end;
  2425. 'DATEDAY':
  2426. begin
  2427. hs:=tostr(startsystime.Day);
  2428. macroIsString:=false;
  2429. end;
  2430. 'TIMEHOUR':
  2431. begin
  2432. hs:=tostr(startsystime.Hour);
  2433. macroIsString:=false;
  2434. end;
  2435. 'TIMEMINUTE':
  2436. begin
  2437. hs:=tostr(startsystime.Minute);
  2438. macroIsString:=false;
  2439. end;
  2440. 'TIMESECOND':
  2441. begin
  2442. hs:=tostr(startsystime.Second);
  2443. macroIsString:=false;
  2444. end;
  2445. 'FILE':
  2446. hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);
  2447. 'LINE':
  2448. hs:=tostr(current_filepos.line);
  2449. 'LINENUM':
  2450. begin
  2451. hs:=tostr(current_filepos.line);
  2452. macroIsString:=false;
  2453. end;
  2454. 'FPCVERSION':
  2455. hs:=version_string;
  2456. 'FPCDATE':
  2457. hs:=date_string;
  2458. 'FPCTARGET':
  2459. hs:=target_cpu_string;
  2460. 'FPCTARGETCPU':
  2461. hs:=target_cpu_string;
  2462. 'FPCTARGETOS':
  2463. hs:=target_info.shortname;
  2464. 'CURRENTROUTINE':
  2465. hs:=current_procinfo.procdef.procsym.RealName;
  2466. else
  2467. hs:=GetEnvironmentVariable(hs);
  2468. end;
  2469. if hs='' then
  2470. Message1(scan_w_include_env_not_found,path);
  2471. { make it a stringconst }
  2472. if macroIsString then
  2473. hs:=''''+hs+'''';
  2474. current_scanner.substitutemacro(path,@hs[1],length(hs),
  2475. current_scanner.line_no,current_scanner.inputfile.ref_index,false);
  2476. end
  2477. else
  2478. begin
  2479. hs:=FixFileName(hs);
  2480. path:=ExtractFilePath(hs);
  2481. name:=ExtractFileName(hs);
  2482. { Special case for Delphi compatibility: '*' has to be replaced
  2483. by the file name of the current source file. }
  2484. if (length(name)>=1) and
  2485. (name[1]='*') then
  2486. name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);
  2487. { try to find the file }
  2488. found:=findincludefile(path,name,foundfile);
  2489. if (not found) and (ExtractFileExt(name)='') then
  2490. begin
  2491. { try default extensions .inc , .pp and .pas }
  2492. if (not found) then
  2493. found:=findincludefile(path,ChangeFileExt(name,'.inc'),foundfile);
  2494. if (not found) then
  2495. found:=findincludefile(path,ChangeFileExt(name,sourceext),foundfile);
  2496. if (not found) then
  2497. found:=findincludefile(path,ChangeFileExt(name,pasext),foundfile);
  2498. end;
  2499. { if the name ends in dot, try without the dot }
  2500. if (not found) and (ExtractFileExt(name)=ExtensionSeparator) and (Length(name)>=2) then
  2501. found:=findincludefile(path,Copy(name,1,Length(name)-1),foundfile);
  2502. if current_scanner.inputfilecount<max_include_nesting then
  2503. begin
  2504. inc(current_scanner.inputfilecount);
  2505. { we need to reread the current char }
  2506. dec(current_scanner.inputpointer);
  2507. { reset c }
  2508. c:=#0;
  2509. { shutdown current file }
  2510. current_scanner.tempcloseinputfile;
  2511. { load new file }
  2512. hp:=do_openinputfile(foundfile);
  2513. hp.inc_path:=path;
  2514. current_scanner.addfile(hp);
  2515. current_module.sourcefiles.register_file(hp);
  2516. if (not found) then
  2517. Message1(scan_f_cannot_open_includefile,hs);
  2518. if (not current_scanner.openinputfile) then
  2519. Message1(scan_f_cannot_open_includefile,hs);
  2520. Message1(scan_t_start_include_file,current_scanner.inputfile.path+current_scanner.inputfile.name);
  2521. current_scanner.reload;
  2522. end
  2523. else
  2524. Message(scan_f_include_deep_ten);
  2525. end;
  2526. end;
  2527. {*****************************************************************************
  2528. Preprocessor writing
  2529. *****************************************************************************}
  2530. {$ifdef PREPROCWRITE}
  2531. constructor tpreprocfile.create(const fn:string);
  2532. begin
  2533. inherited create;
  2534. { open outputfile }
  2535. assign(f,fn);
  2536. {$push}{$I-}
  2537. rewrite(f);
  2538. {$pop}
  2539. if ioresult<>0 then
  2540. Comment(V_Fatal,'can''t create file '+fn);
  2541. getmem(buf,preprocbufsize);
  2542. settextbuf(f,buf^,preprocbufsize);
  2543. { reset }
  2544. eolfound:=false;
  2545. spacefound:=false;
  2546. end;
  2547. destructor tpreprocfile.destroy;
  2548. begin
  2549. close(f);
  2550. freemem(buf,preprocbufsize);
  2551. end;
  2552. procedure tpreprocfile.add(const s:string);
  2553. begin
  2554. write(f,s);
  2555. end;
  2556. procedure tpreprocfile.addspace;
  2557. begin
  2558. if eolfound then
  2559. begin
  2560. writeln(f,'');
  2561. eolfound:=false;
  2562. spacefound:=false;
  2563. end
  2564. else
  2565. if spacefound then
  2566. begin
  2567. write(f,' ');
  2568. spacefound:=false;
  2569. end;
  2570. end;
  2571. {$endif PREPROCWRITE}
  2572. {*****************************************************************************
  2573. TPreProcStack
  2574. *****************************************************************************}
  2575. constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
  2576. begin
  2577. accept:=a;
  2578. typ:=atyp;
  2579. next:=n;
  2580. end;
  2581. {*****************************************************************************
  2582. TReplayStack
  2583. *****************************************************************************}
  2584. constructor treplaystack.Create(atoken:ttoken;aidtoken:ttoken;
  2585. const aorgpattern,apattern:string;const acstringpattern:ansistring;
  2586. apatternw:pcompilerwidestring;asettings:tsettings;
  2587. atokenbuf:tdynamicarray;change_endian:boolean;anext:treplaystack);
  2588. begin
  2589. token:=atoken;
  2590. idtoken:=aidtoken;
  2591. orgpattern:=aorgpattern;
  2592. pattern:=apattern;
  2593. cstringpattern:=acstringpattern;
  2594. initwidestring(patternw);
  2595. if assigned(apatternw) then
  2596. begin
  2597. setlengthwidestring(patternw,apatternw^.len);
  2598. move(apatternw^.data^,patternw^.data^,apatternw^.len*sizeof(tcompilerwidechar));
  2599. end;
  2600. settings:=asettings;
  2601. tokenbuf:=atokenbuf;
  2602. tokenbuf_needs_swapping:=change_endian;
  2603. next:=anext;
  2604. end;
  2605. destructor treplaystack.destroy;
  2606. begin
  2607. donewidestring(patternw);
  2608. end;
  2609. {*****************************************************************************
  2610. TDirectiveItem
  2611. *****************************************************************************}
  2612. constructor TDirectiveItem.Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  2613. begin
  2614. inherited Create(AList,n);
  2615. is_conditional:=false;
  2616. proc:=p;
  2617. end;
  2618. constructor TDirectiveItem.CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
  2619. begin
  2620. inherited Create(AList,n);
  2621. is_conditional:=true;
  2622. proc:=p;
  2623. end;
  2624. {****************************************************************************
  2625. TSCANNERFILE
  2626. ****************************************************************************}
  2627. constructor tscannerfile.create(const fn:string; is_macro: boolean = false);
  2628. begin
  2629. inputfile:=do_openinputfile(fn);
  2630. if is_macro then
  2631. inputfile.is_macro:=true;
  2632. if assigned(current_module) then
  2633. current_module.sourcefiles.register_file(inputfile);
  2634. { reset localinput }
  2635. c:=#0;
  2636. inputbuffer:=nil;
  2637. inputpointer:=nil;
  2638. inputstart:=0;
  2639. { reset scanner }
  2640. preprocstack:=nil;
  2641. replaystack:=nil;
  2642. comment_level:=0;
  2643. yylexcount:=0;
  2644. block_type:=bt_general;
  2645. line_no:=0;
  2646. lastlinepos:=0;
  2647. lasttokenpos:=0;
  2648. nexttokenpos:=0;
  2649. lasttoken:=NOTOKEN;
  2650. nexttoken:=NOTOKEN;
  2651. ignoredirectives:=TFPHashList.Create;
  2652. change_endian_for_replay:=false;
  2653. end;
  2654. procedure tscannerfile.firstfile;
  2655. begin
  2656. { load block }
  2657. if not openinputfile then
  2658. Message1(scan_f_cannot_open_input,inputfile.name);
  2659. reload;
  2660. end;
  2661. destructor tscannerfile.destroy;
  2662. begin
  2663. if assigned(current_module) and
  2664. (current_module.state=ms_compiled) and
  2665. (status.errorcount=0) then
  2666. checkpreprocstack
  2667. else
  2668. begin
  2669. while assigned(preprocstack) do
  2670. poppreprocstack;
  2671. end;
  2672. while assigned(replaystack) do
  2673. popreplaystack;
  2674. if not inputfile.closed then
  2675. closeinputfile;
  2676. if inputfile.is_macro then
  2677. inputfile.free;
  2678. ignoredirectives.free;
  2679. end;
  2680. function tscannerfile.openinputfile:boolean;
  2681. begin
  2682. openinputfile:=inputfile.open;
  2683. { load buffer }
  2684. inputbuffer:=inputfile.buf;
  2685. inputpointer:=inputfile.buf;
  2686. inputstart:=inputfile.bufstart;
  2687. { line }
  2688. line_no:=0;
  2689. lastlinepos:=0;
  2690. lasttokenpos:=0;
  2691. nexttokenpos:=0;
  2692. end;
  2693. procedure tscannerfile.closeinputfile;
  2694. begin
  2695. inputfile.close;
  2696. { reset buffer }
  2697. inputbuffer:=nil;
  2698. inputpointer:=nil;
  2699. inputstart:=0;
  2700. { reset line }
  2701. line_no:=0;
  2702. lastlinepos:=0;
  2703. lasttokenpos:=0;
  2704. nexttokenpos:=0;
  2705. end;
  2706. function tscannerfile.tempopeninputfile:boolean;
  2707. begin
  2708. tempopeninputfile:=false;
  2709. if inputfile.is_macro then
  2710. exit;
  2711. tempopeninputfile:=inputfile.tempopen;
  2712. { reload buffer }
  2713. inputbuffer:=inputfile.buf;
  2714. inputpointer:=inputfile.buf;
  2715. inputstart:=inputfile.bufstart;
  2716. end;
  2717. procedure tscannerfile.tempcloseinputfile;
  2718. begin
  2719. if inputfile.closed or inputfile.is_macro then
  2720. exit;
  2721. inputfile.setpos(inputstart+(inputpointer-inputbuffer));
  2722. inputfile.tempclose;
  2723. { reset buffer }
  2724. inputbuffer:=nil;
  2725. inputpointer:=nil;
  2726. inputstart:=0;
  2727. end;
  2728. procedure tscannerfile.saveinputfile;
  2729. begin
  2730. inputfile.saveinputpointer:=inputpointer;
  2731. inputfile.savelastlinepos:=lastlinepos;
  2732. inputfile.saveline_no:=line_no;
  2733. end;
  2734. procedure tscannerfile.restoreinputfile;
  2735. begin
  2736. inputbuffer:=inputfile.buf;
  2737. inputpointer:=inputfile.saveinputpointer;
  2738. lastlinepos:=inputfile.savelastlinepos;
  2739. line_no:=inputfile.saveline_no;
  2740. if not inputfile.is_macro then
  2741. parser_current_file:=inputfile.name;
  2742. end;
  2743. procedure tscannerfile.nextfile;
  2744. var
  2745. to_dispose : tinputfile;
  2746. begin
  2747. if assigned(inputfile.next) then
  2748. begin
  2749. if inputfile.is_macro then
  2750. begin
  2751. to_dispose:=inputfile;
  2752. dec(macro_nesting_depth);
  2753. end
  2754. else
  2755. begin
  2756. to_dispose:=nil;
  2757. dec(inputfilecount);
  2758. end;
  2759. { we can allways close the file, no ? }
  2760. inputfile.close;
  2761. inputfile:=inputfile.next;
  2762. if assigned(to_dispose) then
  2763. to_dispose.free;
  2764. restoreinputfile;
  2765. end;
  2766. end;
  2767. procedure tscannerfile.startrecordtokens(buf:tdynamicarray);
  2768. begin
  2769. if not assigned(buf) then
  2770. internalerror(200511172);
  2771. if assigned(recordtokenbuf) then
  2772. internalerror(200511173);
  2773. recordtokenbuf:=buf;
  2774. fillchar(last_settings,sizeof(last_settings),0);
  2775. last_message:=nil;
  2776. fillchar(last_filepos,sizeof(last_filepos),0);
  2777. end;
  2778. procedure tscannerfile.stoprecordtokens;
  2779. begin
  2780. if not assigned(recordtokenbuf) then
  2781. internalerror(200511174);
  2782. recordtokenbuf:=nil;
  2783. end;
  2784. function tscannerfile.is_recording_tokens: boolean;
  2785. begin
  2786. result:=assigned(recordtokenbuf);
  2787. end;
  2788. procedure tscannerfile.writetoken(t : ttoken);
  2789. var
  2790. b : byte;
  2791. begin
  2792. if ord(t)>$7f then
  2793. begin
  2794. b:=(ord(t) shr 8) or $80;
  2795. recordtokenbuf.write(b,1);
  2796. end;
  2797. b:=ord(t) and $ff;
  2798. recordtokenbuf.write(b,1);
  2799. end;
  2800. procedure tscannerfile.tokenwritesizeint(val : asizeint);
  2801. begin
  2802. recordtokenbuf.write(val,sizeof(asizeint));
  2803. end;
  2804. procedure tscannerfile.tokenwritelongint(val : longint);
  2805. begin
  2806. recordtokenbuf.write(val,sizeof(longint));
  2807. end;
  2808. procedure tscannerfile.tokenwriteshortint(val : shortint);
  2809. begin
  2810. recordtokenbuf.write(val,sizeof(shortint));
  2811. end;
  2812. procedure tscannerfile.tokenwriteword(val : word);
  2813. begin
  2814. recordtokenbuf.write(val,sizeof(word));
  2815. end;
  2816. procedure tscannerfile.tokenwritelongword(val : longword);
  2817. begin
  2818. recordtokenbuf.write(val,sizeof(longword));
  2819. end;
  2820. function tscannerfile.tokenreadsizeint : asizeint;
  2821. var
  2822. val : asizeint;
  2823. begin
  2824. replaytokenbuf.read(val,sizeof(asizeint));
  2825. if change_endian_for_replay then
  2826. val:=swapendian(val);
  2827. result:=val;
  2828. end;
  2829. function tscannerfile.tokenreadlongword : longword;
  2830. var
  2831. val : longword;
  2832. begin
  2833. replaytokenbuf.read(val,sizeof(longword));
  2834. if change_endian_for_replay then
  2835. val:=swapendian(val);
  2836. result:=val;
  2837. end;
  2838. function tscannerfile.tokenreadlongint : longint;
  2839. var
  2840. val : longint;
  2841. begin
  2842. replaytokenbuf.read(val,sizeof(longint));
  2843. if change_endian_for_replay then
  2844. val:=swapendian(val);
  2845. result:=val;
  2846. end;
  2847. function tscannerfile.tokenreadshortint : shortint;
  2848. var
  2849. val : shortint;
  2850. begin
  2851. replaytokenbuf.read(val,sizeof(shortint));
  2852. result:=val;
  2853. end;
  2854. function tscannerfile.tokenreadbyte : byte;
  2855. var
  2856. val : byte;
  2857. begin
  2858. replaytokenbuf.read(val,sizeof(byte));
  2859. result:=val;
  2860. end;
  2861. function tscannerfile.tokenreadsmallint : smallint;
  2862. var
  2863. val : smallint;
  2864. begin
  2865. replaytokenbuf.read(val,sizeof(smallint));
  2866. if change_endian_for_replay then
  2867. val:=swapendian(val);
  2868. result:=val;
  2869. end;
  2870. function tscannerfile.tokenreadword : word;
  2871. var
  2872. val : word;
  2873. begin
  2874. replaytokenbuf.read(val,sizeof(word));
  2875. if change_endian_for_replay then
  2876. val:=swapendian(val);
  2877. result:=val;
  2878. end;
  2879. function tscannerfile.tokenreadenum(size : longint) : longword;
  2880. begin
  2881. if size=1 then
  2882. result:=tokenreadbyte
  2883. else if size=2 then
  2884. result:=tokenreadword
  2885. else if size=4 then
  2886. result:=tokenreadlongword
  2887. else
  2888. internalerror(2013112901);
  2889. end;
  2890. procedure tscannerfile.tokenreadset(var b;size : longint);
  2891. var
  2892. i : longint;
  2893. begin
  2894. replaytokenbuf.read(b,size);
  2895. if change_endian_for_replay then
  2896. for i:=0 to size-1 do
  2897. Pbyte(@b)[i]:=reverse_byte(Pbyte(@b)[i]);
  2898. end;
  2899. procedure tscannerfile.tokenwriteenum(var b;size : longint);
  2900. begin
  2901. recordtokenbuf.write(b,size);
  2902. end;
  2903. procedure tscannerfile.tokenwriteset(var b;size : longint);
  2904. begin
  2905. recordtokenbuf.write(b,size);
  2906. end;
  2907. procedure tscannerfile.tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
  2908. { This procedure
  2909. needs to be changed whenever
  2910. globals.tsettings type is changed,
  2911. the problem is that no error will appear
  2912. before tests with generics are tested. PM }
  2913. var
  2914. startpos, endpos : longword;
  2915. begin
  2916. { WARNING all those fields need to be in the correct
  2917. order otherwise cross_endian PPU reading will fail }
  2918. startpos:=replaytokenbuf.pos;
  2919. with asettings do
  2920. begin
  2921. alignment.procalign:=tokenreadlongint;
  2922. alignment.loopalign:=tokenreadlongint;
  2923. alignment.jumpalign:=tokenreadlongint;
  2924. alignment.jumpalignskipmax:=tokenreadlongint;
  2925. alignment.coalescealign:=tokenreadlongint;
  2926. alignment.coalescealignskipmax:=tokenreadlongint;
  2927. alignment.constalignmin:=tokenreadlongint;
  2928. alignment.constalignmax:=tokenreadlongint;
  2929. alignment.varalignmin:=tokenreadlongint;
  2930. alignment.varalignmax:=tokenreadlongint;
  2931. alignment.localalignmin:=tokenreadlongint;
  2932. alignment.localalignmax:=tokenreadlongint;
  2933. alignment.recordalignmin:=tokenreadlongint;
  2934. alignment.recordalignmax:=tokenreadlongint;
  2935. alignment.maxCrecordalign:=tokenreadlongint;
  2936. tokenreadset(globalswitches,sizeof(globalswitches));
  2937. tokenreadset(targetswitches,sizeof(targetswitches));
  2938. tokenreadset(moduleswitches,sizeof(moduleswitches));
  2939. tokenreadset(localswitches,sizeof(localswitches));
  2940. tokenreadset(modeswitches,sizeof(modeswitches));
  2941. tokenreadset(optimizerswitches,sizeof(optimizerswitches));
  2942. tokenreadset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
  2943. tokenreadset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
  2944. tokenreadset(debugswitches,sizeof(debugswitches));
  2945. { 0: old behaviour for sets <=256 elements
  2946. >0: round to this size }
  2947. setalloc:=tokenreadshortint;
  2948. packenum:=tokenreadshortint;
  2949. packrecords:=tokenreadshortint;
  2950. maxfpuregisters:=tokenreadshortint;
  2951. cputype:=tcputype(tokenreadenum(sizeof(tcputype)));
  2952. optimizecputype:=tcputype(tokenreadenum(sizeof(tcputype)));
  2953. fputype:=tfputype(tokenreadenum(sizeof(tfputype)));
  2954. asmmode:=tasmmode(tokenreadenum(sizeof(tasmmode)));
  2955. interfacetype:=tinterfacetypes(tokenreadenum(sizeof(tinterfacetypes)));
  2956. defproccall:=tproccalloption(tokenreadenum(sizeof(tproccalloption)));
  2957. { tstringencoding is word type,
  2958. thus this should be OK here }
  2959. sourcecodepage:=tstringEncoding(tokenreadword);
  2960. minfpconstprec:=tfloattype(tokenreadenum(sizeof(tfloattype)));
  2961. disabledircache:=boolean(tokenreadbyte);
  2962. tlsmodel:=ttlsmodel(tokenreadenum(sizeof(ttlsmodel)));
  2963. { TH: Since the field was conditional originally, it was not stored in PPUs. }
  2964. { While adding ControllerSupport constant, I decided not to store ct_none }
  2965. { on targets not supporting controllers, but this might be changed here and }
  2966. { in tokenwritesettings in the future to unify the PPU structure and handling }
  2967. { of this field in the compiler. }
  2968. {$PUSH}
  2969. {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)
  2970. if ControllerSupport then
  2971. controllertype:=tcontrollertype(tokenreadenum(sizeof(tcontrollertype)))
  2972. else
  2973. ControllerType:=ct_none;
  2974. {$POP}
  2975. endpos:=replaytokenbuf.pos;
  2976. if endpos-startpos<>expected_size then
  2977. Comment(V_Error,'Wrong size of Settings read-in');
  2978. end;
  2979. end;
  2980. procedure tscannerfile.tokenwritesettings(var asettings : tsettings; var size : asizeint);
  2981. { This procedure
  2982. needs to be changed whenever
  2983. globals.tsettings type is changed,
  2984. the problem is that no error will appear
  2985. before tests with generics are tested. PM }
  2986. var
  2987. sizepos, startpos, endpos : longword;
  2988. begin
  2989. { WARNING all those fields need to be in the correct
  2990. order otherwise cross_endian PPU reading will fail }
  2991. sizepos:=recordtokenbuf.pos;
  2992. size:=0;
  2993. tokenwritesizeint(size);
  2994. startpos:=recordtokenbuf.pos;
  2995. with asettings do
  2996. begin
  2997. tokenwritelongint(alignment.procalign);
  2998. tokenwritelongint(alignment.loopalign);
  2999. tokenwritelongint(alignment.jumpalign);
  3000. tokenwritelongint(alignment.jumpalignskipmax);
  3001. tokenwritelongint(alignment.coalescealign);
  3002. tokenwritelongint(alignment.coalescealignskipmax);
  3003. tokenwritelongint(alignment.constalignmin);
  3004. tokenwritelongint(alignment.constalignmax);
  3005. tokenwritelongint(alignment.varalignmin);
  3006. tokenwritelongint(alignment.varalignmax);
  3007. tokenwritelongint(alignment.localalignmin);
  3008. tokenwritelongint(alignment.localalignmax);
  3009. tokenwritelongint(alignment.recordalignmin);
  3010. tokenwritelongint(alignment.recordalignmax);
  3011. tokenwritelongint(alignment.maxCrecordalign);
  3012. tokenwriteset(globalswitches,sizeof(globalswitches));
  3013. tokenwriteset(targetswitches,sizeof(targetswitches));
  3014. tokenwriteset(moduleswitches,sizeof(moduleswitches));
  3015. tokenwriteset(localswitches,sizeof(localswitches));
  3016. tokenwriteset(modeswitches,sizeof(modeswitches));
  3017. tokenwriteset(optimizerswitches,sizeof(optimizerswitches));
  3018. tokenwriteset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
  3019. tokenwriteset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
  3020. tokenwriteset(debugswitches,sizeof(debugswitches));
  3021. { 0: old behaviour for sets <=256 elements
  3022. >0: round to this size }
  3023. tokenwriteshortint(setalloc);
  3024. tokenwriteshortint(packenum);
  3025. tokenwriteshortint(packrecords);
  3026. tokenwriteshortint(maxfpuregisters);
  3027. tokenwriteenum(cputype,sizeof(tcputype));
  3028. tokenwriteenum(optimizecputype,sizeof(tcputype));
  3029. tokenwriteenum(fputype,sizeof(tfputype));
  3030. tokenwriteenum(asmmode,sizeof(tasmmode));
  3031. tokenwriteenum(interfacetype,sizeof(tinterfacetypes));
  3032. tokenwriteenum(defproccall,sizeof(tproccalloption));
  3033. { tstringencoding is word type,
  3034. thus this should be OK here }
  3035. tokenwriteword(sourcecodepage);
  3036. tokenwriteenum(minfpconstprec,sizeof(tfloattype));
  3037. recordtokenbuf.write(byte(disabledircache),1);
  3038. tokenwriteenum(tlsmodel,sizeof(tlsmodel));
  3039. { TH: See note about controllertype field in tokenreadsettings. }
  3040. {$PUSH}
  3041. {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)
  3042. if ControllerSupport then
  3043. tokenwriteenum(controllertype,sizeof(tcontrollertype));
  3044. {$POP}
  3045. endpos:=recordtokenbuf.pos;
  3046. size:=endpos-startpos;
  3047. recordtokenbuf.seek(sizepos);
  3048. tokenwritesizeint(size);
  3049. recordtokenbuf.seek(endpos);
  3050. end;
  3051. end;
  3052. procedure tscannerfile.recordtoken;
  3053. var
  3054. t : ttoken;
  3055. s : tspecialgenerictoken;
  3056. len,msgnb,copy_size : asizeint;
  3057. val : longint;
  3058. b : byte;
  3059. pmsg : pmessagestaterecord;
  3060. begin
  3061. if not assigned(recordtokenbuf) then
  3062. internalerror(200511176);
  3063. t:=_GENERICSPECIALTOKEN;
  3064. { settings changed? }
  3065. { last field pmessage is handled separately below in
  3066. ST_LOADMESSAGES }
  3067. if CompareByte(current_settings,last_settings,
  3068. sizeof(current_settings)-sizeof(pointer))<>0 then
  3069. begin
  3070. { use a special token to record it }
  3071. s:=ST_LOADSETTINGS;
  3072. writetoken(t);
  3073. recordtokenbuf.write(s,1);
  3074. copy_size:=sizeof(current_settings)-sizeof(pointer);
  3075. tokenwritesettings(current_settings,copy_size);
  3076. last_settings:=current_settings;
  3077. end;
  3078. if current_settings.pmessage<>last_message then
  3079. begin
  3080. { use a special token to record it }
  3081. s:=ST_LOADMESSAGES;
  3082. writetoken(t);
  3083. recordtokenbuf.write(s,1);
  3084. msgnb:=0;
  3085. pmsg:=current_settings.pmessage;
  3086. while assigned(pmsg) do
  3087. begin
  3088. if msgnb=high(asizeint) then
  3089. { Too many messages }
  3090. internalerror(2011090401);
  3091. inc(msgnb);
  3092. pmsg:=pmsg^.next;
  3093. end;
  3094. tokenwritesizeint(msgnb);
  3095. pmsg:=current_settings.pmessage;
  3096. while assigned(pmsg) do
  3097. begin
  3098. { What about endianess here?}
  3099. { SB: this is handled by tokenreadlongint }
  3100. val:=pmsg^.value;
  3101. tokenwritelongint(val);
  3102. val:=ord(pmsg^.state);
  3103. tokenwritelongint(val);
  3104. pmsg:=pmsg^.next;
  3105. end;
  3106. last_message:=current_settings.pmessage;
  3107. end;
  3108. { file pos changes? }
  3109. if current_tokenpos.fileindex<>last_filepos.fileindex then
  3110. begin
  3111. s:=ST_FILEINDEX;
  3112. writetoken(t);
  3113. recordtokenbuf.write(s,1);
  3114. tokenwriteword(current_tokenpos.fileindex);
  3115. last_filepos.fileindex:=current_tokenpos.fileindex;
  3116. last_filepos.line:=0;
  3117. end;
  3118. if current_tokenpos.line<>last_filepos.line then
  3119. begin
  3120. s:=ST_LINE;
  3121. writetoken(t);
  3122. recordtokenbuf.write(s,1);
  3123. tokenwritelongint(current_tokenpos.line);
  3124. last_filepos.line:=current_tokenpos.line;
  3125. last_filepos.column:=0;
  3126. end;
  3127. if current_tokenpos.column<>last_filepos.column then
  3128. begin
  3129. s:=ST_COLUMN;
  3130. writetoken(t);
  3131. { can the column be written packed? }
  3132. if current_tokenpos.column<$80 then
  3133. begin
  3134. b:=$80 or current_tokenpos.column;
  3135. recordtokenbuf.write(b,1);
  3136. end
  3137. else
  3138. begin
  3139. recordtokenbuf.write(s,1);
  3140. tokenwriteword(current_tokenpos.column);
  3141. end;
  3142. last_filepos.column:=current_tokenpos.column;
  3143. end;
  3144. writetoken(token);
  3145. if token<>_GENERICSPECIALTOKEN then
  3146. writetoken(idtoken);
  3147. case token of
  3148. _CWCHAR,
  3149. _CWSTRING :
  3150. begin
  3151. tokenwritesizeint(patternw^.len);
  3152. if patternw^.len>0 then
  3153. recordtokenbuf.write(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
  3154. end;
  3155. _CSTRING:
  3156. begin
  3157. len:=length(cstringpattern);
  3158. tokenwritesizeint(len);
  3159. if len>0 then
  3160. recordtokenbuf.write(cstringpattern[1],len);
  3161. end;
  3162. _CCHAR,
  3163. _INTCONST,
  3164. _REALNUMBER :
  3165. begin
  3166. { pexpr.pas messes with pattern in case of negative integer consts,
  3167. see around line 2562 the comment of JM; remove the - before recording it
  3168. (FK)
  3169. }
  3170. if (token=_INTCONST) and (pattern[1]='-') then
  3171. delete(pattern,1,1);
  3172. recordtokenbuf.write(pattern[0],1);
  3173. recordtokenbuf.write(pattern[1],length(pattern));
  3174. end;
  3175. _ID :
  3176. begin
  3177. recordtokenbuf.write(orgpattern[0],1);
  3178. recordtokenbuf.write(orgpattern[1],length(orgpattern));
  3179. end;
  3180. else
  3181. ;
  3182. end;
  3183. end;
  3184. procedure tscannerfile.startreplaytokens(buf:tdynamicarray; change_endian:boolean);
  3185. begin
  3186. if not assigned(buf) then
  3187. internalerror(200511175);
  3188. { save current scanner state }
  3189. replaystack:=treplaystack.create(token,idtoken,orgpattern,pattern,
  3190. cstringpattern,patternw,current_settings,replaytokenbuf,change_endian_for_replay,replaystack);
  3191. if assigned(inputpointer) then
  3192. dec(inputpointer);
  3193. { install buffer }
  3194. replaytokenbuf:=buf;
  3195. { Initialize value of change_endian_for_replay variable }
  3196. change_endian_for_replay:=change_endian;
  3197. { reload next token }
  3198. replaytokenbuf.seek(0);
  3199. replaytoken;
  3200. end;
  3201. function tscannerfile.readtoken: ttoken;
  3202. var
  3203. b,b2 : byte;
  3204. begin
  3205. replaytokenbuf.read(b,1);
  3206. if (b and $80)<>0 then
  3207. begin
  3208. replaytokenbuf.read(b2,1);
  3209. result:=ttoken(((b and $7f) shl 8) or b2);
  3210. end
  3211. else
  3212. result:=ttoken(b);
  3213. end;
  3214. procedure tscannerfile.replaytoken;
  3215. var
  3216. wlen,mesgnb,copy_size : asizeint;
  3217. specialtoken : tspecialgenerictoken;
  3218. i : byte;
  3219. pmsg,prevmsg : pmessagestaterecord;
  3220. begin
  3221. if not assigned(replaytokenbuf) then
  3222. internalerror(200511177);
  3223. { End of replay buffer? Then load the next char from the file again }
  3224. if replaytokenbuf.pos>=replaytokenbuf.size then
  3225. begin
  3226. token:=replaystack.token;
  3227. idtoken:=replaystack.idtoken;
  3228. pattern:=replaystack.pattern;
  3229. orgpattern:=replaystack.orgpattern;
  3230. setlengthwidestring(patternw,replaystack.patternw^.len);
  3231. move(replaystack.patternw^.data^,patternw^.data^,replaystack.patternw^.len*sizeof(tcompilerwidechar));
  3232. cstringpattern:=replaystack.cstringpattern;
  3233. replaytokenbuf:=replaystack.tokenbuf;
  3234. change_endian_for_replay:=replaystack.tokenbuf_needs_swapping;
  3235. { restore compiler settings }
  3236. current_settings:=replaystack.settings;
  3237. popreplaystack;
  3238. if assigned(inputpointer) then
  3239. begin
  3240. c:=inputpointer^;
  3241. inc(inputpointer);
  3242. end;
  3243. exit;
  3244. end;
  3245. repeat
  3246. { load token from the buffer }
  3247. token:=readtoken;
  3248. if token<>_GENERICSPECIALTOKEN then
  3249. idtoken:=readtoken
  3250. else
  3251. idtoken:=_NOID;
  3252. case token of
  3253. _CWCHAR,
  3254. _CWSTRING :
  3255. begin
  3256. wlen:=tokenreadsizeint;
  3257. setlengthwidestring(patternw,wlen);
  3258. if wlen>0 then
  3259. replaytokenbuf.read(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
  3260. orgpattern:='';
  3261. pattern:='';
  3262. cstringpattern:='';
  3263. end;
  3264. _CSTRING:
  3265. begin
  3266. wlen:=tokenreadsizeint;
  3267. if wlen>0 then
  3268. begin
  3269. setlength(cstringpattern,wlen);
  3270. replaytokenbuf.read(cstringpattern[1],wlen);
  3271. end
  3272. else
  3273. cstringpattern:='';
  3274. orgpattern:='';
  3275. pattern:='';
  3276. end;
  3277. _CCHAR,
  3278. _INTCONST,
  3279. _REALNUMBER :
  3280. begin
  3281. replaytokenbuf.read(pattern[0],1);
  3282. replaytokenbuf.read(pattern[1],length(pattern));
  3283. orgpattern:='';
  3284. end;
  3285. _ID :
  3286. begin
  3287. replaytokenbuf.read(orgpattern[0],1);
  3288. replaytokenbuf.read(orgpattern[1],length(orgpattern));
  3289. pattern:=upper(orgpattern);
  3290. end;
  3291. _GENERICSPECIALTOKEN:
  3292. begin
  3293. replaytokenbuf.read(specialtoken,1);
  3294. { packed column? }
  3295. if (ord(specialtoken) and $80)<>0 then
  3296. begin
  3297. current_tokenpos.column:=ord(specialtoken) and $7f;
  3298. current_filepos:=current_tokenpos;
  3299. end
  3300. else
  3301. case specialtoken of
  3302. ST_LOADSETTINGS:
  3303. begin
  3304. copy_size:=tokenreadsizeint;
  3305. //if copy_size <> sizeof(current_settings)-sizeof(pointer) then
  3306. // internalerror(2011090501);
  3307. {
  3308. replaytokenbuf.read(current_settings,copy_size);
  3309. }
  3310. tokenreadsettings(current_settings,copy_size);
  3311. end;
  3312. ST_LOADMESSAGES:
  3313. begin
  3314. current_settings.pmessage:=nil;
  3315. mesgnb:=tokenreadsizeint;
  3316. prevmsg:=nil;
  3317. for i:=1 to mesgnb do
  3318. begin
  3319. new(pmsg);
  3320. if i=1 then
  3321. current_settings.pmessage:=pmsg
  3322. else
  3323. prevmsg^.next:=pmsg;
  3324. pmsg^.value:=tokenreadlongint;
  3325. pmsg^.state:=tmsgstate(tokenreadlongint);
  3326. pmsg^.next:=nil;
  3327. prevmsg:=pmsg;
  3328. end;
  3329. end;
  3330. ST_LINE:
  3331. begin
  3332. current_tokenpos.line:=tokenreadlongint;
  3333. current_filepos:=current_tokenpos;
  3334. end;
  3335. ST_COLUMN:
  3336. begin
  3337. current_tokenpos.column:=tokenreadword;
  3338. current_filepos:=current_tokenpos;
  3339. end;
  3340. ST_FILEINDEX:
  3341. begin
  3342. current_tokenpos.fileindex:=tokenreadword;
  3343. current_filepos:=current_tokenpos;
  3344. end;
  3345. end;
  3346. continue;
  3347. end;
  3348. else
  3349. ;
  3350. end;
  3351. break;
  3352. until false;
  3353. end;
  3354. procedure tscannerfile.addfile(hp:tinputfile);
  3355. begin
  3356. saveinputfile;
  3357. { add to list }
  3358. hp.next:=inputfile;
  3359. inputfile:=hp;
  3360. { load new inputfile }
  3361. restoreinputfile;
  3362. end;
  3363. procedure tscannerfile.reload;
  3364. var
  3365. wasmacro: Boolean;
  3366. begin
  3367. with inputfile do
  3368. begin
  3369. { when nothing more to read then leave immediatly, so we
  3370. don't change the current_filepos and leave it point to the last
  3371. char }
  3372. if (c=#26) and (not assigned(next)) then
  3373. exit;
  3374. repeat
  3375. { still more to read?, then change the #0 to a space so its seen
  3376. as a separator, this can't be used for macro's which can change
  3377. the place of the #0 in the buffer with tempopen }
  3378. if (c=#0) and (bufsize>0) and
  3379. not(inputfile.is_macro) and
  3380. (inputpointer-inputbuffer<bufsize) then
  3381. begin
  3382. c:=' ';
  3383. inc(inputpointer);
  3384. exit;
  3385. end;
  3386. { can we read more from this file ? }
  3387. if (c<>#26) and (not endoffile) then
  3388. begin
  3389. readbuf;
  3390. inputpointer:=buf;
  3391. inputbuffer:=buf;
  3392. inputstart:=bufstart;
  3393. { first line? }
  3394. if line_no=0 then
  3395. begin
  3396. c:=inputpointer^;
  3397. { eat utf-8 signature? }
  3398. if (ord(inputpointer^)=$ef) and
  3399. (ord((inputpointer+1)^)=$bb) and
  3400. (ord((inputpointer+2)^)=$bf) then
  3401. begin
  3402. (* we don't support including files with an UTF-8 bom
  3403. inside another file that wasn't encoded as UTF-8
  3404. already (we don't support {$codepage xxx} switches in
  3405. the middle of a file either) *)
  3406. if (current_settings.sourcecodepage<>CP_UTF8) and
  3407. not current_module.in_global then
  3408. Message(scanner_f_illegal_utf8_bom);
  3409. inc(inputpointer,3);
  3410. message(scan_c_switching_to_utf8);
  3411. current_settings.sourcecodepage:=CP_UTF8;
  3412. exclude(current_settings.moduleswitches,cs_system_codepage);
  3413. include(current_settings.moduleswitches,cs_explicit_codepage);
  3414. end;
  3415. line_no:=1;
  3416. if cs_asm_source in current_settings.globalswitches then
  3417. inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);
  3418. end;
  3419. end
  3420. else
  3421. begin
  3422. wasmacro:=inputfile.is_macro;
  3423. { load eof position in tokenpos/current_filepos }
  3424. gettokenpos;
  3425. { close file }
  3426. closeinputfile;
  3427. { no next module, than EOF }
  3428. if not assigned(inputfile.next) then
  3429. begin
  3430. c:=#26;
  3431. exit;
  3432. end;
  3433. { load next file and reopen it }
  3434. nextfile;
  3435. tempopeninputfile;
  3436. { status }
  3437. Message1(scan_t_back_in,inputfile.name);
  3438. { end of include file is like a line break which ends e.g. also // style comments }
  3439. if not(wasmacro) and (current_commentstyle=comment_delphi) then
  3440. begin
  3441. c:=#10;
  3442. { ... but we have to decrease the line number first because it is increased due to this
  3443. inserted line break later on }
  3444. dec(line_no);
  3445. exit;
  3446. end;
  3447. end;
  3448. { load next char }
  3449. c:=inputpointer^;
  3450. inc(inputpointer);
  3451. until c<>#0; { if also end, then reload again }
  3452. end;
  3453. end;
  3454. procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);
  3455. var
  3456. hp : tinputfile;
  3457. begin
  3458. { save old postion }
  3459. dec(inputpointer);
  3460. tempcloseinputfile;
  3461. { create macro 'file' }
  3462. { use special name to dispose after !! }
  3463. hp:=do_openinputfile('_Macro_.'+macname);
  3464. addfile(hp);
  3465. with inputfile do
  3466. begin
  3467. inc(macro_nesting_depth);
  3468. setmacro(p,len);
  3469. { local buffer }
  3470. inputbuffer:=buf;
  3471. inputpointer:=buf;
  3472. inputstart:=bufstart;
  3473. ref_index:=fileindex;
  3474. internally_generated_macro:=internally_generated;
  3475. end;
  3476. { reset line }
  3477. line_no:=line;
  3478. lastlinepos:=0;
  3479. lasttokenpos:=0;
  3480. nexttokenpos:=0;
  3481. { load new c }
  3482. c:=inputpointer^;
  3483. inc(inputpointer);
  3484. end;
  3485. procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
  3486. begin
  3487. tokenpos:=inputstart+(inputpointer-inputbuffer);
  3488. filepos.line:=line_no;
  3489. filepos.column:=tokenpos-lastlinepos;
  3490. filepos.fileindex:=inputfile.ref_index;
  3491. filepos.moduleindex:=current_module.unit_index;
  3492. end;
  3493. procedure tscannerfile.gettokenpos;
  3494. { load the values of tokenpos and lasttokenpos }
  3495. begin
  3496. do_gettokenpos(lasttokenpos,current_tokenpos);
  3497. current_filepos:=current_tokenpos;
  3498. end;
  3499. procedure tscannerfile.cachenexttokenpos;
  3500. begin
  3501. do_gettokenpos(nexttokenpos,next_filepos);
  3502. end;
  3503. procedure tscannerfile.setnexttoken;
  3504. begin
  3505. token:=nexttoken;
  3506. nexttoken:=NOTOKEN;
  3507. lasttokenpos:=nexttokenpos;
  3508. current_tokenpos:=next_filepos;
  3509. current_filepos:=current_tokenpos;
  3510. nexttokenpos:=0;
  3511. end;
  3512. procedure tscannerfile.savetokenpos;
  3513. begin
  3514. oldlasttokenpos:=lasttokenpos;
  3515. oldcurrent_filepos:=current_filepos;
  3516. oldcurrent_tokenpos:=current_tokenpos;
  3517. end;
  3518. procedure tscannerfile.restoretokenpos;
  3519. begin
  3520. lasttokenpos:=oldlasttokenpos;
  3521. current_filepos:=oldcurrent_filepos;
  3522. current_tokenpos:=oldcurrent_tokenpos;
  3523. end;
  3524. procedure tscannerfile.inc_comment_level;
  3525. begin
  3526. if (m_nested_comment in current_settings.modeswitches) then
  3527. inc(comment_level)
  3528. else
  3529. comment_level:=1;
  3530. if (comment_level>1) then
  3531. begin
  3532. savetokenpos;
  3533. gettokenpos; { update for warning }
  3534. Message1(scan_w_comment_level,tostr(comment_level));
  3535. restoretokenpos;
  3536. end;
  3537. end;
  3538. procedure tscannerfile.dec_comment_level;
  3539. begin
  3540. if (m_nested_comment in current_settings.modeswitches) then
  3541. dec(comment_level)
  3542. else
  3543. comment_level:=0;
  3544. end;
  3545. procedure tscannerfile.linebreak;
  3546. var
  3547. cur : char;
  3548. begin
  3549. with inputfile do
  3550. begin
  3551. if (byte(inputpointer^)=0) and not(endoffile) then
  3552. begin
  3553. cur:=c;
  3554. reload;
  3555. if byte(cur)+byte(c)<>23 then
  3556. dec(inputpointer);
  3557. end
  3558. else
  3559. begin
  3560. { Support all combination of #10 and #13 as line break }
  3561. if (byte(inputpointer^)+byte(c)=23) then
  3562. inc(inputpointer);
  3563. end;
  3564. { Always return #10 as line break }
  3565. c:=#10;
  3566. { increase line counters }
  3567. lastlinepos:=inputstart+(inputpointer-inputbuffer);
  3568. inc(line_no);
  3569. { update linebuffer }
  3570. if cs_asm_source in current_settings.globalswitches then
  3571. inputfile.setline(line_no,lastlinepos);
  3572. { update for status and call the show status routine,
  3573. but don't touch current_filepos ! }
  3574. savetokenpos;
  3575. gettokenpos; { update for v_status }
  3576. inc(status.compiledlines);
  3577. ShowStatus;
  3578. restoretokenpos;
  3579. end;
  3580. end;
  3581. procedure tscannerfile.illegal_char(c:char);
  3582. var
  3583. s : string;
  3584. begin
  3585. if c in [#32..#255] then
  3586. s:=''''+c+''''
  3587. else
  3588. s:='#'+tostr(ord(c));
  3589. Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
  3590. end;
  3591. procedure tscannerfile.end_of_file;
  3592. begin
  3593. checkpreprocstack;
  3594. Message(scan_f_end_of_file);
  3595. end;
  3596. {-------------------------------------------
  3597. IF Conditional Handling
  3598. -------------------------------------------}
  3599. procedure tscannerfile.checkpreprocstack;
  3600. begin
  3601. { check for missing ifdefs }
  3602. while assigned(preprocstack) do
  3603. begin
  3604. Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
  3605. current_module.sourcefiles.get_file_name(preprocstack.fileindex),
  3606. tostr(preprocstack.line_nb));
  3607. poppreprocstack;
  3608. end;
  3609. end;
  3610. procedure tscannerfile.poppreprocstack;
  3611. var
  3612. hp : tpreprocstack;
  3613. begin
  3614. if assigned(preprocstack) then
  3615. begin
  3616. Message1(scan_c_endif_found,preprocstack.name);
  3617. hp:=preprocstack.next;
  3618. preprocstack.free;
  3619. preprocstack:=hp;
  3620. end
  3621. else
  3622. Message(scan_e_endif_without_if);
  3623. end;
  3624. procedure tscannerfile.ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  3625. var
  3626. condition: Boolean;
  3627. valuedescr: String;
  3628. begin
  3629. if (preprocstack=nil) or preprocstack.accept then
  3630. condition:=compile_time_predicate(valuedescr)
  3631. else
  3632. begin
  3633. condition:= false;
  3634. valuedescr:= '';
  3635. end;
  3636. preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
  3637. preprocstack.name:=valuedescr;
  3638. preprocstack.line_nb:=line_no;
  3639. preprocstack.fileindex:=current_filepos.fileindex;
  3640. if preprocstack.accept then
  3641. Message2(messid,preprocstack.name,'accepted')
  3642. else
  3643. Message2(messid,preprocstack.name,'rejected');
  3644. end;
  3645. procedure tscannerfile.elsepreprocstack;
  3646. begin
  3647. if assigned(preprocstack) and
  3648. (preprocstack.typ<>pp_else) then
  3649. begin
  3650. if (preprocstack.typ=pp_elseif) then
  3651. preprocstack.accept:=false
  3652. else
  3653. if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
  3654. preprocstack.accept:=not preprocstack.accept;
  3655. preprocstack.iftyp:=preprocstack.typ;
  3656. preprocstack.typ:=pp_else;
  3657. preprocstack.line_nb:=line_no;
  3658. preprocstack.fileindex:=current_filepos.fileindex;
  3659. if preprocstack.accept then
  3660. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3661. else
  3662. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3663. end
  3664. else
  3665. Message(scan_e_endif_without_if);
  3666. end;
  3667. procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  3668. var
  3669. valuedescr: String;
  3670. begin
  3671. if assigned(preprocstack) and
  3672. (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef,pp_elseif]) then
  3673. begin
  3674. { when the branch is accepted we use pp_elseif so we know that
  3675. all the next branches need to be rejected. when this branch is still
  3676. not accepted then leave it at pp_if }
  3677. if (preprocstack.typ=pp_elseif) then
  3678. preprocstack.accept:=false
  3679. else if (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef]) and preprocstack.accept then
  3680. begin
  3681. preprocstack.accept:=false;
  3682. preprocstack.typ:=pp_elseif;
  3683. end
  3684. else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
  3685. and compile_time_predicate(valuedescr) then
  3686. begin
  3687. preprocstack.name:=valuedescr;
  3688. preprocstack.accept:=true;
  3689. preprocstack.typ:=pp_elseif;
  3690. end;
  3691. preprocstack.line_nb:=line_no;
  3692. preprocstack.fileindex:=current_filepos.fileindex;
  3693. if preprocstack.accept then
  3694. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3695. else
  3696. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3697. end
  3698. else
  3699. Message(scan_e_endif_without_if);
  3700. end;
  3701. procedure tscannerfile.popreplaystack;
  3702. var
  3703. hp : treplaystack;
  3704. begin
  3705. if assigned(replaystack) then
  3706. begin
  3707. hp:=replaystack.next;
  3708. replaystack.free;
  3709. replaystack:=hp;
  3710. end;
  3711. end;
  3712. function tscannerfile.replay_stack_depth:longint;
  3713. var
  3714. tmp: treplaystack;
  3715. begin
  3716. result:=0;
  3717. tmp:=replaystack;
  3718. while assigned(tmp) do
  3719. begin
  3720. inc(result);
  3721. tmp:=tmp.next;
  3722. end;
  3723. end;
  3724. procedure tscannerfile.handleconditional(p:tdirectiveitem);
  3725. begin
  3726. savetokenpos;
  3727. repeat
  3728. current_scanner.gettokenpos;
  3729. Message1(scan_d_handling_switch,'$'+p.name);
  3730. p.proc();
  3731. { accept the text ? }
  3732. if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
  3733. break
  3734. else
  3735. begin
  3736. current_scanner.gettokenpos;
  3737. Message(scan_c_skipping_until);
  3738. repeat
  3739. current_scanner.skipuntildirective;
  3740. if not (m_mac in current_settings.modeswitches) then
  3741. p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))
  3742. else
  3743. p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));
  3744. until assigned(p) and (p.is_conditional);
  3745. current_scanner.gettokenpos;
  3746. end;
  3747. until false;
  3748. restoretokenpos;
  3749. end;
  3750. procedure tscannerfile.handledirectives;
  3751. var
  3752. t : tdirectiveitem;
  3753. hs : string;
  3754. begin
  3755. gettokenpos;
  3756. readchar; {Remove the $}
  3757. hs:=readid;
  3758. { handle empty directive }
  3759. if hs='' then
  3760. begin
  3761. Message1(scan_w_illegal_switch,'$');
  3762. exit;
  3763. end;
  3764. {$ifdef PREPROCWRITE}
  3765. if parapreprocess then
  3766. begin
  3767. if not (m_mac in current_settings.modeswitches) then
  3768. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  3769. else
  3770. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  3771. if assigned(t) and not(t.is_conditional) then
  3772. begin
  3773. preprocfile.AddSpace;
  3774. preprocfile.Add('{$'+hs+current_scanner.readcomment+'}');
  3775. exit;
  3776. end;
  3777. end;
  3778. {$endif PREPROCWRITE}
  3779. { skip this directive? }
  3780. if (ignoredirectives.find(hs)<>nil) then
  3781. begin
  3782. if (comment_level>0) then
  3783. readcomment;
  3784. { we've read the whole comment }
  3785. current_commentstyle:=comment_none;
  3786. exit;
  3787. end;
  3788. { Check for compiler switches }
  3789. while (length(hs)=1) and (c in ['-','+']) do
  3790. begin
  3791. Message1(scan_d_handling_switch,'$'+hs+c);
  3792. HandleSwitch(hs[1],c);
  3793. current_scanner.readchar; {Remove + or -}
  3794. if c=',' then
  3795. begin
  3796. current_scanner.readchar; {Remove , }
  3797. { read next switch, support $v+,$+}
  3798. hs:=current_scanner.readid;
  3799. if (hs='') then
  3800. begin
  3801. if (c='$') and (m_fpc in current_settings.modeswitches) then
  3802. begin
  3803. current_scanner.readchar; { skip $ }
  3804. hs:=current_scanner.readid;
  3805. end;
  3806. if (hs='') then
  3807. Message1(scan_w_illegal_directive,'$'+c);
  3808. end;
  3809. end
  3810. else
  3811. hs:='';
  3812. end;
  3813. { directives may follow switches after a , }
  3814. if hs<>'' then
  3815. begin
  3816. if not (m_mac in current_settings.modeswitches) then
  3817. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  3818. else
  3819. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  3820. if assigned(t) then
  3821. begin
  3822. if t.is_conditional then
  3823. handleconditional(t)
  3824. else
  3825. begin
  3826. Message1(scan_d_handling_switch,'$'+hs);
  3827. t.proc();
  3828. end;
  3829. end
  3830. else
  3831. begin
  3832. current_scanner.ignoredirectives.Add(hs,nil);
  3833. Message1(scan_w_illegal_directive,'$'+hs);
  3834. end;
  3835. { conditionals already read the comment }
  3836. if (current_scanner.comment_level>0) then
  3837. current_scanner.readcomment;
  3838. { we've read the whole comment }
  3839. current_commentstyle:=comment_none;
  3840. end;
  3841. end;
  3842. procedure tscannerfile.readchar;
  3843. begin
  3844. c:=inputpointer^;
  3845. if c=#0 then
  3846. reload
  3847. else
  3848. inc(inputpointer);
  3849. end;
  3850. procedure tscannerfile.readstring;
  3851. var
  3852. i : longint;
  3853. err : boolean;
  3854. begin
  3855. err:=false;
  3856. i:=0;
  3857. repeat
  3858. case c of
  3859. '_',
  3860. '0'..'9',
  3861. 'A'..'Z',
  3862. 'a'..'z' :
  3863. begin
  3864. if i<255 then
  3865. begin
  3866. inc(i);
  3867. orgpattern[i]:=c;
  3868. if c in ['a'..'z'] then
  3869. pattern[i]:=chr(ord(c)-32)
  3870. else
  3871. pattern[i]:=c;
  3872. end
  3873. else
  3874. begin
  3875. if not err then
  3876. begin
  3877. Message(scan_e_string_exceeds_255_chars);
  3878. err:=true;
  3879. end;
  3880. end;
  3881. c:=inputpointer^;
  3882. inc(inputpointer);
  3883. end;
  3884. #0 :
  3885. reload;
  3886. else if inputfile.internally_generated_macro and
  3887. (c in [internal_macro_escape_begin..internal_macro_escape_end]) then
  3888. begin
  3889. if i<255 then
  3890. begin
  3891. inc(i);
  3892. orgpattern[i]:=c;
  3893. pattern[i]:=c;
  3894. end
  3895. else
  3896. begin
  3897. if not err then
  3898. begin
  3899. Message(scan_e_string_exceeds_255_chars);
  3900. err:=true;
  3901. end;
  3902. end;
  3903. c:=inputpointer^;
  3904. inc(inputpointer);
  3905. end
  3906. else
  3907. break;
  3908. end;
  3909. until false;
  3910. orgpattern[0]:=chr(i);
  3911. pattern[0]:=chr(i);
  3912. end;
  3913. procedure tscannerfile.readnumber;
  3914. var
  3915. base,
  3916. i : longint;
  3917. firstdigitread: Boolean;
  3918. begin
  3919. case c of
  3920. '%' :
  3921. begin
  3922. readchar;
  3923. base:=2;
  3924. pattern[1]:='%';
  3925. i:=1;
  3926. end;
  3927. '&' :
  3928. begin
  3929. readchar;
  3930. base:=8;
  3931. pattern[1]:='&';
  3932. i:=1;
  3933. end;
  3934. '$' :
  3935. begin
  3936. readchar;
  3937. base:=16;
  3938. pattern[1]:='$';
  3939. i:=1;
  3940. end;
  3941. else
  3942. begin
  3943. base:=10;
  3944. i:=0;
  3945. end;
  3946. end;
  3947. firstdigitread:=false;
  3948. while ((base>=10) and (c in ['0'..'9'])) or
  3949. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  3950. ((base=8) and (c in ['0'..'7'])) or
  3951. ((base=2) and (c in ['0'..'1'])) or
  3952. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  3953. begin
  3954. if (i<255) and (c<>'_') then
  3955. begin
  3956. inc(i);
  3957. pattern[i]:=c;
  3958. end;
  3959. readchar;
  3960. firstdigitread:=true;
  3961. end;
  3962. pattern[0]:=chr(i);
  3963. end;
  3964. function tscannerfile.readid:string;
  3965. begin
  3966. readstring;
  3967. readid:=pattern;
  3968. end;
  3969. function tscannerfile.readval:longint;
  3970. var
  3971. l : longint;
  3972. w : integer;
  3973. begin
  3974. readnumber;
  3975. val(pattern,l,w);
  3976. readval:=l;
  3977. end;
  3978. function tscannerfile.readcomment(include_special_char: boolean):string;
  3979. var
  3980. i : longint;
  3981. begin
  3982. i:=0;
  3983. repeat
  3984. case c of
  3985. '{' :
  3986. begin
  3987. if (include_special_char) and (i<255) then
  3988. begin
  3989. inc(i);
  3990. readcomment[i]:=c;
  3991. end;
  3992. if current_commentstyle=comment_tp then
  3993. inc_comment_level;
  3994. end;
  3995. '}' :
  3996. begin
  3997. if (include_special_char) and (i<255) then
  3998. begin
  3999. inc(i);
  4000. readcomment[i]:=c;
  4001. end;
  4002. if current_commentstyle=comment_tp then
  4003. begin
  4004. readchar;
  4005. dec_comment_level;
  4006. if comment_level=0 then
  4007. break
  4008. else
  4009. continue;
  4010. end;
  4011. end;
  4012. '*' :
  4013. begin
  4014. if current_commentstyle=comment_oldtp then
  4015. begin
  4016. readchar;
  4017. if c=')' then
  4018. begin
  4019. readchar;
  4020. dec_comment_level;
  4021. break;
  4022. end
  4023. else
  4024. { Add both characters !!}
  4025. if (i<255) then
  4026. begin
  4027. inc(i);
  4028. readcomment[i]:='*';
  4029. if (i<255) then
  4030. begin
  4031. inc(i);
  4032. readcomment[i]:=c;
  4033. end;
  4034. end;
  4035. end
  4036. else
  4037. { Not old TP comment, so add...}
  4038. begin
  4039. if (i<255) then
  4040. begin
  4041. inc(i);
  4042. readcomment[i]:='*';
  4043. end;
  4044. end;
  4045. end;
  4046. #10,#13 :
  4047. linebreak;
  4048. #26 :
  4049. end_of_file;
  4050. else
  4051. begin
  4052. if (i<255) then
  4053. begin
  4054. inc(i);
  4055. readcomment[i]:=c;
  4056. end;
  4057. end;
  4058. end;
  4059. readchar;
  4060. until false;
  4061. readcomment[0]:=chr(i);
  4062. end;
  4063. function tscannerfile.readquotedstring:string;
  4064. var
  4065. i : longint;
  4066. msgwritten : boolean;
  4067. begin
  4068. i:=0;
  4069. msgwritten:=false;
  4070. if (c='''') then
  4071. begin
  4072. repeat
  4073. readchar;
  4074. case c of
  4075. #26 :
  4076. end_of_file;
  4077. #10,#13 :
  4078. Message(scan_f_string_exceeds_line);
  4079. '''' :
  4080. begin
  4081. readchar;
  4082. if c<>'''' then
  4083. break;
  4084. end;
  4085. end;
  4086. if i<255 then
  4087. begin
  4088. inc(i);
  4089. result[i]:=c;
  4090. end
  4091. else
  4092. begin
  4093. if not msgwritten then
  4094. begin
  4095. Message(scan_e_string_exceeds_255_chars);
  4096. msgwritten:=true;
  4097. end;
  4098. end;
  4099. until false;
  4100. end;
  4101. result[0]:=chr(i);
  4102. end;
  4103. function tscannerfile.readstate:char;
  4104. var
  4105. state : char;
  4106. begin
  4107. state:=' ';
  4108. if c=' ' then
  4109. begin
  4110. current_scanner.skipspace;
  4111. current_scanner.readid;
  4112. if pattern='ON' then
  4113. state:='+'
  4114. else
  4115. if pattern='OFF' then
  4116. state:='-';
  4117. end
  4118. else
  4119. state:=c;
  4120. if not (state in ['+','-']) then
  4121. Message(scan_e_wrong_switch_toggle);
  4122. readstate:=state;
  4123. end;
  4124. function tscannerfile.readoptionalstate(fallback:char):char;
  4125. var
  4126. state : char;
  4127. begin
  4128. state:=' ';
  4129. if c=' ' then
  4130. begin
  4131. current_scanner.skipspace;
  4132. if c in ['*','}'] then
  4133. state:=fallback
  4134. else
  4135. begin
  4136. current_scanner.readid;
  4137. if pattern='ON' then
  4138. state:='+'
  4139. else
  4140. if pattern='OFF' then
  4141. state:='-';
  4142. end;
  4143. end
  4144. else
  4145. if c in ['*','}'] then
  4146. state:=fallback
  4147. else
  4148. state:=c;
  4149. if not (state in ['+','-']) then
  4150. Message(scan_e_wrong_switch_toggle);
  4151. readoptionalstate:=state;
  4152. end;
  4153. function tscannerfile.readstatedefault:char;
  4154. var
  4155. state : char;
  4156. begin
  4157. state:=' ';
  4158. if c=' ' then
  4159. begin
  4160. current_scanner.skipspace;
  4161. current_scanner.readid;
  4162. if pattern='ON' then
  4163. state:='+'
  4164. else
  4165. if pattern='OFF' then
  4166. state:='-'
  4167. else
  4168. if pattern='DEFAULT' then
  4169. state:='*';
  4170. end
  4171. else
  4172. state:=c;
  4173. if not (state in ['+','-','*']) then
  4174. Message(scan_e_wrong_switch_toggle_default);
  4175. readstatedefault:=state;
  4176. end;
  4177. procedure tscannerfile.skipspace;
  4178. begin
  4179. repeat
  4180. case c of
  4181. #26 :
  4182. begin
  4183. reload;
  4184. if (c=#26) and not assigned(inputfile.next) then
  4185. break;
  4186. continue;
  4187. end;
  4188. #10,
  4189. #13 :
  4190. linebreak;
  4191. #9,#11,#12,' ' :
  4192. ;
  4193. else
  4194. break;
  4195. end;
  4196. readchar;
  4197. until false;
  4198. end;
  4199. procedure tscannerfile.skipuntildirective;
  4200. var
  4201. found : longint;
  4202. next_char_loaded : boolean;
  4203. begin
  4204. found:=0;
  4205. next_char_loaded:=false;
  4206. repeat
  4207. case c of
  4208. #10,
  4209. #13 :
  4210. linebreak;
  4211. #26 :
  4212. begin
  4213. reload;
  4214. if (c=#26) and not assigned(inputfile.next) then
  4215. end_of_file;
  4216. continue;
  4217. end;
  4218. '{' :
  4219. begin
  4220. if (current_commentstyle in [comment_tp,comment_none]) then
  4221. begin
  4222. current_commentstyle:=comment_tp;
  4223. if (comment_level=0) then
  4224. found:=1;
  4225. inc_comment_level;
  4226. end;
  4227. end;
  4228. '*' :
  4229. begin
  4230. if (current_commentstyle=comment_oldtp) then
  4231. begin
  4232. readchar;
  4233. if c=')' then
  4234. begin
  4235. dec_comment_level;
  4236. found:=0;
  4237. current_commentstyle:=comment_none;
  4238. end
  4239. else
  4240. next_char_loaded:=true;
  4241. end
  4242. else
  4243. found := 0;
  4244. end;
  4245. '}' :
  4246. begin
  4247. if (current_commentstyle=comment_tp) then
  4248. begin
  4249. dec_comment_level;
  4250. if (comment_level=0) then
  4251. current_commentstyle:=comment_none;
  4252. found:=0;
  4253. end;
  4254. end;
  4255. '$' :
  4256. begin
  4257. if found=1 then
  4258. found:=2;
  4259. end;
  4260. '''' :
  4261. if (current_commentstyle=comment_none) then
  4262. begin
  4263. repeat
  4264. readchar;
  4265. case c of
  4266. #26 :
  4267. end_of_file;
  4268. #10,#13 :
  4269. break;
  4270. '''' :
  4271. begin
  4272. readchar;
  4273. if c<>'''' then
  4274. begin
  4275. next_char_loaded:=true;
  4276. break;
  4277. end;
  4278. end;
  4279. end;
  4280. until false;
  4281. end;
  4282. '(' :
  4283. begin
  4284. if (current_commentstyle=comment_none) then
  4285. begin
  4286. readchar;
  4287. if c='*' then
  4288. begin
  4289. readchar;
  4290. if c='$' then
  4291. begin
  4292. found:=2;
  4293. inc_comment_level;
  4294. current_commentstyle:=comment_oldtp;
  4295. end
  4296. else
  4297. begin
  4298. skipoldtpcomment(false);
  4299. next_char_loaded:=true;
  4300. end;
  4301. end
  4302. else
  4303. next_char_loaded:=true;
  4304. end
  4305. else
  4306. found:=0;
  4307. end;
  4308. '/' :
  4309. begin
  4310. if (current_commentstyle=comment_none) then
  4311. begin
  4312. readchar;
  4313. if c='/' then
  4314. skipdelphicomment;
  4315. next_char_loaded:=true;
  4316. end
  4317. else
  4318. found:=0;
  4319. end;
  4320. else
  4321. found:=0;
  4322. end;
  4323. if next_char_loaded then
  4324. next_char_loaded:=false
  4325. else
  4326. readchar;
  4327. until (found=2);
  4328. end;
  4329. {****************************************************************************
  4330. Comment Handling
  4331. ****************************************************************************}
  4332. procedure tscannerfile.skipcomment(read_first_char:boolean);
  4333. begin
  4334. current_commentstyle:=comment_tp;
  4335. if read_first_char then
  4336. readchar;
  4337. inc_comment_level;
  4338. { handle compiler switches }
  4339. if (c='$') then
  4340. handledirectives;
  4341. { handle_switches can dec comment_level, }
  4342. while (comment_level>0) do
  4343. begin
  4344. case c of
  4345. '{' :
  4346. inc_comment_level;
  4347. '}' :
  4348. dec_comment_level;
  4349. '*' :
  4350. { in iso mode, comments opened by a curly bracket can be closed by asterisk, round bracket }
  4351. if m_iso in current_settings.modeswitches then
  4352. begin
  4353. readchar;
  4354. if c=')' then
  4355. dec_comment_level
  4356. else
  4357. continue;
  4358. end;
  4359. #10,#13 :
  4360. linebreak;
  4361. #26 :
  4362. begin
  4363. reload;
  4364. if (c=#26) and not assigned(inputfile.next) then
  4365. end_of_file;
  4366. continue;
  4367. end;
  4368. end;
  4369. readchar;
  4370. end;
  4371. current_commentstyle:=comment_none;
  4372. end;
  4373. procedure tscannerfile.skipdelphicomment;
  4374. begin
  4375. current_commentstyle:=comment_delphi;
  4376. inc_comment_level;
  4377. readchar;
  4378. { this is not supported }
  4379. if c='$' then
  4380. Message(scan_w_wrong_styled_switch);
  4381. { skip comment }
  4382. while not (c in [#10,#13,#26]) do
  4383. readchar;
  4384. dec_comment_level;
  4385. current_commentstyle:=comment_none;
  4386. end;
  4387. procedure tscannerfile.skipoldtpcomment(read_first_char:boolean);
  4388. var
  4389. found : longint;
  4390. begin
  4391. current_commentstyle:=comment_oldtp;
  4392. inc_comment_level;
  4393. { only load a char if last already processed,
  4394. was cause of bug1634 PM }
  4395. if read_first_char then
  4396. readchar;
  4397. { this is now supported }
  4398. if (c='$') then
  4399. handledirectives;
  4400. { skip comment }
  4401. while (comment_level>0) do
  4402. begin
  4403. found:=0;
  4404. repeat
  4405. case c of
  4406. #26 :
  4407. begin
  4408. reload;
  4409. if (c=#26) and not assigned(inputfile.next) then
  4410. end_of_file;
  4411. continue;
  4412. end;
  4413. #10,#13 :
  4414. begin
  4415. if found=4 then
  4416. inc_comment_level;
  4417. linebreak;
  4418. found:=0;
  4419. end;
  4420. '*' :
  4421. begin
  4422. if found=3 then
  4423. found:=4
  4424. else
  4425. begin
  4426. if found=4 then
  4427. inc_comment_level;
  4428. found:=1;
  4429. end;
  4430. end;
  4431. ')' :
  4432. begin
  4433. if found in [1,4] then
  4434. begin
  4435. dec_comment_level;
  4436. if comment_level=0 then
  4437. found:=2
  4438. else
  4439. found:=0;
  4440. end
  4441. else
  4442. found:=0;
  4443. end;
  4444. '}' :
  4445. { in iso mode, comments opened by asterisk, round bracket can be closed by a curly bracket }
  4446. if m_iso in current_settings.modeswitches then
  4447. begin
  4448. dec_comment_level;
  4449. if comment_level=0 then
  4450. found:=2
  4451. else
  4452. found:=0;
  4453. end;
  4454. '(' :
  4455. begin
  4456. if found=4 then
  4457. inc_comment_level;
  4458. found:=3;
  4459. end;
  4460. else
  4461. begin
  4462. if found=4 then
  4463. inc_comment_level;
  4464. found:=0;
  4465. end;
  4466. end;
  4467. readchar;
  4468. until (found=2);
  4469. end;
  4470. current_commentstyle:=comment_none;
  4471. end;
  4472. {****************************************************************************
  4473. Token Scanner
  4474. ****************************************************************************}
  4475. procedure tscannerfile.readtoken(allowrecordtoken:boolean);
  4476. var
  4477. code : integer;
  4478. d : cardinal;
  4479. len,
  4480. low,high,mid : longint;
  4481. w : word;
  4482. m : longint;
  4483. mac : tmacro;
  4484. asciinr : string[33];
  4485. iswidestring , firstdigitread: boolean;
  4486. label
  4487. exit_label;
  4488. begin
  4489. flushpendingswitchesstate;
  4490. { record tokens? }
  4491. if allowrecordtoken and
  4492. assigned(recordtokenbuf) then
  4493. recordtoken;
  4494. { replay tokens? }
  4495. if assigned(replaytokenbuf) then
  4496. begin
  4497. replaytoken;
  4498. goto exit_label;
  4499. end;
  4500. { was there already a token read, then return that token }
  4501. if nexttoken<>NOTOKEN then
  4502. begin
  4503. setnexttoken;
  4504. goto exit_label;
  4505. end;
  4506. { Skip all spaces and comments }
  4507. repeat
  4508. case c of
  4509. '{' :
  4510. skipcomment(true);
  4511. #26 :
  4512. begin
  4513. reload;
  4514. if (c=#26) and not assigned(inputfile.next) then
  4515. break;
  4516. end;
  4517. ' ',#9..#13 :
  4518. begin
  4519. {$ifdef PREPROCWRITE}
  4520. if parapreprocess then
  4521. begin
  4522. if c=#10 then
  4523. preprocfile.eolfound:=true
  4524. else
  4525. preprocfile.spacefound:=true;
  4526. end;
  4527. {$endif PREPROCWRITE}
  4528. skipspace;
  4529. end
  4530. else
  4531. break;
  4532. end;
  4533. until false;
  4534. { Save current token position, for EOF its already loaded }
  4535. if c<>#26 then
  4536. gettokenpos;
  4537. { Check first for a identifier/keyword, this is 20+% faster (PFV) }
  4538. if c in ['A'..'Z','a'..'z','_'] then
  4539. begin
  4540. readstring;
  4541. token:=_ID;
  4542. idtoken:=_ID;
  4543. { keyword or any other known token,
  4544. pattern is always uppercased }
  4545. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  4546. begin
  4547. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  4548. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  4549. while low<high do
  4550. begin
  4551. mid:=(high+low+1) shr 1;
  4552. if pattern<tokeninfo^[ttoken(mid)].str then
  4553. high:=mid-1
  4554. else
  4555. low:=mid;
  4556. end;
  4557. with tokeninfo^[ttoken(high)] do
  4558. if pattern=str then
  4559. begin
  4560. if (keyword*current_settings.modeswitches)<>[] then
  4561. if op=NOTOKEN then
  4562. token:=ttoken(high)
  4563. else
  4564. token:=op;
  4565. idtoken:=ttoken(high);
  4566. end;
  4567. end;
  4568. { Only process identifiers and not keywords }
  4569. if token=_ID then
  4570. begin
  4571. { this takes some time ... }
  4572. if (cs_support_macro in current_settings.moduleswitches) then
  4573. begin
  4574. mac:=tmacro(search_macro(pattern));
  4575. if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
  4576. begin
  4577. if (yylexcount<max_macro_nesting) and (macro_nesting_depth<max_macro_nesting) then
  4578. begin
  4579. mac.is_used:=true;
  4580. inc(yylexcount);
  4581. substitutemacro(pattern,mac.buftext,mac.buflen,
  4582. mac.fileinfo.line,mac.fileinfo.fileindex,false);
  4583. { handle empty macros }
  4584. if c=#0 then
  4585. begin
  4586. reload;
  4587. { avoid macro nesting error in case of
  4588. a sequence of empty macros, see #38802 }
  4589. dec(yylexcount);
  4590. readtoken(false);
  4591. end
  4592. else
  4593. begin
  4594. readtoken(false);
  4595. { that's all folks }
  4596. dec(yylexcount);
  4597. end;
  4598. exit;
  4599. end
  4600. else
  4601. Message(scan_w_macro_too_deep);
  4602. end;
  4603. end;
  4604. end;
  4605. { return token }
  4606. goto exit_label;
  4607. end
  4608. else
  4609. begin
  4610. idtoken:=_NOID;
  4611. case c of
  4612. '$' :
  4613. begin
  4614. readnumber;
  4615. token:=_INTCONST;
  4616. goto exit_label;
  4617. end;
  4618. '%' :
  4619. begin
  4620. if [m_fpc,m_delphi] * current_settings.modeswitches = [] then
  4621. Illegal_Char(c)
  4622. else
  4623. begin
  4624. readnumber;
  4625. token:=_INTCONST;
  4626. goto exit_label;
  4627. end;
  4628. end;
  4629. '&' :
  4630. begin
  4631. if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then
  4632. begin
  4633. readnumber;
  4634. if length(pattern)=1 then
  4635. begin
  4636. { does really an identifier follow? }
  4637. if not (c in ['_','A'..'Z','a'..'z']) then
  4638. message2(scan_f_syn_expected,tokeninfo^[_ID].str,c);
  4639. readstring;
  4640. token:=_ID;
  4641. idtoken:=_ID;
  4642. end
  4643. else
  4644. token:=_INTCONST;
  4645. goto exit_label;
  4646. end
  4647. else if m_mac in current_settings.modeswitches then
  4648. begin
  4649. readchar;
  4650. token:=_AMPERSAND;
  4651. goto exit_label;
  4652. end
  4653. else
  4654. Illegal_Char(c);
  4655. end;
  4656. '0'..'9' :
  4657. begin
  4658. readnumber;
  4659. if (c in ['.','e','E']) then
  4660. begin
  4661. { first check for a . }
  4662. if c='.' then
  4663. begin
  4664. cachenexttokenpos;
  4665. readchar;
  4666. { is it a .. from a range? }
  4667. case c of
  4668. '.' :
  4669. begin
  4670. readchar;
  4671. token:=_INTCONST;
  4672. nexttoken:=_POINTPOINT;
  4673. goto exit_label;
  4674. end;
  4675. ')' :
  4676. begin
  4677. readchar;
  4678. token:=_INTCONST;
  4679. nexttoken:=_RECKKLAMMER;
  4680. goto exit_label;
  4681. end;
  4682. '0'..'9' :
  4683. begin
  4684. { insert the number after the . }
  4685. pattern:=pattern+'.';
  4686. firstdigitread:=false;
  4687. while (c in ['0'..'9']) or
  4688. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  4689. begin
  4690. if c<>'_' then
  4691. pattern:=pattern+c;
  4692. readchar;
  4693. firstdigitread:=true;
  4694. end;
  4695. end;
  4696. else
  4697. begin
  4698. token:=_INTCONST;
  4699. nexttoken:=_POINT;
  4700. goto exit_label;
  4701. end;
  4702. end;
  4703. end;
  4704. { E can also follow after a point is scanned }
  4705. if c in ['e','E'] then
  4706. begin
  4707. pattern:=pattern+'E';
  4708. readchar;
  4709. if c in ['-','+'] then
  4710. begin
  4711. pattern:=pattern+c;
  4712. readchar;
  4713. end;
  4714. if not(c in ['0'..'9']) then
  4715. Illegal_Char(c);
  4716. firstdigitread:=false;
  4717. while (c in ['0'..'9']) or
  4718. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  4719. begin
  4720. if c<>'_' then
  4721. pattern:=pattern+c;
  4722. readchar;
  4723. firstdigitread:=true;
  4724. end;
  4725. end;
  4726. token:=_REALNUMBER;
  4727. goto exit_label;
  4728. end;
  4729. token:=_INTCONST;
  4730. goto exit_label;
  4731. end;
  4732. ';' :
  4733. begin
  4734. readchar;
  4735. token:=_SEMICOLON;
  4736. goto exit_label;
  4737. end;
  4738. '[' :
  4739. begin
  4740. readchar;
  4741. token:=_LECKKLAMMER;
  4742. goto exit_label;
  4743. end;
  4744. ']' :
  4745. begin
  4746. readchar;
  4747. token:=_RECKKLAMMER;
  4748. goto exit_label;
  4749. end;
  4750. '(' :
  4751. begin
  4752. readchar;
  4753. case c of
  4754. '*' :
  4755. begin
  4756. skipoldtpcomment(true);
  4757. readtoken(false);
  4758. exit;
  4759. end;
  4760. '.' :
  4761. begin
  4762. readchar;
  4763. token:=_LECKKLAMMER;
  4764. goto exit_label;
  4765. end;
  4766. end;
  4767. token:=_LKLAMMER;
  4768. goto exit_label;
  4769. end;
  4770. ')' :
  4771. begin
  4772. readchar;
  4773. token:=_RKLAMMER;
  4774. goto exit_label;
  4775. end;
  4776. '+' :
  4777. begin
  4778. readchar;
  4779. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4780. begin
  4781. readchar;
  4782. token:=_PLUSASN;
  4783. goto exit_label;
  4784. end;
  4785. token:=_PLUS;
  4786. goto exit_label;
  4787. end;
  4788. '-' :
  4789. begin
  4790. readchar;
  4791. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4792. begin
  4793. readchar;
  4794. token:=_MINUSASN;
  4795. goto exit_label;
  4796. end;
  4797. token:=_MINUS;
  4798. goto exit_label;
  4799. end;
  4800. ':' :
  4801. begin
  4802. readchar;
  4803. if c='=' then
  4804. begin
  4805. readchar;
  4806. token:=_ASSIGNMENT;
  4807. goto exit_label;
  4808. end;
  4809. token:=_COLON;
  4810. goto exit_label;
  4811. end;
  4812. '*' :
  4813. begin
  4814. readchar;
  4815. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4816. begin
  4817. readchar;
  4818. token:=_STARASN;
  4819. end
  4820. else
  4821. if c='*' then
  4822. begin
  4823. readchar;
  4824. token:=_STARSTAR;
  4825. end
  4826. else
  4827. token:=_STAR;
  4828. goto exit_label;
  4829. end;
  4830. '/' :
  4831. begin
  4832. readchar;
  4833. case c of
  4834. '=' :
  4835. begin
  4836. if (cs_support_c_operators in current_settings.moduleswitches) then
  4837. begin
  4838. readchar;
  4839. token:=_SLASHASN;
  4840. goto exit_label;
  4841. end;
  4842. end;
  4843. '/' :
  4844. begin
  4845. skipdelphicomment;
  4846. readtoken(false);
  4847. exit;
  4848. end;
  4849. end;
  4850. token:=_SLASH;
  4851. goto exit_label;
  4852. end;
  4853. '|' :
  4854. if m_mac in current_settings.modeswitches then
  4855. begin
  4856. readchar;
  4857. token:=_PIPE;
  4858. goto exit_label;
  4859. end
  4860. else
  4861. Illegal_Char(c);
  4862. '=' :
  4863. begin
  4864. readchar;
  4865. token:=_EQ;
  4866. goto exit_label;
  4867. end;
  4868. '.' :
  4869. begin
  4870. readchar;
  4871. case c of
  4872. '.' :
  4873. begin
  4874. readchar;
  4875. case c of
  4876. '.' :
  4877. begin
  4878. readchar;
  4879. token:=_POINTPOINTPOINT;
  4880. goto exit_label;
  4881. end;
  4882. else
  4883. begin
  4884. token:=_POINTPOINT;
  4885. goto exit_label;
  4886. end;
  4887. end;
  4888. end;
  4889. ')' :
  4890. begin
  4891. readchar;
  4892. token:=_RECKKLAMMER;
  4893. goto exit_label;
  4894. end;
  4895. end;
  4896. token:=_POINT;
  4897. goto exit_label;
  4898. end;
  4899. '@' :
  4900. begin
  4901. readchar;
  4902. token:=_KLAMMERAFFE;
  4903. goto exit_label;
  4904. end;
  4905. ',' :
  4906. begin
  4907. readchar;
  4908. token:=_COMMA;
  4909. goto exit_label;
  4910. end;
  4911. '''','#','^' :
  4912. begin
  4913. len:=0;
  4914. cstringpattern:='';
  4915. iswidestring:=false;
  4916. if c='^' then
  4917. begin
  4918. readchar;
  4919. c:=upcase(c);
  4920. if (block_type in [bt_type,bt_const_type,bt_var_type]) or
  4921. (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or
  4922. (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
  4923. begin
  4924. token:=_CARET;
  4925. goto exit_label;
  4926. end
  4927. else
  4928. begin
  4929. inc(len);
  4930. setlength(cstringpattern,256);
  4931. if c<#64 then
  4932. cstringpattern[len]:=chr(ord(c)+64)
  4933. else
  4934. cstringpattern[len]:=chr(ord(c)-64);
  4935. readchar;
  4936. end;
  4937. end;
  4938. repeat
  4939. case c of
  4940. '#' :
  4941. begin
  4942. readchar; { read # }
  4943. case c of
  4944. '$':
  4945. begin
  4946. readchar; { read leading $ }
  4947. asciinr:='$';
  4948. while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=7) do
  4949. begin
  4950. asciinr:=asciinr+c;
  4951. readchar;
  4952. end;
  4953. end;
  4954. '&':
  4955. begin
  4956. readchar; { read leading $ }
  4957. asciinr:='&';
  4958. while (upcase(c) in ['0'..'7']) and (length(asciinr)<=8) do
  4959. begin
  4960. asciinr:=asciinr+c;
  4961. readchar;
  4962. end;
  4963. end;
  4964. '%':
  4965. begin
  4966. readchar; { read leading $ }
  4967. asciinr:='%';
  4968. while (upcase(c) in ['0','1']) and (length(asciinr)<=22) do
  4969. begin
  4970. asciinr:=asciinr+c;
  4971. readchar;
  4972. end;
  4973. end;
  4974. else
  4975. begin
  4976. asciinr:='';
  4977. while (c in ['0'..'9']) and (length(asciinr)<=8) do
  4978. begin
  4979. asciinr:=asciinr+c;
  4980. readchar;
  4981. end;
  4982. end;
  4983. end;
  4984. val(asciinr,m,code);
  4985. if (asciinr='') or (code<>0) then
  4986. Message(scan_e_illegal_char_const)
  4987. else if (m<0) or (m>255) or (length(asciinr)>3) then
  4988. begin
  4989. if (m>=0) and (m<=$10FFFF) then
  4990. begin
  4991. if not iswidestring then
  4992. begin
  4993. if len>0 then
  4994. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  4995. else
  4996. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  4997. iswidestring:=true;
  4998. len:=0;
  4999. end;
  5000. if m<=$FFFF then
  5001. concatwidestringchar(patternw,tcompilerwidechar(m))
  5002. else
  5003. begin
  5004. { split into surrogate pair }
  5005. dec(m,$10000);
  5006. concatwidestringchar(patternw,tcompilerwidechar((m shr 10) + $D800));
  5007. concatwidestringchar(patternw,tcompilerwidechar((m and $3FF) + $DC00));
  5008. end;
  5009. end
  5010. else
  5011. Message(scan_e_illegal_char_const)
  5012. end
  5013. else if iswidestring then
  5014. concatwidestringchar(patternw,asciichar2unicode(char(m)))
  5015. else
  5016. begin
  5017. if len>=length(cstringpattern) then
  5018. setlength(cstringpattern,length(cstringpattern)+256);
  5019. inc(len);
  5020. cstringpattern[len]:=chr(m);
  5021. end;
  5022. end;
  5023. '''' :
  5024. begin
  5025. repeat
  5026. readchar;
  5027. case c of
  5028. #26 :
  5029. end_of_file;
  5030. #10,#13 :
  5031. Message(scan_f_string_exceeds_line);
  5032. '''' :
  5033. begin
  5034. readchar;
  5035. if c<>'''' then
  5036. break;
  5037. end;
  5038. end;
  5039. { interpret as utf-8 string? }
  5040. if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then
  5041. begin
  5042. { convert existing string to an utf-8 string }
  5043. if not iswidestring then
  5044. begin
  5045. if len>0 then
  5046. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  5047. else
  5048. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  5049. iswidestring:=true;
  5050. len:=0;
  5051. end;
  5052. { four chars }
  5053. if (ord(c) and $f0)=$f0 then
  5054. begin
  5055. { this always represents a surrogate pair, so
  5056. read as 32-bit value and then split into
  5057. the corresponding pair of two wchars }
  5058. d:=ord(c) and $f;
  5059. readchar;
  5060. if (ord(c) and $c0)<>$80 then
  5061. message(scan_e_utf8_malformed);
  5062. d:=(d shl 6) or (ord(c) and $3f);
  5063. readchar;
  5064. if (ord(c) and $c0)<>$80 then
  5065. message(scan_e_utf8_malformed);
  5066. d:=(d shl 6) or (ord(c) and $3f);
  5067. readchar;
  5068. if (ord(c) and $c0)<>$80 then
  5069. message(scan_e_utf8_malformed);
  5070. d:=(d shl 6) or (ord(c) and $3f);
  5071. if d<$10000 then
  5072. message(scan_e_utf8_malformed);
  5073. d:=d-$10000;
  5074. { high surrogate }
  5075. w:=$d800+(d shr 10);
  5076. concatwidestringchar(patternw,w);
  5077. { low surrogate }
  5078. w:=$dc00+(d and $3ff);
  5079. concatwidestringchar(patternw,w);
  5080. end
  5081. { three chars }
  5082. else if (ord(c) and $e0)=$e0 then
  5083. begin
  5084. w:=ord(c) and $f;
  5085. readchar;
  5086. if (ord(c) and $c0)<>$80 then
  5087. message(scan_e_utf8_malformed);
  5088. w:=(w shl 6) or (ord(c) and $3f);
  5089. readchar;
  5090. if (ord(c) and $c0)<>$80 then
  5091. message(scan_e_utf8_malformed);
  5092. w:=(w shl 6) or (ord(c) and $3f);
  5093. concatwidestringchar(patternw,w);
  5094. end
  5095. { two chars }
  5096. else if (ord(c) and $c0)<>0 then
  5097. begin
  5098. w:=ord(c) and $1f;
  5099. readchar;
  5100. if (ord(c) and $c0)<>$80 then
  5101. message(scan_e_utf8_malformed);
  5102. w:=(w shl 6) or (ord(c) and $3f);
  5103. concatwidestringchar(patternw,w);
  5104. end
  5105. { illegal }
  5106. else if (ord(c) and $80)<>0 then
  5107. message(scan_e_utf8_malformed)
  5108. else
  5109. concatwidestringchar(patternw,tcompilerwidechar(c))
  5110. end
  5111. else if iswidestring then
  5112. begin
  5113. if current_settings.sourcecodepage=CP_UTF8 then
  5114. concatwidestringchar(patternw,ord(c))
  5115. else
  5116. concatwidestringchar(patternw,asciichar2unicode(c))
  5117. end
  5118. else
  5119. begin
  5120. if len>=length(cstringpattern) then
  5121. setlength(cstringpattern,length(cstringpattern)+256);
  5122. inc(len);
  5123. cstringpattern[len]:=c;
  5124. end;
  5125. until false;
  5126. end;
  5127. '^' :
  5128. begin
  5129. readchar;
  5130. c:=upcase(c);
  5131. if c<#64 then
  5132. c:=chr(ord(c)+64)
  5133. else
  5134. c:=chr(ord(c)-64);
  5135. if iswidestring then
  5136. concatwidestringchar(patternw,asciichar2unicode(c))
  5137. else
  5138. begin
  5139. if len>=length(cstringpattern) then
  5140. setlength(cstringpattern,length(cstringpattern)+256);
  5141. inc(len);
  5142. cstringpattern[len]:=c;
  5143. end;
  5144. readchar;
  5145. end;
  5146. else
  5147. break;
  5148. end;
  5149. until false;
  5150. { strings with length 1 become const chars }
  5151. if iswidestring then
  5152. begin
  5153. if patternw^.len=1 then
  5154. token:=_CWCHAR
  5155. else
  5156. token:=_CWSTRING;
  5157. end
  5158. else
  5159. begin
  5160. setlength(cstringpattern,len);
  5161. if length(cstringpattern)=1 then
  5162. begin
  5163. token:=_CCHAR;
  5164. pattern:=cstringpattern;
  5165. end
  5166. else
  5167. token:=_CSTRING;
  5168. end;
  5169. goto exit_label;
  5170. end;
  5171. '>' :
  5172. begin
  5173. readchar;
  5174. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  5175. token:=_RSHARPBRACKET
  5176. else
  5177. begin
  5178. case c of
  5179. '=' :
  5180. begin
  5181. readchar;
  5182. token:=_GTE;
  5183. goto exit_label;
  5184. end;
  5185. '>' :
  5186. begin
  5187. readchar;
  5188. token:=_OP_SHR;
  5189. goto exit_label;
  5190. end;
  5191. '<' :
  5192. begin { >< is for a symetric diff for sets }
  5193. readchar;
  5194. token:=_SYMDIF;
  5195. goto exit_label;
  5196. end;
  5197. end;
  5198. token:=_GT;
  5199. end;
  5200. goto exit_label;
  5201. end;
  5202. '<' :
  5203. begin
  5204. readchar;
  5205. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  5206. token:=_LSHARPBRACKET
  5207. else
  5208. begin
  5209. case c of
  5210. '>' :
  5211. begin
  5212. readchar;
  5213. token:=_NE;
  5214. goto exit_label;
  5215. end;
  5216. '=' :
  5217. begin
  5218. readchar;
  5219. token:=_LTE;
  5220. goto exit_label;
  5221. end;
  5222. '<' :
  5223. begin
  5224. readchar;
  5225. token:=_OP_SHL;
  5226. goto exit_label;
  5227. end;
  5228. end;
  5229. token:=_LT;
  5230. end;
  5231. goto exit_label;
  5232. end;
  5233. #26 :
  5234. begin
  5235. token:=_EOF;
  5236. checkpreprocstack;
  5237. goto exit_label;
  5238. end;
  5239. else if inputfile.internally_generated_macro and
  5240. (c in [internal_macro_escape_begin..internal_macro_escape_end]) then
  5241. begin
  5242. token:=_ID;
  5243. readstring;
  5244. end
  5245. else
  5246. Illegal_Char(c);
  5247. end;
  5248. end;
  5249. exit_label:
  5250. lasttoken:=token;
  5251. end;
  5252. function tscannerfile.readpreproc:ttoken;
  5253. var
  5254. low,high,mid: longint;
  5255. optoken: ttoken;
  5256. begin
  5257. skipspace;
  5258. case c of
  5259. '_',
  5260. 'A'..'Z',
  5261. 'a'..'z' :
  5262. begin
  5263. readstring;
  5264. optoken:=_ID;
  5265. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  5266. begin
  5267. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  5268. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  5269. while low<high do
  5270. begin
  5271. mid:=(high+low+1) shr 1;
  5272. if pattern<tokeninfo^[ttoken(mid)].str then
  5273. high:=mid-1
  5274. else
  5275. low:=mid;
  5276. end;
  5277. with tokeninfo^[ttoken(high)] do
  5278. if pattern=str then
  5279. begin
  5280. if (keyword*current_settings.modeswitches)<>[] then
  5281. if op=NOTOKEN then
  5282. optoken:=ttoken(high)
  5283. else
  5284. optoken:=op;
  5285. end;
  5286. if not (optoken in preproc_operators) then
  5287. optoken:=_ID;
  5288. end;
  5289. current_scanner.preproc_pattern:=pattern;
  5290. readpreproc:=optoken;
  5291. end;
  5292. '''' :
  5293. begin
  5294. readquotedstring;
  5295. current_scanner.preproc_pattern:=cstringpattern;
  5296. readpreproc:=_CSTRING;
  5297. end;
  5298. '0'..'9' :
  5299. begin
  5300. readnumber;
  5301. if (c in ['.','e','E']) then
  5302. begin
  5303. { first check for a . }
  5304. if c='.' then
  5305. begin
  5306. readchar;
  5307. if c in ['0'..'9'] then
  5308. begin
  5309. { insert the number after the . }
  5310. pattern:=pattern+'.';
  5311. while c in ['0'..'9'] do
  5312. begin
  5313. pattern:=pattern+c;
  5314. readchar;
  5315. end;
  5316. end
  5317. else
  5318. Illegal_Char(c);
  5319. end;
  5320. { E can also follow after a point is scanned }
  5321. if c in ['e','E'] then
  5322. begin
  5323. pattern:=pattern+'E';
  5324. readchar;
  5325. if c in ['-','+'] then
  5326. begin
  5327. pattern:=pattern+c;
  5328. readchar;
  5329. end;
  5330. if not(c in ['0'..'9']) then
  5331. Illegal_Char(c);
  5332. while c in ['0'..'9'] do
  5333. begin
  5334. pattern:=pattern+c;
  5335. readchar;
  5336. end;
  5337. end;
  5338. readpreproc:=_REALNUMBER;
  5339. end
  5340. else
  5341. readpreproc:=_INTCONST;
  5342. current_scanner.preproc_pattern:=pattern;
  5343. end;
  5344. '$','%':
  5345. begin
  5346. readnumber;
  5347. current_scanner.preproc_pattern:=pattern;
  5348. readpreproc:=_INTCONST;
  5349. end;
  5350. '&' :
  5351. begin
  5352. readnumber;
  5353. if length(pattern)=1 then
  5354. begin
  5355. readstring;
  5356. readpreproc:=_ID;
  5357. end
  5358. else
  5359. readpreproc:=_INTCONST;
  5360. current_scanner.preproc_pattern:=pattern;
  5361. end;
  5362. '.' :
  5363. begin
  5364. readchar;
  5365. readpreproc:=_POINT;
  5366. end;
  5367. ',' :
  5368. begin
  5369. readchar;
  5370. readpreproc:=_COMMA;
  5371. end;
  5372. '}' :
  5373. begin
  5374. readpreproc:=_END;
  5375. end;
  5376. '(' :
  5377. begin
  5378. readchar;
  5379. readpreproc:=_LKLAMMER;
  5380. end;
  5381. ')' :
  5382. begin
  5383. readchar;
  5384. readpreproc:=_RKLAMMER;
  5385. end;
  5386. '[' :
  5387. begin
  5388. readchar;
  5389. readpreproc:=_LECKKLAMMER;
  5390. end;
  5391. ']' :
  5392. begin
  5393. readchar;
  5394. readpreproc:=_RECKKLAMMER;
  5395. end;
  5396. '+' :
  5397. begin
  5398. readchar;
  5399. readpreproc:=_PLUS;
  5400. end;
  5401. '-' :
  5402. begin
  5403. readchar;
  5404. readpreproc:=_MINUS;
  5405. end;
  5406. '*' :
  5407. begin
  5408. readchar;
  5409. readpreproc:=_STAR;
  5410. end;
  5411. '/' :
  5412. begin
  5413. readchar;
  5414. readpreproc:=_SLASH;
  5415. end;
  5416. '=' :
  5417. begin
  5418. readchar;
  5419. readpreproc:=_EQ;
  5420. end;
  5421. '>' :
  5422. begin
  5423. readchar;
  5424. if c='=' then
  5425. begin
  5426. readchar;
  5427. readpreproc:=_GTE;
  5428. end
  5429. else
  5430. readpreproc:=_GT;
  5431. end;
  5432. '<' :
  5433. begin
  5434. readchar;
  5435. case c of
  5436. '>' :
  5437. begin
  5438. readchar;
  5439. readpreproc:=_NE;
  5440. end;
  5441. '=' :
  5442. begin
  5443. readchar;
  5444. readpreproc:=_LTE;
  5445. end;
  5446. else
  5447. readpreproc:=_LT;
  5448. end;
  5449. end;
  5450. #26 :
  5451. begin
  5452. readpreproc:=_EOF;
  5453. checkpreprocstack;
  5454. end;
  5455. else
  5456. begin
  5457. Illegal_Char(c);
  5458. readpreproc:=NOTOKEN;
  5459. end;
  5460. end;
  5461. end;
  5462. function tscannerfile.readpreprocint(var value:int64;const place:string):boolean;
  5463. var
  5464. hs : texprvalue;
  5465. begin
  5466. hs:=preproc_comp_expr;
  5467. if hs.isInt then
  5468. begin
  5469. value:=hs.asInt64;
  5470. result:=true;
  5471. end
  5472. else
  5473. begin
  5474. hs.error('Integer',place);
  5475. result:=false;
  5476. end;
  5477. hs.free;
  5478. end;
  5479. function tscannerfile.asmgetchar : char;
  5480. begin
  5481. readchar;
  5482. repeat
  5483. case c of
  5484. #26 :
  5485. begin
  5486. reload;
  5487. if (c=#26) and not assigned(inputfile.next) then
  5488. end_of_file;
  5489. continue;
  5490. end;
  5491. else
  5492. begin
  5493. asmgetchar:=c;
  5494. exit;
  5495. end;
  5496. end;
  5497. until false;
  5498. end;
  5499. {*****************************************************************************
  5500. Helpers
  5501. *****************************************************************************}
  5502. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5503. begin
  5504. if dm in [directive_all, directive_turbo] then
  5505. tdirectiveitem.create(turbo_scannerdirectives,s,p);
  5506. if dm in [directive_all, directive_mac] then
  5507. tdirectiveitem.create(mac_scannerdirectives,s,p);
  5508. end;
  5509. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5510. begin
  5511. if dm in [directive_all, directive_turbo] then
  5512. tdirectiveitem.createcond(turbo_scannerdirectives,s,p);
  5513. if dm in [directive_all, directive_mac] then
  5514. tdirectiveitem.createcond(mac_scannerdirectives,s,p);
  5515. end;
  5516. {*****************************************************************************
  5517. Initialization
  5518. *****************************************************************************}
  5519. procedure InitScanner;
  5520. begin
  5521. InitWideString(patternw);
  5522. turbo_scannerdirectives:=TFPHashObjectList.Create;
  5523. mac_scannerdirectives:=TFPHashObjectList.Create;
  5524. { Common directives and conditionals }
  5525. AddDirective('I',directive_all, @dir_include);
  5526. AddDirective('DEFINE',directive_all, @dir_define);
  5527. AddDirective('UNDEF',directive_all, @dir_undef);
  5528. AddConditional('IF',directive_all, @dir_if);
  5529. AddConditional('IFDEF',directive_all, @dir_ifdef);
  5530. AddConditional('IFNDEF',directive_all, @dir_ifndef);
  5531. AddConditional('ELSE',directive_all, @dir_else);
  5532. AddConditional('ELSEIF',directive_all, @dir_elseif);
  5533. AddConditional('ENDIF',directive_all, @dir_endif);
  5534. { Directives and conditionals for all modes except mode macpas}
  5535. AddDirective('INCLUDE',directive_turbo, @dir_include);
  5536. AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
  5537. AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
  5538. AddDirective('EXTENSION',directive_turbo, @dir_extension);
  5539. AddConditional('IFEND',directive_turbo, @dir_ifend);
  5540. AddConditional('IFOPT',directive_turbo, @dir_ifopt);
  5541. { Directives and conditionals for mode macpas: }
  5542. AddDirective('SETC',directive_mac, @dir_setc);
  5543. AddDirective('DEFINEC',directive_mac, @dir_definec);
  5544. AddDirective('UNDEFC',directive_mac, @dir_undef);
  5545. AddConditional('IFC',directive_mac, @dir_if);
  5546. AddConditional('ELSEC',directive_mac, @dir_else);
  5547. AddConditional('ELIFC',directive_mac, @dir_elseif);
  5548. AddConditional('ENDC',directive_mac, @dir_endif);
  5549. end;
  5550. procedure DoneScanner;
  5551. begin
  5552. turbo_scannerdirectives.Free;
  5553. mac_scannerdirectives.Free;
  5554. DoneWideString(patternw);
  5555. end;
  5556. end.