scanner.pas 138 KB

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