scanner.pas 141 KB

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