scanner.pas 202 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957
  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. begin
  3365. with inputfile do
  3366. begin
  3367. { when nothing more to read then leave immediatly, so we
  3368. don't change the current_filepos and leave it point to the last
  3369. char }
  3370. if (c=#26) and (not assigned(next)) then
  3371. exit;
  3372. repeat
  3373. { still more to read?, then change the #0 to a space so its seen
  3374. as a separator, this can't be used for macro's which can change
  3375. the place of the #0 in the buffer with tempopen }
  3376. if (c=#0) and (bufsize>0) and
  3377. not(inputfile.is_macro) and
  3378. (inputpointer-inputbuffer<bufsize) then
  3379. begin
  3380. c:=' ';
  3381. inc(inputpointer);
  3382. exit;
  3383. end;
  3384. { can we read more from this file ? }
  3385. if (c<>#26) and (not endoffile) then
  3386. begin
  3387. readbuf;
  3388. inputpointer:=buf;
  3389. inputbuffer:=buf;
  3390. inputstart:=bufstart;
  3391. { first line? }
  3392. if line_no=0 then
  3393. begin
  3394. c:=inputpointer^;
  3395. { eat utf-8 signature? }
  3396. if (ord(inputpointer^)=$ef) and
  3397. (ord((inputpointer+1)^)=$bb) and
  3398. (ord((inputpointer+2)^)=$bf) then
  3399. begin
  3400. (* we don't support including files with an UTF-8 bom
  3401. inside another file that wasn't encoded as UTF-8
  3402. already (we don't support {$codepage xxx} switches in
  3403. the middle of a file either) *)
  3404. if (current_settings.sourcecodepage<>CP_UTF8) and
  3405. not current_module.in_global then
  3406. Message(scanner_f_illegal_utf8_bom);
  3407. inc(inputpointer,3);
  3408. message(scan_c_switching_to_utf8);
  3409. current_settings.sourcecodepage:=CP_UTF8;
  3410. exclude(current_settings.moduleswitches,cs_system_codepage);
  3411. include(current_settings.moduleswitches,cs_explicit_codepage);
  3412. end;
  3413. line_no:=1;
  3414. if cs_asm_source in current_settings.globalswitches then
  3415. inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);
  3416. end;
  3417. end
  3418. else
  3419. begin
  3420. { load eof position in tokenpos/current_filepos }
  3421. gettokenpos;
  3422. { close file }
  3423. closeinputfile;
  3424. { no next module, than EOF }
  3425. if not assigned(inputfile.next) then
  3426. begin
  3427. c:=#26;
  3428. exit;
  3429. end;
  3430. { load next file and reopen it }
  3431. nextfile;
  3432. tempopeninputfile;
  3433. { status }
  3434. Message1(scan_t_back_in,inputfile.name);
  3435. end;
  3436. { load next char }
  3437. c:=inputpointer^;
  3438. inc(inputpointer);
  3439. until c<>#0; { if also end, then reload again }
  3440. end;
  3441. end;
  3442. procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint;internally_generated: boolean);
  3443. var
  3444. hp : tinputfile;
  3445. begin
  3446. { save old postion }
  3447. dec(inputpointer);
  3448. tempcloseinputfile;
  3449. { create macro 'file' }
  3450. { use special name to dispose after !! }
  3451. hp:=do_openinputfile('_Macro_.'+macname);
  3452. addfile(hp);
  3453. with inputfile do
  3454. begin
  3455. inc(macro_nesting_depth);
  3456. setmacro(p,len);
  3457. { local buffer }
  3458. inputbuffer:=buf;
  3459. inputpointer:=buf;
  3460. inputstart:=bufstart;
  3461. ref_index:=fileindex;
  3462. internally_generated_macro:=internally_generated;
  3463. end;
  3464. { reset line }
  3465. line_no:=line;
  3466. lastlinepos:=0;
  3467. lasttokenpos:=0;
  3468. nexttokenpos:=0;
  3469. { load new c }
  3470. c:=inputpointer^;
  3471. inc(inputpointer);
  3472. end;
  3473. procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
  3474. begin
  3475. tokenpos:=inputstart+(inputpointer-inputbuffer);
  3476. filepos.line:=line_no;
  3477. filepos.column:=tokenpos-lastlinepos;
  3478. filepos.fileindex:=inputfile.ref_index;
  3479. filepos.moduleindex:=current_module.unit_index;
  3480. end;
  3481. procedure tscannerfile.gettokenpos;
  3482. { load the values of tokenpos and lasttokenpos }
  3483. begin
  3484. do_gettokenpos(lasttokenpos,current_tokenpos);
  3485. current_filepos:=current_tokenpos;
  3486. end;
  3487. procedure tscannerfile.cachenexttokenpos;
  3488. begin
  3489. do_gettokenpos(nexttokenpos,next_filepos);
  3490. end;
  3491. procedure tscannerfile.setnexttoken;
  3492. begin
  3493. token:=nexttoken;
  3494. nexttoken:=NOTOKEN;
  3495. lasttokenpos:=nexttokenpos;
  3496. current_tokenpos:=next_filepos;
  3497. current_filepos:=current_tokenpos;
  3498. nexttokenpos:=0;
  3499. end;
  3500. procedure tscannerfile.savetokenpos;
  3501. begin
  3502. oldlasttokenpos:=lasttokenpos;
  3503. oldcurrent_filepos:=current_filepos;
  3504. oldcurrent_tokenpos:=current_tokenpos;
  3505. end;
  3506. procedure tscannerfile.restoretokenpos;
  3507. begin
  3508. lasttokenpos:=oldlasttokenpos;
  3509. current_filepos:=oldcurrent_filepos;
  3510. current_tokenpos:=oldcurrent_tokenpos;
  3511. end;
  3512. procedure tscannerfile.inc_comment_level;
  3513. begin
  3514. if (m_nested_comment in current_settings.modeswitches) then
  3515. inc(comment_level)
  3516. else
  3517. comment_level:=1;
  3518. if (comment_level>1) then
  3519. begin
  3520. savetokenpos;
  3521. gettokenpos; { update for warning }
  3522. Message1(scan_w_comment_level,tostr(comment_level));
  3523. restoretokenpos;
  3524. end;
  3525. end;
  3526. procedure tscannerfile.dec_comment_level;
  3527. begin
  3528. if (m_nested_comment in current_settings.modeswitches) then
  3529. dec(comment_level)
  3530. else
  3531. comment_level:=0;
  3532. end;
  3533. procedure tscannerfile.linebreak;
  3534. var
  3535. cur : char;
  3536. begin
  3537. with inputfile do
  3538. begin
  3539. if (byte(inputpointer^)=0) and not(endoffile) then
  3540. begin
  3541. cur:=c;
  3542. reload;
  3543. if byte(cur)+byte(c)<>23 then
  3544. dec(inputpointer);
  3545. end
  3546. else
  3547. begin
  3548. { Support all combination of #10 and #13 as line break }
  3549. if (byte(inputpointer^)+byte(c)=23) then
  3550. inc(inputpointer);
  3551. end;
  3552. { Always return #10 as line break }
  3553. c:=#10;
  3554. { increase line counters }
  3555. lastlinepos:=inputstart+(inputpointer-inputbuffer);
  3556. inc(line_no);
  3557. { update linebuffer }
  3558. if cs_asm_source in current_settings.globalswitches then
  3559. inputfile.setline(line_no,lastlinepos);
  3560. { update for status and call the show status routine,
  3561. but don't touch current_filepos ! }
  3562. savetokenpos;
  3563. gettokenpos; { update for v_status }
  3564. inc(status.compiledlines);
  3565. ShowStatus;
  3566. restoretokenpos;
  3567. end;
  3568. end;
  3569. procedure tscannerfile.illegal_char(c:char);
  3570. var
  3571. s : string;
  3572. begin
  3573. if c in [#32..#255] then
  3574. s:=''''+c+''''
  3575. else
  3576. s:='#'+tostr(ord(c));
  3577. Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
  3578. end;
  3579. procedure tscannerfile.end_of_file;
  3580. begin
  3581. checkpreprocstack;
  3582. Message(scan_f_end_of_file);
  3583. end;
  3584. {-------------------------------------------
  3585. IF Conditional Handling
  3586. -------------------------------------------}
  3587. procedure tscannerfile.checkpreprocstack;
  3588. begin
  3589. { check for missing ifdefs }
  3590. while assigned(preprocstack) do
  3591. begin
  3592. Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
  3593. current_module.sourcefiles.get_file_name(preprocstack.fileindex),
  3594. tostr(preprocstack.line_nb));
  3595. poppreprocstack;
  3596. end;
  3597. end;
  3598. procedure tscannerfile.poppreprocstack;
  3599. var
  3600. hp : tpreprocstack;
  3601. begin
  3602. if assigned(preprocstack) then
  3603. begin
  3604. Message1(scan_c_endif_found,preprocstack.name);
  3605. hp:=preprocstack.next;
  3606. preprocstack.free;
  3607. preprocstack:=hp;
  3608. end
  3609. else
  3610. Message(scan_e_endif_without_if);
  3611. end;
  3612. procedure tscannerfile.ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
  3613. var
  3614. condition: Boolean;
  3615. valuedescr: String;
  3616. begin
  3617. if (preprocstack=nil) or preprocstack.accept then
  3618. condition:=compile_time_predicate(valuedescr)
  3619. else
  3620. begin
  3621. condition:= false;
  3622. valuedescr:= '';
  3623. end;
  3624. preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
  3625. preprocstack.name:=valuedescr;
  3626. preprocstack.line_nb:=line_no;
  3627. preprocstack.fileindex:=current_filepos.fileindex;
  3628. if preprocstack.accept then
  3629. Message2(messid,preprocstack.name,'accepted')
  3630. else
  3631. Message2(messid,preprocstack.name,'rejected');
  3632. end;
  3633. procedure tscannerfile.elsepreprocstack;
  3634. begin
  3635. if assigned(preprocstack) and
  3636. (preprocstack.typ<>pp_else) then
  3637. begin
  3638. if (preprocstack.typ=pp_elseif) then
  3639. preprocstack.accept:=false
  3640. else
  3641. if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
  3642. preprocstack.accept:=not preprocstack.accept;
  3643. preprocstack.iftyp:=preprocstack.typ;
  3644. preprocstack.typ:=pp_else;
  3645. preprocstack.line_nb:=line_no;
  3646. preprocstack.fileindex:=current_filepos.fileindex;
  3647. if preprocstack.accept then
  3648. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3649. else
  3650. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3651. end
  3652. else
  3653. Message(scan_e_endif_without_if);
  3654. end;
  3655. procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
  3656. var
  3657. valuedescr: String;
  3658. begin
  3659. if assigned(preprocstack) and
  3660. (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef,pp_elseif]) then
  3661. begin
  3662. { when the branch is accepted we use pp_elseif so we know that
  3663. all the next branches need to be rejected. when this branch is still
  3664. not accepted then leave it at pp_if }
  3665. if (preprocstack.typ=pp_elseif) then
  3666. preprocstack.accept:=false
  3667. else if (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef]) and preprocstack.accept then
  3668. begin
  3669. preprocstack.accept:=false;
  3670. preprocstack.typ:=pp_elseif;
  3671. end
  3672. else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
  3673. and compile_time_predicate(valuedescr) then
  3674. begin
  3675. preprocstack.name:=valuedescr;
  3676. preprocstack.accept:=true;
  3677. preprocstack.typ:=pp_elseif;
  3678. end;
  3679. preprocstack.line_nb:=line_no;
  3680. preprocstack.fileindex:=current_filepos.fileindex;
  3681. if preprocstack.accept then
  3682. Message2(scan_c_else_found,preprocstack.name,'accepted')
  3683. else
  3684. Message2(scan_c_else_found,preprocstack.name,'rejected');
  3685. end
  3686. else
  3687. Message(scan_e_endif_without_if);
  3688. end;
  3689. procedure tscannerfile.popreplaystack;
  3690. var
  3691. hp : treplaystack;
  3692. begin
  3693. if assigned(replaystack) then
  3694. begin
  3695. hp:=replaystack.next;
  3696. replaystack.free;
  3697. replaystack:=hp;
  3698. end;
  3699. end;
  3700. function tscannerfile.replay_stack_depth:longint;
  3701. var
  3702. tmp: treplaystack;
  3703. begin
  3704. result:=0;
  3705. tmp:=replaystack;
  3706. while assigned(tmp) do
  3707. begin
  3708. inc(result);
  3709. tmp:=tmp.next;
  3710. end;
  3711. end;
  3712. procedure tscannerfile.handleconditional(p:tdirectiveitem);
  3713. begin
  3714. savetokenpos;
  3715. repeat
  3716. current_scanner.gettokenpos;
  3717. Message1(scan_d_handling_switch,'$'+p.name);
  3718. p.proc();
  3719. { accept the text ? }
  3720. if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
  3721. break
  3722. else
  3723. begin
  3724. current_scanner.gettokenpos;
  3725. Message(scan_c_skipping_until);
  3726. repeat
  3727. current_scanner.skipuntildirective;
  3728. if not (m_mac in current_settings.modeswitches) then
  3729. p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))
  3730. else
  3731. p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));
  3732. until assigned(p) and (p.is_conditional);
  3733. current_scanner.gettokenpos;
  3734. end;
  3735. until false;
  3736. restoretokenpos;
  3737. end;
  3738. procedure tscannerfile.handledirectives;
  3739. var
  3740. t : tdirectiveitem;
  3741. hs : string;
  3742. begin
  3743. gettokenpos;
  3744. readchar; {Remove the $}
  3745. hs:=readid;
  3746. { handle empty directive }
  3747. if hs='' then
  3748. begin
  3749. Message1(scan_w_illegal_switch,'$');
  3750. exit;
  3751. end;
  3752. {$ifdef PREPROCWRITE}
  3753. if parapreprocess then
  3754. begin
  3755. if not (m_mac in current_settings.modeswitches) then
  3756. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  3757. else
  3758. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  3759. if assigned(t) and not(t.is_conditional) then
  3760. begin
  3761. preprocfile.AddSpace;
  3762. preprocfile.Add('{$'+hs+current_scanner.readcomment+'}');
  3763. exit;
  3764. end;
  3765. end;
  3766. {$endif PREPROCWRITE}
  3767. { skip this directive? }
  3768. if (ignoredirectives.find(hs)<>nil) then
  3769. begin
  3770. if (comment_level>0) then
  3771. readcomment;
  3772. { we've read the whole comment }
  3773. current_commentstyle:=comment_none;
  3774. exit;
  3775. end;
  3776. { Check for compiler switches }
  3777. while (length(hs)=1) and (c in ['-','+']) do
  3778. begin
  3779. Message1(scan_d_handling_switch,'$'+hs+c);
  3780. HandleSwitch(hs[1],c);
  3781. current_scanner.readchar; {Remove + or -}
  3782. if c=',' then
  3783. begin
  3784. current_scanner.readchar; {Remove , }
  3785. { read next switch, support $v+,$+}
  3786. hs:=current_scanner.readid;
  3787. if (hs='') then
  3788. begin
  3789. if (c='$') and (m_fpc in current_settings.modeswitches) then
  3790. begin
  3791. current_scanner.readchar; { skip $ }
  3792. hs:=current_scanner.readid;
  3793. end;
  3794. if (hs='') then
  3795. Message1(scan_w_illegal_directive,'$'+c);
  3796. end;
  3797. end
  3798. else
  3799. hs:='';
  3800. end;
  3801. { directives may follow switches after a , }
  3802. if hs<>'' then
  3803. begin
  3804. if not (m_mac in current_settings.modeswitches) then
  3805. t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
  3806. else
  3807. t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
  3808. if assigned(t) then
  3809. begin
  3810. if t.is_conditional then
  3811. handleconditional(t)
  3812. else
  3813. begin
  3814. Message1(scan_d_handling_switch,'$'+hs);
  3815. t.proc();
  3816. end;
  3817. end
  3818. else
  3819. begin
  3820. current_scanner.ignoredirectives.Add(hs,nil);
  3821. Message1(scan_w_illegal_directive,'$'+hs);
  3822. end;
  3823. { conditionals already read the comment }
  3824. if (current_scanner.comment_level>0) then
  3825. current_scanner.readcomment;
  3826. { we've read the whole comment }
  3827. current_commentstyle:=comment_none;
  3828. end;
  3829. end;
  3830. procedure tscannerfile.readchar;
  3831. begin
  3832. c:=inputpointer^;
  3833. if c=#0 then
  3834. reload
  3835. else
  3836. inc(inputpointer);
  3837. end;
  3838. procedure tscannerfile.readstring;
  3839. var
  3840. i : longint;
  3841. err : boolean;
  3842. begin
  3843. err:=false;
  3844. i:=0;
  3845. repeat
  3846. case c of
  3847. '_',
  3848. '0'..'9',
  3849. 'A'..'Z',
  3850. 'a'..'z' :
  3851. begin
  3852. if i<255 then
  3853. begin
  3854. inc(i);
  3855. orgpattern[i]:=c;
  3856. if c in ['a'..'z'] then
  3857. pattern[i]:=chr(ord(c)-32)
  3858. else
  3859. pattern[i]:=c;
  3860. end
  3861. else
  3862. begin
  3863. if not err then
  3864. begin
  3865. Message(scan_e_string_exceeds_255_chars);
  3866. err:=true;
  3867. end;
  3868. end;
  3869. c:=inputpointer^;
  3870. inc(inputpointer);
  3871. end;
  3872. #0 :
  3873. reload;
  3874. else if inputfile.internally_generated_macro and
  3875. (c in [internal_macro_escape_begin..internal_macro_escape_end]) then
  3876. begin
  3877. if i<255 then
  3878. begin
  3879. inc(i);
  3880. orgpattern[i]:=c;
  3881. pattern[i]:=c;
  3882. end
  3883. else
  3884. begin
  3885. if not err then
  3886. begin
  3887. Message(scan_e_string_exceeds_255_chars);
  3888. err:=true;
  3889. end;
  3890. end;
  3891. c:=inputpointer^;
  3892. inc(inputpointer);
  3893. end
  3894. else
  3895. break;
  3896. end;
  3897. until false;
  3898. orgpattern[0]:=chr(i);
  3899. pattern[0]:=chr(i);
  3900. end;
  3901. procedure tscannerfile.readnumber;
  3902. var
  3903. base,
  3904. i : longint;
  3905. firstdigitread: Boolean;
  3906. begin
  3907. case c of
  3908. '%' :
  3909. begin
  3910. readchar;
  3911. base:=2;
  3912. pattern[1]:='%';
  3913. i:=1;
  3914. end;
  3915. '&' :
  3916. begin
  3917. readchar;
  3918. base:=8;
  3919. pattern[1]:='&';
  3920. i:=1;
  3921. end;
  3922. '$' :
  3923. begin
  3924. readchar;
  3925. base:=16;
  3926. pattern[1]:='$';
  3927. i:=1;
  3928. end;
  3929. else
  3930. begin
  3931. base:=10;
  3932. i:=0;
  3933. end;
  3934. end;
  3935. firstdigitread:=false;
  3936. while ((base>=10) and (c in ['0'..'9'])) or
  3937. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  3938. ((base=8) and (c in ['0'..'7'])) or
  3939. ((base=2) and (c in ['0'..'1'])) or
  3940. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  3941. begin
  3942. if (i<255) and (c<>'_') then
  3943. begin
  3944. inc(i);
  3945. pattern[i]:=c;
  3946. end;
  3947. readchar;
  3948. firstdigitread:=true;
  3949. end;
  3950. pattern[0]:=chr(i);
  3951. end;
  3952. function tscannerfile.readid:string;
  3953. begin
  3954. readstring;
  3955. readid:=pattern;
  3956. end;
  3957. function tscannerfile.readval:longint;
  3958. var
  3959. l : longint;
  3960. w : integer;
  3961. begin
  3962. readnumber;
  3963. val(pattern,l,w);
  3964. readval:=l;
  3965. end;
  3966. function tscannerfile.readcomment(include_special_char: boolean):string;
  3967. var
  3968. i : longint;
  3969. begin
  3970. i:=0;
  3971. repeat
  3972. case c of
  3973. '{' :
  3974. begin
  3975. if (include_special_char) and (i<255) then
  3976. begin
  3977. inc(i);
  3978. readcomment[i]:=c;
  3979. end;
  3980. if current_commentstyle=comment_tp then
  3981. inc_comment_level;
  3982. end;
  3983. '}' :
  3984. begin
  3985. if (include_special_char) and (i<255) then
  3986. begin
  3987. inc(i);
  3988. readcomment[i]:=c;
  3989. end;
  3990. if current_commentstyle=comment_tp then
  3991. begin
  3992. readchar;
  3993. dec_comment_level;
  3994. if comment_level=0 then
  3995. break
  3996. else
  3997. continue;
  3998. end;
  3999. end;
  4000. '*' :
  4001. begin
  4002. if current_commentstyle=comment_oldtp then
  4003. begin
  4004. readchar;
  4005. if c=')' then
  4006. begin
  4007. readchar;
  4008. dec_comment_level;
  4009. break;
  4010. end
  4011. else
  4012. { Add both characters !!}
  4013. if (i<255) then
  4014. begin
  4015. inc(i);
  4016. readcomment[i]:='*';
  4017. if (i<255) then
  4018. begin
  4019. inc(i);
  4020. readcomment[i]:=c;
  4021. end;
  4022. end;
  4023. end
  4024. else
  4025. { Not old TP comment, so add...}
  4026. begin
  4027. if (i<255) then
  4028. begin
  4029. inc(i);
  4030. readcomment[i]:='*';
  4031. end;
  4032. end;
  4033. end;
  4034. #10,#13 :
  4035. linebreak;
  4036. #26 :
  4037. end_of_file;
  4038. else
  4039. begin
  4040. if (i<255) then
  4041. begin
  4042. inc(i);
  4043. readcomment[i]:=c;
  4044. end;
  4045. end;
  4046. end;
  4047. readchar;
  4048. until false;
  4049. readcomment[0]:=chr(i);
  4050. end;
  4051. function tscannerfile.readquotedstring:string;
  4052. var
  4053. i : longint;
  4054. msgwritten : boolean;
  4055. begin
  4056. i:=0;
  4057. msgwritten:=false;
  4058. if (c='''') then
  4059. begin
  4060. repeat
  4061. readchar;
  4062. case c of
  4063. #26 :
  4064. end_of_file;
  4065. #10,#13 :
  4066. Message(scan_f_string_exceeds_line);
  4067. '''' :
  4068. begin
  4069. readchar;
  4070. if c<>'''' then
  4071. break;
  4072. end;
  4073. end;
  4074. if i<255 then
  4075. begin
  4076. inc(i);
  4077. result[i]:=c;
  4078. end
  4079. else
  4080. begin
  4081. if not msgwritten then
  4082. begin
  4083. Message(scan_e_string_exceeds_255_chars);
  4084. msgwritten:=true;
  4085. end;
  4086. end;
  4087. until false;
  4088. end;
  4089. result[0]:=chr(i);
  4090. end;
  4091. function tscannerfile.readstate:char;
  4092. var
  4093. state : char;
  4094. begin
  4095. state:=' ';
  4096. if c=' ' then
  4097. begin
  4098. current_scanner.skipspace;
  4099. current_scanner.readid;
  4100. if pattern='ON' then
  4101. state:='+'
  4102. else
  4103. if pattern='OFF' then
  4104. state:='-';
  4105. end
  4106. else
  4107. state:=c;
  4108. if not (state in ['+','-']) then
  4109. Message(scan_e_wrong_switch_toggle);
  4110. readstate:=state;
  4111. end;
  4112. function tscannerfile.readoptionalstate(fallback:char):char;
  4113. var
  4114. state : char;
  4115. begin
  4116. state:=' ';
  4117. if c=' ' then
  4118. begin
  4119. current_scanner.skipspace;
  4120. if c in ['*','}'] then
  4121. state:=fallback
  4122. else
  4123. begin
  4124. current_scanner.readid;
  4125. if pattern='ON' then
  4126. state:='+'
  4127. else
  4128. if pattern='OFF' then
  4129. state:='-';
  4130. end;
  4131. end
  4132. else
  4133. if c in ['*','}'] then
  4134. state:=fallback
  4135. else
  4136. state:=c;
  4137. if not (state in ['+','-']) then
  4138. Message(scan_e_wrong_switch_toggle);
  4139. readoptionalstate:=state;
  4140. end;
  4141. function tscannerfile.readstatedefault:char;
  4142. var
  4143. state : char;
  4144. begin
  4145. state:=' ';
  4146. if c=' ' then
  4147. begin
  4148. current_scanner.skipspace;
  4149. current_scanner.readid;
  4150. if pattern='ON' then
  4151. state:='+'
  4152. else
  4153. if pattern='OFF' then
  4154. state:='-'
  4155. else
  4156. if pattern='DEFAULT' then
  4157. state:='*';
  4158. end
  4159. else
  4160. state:=c;
  4161. if not (state in ['+','-','*']) then
  4162. Message(scan_e_wrong_switch_toggle_default);
  4163. readstatedefault:=state;
  4164. end;
  4165. procedure tscannerfile.skipspace;
  4166. begin
  4167. repeat
  4168. case c of
  4169. #26 :
  4170. begin
  4171. reload;
  4172. if (c=#26) and not assigned(inputfile.next) then
  4173. break;
  4174. continue;
  4175. end;
  4176. #10,
  4177. #13 :
  4178. linebreak;
  4179. #9,#11,#12,' ' :
  4180. ;
  4181. else
  4182. break;
  4183. end;
  4184. readchar;
  4185. until false;
  4186. end;
  4187. procedure tscannerfile.skipuntildirective;
  4188. var
  4189. found : longint;
  4190. next_char_loaded : boolean;
  4191. begin
  4192. found:=0;
  4193. next_char_loaded:=false;
  4194. repeat
  4195. case c of
  4196. #10,
  4197. #13 :
  4198. linebreak;
  4199. #26 :
  4200. begin
  4201. reload;
  4202. if (c=#26) and not assigned(inputfile.next) then
  4203. end_of_file;
  4204. continue;
  4205. end;
  4206. '{' :
  4207. begin
  4208. if (current_commentstyle in [comment_tp,comment_none]) then
  4209. begin
  4210. current_commentstyle:=comment_tp;
  4211. if (comment_level=0) then
  4212. found:=1;
  4213. inc_comment_level;
  4214. end;
  4215. end;
  4216. '*' :
  4217. begin
  4218. if (current_commentstyle=comment_oldtp) then
  4219. begin
  4220. readchar;
  4221. if c=')' then
  4222. begin
  4223. dec_comment_level;
  4224. found:=0;
  4225. current_commentstyle:=comment_none;
  4226. end
  4227. else
  4228. next_char_loaded:=true;
  4229. end
  4230. else
  4231. found := 0;
  4232. end;
  4233. '}' :
  4234. begin
  4235. if (current_commentstyle=comment_tp) then
  4236. begin
  4237. dec_comment_level;
  4238. if (comment_level=0) then
  4239. current_commentstyle:=comment_none;
  4240. found:=0;
  4241. end;
  4242. end;
  4243. '$' :
  4244. begin
  4245. if found=1 then
  4246. found:=2;
  4247. end;
  4248. '''' :
  4249. if (current_commentstyle=comment_none) then
  4250. begin
  4251. repeat
  4252. readchar;
  4253. case c of
  4254. #26 :
  4255. end_of_file;
  4256. #10,#13 :
  4257. break;
  4258. '''' :
  4259. begin
  4260. readchar;
  4261. if c<>'''' then
  4262. begin
  4263. next_char_loaded:=true;
  4264. break;
  4265. end;
  4266. end;
  4267. end;
  4268. until false;
  4269. end;
  4270. '(' :
  4271. begin
  4272. if (current_commentstyle=comment_none) then
  4273. begin
  4274. readchar;
  4275. if c='*' then
  4276. begin
  4277. readchar;
  4278. if c='$' then
  4279. begin
  4280. found:=2;
  4281. inc_comment_level;
  4282. current_commentstyle:=comment_oldtp;
  4283. end
  4284. else
  4285. begin
  4286. skipoldtpcomment(false);
  4287. next_char_loaded:=true;
  4288. end;
  4289. end
  4290. else
  4291. next_char_loaded:=true;
  4292. end
  4293. else
  4294. found:=0;
  4295. end;
  4296. '/' :
  4297. begin
  4298. if (current_commentstyle=comment_none) then
  4299. begin
  4300. readchar;
  4301. if c='/' then
  4302. skipdelphicomment;
  4303. next_char_loaded:=true;
  4304. end
  4305. else
  4306. found:=0;
  4307. end;
  4308. else
  4309. found:=0;
  4310. end;
  4311. if next_char_loaded then
  4312. next_char_loaded:=false
  4313. else
  4314. readchar;
  4315. until (found=2);
  4316. end;
  4317. {****************************************************************************
  4318. Comment Handling
  4319. ****************************************************************************}
  4320. procedure tscannerfile.skipcomment(read_first_char:boolean);
  4321. begin
  4322. current_commentstyle:=comment_tp;
  4323. if read_first_char then
  4324. readchar;
  4325. inc_comment_level;
  4326. { handle compiler switches }
  4327. if (c='$') then
  4328. handledirectives;
  4329. { handle_switches can dec comment_level, }
  4330. while (comment_level>0) do
  4331. begin
  4332. case c of
  4333. '{' :
  4334. inc_comment_level;
  4335. '}' :
  4336. dec_comment_level;
  4337. '*' :
  4338. { in iso mode, comments opened by a curly bracket can be closed by asterisk, round bracket }
  4339. if m_iso in current_settings.modeswitches then
  4340. begin
  4341. readchar;
  4342. if c=')' then
  4343. dec_comment_level
  4344. else
  4345. continue;
  4346. end;
  4347. #10,#13 :
  4348. linebreak;
  4349. #26 :
  4350. begin
  4351. reload;
  4352. if (c=#26) and not assigned(inputfile.next) then
  4353. end_of_file;
  4354. continue;
  4355. end;
  4356. end;
  4357. readchar;
  4358. end;
  4359. current_commentstyle:=comment_none;
  4360. end;
  4361. procedure tscannerfile.skipdelphicomment;
  4362. begin
  4363. current_commentstyle:=comment_delphi;
  4364. inc_comment_level;
  4365. readchar;
  4366. { this is not supported }
  4367. if c='$' then
  4368. Message(scan_w_wrong_styled_switch);
  4369. { skip comment }
  4370. while not (c in [#10,#13,#26]) do
  4371. readchar;
  4372. dec_comment_level;
  4373. current_commentstyle:=comment_none;
  4374. end;
  4375. procedure tscannerfile.skipoldtpcomment(read_first_char:boolean);
  4376. var
  4377. found : longint;
  4378. begin
  4379. current_commentstyle:=comment_oldtp;
  4380. inc_comment_level;
  4381. { only load a char if last already processed,
  4382. was cause of bug1634 PM }
  4383. if read_first_char then
  4384. readchar;
  4385. { this is now supported }
  4386. if (c='$') then
  4387. handledirectives;
  4388. { skip comment }
  4389. while (comment_level>0) do
  4390. begin
  4391. found:=0;
  4392. repeat
  4393. case c of
  4394. #26 :
  4395. begin
  4396. reload;
  4397. if (c=#26) and not assigned(inputfile.next) then
  4398. end_of_file;
  4399. continue;
  4400. end;
  4401. #10,#13 :
  4402. begin
  4403. if found=4 then
  4404. inc_comment_level;
  4405. linebreak;
  4406. found:=0;
  4407. end;
  4408. '*' :
  4409. begin
  4410. if found=3 then
  4411. found:=4
  4412. else
  4413. begin
  4414. if found=4 then
  4415. inc_comment_level;
  4416. found:=1;
  4417. end;
  4418. end;
  4419. ')' :
  4420. begin
  4421. if found in [1,4] then
  4422. begin
  4423. dec_comment_level;
  4424. if comment_level=0 then
  4425. found:=2
  4426. else
  4427. found:=0;
  4428. end
  4429. else
  4430. found:=0;
  4431. end;
  4432. '}' :
  4433. { in iso mode, comments opened by asterisk, round bracket can be closed by a curly bracket }
  4434. if m_iso in current_settings.modeswitches then
  4435. begin
  4436. dec_comment_level;
  4437. if comment_level=0 then
  4438. found:=2
  4439. else
  4440. found:=0;
  4441. end;
  4442. '(' :
  4443. begin
  4444. if found=4 then
  4445. inc_comment_level;
  4446. found:=3;
  4447. end;
  4448. else
  4449. begin
  4450. if found=4 then
  4451. inc_comment_level;
  4452. found:=0;
  4453. end;
  4454. end;
  4455. readchar;
  4456. until (found=2);
  4457. end;
  4458. current_commentstyle:=comment_none;
  4459. end;
  4460. {****************************************************************************
  4461. Token Scanner
  4462. ****************************************************************************}
  4463. procedure tscannerfile.readtoken(allowrecordtoken:boolean);
  4464. var
  4465. code : integer;
  4466. d : cardinal;
  4467. len,
  4468. low,high,mid : longint;
  4469. w : word;
  4470. m : longint;
  4471. mac : tmacro;
  4472. asciinr : string[33];
  4473. iswidestring , firstdigitread: boolean;
  4474. label
  4475. exit_label;
  4476. begin
  4477. flushpendingswitchesstate;
  4478. { record tokens? }
  4479. if allowrecordtoken and
  4480. assigned(recordtokenbuf) then
  4481. recordtoken;
  4482. { replay tokens? }
  4483. if assigned(replaytokenbuf) then
  4484. begin
  4485. replaytoken;
  4486. goto exit_label;
  4487. end;
  4488. { was there already a token read, then return that token }
  4489. if nexttoken<>NOTOKEN then
  4490. begin
  4491. setnexttoken;
  4492. goto exit_label;
  4493. end;
  4494. { Skip all spaces and comments }
  4495. repeat
  4496. case c of
  4497. '{' :
  4498. skipcomment(true);
  4499. #26 :
  4500. begin
  4501. reload;
  4502. if (c=#26) and not assigned(inputfile.next) then
  4503. break;
  4504. end;
  4505. ' ',#9..#13 :
  4506. begin
  4507. {$ifdef PREPROCWRITE}
  4508. if parapreprocess then
  4509. begin
  4510. if c=#10 then
  4511. preprocfile.eolfound:=true
  4512. else
  4513. preprocfile.spacefound:=true;
  4514. end;
  4515. {$endif PREPROCWRITE}
  4516. skipspace;
  4517. end
  4518. else
  4519. break;
  4520. end;
  4521. until false;
  4522. { Save current token position, for EOF its already loaded }
  4523. if c<>#26 then
  4524. gettokenpos;
  4525. { Check first for a identifier/keyword, this is 20+% faster (PFV) }
  4526. if c in ['A'..'Z','a'..'z','_'] then
  4527. begin
  4528. readstring;
  4529. token:=_ID;
  4530. idtoken:=_ID;
  4531. { keyword or any other known token,
  4532. pattern is always uppercased }
  4533. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  4534. begin
  4535. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  4536. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  4537. while low<high do
  4538. begin
  4539. mid:=(high+low+1) shr 1;
  4540. if pattern<tokeninfo^[ttoken(mid)].str then
  4541. high:=mid-1
  4542. else
  4543. low:=mid;
  4544. end;
  4545. with tokeninfo^[ttoken(high)] do
  4546. if pattern=str then
  4547. begin
  4548. if (keyword*current_settings.modeswitches)<>[] then
  4549. if op=NOTOKEN then
  4550. token:=ttoken(high)
  4551. else
  4552. token:=op;
  4553. idtoken:=ttoken(high);
  4554. end;
  4555. end;
  4556. { Only process identifiers and not keywords }
  4557. if token=_ID then
  4558. begin
  4559. { this takes some time ... }
  4560. if (cs_support_macro in current_settings.moduleswitches) then
  4561. begin
  4562. mac:=tmacro(search_macro(pattern));
  4563. if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
  4564. begin
  4565. if (yylexcount<max_macro_nesting) and (macro_nesting_depth<max_macro_nesting) then
  4566. begin
  4567. mac.is_used:=true;
  4568. inc(yylexcount);
  4569. substitutemacro(pattern,mac.buftext,mac.buflen,
  4570. mac.fileinfo.line,mac.fileinfo.fileindex,false);
  4571. { handle empty macros }
  4572. if c=#0 then
  4573. begin
  4574. reload;
  4575. { avoid macro nesting error in case of
  4576. a sequence of empty macros, see #38802 }
  4577. dec(yylexcount);
  4578. readtoken(false);
  4579. end
  4580. else
  4581. begin
  4582. readtoken(false);
  4583. { that's all folks }
  4584. dec(yylexcount);
  4585. end;
  4586. exit;
  4587. end
  4588. else
  4589. Message(scan_w_macro_too_deep);
  4590. end;
  4591. end;
  4592. end;
  4593. { return token }
  4594. goto exit_label;
  4595. end
  4596. else
  4597. begin
  4598. idtoken:=_NOID;
  4599. case c of
  4600. '$' :
  4601. begin
  4602. readnumber;
  4603. token:=_INTCONST;
  4604. goto exit_label;
  4605. end;
  4606. '%' :
  4607. begin
  4608. if [m_fpc,m_delphi] * current_settings.modeswitches = [] then
  4609. Illegal_Char(c)
  4610. else
  4611. begin
  4612. readnumber;
  4613. token:=_INTCONST;
  4614. goto exit_label;
  4615. end;
  4616. end;
  4617. '&' :
  4618. begin
  4619. if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then
  4620. begin
  4621. readnumber;
  4622. if length(pattern)=1 then
  4623. begin
  4624. { does really an identifier follow? }
  4625. if not (c in ['_','A'..'Z','a'..'z']) then
  4626. message2(scan_f_syn_expected,tokeninfo^[_ID].str,c);
  4627. readstring;
  4628. token:=_ID;
  4629. idtoken:=_ID;
  4630. end
  4631. else
  4632. token:=_INTCONST;
  4633. goto exit_label;
  4634. end
  4635. else if m_mac in current_settings.modeswitches then
  4636. begin
  4637. readchar;
  4638. token:=_AMPERSAND;
  4639. goto exit_label;
  4640. end
  4641. else
  4642. Illegal_Char(c);
  4643. end;
  4644. '0'..'9' :
  4645. begin
  4646. readnumber;
  4647. if (c in ['.','e','E']) then
  4648. begin
  4649. { first check for a . }
  4650. if c='.' then
  4651. begin
  4652. cachenexttokenpos;
  4653. readchar;
  4654. { is it a .. from a range? }
  4655. case c of
  4656. '.' :
  4657. begin
  4658. readchar;
  4659. token:=_INTCONST;
  4660. nexttoken:=_POINTPOINT;
  4661. goto exit_label;
  4662. end;
  4663. ')' :
  4664. begin
  4665. readchar;
  4666. token:=_INTCONST;
  4667. nexttoken:=_RECKKLAMMER;
  4668. goto exit_label;
  4669. end;
  4670. '0'..'9' :
  4671. begin
  4672. { insert the number after the . }
  4673. pattern:=pattern+'.';
  4674. firstdigitread:=false;
  4675. while (c in ['0'..'9']) or
  4676. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  4677. begin
  4678. if c<>'_' then
  4679. pattern:=pattern+c;
  4680. readchar;
  4681. firstdigitread:=true;
  4682. end;
  4683. end;
  4684. else
  4685. begin
  4686. token:=_INTCONST;
  4687. nexttoken:=_POINT;
  4688. goto exit_label;
  4689. end;
  4690. end;
  4691. end;
  4692. { E can also follow after a point is scanned }
  4693. if c in ['e','E'] then
  4694. begin
  4695. pattern:=pattern+'E';
  4696. readchar;
  4697. if c in ['-','+'] then
  4698. begin
  4699. pattern:=pattern+c;
  4700. readchar;
  4701. end;
  4702. if not(c in ['0'..'9']) then
  4703. Illegal_Char(c);
  4704. firstdigitread:=false;
  4705. while (c in ['0'..'9']) or
  4706. ((m_underscoreisseparator in current_settings.modeswitches) and firstdigitread and (c='_')) do
  4707. begin
  4708. if c<>'_' then
  4709. pattern:=pattern+c;
  4710. readchar;
  4711. firstdigitread:=true;
  4712. end;
  4713. end;
  4714. token:=_REALNUMBER;
  4715. goto exit_label;
  4716. end;
  4717. token:=_INTCONST;
  4718. goto exit_label;
  4719. end;
  4720. ';' :
  4721. begin
  4722. readchar;
  4723. token:=_SEMICOLON;
  4724. goto exit_label;
  4725. end;
  4726. '[' :
  4727. begin
  4728. readchar;
  4729. token:=_LECKKLAMMER;
  4730. goto exit_label;
  4731. end;
  4732. ']' :
  4733. begin
  4734. readchar;
  4735. token:=_RECKKLAMMER;
  4736. goto exit_label;
  4737. end;
  4738. '(' :
  4739. begin
  4740. readchar;
  4741. case c of
  4742. '*' :
  4743. begin
  4744. skipoldtpcomment(true);
  4745. readtoken(false);
  4746. exit;
  4747. end;
  4748. '.' :
  4749. begin
  4750. readchar;
  4751. token:=_LECKKLAMMER;
  4752. goto exit_label;
  4753. end;
  4754. end;
  4755. token:=_LKLAMMER;
  4756. goto exit_label;
  4757. end;
  4758. ')' :
  4759. begin
  4760. readchar;
  4761. token:=_RKLAMMER;
  4762. goto exit_label;
  4763. end;
  4764. '+' :
  4765. begin
  4766. readchar;
  4767. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4768. begin
  4769. readchar;
  4770. token:=_PLUSASN;
  4771. goto exit_label;
  4772. end;
  4773. token:=_PLUS;
  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:=_MINUSASN;
  4783. goto exit_label;
  4784. end;
  4785. token:=_MINUS;
  4786. goto exit_label;
  4787. end;
  4788. ':' :
  4789. begin
  4790. readchar;
  4791. if c='=' then
  4792. begin
  4793. readchar;
  4794. token:=_ASSIGNMENT;
  4795. goto exit_label;
  4796. end;
  4797. token:=_COLON;
  4798. goto exit_label;
  4799. end;
  4800. '*' :
  4801. begin
  4802. readchar;
  4803. if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
  4804. begin
  4805. readchar;
  4806. token:=_STARASN;
  4807. end
  4808. else
  4809. if c='*' then
  4810. begin
  4811. readchar;
  4812. token:=_STARSTAR;
  4813. end
  4814. else
  4815. token:=_STAR;
  4816. goto exit_label;
  4817. end;
  4818. '/' :
  4819. begin
  4820. readchar;
  4821. case c of
  4822. '=' :
  4823. begin
  4824. if (cs_support_c_operators in current_settings.moduleswitches) then
  4825. begin
  4826. readchar;
  4827. token:=_SLASHASN;
  4828. goto exit_label;
  4829. end;
  4830. end;
  4831. '/' :
  4832. begin
  4833. skipdelphicomment;
  4834. readtoken(false);
  4835. exit;
  4836. end;
  4837. end;
  4838. token:=_SLASH;
  4839. goto exit_label;
  4840. end;
  4841. '|' :
  4842. if m_mac in current_settings.modeswitches then
  4843. begin
  4844. readchar;
  4845. token:=_PIPE;
  4846. goto exit_label;
  4847. end
  4848. else
  4849. Illegal_Char(c);
  4850. '=' :
  4851. begin
  4852. readchar;
  4853. token:=_EQ;
  4854. goto exit_label;
  4855. end;
  4856. '.' :
  4857. begin
  4858. readchar;
  4859. case c of
  4860. '.' :
  4861. begin
  4862. readchar;
  4863. case c of
  4864. '.' :
  4865. begin
  4866. readchar;
  4867. token:=_POINTPOINTPOINT;
  4868. goto exit_label;
  4869. end;
  4870. else
  4871. begin
  4872. token:=_POINTPOINT;
  4873. goto exit_label;
  4874. end;
  4875. end;
  4876. end;
  4877. ')' :
  4878. begin
  4879. readchar;
  4880. token:=_RECKKLAMMER;
  4881. goto exit_label;
  4882. end;
  4883. end;
  4884. token:=_POINT;
  4885. goto exit_label;
  4886. end;
  4887. '@' :
  4888. begin
  4889. readchar;
  4890. token:=_KLAMMERAFFE;
  4891. goto exit_label;
  4892. end;
  4893. ',' :
  4894. begin
  4895. readchar;
  4896. token:=_COMMA;
  4897. goto exit_label;
  4898. end;
  4899. '''','#','^' :
  4900. begin
  4901. len:=0;
  4902. cstringpattern:='';
  4903. iswidestring:=false;
  4904. if c='^' then
  4905. begin
  4906. readchar;
  4907. c:=upcase(c);
  4908. if (block_type in [bt_type,bt_const_type,bt_var_type]) or
  4909. (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or
  4910. (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
  4911. begin
  4912. token:=_CARET;
  4913. goto exit_label;
  4914. end
  4915. else
  4916. begin
  4917. inc(len);
  4918. setlength(cstringpattern,256);
  4919. if c<#64 then
  4920. cstringpattern[len]:=chr(ord(c)+64)
  4921. else
  4922. cstringpattern[len]:=chr(ord(c)-64);
  4923. readchar;
  4924. end;
  4925. end;
  4926. repeat
  4927. case c of
  4928. '#' :
  4929. begin
  4930. readchar; { read # }
  4931. case c of
  4932. '$':
  4933. begin
  4934. readchar; { read leading $ }
  4935. asciinr:='$';
  4936. while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=7) do
  4937. begin
  4938. asciinr:=asciinr+c;
  4939. readchar;
  4940. end;
  4941. end;
  4942. '&':
  4943. begin
  4944. readchar; { read leading $ }
  4945. asciinr:='&';
  4946. while (upcase(c) in ['0'..'7']) and (length(asciinr)<=8) do
  4947. begin
  4948. asciinr:=asciinr+c;
  4949. readchar;
  4950. end;
  4951. end;
  4952. '%':
  4953. begin
  4954. readchar; { read leading $ }
  4955. asciinr:='%';
  4956. while (upcase(c) in ['0','1']) and (length(asciinr)<=22) do
  4957. begin
  4958. asciinr:=asciinr+c;
  4959. readchar;
  4960. end;
  4961. end;
  4962. else
  4963. begin
  4964. asciinr:='';
  4965. while (c in ['0'..'9']) and (length(asciinr)<=8) do
  4966. begin
  4967. asciinr:=asciinr+c;
  4968. readchar;
  4969. end;
  4970. end;
  4971. end;
  4972. val(asciinr,m,code);
  4973. if (asciinr='') or (code<>0) then
  4974. Message(scan_e_illegal_char_const)
  4975. else if (m<0) or (m>255) or (length(asciinr)>3) then
  4976. begin
  4977. if (m>=0) and (m<=$10FFFF) then
  4978. begin
  4979. if not iswidestring then
  4980. begin
  4981. if len>0 then
  4982. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  4983. else
  4984. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  4985. iswidestring:=true;
  4986. len:=0;
  4987. end;
  4988. if m<=$FFFF then
  4989. concatwidestringchar(patternw,tcompilerwidechar(m))
  4990. else
  4991. begin
  4992. { split into surrogate pair }
  4993. dec(m,$10000);
  4994. concatwidestringchar(patternw,tcompilerwidechar((m shr 10) + $D800));
  4995. concatwidestringchar(patternw,tcompilerwidechar((m and $3FF) + $DC00));
  4996. end;
  4997. end
  4998. else
  4999. Message(scan_e_illegal_char_const)
  5000. end
  5001. else if iswidestring then
  5002. concatwidestringchar(patternw,asciichar2unicode(char(m)))
  5003. else
  5004. begin
  5005. if len>=length(cstringpattern) then
  5006. setlength(cstringpattern,length(cstringpattern)+256);
  5007. inc(len);
  5008. cstringpattern[len]:=chr(m);
  5009. end;
  5010. end;
  5011. '''' :
  5012. begin
  5013. repeat
  5014. readchar;
  5015. case c of
  5016. #26 :
  5017. end_of_file;
  5018. #10,#13 :
  5019. Message(scan_f_string_exceeds_line);
  5020. '''' :
  5021. begin
  5022. readchar;
  5023. if c<>'''' then
  5024. break;
  5025. end;
  5026. end;
  5027. { interpret as utf-8 string? }
  5028. if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then
  5029. begin
  5030. { convert existing string to an utf-8 string }
  5031. if not iswidestring then
  5032. begin
  5033. if len>0 then
  5034. ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
  5035. else
  5036. ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
  5037. iswidestring:=true;
  5038. len:=0;
  5039. end;
  5040. { four chars }
  5041. if (ord(c) and $f0)=$f0 then
  5042. begin
  5043. { this always represents a surrogate pair, so
  5044. read as 32-bit value and then split into
  5045. the corresponding pair of two wchars }
  5046. d:=ord(c) and $f;
  5047. readchar;
  5048. if (ord(c) and $c0)<>$80 then
  5049. message(scan_e_utf8_malformed);
  5050. d:=(d shl 6) or (ord(c) and $3f);
  5051. readchar;
  5052. if (ord(c) and $c0)<>$80 then
  5053. message(scan_e_utf8_malformed);
  5054. d:=(d shl 6) or (ord(c) and $3f);
  5055. readchar;
  5056. if (ord(c) and $c0)<>$80 then
  5057. message(scan_e_utf8_malformed);
  5058. d:=(d shl 6) or (ord(c) and $3f);
  5059. if d<$10000 then
  5060. message(scan_e_utf8_malformed);
  5061. d:=d-$10000;
  5062. { high surrogate }
  5063. w:=$d800+(d shr 10);
  5064. concatwidestringchar(patternw,w);
  5065. { low surrogate }
  5066. w:=$dc00+(d and $3ff);
  5067. concatwidestringchar(patternw,w);
  5068. end
  5069. { three chars }
  5070. else if (ord(c) and $e0)=$e0 then
  5071. begin
  5072. w:=ord(c) and $f;
  5073. readchar;
  5074. if (ord(c) and $c0)<>$80 then
  5075. message(scan_e_utf8_malformed);
  5076. w:=(w shl 6) or (ord(c) and $3f);
  5077. readchar;
  5078. if (ord(c) and $c0)<>$80 then
  5079. message(scan_e_utf8_malformed);
  5080. w:=(w shl 6) or (ord(c) and $3f);
  5081. concatwidestringchar(patternw,w);
  5082. end
  5083. { two chars }
  5084. else if (ord(c) and $c0)<>0 then
  5085. begin
  5086. w:=ord(c) and $1f;
  5087. readchar;
  5088. if (ord(c) and $c0)<>$80 then
  5089. message(scan_e_utf8_malformed);
  5090. w:=(w shl 6) or (ord(c) and $3f);
  5091. concatwidestringchar(patternw,w);
  5092. end
  5093. { illegal }
  5094. else if (ord(c) and $80)<>0 then
  5095. message(scan_e_utf8_malformed)
  5096. else
  5097. concatwidestringchar(patternw,tcompilerwidechar(c))
  5098. end
  5099. else if iswidestring then
  5100. begin
  5101. if current_settings.sourcecodepage=CP_UTF8 then
  5102. concatwidestringchar(patternw,ord(c))
  5103. else
  5104. concatwidestringchar(patternw,asciichar2unicode(c))
  5105. end
  5106. else
  5107. begin
  5108. if len>=length(cstringpattern) then
  5109. setlength(cstringpattern,length(cstringpattern)+256);
  5110. inc(len);
  5111. cstringpattern[len]:=c;
  5112. end;
  5113. until false;
  5114. end;
  5115. '^' :
  5116. begin
  5117. readchar;
  5118. c:=upcase(c);
  5119. if c<#64 then
  5120. c:=chr(ord(c)+64)
  5121. else
  5122. c:=chr(ord(c)-64);
  5123. if iswidestring then
  5124. concatwidestringchar(patternw,asciichar2unicode(c))
  5125. else
  5126. begin
  5127. if len>=length(cstringpattern) then
  5128. setlength(cstringpattern,length(cstringpattern)+256);
  5129. inc(len);
  5130. cstringpattern[len]:=c;
  5131. end;
  5132. readchar;
  5133. end;
  5134. else
  5135. break;
  5136. end;
  5137. until false;
  5138. { strings with length 1 become const chars }
  5139. if iswidestring then
  5140. begin
  5141. if patternw^.len=1 then
  5142. token:=_CWCHAR
  5143. else
  5144. token:=_CWSTRING;
  5145. end
  5146. else
  5147. begin
  5148. setlength(cstringpattern,len);
  5149. if length(cstringpattern)=1 then
  5150. begin
  5151. token:=_CCHAR;
  5152. pattern:=cstringpattern;
  5153. end
  5154. else
  5155. token:=_CSTRING;
  5156. end;
  5157. goto exit_label;
  5158. end;
  5159. '>' :
  5160. begin
  5161. readchar;
  5162. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  5163. token:=_RSHARPBRACKET
  5164. else
  5165. begin
  5166. case c of
  5167. '=' :
  5168. begin
  5169. readchar;
  5170. token:=_GTE;
  5171. goto exit_label;
  5172. end;
  5173. '>' :
  5174. begin
  5175. readchar;
  5176. token:=_OP_SHR;
  5177. goto exit_label;
  5178. end;
  5179. '<' :
  5180. begin { >< is for a symetric diff for sets }
  5181. readchar;
  5182. token:=_SYMDIF;
  5183. goto exit_label;
  5184. end;
  5185. end;
  5186. token:=_GT;
  5187. end;
  5188. goto exit_label;
  5189. end;
  5190. '<' :
  5191. begin
  5192. readchar;
  5193. if (block_type in [bt_type,bt_var_type,bt_const_type]) then
  5194. token:=_LSHARPBRACKET
  5195. else
  5196. begin
  5197. case c of
  5198. '>' :
  5199. begin
  5200. readchar;
  5201. token:=_NE;
  5202. goto exit_label;
  5203. end;
  5204. '=' :
  5205. begin
  5206. readchar;
  5207. token:=_LTE;
  5208. goto exit_label;
  5209. end;
  5210. '<' :
  5211. begin
  5212. readchar;
  5213. token:=_OP_SHL;
  5214. goto exit_label;
  5215. end;
  5216. end;
  5217. token:=_LT;
  5218. end;
  5219. goto exit_label;
  5220. end;
  5221. #26 :
  5222. begin
  5223. token:=_EOF;
  5224. checkpreprocstack;
  5225. goto exit_label;
  5226. end;
  5227. else if inputfile.internally_generated_macro and
  5228. (c in [internal_macro_escape_begin..internal_macro_escape_end]) then
  5229. begin
  5230. token:=_ID;
  5231. readstring;
  5232. end
  5233. else
  5234. Illegal_Char(c);
  5235. end;
  5236. end;
  5237. exit_label:
  5238. lasttoken:=token;
  5239. end;
  5240. function tscannerfile.readpreproc:ttoken;
  5241. var
  5242. low,high,mid: longint;
  5243. optoken: ttoken;
  5244. begin
  5245. skipspace;
  5246. case c of
  5247. '_',
  5248. 'A'..'Z',
  5249. 'a'..'z' :
  5250. begin
  5251. readstring;
  5252. optoken:=_ID;
  5253. if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
  5254. begin
  5255. low:=ord(tokenidx^[length(pattern),pattern[1]].first);
  5256. high:=ord(tokenidx^[length(pattern),pattern[1]].last);
  5257. while low<high do
  5258. begin
  5259. mid:=(high+low+1) shr 1;
  5260. if pattern<tokeninfo^[ttoken(mid)].str then
  5261. high:=mid-1
  5262. else
  5263. low:=mid;
  5264. end;
  5265. with tokeninfo^[ttoken(high)] do
  5266. if pattern=str then
  5267. begin
  5268. if (keyword*current_settings.modeswitches)<>[] then
  5269. if op=NOTOKEN then
  5270. optoken:=ttoken(high)
  5271. else
  5272. optoken:=op;
  5273. end;
  5274. if not (optoken in preproc_operators) then
  5275. optoken:=_ID;
  5276. end;
  5277. current_scanner.preproc_pattern:=pattern;
  5278. readpreproc:=optoken;
  5279. end;
  5280. '''' :
  5281. begin
  5282. readquotedstring;
  5283. current_scanner.preproc_pattern:=cstringpattern;
  5284. readpreproc:=_CSTRING;
  5285. end;
  5286. '0'..'9' :
  5287. begin
  5288. readnumber;
  5289. if (c in ['.','e','E']) then
  5290. begin
  5291. { first check for a . }
  5292. if c='.' then
  5293. begin
  5294. readchar;
  5295. if c in ['0'..'9'] then
  5296. begin
  5297. { insert the number after the . }
  5298. pattern:=pattern+'.';
  5299. while c in ['0'..'9'] do
  5300. begin
  5301. pattern:=pattern+c;
  5302. readchar;
  5303. end;
  5304. end
  5305. else
  5306. Illegal_Char(c);
  5307. end;
  5308. { E can also follow after a point is scanned }
  5309. if c in ['e','E'] then
  5310. begin
  5311. pattern:=pattern+'E';
  5312. readchar;
  5313. if c in ['-','+'] then
  5314. begin
  5315. pattern:=pattern+c;
  5316. readchar;
  5317. end;
  5318. if not(c in ['0'..'9']) then
  5319. Illegal_Char(c);
  5320. while c in ['0'..'9'] do
  5321. begin
  5322. pattern:=pattern+c;
  5323. readchar;
  5324. end;
  5325. end;
  5326. readpreproc:=_REALNUMBER;
  5327. end
  5328. else
  5329. readpreproc:=_INTCONST;
  5330. current_scanner.preproc_pattern:=pattern;
  5331. end;
  5332. '$','%':
  5333. begin
  5334. readnumber;
  5335. current_scanner.preproc_pattern:=pattern;
  5336. readpreproc:=_INTCONST;
  5337. end;
  5338. '&' :
  5339. begin
  5340. readnumber;
  5341. if length(pattern)=1 then
  5342. begin
  5343. readstring;
  5344. readpreproc:=_ID;
  5345. end
  5346. else
  5347. readpreproc:=_INTCONST;
  5348. current_scanner.preproc_pattern:=pattern;
  5349. end;
  5350. '.' :
  5351. begin
  5352. readchar;
  5353. readpreproc:=_POINT;
  5354. end;
  5355. ',' :
  5356. begin
  5357. readchar;
  5358. readpreproc:=_COMMA;
  5359. end;
  5360. '}' :
  5361. begin
  5362. readpreproc:=_END;
  5363. end;
  5364. '(' :
  5365. begin
  5366. readchar;
  5367. readpreproc:=_LKLAMMER;
  5368. end;
  5369. ')' :
  5370. begin
  5371. readchar;
  5372. readpreproc:=_RKLAMMER;
  5373. end;
  5374. '[' :
  5375. begin
  5376. readchar;
  5377. readpreproc:=_LECKKLAMMER;
  5378. end;
  5379. ']' :
  5380. begin
  5381. readchar;
  5382. readpreproc:=_RECKKLAMMER;
  5383. end;
  5384. '+' :
  5385. begin
  5386. readchar;
  5387. readpreproc:=_PLUS;
  5388. end;
  5389. '-' :
  5390. begin
  5391. readchar;
  5392. readpreproc:=_MINUS;
  5393. end;
  5394. '*' :
  5395. begin
  5396. readchar;
  5397. readpreproc:=_STAR;
  5398. end;
  5399. '/' :
  5400. begin
  5401. readchar;
  5402. readpreproc:=_SLASH;
  5403. end;
  5404. '=' :
  5405. begin
  5406. readchar;
  5407. readpreproc:=_EQ;
  5408. end;
  5409. '>' :
  5410. begin
  5411. readchar;
  5412. if c='=' then
  5413. begin
  5414. readchar;
  5415. readpreproc:=_GTE;
  5416. end
  5417. else
  5418. readpreproc:=_GT;
  5419. end;
  5420. '<' :
  5421. begin
  5422. readchar;
  5423. case c of
  5424. '>' :
  5425. begin
  5426. readchar;
  5427. readpreproc:=_NE;
  5428. end;
  5429. '=' :
  5430. begin
  5431. readchar;
  5432. readpreproc:=_LTE;
  5433. end;
  5434. else
  5435. readpreproc:=_LT;
  5436. end;
  5437. end;
  5438. #26 :
  5439. begin
  5440. readpreproc:=_EOF;
  5441. checkpreprocstack;
  5442. end;
  5443. else
  5444. begin
  5445. Illegal_Char(c);
  5446. readpreproc:=NOTOKEN;
  5447. end;
  5448. end;
  5449. end;
  5450. function tscannerfile.readpreprocint(var value:int64;const place:string):boolean;
  5451. var
  5452. hs : texprvalue;
  5453. begin
  5454. hs:=preproc_comp_expr;
  5455. if hs.isInt then
  5456. begin
  5457. value:=hs.asInt64;
  5458. result:=true;
  5459. end
  5460. else
  5461. begin
  5462. hs.error('Integer',place);
  5463. result:=false;
  5464. end;
  5465. hs.free;
  5466. end;
  5467. function tscannerfile.asmgetchar : char;
  5468. begin
  5469. readchar;
  5470. repeat
  5471. case c of
  5472. #26 :
  5473. begin
  5474. reload;
  5475. if (c=#26) and not assigned(inputfile.next) then
  5476. end_of_file;
  5477. continue;
  5478. end;
  5479. else
  5480. begin
  5481. asmgetchar:=c;
  5482. exit;
  5483. end;
  5484. end;
  5485. until false;
  5486. end;
  5487. {*****************************************************************************
  5488. Helpers
  5489. *****************************************************************************}
  5490. procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5491. begin
  5492. if dm in [directive_all, directive_turbo] then
  5493. tdirectiveitem.create(turbo_scannerdirectives,s,p);
  5494. if dm in [directive_all, directive_mac] then
  5495. tdirectiveitem.create(mac_scannerdirectives,s,p);
  5496. end;
  5497. procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
  5498. begin
  5499. if dm in [directive_all, directive_turbo] then
  5500. tdirectiveitem.createcond(turbo_scannerdirectives,s,p);
  5501. if dm in [directive_all, directive_mac] then
  5502. tdirectiveitem.createcond(mac_scannerdirectives,s,p);
  5503. end;
  5504. {*****************************************************************************
  5505. Initialization
  5506. *****************************************************************************}
  5507. procedure InitScanner;
  5508. begin
  5509. InitWideString(patternw);
  5510. turbo_scannerdirectives:=TFPHashObjectList.Create;
  5511. mac_scannerdirectives:=TFPHashObjectList.Create;
  5512. { Common directives and conditionals }
  5513. AddDirective('I',directive_all, @dir_include);
  5514. AddDirective('DEFINE',directive_all, @dir_define);
  5515. AddDirective('UNDEF',directive_all, @dir_undef);
  5516. AddConditional('IF',directive_all, @dir_if);
  5517. AddConditional('IFDEF',directive_all, @dir_ifdef);
  5518. AddConditional('IFNDEF',directive_all, @dir_ifndef);
  5519. AddConditional('ELSE',directive_all, @dir_else);
  5520. AddConditional('ELSEIF',directive_all, @dir_elseif);
  5521. AddConditional('ENDIF',directive_all, @dir_endif);
  5522. { Directives and conditionals for all modes except mode macpas}
  5523. AddDirective('INCLUDE',directive_turbo, @dir_include);
  5524. AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
  5525. AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
  5526. AddDirective('EXTENSION',directive_turbo, @dir_extension);
  5527. AddConditional('IFEND',directive_turbo, @dir_ifend);
  5528. AddConditional('IFOPT',directive_turbo, @dir_ifopt);
  5529. { Directives and conditionals for mode macpas: }
  5530. AddDirective('SETC',directive_mac, @dir_setc);
  5531. AddDirective('DEFINEC',directive_mac, @dir_definec);
  5532. AddDirective('UNDEFC',directive_mac, @dir_undef);
  5533. AddConditional('IFC',directive_mac, @dir_if);
  5534. AddConditional('ELSEC',directive_mac, @dir_else);
  5535. AddConditional('ELIFC',directive_mac, @dir_elseif);
  5536. AddConditional('ENDC',directive_mac, @dir_endif);
  5537. end;
  5538. procedure DoneScanner;
  5539. begin
  5540. turbo_scannerdirectives.Free;
  5541. mac_scannerdirectives.Free;
  5542. DoneWideString(patternw);
  5543. end;
  5544. end.