scanner.pas 121 KB

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