scanner.pas 191 KB

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