scanner.pas 184 KB

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