scanner.pas 193 KB

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