scanner.pas 138 KB

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