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