scanner.pas 138 KB

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