scanner.pas 198 KB

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