scanner.pas 125 KB

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