scanner.pas 181 KB

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