pscanner.pp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860
  1. {
  2. This file is part of the Free Component Library
  3. Pascal source lexical scanner
  4. Copyright (c) 2003 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  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.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$h+}
  14. unit PScanner;
  15. interface
  16. uses SysUtils, Classes;
  17. resourcestring
  18. SErrInvalidCharacter = 'Invalid character ''%s''';
  19. SErrOpenString = 'string exceeds end of line';
  20. SErrIncludeFileNotFound = 'Could not find include file ''%s''';
  21. SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
  22. SErrInvalidPPElse = '$ELSE without matching $IFxxx';
  23. SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
  24. SLogOpeningFile = 'Opening source file "%s".';
  25. SLogLineNumber = 'Reading line %d.';
  26. SLogIFDefAccepted = 'IFDEF %s found, accepting.';
  27. SLogIFDefRejected = 'IFDEF %s found, rejecting.';
  28. SLogIFNDefAccepted = 'IFNDEF %s found, accepting.';
  29. SLogIFNDefRejected = 'IFNDEF %s found, rejecting.';
  30. SLogIFOPTIgnored = 'IFOPT %s found, ignoring (rejected).';
  31. SLogIFIgnored = 'IF %s found, ignoring (rejected).';
  32. type
  33. TToken = (
  34. tkEOF,
  35. tkWhitespace,
  36. tkComment,
  37. tkIdentifier,
  38. tkString,
  39. tkNumber,
  40. tkChar,
  41. // Simple (one-character) tokens
  42. tkBraceOpen, // '('
  43. tkBraceClose, // ')'
  44. tkMul, // '*'
  45. tkPlus, // '+'
  46. tkComma, // ','
  47. tkMinus, // '-'
  48. tkDot, // '.'
  49. tkDivision, // '/'
  50. tkColon, // ':'
  51. tkSemicolon, // ';'
  52. tkLessThan, // '<'
  53. tkEqual, // '='
  54. tkGreaterThan, // '>'
  55. tkAt, // '@'
  56. tkSquaredBraceOpen, // '['
  57. tkSquaredBraceClose, // ']'
  58. tkCaret, // '^'
  59. tkBackslash, // '\'
  60. // Two-character tokens
  61. tkDotDot, // '..'
  62. tkAssign, // ':='
  63. tkNotEqual, // '<>'
  64. tkLessEqualThan, // '<='
  65. tkGreaterEqualThan, // '>='
  66. tkPower, // '**'
  67. tkSymmetricalDifference, // '><'
  68. tkAssignPlus, // +=
  69. tkAssignMinus, // -=
  70. tkAssignMul, // *=
  71. tkAssignDivision, // /=
  72. // Reserved words
  73. tkabsolute,
  74. tkand,
  75. tkarray,
  76. tkas,
  77. tkasm,
  78. tkbegin,
  79. tkbitpacked,
  80. tkcase,
  81. tkclass,
  82. tkconst,
  83. tkconstref,
  84. tkconstructor,
  85. tkdestructor,
  86. tkdiv,
  87. tkdo,
  88. tkdownto,
  89. tkelse,
  90. tkend,
  91. tkexcept,
  92. tkexports,
  93. tkfalse,
  94. tkfile,
  95. tkfinalization,
  96. tkfinally,
  97. tkfor,
  98. tkfunction,
  99. tkgeneric,
  100. tkgoto,
  101. tkHelper,
  102. tkif,
  103. tkimplementation,
  104. tkin,
  105. tkinherited,
  106. tkinitialization,
  107. tkinline,
  108. tkinterface,
  109. tkis,
  110. tklabel,
  111. tklibrary,
  112. tkmod,
  113. tknil,
  114. tknot,
  115. tkobject,
  116. tkof,
  117. tkon,
  118. tkoperator,
  119. tkor,
  120. tkpacked,
  121. tkprocedure,
  122. tkprogram,
  123. tkproperty,
  124. tkraise,
  125. tkrecord,
  126. tkrepeat,
  127. tkResourceString,
  128. tkself,
  129. tkset,
  130. tkshl,
  131. tkshr,
  132. tkspecialize,
  133. // tkstring,
  134. tkthen,
  135. tkthreadvar,
  136. tkto,
  137. tktrue,
  138. tktry,
  139. tktype,
  140. tkunit,
  141. tkuntil,
  142. tkuses,
  143. tkvar,
  144. tkwhile,
  145. tkwith,
  146. tkxor,
  147. tkLineEnding,
  148. tkTab
  149. );
  150. TTokens = set of TToken;
  151. { TMacroDef }
  152. TMacroDef = Class(TObject)
  153. Private
  154. FName: String;
  155. FValue: String;
  156. Public
  157. Constructor Create(Const AName,AValue : String);
  158. Property Name : String Read FName;
  159. Property Value : String Read FValue Write FValue;
  160. end;
  161. { TLineReader }
  162. TLineReader = class
  163. Private
  164. FFilename: string;
  165. public
  166. constructor Create(const AFilename: string); virtual;
  167. function IsEOF: Boolean; virtual; abstract;
  168. function ReadLine: string; virtual; abstract;
  169. property Filename: string read FFilename;
  170. end;
  171. { TFileLineReader }
  172. TFileLineReader = class(TLineReader)
  173. private
  174. FTextFile: Text;
  175. FileOpened: Boolean;
  176. FBuffer : Array[0..4096-1] of byte;
  177. public
  178. constructor Create(const AFilename: string); override;
  179. destructor Destroy; override;
  180. function IsEOF: Boolean; override;
  181. function ReadLine: string; override;
  182. end;
  183. { TStreamLineReader }
  184. TStreamLineReader = class(TLineReader)
  185. private
  186. FContent: AnsiString;
  187. FPos : Integer;
  188. public
  189. Procedure InitFromStream(AStream : TStream);
  190. function IsEOF: Boolean; override;
  191. function ReadLine: string; override;
  192. end;
  193. { TFileStreamLineReader }
  194. TFileStreamLineReader = class(TStreamLineReader)
  195. Public
  196. constructor Create(const AFilename: string); override;
  197. end;
  198. { TStringStreamLineReader }
  199. TStringStreamLineReader = class(TStreamLineReader)
  200. Public
  201. constructor Create( const AFilename: string; Const ASource: String);
  202. end;
  203. { TMacroReader }
  204. TMacroReader = Class(TStringStreamLineReader)
  205. private
  206. FCurCol: Integer;
  207. FCurRow: Integer;
  208. Public
  209. Property CurCol : Integer Read FCurCol Write FCurCol;
  210. Property CurRow : Integer Read FCurRow Write FCurRow;
  211. end;
  212. { TBaseFileResolver }
  213. TBaseFileResolver = class
  214. private
  215. FBaseDirectory: string;
  216. FIncludePaths: TStringList;
  217. FStrictFileCase : Boolean;
  218. Protected
  219. procedure SetBaseDirectory(AValue: string); virtual;
  220. procedure SetStrictFileCase(AValue: Boolean); virtual;
  221. Function FindIncludeFileName(const AName: string): String;
  222. Property IncludePaths: TStringList Read FIncludePaths;
  223. public
  224. constructor Create; virtual;
  225. destructor Destroy; override;
  226. procedure AddIncludePath(const APath: string); virtual;
  227. function FindSourceFile(const AName: string): TLineReader; virtual; abstract;
  228. function FindIncludeFile(const AName: string): TLineReader; virtual; abstract;
  229. Property StrictFileCase : Boolean Read FStrictFileCase Write SetStrictFileCase;
  230. property BaseDirectory: string read FBaseDirectory write SetBaseDirectory;
  231. end;
  232. { TFileResolver }
  233. TFileResolver = class(TBaseFileResolver)
  234. private
  235. FUseStreams: Boolean;
  236. Protected
  237. Function CreateFileReader(Const AFileName : String) : TLineReader; virtual;
  238. Public
  239. function FindSourceFile(const AName: string): TLineReader; override;
  240. function FindIncludeFile(const AName: string): TLineReader; override;
  241. Property UseStreams : Boolean Read FUseStreams Write FUseStreams;
  242. end;
  243. { TStreamResolver }
  244. TStreamResolver = class(TBaseFileResolver)
  245. Private
  246. FOwnsStreams: Boolean;
  247. FStreams : TStringList;
  248. function FindStream(const AName: string; ScanIncludes: Boolean): TStream;
  249. function FindStreamReader(const AName: string; ScanIncludes: Boolean): TLineReader;
  250. procedure SetOwnsStreams(AValue: Boolean);
  251. Public
  252. constructor Create; override;
  253. destructor Destroy; override;
  254. Procedure Clear;
  255. Procedure AddStream(Const AName : String; AStream : TStream);
  256. function FindSourceFile(const AName: string): TLineReader; override;
  257. function FindIncludeFile(const AName: string): TLineReader; override;
  258. Property OwnsStreams : Boolean Read FOwnsStreams write SetOwnsStreams;
  259. end;
  260. EScannerError = class(Exception);
  261. EFileNotFoundError = class(Exception);
  262. TPascalScannerPPSkipMode = (ppSkipNone, ppSkipIfBranch, ppSkipElseBranch, ppSkipAll);
  263. TPOption = (po_delphi,po_cassignments);
  264. TPOptions = set of TPOption;
  265. { TPascalScanner }
  266. TPScannerLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
  267. TPScannerLogEvent = (sleFile,sleLineNumber,sleConditionals);
  268. TPScannerLogEvents = Set of TPScannerLogEvent;
  269. TPascalScanner = class
  270. private
  271. FFileResolver: TBaseFileResolver;
  272. FCurSourceFile: TLineReader;
  273. FCurFilename: string;
  274. FCurRow: Integer;
  275. FCurToken: TToken;
  276. FCurTokenString: string;
  277. FCurLine: string;
  278. FMacros,
  279. FDefines: TStrings;
  280. FOptions: TPOptions;
  281. FLogEvents: TPScannerLogEvents;
  282. FOnLog: TPScannerLogHandler;
  283. FSkipComments: Boolean;
  284. FSkipWhiteSpace: Boolean;
  285. TokenStr: PChar;
  286. FIncludeStack: TFPList;
  287. // Preprocessor $IFxxx skipping data
  288. PPSkipMode: TPascalScannerPPSkipMode;
  289. PPIsSkipping: Boolean;
  290. PPSkipStackIndex: Integer;
  291. PPSkipModeStack: array[0..255] of TPascalScannerPPSkipMode;
  292. PPIsSkippingStack: array[0..255] of Boolean;
  293. function GetCurColumn: Integer;
  294. procedure SetOptions(AValue: TPOptions);
  295. protected
  296. Procedure DoLog(Const Msg : String; SkipSourceInfo : Boolean = False);overload;
  297. Procedure DoLog(Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
  298. procedure Error(const Msg: string);overload;
  299. procedure Error(const Msg: string; Args: array of Const);overload;
  300. procedure HandleDefine(Param: String); virtual;
  301. procedure HandleIncludeFile(Param: String); virtual;
  302. procedure HandleUnDefine(Param: String);virtual;
  303. function HandleMacro(AIndex: integer): TToken;virtual;
  304. procedure PushStackItem; virtual;
  305. function DoFetchTextToken: TToken;
  306. function DoFetchToken: TToken;
  307. procedure ClearFiles;
  308. Procedure ClearMacros;
  309. Procedure SetCurTokenString(AValue : string);
  310. function LogEvent(E : TPScannerLogEvent) : Boolean; inline;
  311. public
  312. constructor Create(AFileResolver: TBaseFileResolver);
  313. destructor Destroy; override;
  314. procedure OpenFile(const AFilename: string);
  315. function FetchToken: TToken;
  316. Procedure AddDefine(S : String);
  317. Procedure RemoveDefine(S : String);
  318. property FileResolver: TBaseFileResolver read FFileResolver;
  319. property CurSourceFile: TLineReader read FCurSourceFile;
  320. property CurFilename: string read FCurFilename;
  321. Property SkipWhiteSpace : Boolean Read FSkipWhiteSpace Write FSkipWhiteSpace;
  322. Property SkipComments : Boolean Read FSkipComments Write FSkipComments;
  323. property CurLine: string read FCurLine;
  324. property CurRow: Integer read FCurRow;
  325. property CurColumn: Integer read GetCurColumn;
  326. property CurToken: TToken read FCurToken;
  327. property CurTokenString: string read FCurTokenString;
  328. property Defines: TStrings read FDefines;
  329. property Macros: TStrings read FMacros;
  330. Property Options : TPOptions Read FOptions Write SetOptions;
  331. Property LogEvents : TPScannerLogEvents Read FLogEvents Write FLogEvents;
  332. Property OnLog : TPScannerLogHandler Read FOnLog Write FOnLog;
  333. end;
  334. const
  335. TokenInfos: array[TToken] of string = (
  336. 'EOF',
  337. 'Whitespace',
  338. 'Comment',
  339. 'Identifier',
  340. 'string',
  341. 'Number',
  342. 'Character',
  343. '(',
  344. ')',
  345. '*',
  346. '+',
  347. ',',
  348. '-',
  349. '.',
  350. '/',
  351. ':',
  352. ';',
  353. '<',
  354. '=',
  355. '>',
  356. '@',
  357. '[',
  358. ']',
  359. '^',
  360. '\',
  361. '..',
  362. ':=',
  363. '<>',
  364. '<=',
  365. '>=',
  366. '**',
  367. '><',
  368. '+=',
  369. '-=',
  370. '*=',
  371. '/=',
  372. // Reserved words
  373. 'absolute',
  374. 'and',
  375. 'array',
  376. 'as',
  377. 'asm',
  378. 'begin',
  379. 'bitpacked',
  380. 'case',
  381. 'class',
  382. 'const',
  383. 'constref',
  384. 'constructor',
  385. 'destructor',
  386. 'div',
  387. 'do',
  388. 'downto',
  389. 'else',
  390. 'end',
  391. 'except',
  392. 'exports',
  393. 'false',
  394. 'file',
  395. 'finalization',
  396. 'finally',
  397. 'for',
  398. 'function',
  399. 'generic',
  400. 'goto',
  401. 'helper',
  402. 'if',
  403. 'implementation',
  404. 'in',
  405. 'inherited',
  406. 'initialization',
  407. 'inline',
  408. 'interface',
  409. 'is',
  410. 'label',
  411. 'library',
  412. 'mod',
  413. 'nil',
  414. 'not',
  415. 'object',
  416. 'of',
  417. 'on',
  418. 'operator',
  419. 'or',
  420. 'packed',
  421. 'procedure',
  422. 'program',
  423. 'property',
  424. 'raise',
  425. 'record',
  426. 'repeat',
  427. 'resourcestring',
  428. 'self',
  429. 'set',
  430. 'shl',
  431. 'shr',
  432. 'specialize',
  433. // 'string',
  434. 'then',
  435. 'threadvar',
  436. 'to',
  437. 'true',
  438. 'try',
  439. 'type',
  440. 'unit',
  441. 'until',
  442. 'uses',
  443. 'var',
  444. 'while',
  445. 'with',
  446. 'xor',
  447. 'LineEnding',
  448. 'Tab'
  449. );
  450. function FilenameIsAbsolute(const TheFilename: string):boolean;
  451. function FilenameIsWinAbsolute(const TheFilename: string): boolean;
  452. function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
  453. function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
  454. implementation
  455. Var
  456. SortedTokens : array of TToken;
  457. LowerCaseTokens : Array[ttoken] of String;
  458. Procedure SortTokenInfo;
  459. Var
  460. tk: tToken;
  461. I,J,K, l: integer;
  462. begin
  463. for tk:=Low(TToken) to High(ttoken) do
  464. LowerCaseTokens[tk]:=LowerCase(TokenInfos[tk]);
  465. SetLength(SortedTokens,Ord(tkXor)-Ord(tkAbsolute)+1);
  466. I:=0;
  467. for tk := tkAbsolute to tkXOR do
  468. begin
  469. SortedTokens[i]:=tk;
  470. Inc(i);
  471. end;
  472. l:=Length(SortedTokens)-1;
  473. k:=l shr 1;
  474. while (k>0) do
  475. begin
  476. for i:=0 to l-k do
  477. begin
  478. j:=i;
  479. while (J>=0) and (LowerCaseTokens[SortedTokens[J]]>LowerCaseTokens[SortedTokens[J+K]]) do
  480. begin
  481. tk:=SortedTokens[J];
  482. SortedTokens[J]:=SortedTokens[J+K];
  483. SortedTokens[J+K]:=tk;
  484. if (J>K) then
  485. Dec(J,K)
  486. else
  487. J := 0
  488. end;
  489. end;
  490. K:=K shr 1;
  491. end;
  492. end;
  493. function IndexOfToken(Const AToken : string) : Integer;
  494. var
  495. B,T,M : Integer;
  496. N : String;
  497. begin
  498. B:=0;
  499. T:=Length(SortedTokens)-1;
  500. while (B<=T) do
  501. begin
  502. M:=(B+T) div 2;
  503. N:=LowerCaseTokens[SortedTokens[M]];
  504. if (AToken<N) then
  505. T:=M-1
  506. else if (AToken=N) then
  507. Exit(M)
  508. else
  509. B:=M+1;
  510. end;
  511. Result:=-1;
  512. end;
  513. function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
  514. Var
  515. I : Integer;
  516. begin
  517. if (Length(SortedTokens)=0) then
  518. SortTokenInfo;
  519. I:=IndexOfToken(LowerCase(AToken));
  520. Result:=I<>-1;
  521. If Result then
  522. T:=SortedTokens[I];
  523. end;
  524. type
  525. TIncludeStackItem = class
  526. SourceFile: TLineReader;
  527. Filename: string;
  528. Token: TToken;
  529. TokenString: string;
  530. Line: string;
  531. Row: Integer;
  532. TokenStr: PChar;
  533. end;
  534. function FilenameIsAbsolute(const TheFilename: string):boolean;
  535. begin
  536. {$IFDEF WINDOWS}
  537. // windows
  538. Result:=FilenameIsWinAbsolute(TheFilename);
  539. {$ELSE}
  540. // unix
  541. Result:=FilenameIsUnixAbsolute(TheFilename);
  542. {$ENDIF}
  543. end;
  544. function FilenameIsWinAbsolute(const TheFilename: string): boolean;
  545. begin
  546. Result:=((length(TheFilename)>=2) and (TheFilename[1] in ['A'..'Z','a'..'z'])
  547. and (TheFilename[2]=':'))
  548. or ((length(TheFilename)>=2)
  549. and (TheFilename[1]='\') and (TheFilename[2]='\'));
  550. end;
  551. function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
  552. begin
  553. Result:=(TheFilename<>'') and (TheFilename[1]='/');
  554. end;
  555. { TMacroDef }
  556. constructor TMacroDef.Create(const AName, AValue: String);
  557. begin
  558. FName:=AName;
  559. FValue:=AValue;
  560. end;
  561. { TStreamResolver }
  562. procedure TStreamResolver.SetOwnsStreams(AValue: Boolean);
  563. begin
  564. if FOwnsStreams=AValue then Exit;
  565. FOwnsStreams:=AValue;
  566. end;
  567. constructor TStreamResolver.Create;
  568. begin
  569. Inherited;
  570. FStreams:=TStringList.Create;
  571. FStreams.Sorted:=True;
  572. FStreams.Duplicates:=dupError;
  573. end;
  574. destructor TStreamResolver.Destroy;
  575. begin
  576. Clear;
  577. FreeAndNil(FStreams);
  578. inherited Destroy;
  579. end;
  580. procedure TStreamResolver.Clear;
  581. Var
  582. I : integer;
  583. begin
  584. if OwnsStreams then
  585. begin
  586. For I:=0 to FStreams.Count-1 do
  587. Fstreams.Objects[i].Free;
  588. end;
  589. FStreams.Clear;
  590. end;
  591. procedure TStreamResolver.AddStream(const AName: String; AStream: TStream);
  592. begin
  593. FStreams.AddObject(AName,AStream);
  594. end;
  595. function TStreamResolver.FindStream(const AName: string; ScanIncludes : Boolean) : TStream;
  596. Var
  597. I,J : Integer;
  598. FN : String;
  599. begin
  600. Result:=Nil;
  601. I:=FStreams.IndexOf(AName);
  602. If (I=-1) and ScanIncludes then
  603. begin
  604. J:=0;
  605. While (I=-1) and (J<IncludePaths.Count-1) do
  606. begin
  607. FN:=IncludeTrailingPathDelimiter(IncludePaths[i])+AName;
  608. I:=FStreams.INdexOf(FN);
  609. Inc(J);
  610. end;
  611. end;
  612. If (I<>-1) then
  613. Result:=FStreams.Objects[i] as TStream;
  614. end;
  615. function TStreamResolver.FindStreamReader(const AName: string; ScanIncludes : Boolean) : TLineReader;
  616. Var
  617. S : TStream;
  618. SL : TStreamLineReader;
  619. begin
  620. Result:=Nil;
  621. S:=FindStream(AName,ScanIncludes);
  622. If (S<>Nil) then
  623. begin
  624. SL:=TStreamLineReader.Create(AName);
  625. try
  626. SL.InitFromStream(S);
  627. Result:=SL;
  628. except
  629. FreeAndNil(SL);
  630. Raise;
  631. end;
  632. end;
  633. end;
  634. function TStreamResolver.FindSourceFile(const AName: string): TLineReader;
  635. begin
  636. Result:=FindStreamReader(AName,False);
  637. end;
  638. function TStreamResolver.FindIncludeFile(const AName: string): TLineReader;
  639. begin
  640. Result:=FindStreamReader(AName,True);
  641. end;
  642. { TStringStreamLineReader }
  643. constructor TStringStreamLineReader.Create(const AFilename: string; const ASource: String);
  644. Var
  645. S : TStringStream;
  646. begin
  647. inherited Create(AFilename);
  648. S:=TStringStream.Create(ASource);
  649. try
  650. InitFromStream(S);
  651. finally
  652. S.Free;
  653. end;
  654. end;
  655. { TFileStreamLineReader }
  656. constructor TFileStreamLineReader.Create(const AFilename: string);
  657. Var
  658. S : TFileStream;
  659. begin
  660. inherited Create(AFilename);
  661. S:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
  662. try
  663. InitFromStream(S);
  664. finally
  665. S.Free;
  666. end;
  667. end;
  668. { TStreamLineReader }
  669. Procedure TStreamLineReader.InitFromStream(AStream : TStream);
  670. begin
  671. SetLength(FContent,AStream.Size);
  672. AStream.Read(FContent[1],AStream.Size);
  673. FPos:=0;
  674. end;
  675. function TStreamLineReader.IsEOF: Boolean;
  676. begin
  677. Result:=FPos>=Length(FContent);
  678. end;
  679. function TStreamLineReader.ReadLine: string;
  680. Var
  681. LPos : Integer;
  682. EOL : Boolean;
  683. begin
  684. If isEOF then
  685. exit;
  686. LPos:=FPos+1;
  687. Repeat
  688. Inc(FPos);
  689. EOL:=(FContent[FPos] in [#10,#13]);
  690. until isEOF or EOL;
  691. If EOL then
  692. Result:=Copy(FContent,LPos,FPos-LPos)
  693. else
  694. Result:=Copy(FContent,LPos,FPos-LPos+1);
  695. If (not isEOF) and (FContent[FPos]=#13) and (FContent[FPos+1]=#10) then
  696. inc(FPos);
  697. end;
  698. { TLineReader }
  699. constructor TLineReader.Create(const AFilename: string);
  700. begin
  701. FFileName:=AFileName;
  702. end;
  703. { ---------------------------------------------------------------------
  704. TFileLineReader
  705. ---------------------------------------------------------------------}
  706. constructor TFileLineReader.Create(const AFilename: string);
  707. begin
  708. inherited Create(AFileName);
  709. Assign(FTextFile, AFilename);
  710. Reset(FTextFile);
  711. SetTextBuf(FTextFile,FBuffer,SizeOf(FBuffer));
  712. FileOpened := true;
  713. end;
  714. destructor TFileLineReader.Destroy;
  715. begin
  716. if FileOpened then
  717. Close(FTextFile);
  718. inherited Destroy;
  719. end;
  720. function TFileLineReader.IsEOF: Boolean;
  721. begin
  722. Result := EOF(FTextFile);
  723. end;
  724. function TFileLineReader.ReadLine: string;
  725. begin
  726. ReadLn(FTextFile, Result);
  727. end;
  728. { ---------------------------------------------------------------------
  729. TBaseFileResolver
  730. ---------------------------------------------------------------------}
  731. procedure TBaseFileResolver.SetBaseDirectory(AValue: string);
  732. begin
  733. if FBaseDirectory=AValue then Exit;
  734. FBaseDirectory:=AValue;
  735. end;
  736. procedure TBaseFileResolver.SetStrictFileCase(AValue: Boolean);
  737. begin
  738. if FStrictFileCase=AValue then Exit;
  739. FStrictFileCase:=AValue;
  740. end;
  741. function TBaseFileResolver.FindIncludeFileName(const AName: string): String;
  742. function SearchLowUpCase(FN: string): string;
  743. var
  744. Dir: String;
  745. begin
  746. If FileExists(FN) then
  747. Result:=FN
  748. else if StrictFileCase then
  749. Result:=''
  750. else
  751. begin
  752. Dir:=ExtractFilePath(FN);
  753. FN:=ExtractFileName(FN);
  754. Result:=Dir+LowerCase(FN);
  755. If FileExists(Result) then exit;
  756. Result:=Dir+uppercase(Fn);
  757. If FileExists(Result) then exit;
  758. Result:='';
  759. end;
  760. end;
  761. var
  762. i: Integer;
  763. FN : string;
  764. begin
  765. Result := '';
  766. // convert pathdelims to system
  767. FN:=SetDirSeparators(AName);
  768. If FilenameIsAbsolute(FN) then
  769. begin
  770. // Maybe this should also do a SearchLowUpCase ?
  771. if FileExists(FN) then
  772. Result := FN;
  773. end
  774. else
  775. begin
  776. // file name is relative
  777. // search in include path
  778. I:=0;
  779. While (Result='') and (I<FIncludePaths.Count) do
  780. begin
  781. Result:=SearchLowUpCase(FIncludePaths[i]+AName);
  782. Inc(I);
  783. end;
  784. // search in BaseDirectory
  785. if (Result='') and (BaseDirectory<>'') then
  786. Result:=SearchLowUpCase(BaseDirectory+AName);
  787. end;
  788. end;
  789. constructor TBaseFileResolver.Create;
  790. begin
  791. inherited Create;
  792. FIncludePaths := TStringList.Create;
  793. end;
  794. destructor TBaseFileResolver.Destroy;
  795. begin
  796. FIncludePaths.Free;
  797. inherited Destroy;
  798. end;
  799. procedure TBaseFileResolver.AddIncludePath(const APath: string);
  800. begin
  801. if (APath='') then
  802. FIncludePaths.Add('./')
  803. else
  804. FIncludePaths.Add(IncludeTrailingPathDelimiter(ExpandFileName(APath)));
  805. end;
  806. { ---------------------------------------------------------------------
  807. TFileResolver
  808. ---------------------------------------------------------------------}
  809. function TFileResolver.CreateFileReader(const AFileName: String): TLineReader;
  810. begin
  811. If UseStreams then
  812. Result:=TFileStreamLineReader.Create(AFileName)
  813. else
  814. Result:=TFileLineReader.Create(AFileName);
  815. end;
  816. function TFileResolver.FindSourceFile(const AName: string): TLineReader;
  817. begin
  818. if not FileExists(AName) then
  819. Raise EFileNotFoundError.create(Aname)
  820. else
  821. try
  822. Result := CreateFileReader(AName)
  823. except
  824. Result := nil;
  825. end;
  826. end;
  827. function TFileResolver.FindIncludeFile(const AName: string): TLineReader;
  828. Var
  829. FN : String;
  830. begin
  831. Result:=Nil;
  832. FN:=FindIncludeFileName(ANAme);
  833. If (FN<>'') then
  834. try
  835. Result := TFileLineReader.Create(FN);
  836. except
  837. Result:=Nil;
  838. end;
  839. end;
  840. { ---------------------------------------------------------------------
  841. TPascalScanner
  842. ---------------------------------------------------------------------}
  843. constructor TPascalScanner.Create(AFileResolver: TBaseFileResolver);
  844. Function CS : TStringList;
  845. begin
  846. Result:=TStringList.Create;
  847. Result.Sorted:=True;
  848. Result.Duplicates:=dupError;
  849. end;
  850. begin
  851. inherited Create;
  852. FFileResolver := AFileResolver;
  853. FIncludeStack := TFPList.Create;
  854. FDefines := CS;
  855. FMacros:=CS;
  856. end;
  857. destructor TPascalScanner.Destroy;
  858. begin
  859. ClearMacros;
  860. FreeAndNil(FMacros);
  861. FreeAndNil(FDefines);
  862. ClearFiles;
  863. FIncludeStack.Free;
  864. inherited Destroy;
  865. end;
  866. procedure TPascalScanner.ClearFiles;
  867. begin
  868. // Dont' free the first element, because it is CurSourceFile
  869. while FIncludeStack.Count > 1 do
  870. begin
  871. TFileResolver(FIncludeStack[1]).Free;
  872. FIncludeStack.Delete(1);
  873. end;
  874. FIncludeStack.Clear;
  875. FreeAndNil(FCurSourceFile);
  876. end;
  877. procedure TPascalScanner.ClearMacros;
  878. Var
  879. I : Integer;
  880. begin
  881. For I:=0 to FMacros.Count-1 do
  882. FMacros.Objects[i].Free;
  883. FMacros.Clear;
  884. end;
  885. procedure TPascalScanner.SetCurTokenString(AValue: string);
  886. begin
  887. FCurtokenString:=AValue;
  888. end;
  889. procedure TPascalScanner.OpenFile(const AFilename: string);
  890. begin
  891. Clearfiles;
  892. FCurSourceFile := FileResolver.FindSourceFile(AFilename);
  893. if LogEvent(sleFile) then
  894. DoLog(SLogOpeningFile,[AFileName],True);
  895. FCurFilename := AFilename;
  896. FileResolver.BaseDirectory := IncludeTrailingPathDelimiter(ExtractFilePath(AFilename));
  897. end;
  898. function TPascalScanner.FetchToken: TToken;
  899. var
  900. IncludeStackItem: TIncludeStackItem;
  901. begin
  902. while true do
  903. begin
  904. Result := DoFetchToken;
  905. Case FCurToken of
  906. tkEOF:
  907. begin
  908. if FIncludeStack.Count > 0 then
  909. begin
  910. CurSourceFile.Free;
  911. IncludeStackItem :=
  912. TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
  913. FIncludeStack.Delete(FIncludeStack.Count - 1);
  914. FCurSourceFile := IncludeStackItem.SourceFile;
  915. FCurFilename := IncludeStackItem.Filename;
  916. FCurToken := IncludeStackItem.Token;
  917. FCurTokenString := IncludeStackItem.TokenString;
  918. FCurLine := IncludeStackItem.Line;
  919. FCurRow := IncludeStackItem.Row;
  920. TokenStr := IncludeStackItem.TokenStr;
  921. IncludeStackItem.Free;
  922. Result := FCurToken;
  923. end
  924. else
  925. break
  926. end;
  927. tkWhiteSpace,
  928. tkLineEnding:
  929. if not (FSkipWhiteSpace or PPIsSkipping) then
  930. Break;
  931. tkComment:
  932. if not (FSkipComments or PPIsSkipping) then
  933. Break;
  934. else
  935. if not PPIsSkipping then
  936. break;
  937. end; // Case
  938. end;
  939. // Writeln(Result, '(',CurTokenString,')');
  940. end;
  941. procedure TPascalScanner.Error(const Msg: string);
  942. begin
  943. raise EScannerError.Create(Msg);
  944. end;
  945. procedure TPascalScanner.Error(const Msg: string; Args: array of Const);
  946. begin
  947. raise EScannerError.CreateFmt(Msg, Args);
  948. end;
  949. function TPascalScanner.DoFetchTextToken:TToken;
  950. var
  951. OldLength : Integer;
  952. TokenStart : PChar;
  953. SectionLength : Integer;
  954. begin
  955. Result:=tkEOF;
  956. OldLength:=0;
  957. FCurTokenString := '';
  958. while TokenStr[0] in ['#', ''''] do
  959. begin
  960. case TokenStr[0] of
  961. '#':
  962. begin
  963. TokenStart := TokenStr;
  964. Inc(TokenStr);
  965. if TokenStr[0] = '$' then
  966. begin
  967. Inc(TokenStr);
  968. repeat
  969. Inc(TokenStr);
  970. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'f']);
  971. end else
  972. repeat
  973. Inc(TokenStr);
  974. until not (TokenStr[0] in ['0'..'9']);
  975. if Result=tkEOF then Result := tkChar else Result:=tkString;
  976. end;
  977. '''':
  978. begin
  979. TokenStart := TokenStr;
  980. Inc(TokenStr);
  981. while true do
  982. begin
  983. if TokenStr[0] = '''' then
  984. if TokenStr[1] = '''' then
  985. Inc(TokenStr)
  986. else
  987. break;
  988. if TokenStr[0] = #0 then
  989. Error(SErrOpenString);
  990. Inc(TokenStr);
  991. end;
  992. Inc(TokenStr);
  993. Result := tkString;
  994. end;
  995. else
  996. Break;
  997. end;
  998. SectionLength := TokenStr - TokenStart;
  999. SetLength(FCurTokenString, OldLength + SectionLength);
  1000. if SectionLength > 0 then
  1001. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  1002. Inc(OldLength, SectionLength);
  1003. end;
  1004. end;
  1005. Procedure TPascalScanner.PushStackItem;
  1006. Var
  1007. SI: TIncludeStackItem;
  1008. begin
  1009. SI := TIncludeStackItem.Create;
  1010. SI.SourceFile := CurSourceFile;
  1011. SI.Filename := CurFilename;
  1012. SI.Token := CurToken;
  1013. SI.TokenString := CurTokenString;
  1014. SI.Line := CurLine;
  1015. SI.Row := CurRow;
  1016. SI.TokenStr := TokenStr;
  1017. FIncludeStack.Add(SI);
  1018. TokenStr:=Nil;
  1019. FCurRow := 0;
  1020. end;
  1021. Procedure TPascalScanner.HandleIncludeFile(Param : String);
  1022. begin
  1023. PushStackItem;
  1024. if Length(Param)>1 then
  1025. begin
  1026. if (Param[1]=#39) and (Param[length(Param)]=#39) then
  1027. param:=copy(param,2,length(param)-2);
  1028. end;
  1029. FCurSourceFile := FileResolver.FindIncludeFile(Param);
  1030. if not Assigned(FCurSourceFile) then
  1031. Error(SErrIncludeFileNotFound, [Param]);
  1032. FCurFilename := Param;
  1033. if FCurSourceFile is TFileLineReader then
  1034. FCurFilename := TFileLineReader(FCurSourceFile).Filename; // nicer error messages
  1035. If LogEvent(sleFile) then
  1036. DoLog(SLogOpeningFile,[FCurFileName],True);
  1037. end;
  1038. function TPascalScanner.HandleMacro(AIndex : integer) : TToken;
  1039. Var
  1040. M : TMacroDef;
  1041. ML : TMacroReader;
  1042. begin
  1043. PushStackItem;
  1044. M:=FMacros.Objects[AIndex] as TMacroDef;
  1045. ML:=TMacroReader.Create(FCurFileName,M.Value);
  1046. ML.CurRow:=FCurRow;
  1047. ML.CurCol:=CurColumn;
  1048. FCurSourceFile:=ML;
  1049. Result:=DofetchToken;
  1050. // Writeln(Result,Curtoken);
  1051. end;
  1052. Procedure TPascalScanner.HandleDefine(Param : String);
  1053. Var
  1054. Index : Integer;
  1055. MN,MV : String;
  1056. begin
  1057. Param := UpperCase(Param);
  1058. Index:=Pos(':=',Param);
  1059. If (Index=0) then
  1060. AddDefine(Param)
  1061. else
  1062. begin
  1063. MV:=Trim(Param);
  1064. MN:=Trim(Copy(MV,1,Index-1));
  1065. Delete(MV,1,Index+1);
  1066. Index:=FMacros.IndexOf(MN);
  1067. If (Index=-1) then
  1068. FMacros.AddObject(MN,TMacroDef.Create(MN,MV))
  1069. else
  1070. TMacroDef(FMacros.Objects[index]).Value:=MV;
  1071. end;
  1072. end;
  1073. Procedure TPascalScanner.HandleUnDefine(Param : String);
  1074. Var
  1075. Index : integer;
  1076. begin
  1077. Param := UpperCase(Param);
  1078. Index:=FDefines.IndexOf(Param);
  1079. If (Index>=0) then
  1080. RemoveDefine(Param)
  1081. else
  1082. begin
  1083. Index := FMacros.IndexOf(Param);
  1084. If (Index>=0) then
  1085. begin
  1086. FMacros.Objects[Index].FRee;
  1087. FMacros.Delete(Index);
  1088. end;
  1089. end;
  1090. end;
  1091. function TPascalScanner.DoFetchToken: TToken;
  1092. function FetchLine: Boolean;
  1093. begin
  1094. if CurSourceFile.IsEOF then
  1095. begin
  1096. FCurLine := '';
  1097. TokenStr := nil;
  1098. Result := false;
  1099. end else
  1100. begin
  1101. FCurLine := CurSourceFile.ReadLine;
  1102. TokenStr := PChar(CurLine);
  1103. Result := true;
  1104. Inc(FCurRow);
  1105. if LogEvent(sleLineNumber) and ((FCurRow Mod 100) = 0) then
  1106. DoLog(SLogLineNumber,[FCurRow],True);
  1107. end;
  1108. end;
  1109. var
  1110. TokenStart, CurPos: PChar;
  1111. i: TToken;
  1112. OldLength, SectionLength, NestingLevel, Index: Integer;
  1113. Directive, Param : string;
  1114. begin
  1115. if TokenStr = nil then
  1116. if not FetchLine then
  1117. begin
  1118. Result := tkEOF;
  1119. FCurToken := Result;
  1120. exit;
  1121. end;
  1122. FCurTokenString := '';
  1123. case TokenStr[0] of
  1124. #0: // Empty line
  1125. begin
  1126. FetchLine;
  1127. Result := tkLineEnding;
  1128. end;
  1129. ' ':
  1130. begin
  1131. Result := tkWhitespace;
  1132. repeat
  1133. Inc(TokenStr);
  1134. if TokenStr[0] = #0 then
  1135. if not FetchLine then
  1136. begin
  1137. FCurToken := Result;
  1138. exit;
  1139. end;
  1140. until not (TokenStr[0] in [' ']);
  1141. end;
  1142. #9:
  1143. begin
  1144. Result := tkTab;
  1145. repeat
  1146. Inc(TokenStr);
  1147. if TokenStr[0] = #0 then
  1148. if not FetchLine then
  1149. begin
  1150. FCurToken := Result;
  1151. exit;
  1152. end;
  1153. until not (TokenStr[0] in [#9]);
  1154. end;
  1155. '#', '''':
  1156. Result:=DoFetchTextToken;
  1157. '&':
  1158. begin
  1159. TokenStart := TokenStr;
  1160. repeat
  1161. Inc(TokenStr);
  1162. until not (TokenStr[0] in ['0'..'7']);
  1163. SectionLength := TokenStr - TokenStart;
  1164. SetLength(FCurTokenString, SectionLength);
  1165. if SectionLength > 0 then
  1166. Move(TokenStart^, FCurTokenString[1], SectionLength);
  1167. Result := tkNumber;
  1168. end;
  1169. '$':
  1170. begin
  1171. TokenStart := TokenStr;
  1172. repeat
  1173. Inc(TokenStr);
  1174. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'f']);
  1175. SectionLength := TokenStr - TokenStart;
  1176. SetLength(FCurTokenString, SectionLength);
  1177. if SectionLength > 0 then
  1178. Move(TokenStart^, FCurTokenString[1], SectionLength);
  1179. Result := tkNumber;
  1180. end;
  1181. '%':
  1182. begin
  1183. TokenStart := TokenStr;
  1184. repeat
  1185. Inc(TokenStr);
  1186. until not (TokenStr[0] in ['0','1']);
  1187. SectionLength := TokenStr - TokenStart;
  1188. SetLength(FCurTokenString, SectionLength);
  1189. if SectionLength > 0 then
  1190. Move(TokenStart^, FCurTokenString[1], SectionLength);
  1191. Result := tkNumber;
  1192. end;
  1193. '(':
  1194. begin
  1195. Inc(TokenStr);
  1196. if TokenStr[0] = '*' then
  1197. begin
  1198. // Old-style multi-line comment
  1199. Inc(TokenStr);
  1200. while (TokenStr[0] <> '*') or (TokenStr[1] <> ')') do
  1201. begin
  1202. if TokenStr[0] = #0 then
  1203. begin
  1204. if not FetchLine then
  1205. begin
  1206. Result := tkEOF;
  1207. FCurToken := Result;
  1208. exit;
  1209. end;
  1210. end else
  1211. Inc(TokenStr);
  1212. end;
  1213. Inc(TokenStr, 2);
  1214. Result := tkComment;
  1215. end else
  1216. Result := tkBraceOpen;
  1217. end;
  1218. ')':
  1219. begin
  1220. Inc(TokenStr);
  1221. Result := tkBraceClose;
  1222. end;
  1223. '*':
  1224. begin
  1225. Result:=tkMul;
  1226. Inc(TokenStr);
  1227. if TokenStr[0] = '*' then
  1228. begin
  1229. Inc(TokenStr);
  1230. Result := tkPower;
  1231. end
  1232. else if (po_cassignments in options) then
  1233. begin
  1234. if TokenStr[0]='=' then
  1235. begin
  1236. Inc(TokenStr);
  1237. Result:=tkAssignMul;
  1238. end;
  1239. end
  1240. end;
  1241. '+':
  1242. begin
  1243. Result:=tkPlus;
  1244. Inc(TokenStr);
  1245. if (po_cassignments in options) then
  1246. begin
  1247. if TokenStr[0]='=' then
  1248. begin
  1249. Inc(TokenStr);
  1250. Result:=tkAssignPlus;
  1251. end;
  1252. end
  1253. end;
  1254. ',':
  1255. begin
  1256. Inc(TokenStr);
  1257. Result := tkComma;
  1258. end;
  1259. '-':
  1260. begin
  1261. Result := tkMinus;
  1262. Inc(TokenStr);
  1263. if (po_cassignments in options) then
  1264. begin
  1265. if TokenStr[0]='=' then
  1266. begin
  1267. Inc(TokenStr);
  1268. Result:=tkAssignMinus;
  1269. end;
  1270. end
  1271. end;
  1272. '.':
  1273. begin
  1274. Inc(TokenStr);
  1275. if TokenStr[0] = '.' then
  1276. begin
  1277. Inc(TokenStr);
  1278. Result := tkDotDot;
  1279. end else
  1280. Result := tkDot;
  1281. end;
  1282. '/':
  1283. begin
  1284. Result := tkDivision;
  1285. Inc(TokenStr);
  1286. if (TokenStr[0] = '/') then // Single-line comment
  1287. begin
  1288. Inc(TokenStr);
  1289. TokenStart := TokenStr;
  1290. FCurTokenString := '';
  1291. while TokenStr[0] <> #0 do
  1292. Inc(TokenStr);
  1293. SectionLength := TokenStr - TokenStart;
  1294. SetLength(FCurTokenString, SectionLength);
  1295. if SectionLength > 0 then
  1296. Move(TokenStart^, FCurTokenString[1], SectionLength);
  1297. Result := tkComment;
  1298. end
  1299. else if (po_cassignments in options) then
  1300. begin
  1301. if TokenStr[0]='=' then
  1302. begin
  1303. Inc(TokenStr);
  1304. Result:=tkAssignDivision;
  1305. end;
  1306. end
  1307. end;
  1308. '0'..'9':
  1309. begin
  1310. TokenStart := TokenStr;
  1311. while true do
  1312. begin
  1313. Inc(TokenStr);
  1314. case TokenStr[0] of
  1315. '.':
  1316. begin
  1317. if TokenStr[1] in ['0'..'9', 'e', 'E'] then
  1318. begin
  1319. Inc(TokenStr);
  1320. repeat
  1321. Inc(TokenStr);
  1322. until not (TokenStr[0] in ['0'..'9', 'e', 'E']);
  1323. end;
  1324. break;
  1325. end;
  1326. '0'..'9': ;
  1327. 'e', 'E':
  1328. begin
  1329. Inc(TokenStr);
  1330. if TokenStr[0] = '-' then
  1331. Inc(TokenStr);
  1332. while TokenStr[0] in ['0'..'9'] do
  1333. Inc(TokenStr);
  1334. break;
  1335. end;
  1336. else
  1337. break;
  1338. end;
  1339. end;
  1340. SectionLength := TokenStr - TokenStart;
  1341. SetLength(FCurTokenString, SectionLength);
  1342. if SectionLength > 0 then
  1343. Move(TokenStart^, FCurTokenString[1], SectionLength);
  1344. Result := tkNumber;
  1345. end;
  1346. ':':
  1347. begin
  1348. Inc(TokenStr);
  1349. if TokenStr[0] = '=' then
  1350. begin
  1351. Inc(TokenStr);
  1352. Result := tkAssign;
  1353. end else
  1354. Result := tkColon;
  1355. end;
  1356. ';':
  1357. begin
  1358. Inc(TokenStr);
  1359. Result := tkSemicolon;
  1360. end;
  1361. '<':
  1362. begin
  1363. Inc(TokenStr);
  1364. if TokenStr[0] = '>' then
  1365. begin
  1366. Inc(TokenStr);
  1367. Result := tkNotEqual;
  1368. end else if TokenStr[0] = '=' then
  1369. begin
  1370. Inc(TokenStr);
  1371. Result := tkLessEqualThan;
  1372. end else
  1373. Result := tkLessThan;
  1374. end;
  1375. '=':
  1376. begin
  1377. Inc(TokenStr);
  1378. Result := tkEqual;
  1379. end;
  1380. '>':
  1381. begin
  1382. Inc(TokenStr);
  1383. if TokenStr[0] = '=' then
  1384. begin
  1385. Inc(TokenStr);
  1386. Result := tkGreaterEqualThan;
  1387. end else if TokenStr[0] = '<' then
  1388. begin
  1389. Inc(TokenStr);
  1390. Result := tkSymmetricalDifference;
  1391. end else
  1392. Result := tkGreaterThan;
  1393. end;
  1394. '@':
  1395. begin
  1396. Inc(TokenStr);
  1397. Result := tkAt;
  1398. end;
  1399. '[':
  1400. begin
  1401. Inc(TokenStr);
  1402. Result := tkSquaredBraceOpen;
  1403. end;
  1404. ']':
  1405. begin
  1406. Inc(TokenStr);
  1407. Result := tkSquaredBraceClose;
  1408. end;
  1409. '^':
  1410. begin
  1411. Inc(TokenStr);
  1412. Result := tkCaret;
  1413. end;
  1414. '\':
  1415. begin
  1416. Inc(TokenStr);
  1417. Result := tkBackslash;
  1418. end;
  1419. '{': // Multi-line comment
  1420. begin
  1421. Inc(TokenStr);
  1422. TokenStart := TokenStr;
  1423. FCurTokenString := '';
  1424. OldLength := 0;
  1425. NestingLevel := 0;
  1426. while (TokenStr[0] <> '}') or (NestingLevel > 0) do
  1427. begin
  1428. if TokenStr[0] = #0 then
  1429. begin
  1430. SectionLength := TokenStr - TokenStart + 1;
  1431. SetLength(FCurTokenString, OldLength + SectionLength);
  1432. if SectionLength > 1 then
  1433. Move(TokenStart^, FCurTokenString[OldLength + 1],
  1434. SectionLength - 1);
  1435. Inc(OldLength, SectionLength);
  1436. FCurTokenString[OldLength] := #10;
  1437. if not FetchLine then
  1438. begin
  1439. Result := tkEOF;
  1440. FCurToken := Result;
  1441. exit;
  1442. end;
  1443. TokenStart := TokenStr;
  1444. end else
  1445. begin
  1446. if not(po_delphi in Options) and (TokenStr[0] = '{') then
  1447. Inc(NestingLevel)
  1448. else if TokenStr[0] = '}' then
  1449. Dec(NestingLevel);
  1450. Inc(TokenStr);
  1451. end;
  1452. end;
  1453. SectionLength := TokenStr - TokenStart;
  1454. SetLength(FCurTokenString, OldLength + SectionLength);
  1455. if SectionLength > 0 then
  1456. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  1457. Inc(TokenStr);
  1458. Result := tkComment;
  1459. //WriteLn('Kommentar: "', CurTokenString, '"');
  1460. if (Length(CurTokenString) > 0) and (CurTokenString[1] = '$') then
  1461. begin
  1462. TokenStart := @CurTokenString[2];
  1463. CurPos := TokenStart;
  1464. while (CurPos[0] <> ' ') and (CurPos[0] <> #0) do
  1465. Inc(CurPos);
  1466. SectionLength := CurPos - TokenStart;
  1467. SetLength(Directive, SectionLength);
  1468. if SectionLength > 0 then
  1469. begin
  1470. Move(TokenStart^, Directive[1], SectionLength);
  1471. Directive := UpperCase(Directive);
  1472. if CurPos[0] <> #0 then
  1473. begin
  1474. TokenStart := CurPos + 1;
  1475. CurPos := TokenStart;
  1476. while CurPos[0] <> #0 do
  1477. Inc(CurPos);
  1478. SectionLength := CurPos - TokenStart;
  1479. SetLength(Param, SectionLength);
  1480. if SectionLength > 0 then
  1481. Move(TokenStart^, Param[1], SectionLength);
  1482. end else
  1483. Param := '';
  1484. if Not PPIsSkipping then
  1485. begin
  1486. if (Directive = 'I') or (Directive = 'INCLUDE') then
  1487. begin
  1488. if ((Param='') or (Param[1]<>'%')) then
  1489. HandleIncludeFile(param)
  1490. else if Param[1]='%' then
  1491. begin
  1492. fcurtokenstring:='{$i '+param+'}';
  1493. fcurtoken:=tkstring;
  1494. result:=fcurtoken;
  1495. exit;
  1496. end
  1497. end
  1498. else if (Directive = 'DEFINE') then
  1499. HandleDefine(Param)
  1500. else if (Directive = 'UNDEF') then
  1501. HandleUnDefine(Param)
  1502. end;
  1503. if (Directive = 'IFDEF') then
  1504. begin
  1505. if PPSkipStackIndex = High(PPSkipModeStack) then
  1506. Error(SErrIfXXXNestingLimitReached);
  1507. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  1508. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  1509. Inc(PPSkipStackIndex);
  1510. if PPIsSkipping then
  1511. begin
  1512. PPSkipMode := ppSkipAll;
  1513. PPIsSkipping := true;
  1514. end else
  1515. begin
  1516. Param := UpperCase(Param);
  1517. Index := Defines.IndexOf(Param);
  1518. if Index < 0 then
  1519. Index := Macros.IndexOf(Param);
  1520. if Index < 0 then
  1521. begin
  1522. PPSkipMode := ppSkipIfBranch;
  1523. PPIsSkipping := true;
  1524. end else
  1525. PPSkipMode := ppSkipElseBranch;
  1526. If LogEvent(sleConditionals) then
  1527. if PPSkipMode=ppSkipElseBranch then
  1528. DoLog(SLogIFDefAccepted,[Param])
  1529. else
  1530. DoLog(SLogIFDefRejected,[Param])
  1531. end;
  1532. end else if Directive = 'IFNDEF' then
  1533. begin
  1534. if PPSkipStackIndex = High(PPSkipModeStack) then
  1535. Error(SErrIfXXXNestingLimitReached);
  1536. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  1537. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  1538. Inc(PPSkipStackIndex);
  1539. if PPIsSkipping then
  1540. begin
  1541. PPSkipMode := ppSkipAll;
  1542. PPIsSkipping := true;
  1543. end else
  1544. begin
  1545. Param := UpperCase(Param);
  1546. Index := Defines.IndexOf(Param);
  1547. if Index >= 0 then
  1548. begin
  1549. PPSkipMode := ppSkipIfBranch;
  1550. PPIsSkipping := true;
  1551. end else
  1552. PPSkipMode := ppSkipElseBranch;
  1553. If LogEvent(sleConditionals) then
  1554. if PPSkipMode=ppSkipElseBranch then
  1555. DoLog(SLogIFNDefAccepted,[Param])
  1556. else
  1557. DoLog(SLogIFNDefRejected,[Param])
  1558. end;
  1559. end else if Directive = 'IFOPT' then
  1560. begin
  1561. if PPSkipStackIndex = High(PPSkipModeStack) then
  1562. Error(SErrIfXXXNestingLimitReached);
  1563. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  1564. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  1565. Inc(PPSkipStackIndex);
  1566. if PPIsSkipping then
  1567. begin
  1568. PPSkipMode := ppSkipAll;
  1569. PPIsSkipping := true;
  1570. end else
  1571. begin
  1572. { !!!: Currently, options are not supported, so they are just
  1573. assumed as not being set. }
  1574. PPSkipMode := ppSkipIfBranch;
  1575. PPIsSkipping := true;
  1576. end;
  1577. If LogEvent(sleConditionals) then
  1578. DoLog(SLogIFOPTIgnored,[Uppercase(Param)])
  1579. end else if Directive = 'IF' then
  1580. begin
  1581. if PPSkipStackIndex = High(PPSkipModeStack) then
  1582. Error(SErrIfXXXNestingLimitReached);
  1583. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  1584. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  1585. Inc(PPSkipStackIndex);
  1586. if PPIsSkipping then
  1587. begin
  1588. PPSkipMode := ppSkipAll;
  1589. PPIsSkipping := true;
  1590. end else
  1591. begin
  1592. { !!!: Currently, expressions are not supported, so they are
  1593. just assumed as evaluating to false. }
  1594. PPSkipMode := ppSkipIfBranch;
  1595. PPIsSkipping := true;
  1596. If LogEvent(sleConditionals) then
  1597. DoLog(SLogIFIgnored,[Uppercase(Param)])
  1598. end;
  1599. end else if Directive = 'ELSE' then
  1600. begin
  1601. if PPSkipStackIndex = 0 then
  1602. Error(SErrInvalidPPElse);
  1603. if PPSkipMode = ppSkipIfBranch then
  1604. PPIsSkipping := false
  1605. else if PPSkipMode = ppSkipElseBranch then
  1606. PPIsSkipping := true;
  1607. end else if ((Directive = 'ENDIF') or (Directive='IFEND')) then
  1608. begin
  1609. if PPSkipStackIndex = 0 then
  1610. Error(SErrInvalidPPEndif);
  1611. Dec(PPSkipStackIndex);
  1612. PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
  1613. PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
  1614. end;
  1615. end else
  1616. Directive := '';
  1617. end;
  1618. end;
  1619. 'A'..'Z', 'a'..'z', '_':
  1620. begin
  1621. TokenStart := TokenStr;
  1622. repeat
  1623. Inc(TokenStr);
  1624. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  1625. SectionLength := TokenStr - TokenStart;
  1626. SetLength(FCurTokenString, SectionLength);
  1627. if SectionLength > 0 then
  1628. Move(TokenStart^, FCurTokenString[1], SectionLength);
  1629. for i := tkAbsolute to tkXOR do
  1630. if CompareText(CurTokenString, TokenInfos[i]) = 0 then
  1631. begin
  1632. Result := i;
  1633. FCurToken := Result;
  1634. exit;
  1635. end;
  1636. Index:=FMacros.IndexOf(CurtokenString);
  1637. if (Index=-1) then
  1638. Result := tkIdentifier
  1639. else
  1640. Result:=HandleMacro(index);
  1641. end;
  1642. else
  1643. if PPIsSkipping then
  1644. Inc(TokenStr)
  1645. else
  1646. Error(SErrInvalidCharacter, [TokenStr[0]]);
  1647. end;
  1648. FCurToken := Result;
  1649. end;
  1650. function TPascalScanner.LogEvent(E: TPScannerLogEvent): Boolean;
  1651. begin
  1652. Result:=E in FLogEvents;
  1653. end;
  1654. function TPascalScanner.GetCurColumn: Integer;
  1655. begin
  1656. If (TokenStr<>Nil) then
  1657. Result := TokenStr - PChar(CurLine)
  1658. else
  1659. Result:=0;
  1660. end;
  1661. procedure TPascalScanner.DoLog(const Msg: String;SkipSourceInfo : Boolean = False);
  1662. begin
  1663. If Assigned(FOnLog) then
  1664. if SkipSourceInfo then
  1665. FOnLog(Self,Msg)
  1666. else
  1667. FOnLog(Self,Format('%s(%d) : %s',[FCurFileName,FCurRow,Msg]));
  1668. end;
  1669. procedure TPascalScanner.DoLog(const Fmt: String; Args: array of const;SkipSourceInfo : Boolean = False);
  1670. begin
  1671. DoLog(Format(Fmt,Args),SkipSourceInfo);
  1672. end;
  1673. procedure TPascalScanner.SetOptions(AValue: TPOptions);
  1674. begin
  1675. if FOptions=AValue then Exit;
  1676. FOptions:=AValue;
  1677. end;
  1678. Procedure TPascalScanner.AddDefine(S : String);
  1679. begin
  1680. If FDefines.IndexOf(S)=-1 then
  1681. FDefines.Add(S);
  1682. end;
  1683. Procedure TPascalScanner.RemoveDefine(S : String);
  1684. Var
  1685. I : Integer;
  1686. begin
  1687. I:=FDefines.IndexOf(S);
  1688. if (I<>-1) then
  1689. FDefines.Delete(I);
  1690. end;
  1691. end.