scanner.pas 114 KB

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