123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734 |
- {
- Copyright (c) 1998-2002 by Florian Klaempfl
- This unit implements the scanner part and handling of the switches
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit scanner;
- {$i fpcdefs.inc}
- interface
- uses
- cclasses,
- globtype,globals,constexp,version,tokens,
- verbose,comphook,
- finput,
- widestr;
- const
- max_include_nesting=32;
- max_macro_nesting=16;
- preprocbufsize=32*1024;
- type
- tcommentstyle = (comment_none,comment_tp,comment_oldtp,comment_delphi,comment_c);
- tscannerfile = class;
- preproctyp = (pp_ifdef,pp_ifndef,pp_if,pp_ifopt,pp_else,pp_elseif);
- tpreprocstack = class
- typ : preproctyp;
- accept : boolean;
- next : tpreprocstack;
- name : TIDString;
- line_nb : longint;
- owner : tscannerfile;
- constructor Create(atyp:preproctyp;a:boolean;n:tpreprocstack);
- end;
- tdirectiveproc=procedure;
- tdirectiveitem = class(TFPHashObject)
- public
- is_conditional : boolean;
- proc : tdirectiveproc;
- constructor Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- constructor CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- end;
- // stack for replay buffers
- treplaystack = class
- token : ttoken;
- settings : tsettings;
- tokenbuf : tdynamicarray;
- next : treplaystack;
- change_endian : boolean;
- constructor Create(atoken: ttoken;asettings:tsettings;
- atokenbuf:tdynamicarray;anext:treplaystack; achange_endian : boolean);
- end;
- tcompile_time_predicate = function(var valuedescr: String) : Boolean;
- tspecialgenerictoken =
- (ST_LOADSETTINGS,
- ST_LINE,
- ST_COLUMN,
- ST_FILEINDEX,
- ST_LOADMESSAGES);
- { tscannerfile }
- tscannerfile = class
- private
- procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
- procedure cachenexttokenpos;
- procedure setnexttoken;
- procedure savetokenpos;
- procedure restoretokenpos;
- procedure writetoken(t: ttoken);
- function readtoken : ttoken;
- public
- inputfile : tinputfile; { current inputfile list }
- inputfilecount : longint;
- inputbuffer, { input buffer }
- inputpointer : pchar;
- inputstart : longint;
- line_no, { line }
- lastlinepos : longint;
- lasttokenpos,
- nexttokenpos : longint; { token }
- lasttoken,
- nexttoken : ttoken;
- oldlasttokenpos : longint; { temporary saving/restoring tokenpos }
- oldcurrent_filepos,
- oldcurrent_tokenpos : tfileposinfo;
- replaytokenbuf,
- recordtokenbuf : tdynamicarray;
- tokenbuf_change_endian : boolean;
- { last settings we stored }
- last_settings : tsettings;
- last_message : pmessagestaterecord;
- { last filepos we stored }
- last_filepos,
- { if nexttoken<>NOTOKEN, then nexttokenpos holds its filepos }
- next_filepos : tfileposinfo;
- comment_level,
- yylexcount : longint;
- lastasmgetchar : char;
- ignoredirectives : TFPHashList; { ignore directives, used to give warnings only once }
- preprocstack : tpreprocstack;
- replaystack : treplaystack;
- in_asm_string : boolean;
- preproc_pattern : string;
- preproc_token : ttoken;
- constructor Create(const fn:string);
- destructor Destroy;override;
- { File buffer things }
- function openinputfile:boolean;
- procedure closeinputfile;
- function tempopeninputfile:boolean;
- procedure tempcloseinputfile;
- procedure saveinputfile;
- procedure restoreinputfile;
- procedure firstfile;
- procedure nextfile;
- procedure addfile(hp:tinputfile);
- procedure reload;
- procedure insertmacro(const macname:string;p:pchar;len,line,fileindex:longint);
- { Scanner things }
- procedure gettokenpos;
- procedure inc_comment_level;
- procedure dec_comment_level;
- procedure illegal_char(c:char);
- procedure end_of_file;
- procedure checkpreprocstack;
- procedure poppreprocstack;
- procedure ifpreprocstack(atyp : preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
- procedure elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
- procedure elsepreprocstack;
- procedure popreplaystack;
- procedure handleconditional(p:tdirectiveitem);
- procedure handledirectives;
- procedure linebreak;
- procedure recordtoken;
- procedure startrecordtokens(buf:tdynamicarray);
- procedure stoprecordtokens;
- procedure replaytoken;
- procedure startreplaytokens(buf:tdynamicarray; achange_endian : boolean);
- { bit length sizeint is target depend }
- procedure tokenwritesizeint(val : sizeint);
- function tokenreadsizeint : sizeint;
- { longword/longint are 32 bits on all targets }
- { word/smallint are 16-bits on all targest }
- function tokenreadlongword : longword;
- function tokenreadword : word;
- function tokenreadlongint : longint;
- function tokenreadsmallint : smallint;
- { short int is one a signed byte }
- function tokenreadshortint : shortint;
- function tokenreadbyte : byte;
- { This one takes the set size as an parameter }
- procedure tokenreadset(var b;size : longint);
- function tokenreadenum(size : longint) : longword;
- procedure tokenreadsettings(var asettings : tsettings; expected_size : longint);
- procedure readchar;
- procedure readstring;
- procedure readnumber;
- function readid:string;
- function readval:longint;
- function readval_asstring:string;
- function readcomment:string;
- function readquotedstring:string;
- function readstate:char;
- function readstatedefault:char;
- procedure skipspace;
- procedure skipuntildirective;
- procedure skipcomment;
- procedure skipdelphicomment;
- procedure skipoldtpcomment;
- procedure readtoken(allowrecordtoken:boolean);
- function readpreproc:ttoken;
- function asmgetcharstart : char;
- function asmgetchar:char;
- end;
- {$ifdef PREPROCWRITE}
- tpreprocfile=class
- f : text;
- buf : pointer;
- spacefound,
- eolfound : boolean;
- constructor create(const fn:string);
- destructor destroy;
- procedure Add(const s:string);
- procedure AddSpace;
- end;
- {$endif PREPROCWRITE}
- var
- { read strings }
- c : char;
- orgpattern,
- pattern : string;
- cstringpattern : ansistring;
- patternw : pcompilerwidestring;
- { token }
- token, { current token being parsed }
- idtoken : ttoken; { holds the token if the pattern is a known word }
- current_scanner : tscannerfile; { current scanner in use }
- aktcommentstyle : tcommentstyle; { needed to use read_comment from directives }
- {$ifdef PREPROCWRITE}
- preprocfile : tpreprocfile; { used with only preprocessing }
- {$endif PREPROCWRITE}
- type
- tdirectivemode = (directive_all, directive_turbo, directive_mac);
- procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- procedure InitScanner;
- procedure DoneScanner;
- { To be called when the language mode is finally determined }
- Function SetCompileMode(const s:string; changeInit: boolean):boolean;
- Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
- implementation
- uses
- SysUtils,
- cutils,cfileutl,
- systems,
- switches,
- symbase,symtable,symtype,symsym,symconst,symdef,defutil,
- { This is needed for tcputype }
- cpuinfo,
- fmodule
- {$if FPC_FULLVERSION<20700}
- ,ccharset
- {$endif}
- ;
- var
- { dictionaries with the supported directives }
- turbo_scannerdirectives : TFPHashObjectList; { for other modes }
- mac_scannerdirectives : TFPHashObjectList; { for mode mac }
- {*****************************************************************************
- Helper routines
- *****************************************************************************}
- const
- { use any special name that is an invalid file name to avoid problems }
- preprocstring : array [preproctyp] of string[7]
- = ('$IFDEF','$IFNDEF','$IF','$IFOPT','$ELSE','$ELSEIF');
- function is_keyword(const s:string):boolean;
- var
- low,high,mid : longint;
- begin
- if not (length(s) in [tokenlenmin..tokenlenmax]) or
- not (s[1] in ['a'..'z','A'..'Z']) then
- begin
- is_keyword:=false;
- exit;
- end;
- low:=ord(tokenidx^[length(s),s[1]].first);
- high:=ord(tokenidx^[length(s),s[1]].last);
- while low<high do
- begin
- mid:=(high+low+1) shr 1;
- if pattern<tokeninfo^[ttoken(mid)].str then
- high:=mid-1
- else
- low:=mid;
- end;
- is_keyword:=(pattern=tokeninfo^[ttoken(high)].str) and
- (tokeninfo^[ttoken(high)].keyword in current_settings.modeswitches);
- end;
- Procedure HandleModeSwitches(changeInit: boolean);
- begin
- { turn ansistrings on by default ? }
- if (m_default_ansistring in current_settings.modeswitches) then
- begin
- include(current_settings.localswitches,cs_ansistrings);
- if changeinit then
- include(init_settings.localswitches,cs_ansistrings);
- end
- else
- begin
- exclude(current_settings.localswitches,cs_ansistrings);
- if changeinit then
- exclude(init_settings.localswitches,cs_ansistrings);
- end;
- { turn inline on by default ? }
- if (m_default_inline in current_settings.modeswitches) then
- begin
- include(current_settings.localswitches,cs_do_inline);
- if changeinit then
- include(init_settings.localswitches,cs_do_inline);
- end
- else
- begin
- exclude(current_settings.localswitches,cs_do_inline);
- if changeinit then
- exclude(init_settings.localswitches,cs_do_inline);
- end;
- { turn system codepage by default }
- if m_systemcodepage in current_settings.modeswitches then
- begin
- current_settings.sourcecodepage:=DefaultSystemCodePage;
- include(current_settings.moduleswitches,cs_explicit_codepage);
- if changeinit then
- begin
- init_settings.sourcecodepage:=DefaultSystemCodePage;
- include(init_settings.moduleswitches,cs_explicit_codepage);
- end;
- end
- else
- begin
- exclude(current_settings.moduleswitches,cs_explicit_codepage);
- if changeinit then
- exclude(init_settings.moduleswitches,cs_explicit_codepage);
- end;
- end;
- Function SetCompileMode(const s:string; changeInit: boolean):boolean;
- var
- b : boolean;
- oldmodeswitches : tmodeswitches;
- begin
- oldmodeswitches:=current_settings.modeswitches;
- b:=true;
- if s='DEFAULT' then
- current_settings.modeswitches:=fpcmodeswitches
- else
- if s='DELPHI' then
- current_settings.modeswitches:=delphimodeswitches
- else
- if s='DELPHIUNICODE' then
- current_settings.modeswitches:=delphiunicodemodeswitches
- else
- if s='TP' then
- current_settings.modeswitches:=tpmodeswitches
- else
- if s='FPC' then begin
- current_settings.modeswitches:=fpcmodeswitches;
- { TODO: enable this for 2.3/2.9 }
- // include(current_settings.localswitches, cs_typed_addresses);
- end else
- if s='OBJFPC' then begin
- current_settings.modeswitches:=objfpcmodeswitches;
- { TODO: enable this for 2.3/2.9 }
- // include(current_settings.localswitches, cs_typed_addresses);
- end
- {$ifdef gpc_mode}
- else if s='GPC' then
- current_settings.modeswitches:=gpcmodeswitches
- {$endif}
- else
- if s='MACPAS' then
- current_settings.modeswitches:=macmodeswitches
- else
- if s='ISO' then
- current_settings.modeswitches:=isomodeswitches
- else
- b:=false;
- if b and changeInit then
- init_settings.modeswitches := current_settings.modeswitches;
- if b then
- begin
- { resolve all postponed switch changes }
- flushpendingswitchesstate;
- HandleModeSwitches(changeinit);
- { turn on bitpacking for mode macpas and iso pascal }
- if ([m_mac,m_iso] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_bitpacking);
- if changeinit then
- include(init_settings.localswitches,cs_bitpacking);
- end;
- { support goto/label by default in delphi/tp7/mac modes }
- if ([m_delphi,m_tp7,m_mac,m_iso] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.moduleswitches,cs_support_goto);
- if changeinit then
- include(init_settings.moduleswitches,cs_support_goto);
- end;
- { support pointer math by default in fpc/objfpc modes }
- if ([m_fpc,m_objfpc] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_pointermath);
- if changeinit then
- include(init_settings.localswitches,cs_pointermath);
- end
- else
- begin
- exclude(current_settings.localswitches,cs_pointermath);
- if changeinit then
- exclude(init_settings.localswitches,cs_pointermath);
- end;
- { Default enum and set packing for delphi/tp7 }
- if (m_tp7 in current_settings.modeswitches) or
- (m_delphi in current_settings.modeswitches) then
- begin
- current_settings.packenum:=1;
- current_settings.setalloc:=1;
- end
- else if (m_mac in current_settings.modeswitches) then
- { compatible with Metrowerks Pascal }
- current_settings.packenum:=2
- else
- current_settings.packenum:=4;
- if changeinit then
- init_settings.packenum:=current_settings.packenum;
- {$ifdef i386}
- { Default to intel assembler for delphi/tp7 on i386 }
- if (m_delphi in current_settings.modeswitches) or
- (m_tp7 in current_settings.modeswitches) then
- current_settings.asmmode:=asmmode_i386_intel;
- if changeinit then
- init_settings.asmmode:=current_settings.asmmode;
- {$endif i386}
- { Exception support explicitly turned on (mainly for macpas, to }
- { compensate for lack of interprocedural goto support) }
- if (cs_support_exceptions in current_settings.globalswitches) then
- include(current_settings.modeswitches,m_except);
- { Default strict string var checking in TP/Delphi modes }
- if ([m_delphi,m_tp7] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_strict_var_strings);
- if changeinit then
- include(init_settings.localswitches,cs_strict_var_strings);
- end;
- { Undefine old symbol }
- if (m_delphi in oldmodeswitches) then
- undef_system_macro('FPC_DELPHI')
- else if (m_tp7 in oldmodeswitches) then
- undef_system_macro('FPC_TP')
- else if (m_objfpc in oldmodeswitches) then
- undef_system_macro('FPC_OBJFPC')
- {$ifdef gpc_mode}
- else if (m_gpc in oldmodeswitches) then
- undef_system_macro('FPC_GPC')
- {$endif}
- else if (m_mac in oldmodeswitches) then
- undef_system_macro('FPC_MACPAS');
- { define new symbol in delphi,objfpc,tp,gpc,macpas mode }
- if (m_delphi in current_settings.modeswitches) then
- def_system_macro('FPC_DELPHI')
- else if (m_tp7 in current_settings.modeswitches) then
- def_system_macro('FPC_TP')
- else if (m_objfpc in current_settings.modeswitches) then
- def_system_macro('FPC_OBJFPC')
- {$ifdef gpc_mode}
- else if (m_gpc in current_settings.modeswitches) then
- def_system_macro('FPC_GPC')
- {$endif}
- else if (m_mac in current_settings.modeswitches) then
- def_system_macro('FPC_MACPAS');
- end;
- SetCompileMode:=b;
- end;
- Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
- var
- i : tmodeswitch;
- doinclude : boolean;
- begin
- s:=upper(s);
- { on/off? }
- doinclude:=true;
- case s[length(s)] of
- '+':
- s:=copy(s,1,length(s)-1);
- '-':
- begin
- s:=copy(s,1,length(s)-1);
- doinclude:=false;
- end;
- end;
- Result:=false;
- for i:=m_class to high(tmodeswitch) do
- if s=modeswitchstr[i] then
- begin
- { Objective-C is currently only supported for Darwin targets }
- if doinclude and
- (i in [m_objectivec1,m_objectivec2]) and
- not(target_info.system in systems_objc_supported) then
- begin
- Message1(option_unsupported_target_for_feature,'Objective-C');
- break;
- end;
- if changeInit then
- current_settings.modeswitches:=init_settings.modeswitches;
- Result:=true;
- if doinclude then
- begin
- include(current_settings.modeswitches,i);
- { Objective-C 2.0 support implies 1.0 support }
- if (i=m_objectivec2) then
- include(current_settings.modeswitches,m_objectivec1);
- if (i in [m_objectivec1,m_objectivec2]) then
- include(current_settings.modeswitches,m_class);
- end
- else
- begin
- exclude(current_settings.modeswitches,i);
- { Objective-C 2.0 support implies 1.0 support }
- if (i=m_objectivec2) then
- exclude(current_settings.modeswitches,m_objectivec1);
- if (i in [m_objectivec1,m_objectivec2]) and
- ([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then
- exclude(current_settings.modeswitches,m_class);
- end;
- { set other switches depending on changed mode switch }
- HandleModeSwitches(changeinit);
- if changeInit then
- init_settings.modeswitches:=current_settings.modeswitches;
- break;
- end;
- end;
- {*****************************************************************************
- Conditional Directives
- *****************************************************************************}
- procedure dir_else;
- begin
- current_scanner.elsepreprocstack;
- end;
- procedure dir_endif;
- begin
- current_scanner.poppreprocstack;
- end;
- function isdef(var valuedescr: String): Boolean;
- var
- hs : string;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- valuedescr:= hs;
- if hs='' then
- Message(scan_e_error_in_preproc_expr);
- isdef:=defined_macro(hs);
- end;
- procedure dir_ifdef;
- begin
- current_scanner.ifpreprocstack(pp_ifdef,@isdef,scan_c_ifdef_found);
- end;
- function isnotdef(var valuedescr: String): Boolean;
- var
- hs : string;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- valuedescr:= hs;
- if hs='' then
- Message(scan_e_error_in_preproc_expr);
- isnotdef:=not defined_macro(hs);
- end;
- procedure dir_ifndef;
- begin
- current_scanner.ifpreprocstack(pp_ifndef,@isnotdef,scan_c_ifndef_found);
- end;
- function opt_check(var valuedescr: String): Boolean;
- var
- hs : string;
- state : char;
- begin
- opt_check:= false;
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- valuedescr:= hs;
- if (length(hs)>1) then
- Message1(scan_w_illegal_switch,hs)
- else
- begin
- state:=current_scanner.ReadState;
- if state in ['-','+'] then
- opt_check:=CheckSwitch(hs[1],state)
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- end;
- procedure dir_ifopt;
- begin
- flushpendingswitchesstate;
- current_scanner.ifpreprocstack(pp_ifopt,@opt_check,scan_c_ifopt_found);
- end;
- procedure dir_libprefix;
- var
- s : string;
- begin
- current_scanner.skipspace;
- if c <> '''' then
- Message2(scan_f_syn_expected, '''', c);
- s := current_scanner.readquotedstring;
- stringdispose(outputprefix);
- outputprefix := stringdup(s);
- with current_module do
- setfilename(paramfn^, paramallowoutput);
- end;
- procedure dir_libsuffix;
- var
- s : string;
- begin
- current_scanner.skipspace;
- if c <> '''' then
- Message2(scan_f_syn_expected, '''', c);
- s := current_scanner.readquotedstring;
- stringdispose(outputsuffix);
- outputsuffix := stringdup(s);
- with current_module do
- setfilename(paramfn^, paramallowoutput);
- end;
- procedure dir_extension;
- var
- s : string;
- begin
- current_scanner.skipspace;
- if c <> '''' then
- Message2(scan_f_syn_expected, '''', c);
- s := current_scanner.readquotedstring;
- if OutputFileName='' then
- OutputFileName:=InputFileName;
- OutputFileName:=ChangeFileExt(OutputFileName,'.'+s);
- with current_module do
- setfilename(paramfn^, paramallowoutput);
- end;
- {
- Compile time expression type check
- ----------------------------------
- Each subexpression returns its type to the caller, which then can
- do type check. Since data types of compile time expressions is
- not well defined, the type system does a best effort. The drawback is
- that some errors might not be detected.
- Instead of returning a particular data type, a set of possible data types
- are returned. This way ambigouos types can be handled. For instance a
- value of 1 can be both a boolean and and integer.
- Booleans
- --------
- The following forms of boolean values are supported:
- * C coded, that is 0 is false, non-zero is true.
- * TRUE/FALSE for mac style compile time variables
- Thus boolean mac compile time variables are always stored as TRUE/FALSE.
- When a compile time expression is evaluated, they are then translated
- to C coded booleans (0/1), to simplify for the expression evaluator.
- Note that this scheme then also of support mac compile time variables which
- are 0/1 but with a boolean meaning.
- The TRUE/FALSE format is new from 22 august 2005, but the above scheme
- means that units which is not recompiled, and thus stores
- compile time variables as the old format (0/1), continue to work.
- Short circuit evaluation
- ------------------------
- For this to work, the part of a compile time expression which is short
- circuited, should not be evaluated, while it still should be parsed.
- Therefor there is a parameter eval, telling whether evaluation is needed.
- In case not, the value returned can be arbitrary.
- }
- type
- {Compile time expression types}
- TCTEType = (ctetBoolean, ctetInteger, ctetString, ctetSet);
- TCTETypeSet = set of TCTEType;
- const
- cteTypeNames : array[TCTEType] of string[10] = (
- 'BOOLEAN','INTEGER','STRING','SET');
- {Subset of types which can be elements in sets.}
- setelementdefs = [ctetBoolean, ctetInteger, ctetString];
- function GetCTETypeName(t: TCTETypeSet): String;
- var
- i: TCTEType;
- begin
- result:= '';
- for i:= Low(TCTEType) to High(TCTEType) do
- if i in t then
- if result = '' then
- result:= cteTypeNames[i]
- else
- result:= result + ' or ' + cteTypeNames[i];
- end;
- procedure CTEError(actType, desiredExprType: TCTETypeSet; place: String);
- begin
- Message3(scan_e_compile_time_typeerror,
- GetCTETypeName(desiredExprType),
- GetCTETypeName(actType),
- place
- );
- end;
- function parse_compiler_expr(var compileExprType: TCTETypeSet):string;
- function read_expr(var exprType: TCTETypeSet; eval : Boolean) : string; forward;
- procedure preproc_consume(t : ttoken);
- begin
- if t<>current_scanner.preproc_token then
- Message(scan_e_preproc_syntax_error);
- current_scanner.preproc_token:=current_scanner.readpreproc;
- end;
- function preproc_substitutedtoken(var macroType: TCTETypeSet; eval : Boolean): string;
- { Currently this parses identifiers as well as numbers.
- The result from this procedure can either be that the token
- itself is a value, or that it is a compile time variable/macro,
- which then is substituted for another value (for macros
- recursivelly substituted).}
- var
- hs: string;
- mac : tmacro;
- macrocount,
- len : integer;
- numres : longint;
- w: word;
- begin
- result := current_scanner.preproc_pattern;
- if not eval then
- exit;
- mac:= nil;
- { Substitue macros and compiler variables with their content/value.
- For real macros also do recursive substitution. }
- macrocount:=0;
- repeat
- mac:=tmacro(search_macro(result));
- inc(macrocount);
- if macrocount>max_macro_nesting then
- begin
- Message(scan_w_macro_too_deep);
- break;
- end;
- if assigned(mac) and mac.defined then
- if assigned(mac.buftext) then
- begin
- if mac.buflen>255 then
- begin
- len:=255;
- Message(scan_w_macro_cut_after_255_chars);
- end
- else
- len:=mac.buflen;
- hs[0]:=char(len);
- move(mac.buftext^,hs[1],len);
- result:=upcase(hs);
- mac.is_used:=true;
- end
- else
- begin
- Message1(scan_e_error_macro_lacks_value, result);
- break;
- end
- else
- begin
- break;
- end;
- if mac.is_compiler_var then
- break;
- until false;
- { At this point, result do contain the value. Do some decoding and
- determine the type.}
- val(result,numres,w);
- if (w=0) then {It is an integer}
- begin
- if (numres = 0) or (numres = 1) then
- macroType := [ctetInteger, ctetBoolean]
- else
- macroType := [ctetInteger];
- end
- else if assigned(mac) and (m_mac in current_settings.modeswitches) and (result='FALSE') then
- begin
- result:= '0';
- macroType:= [ctetBoolean];
- end
- else if assigned(mac) and (m_mac in current_settings.modeswitches) and (result='TRUE') then
- begin
- result:= '1';
- macroType:= [ctetBoolean];
- end
- else if (m_mac in current_settings.modeswitches) and
- (not assigned(mac) or not mac.defined) and
- (macrocount = 1) then
- begin
- {Errors in mode mac is issued here. For non macpas modes there is
- more liberty, but the error will eventually be caught at a later stage.}
- Message1(scan_e_error_macro_undefined, result);
- macroType:= [ctetString]; {Just to have something}
- end
- else
- macroType:= [ctetString];
- end;
- function read_factor(var factorType: TCTETypeSet; eval : Boolean) : string;
- var
- hs : string;
- mac: tmacro;
- srsym : tsym;
- srsymtable : TSymtable;
- hdef : TDef;
- l : longint;
- w : integer;
- hasKlammer: Boolean;
- setElemType : TCTETypeSet;
- begin
- if current_scanner.preproc_token=_ID then
- begin
- if current_scanner.preproc_pattern='DEFINED' then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- hasKlammer:= true;
- end
- else if (m_mac in current_settings.modeswitches) then
- hasKlammer:= false
- else
- Message(scan_e_error_in_preproc_expr);
- if current_scanner.preproc_token =_ID then
- begin
- hs := current_scanner.preproc_pattern;
- mac := tmacro(search_macro(hs));
- if assigned(mac) and mac.defined then
- begin
- hs := '1';
- mac.is_used:=true;
- end
- else
- hs := '0';
- read_factor := hs;
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if hasKlammer then
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='UNDEFINED') then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_ID then
- begin
- hs := current_scanner.preproc_pattern;
- mac := tmacro(search_macro(hs));
- if assigned(mac) then
- begin
- hs := '0';
- mac.is_used:=true;
- end
- else
- hs := '1';
- read_factor := hs;
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='OPTION') then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if not (current_scanner.preproc_token = _ID) then
- Message(scan_e_error_in_preproc_expr);
- hs:=current_scanner.preproc_pattern;
- if (length(hs) > 1) then
- {This is allowed in Metrowerks Pascal}
- Message(scan_e_error_in_preproc_expr)
- else
- begin
- if CheckSwitch(hs[1],'+') then
- read_factor := '1'
- else
- read_factor := '0';
- end;
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if current_scanner.preproc_pattern='SIZEOF' then
- begin
- factorType:= [ctetInteger];
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_preproc_syntax_error);
- if eval then
- if searchsym(current_scanner.preproc_pattern,srsym,srsymtable) then
- begin
- l:=0;
- case srsym.typ of
- staticvarsym,
- localvarsym,
- paravarsym :
- l:=tabstractvarsym(srsym).getsize;
- typesym:
- l:=ttypesym(srsym).typedef.size;
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- str(l,read_factor);
- end
- else
- Message1(sym_e_id_not_found,current_scanner.preproc_pattern);
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_preproc_syntax_error);
- end
- else
- if current_scanner.preproc_pattern='HIGH' then
- begin
- factorType:= [ctetInteger];
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_preproc_syntax_error);
- if eval then
- if searchsym(current_scanner.preproc_pattern,srsym,srsymtable) then
- begin
- hdef:=nil;
- hs:='';
- l:=0;
- case srsym.typ of
- staticvarsym,
- localvarsym,
- paravarsym :
- hdef:=tabstractvarsym(srsym).vardef;
- typesym:
- hdef:=ttypesym(srsym).typedef;
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- if hdef<>nil then
- begin
- if hdef.typ=setdef then
- hdef:=tsetdef(hdef).elementdef;
- case hdef.typ of
- orddef:
- with torddef(hdef).high do
- if signed then
- str(svalue,hs)
- else
- str(uvalue,hs);
- enumdef:
- l:=tenumdef(hdef).maxval;
- arraydef:
- if is_open_array(hdef) or is_array_of_const(hdef) or is_dynamic_array(hdef) then
- Message(type_e_mismatch)
- else
- l:=tarraydef(hdef).highrange;
- stringdef:
- if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then
- Message(type_e_mismatch)
- else
- l:=tstringdef(hdef).len;
- else
- Message(type_e_mismatch);
- end;
- end;
- if hs='' then
- str(l,read_factor)
- else
- read_factor:=hs;
- end
- else
- Message1(sym_e_id_not_found,current_scanner.preproc_pattern);
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_preproc_syntax_error);
- end
- else
- if current_scanner.preproc_pattern='DECLARED' then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if current_scanner.preproc_token =_ID then
- begin
- hs := upper(current_scanner.preproc_pattern);
- if searchsym(hs,srsym,srsymtable) then
- hs := '1'
- else
- hs := '0';
- read_factor := hs;
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if current_scanner.preproc_pattern='NOT' then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- hs:=read_factor(factorType, eval);
- if eval then
- begin
- if not (ctetBoolean in factorType) then
- CTEError(factorType, [ctetBoolean], 'NOT');
- val(hs,l,w);
- if l<>0 then
- read_factor:='0'
- else
- read_factor:='1';
- end
- else
- read_factor:='0'; {Just to have something}
- end
- else
- if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='TRUE') then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- read_factor:='1';
- end
- else
- if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='FALSE') then
- begin
- factorType:= [ctetBoolean];
- preproc_consume(_ID);
- read_factor:='0';
- end
- else
- begin
- hs:=preproc_substitutedtoken(factorType, eval);
- { Default is to return the original symbol }
- read_factor:=hs;
- if eval and ([m_delphi,m_objfpc]*current_settings.modeswitches<>[]) and (ctetString in factorType) then
- if searchsym(current_scanner.preproc_pattern,srsym,srsymtable) then
- begin
- case srsym.typ of
- constsym :
- begin
- with tconstsym(srsym) do
- begin
- case consttyp of
- constord :
- begin
- case constdef.typ of
- orddef:
- begin
- if is_integer(constdef) then
- begin
- read_factor:=tostr(value.valueord);
- factorType:= [ctetInteger];
- end
- else if is_boolean(constdef) then
- begin
- read_factor:=tostr(value.valueord);
- factorType:= [ctetBoolean];
- end
- else if is_char(constdef) then
- begin
- read_factor:=char(qword(value.valueord));
- factorType:= [ctetString];
- end
- end;
- enumdef:
- begin
- read_factor:=tostr(value.valueord);
- factorType:= [ctetInteger];
- end;
- end;
- end;
- conststring :
- begin
- read_factor := upper(pchar(value.valueptr));
- factorType:= [ctetString];
- end;
- constset :
- begin
- hs:=',';
- for l:=0 to 255 do
- if l in pconstset(tconstsym(srsym).value.valueptr)^ then
- hs:=hs+tostr(l)+',';
- read_factor := hs;
- factorType:= [ctetSet];
- end;
- end;
- end;
- end;
- enumsym :
- begin
- read_factor:=tostr(tenumsym(srsym).value);
- factorType:= [ctetInteger];
- end;
- end;
- end;
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- end
- else if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- read_factor:=read_expr(factorType, eval);
- preproc_consume(_RKLAMMER);
- end
- else if current_scanner.preproc_token = _LECKKLAMMER then
- begin
- preproc_consume(_LECKKLAMMER);
- read_factor := ',';
- while current_scanner.preproc_token = _ID do
- begin
- read_factor := read_factor+read_factor(setElemType, eval)+',';
- if current_scanner.preproc_token = _COMMA then
- preproc_consume(_COMMA);
- end;
- // TODO Add check of setElemType
- preproc_consume(_RECKKLAMMER);
- factorType:= [ctetSet];
- end
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- function read_term(var termType: TCTETypeSet; eval : Boolean) : string;
- var
- hs1,hs2 : string;
- l1,l2 : longint;
- w : integer;
- termType2: TCTETypeSet;
- begin
- hs1:=read_factor(termType, eval);
- repeat
- if (current_scanner.preproc_token<>_ID) then
- break;
- if current_scanner.preproc_pattern<>'AND' then
- break;
- val(hs1,l1,w);
- if l1=0 then
- eval:= false; {Short circuit evaluation of OR}
- if eval then
- begin
- {Check if first expr is boolean. Must be done here, after we know
- it is an AND expression.}
- if not (ctetBoolean in termType) then
- CTEError(termType, [ctetBoolean], 'AND');
- termType:= [ctetBoolean];
- end;
- preproc_consume(_ID);
- hs2:=read_factor(termType2, eval);
- if eval then
- begin
- if not (ctetBoolean in termType2) then
- CTEError(termType2, [ctetBoolean], 'AND');
- val(hs2,l2,w);
- if (l1<>0) and (l2<>0) then
- hs1:='1'
- else
- hs1:='0';
- end;
- until false;
- read_term:=hs1;
- end;
- function read_simple_expr(var simpleExprType: TCTETypeSet; eval : Boolean) : string;
- var
- hs1,hs2 : string;
- l1,l2 : longint;
- w : integer;
- simpleExprType2: TCTETypeSet;
- begin
- hs1:=read_term(simpleExprType, eval);
- repeat
- if (current_scanner.preproc_token<>_ID) then
- break;
- if current_scanner.preproc_pattern<>'OR' then
- break;
- val(hs1,l1,w);
- if l1<>0 then
- eval:= false; {Short circuit evaluation of OR}
- if eval then
- begin
- {Check if first expr is boolean. Must be done here, after we know
- it is an OR expression.}
- if not (ctetBoolean in simpleExprType) then
- CTEError(simpleExprType, [ctetBoolean], 'OR');
- simpleExprType:= [ctetBoolean];
- end;
- preproc_consume(_ID);
- hs2:=read_term(simpleExprType2, eval);
- if eval then
- begin
- if not (ctetBoolean in simpleExprType2) then
- CTEError(simpleExprType2, [ctetBoolean], 'OR');
- val(hs2,l2,w);
- if (l1<>0) or (l2<>0) then
- hs1:='1'
- else
- hs1:='0';
- end;
- until false;
- read_simple_expr:=hs1;
- end;
- function read_expr(var exprType: TCTETypeSet; eval : Boolean) : string;
- var
- hs1,hs2 : string;
- b : boolean;
- op : ttoken;
- w : integer;
- l1,l2 : longint;
- exprType2: TCTETypeSet;
- begin
- hs1:=read_simple_expr(exprType, eval);
- op:=current_scanner.preproc_token;
- if (op = _ID) and (current_scanner.preproc_pattern = 'IN') then
- op := _IN;
- if not (op in [_IN,_EQ,_NE,_LT,_GT,_LTE,_GTE]) then
- begin
- read_expr:=hs1;
- exit;
- end;
- if (op = _IN) then
- preproc_consume(_ID)
- else
- preproc_consume(op);
- hs2:=read_simple_expr(exprType2, eval);
- if eval then
- begin
- if op = _IN then
- begin
- if exprType2 <> [ctetSet] then
- CTEError(exprType2, [ctetSet], 'IN');
- if exprType = [ctetSet] then
- CTEError(exprType, setelementdefs, 'IN');
- if is_number(hs1) and is_number(hs2) then
- Message(scan_e_preproc_syntax_error)
- else if hs2[1] = ',' then
- b:=pos(','+hs1+',', hs2) > 0 { TODO For integer sets, perhaps check for numeric equivalence so that 0 = 00 }
- else
- Message(scan_e_preproc_syntax_error);
- end
- else
- begin
- if (exprType * exprType2) = [] then
- CTEError(exprType2, exprType, '"'+hs1+' '+tokeninfo^[op].str+' '+hs2+'"');
- if is_number(hs1) and is_number(hs2) then
- begin
- val(hs1,l1,w);
- val(hs2,l2,w);
- case op of
- _EQ :
- b:=l1=l2;
- _NE :
- b:=l1<>l2;
- _LT :
- b:=l1<l2;
- _GT :
- b:=l1>l2;
- _GTE :
- b:=l1>=l2;
- _LTE :
- b:=l1<=l2;
- end;
- end
- else
- begin
- case op of
- _EQ:
- b:=hs1=hs2;
- _NE :
- b:=hs1<>hs2;
- _LT :
- b:=hs1<hs2;
- _GT :
- b:=hs1>hs2;
- _GTE :
- b:=hs1>=hs2;
- _LTE :
- b:=hs1<=hs2;
- end;
- end;
- end;
- end
- else
- b:= false; {Just to have something}
- if b then
- read_expr:='1'
- else
- read_expr:='0';
- exprType:= [ctetBoolean];
- end;
- begin
- current_scanner.skipspace;
- { start preproc expression scanner }
- current_scanner.preproc_token:=current_scanner.readpreproc;
- parse_compiler_expr:=read_expr(compileExprType, true);
- end;
- function boolean_compile_time_expr(var valuedescr: String): Boolean;
- var
- hs : string;
- exprType: TCTETypeSet;
- begin
- hs:=parse_compiler_expr(exprType);
- if (exprType * [ctetBoolean]) = [] then
- CTEError(exprType, [ctetBoolean], 'IF or ELSEIF');
- boolean_compile_time_expr:= hs <> '0';
- valuedescr:= hs;
- end;
- procedure dir_if;
- begin
- current_scanner.ifpreprocstack(pp_if,@boolean_compile_time_expr, scan_c_if_found);
- end;
- procedure dir_elseif;
- begin
- current_scanner.elseifpreprocstack(@boolean_compile_time_expr);
- end;
- procedure dir_define_impl(macstyle: boolean);
- var
- hs : string;
- bracketcount : longint;
- mac : tmacro;
- macropos : longint;
- macrobuffer : pmacrobuffer;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- mac:=tmacro(search_macro(hs));
- if not assigned(mac) or (mac.owner <> current_module.localmacrosymtable) then
- begin
- mac:=tmacro.create(hs);
- mac.defined:=true;
- current_module.localmacrosymtable.insert(mac);
- end
- else
- begin
- mac.defined:=true;
- mac.is_compiler_var:=false;
- { delete old definition }
- if assigned(mac.buftext) then
- begin
- freemem(mac.buftext,mac.buflen);
- mac.buftext:=nil;
- end;
- end;
- Message1(parser_c_macro_defined,mac.name);
- mac.is_used:=true;
- if (cs_support_macro in current_settings.moduleswitches) then
- begin
- current_scanner.skipspace;
- if not macstyle then
- begin
- { may be a macro? }
- if c <> ':' then
- exit;
- current_scanner.readchar;
- if c <> '=' then
- exit;
- current_scanner.readchar;
- current_scanner.skipspace;
- end;
- { key words are never substituted }
- if is_keyword(hs) then
- Message(scan_e_keyword_cant_be_a_macro);
- new(macrobuffer);
- macropos:=0;
- { parse macro, brackets are counted so it's possible
- to have a $ifdef etc. in the macro }
- bracketcount:=0;
- repeat
- case c of
- '}' :
- if (bracketcount=0) then
- break
- else
- dec(bracketcount);
- '{' :
- inc(bracketcount);
- #10,#13 :
- current_scanner.linebreak;
- #26 :
- current_scanner.end_of_file;
- end;
- macrobuffer^[macropos]:=c;
- inc(macropos);
- if macropos>=maxmacrolen then
- Message(scan_f_macro_buffer_overflow);
- current_scanner.readchar;
- until false;
- { free buffer of macro ?}
- if assigned(mac.buftext) then
- freemem(mac.buftext,mac.buflen);
- { get new mem }
- getmem(mac.buftext,macropos);
- mac.buflen:=macropos;
- { copy the text }
- move(macrobuffer^,mac.buftext^,macropos);
- dispose(macrobuffer);
- end
- else
- begin
- { check if there is an assignment, then we need to give a
- warning }
- current_scanner.skipspace;
- if c=':' then
- begin
- current_scanner.readchar;
- if c='=' then
- Message(scan_w_macro_support_turned_off);
- end;
- end;
- end;
- procedure dir_define;
- begin
- dir_define_impl(false);
- end;
- procedure dir_definec;
- begin
- dir_define_impl(true);
- end;
- procedure dir_setc;
- var
- hs : string;
- mac : tmacro;
- exprType: TCTETypeSet;
- l : longint;
- w : integer;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- mac:=tmacro(search_macro(hs));
- if not assigned(mac) or
- (mac.owner <> current_module.localmacrosymtable) then
- begin
- mac:=tmacro.create(hs);
- mac.defined:=true;
- mac.is_compiler_var:=true;
- current_module.localmacrosymtable.insert(mac);
- end
- else
- begin
- mac.defined:=true;
- mac.is_compiler_var:=true;
- { delete old definition }
- if assigned(mac.buftext) then
- begin
- freemem(mac.buftext,mac.buflen);
- mac.buftext:=nil;
- end;
- end;
- Message1(parser_c_macro_defined,mac.name);
- mac.is_used:=true;
- { key words are never substituted }
- if is_keyword(hs) then
- Message(scan_e_keyword_cant_be_a_macro);
- { macro assignment can be both := and = }
- current_scanner.skipspace;
- if c=':' then
- current_scanner.readchar;
- if c='=' then
- begin
- current_scanner.readchar;
- hs:= parse_compiler_expr(exprType);
- if (exprType * [ctetBoolean, ctetInteger]) = [] then
- CTEError(exprType, [ctetBoolean, ctetInteger], 'SETC');
- if length(hs) <> 0 then
- begin
- {If we are absolutely shure it is boolean, translate
- to TRUE/FALSE to increase possibility to do future type check}
- if exprType = [ctetBoolean] then
- begin
- val(hs,l,w);
- if l<>0 then
- hs:='TRUE'
- else
- hs:='FALSE';
- end;
- Message2(parser_c_macro_set_to,mac.name,hs);
- { free buffer of macro ?}
- if assigned(mac.buftext) then
- freemem(mac.buftext,mac.buflen);
- { get new mem }
- getmem(mac.buftext,length(hs));
- mac.buflen:=length(hs);
- { copy the text }
- move(hs[1],mac.buftext^,mac.buflen);
- end
- else
- Message(scan_e_preproc_syntax_error);
- end
- else
- Message(scan_e_preproc_syntax_error);
- end;
- procedure dir_undef;
- var
- hs : string;
- mac : tmacro;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- mac:=tmacro(search_macro(hs));
- if not assigned(mac) or
- (mac.owner <> current_module.localmacrosymtable) then
- begin
- mac:=tmacro.create(hs);
- mac.defined:=false;
- current_module.localmacrosymtable.insert(mac);
- end
- else
- begin
- mac.defined:=false;
- mac.is_compiler_var:=false;
- { delete old definition }
- if assigned(mac.buftext) then
- begin
- freemem(mac.buftext,mac.buflen);
- mac.buftext:=nil;
- end;
- end;
- Message1(parser_c_macro_undefined,mac.name);
- mac.is_used:=true;
- end;
- procedure dir_include;
- function findincludefile(const path,name:TCmdStr;var foundfile:TCmdStr):boolean;
- var
- found : boolean;
- hpath : TCmdStr;
- begin
- (* look for the include file
- If path was absolute and specified as part of {$I } then
- 1. specified path
- else
- 1. path of current inputfile,current dir
- 2. local includepath
- 3. global includepath
- -- Check mantis #13461 before changing this *)
- found:=false;
- foundfile:='';
- hpath:='';
- if path_absolute(path) then
- begin
- found:=FindFile(name,path,true,foundfile);
- end
- else
- begin
- hpath:=current_scanner.inputfile.path^+';'+CurDirRelPath(source_info);
- found:=FindFile(path+name, hpath,true,foundfile);
- if not found then
- found:=current_module.localincludesearchpath.FindFile(path+name,true,foundfile);
- if not found then
- found:=includesearchpath.FindFile(path+name,true,foundfile);
- end;
- result:=found;
- end;
- var
- foundfile : TCmdStr;
- path,
- name,
- hs : tpathstr;
- args : string;
- hp : tinputfile;
- found : boolean;
- begin
- current_scanner.skipspace;
- args:=current_scanner.readcomment;
- hs:=GetToken(args,' ');
- if hs='' then
- exit;
- if (hs[1]='%') then
- begin
- { case insensitive }
- hs:=upper(hs);
- { remove %'s }
- Delete(hs,1,1);
- if hs[length(hs)]='%' then
- Delete(hs,length(hs),1);
- { save old }
- path:=hs;
- { first check for internal macros }
- if hs='TIME' then
- hs:=gettimestr
- else
- if hs='DATE' then
- hs:=getdatestr
- else
- if hs='FILE' then
- hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex)
- else
- if hs='LINE' then
- hs:=tostr(current_filepos.line)
- else
- if hs='FPCVERSION' then
- hs:=version_string
- else
- if hs='FPCDATE' then
- hs:=date_string
- else
- if hs='FPCTARGET' then
- hs:=target_cpu_string
- else
- if hs='FPCTARGETCPU' then
- hs:=target_cpu_string
- else
- if hs='FPCTARGETOS' then
- hs:=target_info.shortname
- else
- hs:=GetEnvironmentVariable(hs);
- if hs='' then
- Message1(scan_w_include_env_not_found,path);
- { make it a stringconst }
- hs:=''''+hs+'''';
- current_scanner.insertmacro(path,@hs[1],length(hs),
- current_scanner.line_no,current_scanner.inputfile.ref_index);
- end
- else
- begin
- hs:=FixFileName(hs);
- path:=ExtractFilePath(hs);
- name:=ExtractFileName(hs);
- { Special case for Delphi compatibility: '*' has to be replaced
- by the file name of the current source file. }
- if (length(name)>=1) and
- (name[1]='*') then
- name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);
- { try to find the file }
- found:=findincludefile(path,name,foundfile);
- if (ExtractFileExt(name)='') then
- begin
- { try default extensions .inc , .pp and .pas }
- if (not found) then
- found:=findincludefile(path,ChangeFileExt(name,'.inc'),foundfile);
- if (not found) then
- found:=findincludefile(path,ChangeFileExt(name,sourceext),foundfile);
- if (not found) then
- found:=findincludefile(path,ChangeFileExt(name,pasext),foundfile);
- end;
- if current_scanner.inputfilecount<max_include_nesting then
- begin
- inc(current_scanner.inputfilecount);
- { we need to reread the current char }
- dec(current_scanner.inputpointer);
- { shutdown current file }
- current_scanner.tempcloseinputfile;
- { load new file }
- hp:=do_openinputfile(foundfile);
- current_scanner.addfile(hp);
- current_module.sourcefiles.register_file(hp);
- if (not found) then
- Message1(scan_f_cannot_open_includefile,hs);
- if (not current_scanner.openinputfile) then
- Message1(scan_f_cannot_open_includefile,hs);
- Message1(scan_t_start_include_file,current_scanner.inputfile.path^+current_scanner.inputfile.name^);
- current_scanner.reload;
- end
- else
- Message(scan_f_include_deep_ten);
- end;
- end;
- {*****************************************************************************
- Preprocessor writing
- *****************************************************************************}
- {$ifdef PREPROCWRITE}
- constructor tpreprocfile.create(const fn:string);
- begin
- { open outputfile }
- assign(f,fn);
- {$push}{$I-}
- rewrite(f);
- {$pop}
- if ioresult<>0 then
- Comment(V_Fatal,'can''t create file '+fn);
- getmem(buf,preprocbufsize);
- settextbuf(f,buf^,preprocbufsize);
- { reset }
- eolfound:=false;
- spacefound:=false;
- end;
- destructor tpreprocfile.destroy;
- begin
- close(f);
- freemem(buf,preprocbufsize);
- end;
- procedure tpreprocfile.add(const s:string);
- begin
- write(f,s);
- end;
- procedure tpreprocfile.addspace;
- begin
- if eolfound then
- begin
- writeln(f,'');
- eolfound:=false;
- spacefound:=false;
- end
- else
- if spacefound then
- begin
- write(f,' ');
- spacefound:=false;
- end;
- end;
- {$endif PREPROCWRITE}
- {*****************************************************************************
- TPreProcStack
- *****************************************************************************}
- constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
- begin
- accept:=a;
- typ:=atyp;
- next:=n;
- end;
- {*****************************************************************************
- TReplayStack
- *****************************************************************************}
- constructor treplaystack.Create(atoken:ttoken;asettings:tsettings;
- atokenbuf:tdynamicarray;anext:treplaystack;achange_endian : boolean);
- begin
- token:=atoken;
- settings:=asettings;
- tokenbuf:=atokenbuf;
- change_endian:=achange_endian;
- next:=anext;
- end;
- {*****************************************************************************
- TDirectiveItem
- *****************************************************************************}
- constructor TDirectiveItem.Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- begin
- inherited Create(AList,n);
- is_conditional:=false;
- proc:=p;
- end;
- constructor TDirectiveItem.CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- begin
- inherited Create(AList,n);
- is_conditional:=true;
- proc:=p;
- end;
- {****************************************************************************
- TSCANNERFILE
- ****************************************************************************}
- constructor tscannerfile.create(const fn:string);
- begin
- inputfile:=do_openinputfile(fn);
- if assigned(current_module) then
- current_module.sourcefiles.register_file(inputfile);
- { reset localinput }
- c:=#0;
- inputbuffer:=nil;
- inputpointer:=nil;
- inputstart:=0;
- { reset scanner }
- preprocstack:=nil;
- replaystack:=nil;
- tokenbuf_change_endian:=false;
- comment_level:=0;
- yylexcount:=0;
- block_type:=bt_general;
- line_no:=0;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- lasttoken:=NOTOKEN;
- nexttoken:=NOTOKEN;
- lastasmgetchar:=#0;
- ignoredirectives:=TFPHashList.Create;
- in_asm_string:=false;
- end;
- procedure tscannerfile.firstfile;
- begin
- { load block }
- if not openinputfile then
- Message1(scan_f_cannot_open_input,inputfile.name^);
- reload;
- end;
- destructor tscannerfile.destroy;
- begin
- if assigned(current_module) and
- (current_module.state=ms_compiled) and
- (status.errorcount=0) then
- checkpreprocstack
- else
- begin
- while assigned(preprocstack) do
- poppreprocstack;
- end;
- while assigned(replaystack) do
- popreplaystack;
- if not inputfile.closed then
- closeinputfile;
- ignoredirectives.free;
- end;
- function tscannerfile.openinputfile:boolean;
- begin
- openinputfile:=inputfile.open;
- { load buffer }
- inputbuffer:=inputfile.buf;
- inputpointer:=inputfile.buf;
- inputstart:=inputfile.bufstart;
- { line }
- line_no:=0;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- end;
- procedure tscannerfile.closeinputfile;
- begin
- inputfile.close;
- { reset buffer }
- inputbuffer:=nil;
- inputpointer:=nil;
- inputstart:=0;
- { reset line }
- line_no:=0;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- end;
- function tscannerfile.tempopeninputfile:boolean;
- begin
- if inputfile.is_macro then
- exit;
- tempopeninputfile:=inputfile.tempopen;
- { reload buffer }
- inputbuffer:=inputfile.buf;
- inputpointer:=inputfile.buf;
- inputstart:=inputfile.bufstart;
- end;
- procedure tscannerfile.tempcloseinputfile;
- begin
- if inputfile.closed or inputfile.is_macro then
- exit;
- inputfile.setpos(inputstart+(inputpointer-inputbuffer));
- inputfile.tempclose;
- { reset buffer }
- inputbuffer:=nil;
- inputpointer:=nil;
- inputstart:=0;
- end;
- procedure tscannerfile.saveinputfile;
- begin
- inputfile.saveinputpointer:=inputpointer;
- inputfile.savelastlinepos:=lastlinepos;
- inputfile.saveline_no:=line_no;
- end;
- procedure tscannerfile.restoreinputfile;
- begin
- inputbuffer:=inputfile.buf;
- inputpointer:=inputfile.saveinputpointer;
- lastlinepos:=inputfile.savelastlinepos;
- line_no:=inputfile.saveline_no;
- if not inputfile.is_macro then
- parser_current_file:=inputfile.name^;
- end;
- procedure tscannerfile.nextfile;
- var
- to_dispose : tinputfile;
- begin
- if assigned(inputfile.next) then
- begin
- if inputfile.is_macro then
- to_dispose:=inputfile
- else
- begin
- to_dispose:=nil;
- dec(inputfilecount);
- end;
- { we can allways close the file, no ? }
- inputfile.close;
- inputfile:=inputfile.next;
- if assigned(to_dispose) then
- to_dispose.free;
- restoreinputfile;
- end;
- end;
- procedure tscannerfile.startrecordtokens(buf:tdynamicarray);
- begin
- if not assigned(buf) then
- internalerror(200511172);
- if assigned(recordtokenbuf) then
- internalerror(200511173);
- recordtokenbuf:=buf;
- fillchar(last_settings,sizeof(last_settings),0);
- last_message:=nil;
- fillchar(last_filepos,sizeof(last_filepos),0);
- end;
- procedure tscannerfile.stoprecordtokens;
- begin
- if not assigned(recordtokenbuf) then
- internalerror(200511174);
- recordtokenbuf:=nil;
- end;
- procedure tscannerfile.writetoken(t : ttoken);
- var
- b : byte;
- begin
- if ord(t)>$7f then
- begin
- b:=(ord(t) shr 8) or $80;
- recordtokenbuf.write(b,1);
- end;
- b:=ord(t) and $ff;
- recordtokenbuf.write(b,1);
- end;
- procedure tscannerfile.tokenwritesizeint(val : sizeint);
- begin
- recordtokenbuf.write(val,sizeof(sizeint));
- end;
- function tscannerfile.tokenreadsizeint : sizeint;
- var
- val : sizeint;
- begin
- replaytokenbuf.read(val,sizeof(sizeint));
- if tokenbuf_change_endian then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadlongword : longword;
- var
- val : longword;
- begin
- replaytokenbuf.read(val,sizeof(longword));
- if tokenbuf_change_endian then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadlongint : longint;
- var
- val : longint;
- begin
- replaytokenbuf.read(val,sizeof(longint));
- if tokenbuf_change_endian then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadshortint : shortint;
- var
- val : shortint;
- begin
- replaytokenbuf.read(val,sizeof(shortint));
- result:=val;
- end;
- function tscannerfile.tokenreadbyte : byte;
- var
- val : byte;
- begin
- replaytokenbuf.read(val,sizeof(byte));
- result:=val;
- end;
- function tscannerfile.tokenreadsmallint : smallint;
- var
- val : smallint;
- begin
- replaytokenbuf.read(val,sizeof(smallint));
- if tokenbuf_change_endian then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadword : word;
- var
- val : word;
- begin
- replaytokenbuf.read(val,sizeof(word));
- if tokenbuf_change_endian then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadenum(size : longint) : longword;
- begin
- if size=1 then
- result:=tokenreadbyte
- else if size=2 then
- result:=tokenreadword
- else if size=4 then
- result:=tokenreadlongword;
- end;
- procedure tscannerfile.tokenreadset(var b;size : longint);
- var
- i : longint;
- begin
- replaytokenbuf.read(b,size);
- if tokenbuf_change_endian then
- for i:=0 to size-1 do
- Pbyte(@b)[i]:=reverse_byte(Pbyte(@b)[i]);
- end;
- procedure tscannerfile.tokenreadsettings(var asettings : tsettings; expected_size : longint);
- { This procedure
- needs to be changed whenever
- globals.tsettings type is changed,
- the problem is that no error will appear
- before tests with generics are tested. PM }
- var
- startpos, endpos : longword;
- begin
- { WARNING all those fields need to be in the correct
- order otherwise cross_endian PPU reading will fail }
- startpos:=replaytokenbuf.pos;
- with asettings do
- begin
- alignment.procalign:=tokenreadlongint;
- alignment.loopalign:=tokenreadlongint;
- alignment.jumpalign:=tokenreadlongint;
- alignment.constalignmin:=tokenreadlongint;
- alignment.constalignmax:=tokenreadlongint;
- alignment.varalignmin:=tokenreadlongint;
- alignment.varalignmax:=tokenreadlongint;
- alignment.localalignmin:=tokenreadlongint;
- alignment.localalignmax:=tokenreadlongint;
- alignment.recordalignmin:=tokenreadlongint;
- alignment.recordalignmax:=tokenreadlongint;
- alignment.maxCrecordalign:=tokenreadlongint;
- tokenreadset(globalswitches,sizeof(globalswitches));
- tokenreadset(moduleswitches,sizeof(moduleswitches));
- tokenreadset(localswitches,sizeof(localswitches));
- tokenreadset(modeswitches,sizeof(modeswitches));
- tokenreadset(optimizerswitches,sizeof(optimizerswitches));
- tokenreadset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
- tokenreadset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
- tokenreadset(debugswitches,sizeof(debugswitches));
- { 0: old behaviour for sets <=256 elements
- >0: round to this size }
- setalloc:=tokenreadshortint;
- packenum:=tokenreadshortint;
- packrecords:=tokenreadshortint;
- maxfpuregisters:=tokenreadshortint;
- cputype:=tcputype(tokenreadenum(sizeof(tcputype)));
- optimizecputype:=tcputype(tokenreadenum(sizeof(tcputype)));
- fputype:=tfputype(tokenreadenum(sizeof(tfputype)));
- asmmode:=tasmmode(tokenreadenum(sizeof(tasmmode)));
- interfacetype:=tinterfacetypes(tokenreadenum(sizeof(tinterfacetypes)));
- defproccall:=tproccalloption(tokenreadenum(sizeof(tproccalloption)));
- { tstringencoding is word type,
- thus this should be OK here }
- sourcecodepage:=tstringEncoding(tokenreadword);
- minfpconstprec:=tfloattype(tokenreadenum(sizeof(tfloattype)));
- disabledircache:=boolean(tokenreadbyte);
- {$if defined(ARM) or defined(AVR)}
- controllertype:=tcontrollertype(tokenreadenum(sizeof(tcontrollertype)));
- {$endif defined(ARM) or defined(AVR)}
- endpos:=replaytokenbuf.pos;
- if endpos-startpos<>expected_size then
- Comment(V_Error,'Wrong size of Settings read-in');
- end;
- end;
- procedure tscannerfile.recordtoken;
- var
- t : ttoken;
- s : tspecialgenerictoken;
- len,val,msgnb,copy_size : sizeint;
- b : byte;
- pmsg : pmessagestaterecord;
- begin
- if not assigned(recordtokenbuf) then
- internalerror(200511176);
- t:=_GENERICSPECIALTOKEN;
- { settings changed? }
- { last field pmessage is handled separately below in
- ST_LOADMESSAGES }
- if CompareByte(current_settings,last_settings,
- sizeof(current_settings)-sizeof(pointer))<>0 then
- begin
- { use a special token to record it }
- s:=ST_LOADSETTINGS;
- writetoken(t);
- recordtokenbuf.write(s,1);
- copy_size:=sizeof(current_settings)-sizeof(pointer);
- tokenwritesizeint(copy_size);
- recordtokenbuf.write(current_settings,copy_size);
- last_settings:=current_settings;
- end;
- if current_settings.pmessage<>last_message then
- begin
- { use a special token to record it }
- s:=ST_LOADMESSAGES;
- writetoken(t);
- recordtokenbuf.write(s,1);
- msgnb:=0;
- pmsg:=current_settings.pmessage;
- while assigned(pmsg) do
- begin
- if msgnb=high(sizeint) then
- { Too many messages }
- internalerror(2011090401);
- inc(msgnb);
- pmsg:=pmsg^.next;
- end;
- tokenwritesizeint(msgnb);
- pmsg:=current_settings.pmessage;
- while assigned(pmsg) do
- begin
- { What about endianess here? }
- val:=pmsg^.value;
- tokenwritesizeint(val);
- val:=ord(pmsg^.state);
- tokenwritesizeint(val);
- pmsg:=pmsg^.next;
- end;
- last_message:=current_settings.pmessage;
- end;
- { file pos changes? }
- if current_tokenpos.line<>last_filepos.line then
- begin
- s:=ST_LINE;
- writetoken(t);
- recordtokenbuf.write(s,1);
- recordtokenbuf.write(current_tokenpos.line,sizeof(current_tokenpos.line));
- last_filepos.line:=current_tokenpos.line;
- end;
- if current_tokenpos.column<>last_filepos.column then
- begin
- s:=ST_COLUMN;
- writetoken(t);
- { can the column be written packed? }
- if current_tokenpos.column<$80 then
- begin
- b:=$80 or current_tokenpos.column;
- recordtokenbuf.write(b,1);
- end
- else
- begin
- recordtokenbuf.write(s,1);
- recordtokenbuf.write(current_tokenpos.column,sizeof(current_tokenpos.column));
- end;
- last_filepos.column:=current_tokenpos.column;
- end;
- if current_tokenpos.fileindex<>last_filepos.fileindex then
- begin
- s:=ST_FILEINDEX;
- writetoken(t);
- recordtokenbuf.write(s,1);
- recordtokenbuf.write(current_tokenpos.fileindex,sizeof(current_tokenpos.fileindex));
- last_filepos.fileindex:=current_tokenpos.fileindex;
- end;
- writetoken(token);
- if token<>_GENERICSPECIALTOKEN then
- writetoken(idtoken);
- case token of
- _CWCHAR,
- _CWSTRING :
- begin
- tokenwritesizeint(patternw^.len);
- recordtokenbuf.write(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
- end;
- _CSTRING:
- begin
- len:=length(cstringpattern);
- tokenwritesizeint(len);
- recordtokenbuf.write(cstringpattern[1],length(cstringpattern));
- end;
- _CCHAR,
- _INTCONST,
- _REALNUMBER :
- begin
- { pexpr.pas messes with pattern in case of negative integer consts,
- see around line 2562 the comment of JM; remove the - before recording it
- (FK)
- }
- if (token=_INTCONST) and (pattern[1]='-') then
- delete(pattern,1,1);
- recordtokenbuf.write(pattern[0],1);
- recordtokenbuf.write(pattern[1],length(pattern));
- end;
- _ID :
- begin
- recordtokenbuf.write(orgpattern[0],1);
- recordtokenbuf.write(orgpattern[1],length(orgpattern));
- end;
- end;
- end;
- procedure tscannerfile.startreplaytokens(buf:tdynamicarray; achange_endian : boolean);
- begin
- if not assigned(buf) then
- internalerror(200511175);
- { save current token }
- if token in [_CWCHAR,_CWSTRING,_CCHAR,_CSTRING,_INTCONST,_REALNUMBER,_ID] then
- internalerror(200511178);
- replaystack:=treplaystack.create(token,current_settings,
- replaytokenbuf,replaystack,tokenbuf_change_endian);
- if assigned(inputpointer) then
- dec(inputpointer);
- { install buffer }
- replaytokenbuf:=buf;
- tokenbuf_change_endian:=achange_endian;
- { reload next token }
- replaytokenbuf.seek(0);
- replaytoken;
- end;
- function tscannerfile.readtoken: ttoken;
- var
- b,b2 : byte;
- begin
- replaytokenbuf.read(b,1);
- if (b and $80)<>0 then
- begin
- replaytokenbuf.read(b2,1);
- result:=ttoken(((b and $7f) shl 8) or b2);
- end
- else
- result:=ttoken(b);
- end;
- procedure tscannerfile.replaytoken;
- var
- wlen,mesgnb,copy_size : sizeint;
- specialtoken : tspecialgenerictoken;
- i : byte;
- pmsg,prevmsg : pmessagestaterecord;
- begin
- if not assigned(replaytokenbuf) then
- internalerror(200511177);
- { End of replay buffer? Then load the next char from the file again }
- if replaytokenbuf.pos>=replaytokenbuf.size then
- begin
- token:=replaystack.token;
- replaytokenbuf:=replaystack.tokenbuf;
- { restore compiler settings }
- current_settings:=replaystack.settings;
- popreplaystack;
- if assigned(inputpointer) then
- begin
- c:=inputpointer^;
- inc(inputpointer);
- end;
- exit;
- end;
- repeat
- { load token from the buffer }
- token:=readtoken;
- if token<>_GENERICSPECIALTOKEN then
- idtoken:=readtoken
- else
- idtoken:=_NOID;
- case token of
- _CWCHAR,
- _CWSTRING :
- begin
- wlen:=tokenreadsizeint;
- setlengthwidestring(patternw,wlen);
- replaytokenbuf.read(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
- orgpattern:='';
- pattern:='';
- cstringpattern:='';
- end;
- _CSTRING:
- begin
- wlen:=tokenreadsizeint;
- setlength(cstringpattern,wlen);
- replaytokenbuf.read(cstringpattern[1],wlen);
- orgpattern:='';
- pattern:='';
- end;
- _CCHAR,
- _INTCONST,
- _REALNUMBER :
- begin
- replaytokenbuf.read(pattern[0],1);
- replaytokenbuf.read(pattern[1],length(pattern));
- orgpattern:='';
- end;
- _ID :
- begin
- replaytokenbuf.read(orgpattern[0],1);
- replaytokenbuf.read(orgpattern[1],length(orgpattern));
- pattern:=upper(orgpattern);
- end;
- _GENERICSPECIALTOKEN:
- begin
- replaytokenbuf.read(specialtoken,1);
- { packed column? }
- if (ord(specialtoken) and $80)<>0 then
- begin
- current_tokenpos.column:=ord(specialtoken) and $7f;
- { don't generate invalid line info if no sources are available for the current module }
- if not(get_module(current_filepos.moduleindex).sources_avail) then
- current_tokenpos.column:=0;
- current_filepos:=current_tokenpos;
- end
- else
- case specialtoken of
- ST_LOADSETTINGS:
- begin
- copy_size:=tokenreadsizeint;
- if copy_size <> sizeof(current_settings)-sizeof(pointer) then
- internalerror(2011090501);
- {
- replaytokenbuf.read(current_settings,copy_size);
- }
- tokenreadsettings(current_settings,copy_size);
- end;
- ST_LOADMESSAGES:
- begin
- current_settings.pmessage:=nil;
- mesgnb:=tokenreadsizeint;
- if mesgnb>0 then
- Comment(V_Error,'Message recordind not yet supported');
- for i:=1 to mesgnb do
- begin
- new(pmsg);
- if i=1 then
- begin
- current_settings.pmessage:=pmsg;
- prevmsg:=nil;
- end
- else
- prevmsg^.next:=pmsg;
- replaytokenbuf.read(pmsg^.value,sizeof(longint));
- replaytokenbuf.read(pmsg^.state,sizeof(tmsgstate));
- pmsg^.next:=nil;
- prevmsg:=pmsg;
- end;
- end;
- ST_LINE:
- begin
- current_tokenpos.line:=tokenreadlongint;
- { don't generate invalid line info if no sources are available for the current module }
- if not(get_module(current_filepos.moduleindex).sources_avail) then
- current_tokenpos.line:=0;
- current_filepos:=current_tokenpos;
- end;
- ST_COLUMN:
- begin
- current_tokenpos.column:=tokenreadword;
- { don't generate invalid line info if no sources are available for the current module }
- if not(get_module(current_filepos.moduleindex).sources_avail) then
- current_tokenpos.column:=0;
- current_filepos:=current_tokenpos;
- end;
- ST_FILEINDEX:
- begin
- current_tokenpos.fileindex:=tokenreadword;
- { don't generate invalid line info if no sources are available for the current module }
- if not(get_module(current_filepos.moduleindex).sources_avail) then
- begin
- current_tokenpos.column:=0;
- current_tokenpos.line:=0;
- end;
- current_filepos:=current_tokenpos;
- end;
- else
- internalerror(2006103010);
- end;
- continue;
- end;
- end;
- break;
- until false;
- end;
- procedure tscannerfile.addfile(hp:tinputfile);
- begin
- saveinputfile;
- { add to list }
- hp.next:=inputfile;
- inputfile:=hp;
- { load new inputfile }
- restoreinputfile;
- end;
- procedure tscannerfile.reload;
- begin
- with inputfile do
- begin
- { when nothing more to read then leave immediatly, so we
- don't change the current_filepos and leave it point to the last
- char }
- if (c=#26) and (not assigned(next)) then
- exit;
- repeat
- { still more to read?, then change the #0 to a space so its seen
- as a seperator, this can't be used for macro's which can change
- the place of the #0 in the buffer with tempopen }
- if (c=#0) and (bufsize>0) and
- not(inputfile.is_macro) and
- (inputpointer-inputbuffer<bufsize) then
- begin
- c:=' ';
- inc(inputpointer);
- exit;
- end;
- { can we read more from this file ? }
- if (c<>#26) and (not endoffile) then
- begin
- readbuf;
- inputpointer:=buf;
- inputbuffer:=buf;
- inputstart:=bufstart;
- { first line? }
- if line_no=0 then
- begin
- c:=inputpointer^;
- { eat utf-8 signature? }
- if (ord(inputpointer^)=$ef) and
- (ord((inputpointer+1)^)=$bb) and
- (ord((inputpointer+2)^)=$bf) then
- begin
- inc(inputpointer,3);
- message(scan_c_switching_to_utf8);
- current_settings.sourcecodepage:=CP_UTF8;
- include(current_settings.moduleswitches,cs_explicit_codepage);
- end;
- line_no:=1;
- if cs_asm_source in current_settings.globalswitches then
- inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);
- end;
- end
- else
- begin
- { load eof position in tokenpos/current_filepos }
- gettokenpos;
- { close file }
- closeinputfile;
- { no next module, than EOF }
- if not assigned(inputfile.next) then
- begin
- c:=#26;
- exit;
- end;
- { load next file and reopen it }
- nextfile;
- tempopeninputfile;
- { status }
- Message1(scan_t_back_in,inputfile.name^);
- end;
- { load next char }
- c:=inputpointer^;
- inc(inputpointer);
- until c<>#0; { if also end, then reload again }
- end;
- end;
- procedure tscannerfile.insertmacro(const macname:string;p:pchar;len,line,fileindex:longint);
- var
- hp : tinputfile;
- begin
- { save old postion }
- dec(inputpointer);
- tempcloseinputfile;
- { create macro 'file' }
- { use special name to dispose after !! }
- hp:=do_openinputfile('_Macro_.'+macname);
- addfile(hp);
- with inputfile do
- begin
- setmacro(p,len);
- { local buffer }
- inputbuffer:=buf;
- inputpointer:=buf;
- inputstart:=bufstart;
- ref_index:=fileindex;
- end;
- { reset line }
- line_no:=line;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- { load new c }
- c:=inputpointer^;
- inc(inputpointer);
- end;
- procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
- begin
- tokenpos:=inputstart+(inputpointer-inputbuffer);
- filepos.line:=line_no;
- filepos.column:=tokenpos-lastlinepos;
- filepos.fileindex:=inputfile.ref_index;
- filepos.moduleindex:=current_module.unit_index;
- end;
- procedure tscannerfile.gettokenpos;
- { load the values of tokenpos and lasttokenpos }
- begin
- do_gettokenpos(lasttokenpos,current_tokenpos);
- current_filepos:=current_tokenpos;
- end;
- procedure tscannerfile.cachenexttokenpos;
- begin
- do_gettokenpos(nexttokenpos,next_filepos);
- end;
- procedure tscannerfile.setnexttoken;
- begin
- token:=nexttoken;
- nexttoken:=NOTOKEN;
- lasttokenpos:=nexttokenpos;
- current_tokenpos:=next_filepos;
- current_filepos:=current_tokenpos;
- nexttokenpos:=0;
- end;
- procedure tscannerfile.savetokenpos;
- begin
- oldlasttokenpos:=lasttokenpos;
- oldcurrent_filepos:=current_filepos;
- oldcurrent_tokenpos:=current_tokenpos;
- end;
- procedure tscannerfile.restoretokenpos;
- begin
- lasttokenpos:=oldlasttokenpos;
- current_filepos:=oldcurrent_filepos;
- current_tokenpos:=oldcurrent_tokenpos;
- end;
- procedure tscannerfile.inc_comment_level;
- begin
- if (m_nested_comment in current_settings.modeswitches) then
- inc(comment_level)
- else
- comment_level:=1;
- if (comment_level>1) then
- begin
- savetokenpos;
- gettokenpos; { update for warning }
- Message1(scan_w_comment_level,tostr(comment_level));
- restoretokenpos;
- end;
- end;
- procedure tscannerfile.dec_comment_level;
- begin
- if (m_nested_comment in current_settings.modeswitches) then
- dec(comment_level)
- else
- comment_level:=0;
- end;
- procedure tscannerfile.linebreak;
- var
- cur : char;
- begin
- with inputfile do
- begin
- if (byte(inputpointer^)=0) and not(endoffile) then
- begin
- cur:=c;
- reload;
- if byte(cur)+byte(c)<>23 then
- dec(inputpointer);
- end
- else
- begin
- { Support all combination of #10 and #13 as line break }
- if (byte(inputpointer^)+byte(c)=23) then
- inc(inputpointer);
- end;
- { Always return #10 as line break }
- c:=#10;
- { increase line counters }
- lastlinepos:=inputstart+(inputpointer-inputbuffer);
- inc(line_no);
- { update linebuffer }
- if cs_asm_source in current_settings.globalswitches then
- inputfile.setline(line_no,lastlinepos);
- { update for status and call the show status routine,
- but don't touch current_filepos ! }
- savetokenpos;
- gettokenpos; { update for v_status }
- inc(status.compiledlines);
- ShowStatus;
- restoretokenpos;
- end;
- end;
- procedure tscannerfile.illegal_char(c:char);
- var
- s : string;
- begin
- if c in [#32..#255] then
- s:=''''+c+''''
- else
- s:='#'+tostr(ord(c));
- Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
- end;
- procedure tscannerfile.end_of_file;
- begin
- checkpreprocstack;
- Message(scan_f_end_of_file);
- end;
- {-------------------------------------------
- IF Conditional Handling
- -------------------------------------------}
- procedure tscannerfile.checkpreprocstack;
- begin
- { check for missing ifdefs }
- while assigned(preprocstack) do
- begin
- Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
- preprocstack.owner.inputfile.name^,tostr(preprocstack.line_nb));
- poppreprocstack;
- end;
- end;
- procedure tscannerfile.poppreprocstack;
- var
- hp : tpreprocstack;
- begin
- if assigned(preprocstack) then
- begin
- Message1(scan_c_endif_found,preprocstack.name);
- hp:=preprocstack.next;
- preprocstack.free;
- preprocstack:=hp;
- end
- else
- Message(scan_e_endif_without_if);
- end;
- procedure tscannerfile.ifpreprocstack(atyp : preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
- var
- condition: Boolean;
- valuedescr: String;
- begin
- if (preprocstack=nil) or preprocstack.accept then
- condition:= compile_time_predicate(valuedescr)
- else
- begin
- condition:= false;
- valuedescr:= '';
- end;
- preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
- preprocstack.name:=valuedescr;
- preprocstack.line_nb:=line_no;
- preprocstack.owner:=self;
- if preprocstack.accept then
- Message2(messid,preprocstack.name,'accepted')
- else
- Message2(messid,preprocstack.name,'rejected');
- end;
- procedure tscannerfile.elsepreprocstack;
- begin
- if assigned(preprocstack) and
- (preprocstack.typ<>pp_else) then
- begin
- if (preprocstack.typ=pp_elseif) then
- preprocstack.accept:=false
- else
- if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
- preprocstack.accept:=not preprocstack.accept;
- preprocstack.typ:=pp_else;
- preprocstack.line_nb:=line_no;
- if preprocstack.accept then
- Message2(scan_c_else_found,preprocstack.name,'accepted')
- else
- Message2(scan_c_else_found,preprocstack.name,'rejected');
- end
- else
- Message(scan_e_endif_without_if);
- end;
- procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
- var
- valuedescr: String;
- begin
- if assigned(preprocstack) and
- (preprocstack.typ in [pp_if,pp_elseif]) then
- begin
- { when the branch is accepted we use pp_elseif so we know that
- all the next branches need to be rejected. when this branch is still
- not accepted then leave it at pp_if }
- if (preprocstack.typ=pp_elseif) then
- preprocstack.accept:=false
- else if (preprocstack.typ=pp_if) and preprocstack.accept then
- begin
- preprocstack.accept:=false;
- preprocstack.typ:=pp_elseif;
- end
- else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
- and compile_time_predicate(valuedescr) then
- begin
- preprocstack.name:=valuedescr;
- preprocstack.accept:=true;
- preprocstack.typ:=pp_elseif;
- end;
- preprocstack.line_nb:=line_no;
- if preprocstack.accept then
- Message2(scan_c_else_found,preprocstack.name,'accepted')
- else
- Message2(scan_c_else_found,preprocstack.name,'rejected');
- end
- else
- Message(scan_e_endif_without_if);
- end;
- procedure tscannerfile.popreplaystack;
- var
- hp : treplaystack;
- begin
- if assigned(replaystack) then
- begin
- hp:=replaystack.next;
- replaystack.free;
- replaystack:=hp;
- if assigned (replaystack) then
- tokenbuf_change_endian:=replaystack.change_endian
- else
- tokenbuf_change_endian:=false;
- end;
- end;
- procedure tscannerfile.handleconditional(p:tdirectiveitem);
- begin
- savetokenpos;
- repeat
- current_scanner.gettokenpos;
- p.proc();
- { accept the text ? }
- if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
- break
- else
- begin
- current_scanner.gettokenpos;
- Message(scan_c_skipping_until);
- repeat
- current_scanner.skipuntildirective;
- if not (m_mac in current_settings.modeswitches) then
- p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))
- else
- p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));
- until assigned(p) and (p.is_conditional);
- current_scanner.gettokenpos;
- Message1(scan_d_handling_switch,'$'+p.name);
- end;
- until false;
- restoretokenpos;
- end;
- procedure tscannerfile.handledirectives;
- var
- t : tdirectiveitem;
- hs : string;
- begin
- gettokenpos;
- readchar; {Remove the $}
- hs:=readid;
- { handle empty directive }
- if hs='' then
- begin
- Message1(scan_w_illegal_switch,'$');
- exit;
- end;
- {$ifdef PREPROCWRITE}
- if parapreprocess then
- begin
- t:=Get_Directive(hs);
- if not(is_conditional(t) or (t=_DIR_DEFINE) or (t=_DIR_UNDEF)) then
- begin
- preprocfile^.AddSpace;
- preprocfile^.Add('{$'+hs+current_scanner.readcomment+'}');
- exit;
- end;
- end;
- {$endif PREPROCWRITE}
- { skip this directive? }
- if (ignoredirectives.find(hs)<>nil) then
- begin
- if (comment_level>0) then
- readcomment;
- { we've read the whole comment }
- aktcommentstyle:=comment_none;
- exit;
- end;
- { Check for compiler switches }
- while (length(hs)=1) and (c in ['-','+']) do
- begin
- HandleSwitch(hs[1],c);
- current_scanner.readchar; {Remove + or -}
- if c=',' then
- begin
- current_scanner.readchar; {Remove , }
- { read next switch, support $v+,$+}
- hs:=current_scanner.readid;
- if (hs='') then
- begin
- if (c='$') and (m_fpc in current_settings.modeswitches) then
- begin
- current_scanner.readchar; { skip $ }
- hs:=current_scanner.readid;
- end;
- if (hs='') then
- Message1(scan_w_illegal_directive,'$'+c);
- end
- else
- Message1(scan_d_handling_switch,'$'+hs);
- end
- else
- hs:='';
- end;
- { directives may follow switches after a , }
- if hs<>'' then
- begin
- if not (m_mac in current_settings.modeswitches) then
- t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
- else
- t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
- if assigned(t) then
- begin
- if t.is_conditional then
- handleconditional(t)
- else
- begin
- Message1(scan_d_handling_switch,'$'+hs);
- t.proc();
- end;
- end
- else
- begin
- current_scanner.ignoredirectives.Add(hs,nil);
- Message1(scan_w_illegal_directive,'$'+hs);
- end;
- { conditionals already read the comment }
- if (current_scanner.comment_level>0) then
- current_scanner.readcomment;
- { we've read the whole comment }
- aktcommentstyle:=comment_none;
- end;
- end;
- procedure tscannerfile.readchar;
- begin
- c:=inputpointer^;
- if c=#0 then
- reload
- else
- inc(inputpointer);
- end;
- procedure tscannerfile.readstring;
- var
- i : longint;
- err : boolean;
- begin
- err:=false;
- i:=0;
- repeat
- case c of
- '_',
- '0'..'9',
- 'A'..'Z' :
- begin
- if i<255 then
- begin
- inc(i);
- orgpattern[i]:=c;
- pattern[i]:=c;
- end
- else
- begin
- if not err then
- begin
- Message(scan_e_string_exceeds_255_chars);
- err:=true;
- end;
- end;
- c:=inputpointer^;
- inc(inputpointer);
- end;
- 'a'..'z' :
- begin
- if i<255 then
- begin
- inc(i);
- orgpattern[i]:=c;
- pattern[i]:=chr(ord(c)-32)
- end
- else
- begin
- if not err then
- begin
- Message(scan_e_string_exceeds_255_chars);
- err:=true;
- end;
- end;
- c:=inputpointer^;
- inc(inputpointer);
- end;
- #0 :
- reload;
- else
- break;
- end;
- until false;
- orgpattern[0]:=chr(i);
- pattern[0]:=chr(i);
- end;
- procedure tscannerfile.readnumber;
- var
- base,
- i : longint;
- begin
- case c of
- '%' :
- begin
- readchar;
- base:=2;
- pattern[1]:='%';
- i:=1;
- end;
- '&' :
- begin
- readchar;
- base:=8;
- pattern[1]:='&';
- i:=1;
- end;
- '$' :
- begin
- readchar;
- base:=16;
- pattern[1]:='$';
- i:=1;
- end;
- else
- begin
- base:=10;
- i:=0;
- end;
- end;
- while ((base>=10) and (c in ['0'..'9'])) or
- ((base=16) and (c in ['A'..'F','a'..'f'])) or
- ((base=8) and (c in ['0'..'7'])) or
- ((base=2) and (c in ['0'..'1'])) do
- begin
- if i<255 then
- begin
- inc(i);
- pattern[i]:=c;
- end;
- readchar;
- end;
- pattern[0]:=chr(i);
- end;
- function tscannerfile.readid:string;
- begin
- readstring;
- readid:=pattern;
- end;
- function tscannerfile.readval:longint;
- var
- l : longint;
- w : integer;
- begin
- readnumber;
- val(pattern,l,w);
- readval:=l;
- end;
- function tscannerfile.readval_asstring:string;
- begin
- readnumber;
- readval_asstring:=pattern;
- end;
- function tscannerfile.readcomment:string;
- var
- i : longint;
- begin
- i:=0;
- repeat
- case c of
- '{' :
- begin
- if aktcommentstyle=comment_tp then
- inc_comment_level;
- end;
- '}' :
- begin
- if aktcommentstyle=comment_tp then
- begin
- readchar;
- dec_comment_level;
- if comment_level=0 then
- break
- else
- continue;
- end;
- end;
- '*' :
- begin
- if aktcommentstyle=comment_oldtp then
- begin
- readchar;
- if c=')' then
- begin
- readchar;
- dec_comment_level;
- break;
- end
- else
- { Add both characters !!}
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:='*';
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:=c;
- end;
- end;
- end
- else
- { Not old TP comment, so add...}
- begin
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:='*';
- end;
- end;
- end;
- #10,#13 :
- linebreak;
- #26 :
- end_of_file;
- else
- begin
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:=c;
- end;
- end;
- end;
- readchar;
- until false;
- readcomment[0]:=chr(i);
- end;
- function tscannerfile.readquotedstring:string;
- var
- i : longint;
- msgwritten : boolean;
- begin
- i:=0;
- msgwritten:=false;
- if (c='''') then
- begin
- repeat
- readchar;
- case c of
- #26 :
- end_of_file;
- #10,#13 :
- Message(scan_f_string_exceeds_line);
- '''' :
- begin
- readchar;
- if c<>'''' then
- break;
- end;
- end;
- if i<255 then
- begin
- inc(i);
- result[i]:=c;
- end
- else
- begin
- if not msgwritten then
- begin
- Message(scan_e_string_exceeds_255_chars);
- msgwritten:=true;
- end;
- end;
- until false;
- end;
- result[0]:=chr(i);
- end;
- function tscannerfile.readstate:char;
- var
- state : char;
- begin
- state:=' ';
- if c=' ' then
- begin
- current_scanner.skipspace;
- current_scanner.readid;
- if pattern='ON' then
- state:='+'
- else
- if pattern='OFF' then
- state:='-';
- end
- else
- state:=c;
- if not (state in ['+','-']) then
- Message(scan_e_wrong_switch_toggle);
- readstate:=state;
- end;
- function tscannerfile.readstatedefault:char;
- var
- state : char;
- begin
- state:=' ';
- if c=' ' then
- begin
- current_scanner.skipspace;
- current_scanner.readid;
- if pattern='ON' then
- state:='+'
- else
- if pattern='OFF' then
- state:='-'
- else
- if pattern='DEFAULT' then
- state:='*';
- end
- else
- state:=c;
- if not (state in ['+','-','*']) then
- Message(scan_e_wrong_switch_toggle_default);
- readstatedefault:=state;
- end;
- procedure tscannerfile.skipspace;
- begin
- repeat
- case c of
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- break;
- continue;
- end;
- #10,
- #13 :
- linebreak;
- #9,#11,#12,' ' :
- ;
- else
- break;
- end;
- readchar;
- until false;
- end;
- procedure tscannerfile.skipuntildirective;
- var
- found : longint;
- next_char_loaded : boolean;
- begin
- found:=0;
- next_char_loaded:=false;
- repeat
- case c of
- #10,
- #13 :
- linebreak;
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- '{' :
- begin
- if (aktcommentstyle in [comment_tp,comment_none]) then
- begin
- aktcommentstyle:=comment_tp;
- if (comment_level=0) then
- found:=1;
- inc_comment_level;
- end;
- end;
- '*' :
- begin
- if (aktcommentstyle=comment_oldtp) then
- begin
- readchar;
- if c=')' then
- begin
- dec_comment_level;
- found:=0;
- aktcommentstyle:=comment_none;
- end
- else
- next_char_loaded:=true;
- end
- else
- found := 0;
- end;
- '}' :
- begin
- if (aktcommentstyle=comment_tp) then
- begin
- dec_comment_level;
- if (comment_level=0) then
- aktcommentstyle:=comment_none;
- found:=0;
- end;
- end;
- '$' :
- begin
- if found=1 then
- found:=2;
- end;
- '''' :
- if (aktcommentstyle=comment_none) then
- begin
- repeat
- readchar;
- case c of
- #26 :
- end_of_file;
- #10,#13 :
- break;
- '''' :
- begin
- readchar;
- if c<>'''' then
- begin
- next_char_loaded:=true;
- break;
- end;
- end;
- end;
- until false;
- end;
- '(' :
- begin
- if (aktcommentstyle=comment_none) then
- begin
- readchar;
- if c='*' then
- begin
- readchar;
- if c='$' then
- begin
- found:=2;
- inc_comment_level;
- aktcommentstyle:=comment_oldtp;
- end
- else
- begin
- skipoldtpcomment;
- next_char_loaded:=true;
- end;
- end
- else
- next_char_loaded:=true;
- end
- else
- found:=0;
- end;
- '/' :
- begin
- if (aktcommentstyle=comment_none) then
- begin
- readchar;
- if c='/' then
- skipdelphicomment;
- next_char_loaded:=true;
- end
- else
- found:=0;
- end;
- else
- found:=0;
- end;
- if next_char_loaded then
- next_char_loaded:=false
- else
- readchar;
- until (found=2);
- end;
- {****************************************************************************
- Comment Handling
- ****************************************************************************}
- procedure tscannerfile.skipcomment;
- begin
- aktcommentstyle:=comment_tp;
- readchar;
- inc_comment_level;
- { handle compiler switches }
- if (c='$') then
- handledirectives;
- { handle_switches can dec comment_level, }
- while (comment_level>0) do
- begin
- case c of
- '{' :
- inc_comment_level;
- '}' :
- dec_comment_level;
- #10,#13 :
- linebreak;
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- end;
- readchar;
- end;
- aktcommentstyle:=comment_none;
- end;
- procedure tscannerfile.skipdelphicomment;
- begin
- aktcommentstyle:=comment_delphi;
- inc_comment_level;
- readchar;
- { this is not supported }
- if c='$' then
- Message(scan_w_wrong_styled_switch);
- { skip comment }
- while not (c in [#10,#13,#26]) do
- readchar;
- dec_comment_level;
- aktcommentstyle:=comment_none;
- end;
- procedure tscannerfile.skipoldtpcomment;
- var
- found : longint;
- begin
- aktcommentstyle:=comment_oldtp;
- inc_comment_level;
- { only load a char if last already processed,
- was cause of bug1634 PM }
- if c=#0 then
- readchar;
- { this is now supported }
- if (c='$') then
- handledirectives;
- { skip comment }
- while (comment_level>0) do
- begin
- found:=0;
- repeat
- case c of
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- #10,#13 :
- begin
- if found=4 then
- inc_comment_level;
- linebreak;
- found:=0;
- end;
- '*' :
- begin
- if found=3 then
- found:=4
- else
- found:=1;
- end;
- ')' :
- begin
- if found in [1,4] then
- begin
- dec_comment_level;
- if comment_level=0 then
- found:=2
- else
- found:=0;
- end
- else
- found:=0;
- end;
- '(' :
- begin
- if found=4 then
- inc_comment_level;
- found:=3;
- end;
- else
- begin
- if found=4 then
- inc_comment_level;
- found:=0;
- end;
- end;
- readchar;
- until (found=2);
- end;
- aktcommentstyle:=comment_none;
- end;
- {****************************************************************************
- Token Scanner
- ****************************************************************************}
- procedure tscannerfile.readtoken(allowrecordtoken:boolean);
- var
- code : integer;
- len,
- low,high,mid : longint;
- w : word;
- m : longint;
- mac : tmacro;
- asciinr : string[6];
- iswidestring : boolean;
- label
- exit_label;
- begin
- flushpendingswitchesstate;
- { record tokens? }
- if allowrecordtoken and
- assigned(recordtokenbuf) then
- recordtoken;
- { replay tokens? }
- if assigned(replaytokenbuf) then
- begin
- replaytoken;
- goto exit_label;
- end;
- { was there already a token read, then return that token }
- if nexttoken<>NOTOKEN then
- begin
- setnexttoken;
- goto exit_label;
- end;
- { Skip all spaces and comments }
- repeat
- case c of
- '{' :
- skipcomment;
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- break;
- end;
- ' ',#9..#13 :
- begin
- {$ifdef PREPROCWRITE}
- if parapreprocess then
- begin
- if c=#10 then
- preprocfile.eolfound:=true
- else
- preprocfile.spacefound:=true;
- end;
- {$endif PREPROCWRITE}
- skipspace;
- end
- else
- break;
- end;
- until false;
- { Save current token position, for EOF its already loaded }
- if c<>#26 then
- gettokenpos;
- { Check first for a identifier/keyword, this is 20+% faster (PFV) }
- if c in ['A'..'Z','a'..'z','_'] then
- begin
- readstring;
- token:=_ID;
- idtoken:=_ID;
- { keyword or any other known token,
- pattern is always uppercased }
- if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
- begin
- low:=ord(tokenidx^[length(pattern),pattern[1]].first);
- high:=ord(tokenidx^[length(pattern),pattern[1]].last);
- while low<high do
- begin
- mid:=(high+low+1) shr 1;
- if pattern<tokeninfo^[ttoken(mid)].str then
- high:=mid-1
- else
- low:=mid;
- end;
- with tokeninfo^[ttoken(high)] do
- if pattern=str then
- begin
- if keyword in current_settings.modeswitches then
- if op=NOTOKEN then
- token:=ttoken(high)
- else
- token:=op;
- idtoken:=ttoken(high);
- end;
- end;
- { Only process identifiers and not keywords }
- if token=_ID then
- begin
- { this takes some time ... }
- if (cs_support_macro in current_settings.moduleswitches) then
- begin
- mac:=tmacro(search_macro(pattern));
- if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
- begin
- if yylexcount<max_macro_nesting then
- begin
- mac.is_used:=true;
- inc(yylexcount);
- insertmacro(pattern,mac.buftext,mac.buflen,
- mac.fileinfo.line,mac.fileinfo.fileindex);
- { handle empty macros }
- if c=#0 then
- reload;
- readtoken(false);
- { that's all folks }
- dec(yylexcount);
- exit;
- end
- else
- Message(scan_w_macro_too_deep);
- end;
- end;
- end;
- { return token }
- goto exit_label;
- end
- else
- begin
- idtoken:=_NOID;
- case c of
- '$' :
- begin
- readnumber;
- token:=_INTCONST;
- goto exit_label;
- end;
- '%' :
- begin
- if not(m_fpc in current_settings.modeswitches) then
- Illegal_Char(c)
- else
- begin
- readnumber;
- token:=_INTCONST;
- goto exit_label;
- end;
- end;
- '&' :
- begin
- if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then
- begin
- readnumber;
- if length(pattern)=1 then
- begin
- readstring;
- token:=_ID;
- idtoken:=_ID;
- end
- else
- token:=_INTCONST;
- goto exit_label;
- end
- else if m_mac in current_settings.modeswitches then
- begin
- readchar;
- token:=_AMPERSAND;
- goto exit_label;
- end
- else
- Illegal_Char(c);
- end;
- '0'..'9' :
- begin
- readnumber;
- if (c in ['.','e','E']) then
- begin
- { first check for a . }
- if c='.' then
- begin
- cachenexttokenpos;
- readchar;
- { is it a .. from a range? }
- case c of
- '.' :
- begin
- readchar;
- token:=_INTCONST;
- nexttoken:=_POINTPOINT;
- goto exit_label;
- end;
- ')' :
- begin
- readchar;
- token:=_INTCONST;
- nexttoken:=_RECKKLAMMER;
- goto exit_label;
- end;
- end;
- { insert the number after the . }
- pattern:=pattern+'.';
- while c in ['0'..'9'] do
- begin
- pattern:=pattern+c;
- readchar;
- end;
- end;
- { E can also follow after a point is scanned }
- if c in ['e','E'] then
- begin
- pattern:=pattern+'E';
- readchar;
- if c in ['-','+'] then
- begin
- pattern:=pattern+c;
- readchar;
- end;
- if not(c in ['0'..'9']) then
- Illegal_Char(c);
- while c in ['0'..'9'] do
- begin
- pattern:=pattern+c;
- readchar;
- end;
- end;
- token:=_REALNUMBER;
- goto exit_label;
- end;
- token:=_INTCONST;
- goto exit_label;
- end;
- ';' :
- begin
- readchar;
- token:=_SEMICOLON;
- goto exit_label;
- end;
- '[' :
- begin
- readchar;
- token:=_LECKKLAMMER;
- goto exit_label;
- end;
- ']' :
- begin
- readchar;
- token:=_RECKKLAMMER;
- goto exit_label;
- end;
- '(' :
- begin
- readchar;
- case c of
- '*' :
- begin
- c:=#0;{Signal skipoldtpcomment to reload a char }
- skipoldtpcomment;
- readtoken(false);
- exit;
- end;
- '.' :
- begin
- readchar;
- token:=_LECKKLAMMER;
- goto exit_label;
- end;
- end;
- token:=_LKLAMMER;
- goto exit_label;
- end;
- ')' :
- begin
- readchar;
- token:=_RKLAMMER;
- goto exit_label;
- end;
- '+' :
- begin
- readchar;
- if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_PLUSASN;
- goto exit_label;
- end;
- token:=_PLUS;
- goto exit_label;
- end;
- '-' :
- begin
- readchar;
- if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_MINUSASN;
- goto exit_label;
- end;
- token:=_MINUS;
- goto exit_label;
- end;
- ':' :
- begin
- readchar;
- if c='=' then
- begin
- readchar;
- token:=_ASSIGNMENT;
- goto exit_label;
- end;
- token:=_COLON;
- goto exit_label;
- end;
- '*' :
- begin
- readchar;
- if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_STARASN;
- end
- else
- if c='*' then
- begin
- readchar;
- token:=_STARSTAR;
- end
- else
- token:=_STAR;
- goto exit_label;
- end;
- '/' :
- begin
- readchar;
- case c of
- '=' :
- begin
- if (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_SLASHASN;
- goto exit_label;
- end;
- end;
- '/' :
- begin
- skipdelphicomment;
- readtoken(false);
- exit;
- end;
- end;
- token:=_SLASH;
- goto exit_label;
- end;
- '|' :
- if m_mac in current_settings.modeswitches then
- begin
- readchar;
- token:=_PIPE;
- goto exit_label;
- end
- else
- Illegal_Char(c);
- '=' :
- begin
- readchar;
- token:=_EQ;
- goto exit_label;
- end;
- '.' :
- begin
- readchar;
- case c of
- '.' :
- begin
- readchar;
- case c of
- '.' :
- begin
- readchar;
- token:=_POINTPOINTPOINT;
- goto exit_label;
- end;
- else
- begin
- token:=_POINTPOINT;
- goto exit_label;
- end;
- end;
- end;
- ')' :
- begin
- readchar;
- token:=_RECKKLAMMER;
- goto exit_label;
- end;
- end;
- token:=_POINT;
- goto exit_label;
- end;
- '@' :
- begin
- readchar;
- token:=_KLAMMERAFFE;
- goto exit_label;
- end;
- ',' :
- begin
- readchar;
- token:=_COMMA;
- goto exit_label;
- end;
- '''','#','^' :
- begin
- len:=0;
- cstringpattern:='';
- iswidestring:=false;
- if c='^' then
- begin
- readchar;
- c:=upcase(c);
- if (block_type in [bt_type,bt_const_type,bt_var_type]) or
- (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or
- (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
- begin
- token:=_CARET;
- goto exit_label;
- end
- else
- begin
- inc(len);
- setlength(cstringpattern,256);
- if c<#64 then
- cstringpattern[len]:=chr(ord(c)+64)
- else
- cstringpattern[len]:=chr(ord(c)-64);
- readchar;
- end;
- end;
- repeat
- case c of
- '#' :
- begin
- readchar; { read # }
- case c of
- '$':
- begin
- readchar; { read leading $ }
- asciinr:='$';
- while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=5) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- '&':
- begin
- readchar; { read leading $ }
- asciinr:='&';
- while (upcase(c) in ['0'..'7']) and (length(asciinr)<=7) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- '%':
- begin
- readchar; { read leading $ }
- asciinr:='%';
- while (upcase(c) in ['0','1']) and (length(asciinr)<=17) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- else
- begin
- asciinr:='';
- while (c in ['0'..'9']) and (length(asciinr)<=5) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- end;
- val(asciinr,m,code);
- if (asciinr='') or (code<>0) then
- Message(scan_e_illegal_char_const)
- else if (m<0) or (m>255) or (length(asciinr)>3) then
- begin
- if (m>=0) and (m<=65535) then
- begin
- if not iswidestring then
- begin
- if len>0 then
- ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
- else
- ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
- iswidestring:=true;
- len:=0;
- end;
- concatwidestringchar(patternw,tcompilerwidechar(m));
- end
- else
- Message(scan_e_illegal_char_const)
- end
- else if iswidestring then
- concatwidestringchar(patternw,asciichar2unicode(char(m)))
- else
- begin
- if len>=length(cstringpattern) then
- setlength(cstringpattern,length(cstringpattern)+256);
- inc(len);
- cstringpattern[len]:=chr(m);
- end;
- end;
- '''' :
- begin
- repeat
- readchar;
- case c of
- #26 :
- end_of_file;
- #10,#13 :
- Message(scan_f_string_exceeds_line);
- '''' :
- begin
- readchar;
- if c<>'''' then
- break;
- end;
- end;
- { interpret as utf-8 string? }
- if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then
- begin
- { convert existing string to an utf-8 string }
- if not iswidestring then
- begin
- if len>0 then
- ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
- else
- ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
- iswidestring:=true;
- len:=0;
- end;
- { four or more chars aren't handled }
- if (ord(c) and $f0)=$f0 then
- message(scan_e_utf8_bigger_than_65535)
- { three chars }
- else if (ord(c) and $e0)=$e0 then
- begin
- w:=ord(c) and $f;
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- w:=(w shl 6) or (ord(c) and $3f);
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- w:=(w shl 6) or (ord(c) and $3f);
- concatwidestringchar(patternw,w);
- end
- { two chars }
- else if (ord(c) and $c0)<>0 then
- begin
- w:=ord(c) and $1f;
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- w:=(w shl 6) or (ord(c) and $3f);
- concatwidestringchar(patternw,w);
- end
- { illegal }
- else if (ord(c) and $80)<>0 then
- message(scan_e_utf8_malformed)
- else
- concatwidestringchar(patternw,tcompilerwidechar(c))
- end
- else if iswidestring then
- begin
- if current_settings.sourcecodepage=CP_UTF8 then
- concatwidestringchar(patternw,ord(c))
- else
- concatwidestringchar(patternw,asciichar2unicode(c))
- end
- else
- begin
- if len>=length(cstringpattern) then
- setlength(cstringpattern,length(cstringpattern)+256);
- inc(len);
- cstringpattern[len]:=c;
- end;
- until false;
- end;
- '^' :
- begin
- readchar;
- c:=upcase(c);
- if c<#64 then
- c:=chr(ord(c)+64)
- else
- c:=chr(ord(c)-64);
- if iswidestring then
- concatwidestringchar(patternw,asciichar2unicode(c))
- else
- begin
- if len>=length(cstringpattern) then
- setlength(cstringpattern,length(cstringpattern)+256);
- inc(len);
- cstringpattern[len]:=c;
- end;
- readchar;
- end;
- else
- break;
- end;
- until false;
- { strings with length 1 become const chars }
- if iswidestring then
- begin
- if patternw^.len=1 then
- token:=_CWCHAR
- else
- token:=_CWSTRING;
- end
- else
- begin
- setlength(cstringpattern,len);
- if length(cstringpattern)=1 then
- begin
- token:=_CCHAR;
- pattern:=cstringpattern;
- end
- else
- token:=_CSTRING;
- end;
- goto exit_label;
- end;
- '>' :
- begin
- readchar;
- if (block_type in [bt_type,bt_var_type,bt_const_type]) then
- token:=_RSHARPBRACKET
- else
- begin
- case c of
- '=' :
- begin
- readchar;
- token:=_GTE;
- goto exit_label;
- end;
- '>' :
- begin
- readchar;
- token:=_OP_SHR;
- goto exit_label;
- end;
- '<' :
- begin { >< is for a symetric diff for sets }
- readchar;
- token:=_SYMDIF;
- goto exit_label;
- end;
- end;
- token:=_GT;
- end;
- goto exit_label;
- end;
- '<' :
- begin
- readchar;
- if (block_type in [bt_type,bt_var_type,bt_const_type]) then
- token:=_LSHARPBRACKET
- else
- begin
- case c of
- '>' :
- begin
- readchar;
- token:=_NE;
- goto exit_label;
- end;
- '=' :
- begin
- readchar;
- token:=_LTE;
- goto exit_label;
- end;
- '<' :
- begin
- readchar;
- token:=_OP_SHL;
- goto exit_label;
- end;
- end;
- token:=_LT;
- end;
- goto exit_label;
- end;
- #26 :
- begin
- token:=_EOF;
- checkpreprocstack;
- goto exit_label;
- end;
- else
- Illegal_Char(c);
- end;
- end;
- exit_label:
- lasttoken:=token;
- end;
- function tscannerfile.readpreproc:ttoken;
- begin
- skipspace;
- case c of
- '_',
- 'A'..'Z',
- 'a'..'z' :
- begin
- current_scanner.preproc_pattern:=readid;
- readpreproc:=_ID;
- end;
- '0'..'9' :
- begin
- current_scanner.preproc_pattern:=readval_asstring;
- { realnumber? }
- if c='.' then
- begin
- readchar;
- while c in ['0'..'9'] do
- begin
- current_scanner.preproc_pattern:=current_scanner.preproc_pattern+c;
- readchar;
- end;
- end;
- readpreproc:=_ID;
- end;
- '$','%','&' :
- begin
- current_scanner.preproc_pattern:=readval_asstring;
- readpreproc:=_ID;
- end;
- ',' :
- begin
- readchar;
- readpreproc:=_COMMA;
- end;
- '}' :
- begin
- readpreproc:=_END;
- end;
- '(' :
- begin
- readchar;
- readpreproc:=_LKLAMMER;
- end;
- ')' :
- begin
- readchar;
- readpreproc:=_RKLAMMER;
- end;
- '[' :
- begin
- readchar;
- readpreproc:=_LECKKLAMMER;
- end;
- ']' :
- begin
- readchar;
- readpreproc:=_RECKKLAMMER;
- end;
- '+' :
- begin
- readchar;
- readpreproc:=_PLUS;
- end;
- '-' :
- begin
- readchar;
- readpreproc:=_MINUS;
- end;
- '*' :
- begin
- readchar;
- readpreproc:=_STAR;
- end;
- '/' :
- begin
- readchar;
- readpreproc:=_SLASH;
- end;
- '=' :
- begin
- readchar;
- readpreproc:=_EQ;
- end;
- '>' :
- begin
- readchar;
- if c='=' then
- begin
- readchar;
- readpreproc:=_GTE;
- end
- else
- readpreproc:=_GT;
- end;
- '<' :
- begin
- readchar;
- case c of
- '>' :
- begin
- readchar;
- readpreproc:=_NE;
- end;
- '=' :
- begin
- readchar;
- readpreproc:=_LTE;
- end;
- else
- readpreproc:=_LT;
- end;
- end;
- #26 :
- begin
- readpreproc:=_EOF;
- checkpreprocstack;
- end;
- else
- Illegal_Char(c);
- end;
- end;
- function tscannerfile.asmgetcharstart : char;
- begin
- { return first the character already
- available in c }
- lastasmgetchar:=c;
- result:=asmgetchar;
- end;
- function tscannerfile.asmgetchar : char;
- begin
- if lastasmgetchar<>#0 then
- begin
- c:=lastasmgetchar;
- lastasmgetchar:=#0;
- end
- else
- readchar;
- if in_asm_string then
- begin
- asmgetchar:=c;
- exit;
- end;
- repeat
- case c of
- // the { ... } is used in ARM assembler to define register sets, so we can't used
- // it as comment, either (* ... *), /* ... */ or // ... should be used instead.
- // But compiler directives {$...} are allowed in ARM assembler.
- '{' :
- begin
- {$ifdef arm}
- readchar;
- dec(inputpointer);
- if c<>'$' then
- begin
- asmgetchar:='{';
- exit;
- end
- else
- {$endif arm}
- skipcomment;
- end;
- #10,#13 :
- begin
- linebreak;
- asmgetchar:=c;
- exit;
- end;
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- '/' :
- begin
- readchar;
- if c='/' then
- skipdelphicomment
- else
- begin
- asmgetchar:='/';
- lastasmgetchar:=c;
- exit;
- end;
- end;
- '(' :
- begin
- readchar;
- if c='*' then
- begin
- c:=#0;{Signal skipoldtpcomment to reload a char }
- skipoldtpcomment;
- end
- else
- begin
- asmgetchar:='(';
- lastasmgetchar:=c;
- exit;
- end;
- end;
- else
- begin
- asmgetchar:=c;
- exit;
- end;
- end;
- until false;
- end;
- {*****************************************************************************
- Helpers
- *****************************************************************************}
- procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- begin
- if dm in [directive_all, directive_turbo] then
- tdirectiveitem.create(turbo_scannerdirectives,s,p);
- if dm in [directive_all, directive_mac] then
- tdirectiveitem.create(mac_scannerdirectives,s,p);
- end;
- procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- begin
- if dm in [directive_all, directive_turbo] then
- tdirectiveitem.createcond(turbo_scannerdirectives,s,p);
- if dm in [directive_all, directive_mac] then
- tdirectiveitem.createcond(mac_scannerdirectives,s,p);
- end;
- {*****************************************************************************
- Initialization
- *****************************************************************************}
- procedure InitScanner;
- begin
- InitWideString(patternw);
- turbo_scannerdirectives:=TFPHashObjectList.Create;
- mac_scannerdirectives:=TFPHashObjectList.Create;
- { Common directives and conditionals }
- AddDirective('I',directive_all, @dir_include);
- AddDirective('DEFINE',directive_all, @dir_define);
- AddDirective('UNDEF',directive_all, @dir_undef);
- AddConditional('IF',directive_all, @dir_if);
- AddConditional('IFDEF',directive_all, @dir_ifdef);
- AddConditional('IFNDEF',directive_all, @dir_ifndef);
- AddConditional('ELSE',directive_all, @dir_else);
- AddConditional('ELSEIF',directive_all, @dir_elseif);
- AddConditional('ENDIF',directive_all, @dir_endif);
- { Directives and conditionals for all modes except mode macpas}
- AddDirective('INCLUDE',directive_turbo, @dir_include);
- AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
- AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
- AddDirective('EXTENSION',directive_turbo, @dir_extension);
- AddConditional('IFEND',directive_turbo, @dir_endif);
- AddConditional('IFOPT',directive_turbo, @dir_ifopt);
- { Directives and conditionals for mode macpas: }
- AddDirective('SETC',directive_mac, @dir_setc);
- AddDirective('DEFINEC',directive_mac, @dir_definec);
- AddDirective('UNDEFC',directive_mac, @dir_undef);
- AddConditional('IFC',directive_mac, @dir_if);
- AddConditional('ELSEC',directive_mac, @dir_else);
- AddConditional('ELIFC',directive_mac, @dir_elseif);
- AddConditional('ENDC',directive_mac, @dir_endif);
- end;
- procedure DoneScanner;
- begin
- turbo_scannerdirectives.Free;
- mac_scannerdirectives.Free;
- DoneWideString(patternw);
- end;
- end.
|