scanner.pas 124 KB

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