12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891 |
- {
- Copyright (c) 1998-2002 by Florian Klaempfl
- This unit implements the scanner part and handling of the switches
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit scanner;
- {$i fpcdefs.inc}
- interface
- uses
- cclasses,
- globtype,globals,constexp,version,tokens,
- verbose,comphook,
- finput,
- widestr;
- const
- max_include_nesting=32;
- max_macro_nesting=16;
- preprocbufsize=32*1024;
- type
- tcommentstyle = (comment_none,comment_tp,comment_oldtp,comment_delphi,comment_c);
- tscannerfile = class;
- preproctyp = (pp_ifdef,pp_ifndef,pp_if,pp_ifopt,pp_else,pp_elseif);
- tpreprocstack = class
- typ : preproctyp;
- accept : boolean;
- next : tpreprocstack;
- name : TIDString;
- line_nb : longint;
- fileindex : longint;
- constructor Create(atyp:preproctyp;a:boolean;n:tpreprocstack);
- end;
- tdirectiveproc=procedure;
- tdirectiveitem = class(TFPHashObject)
- public
- is_conditional : boolean;
- proc : tdirectiveproc;
- constructor Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- constructor CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- end;
- // stack for replay buffers
- treplaystack = class
- token : ttoken;
- idtoken : ttoken;
- orgpattern,
- pattern : string;
- cstringpattern: ansistring;
- patternw : pcompilerwidestring;
- settings : tsettings;
- tokenbuf : tdynamicarray;
- tokenbuf_needs_swapping : boolean;
- next : treplaystack;
- constructor Create(atoken: ttoken;aidtoken:ttoken;
- const aorgpattern,apattern:string;const acstringpattern:ansistring;
- apatternw:pcompilerwidestring;asettings:tsettings;
- atokenbuf:tdynamicarray;change_endian:boolean;anext:treplaystack);
- destructor destroy;override;
- end;
- tcompile_time_predicate = function(var valuedescr: String) : Boolean;
- tspecialgenerictoken =
- (ST_LOADSETTINGS,
- ST_LINE,
- ST_COLUMN,
- ST_FILEINDEX,
- ST_LOADMESSAGES);
- { tscannerfile }
- tscannerfile = class
- private
- procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
- procedure cachenexttokenpos;
- procedure setnexttoken;
- procedure savetokenpos;
- procedure restoretokenpos;
- procedure writetoken(t: ttoken);
- function readtoken : ttoken;
- public
- inputfile : tinputfile; { current inputfile list }
- inputfilecount : longint;
- inputbuffer, { input buffer }
- inputpointer : pchar;
- inputstart : longint;
- line_no, { line }
- lastlinepos : longint;
- lasttokenpos,
- nexttokenpos : longint; { token }
- lasttoken,
- nexttoken : ttoken;
- oldlasttokenpos : longint; { temporary saving/restoring tokenpos }
- oldcurrent_filepos,
- oldcurrent_tokenpos : tfileposinfo;
- replaytokenbuf,
- recordtokenbuf : tdynamicarray;
- { last settings we stored }
- last_settings : tsettings;
- last_message : pmessagestaterecord;
- { last filepos we stored }
- last_filepos,
- { if nexttoken<>NOTOKEN, then nexttokenpos holds its filepos }
- next_filepos : tfileposinfo;
- { current macro nesting depth }
- macro_nesting_depth,
- comment_level,
- yylexcount : longint;
- ignoredirectives : TFPHashList; { ignore directives, used to give warnings only once }
- preprocstack : tpreprocstack;
- replaystack : treplaystack;
- preproc_pattern : string;
- preproc_token : ttoken;
- { true, if we are parsing preprocessor expressions }
- in_preproc_comp_expr : boolean;
- { true if tokens must be converted to opposite endianess}
- change_endian_for_replay : boolean;
- constructor Create(const fn:string; is_macro: boolean = false);
- destructor Destroy;override;
- { File buffer things }
- function openinputfile:boolean;
- procedure closeinputfile;
- function tempopeninputfile:boolean;
- procedure tempcloseinputfile;
- procedure saveinputfile;
- procedure restoreinputfile;
- procedure firstfile;
- procedure nextfile;
- procedure addfile(hp:tinputfile);
- procedure reload;
- { replaces current token with the text in p }
- procedure substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint);
- { Scanner things }
- procedure gettokenpos;
- procedure inc_comment_level;
- procedure dec_comment_level;
- procedure illegal_char(c:char);
- procedure end_of_file;
- procedure checkpreprocstack;
- procedure poppreprocstack;
- procedure ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
- procedure elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
- procedure elsepreprocstack;
- procedure popreplaystack;
- function replay_stack_depth:longint;
- procedure handleconditional(p:tdirectiveitem);
- procedure handledirectives;
- procedure linebreak;
- procedure recordtoken;
- procedure startrecordtokens(buf:tdynamicarray);
- procedure stoprecordtokens;
- function is_recording_tokens:boolean;
- procedure replaytoken;
- procedure startreplaytokens(buf:tdynamicarray; change_endian:boolean);
- { bit length asizeint is target depend }
- procedure tokenwritesizeint(val : asizeint);
- procedure tokenwritelongint(val : longint);
- procedure tokenwritelongword(val : longword);
- procedure tokenwriteword(val : word);
- procedure tokenwriteshortint(val : shortint);
- procedure tokenwriteset(var b;size : longint);
- procedure tokenwriteenum(var b;size : longint);
- function tokenreadsizeint : asizeint;
- procedure tokenwritesettings(var asettings : tsettings; var size : asizeint);
- { longword/longint are 32 bits on all targets }
- { word/smallint are 16-bits on all targest }
- function tokenreadlongword : longword;
- function tokenreadword : word;
- function tokenreadlongint : longint;
- function tokenreadsmallint : smallint;
- { short int is one a signed byte }
- function tokenreadshortint : shortint;
- function tokenreadbyte : byte;
- { This one takes the set size as an parameter }
- procedure tokenreadset(var b;size : longint);
- function tokenreadenum(size : longint) : longword;
- procedure tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
- procedure readchar;
- procedure readstring;
- procedure readnumber;
- function readid:string;
- function readval:longint;
- function readcomment(include_special_char: boolean = false):string;
- function readquotedstring:string;
- function readstate:char;
- function readoptionalstate(fallback:char):char;
- function readstatedefault:char;
- procedure skipspace;
- procedure skipuntildirective;
- procedure skipcomment(read_first_char:boolean);
- procedure skipdelphicomment;
- procedure skipoldtpcomment(read_first_char:boolean);
- procedure readtoken(allowrecordtoken:boolean);
- function readpreproc:ttoken;
- function readpreprocint(var value:int64;const place:string):boolean;
- function asmgetchar:char;
- end;
- {$ifdef PREPROCWRITE}
- tpreprocfile=class
- f : text;
- buf : pointer;
- spacefound,
- eolfound : boolean;
- constructor create(const fn:string);
- destructor destroy; override;
- procedure Add(const s:string);
- procedure AddSpace;
- end;
- {$endif PREPROCWRITE}
- var
- { read strings }
- c : char;
- orgpattern,
- pattern : string;
- cstringpattern : ansistring;
- patternw : pcompilerwidestring;
- { token }
- token, { current token being parsed }
- idtoken : ttoken; { holds the token if the pattern is a known word }
- current_scanner : tscannerfile; { current scanner in use }
- current_commentstyle : tcommentstyle; { needed to use read_comment from directives }
- {$ifdef PREPROCWRITE}
- preprocfile : tpreprocfile; { used with only preprocessing }
- {$endif PREPROCWRITE}
- type
- tdirectivemode = (directive_all, directive_turbo, directive_mac);
- procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- procedure InitScanner;
- procedure DoneScanner;
- { To be called when the language mode is finally determined }
- Function SetCompileMode(const s:string; changeInit: boolean):boolean;
- Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
- procedure SetAppType(NewAppType:tapptype);
- implementation
- uses
- SysUtils,
- cutils,cfileutl,
- systems,
- switches,
- symbase,symtable,symtype,symsym,symconst,symdef,defutil,
- { This is needed for tcputype }
- cpuinfo,
- fmodule,fppu,
- { this is needed for $I %CURRENTROUTINE%}
- procinfo
- {$if FPC_FULLVERSION<20700}
- ,ccharset
- {$endif}
- ;
- var
- { dictionaries with the supported directives }
- turbo_scannerdirectives : TFPHashObjectList; { for other modes }
- mac_scannerdirectives : TFPHashObjectList; { for mode mac }
- {*****************************************************************************
- Helper routines
- *****************************************************************************}
- const
- { use any special name that is an invalid file name to avoid problems }
- preprocstring : array [preproctyp] of string[7]
- = ('$IFDEF','$IFNDEF','$IF','$IFOPT','$ELSE','$ELSEIF');
- function is_keyword(const s:string):boolean;
- var
- low,high,mid : longint;
- begin
- if not (length(s) in [tokenlenmin..tokenlenmax]) or
- not (s[1] in ['a'..'z','A'..'Z']) then
- begin
- is_keyword:=false;
- exit;
- end;
- low:=ord(tokenidx^[length(s),s[1]].first);
- high:=ord(tokenidx^[length(s),s[1]].last);
- while low<high do
- begin
- mid:=(high+low+1) shr 1;
- if pattern<tokeninfo^[ttoken(mid)].str then
- high:=mid-1
- else
- low:=mid;
- end;
- is_keyword:=(pattern=tokeninfo^[ttoken(high)].str) and
- ((tokeninfo^[ttoken(high)].keyword*current_settings.modeswitches)<>[]);
- end;
- Procedure HandleModeSwitches(switch: tmodeswitch; changeInit: boolean);
- begin
- { turn ansi/unicodestrings on by default ? (only change when this
- particular setting is changed, so that a random modeswitch won't
- change the state of $h+/$h-) }
- if switch in [m_none,m_default_ansistring,m_default_unicodestring] then
- begin
- if ([m_default_ansistring,m_default_unicodestring]*current_settings.modeswitches)<>[] then
- begin
- { can't have both ansistring and unicodestring as default }
- if switch=m_default_ansistring then
- begin
- exclude(current_settings.modeswitches,m_default_unicodestring);
- if changeinit then
- exclude(init_settings.modeswitches,m_default_unicodestring);
- end
- else if switch=m_default_unicodestring then
- begin
- exclude(current_settings.modeswitches,m_default_ansistring);
- if changeinit then
- exclude(init_settings.modeswitches,m_default_ansistring);
- end;
- { enable $h+ }
- include(current_settings.localswitches,cs_refcountedstrings);
- if changeinit then
- include(init_settings.localswitches,cs_refcountedstrings);
- if m_default_unicodestring in current_settings.modeswitches then
- begin
- def_system_macro('FPC_UNICODESTRINGS');
- def_system_macro('UNICODE');
- end;
- end
- else
- begin
- exclude(current_settings.localswitches,cs_refcountedstrings);
- if changeinit then
- exclude(init_settings.localswitches,cs_refcountedstrings);
- undef_system_macro('FPC_UNICODESTRINGS');
- undef_system_macro('UNICODE');
- end;
- end;
- { turn inline on by default ? }
- if switch in [m_none,m_default_inline] then
- begin
- if (m_default_inline in current_settings.modeswitches) then
- begin
- include(current_settings.localswitches,cs_do_inline);
- if changeinit then
- include(init_settings.localswitches,cs_do_inline);
- end
- else
- begin
- exclude(current_settings.localswitches,cs_do_inline);
- if changeinit then
- exclude(init_settings.localswitches,cs_do_inline);
- end;
- end;
- { turn on system codepage by default }
- if switch in [m_none,m_systemcodepage] then
- begin
- { both m_systemcodepage and specifying a code page via -FcXXX or
- "$codepage XXX" change current_settings.sourcecodepage. If
- we used -FcXXX and then have a sourcefile with "$mode objfpc",
- this routine will be called to disable m_systemcodepage (to ensure
- it's off in case it would have been set on the command line, or
- by a previous mode(switch).
- In that case, we have to ensure that we don't overwrite
- current_settings.sourcecodepage, as that would cancel out the
- -FcXXX. This is why we use two separate module switches
- (cs_explicit_codepage and cs_system_codepage) for the same setting
- (current_settings.sourcecodepage)
- }
- if m_systemcodepage in current_settings.modeswitches then
- begin
- { m_systemcodepage gets enabled -> disable any -FcXXX and
- "codepage XXX" settings (exclude cs_explicit_codepage), and
- overwrite the sourcecode page }
- current_settings.sourcecodepage:=DefaultSystemCodePage;
- if (current_settings.sourcecodepage<>CP_UTF8) and not cpavailable(current_settings.sourcecodepage) then
- begin
- Message2(scan_w_unavailable_system_codepage,IntToStr(current_settings.sourcecodepage),IntToStr(default_settings.sourcecodepage));
- current_settings.sourcecodepage:=default_settings.sourcecodepage;
- end;
- exclude(current_settings.moduleswitches,cs_explicit_codepage);
- include(current_settings.moduleswitches,cs_system_codepage);
- if changeinit then
- begin
- init_settings.sourcecodepage:=current_settings.sourcecodepage;
- exclude(init_settings.moduleswitches,cs_explicit_codepage);
- include(init_settings.moduleswitches,cs_system_codepage);
- end;
- end
- else
- begin
- { m_systemcodepage gets disabled -> reset sourcecodepage only if
- cs_explicit_codepage is not set (it may be set in the scenario
- where -FcXXX was passed on the command line and then "$mode
- fpc" is used, because then the caller of this routine will
- set the "$mode fpc" modeswitches (which don't include
- m_systemcodepage) and call this routine with m_none).
- Or it can happen if -FcXXX was passed, and the sourcefile
- contains "$modeswitch systemcodepage-" statement.
- Since we unset cs_system_codepage if m_systemcodepage gets
- activated, we will revert to the default code page if you
- set a source file code page, then enable the systemcode page
- and finally disable it again. We don't keep a stack of
- settings, by design. The only thing we have to ensure is that
- disabling m_systemcodepage if it wasn't on in the first place
- doesn't overwrite the sourcecodepage }
- exclude(current_settings.moduleswitches,cs_system_codepage);
- if not(cs_explicit_codepage in current_settings.moduleswitches) then
- current_settings.sourcecodepage:=default_settings.sourcecodepage;
- if changeinit then
- begin
- exclude(init_settings.moduleswitches,cs_system_codepage);
- if not(cs_explicit_codepage in init_settings.moduleswitches) then
- init_settings.sourcecodepage:=default_settings.sourcecodepage;
- end;
- end;
- end;
- {$ifdef i8086}
- { enable cs_force_far_calls when m_nested_procvars is enabled }
- if switch=m_nested_procvars then
- begin
- include(current_settings.localswitches,cs_force_far_calls);
- if changeinit then
- include(init_settings.localswitches,cs_force_far_calls);
- end;
- {$endif i8086}
- end;
- Function SetCompileMode(const s:string; changeInit: boolean):boolean;
- var
- b : boolean;
- oldmodeswitches : tmodeswitches;
- begin
- oldmodeswitches:=current_settings.modeswitches;
- b:=true;
- if s='DEFAULT' then
- current_settings.modeswitches:=fpcmodeswitches
- else
- if s='DELPHI' then
- current_settings.modeswitches:=delphimodeswitches
- else
- if s='DELPHIUNICODE' then
- current_settings.modeswitches:=delphiunicodemodeswitches
- else
- if s='TP' then
- current_settings.modeswitches:=tpmodeswitches
- else
- if s='FPC' then begin
- current_settings.modeswitches:=fpcmodeswitches;
- { TODO: enable this for 2.3/2.9 }
- // include(current_settings.localswitches, cs_typed_addresses);
- end else
- if s='OBJFPC' then begin
- current_settings.modeswitches:=objfpcmodeswitches;
- { TODO: enable this for 2.3/2.9 }
- // include(current_settings.localswitches, cs_typed_addresses);
- end
- {$ifdef gpc_mode}
- else if s='GPC' then
- current_settings.modeswitches:=gpcmodeswitches
- {$endif}
- else
- if s='MACPAS' then
- current_settings.modeswitches:=macmodeswitches
- else
- if s='ISO' then
- current_settings.modeswitches:=isomodeswitches
- else
- if s='EXTENDEDPASCAL' then
- current_settings.modeswitches:=extpasmodeswitches
- else
- b:=false;
- {$ifdef jvm}
- { enable final fields by default for the JVM targets }
- include(current_settings.modeswitches,m_final_fields);
- {$endif jvm}
- if b and changeInit then
- init_settings.modeswitches := current_settings.modeswitches;
- if b then
- begin
- { resolve all postponed switch changes }
- flushpendingswitchesstate;
- HandleModeSwitches(m_none,changeinit);
- { turn on bitpacking and case checking for mode macpas and iso pascal,
- as well as extended pascal }
- if ([m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_bitpacking);
- include(current_settings.localswitches,cs_check_all_case_coverage);
- if changeinit then
- begin
- include(init_settings.localswitches,cs_bitpacking);
- include(init_settings.localswitches,cs_check_all_case_coverage);
- end;
- end;
- { support goto/label by default in delphi/tp7/mac/iso/extpas modes }
- if ([m_delphi,m_tp7,m_mac,m_iso,m_extpas] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.moduleswitches,cs_support_goto);
- if changeinit then
- include(init_settings.moduleswitches,cs_support_goto);
- end;
- { support pointer math by default in fpc/objfpc modes }
- if ([m_fpc,m_objfpc] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_pointermath);
- if changeinit then
- include(init_settings.localswitches,cs_pointermath);
- end
- else
- begin
- exclude(current_settings.localswitches,cs_pointermath);
- if changeinit then
- exclude(init_settings.localswitches,cs_pointermath);
- end;
- { Default enum and set packing for delphi/tp7 }
- if (m_tp7 in current_settings.modeswitches) or
- (m_delphi in current_settings.modeswitches) then
- begin
- current_settings.packenum:=1;
- current_settings.setalloc:=1;
- end
- else if (m_mac in current_settings.modeswitches) then
- { compatible with Metrowerks Pascal }
- current_settings.packenum:=2
- else
- current_settings.packenum:=4;
- if changeinit then
- begin
- init_settings.packenum:=current_settings.packenum;
- init_settings.setalloc:=current_settings.setalloc;
- end;
- {$if defined(i386) or defined(i8086)}
- { Default to intel assembler for delphi/tp7 on i386/i8086 }
- if (m_delphi in current_settings.modeswitches) or
- (m_tp7 in current_settings.modeswitches) then
- begin
- {$ifdef i8086}
- current_settings.asmmode:=asmmode_i8086_intel;
- {$else i8086}
- current_settings.asmmode:=asmmode_i386_intel;
- {$endif i8086}
- if changeinit then
- init_settings.asmmode:=current_settings.asmmode;
- end;
- {$endif i386 or i8086}
- { Exception support explicitly turned on (mainly for macpas, to }
- { compensate for lack of interprocedural goto support) }
- if (cs_support_exceptions in current_settings.globalswitches) then
- include(current_settings.modeswitches,m_except);
- { Default strict string var checking in TP/Delphi modes }
- if ([m_delphi,m_tp7] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_strict_var_strings);
- if changeinit then
- include(init_settings.localswitches,cs_strict_var_strings);
- end;
- { in delphi mode, excess precision is by default on }
- if ([m_delphi] * current_settings.modeswitches <> []) then
- begin
- include(current_settings.localswitches,cs_excessprecision);
- if changeinit then
- include(init_settings.localswitches,cs_excessprecision);
- end;
- {$ifdef i8086}
- { Do not force far calls in the TP mode by default, force it in other modes }
- if (m_tp7 in current_settings.modeswitches) then
- begin
- exclude(current_settings.localswitches,cs_force_far_calls);
- if changeinit then
- exclude(init_settings.localswitches,cs_force_far_calls);
- end
- else
- begin
- include(current_settings.localswitches,cs_force_far_calls);
- if changeinit then
- include(init_settings.localswitches,cs_force_far_calls);
- end;
- {$endif i8086}
- { Undefine old symbol }
- if (m_delphi in oldmodeswitches) then
- undef_system_macro('FPC_DELPHI')
- else if (m_tp7 in oldmodeswitches) then
- undef_system_macro('FPC_TP')
- else if (m_objfpc in oldmodeswitches) then
- undef_system_macro('FPC_OBJFPC')
- {$ifdef gpc_mode}
- else if (m_gpc in oldmodeswitches) then
- undef_system_macro('FPC_GPC')
- {$endif}
- else if (m_mac in oldmodeswitches) then
- undef_system_macro('FPC_MACPAS')
- else if (m_iso in oldmodeswitches) then
- undef_system_macro('FPC_ISO')
- else if (m_extpas in oldmodeswitches) then
- undef_system_macro('FPC_EXTENDEDPASCAL');
- { define new symbol in delphi,objfpc,tp,gpc,macpas mode }
- if (m_delphi in current_settings.modeswitches) then
- def_system_macro('FPC_DELPHI')
- else if (m_tp7 in current_settings.modeswitches) then
- def_system_macro('FPC_TP')
- else if (m_objfpc in current_settings.modeswitches) then
- def_system_macro('FPC_OBJFPC')
- {$ifdef gpc_mode}
- else if (m_gpc in current_settings.modeswitches) then
- def_system_macro('FPC_GPC')
- {$endif}
- else if (m_mac in current_settings.modeswitches) then
- def_system_macro('FPC_MACPAS')
- else if (m_iso in current_settings.modeswitches) then
- def_system_macro('FPC_ISO')
- else if (m_extpas in current_settings.modeswitches) then
- def_system_macro('FPC_EXTENDEDPASCAL');
- end;
- SetCompileMode:=b;
- end;
- Function SetCompileModeSwitch(s:string; changeInit: boolean):boolean;
- var
- i : tmodeswitch;
- doinclude : boolean;
- begin
- s:=upper(s);
- { on/off? }
- doinclude:=true;
- case s[length(s)] of
- '+':
- s:=copy(s,1,length(s)-1);
- '-':
- begin
- s:=copy(s,1,length(s)-1);
- doinclude:=false;
- end;
- end;
- Result:=false;
- for i:=m_class to high(tmodeswitch) do
- if s=modeswitchstr[i] then
- begin
- { Objective-C is currently only supported for Darwin targets }
- if doinclude and
- (i in [m_objectivec1,m_objectivec2]) and
- not(target_info.system in systems_objc_supported) then
- begin
- Message1(option_unsupported_target_for_feature,'Objective-C');
- break;
- end;
- { Blocks supported? }
- if doinclude and
- (i = m_blocks) and
- not(target_info.system in systems_blocks_supported) then
- begin
- Message1(option_unsupported_target_for_feature,'Blocks');
- break;
- end;
- if changeInit then
- current_settings.modeswitches:=init_settings.modeswitches;
- Result:=true;
- if doinclude then
- begin
- include(current_settings.modeswitches,i);
- { Objective-C 2.0 support implies 1.0 support }
- if (i=m_objectivec2) then
- include(current_settings.modeswitches,m_objectivec1);
- if (i in [m_objectivec1,m_objectivec2]) then
- include(current_settings.modeswitches,m_class);
- end
- else
- begin
- exclude(current_settings.modeswitches,i);
- { Objective-C 2.0 support implies 1.0 support }
- if (i=m_objectivec2) then
- exclude(current_settings.modeswitches,m_objectivec1);
- if (i in [m_objectivec1,m_objectivec2]) and
- ([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then
- exclude(current_settings.modeswitches,m_class);
- end;
- { set other switches depending on changed mode switch }
- HandleModeSwitches(i,changeinit);
- if changeInit then
- init_settings.modeswitches:=current_settings.modeswitches;
- break;
- end;
- end;
- procedure SetAppType(NewAppType:tapptype);
- begin
- {$ifdef i8086}
- if (target_info.system in [system_i8086_msdos,system_i8086_embedded]) and (apptype<>NewAppType) then
- begin
- if NewAppType=app_com then
- begin
- targetinfos[target_info.system]^.exeext:='.com';
- target_info.exeext:='.com';
- end
- else
- begin
- targetinfos[target_info.system]^.exeext:='.exe';
- target_info.exeext:='.exe';
- end;
- end;
- {$endif i8086}
- if apptype in [app_cui,app_com] then
- undef_system_macro('CONSOLE');
- apptype:=NewAppType;
- if apptype in [app_cui,app_com] then
- def_system_macro('CONSOLE');
- end;
- {*****************************************************************************
- Conditional Directives
- *****************************************************************************}
- procedure dir_else;
- begin
- current_scanner.elsepreprocstack;
- end;
- procedure dir_endif;
- begin
- current_scanner.poppreprocstack;
- end;
- function isdef(var valuedescr: String): Boolean;
- var
- hs : string;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- valuedescr:= hs;
- if hs='' then
- Message(scan_e_error_in_preproc_expr);
- isdef:=defined_macro(hs);
- end;
- procedure dir_ifdef;
- begin
- current_scanner.ifpreprocstack(pp_ifdef,@isdef,scan_c_ifdef_found);
- end;
- function isnotdef(var valuedescr: String): Boolean;
- var
- hs : string;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- valuedescr:= hs;
- if hs='' then
- Message(scan_e_error_in_preproc_expr);
- isnotdef:=not defined_macro(hs);
- end;
- procedure dir_ifndef;
- begin
- current_scanner.ifpreprocstack(pp_ifndef,@isnotdef,scan_c_ifndef_found);
- end;
- function opt_check(var valuedescr: String): Boolean;
- var
- hs : string;
- state : char;
- begin
- opt_check:= false;
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- valuedescr:= hs;
- if (length(hs)>1) then
- Message1(scan_w_illegal_switch,hs)
- else
- begin
- state:=current_scanner.ReadState;
- if state in ['-','+'] then
- opt_check:=CheckSwitch(hs[1],state)
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- end;
- procedure dir_ifopt;
- begin
- flushpendingswitchesstate;
- current_scanner.ifpreprocstack(pp_ifopt,@opt_check,scan_c_ifopt_found);
- end;
- procedure dir_libprefix;
- var
- s : string;
- begin
- current_scanner.skipspace;
- if c <> '''' then
- Message2(scan_f_syn_expected, '''', c);
- s := current_scanner.readquotedstring;
- stringdispose(outputprefix);
- outputprefix := stringdup(s);
- with current_module do
- setfilename(paramfn, paramallowoutput);
- end;
- procedure dir_libsuffix;
- var
- s : string;
- begin
- current_scanner.skipspace;
- if c <> '''' then
- Message2(scan_f_syn_expected, '''', c);
- s := current_scanner.readquotedstring;
- stringdispose(outputsuffix);
- outputsuffix := stringdup(s);
- with current_module do
- setfilename(paramfn, paramallowoutput);
- end;
- procedure dir_extension;
- var
- s : string;
- begin
- current_scanner.skipspace;
- if c <> '''' then
- Message2(scan_f_syn_expected, '''', c);
- s := current_scanner.readquotedstring;
- if OutputFileName='' then
- OutputFileName:=InputFileName;
- OutputFileName:=ChangeFileExt(OutputFileName,'.'+s);
- with current_module do
- setfilename(paramfn, paramallowoutput);
- end;
- {
- Compile time expression type check
- ----------------------------------
- Each subexpression returns its type to the caller, which then can
- do type check. Since data types of compile time expressions is
- not well defined, the type system does a best effort. The drawback is
- that some errors might not be detected.
- Instead of returning a particular data type, a set of possible data types
- are returned. This way ambigouos types can be handled. For instance a
- value of 1 can be both a boolean and and integer.
- Booleans
- --------
- The following forms of boolean values are supported:
- * C coded, that is 0 is false, non-zero is true.
- * TRUE/FALSE for mac style compile time variables
- Thus boolean mac compile time variables are always stored as TRUE/FALSE.
- When a compile time expression is evaluated, they are then translated
- to C coded booleans (0/1), to simplify for the expression evaluator.
- Note that this scheme then also of support mac compile time variables which
- are 0/1 but with a boolean meaning.
- The TRUE/FALSE format is new from 22 august 2005, but the above scheme
- means that units which is not recompiled, and thus stores
- compile time variables as the old format (0/1), continue to work.
- Short circuit evaluation
- ------------------------
- For this to work, the part of a compile time expression which is short
- circuited, should not be evaluated, while it still should be parsed.
- Therefor there is a parameter eval, telling whether evaluation is needed.
- In case not, the value returned can be arbitrary.
- }
- type
- { texprvalue }
- texprvalue = class
- private
- { we can't use built-in defs since they
- may be not created at the moment }
- class var
- sintdef,uintdef,booldef,strdef,setdef,realdef: tdef;
- class constructor createdefs;
- class destructor destroydefs;
- public
- consttyp: tconsttyp;
- value: tconstvalue;
- def: tdef;
- constructor create_const(c:tconstsym);
- constructor create_error;
- constructor create_ord(v: Tconstexprint);
- constructor create_int(v: int64);
- constructor create_uint(v: qword);
- constructor create_bool(b: boolean);
- constructor create_str(s: string);
- constructor create_set(ns: tnormalset);
- constructor create_real(r: bestreal);
- class function try_parse_number(s:string):texprvalue; static;
- class function try_parse_real(s:string):texprvalue; static;
- function evaluate(v:texprvalue;op:ttoken):texprvalue;
- procedure error(expecteddef, place: string);
- function isBoolean: Boolean;
- function isInt: Boolean;
- function asBool: Boolean;
- function asInt: Integer;
- function asInt64: Int64;
- function asStr: String;
- destructor destroy; override;
- end;
- class constructor texprvalue.createdefs;
- begin
- { do not use corddef etc here: this code is executed before those
- variables are initialised. Since these types are only used for
- compile-time evaluation of conditional expressions, it doesn't matter
- that we use the base types instead of the cpu-specific ones. }
- sintdef:=torddef.create(s64bit,low(int64),high(int64),false);
- uintdef:=torddef.create(u64bit,low(qword),high(qword),false);
- booldef:=torddef.create(pasbool1,0,1,false);
- strdef:=tstringdef.createansi(0,false);
- setdef:=tsetdef.create(sintdef,0,255,false);
- realdef:=tfloatdef.create(s80real,false);
- end;
- class destructor texprvalue.destroydefs;
- begin
- setdef.free;
- sintdef.free;
- uintdef.free;
- booldef.free;
- strdef.free;
- realdef.free;
- end;
- constructor texprvalue.create_const(c: tconstsym);
- begin
- consttyp:=c.consttyp;
- def:=c.constdef;
- case consttyp of
- conststring,
- constresourcestring:
- begin
- value.len:=c.value.len;
- getmem(value.valueptr,value.len+1);
- move(c.value.valueptr^,value.valueptr^,value.len+1);
- end;
- constwstring:
- begin
- initwidestring(value.valueptr);
- copywidestring(c.value.valueptr,value.valueptr);
- end;
- constreal:
- begin
- new(pbestreal(value.valueptr));
- pbestreal(value.valueptr)^:=pbestreal(c.value.valueptr)^;
- end;
- constset:
- begin
- new(pnormalset(value.valueptr));
- pnormalset(value.valueptr)^:=pnormalset(c.value.valueptr)^;
- end;
- constguid:
- begin
- new(pguid(value.valueptr));
- pguid(value.valueptr)^:=pguid(c.value.valueptr)^;
- end;
- else
- value:=c.value;
- end;
- end;
- constructor texprvalue.create_error;
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constnone;
- def:=generrordef;
- end;
- constructor texprvalue.create_ord(v: Tconstexprint);
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constord;
- value.valueord:=v;
- if v.signed then
- def:=sintdef
- else
- def:=uintdef;
- end;
- constructor texprvalue.create_int(v: int64);
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constord;
- value.valueord:=v;
- def:=sintdef;
- end;
- constructor texprvalue.create_uint(v: qword);
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constord;
- value.valueord:=v;
- def:=uintdef;
- end;
- constructor texprvalue.create_bool(b: boolean);
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constord;
- value.valueord:=ord(b);
- def:=booldef;
- end;
- constructor texprvalue.create_str(s: string);
- var
- sp: pansichar;
- len: integer;
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=conststring;
- len:=length(s);
- getmem(sp,len+1);
- move(s[1],sp^,len+1);
- value.valueptr:=sp;
- value.len:=len;
- def:=strdef;
- end;
- constructor texprvalue.create_set(ns: tnormalset);
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constset;
- new(pnormalset(value.valueptr));
- pnormalset(value.valueptr)^:=ns;
- def:=setdef;
- end;
- constructor texprvalue.create_real(r: bestreal);
- begin
- fillchar(value,sizeof(value),#0);
- consttyp:=constreal;
- new(pbestreal(value.valueptr));
- pbestreal(value.valueptr)^:=r;
- def:=realdef;
- end;
- class function texprvalue.try_parse_number(s:string):texprvalue;
- var
- ic: int64;
- qc: qword;
- code: integer;
- begin
- { try int64 }
- val(s,ic,code);
- if code=0 then
- result:=texprvalue.create_int(ic)
- else
- begin
- { try qword }
- val(s,qc,code);
- if code=0 then
- result:=texprvalue.create_uint(qc)
- else
- result:=try_parse_real(s);
- end;
- end;
- class function texprvalue.try_parse_real(s:string):texprvalue;
- var
- d: bestreal;
- code: integer;
- begin
- val(s,d,code);
- if code=0 then
- result:=texprvalue.create_real(d)
- else
- result:=nil;
- end;
- function texprvalue.evaluate(v:texprvalue;op:ttoken):texprvalue;
- function check_compatible: boolean;
- begin
- result:=(
- (is_ordinal(v.def) or is_fpu(v.def)) and
- (is_ordinal(def) or is_fpu(def))
- ) or
- (is_stringlike(v.def) and is_stringlike(def));
- if not result then
- Message2(type_e_incompatible_types,def.typename,v.def.typename);
- end;
- var
- lv,rv: tconstexprint;
- lvd,rvd: bestreal;
- lvs,rvs: string;
- begin
- case op of
- _OP_IN:
- begin
- if not is_set(v.def) then
- begin
- v.error('Set', 'IN');
- result:=texprvalue.create_error;
- end
- else
- if not is_ordinal(def) then
- begin
- error('Ordinal', 'IN');
- result:=texprvalue.create_error;
- end
- else
- if value.valueord.signed then
- result:=texprvalue.create_bool(value.valueord.svalue in pnormalset(v.value.valueptr)^)
- else
- result:=texprvalue.create_bool(value.valueord.uvalue in pnormalset(v.value.valueptr)^);
- end;
- _OP_NOT:
- begin
- if isBoolean then
- result:=texprvalue.create_bool(not asBool)
- else if is_ordinal(def) then
- begin
- result:=texprvalue.create_ord(value.valueord);
- result.def:=def;
- calc_not_ordvalue(result.value.valueord,result.def);
- end
- else
- begin
- error('Boolean', 'NOT');
- result:=texprvalue.create_error;
- end;
- end;
- _OP_OR:
- begin
- if isBoolean then
- if v.isBoolean then
- result:=texprvalue.create_bool(asBool or v.asBool)
- else
- begin
- v.error('Boolean','OR');
- result:=texprvalue.create_error;
- end
- else if is_ordinal(def) then
- if is_ordinal(v.def) then
- result:=texprvalue.create_ord(value.valueord or v.value.valueord)
- else
- begin
- v.error('Ordinal','OR');
- result:=texprvalue.create_error;
- end
- else
- begin
- error('Boolean','OR');
- result:=texprvalue.create_error;
- end;
- end;
- _OP_XOR:
- begin
- if isBoolean then
- if v.isBoolean then
- result:=texprvalue.create_bool(asBool xor v.asBool)
- else
- begin
- v.error('Boolean','XOR');
- result:=texprvalue.create_error;
- end
- else if is_ordinal(def) then
- if is_ordinal(v.def) then
- result:=texprvalue.create_ord(value.valueord xor v.value.valueord)
- else
- begin
- v.error('Ordinal','XOR');
- result:=texprvalue.create_error;
- end
- else
- begin
- error('Boolean','XOR');
- result:=texprvalue.create_error;
- end;
- end;
- _OP_AND:
- begin
- if isBoolean then
- if v.isBoolean then
- result:=texprvalue.create_bool(asBool and v.asBool)
- else
- begin
- v.error('Boolean','AND');
- result:=texprvalue.create_error;
- end
- else if is_ordinal(def) then
- if is_ordinal(v.def) then
- result:=texprvalue.create_ord(value.valueord and v.value.valueord)
- else
- begin
- v.error('Ordinal','AND');
- result:=texprvalue.create_error;
- end
- else
- begin
- error('Boolean','AND');
- result:=texprvalue.create_error;
- end;
- end;
- _EQ,_NE,_LT,_GT,_GTE,_LTE,_PLUS,_MINUS,_STAR,_SLASH,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR:
- if check_compatible then
- begin
- if (is_ordinal(def) and is_ordinal(v.def)) then
- begin
- lv:=value.valueord;
- rv:=v.value.valueord;
- case op of
- _EQ:
- result:=texprvalue.create_bool(lv=rv);
- _NE:
- result:=texprvalue.create_bool(lv<>rv);
- _LT:
- result:=texprvalue.create_bool(lv<rv);
- _GT:
- result:=texprvalue.create_bool(lv>rv);
- _GTE:
- result:=texprvalue.create_bool(lv>=rv);
- _LTE:
- result:=texprvalue.create_bool(lv<=rv);
- _PLUS:
- result:=texprvalue.create_ord(lv+rv);
- _MINUS:
- result:=texprvalue.create_ord(lv-rv);
- _STAR:
- result:=texprvalue.create_ord(lv*rv);
- _SLASH:
- result:=texprvalue.create_real(lv/rv);
- _OP_DIV:
- result:=texprvalue.create_ord(lv div rv);
- _OP_MOD:
- result:=texprvalue.create_ord(lv mod rv);
- _OP_SHL:
- result:=texprvalue.create_ord(lv shl rv);
- _OP_SHR:
- result:=texprvalue.create_ord(lv shr rv);
- else
- begin
- { actually we should never get here but this avoids a warning }
- Message(parser_e_illegal_expression);
- result:=texprvalue.create_error;
- end;
- end;
- end
- else
- if (is_fpu(def) or is_ordinal(def)) and
- (is_fpu(v.def) or is_ordinal(v.def)) then
- begin
- if is_fpu(def) then
- lvd:=pbestreal(value.valueptr)^
- else
- lvd:=value.valueord;
- if is_fpu(v.def) then
- rvd:=pbestreal(v.value.valueptr)^
- else
- rvd:=v.value.valueord;
- case op of
- _EQ:
- result:=texprvalue.create_bool(lvd=rvd);
- _NE:
- result:=texprvalue.create_bool(lvd<>rvd);
- _LT:
- result:=texprvalue.create_bool(lvd<rvd);
- _GT:
- result:=texprvalue.create_bool(lvd>rvd);
- _GTE:
- result:=texprvalue.create_bool(lvd>=rvd);
- _LTE:
- result:=texprvalue.create_bool(lvd<=rvd);
- _PLUS:
- result:=texprvalue.create_real(lvd+rvd);
- _MINUS:
- result:=texprvalue.create_real(lvd-rvd);
- _STAR:
- result:=texprvalue.create_real(lvd*rvd);
- _SLASH:
- result:=texprvalue.create_real(lvd/rvd);
- else
- begin
- Message(parser_e_illegal_expression);
- result:=texprvalue.create_error;
- end;
- end;
- end
- else
- begin
- lvs:=asStr;
- rvs:=v.asStr;
- case op of
- _EQ:
- result:=texprvalue.create_bool(lvs=rvs);
- _NE:
- result:=texprvalue.create_bool(lvs<>rvs);
- _LT:
- result:=texprvalue.create_bool(lvs<rvs);
- _GT:
- result:=texprvalue.create_bool(lvs>rvs);
- _GTE:
- result:=texprvalue.create_bool(lvs>=rvs);
- _LTE:
- result:=texprvalue.create_bool(lvs<=rvs);
- _PLUS:
- result:=texprvalue.create_str(lvs+rvs);
- else
- begin
- Message(parser_e_illegal_expression);
- result:=texprvalue.create_error;
- end;
- end;
- end;
- end
- else
- result:=texprvalue.create_error;
- else
- result:=texprvalue.create_error;
- end;
- end;
- procedure texprvalue.error(expecteddef, place: string);
- begin
- Message3(scan_e_compile_time_typeerror,
- expecteddef,
- def.typename,
- place
- );
- end;
- function texprvalue.isBoolean: Boolean;
- var
- i: int64;
- begin
- result:=is_boolean(def);
- if not result and is_integer(def) then
- begin
- i:=asInt64;
- result:=(i=0)or(i=1);
- end;
- end;
- function texprvalue.isInt: Boolean;
- begin
- result:=is_integer(def);
- end;
- function texprvalue.asBool: Boolean;
- begin
- result:=value.valueord<>0;
- end;
- function texprvalue.asInt: Integer;
- begin
- result:=value.valueord.svalue;
- end;
- function texprvalue.asInt64: Int64;
- begin
- result:=value.valueord.svalue;
- end;
- function texprvalue.asStr: String;
- var
- b:byte;
- begin
- case consttyp of
- constord:
- result:=tostr(value.valueord);
- conststring,
- constresourcestring:
- SetString(result,pchar(value.valueptr),value.len);
- constreal:
- str(pbestreal(value.valueptr)^,result);
- constset:
- begin
- result:=',';
- for b:=0 to 255 do
- if b in pconstset(value.valueptr)^ then
- result:=result+tostr(b)+',';
- end;
- { error values }
- constnone:
- result:='';
- else
- internalerror(2013112801);
- end;
- end;
- destructor texprvalue.destroy;
- begin
- case consttyp of
- conststring,
- constresourcestring :
- freemem(value.valueptr,value.len+1);
- constwstring :
- donewidestring(pcompilerwidestring(value.valueptr));
- constreal :
- dispose(pbestreal(value.valueptr));
- constset :
- dispose(pnormalset(value.valueptr));
- constguid :
- dispose(pguid(value.valueptr));
- constord,
- { error values }
- constnone:
- ;
- else
- internalerror(2013112802);
- end;
- inherited destroy;
- end;
- const
- 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];
- function preproc_comp_expr:texprvalue;
- function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean):texprvalue; forward;
- procedure preproc_consume(t:ttoken);
- begin
- if t<>current_scanner.preproc_token then
- Message(scan_e_preproc_syntax_error);
- current_scanner.preproc_token:=current_scanner.readpreproc;
- end;
- function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;out tokentoconsume:ttoken):boolean;
- var
- hmodule: tmodule;
- ns:ansistring;
- nssym:tsym;
- begin
- result:=false;
- tokentoconsume:=_ID;
- if assigned(srsym) and (srsym.typ in [unitsym,namespacesym]) then
- begin
- if not(srsym.owner.symtabletype in [staticsymtable,globalsymtable]) then
- internalerror(200501154);
- { only allow unit.symbol access if the name was
- found in the current module
- we can use iscurrentunit because generic specializations does not
- change current_unit variable }
- hmodule:=find_module_from_symtable(srsym.Owner);
- if not Assigned(hmodule) then
- internalerror(201001120);
- if hmodule.unit_index=current_filepos.moduleindex then
- begin
- preproc_consume(_POINT);
- current_scanner.skipspace;
- if srsym.typ=namespacesym then
- begin
- ns:=srsym.name;
- nssym:=srsym;
- while assigned(srsym) and (srsym.typ=namespacesym) do
- begin
- { we have a namespace. the next identifier should be either a namespace or a unit }
- searchsym_in_module(hmodule,ns+'.'+current_scanner.preproc_pattern,srsym,srsymtable);
- if assigned(srsym) and (srsym.typ in [namespacesym,unitsym]) then
- begin
- ns:=ns+'.'+current_scanner.preproc_pattern;
- nssym:=srsym;
- preproc_consume(_ID);
- current_scanner.skipspace;
- preproc_consume(_POINT);
- current_scanner.skipspace;
- end;
- end;
- { check if there is a hidden unit with this pattern in the namespace }
- if not assigned(srsym) and
- assigned(nssym) and (nssym.typ=namespacesym) and assigned(tnamespacesym(nssym).unitsym) then
- srsym:=tnamespacesym(nssym).unitsym;
- if assigned(srsym) and (srsym.typ<>unitsym) then
- internalerror(201108260);
- if not assigned(srsym) then
- begin
- result:=true;
- srsymtable:=nil;
- exit;
- end;
- end;
- case current_scanner.preproc_token of
- _ID:
- { system.char? (char=widechar comes from the implicit
- uuchar unit -> override) }
- if (current_scanner.preproc_pattern='CHAR') and
- (tmodule(tunitsym(srsym).module).globalsymtable=systemunit) then
- begin
- if m_default_unicodestring in current_settings.modeswitches then
- searchsym_in_module(tunitsym(srsym).module,'WIDECHAR',srsym,srsymtable)
- else
- searchsym_in_module(tunitsym(srsym).module,'ANSICHAR',srsym,srsymtable)
- end
- else
- searchsym_in_module(tunitsym(srsym).module,current_scanner.preproc_pattern,srsym,srsymtable);
- _STRING:
- begin
- { system.string? }
- if tmodule(tunitsym(srsym).module).globalsymtable=systemunit then
- begin
- if cs_refcountedstrings in current_settings.localswitches then
- begin
- if m_default_unicodestring in current_settings.modeswitches then
- searchsym_in_module(tunitsym(srsym).module,'UNICODESTRING',srsym,srsymtable)
- else
- searchsym_in_module(tunitsym(srsym).module,'ANSISTRING',srsym,srsymtable)
- end
- else
- searchsym_in_module(tunitsym(srsym).module,'SHORTSTRING',srsym,srsymtable);
- tokentoconsume:=_STRING;
- end;
- end
- else
- ;
- end;
- end
- else
- begin
- srsym:=nil;
- srsymtable:=nil;
- end;
- result:=true;
- end;
- end;
- procedure try_consume_nestedsym(var srsym:tsym;var srsymtable:TSymtable);
- var
- def:tdef;
- tokentoconsume:ttoken;
- found:boolean;
- begin
- found:=try_consume_unitsym(srsym,srsymtable,tokentoconsume);
- if found then
- begin
- preproc_consume(tokentoconsume);
- current_scanner.skipspace;
- end;
- while (current_scanner.preproc_token=_POINT) do
- begin
- if assigned(srsym)and(srsym.typ=typesym) then
- begin
- def:=ttypesym(srsym).typedef;
- if is_class_or_object(def) or is_record(def) or is_java_class_or_interface(def) then
- begin
- preproc_consume(_POINT);
- current_scanner.skipspace;
- if def.typ=objectdef then
- found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,[ssf_search_helper])
- else
- found:=searchsym_in_record(trecorddef(def),current_scanner.preproc_pattern,srsym,srsymtable);
- if not found then
- begin
- Message1(sym_e_id_not_found,current_scanner.preproc_pattern);
- exit;
- end;
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- else
- begin
- Message(sym_e_type_must_be_rec_or_object_or_class);
- exit;
- end;
- end
- else
- begin
- Message(type_e_type_id_expected);
- exit;
- end;
- end;
- end;
- function preproc_substitutedtoken(searchstr:string;eval:Boolean):texprvalue;
- { Currently this parses identifiers as well as numbers.
- The result from this procedure can either be that the token
- itself is a value, or that it is a compile time variable/macro,
- which then is substituted for another value (for macros
- recursivelly substituted).}
- var
- hs: string;
- mac: tmacro;
- macrocount,
- len: integer;
- foundmacro: boolean;
- begin
- if not eval then
- begin
- result:=texprvalue.create_str(searchstr);
- exit;
- end;
- mac:=nil;
- foundmacro:=false;
- { Substitue macros and compiler variables with their content/value.
- For real macros also do recursive substitution. }
- macrocount:=0;
- repeat
- mac:=tmacro(search_macro(searchstr));
- inc(macrocount);
- if macrocount>max_macro_nesting then
- begin
- Message(scan_w_macro_too_deep);
- break;
- end;
- if assigned(mac) and mac.defined then
- if assigned(mac.buftext) then
- begin
- if mac.buflen>255 then
- begin
- len:=255;
- Message(scan_w_macro_cut_after_255_chars);
- end
- else
- len:=mac.buflen;
- hs[0]:=char(len);
- move(mac.buftext^,hs[1],len);
- searchstr:=upcase(hs);
- mac.is_used:=true;
- foundmacro:=true;
- end
- else
- begin
- Message1(scan_e_error_macro_lacks_value,searchstr);
- break;
- end
- else
- break;
- if mac.is_compiler_var then
- break;
- until false;
- { At this point, result do contain the value. Do some decoding and
- determine the type.}
- result:=texprvalue.try_parse_number(searchstr);
- if not assigned(result) then
- begin
- if foundmacro and (searchstr='FALSE') then
- result:=texprvalue.create_bool(false)
- else if foundmacro and (searchstr='TRUE') then
- result:=texprvalue.create_bool(true)
- else if (m_mac in current_settings.modeswitches) and
- (not assigned(mac) or not mac.defined) and
- (macrocount = 1) then
- begin
- {Errors in mode mac is issued here. For non macpas modes there is
- more liberty, but the error will eventually be caught at a later stage.}
- Message1(scan_e_error_macro_undefined,searchstr);
- result:=texprvalue.create_str(searchstr); { just to have something }
- end
- else
- result:=texprvalue.create_str(searchstr);
- end;
- end;
- function preproc_factor(eval: Boolean):texprvalue;
- var
- hs,countstr,storedpattern: string;
- mac: tmacro;
- srsym : tsym;
- srsymtable : TSymtable;
- hdef : TDef;
- l : longint;
- hasKlammer: Boolean;
- exprvalue:texprvalue;
- ns:tnormalset;
- begin
- result:=nil;
- hasKlammer:=false;
- if current_scanner.preproc_token=_ID then
- begin
- if current_scanner.preproc_pattern='DEFINED' then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- hasKlammer:= true;
- end
- else if (m_mac in current_settings.modeswitches) then
- hasKlammer:= false
- else
- Message(scan_e_error_in_preproc_expr);
- if current_scanner.preproc_token =_ID then
- begin
- hs := current_scanner.preproc_pattern;
- mac := tmacro(search_macro(hs));
- if assigned(mac) and mac.defined then
- begin
- result:=texprvalue.create_bool(true);
- mac.is_used:=true;
- end
- else
- result:=texprvalue.create_bool(false);
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if hasKlammer then
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='UNDEFINED') then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_ID then
- begin
- hs := current_scanner.preproc_pattern;
- mac := tmacro(search_macro(hs));
- if assigned(mac) then
- begin
- result:=texprvalue.create_bool(false);
- mac.is_used:=true;
- end
- else
- result:=texprvalue.create_bool(true);
- preproc_consume(_ID);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if (m_mac in current_settings.modeswitches) and (current_scanner.preproc_pattern='OPTION') then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if not (current_scanner.preproc_token = _ID) then
- Message(scan_e_error_in_preproc_expr);
- hs:=current_scanner.preproc_pattern;
- if (length(hs) > 1) then
- {This is allowed in Metrowerks Pascal}
- Message(scan_e_error_in_preproc_expr)
- else
- begin
- if CheckSwitch(hs[1],'+') then
- result:=texprvalue.create_bool(true)
- else
- result:=texprvalue.create_bool(false);
- end;
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if current_scanner.preproc_pattern='SIZEOF' then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_preproc_syntax_error);
- storedpattern:=current_scanner.preproc_pattern;
- preproc_consume(_ID);
- current_scanner.skipspace;
- if eval then
- if searchsym(storedpattern,srsym,srsymtable) then
- begin
- try_consume_nestedsym(srsym,srsymtable);
- l:=0;
- if assigned(srsym) then
- case srsym.typ of
- staticvarsym,
- localvarsym,
- paravarsym :
- l:=tabstractvarsym(srsym).getsize;
- typesym:
- l:=ttypesym(srsym).typedef.size;
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- result:=texprvalue.create_int(l);
- end
- else
- Message1(sym_e_id_not_found,storedpattern);
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_preproc_syntax_error);
- end
- else
- if current_scanner.preproc_pattern='HIGH' then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_preproc_syntax_error);
- storedpattern:=current_scanner.preproc_pattern;
- preproc_consume(_ID);
- current_scanner.skipspace;
- if eval then
- if searchsym(storedpattern,srsym,srsymtable) then
- begin
- try_consume_nestedsym(srsym,srsymtable);
- hdef:=nil;
- hs:='';
- l:=0;
- if assigned(srsym) then
- case srsym.typ of
- staticvarsym,
- localvarsym,
- paravarsym :
- hdef:=tabstractvarsym(srsym).vardef;
- typesym:
- hdef:=ttypesym(srsym).typedef;
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- if assigned(hdef) then
- begin
- if hdef.typ=setdef then
- hdef:=tsetdef(hdef).elementdef;
- case hdef.typ of
- orddef:
- with torddef(hdef).high do
- if signed then
- result:=texprvalue.create_int(svalue)
- else
- result:=texprvalue.create_uint(uvalue);
- enumdef:
- result:=texprvalue.create_int(tenumdef(hdef).maxval);
- arraydef:
- if is_open_array(hdef) or is_array_of_const(hdef) or is_dynamic_array(hdef) then
- Message(type_e_mismatch)
- else
- result:=texprvalue.create_int(tarraydef(hdef).highrange);
- stringdef:
- if is_open_string(hdef) or is_ansistring(hdef) or is_wide_or_unicode_string(hdef) then
- Message(type_e_mismatch)
- else
- result:=texprvalue.create_int(tstringdef(hdef).len);
- else
- Message(type_e_mismatch);
- end;
- end;
- end
- else
- Message1(sym_e_id_not_found,storedpattern);
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_preproc_syntax_error);
- end
- else
- if current_scanner.preproc_pattern='DECLARED' then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if current_scanner.preproc_token =_ID then
- begin
- hs := upper(current_scanner.preproc_pattern);
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token in [_LT,_LSHARPBRACKET] then
- begin
- l:=1;
- preproc_consume(current_scanner.preproc_token);
- current_scanner.skipspace;
- while current_scanner.preproc_token=_COMMA do
- begin
- inc(l);
- preproc_consume(_COMMA);
- current_scanner.skipspace;
- end;
- if not (current_scanner.preproc_token in [_GT,_RSHARPBRACKET]) then
- Message(scan_e_error_in_preproc_expr)
- else
- preproc_consume(current_scanner.preproc_token);
- str(l,countstr);
- hs:=hs+'$'+countstr;
- end
- else
- { special case: <> }
- if current_scanner.preproc_token=_NE then
- begin
- hs:=hs+'$1';
- preproc_consume(_NE);
- end;
- current_scanner.skipspace;
- if searchsym(hs,srsym,srsymtable) then
- begin
- { TSomeGeneric<...> also adds a TSomeGeneric symbol }
- if (sp_generic_dummy in srsym.symoptions) and
- (srsym.typ=typesym) and
- (
- { mode delphi}
- (ttypesym(srsym).typedef.typ in [undefineddef,errordef]) or
- { non-delphi modes }
- (df_generic in ttypesym(srsym).typedef.defoptions)
- ) then
- result:=texprvalue.create_bool(false)
- else
- result:=texprvalue.create_bool(true);
- end
- else
- result:=texprvalue.create_bool(false);
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if current_scanner.preproc_pattern='ORD' then
- begin
- preproc_consume(_ID);
- current_scanner.skipspace;
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- end
- else
- Message(scan_e_preproc_syntax_error);
- exprvalue:=preproc_factor(eval);
- if eval then
- begin
- if is_ordinal(exprvalue.def) then
- result:=texprvalue.create_int(exprvalue.asInt)
- else
- begin
- exprvalue.error('Ordinal','ORD');
- result:=texprvalue.create_int(0);
- end;
- end
- else
- result:=texprvalue.create_int(0);
- exprvalue.free;
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end
- else
- if current_scanner.preproc_pattern='NOT' then
- begin
- preproc_consume(_ID);
- exprvalue:=preproc_factor(eval);
- if eval then
- result:=exprvalue.evaluate(nil,_OP_NOT)
- else
- result:=texprvalue.create_bool(false); {Just to have something}
- exprvalue.free;
- end
- else
- if (current_scanner.preproc_pattern='TRUE') then
- begin
- result:=texprvalue.create_bool(true);
- preproc_consume(_ID);
- end
- else
- if (current_scanner.preproc_pattern='FALSE') then
- begin
- result:=texprvalue.create_bool(false);
- preproc_consume(_ID);
- end
- else
- begin
- storedpattern:=current_scanner.preproc_pattern;
- preproc_consume(_ID);
- current_scanner.skipspace;
- { first look for a macros/int/float }
- result:=preproc_substitutedtoken(storedpattern,eval);
- if eval and (result.consttyp=conststring) then
- begin
- if searchsym(storedpattern,srsym,srsymtable) then
- begin
- try_consume_nestedsym(srsym,srsymtable);
- if assigned(srsym) then
- case srsym.typ of
- constsym:
- begin
- result.free;
- result:=texprvalue.create_const(tconstsym(srsym));
- end;
- enumsym:
- begin
- result.free;
- result:=texprvalue.create_int(tenumsym(srsym).value);
- end;
- else
- ;
- end;
- end
- end
- { skip id(<expr>) if expression must not be evaluated }
- else if not(eval) and (result.consttyp=conststring) then
- begin
- if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- current_scanner.skipspace;
- result:=preproc_factor(false);
- if current_scanner.preproc_token =_RKLAMMER then
- preproc_consume(_RKLAMMER)
- else
- Message(scan_e_error_in_preproc_expr);
- end;
- end;
- end
- end
- else if current_scanner.preproc_token =_LKLAMMER then
- begin
- preproc_consume(_LKLAMMER);
- result:=preproc_sub_expr(opcompare,eval);
- preproc_consume(_RKLAMMER);
- end
- else if current_scanner.preproc_token = _LECKKLAMMER then
- begin
- preproc_consume(_LECKKLAMMER);
- ns:=[];
- while current_scanner.preproc_token in [_ID,_INTCONST] do
- begin
- exprvalue:=preproc_factor(eval);
- include(ns,exprvalue.asInt);
- if current_scanner.preproc_token = _COMMA then
- preproc_consume(_COMMA);
- end;
- // TODO Add check of setElemType
- preproc_consume(_RECKKLAMMER);
- result:=texprvalue.create_set(ns);
- end
- else if current_scanner.preproc_token = _INTCONST then
- begin
- result:=texprvalue.try_parse_number(current_scanner.preproc_pattern);
- if not assigned(result) then
- begin
- Message(parser_e_invalid_integer);
- result:=texprvalue.create_int(1);
- end;
- preproc_consume(_INTCONST);
- end
- else if current_scanner.preproc_token = _CSTRING then
- begin
- result:=texprvalue.create_str(current_scanner.preproc_pattern);
- preproc_consume(_CSTRING);
- end
- else if current_scanner.preproc_token = _REALNUMBER then
- begin
- result:=texprvalue.try_parse_real(current_scanner.preproc_pattern);
- if not assigned(result) then
- begin
- Message(parser_e_error_in_real);
- result:=texprvalue.create_real(1.0);
- end;
- preproc_consume(_REALNUMBER);
- end
- else
- Message(scan_e_error_in_preproc_expr);
- if not assigned(result) then
- result:=texprvalue.create_error;
- end;
- function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean): texprvalue;
- var
- hs1,hs2: texprvalue;
- op: ttoken;
- begin
- if pred_level=highest_precedence then
- result:=preproc_factor(eval)
- else
- result:=preproc_sub_expr(succ(pred_level),eval);
- repeat
- op:=current_scanner.preproc_token;
- if (op in preproc_operators) and
- (op in operator_levels[pred_level]) then
- begin
- hs1:=result;
- preproc_consume(op);
- if (op=_OP_OR) and hs1.isBoolean and hs1.asBool then
- begin
- { stop evaluation the rest of expression }
- result:=texprvalue.create_bool(true);
- if pred_level=highest_precedence then
- hs2:=preproc_factor(false)
- else
- hs2:=preproc_sub_expr(succ(pred_level),false);
- end
- else if (op=_OP_AND) and hs1.isBoolean and not hs1.asBool then
- begin
- { stop evaluation the rest of expression }
- result:=texprvalue.create_bool(false);
- if pred_level=highest_precedence then
- hs2:=preproc_factor(false)
- else
- hs2:=preproc_sub_expr(succ(pred_level),false);
- end
- else
- begin
- if pred_level=highest_precedence then
- hs2:=preproc_factor(eval)
- else
- hs2:=preproc_sub_expr(succ(pred_level),eval);
- if eval then
- result:=hs1.evaluate(hs2,op)
- else
- result:=texprvalue.create_bool(false); {Just to have something}
- end;
- hs1.free;
- hs2.free;
- end
- else
- break;
- until false;
- end;
- begin
- current_scanner.in_preproc_comp_expr:=true;
- current_scanner.skipspace;
- { start preproc expression scanner }
- current_scanner.preproc_token:=current_scanner.readpreproc;
- preproc_comp_expr:=preproc_sub_expr(opcompare,true);
- current_scanner.in_preproc_comp_expr:=false;
- end;
- function boolean_compile_time_expr(var valuedescr: string): Boolean;
- var
- hs: texprvalue;
- begin
- hs:=preproc_comp_expr;
- if hs.isBoolean then
- result:=hs.asBool
- else
- begin
- hs.error('Boolean', 'IF or ELSEIF');
- result:=false;
- end;
- valuedescr:=hs.asStr;
- hs.free;
- end;
- procedure dir_if;
- begin
- current_scanner.ifpreprocstack(pp_if,@boolean_compile_time_expr, scan_c_if_found);
- end;
- procedure dir_elseif;
- begin
- current_scanner.elseifpreprocstack(@boolean_compile_time_expr);
- end;
- procedure dir_define_impl(macstyle: boolean);
- var
- hs : string;
- bracketcount : longint;
- mac : tmacro;
- macropos : longint;
- macrobuffer : pmacrobuffer;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- if hs='' then
- begin
- Message(scan_e_emptymacroname);
- exit;
- end;
- mac:=tmacro(search_macro(hs));
- if not assigned(mac) or (mac.owner <> current_module.localmacrosymtable) then
- begin
- mac:=tmacro.create(hs);
- mac.defined:=true;
- current_module.localmacrosymtable.insert(mac);
- end
- else
- begin
- mac.defined:=true;
- mac.is_compiler_var:=false;
- { delete old definition }
- if assigned(mac.buftext) then
- begin
- freemem(mac.buftext,mac.buflen);
- mac.buftext:=nil;
- end;
- end;
- Message1(parser_c_macro_defined,mac.name);
- mac.is_used:=true;
- if (cs_support_macro in current_settings.moduleswitches) then
- begin
- current_scanner.skipspace;
- if not macstyle then
- begin
- { may be a macro? }
- if c <> ':' then
- exit;
- current_scanner.readchar;
- if c <> '=' then
- exit;
- current_scanner.readchar;
- current_scanner.skipspace;
- end;
- { key words are never substituted }
- if is_keyword(hs) then
- Message(scan_e_keyword_cant_be_a_macro);
- new(macrobuffer);
- macropos:=0;
- { parse macro, brackets are counted so it's possible
- to have a $ifdef etc. in the macro }
- bracketcount:=0;
- repeat
- case c of
- '}' :
- if (bracketcount=0) then
- break
- else
- dec(bracketcount);
- '{' :
- inc(bracketcount);
- #10,#13 :
- current_scanner.linebreak;
- #26 :
- current_scanner.end_of_file;
- end;
- macrobuffer^[macropos]:=c;
- inc(macropos);
- if macropos>=maxmacrolen then
- Message(scan_f_macro_buffer_overflow);
- current_scanner.readchar;
- until false;
- { free buffer of macro ?}
- if assigned(mac.buftext) then
- freemem(mac.buftext,mac.buflen);
- { get new mem }
- getmem(mac.buftext,macropos);
- mac.buflen:=macropos;
- { copy the text }
- move(macrobuffer^,mac.buftext^,macropos);
- dispose(macrobuffer);
- end
- else
- begin
- { check if there is an assignment, then we need to give a
- warning }
- current_scanner.skipspace;
- if c=':' then
- begin
- current_scanner.readchar;
- if c='=' then
- Message(scan_w_macro_support_turned_off);
- end;
- end;
- end;
- procedure dir_define;
- begin
- dir_define_impl(false);
- end;
- procedure dir_definec;
- begin
- dir_define_impl(true);
- end;
- procedure dir_setc;
- var
- hs : string;
- mac : tmacro;
- exprvalue: texprvalue;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- mac:=tmacro(search_macro(hs));
- if not assigned(mac) or
- (mac.owner <> current_module.localmacrosymtable) then
- begin
- mac:=tmacro.create(hs);
- mac.defined:=true;
- mac.is_compiler_var:=true;
- current_module.localmacrosymtable.insert(mac);
- end
- else
- begin
- mac.defined:=true;
- mac.is_compiler_var:=true;
- { delete old definition }
- if assigned(mac.buftext) then
- begin
- freemem(mac.buftext,mac.buflen);
- mac.buftext:=nil;
- end;
- end;
- Message1(parser_c_macro_defined,mac.name);
- mac.is_used:=true;
- { key words are never substituted }
- if is_keyword(hs) then
- Message(scan_e_keyword_cant_be_a_macro);
- { macro assignment can be both := and = }
- current_scanner.skipspace;
- if c=':' then
- current_scanner.readchar;
- if c='=' then
- begin
- current_scanner.readchar;
- exprvalue:=preproc_comp_expr;
- if not is_boolean(exprvalue.def) and
- not is_integer(exprvalue.def) then
- exprvalue.error('Boolean, Integer', 'SETC');
- hs:=exprvalue.asStr;
- if length(hs) <> 0 then
- begin
- {If we are absolutely shure it is boolean, translate
- to TRUE/FALSE to increase possibility to do future type check}
- if exprvalue.isBoolean then
- begin
- if exprvalue.asBool then
- hs:='TRUE'
- else
- hs:='FALSE';
- end;
- Message2(parser_c_macro_set_to,mac.name,hs);
- { free buffer of macro ?}
- if assigned(mac.buftext) then
- freemem(mac.buftext,mac.buflen);
- { get new mem }
- getmem(mac.buftext,length(hs));
- mac.buflen:=length(hs);
- { copy the text }
- move(hs[1],mac.buftext^,mac.buflen);
- end
- else
- Message(scan_e_preproc_syntax_error);
- exprvalue.free;
- end
- else
- Message(scan_e_preproc_syntax_error);
- end;
- procedure dir_undef;
- var
- hs : string;
- mac : tmacro;
- begin
- current_scanner.skipspace;
- hs:=current_scanner.readid;
- mac:=tmacro(search_macro(hs));
- if not assigned(mac) or
- (mac.owner <> current_module.localmacrosymtable) then
- begin
- mac:=tmacro.create(hs);
- mac.defined:=false;
- current_module.localmacrosymtable.insert(mac);
- end
- else
- begin
- mac.defined:=false;
- mac.is_compiler_var:=false;
- { delete old definition }
- if assigned(mac.buftext) then
- begin
- freemem(mac.buftext,mac.buflen);
- mac.buftext:=nil;
- end;
- end;
- Message1(parser_c_macro_undefined,mac.name);
- mac.is_used:=true;
- end;
- procedure dir_include;
- function findincludefile(const path,name:TCmdStr;var foundfile:TCmdStr):boolean;
- var
- found : boolean;
- hpath : TCmdStr;
- begin
- (* look for the include file
- If path was absolute and specified as part of {$I } then
- 1. specified path
- else
- 1. path of current inputfile,current dir
- 2. local includepath
- 3. global includepath
- -- Check mantis #13461 before changing this *)
- found:=false;
- foundfile:='';
- hpath:='';
- if path_absolute(path) then
- begin
- found:=FindFile(name,path,true,foundfile);
- end
- else
- begin
- hpath:=current_scanner.inputfile.path+';'+CurDirRelPath(source_info);
- found:=FindFile(path+name, hpath,true,foundfile);
- if not found then
- found:=current_module.localincludesearchpath.FindFile(path+name,true,foundfile);
- if not found then
- found:=includesearchpath.FindFile(path+name,true,foundfile);
- end;
- result:=found;
- end;
- var
- foundfile : TCmdStr;
- path,
- name,
- hs : tpathstr;
- args : string;
- hp : tinputfile;
- found : boolean;
- macroIsString : boolean;
- begin
- current_scanner.skipspace;
- args:=current_scanner.readcomment;
- hs:=GetToken(args,' ');
- if hs='' then
- exit;
- if (hs[1]='%') then
- begin
- { case insensitive }
- hs:=upper(hs);
- { remove %'s }
- Delete(hs,1,1);
- if hs[length(hs)]='%' then
- Delete(hs,length(hs),1);
- { save old }
- path:=hs;
- { first check for internal macros }
- macroIsString:=true;
- case hs of
- 'TIME':
- if timestr<>'' then
- hs:=timestr
- else
- hs:=gettimestr;
- 'DATE':
- if datestr<>'' then
- hs:=datestr
- else
- hs:=getdatestr;
- 'DATEYEAR':
- begin
- hs:=tostr(startsystime.Year);
- macroIsString:=false;
- end;
- 'DATEMONTH':
- begin
- hs:=tostr(startsystime.Month);
- macroIsString:=false;
- end;
- 'DATEDAY':
- begin
- hs:=tostr(startsystime.Day);
- macroIsString:=false;
- end;
- 'TIMEHOUR':
- begin
- hs:=tostr(startsystime.Hour);
- macroIsString:=false;
- end;
- 'TIMEMINUTE':
- begin
- hs:=tostr(startsystime.Minute);
- macroIsString:=false;
- end;
- 'TIMESECOND':
- begin
- hs:=tostr(startsystime.Second);
- macroIsString:=false;
- end;
- 'FILE':
- hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);
- 'LINE':
- hs:=tostr(current_filepos.line);
- 'LINENUM':
- begin
- hs:=tostr(current_filepos.line);
- macroIsString:=false;
- end;
- 'FPCVERSION':
- hs:=version_string;
- 'FPCDATE':
- hs:=date_string;
- 'FPCTARGET':
- hs:=target_cpu_string;
- 'FPCTARGETCPU':
- hs:=target_cpu_string;
- 'FPCTARGETOS':
- hs:=target_info.shortname;
- 'CURRENTROUTINE':
- hs:=current_procinfo.procdef.procsym.RealName;
- else
- hs:=GetEnvironmentVariable(hs);
- end;
- if hs='' then
- Message1(scan_w_include_env_not_found,path);
- { make it a stringconst }
- if macroIsString then
- hs:=''''+hs+'''';
- current_scanner.substitutemacro(path,@hs[1],length(hs),
- current_scanner.line_no,current_scanner.inputfile.ref_index);
- end
- else
- begin
- hs:=FixFileName(hs);
- path:=ExtractFilePath(hs);
- name:=ExtractFileName(hs);
- { Special case for Delphi compatibility: '*' has to be replaced
- by the file name of the current source file. }
- if (length(name)>=1) and
- (name[1]='*') then
- name:=ChangeFileExt(current_module.sourcefiles.get_file_name(current_filepos.fileindex),'')+ExtractFileExt(name);
- { try to find the file }
- found:=findincludefile(path,name,foundfile);
- if (not found) and (ExtractFileExt(name)='') then
- begin
- { try default extensions .inc , .pp and .pas }
- if (not found) then
- found:=findincludefile(path,ChangeFileExt(name,'.inc'),foundfile);
- if (not found) then
- found:=findincludefile(path,ChangeFileExt(name,sourceext),foundfile);
- if (not found) then
- found:=findincludefile(path,ChangeFileExt(name,pasext),foundfile);
- end;
- { if the name ends in dot, try without the dot }
- if (not found) and (ExtractFileExt(name)=ExtensionSeparator) and (Length(name)>=2) then
- found:=findincludefile(path,Copy(name,1,Length(name)-1),foundfile);
- if current_scanner.inputfilecount<max_include_nesting then
- begin
- inc(current_scanner.inputfilecount);
- { we need to reread the current char }
- dec(current_scanner.inputpointer);
- { reset c }
- c:=#0;
- { shutdown current file }
- current_scanner.tempcloseinputfile;
- { load new file }
- hp:=do_openinputfile(foundfile);
- hp.inc_path:=path;
- current_scanner.addfile(hp);
- current_module.sourcefiles.register_file(hp);
- if (not found) then
- Message1(scan_f_cannot_open_includefile,hs);
- if (not current_scanner.openinputfile) then
- Message1(scan_f_cannot_open_includefile,hs);
- Message1(scan_t_start_include_file,current_scanner.inputfile.path+current_scanner.inputfile.name);
- current_scanner.reload;
- end
- else
- Message(scan_f_include_deep_ten);
- end;
- end;
- {*****************************************************************************
- Preprocessor writing
- *****************************************************************************}
- {$ifdef PREPROCWRITE}
- constructor tpreprocfile.create(const fn:string);
- begin
- inherited create;
- { open outputfile }
- assign(f,fn);
- {$push}{$I-}
- rewrite(f);
- {$pop}
- if ioresult<>0 then
- Comment(V_Fatal,'can''t create file '+fn);
- getmem(buf,preprocbufsize);
- settextbuf(f,buf^,preprocbufsize);
- { reset }
- eolfound:=false;
- spacefound:=false;
- end;
- destructor tpreprocfile.destroy;
- begin
- close(f);
- freemem(buf,preprocbufsize);
- end;
- procedure tpreprocfile.add(const s:string);
- begin
- write(f,s);
- end;
- procedure tpreprocfile.addspace;
- begin
- if eolfound then
- begin
- writeln(f,'');
- eolfound:=false;
- spacefound:=false;
- end
- else
- if spacefound then
- begin
- write(f,' ');
- spacefound:=false;
- end;
- end;
- {$endif PREPROCWRITE}
- {*****************************************************************************
- TPreProcStack
- *****************************************************************************}
- constructor tpreprocstack.create(atyp : preproctyp;a:boolean;n:tpreprocstack);
- begin
- accept:=a;
- typ:=atyp;
- next:=n;
- end;
- {*****************************************************************************
- TReplayStack
- *****************************************************************************}
- constructor treplaystack.Create(atoken:ttoken;aidtoken:ttoken;
- const aorgpattern,apattern:string;const acstringpattern:ansistring;
- apatternw:pcompilerwidestring;asettings:tsettings;
- atokenbuf:tdynamicarray;change_endian:boolean;anext:treplaystack);
- begin
- token:=atoken;
- idtoken:=aidtoken;
- orgpattern:=aorgpattern;
- pattern:=apattern;
- cstringpattern:=acstringpattern;
- initwidestring(patternw);
- if assigned(apatternw) then
- begin
- setlengthwidestring(patternw,apatternw^.len);
- move(apatternw^.data^,patternw^.data^,apatternw^.len*sizeof(tcompilerwidechar));
- end;
- settings:=asettings;
- tokenbuf:=atokenbuf;
- tokenbuf_needs_swapping:=change_endian;
- next:=anext;
- end;
- destructor treplaystack.destroy;
- begin
- donewidestring(patternw);
- end;
- {*****************************************************************************
- TDirectiveItem
- *****************************************************************************}
- constructor TDirectiveItem.Create(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- begin
- inherited Create(AList,n);
- is_conditional:=false;
- proc:=p;
- end;
- constructor TDirectiveItem.CreateCond(AList:TFPHashObjectList;const n:string;p:tdirectiveproc);
- begin
- inherited Create(AList,n);
- is_conditional:=true;
- proc:=p;
- end;
- {****************************************************************************
- TSCANNERFILE
- ****************************************************************************}
- constructor tscannerfile.create(const fn:string; is_macro: boolean = false);
- begin
- inputfile:=do_openinputfile(fn);
- if is_macro then
- inputfile.is_macro:=true;
- if assigned(current_module) then
- current_module.sourcefiles.register_file(inputfile);
- { reset localinput }
- c:=#0;
- inputbuffer:=nil;
- inputpointer:=nil;
- inputstart:=0;
- { reset scanner }
- preprocstack:=nil;
- replaystack:=nil;
- comment_level:=0;
- yylexcount:=0;
- block_type:=bt_general;
- line_no:=0;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- lasttoken:=NOTOKEN;
- nexttoken:=NOTOKEN;
- ignoredirectives:=TFPHashList.Create;
- change_endian_for_replay:=false;
- end;
- procedure tscannerfile.firstfile;
- begin
- { load block }
- if not openinputfile then
- Message1(scan_f_cannot_open_input,inputfile.name);
- reload;
- end;
- destructor tscannerfile.destroy;
- begin
- if assigned(current_module) and
- (current_module.state=ms_compiled) and
- (status.errorcount=0) then
- checkpreprocstack
- else
- begin
- while assigned(preprocstack) do
- poppreprocstack;
- end;
- while assigned(replaystack) do
- popreplaystack;
- if not inputfile.closed then
- closeinputfile;
- if inputfile.is_macro then
- inputfile.free;
- ignoredirectives.free;
- end;
- function tscannerfile.openinputfile:boolean;
- begin
- openinputfile:=inputfile.open;
- { load buffer }
- inputbuffer:=inputfile.buf;
- inputpointer:=inputfile.buf;
- inputstart:=inputfile.bufstart;
- { line }
- line_no:=0;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- end;
- procedure tscannerfile.closeinputfile;
- begin
- inputfile.close;
- { reset buffer }
- inputbuffer:=nil;
- inputpointer:=nil;
- inputstart:=0;
- { reset line }
- line_no:=0;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- end;
- function tscannerfile.tempopeninputfile:boolean;
- begin
- tempopeninputfile:=false;
- if inputfile.is_macro then
- exit;
- tempopeninputfile:=inputfile.tempopen;
- { reload buffer }
- inputbuffer:=inputfile.buf;
- inputpointer:=inputfile.buf;
- inputstart:=inputfile.bufstart;
- end;
- procedure tscannerfile.tempcloseinputfile;
- begin
- if inputfile.closed or inputfile.is_macro then
- exit;
- inputfile.setpos(inputstart+(inputpointer-inputbuffer));
- inputfile.tempclose;
- { reset buffer }
- inputbuffer:=nil;
- inputpointer:=nil;
- inputstart:=0;
- end;
- procedure tscannerfile.saveinputfile;
- begin
- inputfile.saveinputpointer:=inputpointer;
- inputfile.savelastlinepos:=lastlinepos;
- inputfile.saveline_no:=line_no;
- end;
- procedure tscannerfile.restoreinputfile;
- begin
- inputbuffer:=inputfile.buf;
- inputpointer:=inputfile.saveinputpointer;
- lastlinepos:=inputfile.savelastlinepos;
- line_no:=inputfile.saveline_no;
- if not inputfile.is_macro then
- parser_current_file:=inputfile.name;
- end;
- procedure tscannerfile.nextfile;
- var
- to_dispose : tinputfile;
- begin
- if assigned(inputfile.next) then
- begin
- if inputfile.is_macro then
- begin
- to_dispose:=inputfile;
- dec(macro_nesting_depth);
- end
- else
- begin
- to_dispose:=nil;
- dec(inputfilecount);
- end;
- { we can allways close the file, no ? }
- inputfile.close;
- inputfile:=inputfile.next;
- if assigned(to_dispose) then
- to_dispose.free;
- restoreinputfile;
- end;
- end;
- procedure tscannerfile.startrecordtokens(buf:tdynamicarray);
- begin
- if not assigned(buf) then
- internalerror(200511172);
- if assigned(recordtokenbuf) then
- internalerror(200511173);
- recordtokenbuf:=buf;
- fillchar(last_settings,sizeof(last_settings),0);
- last_message:=nil;
- fillchar(last_filepos,sizeof(last_filepos),0);
- end;
- procedure tscannerfile.stoprecordtokens;
- begin
- if not assigned(recordtokenbuf) then
- internalerror(200511174);
- recordtokenbuf:=nil;
- end;
- function tscannerfile.is_recording_tokens: boolean;
- begin
- result:=assigned(recordtokenbuf);
- end;
- procedure tscannerfile.writetoken(t : ttoken);
- var
- b : byte;
- begin
- if ord(t)>$7f then
- begin
- b:=(ord(t) shr 8) or $80;
- recordtokenbuf.write(b,1);
- end;
- b:=ord(t) and $ff;
- recordtokenbuf.write(b,1);
- end;
- procedure tscannerfile.tokenwritesizeint(val : asizeint);
- begin
- recordtokenbuf.write(val,sizeof(asizeint));
- end;
- procedure tscannerfile.tokenwritelongint(val : longint);
- begin
- recordtokenbuf.write(val,sizeof(longint));
- end;
- procedure tscannerfile.tokenwriteshortint(val : shortint);
- begin
- recordtokenbuf.write(val,sizeof(shortint));
- end;
- procedure tscannerfile.tokenwriteword(val : word);
- begin
- recordtokenbuf.write(val,sizeof(word));
- end;
- procedure tscannerfile.tokenwritelongword(val : longword);
- begin
- recordtokenbuf.write(val,sizeof(longword));
- end;
- function tscannerfile.tokenreadsizeint : asizeint;
- var
- val : asizeint;
- begin
- replaytokenbuf.read(val,sizeof(asizeint));
- if change_endian_for_replay then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadlongword : longword;
- var
- val : longword;
- begin
- replaytokenbuf.read(val,sizeof(longword));
- if change_endian_for_replay then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadlongint : longint;
- var
- val : longint;
- begin
- replaytokenbuf.read(val,sizeof(longint));
- if change_endian_for_replay then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadshortint : shortint;
- var
- val : shortint;
- begin
- replaytokenbuf.read(val,sizeof(shortint));
- result:=val;
- end;
- function tscannerfile.tokenreadbyte : byte;
- var
- val : byte;
- begin
- replaytokenbuf.read(val,sizeof(byte));
- result:=val;
- end;
- function tscannerfile.tokenreadsmallint : smallint;
- var
- val : smallint;
- begin
- replaytokenbuf.read(val,sizeof(smallint));
- if change_endian_for_replay then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadword : word;
- var
- val : word;
- begin
- replaytokenbuf.read(val,sizeof(word));
- if change_endian_for_replay then
- val:=swapendian(val);
- result:=val;
- end;
- function tscannerfile.tokenreadenum(size : longint) : longword;
- begin
- if size=1 then
- result:=tokenreadbyte
- else if size=2 then
- result:=tokenreadword
- else if size=4 then
- result:=tokenreadlongword
- else
- internalerror(2013112901);
- end;
- procedure tscannerfile.tokenreadset(var b;size : longint);
- var
- i : longint;
- begin
- replaytokenbuf.read(b,size);
- if change_endian_for_replay then
- for i:=0 to size-1 do
- Pbyte(@b)[i]:=reverse_byte(Pbyte(@b)[i]);
- end;
- procedure tscannerfile.tokenwriteenum(var b;size : longint);
- begin
- recordtokenbuf.write(b,size);
- end;
- procedure tscannerfile.tokenwriteset(var b;size : longint);
- begin
- recordtokenbuf.write(b,size);
- end;
- procedure tscannerfile.tokenreadsettings(var asettings : tsettings; expected_size : asizeint);
- { This procedure
- needs to be changed whenever
- globals.tsettings type is changed,
- the problem is that no error will appear
- before tests with generics are tested. PM }
- var
- startpos, endpos : longword;
- begin
- { WARNING all those fields need to be in the correct
- order otherwise cross_endian PPU reading will fail }
- startpos:=replaytokenbuf.pos;
- with asettings do
- begin
- alignment.procalign:=tokenreadlongint;
- alignment.loopalign:=tokenreadlongint;
- alignment.jumpalign:=tokenreadlongint;
- alignment.jumpalignskipmax:=tokenreadlongint;
- alignment.coalescealign:=tokenreadlongint;
- alignment.coalescealignskipmax:=tokenreadlongint;
- alignment.constalignmin:=tokenreadlongint;
- alignment.constalignmax:=tokenreadlongint;
- alignment.varalignmin:=tokenreadlongint;
- alignment.varalignmax:=tokenreadlongint;
- alignment.localalignmin:=tokenreadlongint;
- alignment.localalignmax:=tokenreadlongint;
- alignment.recordalignmin:=tokenreadlongint;
- alignment.recordalignmax:=tokenreadlongint;
- alignment.maxCrecordalign:=tokenreadlongint;
- tokenreadset(globalswitches,sizeof(globalswitches));
- tokenreadset(targetswitches,sizeof(targetswitches));
- tokenreadset(moduleswitches,sizeof(moduleswitches));
- tokenreadset(localswitches,sizeof(localswitches));
- tokenreadset(modeswitches,sizeof(modeswitches));
- tokenreadset(optimizerswitches,sizeof(optimizerswitches));
- tokenreadset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
- tokenreadset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
- tokenreadset(debugswitches,sizeof(debugswitches));
- { 0: old behaviour for sets <=256 elements
- >0: round to this size }
- setalloc:=tokenreadshortint;
- packenum:=tokenreadshortint;
- packrecords:=tokenreadshortint;
- maxfpuregisters:=tokenreadshortint;
- cputype:=tcputype(tokenreadenum(sizeof(tcputype)));
- optimizecputype:=tcputype(tokenreadenum(sizeof(tcputype)));
- fputype:=tfputype(tokenreadenum(sizeof(tfputype)));
- asmmode:=tasmmode(tokenreadenum(sizeof(tasmmode)));
- interfacetype:=tinterfacetypes(tokenreadenum(sizeof(tinterfacetypes)));
- defproccall:=tproccalloption(tokenreadenum(sizeof(tproccalloption)));
- { tstringencoding is word type,
- thus this should be OK here }
- sourcecodepage:=tstringEncoding(tokenreadword);
- minfpconstprec:=tfloattype(tokenreadenum(sizeof(tfloattype)));
- disabledircache:=boolean(tokenreadbyte);
- tlsmodel:=ttlsmodel(tokenreadenum(sizeof(ttlsmodel)));
- { TH: Since the field was conditional originally, it was not stored in PPUs. }
- { While adding ControllerSupport constant, I decided not to store ct_none }
- { on targets not supporting controllers, but this might be changed here and }
- { in tokenwritesettings in the future to unify the PPU structure and handling }
- { of this field in the compiler. }
- {$PUSH}
- {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)
- if ControllerSupport then
- controllertype:=tcontrollertype(tokenreadenum(sizeof(tcontrollertype)))
- else
- ControllerType:=ct_none;
- {$POP}
- endpos:=replaytokenbuf.pos;
- if endpos-startpos<>expected_size then
- Comment(V_Error,'Wrong size of Settings read-in');
- end;
- end;
- procedure tscannerfile.tokenwritesettings(var asettings : tsettings; var size : asizeint);
- { This procedure
- needs to be changed whenever
- globals.tsettings type is changed,
- the problem is that no error will appear
- before tests with generics are tested. PM }
- var
- sizepos, startpos, endpos : longword;
- begin
- { WARNING all those fields need to be in the correct
- order otherwise cross_endian PPU reading will fail }
- sizepos:=recordtokenbuf.pos;
- size:=0;
- tokenwritesizeint(size);
- startpos:=recordtokenbuf.pos;
- with asettings do
- begin
- tokenwritelongint(alignment.procalign);
- tokenwritelongint(alignment.loopalign);
- tokenwritelongint(alignment.jumpalign);
- tokenwritelongint(alignment.jumpalignskipmax);
- tokenwritelongint(alignment.coalescealign);
- tokenwritelongint(alignment.coalescealignskipmax);
- tokenwritelongint(alignment.constalignmin);
- tokenwritelongint(alignment.constalignmax);
- tokenwritelongint(alignment.varalignmin);
- tokenwritelongint(alignment.varalignmax);
- tokenwritelongint(alignment.localalignmin);
- tokenwritelongint(alignment.localalignmax);
- tokenwritelongint(alignment.recordalignmin);
- tokenwritelongint(alignment.recordalignmax);
- tokenwritelongint(alignment.maxCrecordalign);
- tokenwriteset(globalswitches,sizeof(globalswitches));
- tokenwriteset(targetswitches,sizeof(targetswitches));
- tokenwriteset(moduleswitches,sizeof(moduleswitches));
- tokenwriteset(localswitches,sizeof(localswitches));
- tokenwriteset(modeswitches,sizeof(modeswitches));
- tokenwriteset(optimizerswitches,sizeof(optimizerswitches));
- tokenwriteset(genwpoptimizerswitches,sizeof(genwpoptimizerswitches));
- tokenwriteset(dowpoptimizerswitches,sizeof(dowpoptimizerswitches));
- tokenwriteset(debugswitches,sizeof(debugswitches));
- { 0: old behaviour for sets <=256 elements
- >0: round to this size }
- tokenwriteshortint(setalloc);
- tokenwriteshortint(packenum);
- tokenwriteshortint(packrecords);
- tokenwriteshortint(maxfpuregisters);
- tokenwriteenum(cputype,sizeof(tcputype));
- tokenwriteenum(optimizecputype,sizeof(tcputype));
- tokenwriteenum(fputype,sizeof(tfputype));
- tokenwriteenum(asmmode,sizeof(tasmmode));
- tokenwriteenum(interfacetype,sizeof(tinterfacetypes));
- tokenwriteenum(defproccall,sizeof(tproccalloption));
- { tstringencoding is word type,
- thus this should be OK here }
- tokenwriteword(sourcecodepage);
- tokenwriteenum(minfpconstprec,sizeof(tfloattype));
- recordtokenbuf.write(byte(disabledircache),1);
- tokenwriteenum(tlsmodel,sizeof(tlsmodel));
- { TH: See note about controllertype field in tokenreadsettings. }
- {$PUSH}
- {$WARN 6018 OFF} (* Unreachable code due to compile time evaluation *)
- if ControllerSupport then
- tokenwriteenum(controllertype,sizeof(tcontrollertype));
- {$POP}
- endpos:=recordtokenbuf.pos;
- size:=endpos-startpos;
- recordtokenbuf.seek(sizepos);
- tokenwritesizeint(size);
- recordtokenbuf.seek(endpos);
- end;
- end;
- procedure tscannerfile.recordtoken;
- var
- t : ttoken;
- s : tspecialgenerictoken;
- len,msgnb,copy_size : asizeint;
- val : longint;
- b : byte;
- pmsg : pmessagestaterecord;
- begin
- if not assigned(recordtokenbuf) then
- internalerror(200511176);
- t:=_GENERICSPECIALTOKEN;
- { settings changed? }
- { last field pmessage is handled separately below in
- ST_LOADMESSAGES }
- if CompareByte(current_settings,last_settings,
- sizeof(current_settings)-sizeof(pointer))<>0 then
- begin
- { use a special token to record it }
- s:=ST_LOADSETTINGS;
- writetoken(t);
- recordtokenbuf.write(s,1);
- copy_size:=sizeof(current_settings)-sizeof(pointer);
- tokenwritesettings(current_settings,copy_size);
- last_settings:=current_settings;
- end;
- if current_settings.pmessage<>last_message then
- begin
- { use a special token to record it }
- s:=ST_LOADMESSAGES;
- writetoken(t);
- recordtokenbuf.write(s,1);
- msgnb:=0;
- pmsg:=current_settings.pmessage;
- while assigned(pmsg) do
- begin
- if msgnb=high(asizeint) then
- { Too many messages }
- internalerror(2011090401);
- inc(msgnb);
- pmsg:=pmsg^.next;
- end;
- tokenwritesizeint(msgnb);
- pmsg:=current_settings.pmessage;
- while assigned(pmsg) do
- begin
- { What about endianess here?}
- { SB: this is handled by tokenreadlongint }
- val:=pmsg^.value;
- tokenwritelongint(val);
- val:=ord(pmsg^.state);
- tokenwritelongint(val);
- pmsg:=pmsg^.next;
- end;
- last_message:=current_settings.pmessage;
- end;
- { file pos changes? }
- if current_tokenpos.fileindex<>last_filepos.fileindex then
- begin
- s:=ST_FILEINDEX;
- writetoken(t);
- recordtokenbuf.write(s,1);
- tokenwriteword(current_tokenpos.fileindex);
- last_filepos.fileindex:=current_tokenpos.fileindex;
- last_filepos.line:=0;
- end;
- if current_tokenpos.line<>last_filepos.line then
- begin
- s:=ST_LINE;
- writetoken(t);
- recordtokenbuf.write(s,1);
- tokenwritelongint(current_tokenpos.line);
- last_filepos.line:=current_tokenpos.line;
- last_filepos.column:=0;
- end;
- if current_tokenpos.column<>last_filepos.column then
- begin
- s:=ST_COLUMN;
- writetoken(t);
- { can the column be written packed? }
- if current_tokenpos.column<$80 then
- begin
- b:=$80 or current_tokenpos.column;
- recordtokenbuf.write(b,1);
- end
- else
- begin
- recordtokenbuf.write(s,1);
- tokenwriteword(current_tokenpos.column);
- end;
- last_filepos.column:=current_tokenpos.column;
- end;
- writetoken(token);
- if token<>_GENERICSPECIALTOKEN then
- writetoken(idtoken);
- case token of
- _CWCHAR,
- _CWSTRING :
- begin
- tokenwritesizeint(patternw^.len);
- if patternw^.len>0 then
- recordtokenbuf.write(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
- end;
- _CSTRING:
- begin
- len:=length(cstringpattern);
- tokenwritesizeint(len);
- if len>0 then
- recordtokenbuf.write(cstringpattern[1],len);
- end;
- _CCHAR,
- _INTCONST,
- _REALNUMBER :
- begin
- { pexpr.pas messes with pattern in case of negative integer consts,
- see around line 2562 the comment of JM; remove the - before recording it
- (FK)
- }
- if (token=_INTCONST) and (pattern[1]='-') then
- delete(pattern,1,1);
- recordtokenbuf.write(pattern[0],1);
- recordtokenbuf.write(pattern[1],length(pattern));
- end;
- _ID :
- begin
- recordtokenbuf.write(orgpattern[0],1);
- recordtokenbuf.write(orgpattern[1],length(orgpattern));
- end;
- else
- ;
- end;
- end;
- procedure tscannerfile.startreplaytokens(buf:tdynamicarray; change_endian:boolean);
- begin
- if not assigned(buf) then
- internalerror(200511175);
- { save current scanner state }
- replaystack:=treplaystack.create(token,idtoken,orgpattern,pattern,
- cstringpattern,patternw,current_settings,replaytokenbuf,change_endian_for_replay,replaystack);
- if assigned(inputpointer) then
- dec(inputpointer);
- { install buffer }
- replaytokenbuf:=buf;
- { Initialize value of change_endian_for_replay variable }
- change_endian_for_replay:=change_endian;
- { reload next token }
- replaytokenbuf.seek(0);
- replaytoken;
- end;
- function tscannerfile.readtoken: ttoken;
- var
- b,b2 : byte;
- begin
- replaytokenbuf.read(b,1);
- if (b and $80)<>0 then
- begin
- replaytokenbuf.read(b2,1);
- result:=ttoken(((b and $7f) shl 8) or b2);
- end
- else
- result:=ttoken(b);
- end;
- procedure tscannerfile.replaytoken;
- var
- wlen,mesgnb,copy_size : asizeint;
- specialtoken : tspecialgenerictoken;
- i : byte;
- pmsg,prevmsg : pmessagestaterecord;
- begin
- if not assigned(replaytokenbuf) then
- internalerror(200511177);
- { End of replay buffer? Then load the next char from the file again }
- if replaytokenbuf.pos>=replaytokenbuf.size then
- begin
- token:=replaystack.token;
- idtoken:=replaystack.idtoken;
- pattern:=replaystack.pattern;
- orgpattern:=replaystack.orgpattern;
- setlengthwidestring(patternw,replaystack.patternw^.len);
- move(replaystack.patternw^.data^,patternw^.data^,replaystack.patternw^.len*sizeof(tcompilerwidechar));
- cstringpattern:=replaystack.cstringpattern;
- replaytokenbuf:=replaystack.tokenbuf;
- change_endian_for_replay:=replaystack.tokenbuf_needs_swapping;
- { restore compiler settings }
- current_settings:=replaystack.settings;
- popreplaystack;
- if assigned(inputpointer) then
- begin
- c:=inputpointer^;
- inc(inputpointer);
- end;
- exit;
- end;
- repeat
- { load token from the buffer }
- token:=readtoken;
- if token<>_GENERICSPECIALTOKEN then
- idtoken:=readtoken
- else
- idtoken:=_NOID;
- case token of
- _CWCHAR,
- _CWSTRING :
- begin
- wlen:=tokenreadsizeint;
- setlengthwidestring(patternw,wlen);
- if wlen>0 then
- replaytokenbuf.read(patternw^.data^,patternw^.len*sizeof(tcompilerwidechar));
- orgpattern:='';
- pattern:='';
- cstringpattern:='';
- end;
- _CSTRING:
- begin
- wlen:=tokenreadsizeint;
- if wlen>0 then
- begin
- setlength(cstringpattern,wlen);
- replaytokenbuf.read(cstringpattern[1],wlen);
- end
- else
- cstringpattern:='';
- orgpattern:='';
- pattern:='';
- end;
- _CCHAR,
- _INTCONST,
- _REALNUMBER :
- begin
- replaytokenbuf.read(pattern[0],1);
- replaytokenbuf.read(pattern[1],length(pattern));
- orgpattern:='';
- end;
- _ID :
- begin
- replaytokenbuf.read(orgpattern[0],1);
- replaytokenbuf.read(orgpattern[1],length(orgpattern));
- pattern:=upper(orgpattern);
- end;
- _GENERICSPECIALTOKEN:
- begin
- replaytokenbuf.read(specialtoken,1);
- { packed column? }
- if (ord(specialtoken) and $80)<>0 then
- begin
- current_tokenpos.column:=ord(specialtoken) and $7f;
- current_filepos:=current_tokenpos;
- end
- else
- case specialtoken of
- ST_LOADSETTINGS:
- begin
- copy_size:=tokenreadsizeint;
- //if copy_size <> sizeof(current_settings)-sizeof(pointer) then
- // internalerror(2011090501);
- {
- replaytokenbuf.read(current_settings,copy_size);
- }
- tokenreadsettings(current_settings,copy_size);
- end;
- ST_LOADMESSAGES:
- begin
- current_settings.pmessage:=nil;
- mesgnb:=tokenreadsizeint;
- prevmsg:=nil;
- for i:=1 to mesgnb do
- begin
- new(pmsg);
- if i=1 then
- current_settings.pmessage:=pmsg
- else
- prevmsg^.next:=pmsg;
- pmsg^.value:=tokenreadlongint;
- pmsg^.state:=tmsgstate(tokenreadlongint);
- pmsg^.next:=nil;
- prevmsg:=pmsg;
- end;
- end;
- ST_LINE:
- begin
- current_tokenpos.line:=tokenreadlongint;
- current_filepos:=current_tokenpos;
- end;
- ST_COLUMN:
- begin
- current_tokenpos.column:=tokenreadword;
- current_filepos:=current_tokenpos;
- end;
- ST_FILEINDEX:
- begin
- current_tokenpos.fileindex:=tokenreadword;
- current_filepos:=current_tokenpos;
- end;
- end;
- continue;
- end;
- else
- ;
- end;
- break;
- until false;
- end;
- procedure tscannerfile.addfile(hp:tinputfile);
- begin
- saveinputfile;
- { add to list }
- hp.next:=inputfile;
- inputfile:=hp;
- { load new inputfile }
- restoreinputfile;
- end;
- procedure tscannerfile.reload;
- begin
- with inputfile do
- begin
- { when nothing more to read then leave immediatly, so we
- don't change the current_filepos and leave it point to the last
- char }
- if (c=#26) and (not assigned(next)) then
- exit;
- repeat
- { still more to read?, then change the #0 to a space so its seen
- as a seperator, this can't be used for macro's which can change
- the place of the #0 in the buffer with tempopen }
- if (c=#0) and (bufsize>0) and
- not(inputfile.is_macro) and
- (inputpointer-inputbuffer<bufsize) then
- begin
- c:=' ';
- inc(inputpointer);
- exit;
- end;
- { can we read more from this file ? }
- if (c<>#26) and (not endoffile) then
- begin
- readbuf;
- inputpointer:=buf;
- inputbuffer:=buf;
- inputstart:=bufstart;
- { first line? }
- if line_no=0 then
- begin
- c:=inputpointer^;
- { eat utf-8 signature? }
- if (ord(inputpointer^)=$ef) and
- (ord((inputpointer+1)^)=$bb) and
- (ord((inputpointer+2)^)=$bf) then
- begin
- (* we don't support including files with an UTF-8 bom
- inside another file that wasn't encoded as UTF-8
- already (we don't support {$codepage xxx} switches in
- the middle of a file either) *)
- if (current_settings.sourcecodepage<>CP_UTF8) and
- not current_module.in_global then
- Message(scanner_f_illegal_utf8_bom);
- inc(inputpointer,3);
- message(scan_c_switching_to_utf8);
- current_settings.sourcecodepage:=CP_UTF8;
- exclude(current_settings.moduleswitches,cs_system_codepage);
- include(current_settings.moduleswitches,cs_explicit_codepage);
- end;
- line_no:=1;
- if cs_asm_source in current_settings.globalswitches then
- inputfile.setline(line_no,inputstart+inputpointer-inputbuffer);
- end;
- end
- else
- begin
- { load eof position in tokenpos/current_filepos }
- gettokenpos;
- { close file }
- closeinputfile;
- { no next module, than EOF }
- if not assigned(inputfile.next) then
- begin
- c:=#26;
- exit;
- end;
- { load next file and reopen it }
- nextfile;
- tempopeninputfile;
- { status }
- Message1(scan_t_back_in,inputfile.name);
- end;
- { load next char }
- c:=inputpointer^;
- inc(inputpointer);
- until c<>#0; { if also end, then reload again }
- end;
- end;
- procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint);
- var
- hp : tinputfile;
- begin
- { save old postion }
- dec(inputpointer);
- tempcloseinputfile;
- { create macro 'file' }
- { use special name to dispose after !! }
- hp:=do_openinputfile('_Macro_.'+macname);
- addfile(hp);
- with inputfile do
- begin
- inc(macro_nesting_depth);
- setmacro(p,len);
- { local buffer }
- inputbuffer:=buf;
- inputpointer:=buf;
- inputstart:=bufstart;
- ref_index:=fileindex;
- end;
- { reset line }
- line_no:=line;
- lastlinepos:=0;
- lasttokenpos:=0;
- nexttokenpos:=0;
- { load new c }
- c:=inputpointer^;
- inc(inputpointer);
- end;
- procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
- begin
- tokenpos:=inputstart+(inputpointer-inputbuffer);
- filepos.line:=line_no;
- filepos.column:=tokenpos-lastlinepos;
- filepos.fileindex:=inputfile.ref_index;
- filepos.moduleindex:=current_module.unit_index;
- end;
- procedure tscannerfile.gettokenpos;
- { load the values of tokenpos and lasttokenpos }
- begin
- do_gettokenpos(lasttokenpos,current_tokenpos);
- current_filepos:=current_tokenpos;
- end;
- procedure tscannerfile.cachenexttokenpos;
- begin
- do_gettokenpos(nexttokenpos,next_filepos);
- end;
- procedure tscannerfile.setnexttoken;
- begin
- token:=nexttoken;
- nexttoken:=NOTOKEN;
- lasttokenpos:=nexttokenpos;
- current_tokenpos:=next_filepos;
- current_filepos:=current_tokenpos;
- nexttokenpos:=0;
- end;
- procedure tscannerfile.savetokenpos;
- begin
- oldlasttokenpos:=lasttokenpos;
- oldcurrent_filepos:=current_filepos;
- oldcurrent_tokenpos:=current_tokenpos;
- end;
- procedure tscannerfile.restoretokenpos;
- begin
- lasttokenpos:=oldlasttokenpos;
- current_filepos:=oldcurrent_filepos;
- current_tokenpos:=oldcurrent_tokenpos;
- end;
- procedure tscannerfile.inc_comment_level;
- begin
- if (m_nested_comment in current_settings.modeswitches) then
- inc(comment_level)
- else
- comment_level:=1;
- if (comment_level>1) then
- begin
- savetokenpos;
- gettokenpos; { update for warning }
- Message1(scan_w_comment_level,tostr(comment_level));
- restoretokenpos;
- end;
- end;
- procedure tscannerfile.dec_comment_level;
- begin
- if (m_nested_comment in current_settings.modeswitches) then
- dec(comment_level)
- else
- comment_level:=0;
- end;
- procedure tscannerfile.linebreak;
- var
- cur : char;
- begin
- with inputfile do
- begin
- if (byte(inputpointer^)=0) and not(endoffile) then
- begin
- cur:=c;
- reload;
- if byte(cur)+byte(c)<>23 then
- dec(inputpointer);
- end
- else
- begin
- { Support all combination of #10 and #13 as line break }
- if (byte(inputpointer^)+byte(c)=23) then
- inc(inputpointer);
- end;
- { Always return #10 as line break }
- c:=#10;
- { increase line counters }
- lastlinepos:=inputstart+(inputpointer-inputbuffer);
- inc(line_no);
- { update linebuffer }
- if cs_asm_source in current_settings.globalswitches then
- inputfile.setline(line_no,lastlinepos);
- { update for status and call the show status routine,
- but don't touch current_filepos ! }
- savetokenpos;
- gettokenpos; { update for v_status }
- inc(status.compiledlines);
- ShowStatus;
- restoretokenpos;
- end;
- end;
- procedure tscannerfile.illegal_char(c:char);
- var
- s : string;
- begin
- if c in [#32..#255] then
- s:=''''+c+''''
- else
- s:='#'+tostr(ord(c));
- Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
- end;
- procedure tscannerfile.end_of_file;
- begin
- checkpreprocstack;
- Message(scan_f_end_of_file);
- end;
- {-------------------------------------------
- IF Conditional Handling
- -------------------------------------------}
- procedure tscannerfile.checkpreprocstack;
- begin
- { check for missing ifdefs }
- while assigned(preprocstack) do
- begin
- Message4(scan_e_endif_expected,preprocstring[preprocstack.typ],preprocstack.name,
- current_module.sourcefiles.get_file_name(preprocstack.fileindex),
- tostr(preprocstack.line_nb));
- poppreprocstack;
- end;
- end;
- procedure tscannerfile.poppreprocstack;
- var
- hp : tpreprocstack;
- begin
- if assigned(preprocstack) then
- begin
- Message1(scan_c_endif_found,preprocstack.name);
- hp:=preprocstack.next;
- preprocstack.free;
- preprocstack:=hp;
- end
- else
- Message(scan_e_endif_without_if);
- end;
- procedure tscannerfile.ifpreprocstack(atyp:preproctyp;compile_time_predicate:tcompile_time_predicate;messid:longint);
- var
- condition: Boolean;
- valuedescr: String;
- begin
- if (preprocstack=nil) or preprocstack.accept then
- condition:=compile_time_predicate(valuedescr)
- else
- begin
- condition:= false;
- valuedescr:= '';
- end;
- preprocstack:=tpreprocstack.create(atyp, condition, preprocstack);
- preprocstack.name:=valuedescr;
- preprocstack.line_nb:=line_no;
- preprocstack.fileindex:=current_filepos.fileindex;
- if preprocstack.accept then
- Message2(messid,preprocstack.name,'accepted')
- else
- Message2(messid,preprocstack.name,'rejected');
- end;
- procedure tscannerfile.elsepreprocstack;
- begin
- if assigned(preprocstack) and
- (preprocstack.typ<>pp_else) then
- begin
- if (preprocstack.typ=pp_elseif) then
- preprocstack.accept:=false
- else
- if (not(assigned(preprocstack.next)) or (preprocstack.next.accept)) then
- preprocstack.accept:=not preprocstack.accept;
- preprocstack.typ:=pp_else;
- preprocstack.line_nb:=line_no;
- preprocstack.fileindex:=current_filepos.fileindex;
- if preprocstack.accept then
- Message2(scan_c_else_found,preprocstack.name,'accepted')
- else
- Message2(scan_c_else_found,preprocstack.name,'rejected');
- end
- else
- Message(scan_e_endif_without_if);
- end;
- procedure tscannerfile.elseifpreprocstack(compile_time_predicate:tcompile_time_predicate);
- var
- valuedescr: String;
- begin
- if assigned(preprocstack) and
- (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef,pp_elseif]) then
- begin
- { when the branch is accepted we use pp_elseif so we know that
- all the next branches need to be rejected. when this branch is still
- not accepted then leave it at pp_if }
- if (preprocstack.typ=pp_elseif) then
- preprocstack.accept:=false
- else if (preprocstack.typ in [pp_if,pp_ifdef,pp_ifndef]) and preprocstack.accept then
- begin
- preprocstack.accept:=false;
- preprocstack.typ:=pp_elseif;
- end
- else if (not(assigned(preprocstack.next)) or (preprocstack.next.accept))
- and compile_time_predicate(valuedescr) then
- begin
- preprocstack.name:=valuedescr;
- preprocstack.accept:=true;
- preprocstack.typ:=pp_elseif;
- end;
- preprocstack.line_nb:=line_no;
- preprocstack.fileindex:=current_filepos.fileindex;
- if preprocstack.accept then
- Message2(scan_c_else_found,preprocstack.name,'accepted')
- else
- Message2(scan_c_else_found,preprocstack.name,'rejected');
- end
- else
- Message(scan_e_endif_without_if);
- end;
- procedure tscannerfile.popreplaystack;
- var
- hp : treplaystack;
- begin
- if assigned(replaystack) then
- begin
- hp:=replaystack.next;
- replaystack.free;
- replaystack:=hp;
- end;
- end;
- function tscannerfile.replay_stack_depth:longint;
- var
- tmp: treplaystack;
- begin
- result:=0;
- tmp:=replaystack;
- while assigned(tmp) do
- begin
- inc(result);
- tmp:=tmp.next;
- end;
- end;
- procedure tscannerfile.handleconditional(p:tdirectiveitem);
- begin
- savetokenpos;
- repeat
- current_scanner.gettokenpos;
- Message1(scan_d_handling_switch,'$'+p.name);
- p.proc();
- { accept the text ? }
- if (current_scanner.preprocstack=nil) or current_scanner.preprocstack.accept then
- break
- else
- begin
- current_scanner.gettokenpos;
- Message(scan_c_skipping_until);
- repeat
- current_scanner.skipuntildirective;
- if not (m_mac in current_settings.modeswitches) then
- p:=tdirectiveitem(turbo_scannerdirectives.Find(current_scanner.readid))
- else
- p:=tdirectiveitem(mac_scannerdirectives.Find(current_scanner.readid));
- until assigned(p) and (p.is_conditional);
- current_scanner.gettokenpos;
- end;
- until false;
- restoretokenpos;
- end;
- procedure tscannerfile.handledirectives;
- var
- t : tdirectiveitem;
- hs : string;
- begin
- gettokenpos;
- readchar; {Remove the $}
- hs:=readid;
- { handle empty directive }
- if hs='' then
- begin
- Message1(scan_w_illegal_switch,'$');
- exit;
- end;
- {$ifdef PREPROCWRITE}
- if parapreprocess then
- begin
- if not (m_mac in current_settings.modeswitches) then
- t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
- else
- t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
- if assigned(t) and not(t.is_conditional) then
- begin
- preprocfile.AddSpace;
- preprocfile.Add('{$'+hs+current_scanner.readcomment+'}');
- exit;
- end;
- end;
- {$endif PREPROCWRITE}
- { skip this directive? }
- if (ignoredirectives.find(hs)<>nil) then
- begin
- if (comment_level>0) then
- readcomment;
- { we've read the whole comment }
- current_commentstyle:=comment_none;
- exit;
- end;
- { Check for compiler switches }
- while (length(hs)=1) and (c in ['-','+']) do
- begin
- Message1(scan_d_handling_switch,'$'+hs+c);
- HandleSwitch(hs[1],c);
- current_scanner.readchar; {Remove + or -}
- if c=',' then
- begin
- current_scanner.readchar; {Remove , }
- { read next switch, support $v+,$+}
- hs:=current_scanner.readid;
- if (hs='') then
- begin
- if (c='$') and (m_fpc in current_settings.modeswitches) then
- begin
- current_scanner.readchar; { skip $ }
- hs:=current_scanner.readid;
- end;
- if (hs='') then
- Message1(scan_w_illegal_directive,'$'+c);
- end;
- end
- else
- hs:='';
- end;
- { directives may follow switches after a , }
- if hs<>'' then
- begin
- if not (m_mac in current_settings.modeswitches) then
- t:=tdirectiveitem(turbo_scannerdirectives.Find(hs))
- else
- t:=tdirectiveitem(mac_scannerdirectives.Find(hs));
- if assigned(t) then
- begin
- if t.is_conditional then
- handleconditional(t)
- else
- begin
- Message1(scan_d_handling_switch,'$'+hs);
- t.proc();
- end;
- end
- else
- begin
- current_scanner.ignoredirectives.Add(hs,nil);
- Message1(scan_w_illegal_directive,'$'+hs);
- end;
- { conditionals already read the comment }
- if (current_scanner.comment_level>0) then
- current_scanner.readcomment;
- { we've read the whole comment }
- current_commentstyle:=comment_none;
- end;
- end;
- procedure tscannerfile.readchar;
- begin
- c:=inputpointer^;
- if c=#0 then
- reload
- else
- inc(inputpointer);
- end;
- procedure tscannerfile.readstring;
- var
- i : longint;
- err : boolean;
- begin
- err:=false;
- i:=0;
- repeat
- case c of
- '_',
- '0'..'9',
- 'A'..'Z' :
- begin
- if i<255 then
- begin
- inc(i);
- orgpattern[i]:=c;
- pattern[i]:=c;
- end
- else
- begin
- if not err then
- begin
- Message(scan_e_string_exceeds_255_chars);
- err:=true;
- end;
- end;
- c:=inputpointer^;
- inc(inputpointer);
- end;
- 'a'..'z' :
- begin
- if i<255 then
- begin
- inc(i);
- orgpattern[i]:=c;
- pattern[i]:=chr(ord(c)-32)
- end
- else
- begin
- if not err then
- begin
- Message(scan_e_string_exceeds_255_chars);
- err:=true;
- end;
- end;
- c:=inputpointer^;
- inc(inputpointer);
- end;
- #0 :
- reload;
- else
- break;
- end;
- until false;
- orgpattern[0]:=chr(i);
- pattern[0]:=chr(i);
- end;
- procedure tscannerfile.readnumber;
- var
- base,
- i : longint;
- begin
- case c of
- '%' :
- begin
- readchar;
- base:=2;
- pattern[1]:='%';
- i:=1;
- end;
- '&' :
- begin
- readchar;
- base:=8;
- pattern[1]:='&';
- i:=1;
- end;
- '$' :
- begin
- readchar;
- base:=16;
- pattern[1]:='$';
- i:=1;
- end;
- else
- begin
- base:=10;
- i:=0;
- end;
- end;
- while ((base>=10) and (c in ['0'..'9'])) or
- ((base=16) and (c in ['A'..'F','a'..'f'])) or
- ((base=8) and (c in ['0'..'7'])) or
- ((base=2) and (c in ['0'..'1'])) do
- begin
- if i<255 then
- begin
- inc(i);
- pattern[i]:=c;
- end;
- readchar;
- end;
- pattern[0]:=chr(i);
- end;
- function tscannerfile.readid:string;
- begin
- readstring;
- readid:=pattern;
- end;
- function tscannerfile.readval:longint;
- var
- l : longint;
- w : integer;
- begin
- readnumber;
- val(pattern,l,w);
- readval:=l;
- end;
- function tscannerfile.readcomment(include_special_char: boolean):string;
- var
- i : longint;
- begin
- i:=0;
- repeat
- case c of
- '{' :
- begin
- if (include_special_char) and (i<255) then
- begin
- inc(i);
- readcomment[i]:=c;
- end;
- if current_commentstyle=comment_tp then
- inc_comment_level;
- end;
- '}' :
- begin
- if (include_special_char) and (i<255) then
- begin
- inc(i);
- readcomment[i]:=c;
- end;
- if current_commentstyle=comment_tp then
- begin
- readchar;
- dec_comment_level;
- if comment_level=0 then
- break
- else
- continue;
- end;
- end;
- '*' :
- begin
- if current_commentstyle=comment_oldtp then
- begin
- readchar;
- if c=')' then
- begin
- readchar;
- dec_comment_level;
- break;
- end
- else
- { Add both characters !!}
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:='*';
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:=c;
- end;
- end;
- end
- else
- { Not old TP comment, so add...}
- begin
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:='*';
- end;
- end;
- end;
- #10,#13 :
- linebreak;
- #26 :
- end_of_file;
- else
- begin
- if (i<255) then
- begin
- inc(i);
- readcomment[i]:=c;
- end;
- end;
- end;
- readchar;
- until false;
- readcomment[0]:=chr(i);
- end;
- function tscannerfile.readquotedstring:string;
- var
- i : longint;
- msgwritten : boolean;
- begin
- i:=0;
- msgwritten:=false;
- if (c='''') then
- begin
- repeat
- readchar;
- case c of
- #26 :
- end_of_file;
- #10,#13 :
- Message(scan_f_string_exceeds_line);
- '''' :
- begin
- readchar;
- if c<>'''' then
- break;
- end;
- end;
- if i<255 then
- begin
- inc(i);
- result[i]:=c;
- end
- else
- begin
- if not msgwritten then
- begin
- Message(scan_e_string_exceeds_255_chars);
- msgwritten:=true;
- end;
- end;
- until false;
- end;
- result[0]:=chr(i);
- end;
- function tscannerfile.readstate:char;
- var
- state : char;
- begin
- state:=' ';
- if c=' ' then
- begin
- current_scanner.skipspace;
- current_scanner.readid;
- if pattern='ON' then
- state:='+'
- else
- if pattern='OFF' then
- state:='-';
- end
- else
- state:=c;
- if not (state in ['+','-']) then
- Message(scan_e_wrong_switch_toggle);
- readstate:=state;
- end;
- function tscannerfile.readoptionalstate(fallback:char):char;
- var
- state : char;
- begin
- state:=' ';
- if c=' ' then
- begin
- current_scanner.skipspace;
- if c in ['*','}'] then
- state:=fallback
- else
- begin
- current_scanner.readid;
- if pattern='ON' then
- state:='+'
- else
- if pattern='OFF' then
- state:='-';
- end;
- end
- else
- if c in ['*','}'] then
- state:=fallback
- else
- state:=c;
- if not (state in ['+','-']) then
- Message(scan_e_wrong_switch_toggle);
- readoptionalstate:=state;
- end;
- function tscannerfile.readstatedefault:char;
- var
- state : char;
- begin
- state:=' ';
- if c=' ' then
- begin
- current_scanner.skipspace;
- current_scanner.readid;
- if pattern='ON' then
- state:='+'
- else
- if pattern='OFF' then
- state:='-'
- else
- if pattern='DEFAULT' then
- state:='*';
- end
- else
- state:=c;
- if not (state in ['+','-','*']) then
- Message(scan_e_wrong_switch_toggle_default);
- readstatedefault:=state;
- end;
- procedure tscannerfile.skipspace;
- begin
- repeat
- case c of
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- break;
- continue;
- end;
- #10,
- #13 :
- linebreak;
- #9,#11,#12,' ' :
- ;
- else
- break;
- end;
- readchar;
- until false;
- end;
- procedure tscannerfile.skipuntildirective;
- var
- found : longint;
- next_char_loaded : boolean;
- begin
- found:=0;
- next_char_loaded:=false;
- repeat
- case c of
- #10,
- #13 :
- linebreak;
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- '{' :
- begin
- if (current_commentstyle in [comment_tp,comment_none]) then
- begin
- current_commentstyle:=comment_tp;
- if (comment_level=0) then
- found:=1;
- inc_comment_level;
- end;
- end;
- '*' :
- begin
- if (current_commentstyle=comment_oldtp) then
- begin
- readchar;
- if c=')' then
- begin
- dec_comment_level;
- found:=0;
- current_commentstyle:=comment_none;
- end
- else
- next_char_loaded:=true;
- end
- else
- found := 0;
- end;
- '}' :
- begin
- if (current_commentstyle=comment_tp) then
- begin
- dec_comment_level;
- if (comment_level=0) then
- current_commentstyle:=comment_none;
- found:=0;
- end;
- end;
- '$' :
- begin
- if found=1 then
- found:=2;
- end;
- '''' :
- if (current_commentstyle=comment_none) then
- begin
- repeat
- readchar;
- case c of
- #26 :
- end_of_file;
- #10,#13 :
- break;
- '''' :
- begin
- readchar;
- if c<>'''' then
- begin
- next_char_loaded:=true;
- break;
- end;
- end;
- end;
- until false;
- end;
- '(' :
- begin
- if (current_commentstyle=comment_none) then
- begin
- readchar;
- if c='*' then
- begin
- readchar;
- if c='$' then
- begin
- found:=2;
- inc_comment_level;
- current_commentstyle:=comment_oldtp;
- end
- else
- begin
- skipoldtpcomment(false);
- next_char_loaded:=true;
- end;
- end
- else
- next_char_loaded:=true;
- end
- else
- found:=0;
- end;
- '/' :
- begin
- if (current_commentstyle=comment_none) then
- begin
- readchar;
- if c='/' then
- skipdelphicomment;
- next_char_loaded:=true;
- end
- else
- found:=0;
- end;
- else
- found:=0;
- end;
- if next_char_loaded then
- next_char_loaded:=false
- else
- readchar;
- until (found=2);
- end;
- {****************************************************************************
- Comment Handling
- ****************************************************************************}
- procedure tscannerfile.skipcomment(read_first_char:boolean);
- begin
- current_commentstyle:=comment_tp;
- if read_first_char then
- readchar;
- inc_comment_level;
- { handle compiler switches }
- if (c='$') then
- handledirectives;
- { handle_switches can dec comment_level, }
- while (comment_level>0) do
- begin
- case c of
- '{' :
- inc_comment_level;
- '}' :
- dec_comment_level;
- '*' :
- { in iso mode, comments opened by a curly bracket can be closed by asterisk, round bracket }
- if m_iso in current_settings.modeswitches then
- begin
- readchar;
- if c=')' then
- dec_comment_level
- else
- continue;
- end;
- #10,#13 :
- linebreak;
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- end;
- readchar;
- end;
- current_commentstyle:=comment_none;
- end;
- procedure tscannerfile.skipdelphicomment;
- begin
- current_commentstyle:=comment_delphi;
- inc_comment_level;
- readchar;
- { this is not supported }
- if c='$' then
- Message(scan_w_wrong_styled_switch);
- { skip comment }
- while not (c in [#10,#13,#26]) do
- readchar;
- dec_comment_level;
- current_commentstyle:=comment_none;
- end;
- procedure tscannerfile.skipoldtpcomment(read_first_char:boolean);
- var
- found : longint;
- begin
- current_commentstyle:=comment_oldtp;
- inc_comment_level;
- { only load a char if last already processed,
- was cause of bug1634 PM }
- if read_first_char then
- readchar;
- { this is now supported }
- if (c='$') then
- handledirectives;
- { skip comment }
- while (comment_level>0) do
- begin
- found:=0;
- repeat
- case c of
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- #10,#13 :
- begin
- if found=4 then
- inc_comment_level;
- linebreak;
- found:=0;
- end;
- '*' :
- begin
- if found=3 then
- found:=4
- else
- begin
- if found=4 then
- inc_comment_level;
- found:=1;
- end;
- end;
- ')' :
- begin
- if found in [1,4] then
- begin
- dec_comment_level;
- if comment_level=0 then
- found:=2
- else
- found:=0;
- end
- else
- found:=0;
- end;
- '}' :
- { in iso mode, comments opened by asterisk, round bracket can be closed by a curly bracket }
- if m_iso in current_settings.modeswitches then
- begin
- dec_comment_level;
- if comment_level=0 then
- found:=2
- else
- found:=0;
- end;
- '(' :
- begin
- if found=4 then
- inc_comment_level;
- found:=3;
- end;
- else
- begin
- if found=4 then
- inc_comment_level;
- found:=0;
- end;
- end;
- readchar;
- until (found=2);
- end;
- current_commentstyle:=comment_none;
- end;
- {****************************************************************************
- Token Scanner
- ****************************************************************************}
- procedure tscannerfile.readtoken(allowrecordtoken:boolean);
- var
- code : integer;
- d : cardinal;
- len,
- low,high,mid : longint;
- w : word;
- m : longint;
- mac : tmacro;
- asciinr : string[33];
- iswidestring : boolean;
- label
- exit_label;
- begin
- flushpendingswitchesstate;
- { record tokens? }
- if allowrecordtoken and
- assigned(recordtokenbuf) then
- recordtoken;
- { replay tokens? }
- if assigned(replaytokenbuf) then
- begin
- replaytoken;
- goto exit_label;
- end;
- { was there already a token read, then return that token }
- if nexttoken<>NOTOKEN then
- begin
- setnexttoken;
- goto exit_label;
- end;
- { Skip all spaces and comments }
- repeat
- case c of
- '{' :
- skipcomment(true);
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- break;
- end;
- ' ',#9..#13 :
- begin
- {$ifdef PREPROCWRITE}
- if parapreprocess then
- begin
- if c=#10 then
- preprocfile.eolfound:=true
- else
- preprocfile.spacefound:=true;
- end;
- {$endif PREPROCWRITE}
- skipspace;
- end
- else
- break;
- end;
- until false;
- { Save current token position, for EOF its already loaded }
- if c<>#26 then
- gettokenpos;
- { Check first for a identifier/keyword, this is 20+% faster (PFV) }
- if c in ['A'..'Z','a'..'z','_'] then
- begin
- readstring;
- token:=_ID;
- idtoken:=_ID;
- { keyword or any other known token,
- pattern is always uppercased }
- if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
- begin
- low:=ord(tokenidx^[length(pattern),pattern[1]].first);
- high:=ord(tokenidx^[length(pattern),pattern[1]].last);
- while low<high do
- begin
- mid:=(high+low+1) shr 1;
- if pattern<tokeninfo^[ttoken(mid)].str then
- high:=mid-1
- else
- low:=mid;
- end;
- with tokeninfo^[ttoken(high)] do
- if pattern=str then
- begin
- if (keyword*current_settings.modeswitches)<>[] then
- if op=NOTOKEN then
- token:=ttoken(high)
- else
- token:=op;
- idtoken:=ttoken(high);
- end;
- end;
- { Only process identifiers and not keywords }
- if token=_ID then
- begin
- { this takes some time ... }
- if (cs_support_macro in current_settings.moduleswitches) then
- begin
- mac:=tmacro(search_macro(pattern));
- if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then
- begin
- if (yylexcount<max_macro_nesting) and (macro_nesting_depth<max_macro_nesting) then
- begin
- mac.is_used:=true;
- inc(yylexcount);
- substitutemacro(pattern,mac.buftext,mac.buflen,
- mac.fileinfo.line,mac.fileinfo.fileindex);
- { handle empty macros }
- if c=#0 then
- begin
- reload;
- { avoid macro nesting error in case of
- a sequence of empty macros, see #38802 }
- dec(yylexcount);
- readtoken(false);
- end
- else
- begin
- readtoken(false);
- { that's all folks }
- dec(yylexcount);
- end;
- exit;
- end
- else
- Message(scan_w_macro_too_deep);
- end;
- end;
- end;
- { return token }
- goto exit_label;
- end
- else
- begin
- idtoken:=_NOID;
- case c of
- '$' :
- begin
- readnumber;
- token:=_INTCONST;
- goto exit_label;
- end;
- '%' :
- begin
- if not(m_fpc in current_settings.modeswitches) then
- Illegal_Char(c)
- else
- begin
- readnumber;
- token:=_INTCONST;
- goto exit_label;
- end;
- end;
- '&' :
- begin
- if [m_fpc,m_delphi] * current_settings.modeswitches <> [] then
- begin
- readnumber;
- if length(pattern)=1 then
- begin
- { does really an identifier follow? }
- if not (c in ['_','A'..'Z','a'..'z']) then
- message2(scan_f_syn_expected,tokeninfo^[_ID].str,c);
- readstring;
- token:=_ID;
- idtoken:=_ID;
- end
- else
- token:=_INTCONST;
- goto exit_label;
- end
- else if m_mac in current_settings.modeswitches then
- begin
- readchar;
- token:=_AMPERSAND;
- goto exit_label;
- end
- else
- Illegal_Char(c);
- end;
- '0'..'9' :
- begin
- readnumber;
- if (c in ['.','e','E']) then
- begin
- { first check for a . }
- if c='.' then
- begin
- cachenexttokenpos;
- readchar;
- { is it a .. from a range? }
- case c of
- '.' :
- begin
- readchar;
- token:=_INTCONST;
- nexttoken:=_POINTPOINT;
- goto exit_label;
- end;
- ')' :
- begin
- readchar;
- token:=_INTCONST;
- nexttoken:=_RECKKLAMMER;
- goto exit_label;
- end;
- '0'..'9' :
- begin
- { insert the number after the . }
- pattern:=pattern+'.';
- while c in ['0'..'9'] do
- begin
- pattern:=pattern+c;
- readchar;
- end;
- end;
- else
- begin
- token:=_INTCONST;
- nexttoken:=_POINT;
- goto exit_label;
- end;
- end;
- end;
- { E can also follow after a point is scanned }
- if c in ['e','E'] then
- begin
- pattern:=pattern+'E';
- readchar;
- if c in ['-','+'] then
- begin
- pattern:=pattern+c;
- readchar;
- end;
- if not(c in ['0'..'9']) then
- Illegal_Char(c);
- while c in ['0'..'9'] do
- begin
- pattern:=pattern+c;
- readchar;
- end;
- end;
- token:=_REALNUMBER;
- goto exit_label;
- end;
- token:=_INTCONST;
- goto exit_label;
- end;
- ';' :
- begin
- readchar;
- token:=_SEMICOLON;
- goto exit_label;
- end;
- '[' :
- begin
- readchar;
- token:=_LECKKLAMMER;
- goto exit_label;
- end;
- ']' :
- begin
- readchar;
- token:=_RECKKLAMMER;
- goto exit_label;
- end;
- '(' :
- begin
- readchar;
- case c of
- '*' :
- begin
- skipoldtpcomment(true);
- readtoken(false);
- exit;
- end;
- '.' :
- begin
- readchar;
- token:=_LECKKLAMMER;
- goto exit_label;
- end;
- end;
- token:=_LKLAMMER;
- goto exit_label;
- end;
- ')' :
- begin
- readchar;
- token:=_RKLAMMER;
- goto exit_label;
- end;
- '+' :
- begin
- readchar;
- if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_PLUSASN;
- goto exit_label;
- end;
- token:=_PLUS;
- goto exit_label;
- end;
- '-' :
- begin
- readchar;
- if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_MINUSASN;
- goto exit_label;
- end;
- token:=_MINUS;
- goto exit_label;
- end;
- ':' :
- begin
- readchar;
- if c='=' then
- begin
- readchar;
- token:=_ASSIGNMENT;
- goto exit_label;
- end;
- token:=_COLON;
- goto exit_label;
- end;
- '*' :
- begin
- readchar;
- if (c='=') and (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_STARASN;
- end
- else
- if c='*' then
- begin
- readchar;
- token:=_STARSTAR;
- end
- else
- token:=_STAR;
- goto exit_label;
- end;
- '/' :
- begin
- readchar;
- case c of
- '=' :
- begin
- if (cs_support_c_operators in current_settings.moduleswitches) then
- begin
- readchar;
- token:=_SLASHASN;
- goto exit_label;
- end;
- end;
- '/' :
- begin
- skipdelphicomment;
- readtoken(false);
- exit;
- end;
- end;
- token:=_SLASH;
- goto exit_label;
- end;
- '|' :
- if m_mac in current_settings.modeswitches then
- begin
- readchar;
- token:=_PIPE;
- goto exit_label;
- end
- else
- Illegal_Char(c);
- '=' :
- begin
- readchar;
- token:=_EQ;
- goto exit_label;
- end;
- '.' :
- begin
- readchar;
- case c of
- '.' :
- begin
- readchar;
- case c of
- '.' :
- begin
- readchar;
- token:=_POINTPOINTPOINT;
- goto exit_label;
- end;
- else
- begin
- token:=_POINTPOINT;
- goto exit_label;
- end;
- end;
- end;
- ')' :
- begin
- readchar;
- token:=_RECKKLAMMER;
- goto exit_label;
- end;
- end;
- token:=_POINT;
- goto exit_label;
- end;
- '@' :
- begin
- readchar;
- token:=_KLAMMERAFFE;
- goto exit_label;
- end;
- ',' :
- begin
- readchar;
- token:=_COMMA;
- goto exit_label;
- end;
- '''','#','^' :
- begin
- len:=0;
- cstringpattern:='';
- iswidestring:=false;
- if c='^' then
- begin
- readchar;
- c:=upcase(c);
- if (block_type in [bt_type,bt_const_type,bt_var_type]) or
- (lasttoken=_ID) or (lasttoken=_NIL) or (lasttoken=_OPERATOR) or
- (lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
- begin
- token:=_CARET;
- goto exit_label;
- end
- else
- begin
- inc(len);
- setlength(cstringpattern,256);
- if c<#64 then
- cstringpattern[len]:=chr(ord(c)+64)
- else
- cstringpattern[len]:=chr(ord(c)-64);
- readchar;
- end;
- end;
- repeat
- case c of
- '#' :
- begin
- readchar; { read # }
- case c of
- '$':
- begin
- readchar; { read leading $ }
- asciinr:='$';
- while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<=7) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- '&':
- begin
- readchar; { read leading $ }
- asciinr:='&';
- while (upcase(c) in ['0'..'7']) and (length(asciinr)<=8) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- '%':
- begin
- readchar; { read leading $ }
- asciinr:='%';
- while (upcase(c) in ['0','1']) and (length(asciinr)<=22) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- else
- begin
- asciinr:='';
- while (c in ['0'..'9']) and (length(asciinr)<=8) do
- begin
- asciinr:=asciinr+c;
- readchar;
- end;
- end;
- end;
- val(asciinr,m,code);
- if (asciinr='') or (code<>0) then
- Message(scan_e_illegal_char_const)
- else if (m<0) or (m>255) or (length(asciinr)>3) then
- begin
- if (m>=0) and (m<=$10FFFF) then
- begin
- if not iswidestring then
- begin
- if len>0 then
- ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
- else
- ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
- iswidestring:=true;
- len:=0;
- end;
- if m<=$FFFF then
- concatwidestringchar(patternw,tcompilerwidechar(m))
- else
- begin
- { split into surrogate pair }
- dec(m,$10000);
- concatwidestringchar(patternw,tcompilerwidechar((m shr 10) + $D800));
- concatwidestringchar(patternw,tcompilerwidechar((m and $3FF) + $DC00));
- end;
- end
- else
- Message(scan_e_illegal_char_const)
- end
- else if iswidestring then
- concatwidestringchar(patternw,asciichar2unicode(char(m)))
- else
- begin
- if len>=length(cstringpattern) then
- setlength(cstringpattern,length(cstringpattern)+256);
- inc(len);
- cstringpattern[len]:=chr(m);
- end;
- end;
- '''' :
- begin
- repeat
- readchar;
- case c of
- #26 :
- end_of_file;
- #10,#13 :
- Message(scan_f_string_exceeds_line);
- '''' :
- begin
- readchar;
- if c<>'''' then
- break;
- end;
- end;
- { interpret as utf-8 string? }
- if (ord(c)>=$80) and (current_settings.sourcecodepage=CP_UTF8) then
- begin
- { convert existing string to an utf-8 string }
- if not iswidestring then
- begin
- if len>0 then
- ascii2unicode(@cstringpattern[1],len,current_settings.sourcecodepage,patternw)
- else
- ascii2unicode(nil,len,current_settings.sourcecodepage,patternw);
- iswidestring:=true;
- len:=0;
- end;
- { four chars }
- if (ord(c) and $f0)=$f0 then
- begin
- { this always represents a surrogate pair, so
- read as 32-bit value and then split into
- the corresponding pair of two wchars }
- d:=ord(c) and $f;
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- d:=(d shl 6) or (ord(c) and $3f);
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- d:=(d shl 6) or (ord(c) and $3f);
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- d:=(d shl 6) or (ord(c) and $3f);
- if d<$10000 then
- message(scan_e_utf8_malformed);
- d:=d-$10000;
- { high surrogate }
- w:=$d800+(d shr 10);
- concatwidestringchar(patternw,w);
- { low surrogate }
- w:=$dc00+(d and $3ff);
- concatwidestringchar(patternw,w);
- end
- { three chars }
- else if (ord(c) and $e0)=$e0 then
- begin
- w:=ord(c) and $f;
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- w:=(w shl 6) or (ord(c) and $3f);
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- w:=(w shl 6) or (ord(c) and $3f);
- concatwidestringchar(patternw,w);
- end
- { two chars }
- else if (ord(c) and $c0)<>0 then
- begin
- w:=ord(c) and $1f;
- readchar;
- if (ord(c) and $c0)<>$80 then
- message(scan_e_utf8_malformed);
- w:=(w shl 6) or (ord(c) and $3f);
- concatwidestringchar(patternw,w);
- end
- { illegal }
- else if (ord(c) and $80)<>0 then
- message(scan_e_utf8_malformed)
- else
- concatwidestringchar(patternw,tcompilerwidechar(c))
- end
- else if iswidestring then
- begin
- if current_settings.sourcecodepage=CP_UTF8 then
- concatwidestringchar(patternw,ord(c))
- else
- concatwidestringchar(patternw,asciichar2unicode(c))
- end
- else
- begin
- if len>=length(cstringpattern) then
- setlength(cstringpattern,length(cstringpattern)+256);
- inc(len);
- cstringpattern[len]:=c;
- end;
- until false;
- end;
- '^' :
- begin
- readchar;
- c:=upcase(c);
- if c<#64 then
- c:=chr(ord(c)+64)
- else
- c:=chr(ord(c)-64);
- if iswidestring then
- concatwidestringchar(patternw,asciichar2unicode(c))
- else
- begin
- if len>=length(cstringpattern) then
- setlength(cstringpattern,length(cstringpattern)+256);
- inc(len);
- cstringpattern[len]:=c;
- end;
- readchar;
- end;
- else
- break;
- end;
- until false;
- { strings with length 1 become const chars }
- if iswidestring then
- begin
- if patternw^.len=1 then
- token:=_CWCHAR
- else
- token:=_CWSTRING;
- end
- else
- begin
- setlength(cstringpattern,len);
- if length(cstringpattern)=1 then
- begin
- token:=_CCHAR;
- pattern:=cstringpattern;
- end
- else
- token:=_CSTRING;
- end;
- goto exit_label;
- end;
- '>' :
- begin
- readchar;
- if (block_type in [bt_type,bt_var_type,bt_const_type]) then
- token:=_RSHARPBRACKET
- else
- begin
- case c of
- '=' :
- begin
- readchar;
- token:=_GTE;
- goto exit_label;
- end;
- '>' :
- begin
- readchar;
- token:=_OP_SHR;
- goto exit_label;
- end;
- '<' :
- begin { >< is for a symetric diff for sets }
- readchar;
- token:=_SYMDIF;
- goto exit_label;
- end;
- end;
- token:=_GT;
- end;
- goto exit_label;
- end;
- '<' :
- begin
- readchar;
- if (block_type in [bt_type,bt_var_type,bt_const_type]) then
- token:=_LSHARPBRACKET
- else
- begin
- case c of
- '>' :
- begin
- readchar;
- token:=_NE;
- goto exit_label;
- end;
- '=' :
- begin
- readchar;
- token:=_LTE;
- goto exit_label;
- end;
- '<' :
- begin
- readchar;
- token:=_OP_SHL;
- goto exit_label;
- end;
- end;
- token:=_LT;
- end;
- goto exit_label;
- end;
- #26 :
- begin
- token:=_EOF;
- checkpreprocstack;
- goto exit_label;
- end;
- else
- Illegal_Char(c);
- end;
- end;
- exit_label:
- lasttoken:=token;
- end;
- function tscannerfile.readpreproc:ttoken;
- var
- low,high,mid: longint;
- optoken: ttoken;
- begin
- skipspace;
- case c of
- '_',
- 'A'..'Z',
- 'a'..'z' :
- begin
- readstring;
- optoken:=_ID;
- if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
- begin
- low:=ord(tokenidx^[length(pattern),pattern[1]].first);
- high:=ord(tokenidx^[length(pattern),pattern[1]].last);
- while low<high do
- begin
- mid:=(high+low+1) shr 1;
- if pattern<tokeninfo^[ttoken(mid)].str then
- high:=mid-1
- else
- low:=mid;
- end;
- with tokeninfo^[ttoken(high)] do
- if pattern=str then
- begin
- if (keyword*current_settings.modeswitches)<>[] then
- if op=NOTOKEN then
- optoken:=ttoken(high)
- else
- optoken:=op;
- end;
- if not (optoken in preproc_operators) then
- optoken:=_ID;
- end;
- current_scanner.preproc_pattern:=pattern;
- readpreproc:=optoken;
- end;
- '''' :
- begin
- readquotedstring;
- current_scanner.preproc_pattern:=cstringpattern;
- readpreproc:=_CSTRING;
- end;
- '0'..'9' :
- begin
- readnumber;
- if (c in ['.','e','E']) then
- begin
- { first check for a . }
- if c='.' then
- begin
- readchar;
- if c in ['0'..'9'] then
- begin
- { insert the number after the . }
- pattern:=pattern+'.';
- while c in ['0'..'9'] do
- begin
- pattern:=pattern+c;
- readchar;
- end;
- end
- else
- Illegal_Char(c);
- end;
- { E can also follow after a point is scanned }
- if c in ['e','E'] then
- begin
- pattern:=pattern+'E';
- readchar;
- if c in ['-','+'] then
- begin
- pattern:=pattern+c;
- readchar;
- end;
- if not(c in ['0'..'9']) then
- Illegal_Char(c);
- while c in ['0'..'9'] do
- begin
- pattern:=pattern+c;
- readchar;
- end;
- end;
- readpreproc:=_REALNUMBER;
- end
- else
- readpreproc:=_INTCONST;
- current_scanner.preproc_pattern:=pattern;
- end;
- '$','%':
- begin
- readnumber;
- current_scanner.preproc_pattern:=pattern;
- readpreproc:=_INTCONST;
- end;
- '&' :
- begin
- readnumber;
- if length(pattern)=1 then
- begin
- readstring;
- readpreproc:=_ID;
- end
- else
- readpreproc:=_INTCONST;
- current_scanner.preproc_pattern:=pattern;
- end;
- '.' :
- begin
- readchar;
- readpreproc:=_POINT;
- end;
- ',' :
- begin
- readchar;
- readpreproc:=_COMMA;
- end;
- '}' :
- begin
- readpreproc:=_END;
- end;
- '(' :
- begin
- readchar;
- readpreproc:=_LKLAMMER;
- end;
- ')' :
- begin
- readchar;
- readpreproc:=_RKLAMMER;
- end;
- '[' :
- begin
- readchar;
- readpreproc:=_LECKKLAMMER;
- end;
- ']' :
- begin
- readchar;
- readpreproc:=_RECKKLAMMER;
- end;
- '+' :
- begin
- readchar;
- readpreproc:=_PLUS;
- end;
- '-' :
- begin
- readchar;
- readpreproc:=_MINUS;
- end;
- '*' :
- begin
- readchar;
- readpreproc:=_STAR;
- end;
- '/' :
- begin
- readchar;
- readpreproc:=_SLASH;
- end;
- '=' :
- begin
- readchar;
- readpreproc:=_EQ;
- end;
- '>' :
- begin
- readchar;
- if c='=' then
- begin
- readchar;
- readpreproc:=_GTE;
- end
- else
- readpreproc:=_GT;
- end;
- '<' :
- begin
- readchar;
- case c of
- '>' :
- begin
- readchar;
- readpreproc:=_NE;
- end;
- '=' :
- begin
- readchar;
- readpreproc:=_LTE;
- end;
- else
- readpreproc:=_LT;
- end;
- end;
- #26 :
- begin
- readpreproc:=_EOF;
- checkpreprocstack;
- end;
- else
- begin
- Illegal_Char(c);
- readpreproc:=NOTOKEN;
- end;
- end;
- end;
- function tscannerfile.readpreprocint(var value:int64;const place:string):boolean;
- var
- hs : texprvalue;
- begin
- hs:=preproc_comp_expr;
- if hs.isInt then
- begin
- value:=hs.asInt64;
- result:=true;
- end
- else
- begin
- hs.error('Integer',place);
- result:=false;
- end;
- hs.free;
- end;
- function tscannerfile.asmgetchar : char;
- begin
- readchar;
- repeat
- case c of
- #26 :
- begin
- reload;
- if (c=#26) and not assigned(inputfile.next) then
- end_of_file;
- continue;
- end;
- else
- begin
- asmgetchar:=c;
- exit;
- end;
- end;
- until false;
- end;
- {*****************************************************************************
- Helpers
- *****************************************************************************}
- procedure AddDirective(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- begin
- if dm in [directive_all, directive_turbo] then
- tdirectiveitem.create(turbo_scannerdirectives,s,p);
- if dm in [directive_all, directive_mac] then
- tdirectiveitem.create(mac_scannerdirectives,s,p);
- end;
- procedure AddConditional(const s:string; dm: tdirectivemode; p:tdirectiveproc);
- begin
- if dm in [directive_all, directive_turbo] then
- tdirectiveitem.createcond(turbo_scannerdirectives,s,p);
- if dm in [directive_all, directive_mac] then
- tdirectiveitem.createcond(mac_scannerdirectives,s,p);
- end;
- {*****************************************************************************
- Initialization
- *****************************************************************************}
- procedure InitScanner;
- begin
- InitWideString(patternw);
- turbo_scannerdirectives:=TFPHashObjectList.Create;
- mac_scannerdirectives:=TFPHashObjectList.Create;
- { Common directives and conditionals }
- AddDirective('I',directive_all, @dir_include);
- AddDirective('DEFINE',directive_all, @dir_define);
- AddDirective('UNDEF',directive_all, @dir_undef);
- AddConditional('IF',directive_all, @dir_if);
- AddConditional('IFDEF',directive_all, @dir_ifdef);
- AddConditional('IFNDEF',directive_all, @dir_ifndef);
- AddConditional('ELSE',directive_all, @dir_else);
- AddConditional('ELSEIF',directive_all, @dir_elseif);
- AddConditional('ENDIF',directive_all, @dir_endif);
- { Directives and conditionals for all modes except mode macpas}
- AddDirective('INCLUDE',directive_turbo, @dir_include);
- AddDirective('LIBPREFIX',directive_turbo, @dir_libprefix);
- AddDirective('LIBSUFFIX',directive_turbo, @dir_libsuffix);
- AddDirective('EXTENSION',directive_turbo, @dir_extension);
- AddConditional('IFEND',directive_turbo, @dir_endif);
- AddConditional('IFOPT',directive_turbo, @dir_ifopt);
- { Directives and conditionals for mode macpas: }
- AddDirective('SETC',directive_mac, @dir_setc);
- AddDirective('DEFINEC',directive_mac, @dir_definec);
- AddDirective('UNDEFC',directive_mac, @dir_undef);
- AddConditional('IFC',directive_mac, @dir_if);
- AddConditional('ELSEC',directive_mac, @dir_else);
- AddConditional('ELIFC',directive_mac, @dir_elseif);
- AddConditional('ENDC',directive_mac, @dir_endif);
- end;
- procedure DoneScanner;
- begin
- turbo_scannerdirectives.Free;
- mac_scannerdirectives.Free;
- DoneWideString(patternw);
- end;
- end.
|