scanner.pas 124 KB

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