scanner.pas 147 KB

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