scanner.pas 186 KB

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