scanner.pas 177 KB

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