scanner.pas 184 KB

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