scanner.pas 146 KB

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