scanner.pas 125 KB

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