scanner.pas 162 KB

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