pscanner.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  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. unit PScanner;
  13. interface
  14. uses SysUtils, Classes;
  15. resourcestring
  16. SErrInvalidCharacter = 'Invalid character ''%s''';
  17. SErrOpenString = 'string exceeds end of line';
  18. SErrIncludeFileNotFound = 'Could not find include file ''%s''';
  19. SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
  20. SErrInvalidPPElse = '$ELSE without matching $IFxxx';
  21. SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
  22. type
  23. TToken = (
  24. tkEOF,
  25. tkWhitespace,
  26. tkComment,
  27. tkIdentifier,
  28. tkString,
  29. tkNumber,
  30. tkChar,
  31. // Simple (one-character) tokens
  32. tkBraceOpen, // '('
  33. tkBraceClose, // ')'
  34. tkMul, // '*'
  35. tkPlus, // '+'
  36. tkComma, // ','
  37. tkMinus, // '-'
  38. tkDot, // '.'
  39. tkDivision, // '/'
  40. tkColon, // ':'
  41. tkSemicolon, // ';'
  42. tkLessThan, // '<'
  43. tkEqual, // '='
  44. tkGreaterThan, // '>'
  45. tkAt, // '@'
  46. tkSquaredBraceOpen, // '['
  47. tkSquaredBraceClose, // ']'
  48. tkCaret, // '^'
  49. // Two-character tokens
  50. tkDotDot, // '..'
  51. tkAssign, // ':='
  52. tkNotEqual, // '<>'
  53. tkLessEqualThan, // '<='
  54. tkGreaterEqualThan, // '>='
  55. tkPower, // '**'
  56. tkSymmetricalDifference, // '><'
  57. // Reserved words
  58. tkabsolute,
  59. tkand,
  60. tkarray,
  61. tkas,
  62. tkasm,
  63. tkbegin,
  64. tkcase,
  65. tkclass,
  66. tkconst,
  67. tkconstructor,
  68. tkdestructor,
  69. tkdiv,
  70. tkdo,
  71. tkdownto,
  72. tkelse,
  73. tkend,
  74. tkexcept,
  75. tkexports,
  76. tkfalse,
  77. tkfinalization,
  78. tkfinally,
  79. tkfor,
  80. tkfunction,
  81. tkgoto,
  82. tkif,
  83. tkimplementation,
  84. tkin,
  85. tkinherited,
  86. tkinitialization,
  87. tkinline,
  88. tkinterface,
  89. tkis,
  90. tklabel,
  91. tklibrary,
  92. tkmod,
  93. tknil,
  94. tknot,
  95. tkobject,
  96. tkof,
  97. tkon,
  98. tkoperator,
  99. tkor,
  100. tkpacked,
  101. tkprocedure,
  102. tkprogram,
  103. tkproperty,
  104. tkraise,
  105. tkrecord,
  106. tkrepeat,
  107. tkResourceString,
  108. tkself,
  109. tkset,
  110. tkshl,
  111. tkshr,
  112. // tkstring,
  113. tkthen,
  114. tkthreadvar,
  115. tkto,
  116. tktrue,
  117. tktry,
  118. tktype,
  119. tkunit,
  120. tkuntil,
  121. tkuses,
  122. tkvar,
  123. tkwhile,
  124. tkwith,
  125. tkxor);
  126. TLineReader = class
  127. public
  128. function IsEOF: Boolean; virtual; abstract;
  129. function ReadLine: string; virtual; abstract;
  130. end;
  131. TFileLineReader = class(TLineReader)
  132. private
  133. FTextFile: Text;
  134. FileOpened: Boolean;
  135. public
  136. constructor Create(const AFilename: string);
  137. destructor Destroy; override;
  138. function IsEOF: Boolean; override;
  139. function ReadLine: string; override;
  140. end;
  141. TFileResolver = class
  142. private
  143. FIncludePaths: TStringList;
  144. public
  145. constructor Create;
  146. destructor Destroy; override;
  147. procedure AddIncludePath(const APath: string);
  148. function FindSourceFile(const AName: string): TLineReader;
  149. function FindIncludeFile(const AName: string): TLineReader;
  150. end;
  151. EScannerError = class(Exception);
  152. EFileNotFoundError = class(Exception);
  153. TPascalScannerPPSkipMode = (ppSkipNone, ppSkipIfBranch, ppSkipElseBranch,
  154. ppSkipAll);
  155. TPOptions = (po_delphi);
  156. TPascalScanner = class
  157. private
  158. FFileResolver: TFileResolver;
  159. FCurSourceFile: TLineReader;
  160. FCurFilename: string;
  161. FCurRow: Integer;
  162. FCurToken: TToken;
  163. FCurTokenString: string;
  164. FCurLine: string;
  165. FDefines: TStrings;
  166. TokenStr: PChar;
  167. FIncludeStack: TList;
  168. // Preprocessor $IFxxx skipping data
  169. PPSkipMode: TPascalScannerPPSkipMode;
  170. PPIsSkipping: Boolean;
  171. PPSkipStackIndex: Integer;
  172. PPSkipModeStack: array[0..255] of TPascalScannerPPSkipMode;
  173. PPIsSkippingStack: array[0..255] of Boolean;
  174. function GetCurColumn: Integer;
  175. protected
  176. procedure Error(const Msg: string);
  177. procedure Error(const Msg: string; Args: array of Const);
  178. function DoFetchToken: TToken;
  179. public
  180. Options : set of TPOptions;
  181. constructor Create(AFileResolver: TFileResolver);
  182. destructor Destroy; override;
  183. procedure OpenFile(const AFilename: string);
  184. function FetchToken: TToken;
  185. property FileResolver: TFileResolver read FFileResolver;
  186. property CurSourceFile: TLineReader read FCurSourceFile;
  187. property CurFilename: string read FCurFilename;
  188. property CurLine: string read FCurLine;
  189. property CurRow: Integer read FCurRow;
  190. property CurColumn: Integer read GetCurColumn;
  191. property CurToken: TToken read FCurToken;
  192. property CurTokenString: string read FCurTokenString;
  193. property Defines: TStrings read FDefines;
  194. end;
  195. const
  196. TokenInfos: array[TToken] of string = (
  197. 'EOF',
  198. 'Whitespace',
  199. 'Comment',
  200. 'Identifier',
  201. 'string',
  202. 'Number',
  203. 'Character',
  204. '(',
  205. ')',
  206. '*',
  207. '+',
  208. ',',
  209. '-',
  210. '.',
  211. '/',
  212. ':',
  213. ';',
  214. '<',
  215. '=',
  216. '>',
  217. '@',
  218. '[',
  219. ']',
  220. '^',
  221. '..',
  222. ':=',
  223. '<>',
  224. '<=',
  225. '>=',
  226. '**',
  227. '><',
  228. // Reserved words
  229. 'absolute',
  230. 'and',
  231. 'array',
  232. 'as',
  233. 'asm',
  234. 'begin',
  235. 'case',
  236. 'class',
  237. 'const',
  238. 'constructor',
  239. 'destructor',
  240. 'div',
  241. 'do',
  242. 'downto',
  243. 'else',
  244. 'end',
  245. 'except',
  246. 'exports',
  247. 'false',
  248. 'finalization',
  249. 'finally',
  250. 'for',
  251. 'function',
  252. 'goto',
  253. 'if',
  254. 'implementation',
  255. 'in',
  256. 'inherited',
  257. 'initialization',
  258. 'inline',
  259. 'interface',
  260. 'is',
  261. 'label',
  262. 'library',
  263. 'mod',
  264. 'nil',
  265. 'not',
  266. 'object',
  267. 'of',
  268. 'on',
  269. 'operator',
  270. 'or',
  271. 'packed',
  272. 'procedure',
  273. 'program',
  274. 'property',
  275. 'raise',
  276. 'record',
  277. 'repeat',
  278. 'resourcestring',
  279. 'self',
  280. 'set',
  281. 'shl',
  282. 'shr',
  283. // 'string',
  284. 'then',
  285. 'threadvar',
  286. 'to',
  287. 'true',
  288. 'try',
  289. 'type',
  290. 'unit',
  291. 'until',
  292. 'uses',
  293. 'var',
  294. 'while',
  295. 'with',
  296. 'xor'
  297. );
  298. implementation
  299. type
  300. TIncludeStackItem = class
  301. SourceFile: TLineReader;
  302. Filename: string;
  303. Token: TToken;
  304. TokenString: string;
  305. Line: string;
  306. Row: Integer;
  307. TokenStr: PChar;
  308. end;
  309. constructor TFileLineReader.Create(const AFilename: string);
  310. begin
  311. inherited Create;
  312. Assign(FTextFile, AFilename);
  313. Reset(FTextFile);
  314. FileOpened := true;
  315. end;
  316. destructor TFileLineReader.Destroy;
  317. begin
  318. if FileOpened then
  319. Close(FTextFile);
  320. inherited Destroy;
  321. end;
  322. function TFileLineReader.IsEOF: Boolean;
  323. begin
  324. Result := EOF(FTextFile);
  325. end;
  326. function TFileLineReader.ReadLine: string;
  327. begin
  328. ReadLn(FTextFile, Result);
  329. end;
  330. constructor TFileResolver.Create;
  331. begin
  332. inherited Create;
  333. FIncludePaths := TStringList.Create;
  334. end;
  335. destructor TFileResolver.Destroy;
  336. begin
  337. FIncludePaths.Free;
  338. inherited Destroy;
  339. end;
  340. procedure TFileResolver.AddIncludePath(const APath: string);
  341. begin
  342. FIncludePaths.Add(IncludeTrailingPathDelimiter(ExpandFileName(APath)));
  343. end;
  344. function TFileResolver.FindSourceFile(const AName: string): TLineReader;
  345. begin
  346. if not FileExists(AName) then
  347. Raise EFileNotFoundError.create(Aname)
  348. else
  349. try
  350. Result := TFileLineReader.Create(AName);
  351. except
  352. Result := nil;
  353. end;
  354. end;
  355. function TFileResolver.FindIncludeFile(const AName: string): TLineReader;
  356. var
  357. i: Integer;
  358. FN : string;
  359. begin
  360. Result := nil;
  361. If FileExists(AName) then
  362. Result := TFileLineReader.Create(AName)
  363. else
  364. begin
  365. I:=0;
  366. While (Result=Nil) and (I<FIncludePaths.Count) do
  367. begin
  368. Try
  369. FN:=FIncludePaths[i]+AName;
  370. If FileExists(FN) then
  371. Result := TFileLineReader.Create(FN);
  372. except
  373. Result:=Nil;
  374. end;
  375. Inc(I);
  376. end;
  377. end;
  378. end;
  379. constructor TPascalScanner.Create(AFileResolver: TFileResolver);
  380. begin
  381. inherited Create;
  382. FFileResolver := AFileResolver;
  383. FIncludeStack := TList.Create;
  384. FDefines := TStringList.Create;
  385. end;
  386. destructor TPascalScanner.Destroy;
  387. begin
  388. FDefines.Free;
  389. // Dont' free the first element, because it is CurSourceFile
  390. while FIncludeStack.Count > 1 do
  391. begin
  392. TFileResolver(FIncludeStack[1]).Free;
  393. FIncludeStack.Delete(1);
  394. end;
  395. FIncludeStack.Free;
  396. CurSourceFile.Free;
  397. inherited Destroy;
  398. end;
  399. procedure TPascalScanner.OpenFile(const AFilename: string);
  400. begin
  401. FCurSourceFile := FileResolver.FindSourceFile(AFilename);
  402. FCurFilename := AFilename;
  403. end;
  404. function TPascalScanner.FetchToken: TToken;
  405. var
  406. IncludeStackItem: TIncludeStackItem;
  407. begin
  408. while true do
  409. begin
  410. Result := DoFetchToken;
  411. if FCurToken = tkEOF then
  412. if FIncludeStack.Count > 0 then
  413. begin
  414. CurSourceFile.Free;
  415. IncludeStackItem :=
  416. TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
  417. FIncludeStack.Delete(FIncludeStack.Count - 1);
  418. FCurSourceFile := IncludeStackItem.SourceFile;
  419. FCurFilename := IncludeStackItem.Filename;
  420. FCurToken := IncludeStackItem.Token;
  421. FCurTokenString := IncludeStackItem.TokenString;
  422. FCurLine := IncludeStackItem.Line;
  423. FCurRow := IncludeStackItem.Row;
  424. TokenStr := IncludeStackItem.TokenStr;
  425. IncludeStackItem.Free;
  426. Result := FCurToken;
  427. end else
  428. break
  429. else
  430. if not PPIsSkipping then
  431. break;
  432. end;
  433. end;
  434. procedure TPascalScanner.Error(const Msg: string);
  435. begin
  436. raise EScannerError.Create(Msg);
  437. end;
  438. procedure TPascalScanner.Error(const Msg: string; Args: array of Const);
  439. begin
  440. raise EScannerError.CreateFmt(Msg, Args);
  441. end;
  442. function TPascalScanner.DoFetchToken: TToken;
  443. function FetchLine: Boolean;
  444. begin
  445. if CurSourceFile.IsEOF then
  446. begin
  447. FCurLine := '';
  448. TokenStr := nil;
  449. Result := false;
  450. end else
  451. begin
  452. FCurLine := CurSourceFile.ReadLine;
  453. TokenStr := PChar(CurLine);
  454. Result := true;
  455. Inc(FCurRow);
  456. end;
  457. end;
  458. var
  459. TokenStart, CurPos: PChar;
  460. i: TToken;
  461. OldLength, SectionLength, NestingLevel, Index: Integer;
  462. Directive, Param: string;
  463. IncludeStackItem: TIncludeStackItem;
  464. begin
  465. if TokenStr = nil then
  466. if not FetchLine then
  467. begin
  468. Result := tkEOF;
  469. FCurToken := Result;
  470. exit;
  471. end;
  472. FCurTokenString := '';
  473. case TokenStr[0] of
  474. #0: // Empty line
  475. begin
  476. FetchLine;
  477. Result := tkWhitespace;
  478. end;
  479. #9, ' ':
  480. begin
  481. Result := tkWhitespace;
  482. repeat
  483. Inc(TokenStr);
  484. if TokenStr[0] = #0 then
  485. if not FetchLine then
  486. begin
  487. FCurToken := Result;
  488. exit;
  489. end;
  490. until not (TokenStr[0] in [#9, ' ']);
  491. end;
  492. '#':
  493. begin
  494. TokenStart := TokenStr;
  495. Inc(TokenStr);
  496. if TokenStr[0] = '$' then
  497. begin
  498. Inc(TokenStr);
  499. repeat
  500. Inc(TokenStr);
  501. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'F']);
  502. end else
  503. repeat
  504. Inc(TokenStr);
  505. until not (TokenStr[0] in ['0'..'9']);
  506. SectionLength := TokenStr - TokenStart;
  507. SetLength(FCurTokenString, SectionLength);
  508. if SectionLength > 0 then
  509. Move(TokenStart^, FCurTokenString[1], SectionLength);
  510. Result := tkChar;
  511. end;
  512. '&':
  513. begin
  514. TokenStart := TokenStr;
  515. repeat
  516. Inc(TokenStr);
  517. until not (TokenStr[0] in ['0'..'7']);
  518. SectionLength := TokenStr - TokenStart;
  519. SetLength(FCurTokenString, SectionLength);
  520. if SectionLength > 0 then
  521. Move(TokenStart^, FCurTokenString[1], SectionLength);
  522. Result := tkNumber;
  523. end;
  524. '$':
  525. begin
  526. TokenStart := TokenStr;
  527. repeat
  528. Inc(TokenStr);
  529. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'F']);
  530. SectionLength := TokenStr - TokenStart;
  531. SetLength(FCurTokenString, SectionLength);
  532. if SectionLength > 0 then
  533. Move(TokenStart^, FCurTokenString[1], SectionLength);
  534. Result := tkNumber;
  535. end;
  536. '%':
  537. begin
  538. TokenStart := TokenStr;
  539. repeat
  540. Inc(TokenStr);
  541. until not (TokenStr[0] in ['0','1']);
  542. SectionLength := TokenStr - TokenStart;
  543. SetLength(FCurTokenString, SectionLength);
  544. if SectionLength > 0 then
  545. Move(TokenStart^, FCurTokenString[1], SectionLength);
  546. Result := tkNumber;
  547. end;
  548. '''':
  549. begin
  550. Inc(TokenStr);
  551. TokenStart := TokenStr;
  552. OldLength := 0;
  553. FCurTokenString := '';
  554. while true do
  555. begin
  556. if TokenStr[0] = '''' then
  557. if TokenStr[1] = '''' then
  558. begin
  559. SectionLength := TokenStr - TokenStart + 1;
  560. SetLength(FCurTokenString, OldLength + SectionLength);
  561. if SectionLength > 0 then
  562. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  563. Inc(OldLength, SectionLength);
  564. Inc(TokenStr);
  565. TokenStart := TokenStr+1;
  566. end else
  567. break;
  568. if TokenStr[0] = #0 then
  569. Error(SErrOpenString);
  570. Inc(TokenStr);
  571. end;
  572. SectionLength := TokenStr - TokenStart;
  573. SetLength(FCurTokenString, OldLength + SectionLength);
  574. if SectionLength > 0 then
  575. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  576. Inc(TokenStr);
  577. Result := tkString;
  578. end;
  579. '(':
  580. begin
  581. Inc(TokenStr);
  582. if TokenStr[0] = '*' then
  583. begin
  584. // Old-style multi-line comment
  585. Inc(TokenStr);
  586. while (TokenStr[0] <> '*') or (TokenStr[1] <> ')') do
  587. begin
  588. if TokenStr[0] = #0 then
  589. begin
  590. if not FetchLine then
  591. begin
  592. Result := tkEOF;
  593. FCurToken := Result;
  594. exit;
  595. end;
  596. end else
  597. Inc(TokenStr);
  598. end;
  599. Inc(TokenStr, 2);
  600. Result := tkComment;
  601. end else
  602. Result := tkBraceOpen;
  603. end;
  604. ')':
  605. begin
  606. Inc(TokenStr);
  607. Result := tkBraceClose;
  608. end;
  609. '*':
  610. begin
  611. Inc(TokenStr);
  612. if TokenStr[0] = '*' then
  613. begin
  614. Inc(TokenStr);
  615. Result := tkPower;
  616. end else
  617. Result := tkMul;
  618. end;
  619. '+':
  620. begin
  621. Inc(TokenStr);
  622. Result := tkPlus;
  623. end;
  624. ',':
  625. begin
  626. Inc(TokenStr);
  627. Result := tkComma;
  628. end;
  629. '-':
  630. begin
  631. Inc(TokenStr);
  632. Result := tkMinus;
  633. end;
  634. '.':
  635. begin
  636. Inc(TokenStr);
  637. if TokenStr[0] = '.' then
  638. begin
  639. Inc(TokenStr);
  640. Result := tkDotDot;
  641. end else
  642. Result := tkDot;
  643. end;
  644. '/':
  645. begin
  646. Inc(TokenStr);
  647. if TokenStr[0] = '/' then // Single-line comment
  648. begin
  649. Inc(TokenStr);
  650. TokenStart := TokenStr;
  651. FCurTokenString := '';
  652. while TokenStr[0] <> #0 do
  653. Inc(TokenStr);
  654. SectionLength := TokenStr - TokenStart;
  655. SetLength(FCurTokenString, SectionLength);
  656. if SectionLength > 0 then
  657. Move(TokenStart^, FCurTokenString[1], SectionLength);
  658. Result := tkComment;
  659. //WriteLn('Einzeiliger Kommentar: "', CurTokenString, '"');
  660. end else
  661. Result := tkDivision;
  662. end;
  663. '0'..'9':
  664. begin
  665. TokenStart := TokenStr;
  666. while true do
  667. begin
  668. Inc(TokenStr);
  669. case TokenStr[0] of
  670. '.':
  671. begin
  672. if TokenStr[1] in ['0'..'9', 'e', 'E'] then
  673. begin
  674. Inc(TokenStr);
  675. repeat
  676. Inc(TokenStr);
  677. until not (TokenStr[0] in ['0'..'9', 'e', 'E']);
  678. end;
  679. break;
  680. end;
  681. '0'..'9': ;
  682. 'e', 'E':
  683. begin
  684. Inc(TokenStr);
  685. if TokenStr[0] = '-' then
  686. Inc(TokenStr);
  687. while TokenStr[0] in ['0'..'9'] do
  688. Inc(TokenStr);
  689. break;
  690. end;
  691. else
  692. break;
  693. end;
  694. end;
  695. SectionLength := TokenStr - TokenStart;
  696. SetLength(FCurTokenString, SectionLength);
  697. if SectionLength > 0 then
  698. Move(TokenStart^, FCurTokenString[1], SectionLength);
  699. Result := tkNumber;
  700. end;
  701. ':':
  702. begin
  703. Inc(TokenStr);
  704. if TokenStr[0] = '=' then
  705. begin
  706. Inc(TokenStr);
  707. Result := tkAssign;
  708. end else
  709. Result := tkColon;
  710. end;
  711. ';':
  712. begin
  713. Inc(TokenStr);
  714. Result := tkSemicolon;
  715. end;
  716. '<':
  717. begin
  718. Inc(TokenStr);
  719. if TokenStr[0] = '>' then
  720. begin
  721. Inc(TokenStr);
  722. Result := tkNotEqual;
  723. end else if TokenStr[0] = '=' then
  724. begin
  725. Inc(TokenStr);
  726. Result := tkLessEqualThan;
  727. end else
  728. Result := tkLessThan;
  729. end;
  730. '=':
  731. begin
  732. Inc(TokenStr);
  733. Result := tkEqual;
  734. end;
  735. '>':
  736. begin
  737. Inc(TokenStr);
  738. if TokenStr[0] = '=' then
  739. begin
  740. Inc(TokenStr);
  741. Result := tkGreaterEqualThan;
  742. end else if TokenStr[0] = '<' then
  743. begin
  744. Inc(TokenStr);
  745. Result := tkSymmetricalDifference;
  746. end else
  747. Result := tkGreaterThan;
  748. end;
  749. '@':
  750. begin
  751. Inc(TokenStr);
  752. Result := tkAt;
  753. end;
  754. '[':
  755. begin
  756. Inc(TokenStr);
  757. Result := tkSquaredBraceOpen;
  758. end;
  759. ']':
  760. begin
  761. Inc(TokenStr);
  762. Result := tkSquaredBraceClose;
  763. end;
  764. '^':
  765. begin
  766. Inc(TokenStr);
  767. Result := tkCaret;
  768. end;
  769. '{': // Multi-line comment
  770. begin
  771. Inc(TokenStr);
  772. TokenStart := TokenStr;
  773. FCurTokenString := '';
  774. OldLength := 0;
  775. NestingLevel := 0;
  776. while (TokenStr[0] <> '}') or (NestingLevel > 0) do
  777. begin
  778. if TokenStr[0] = #0 then
  779. begin
  780. SectionLength := TokenStr - TokenStart + 1;
  781. SetLength(FCurTokenString, OldLength + SectionLength);
  782. if SectionLength > 1 then
  783. Move(TokenStart^, FCurTokenString[OldLength + 1],
  784. SectionLength - 1);
  785. Inc(OldLength, SectionLength);
  786. FCurTokenString[OldLength] := #10;
  787. if not FetchLine then
  788. begin
  789. Result := tkEOF;
  790. FCurToken := Result;
  791. exit;
  792. end;
  793. TokenStart := TokenStr;
  794. end else
  795. begin
  796. if not(po_delphi in Options) and (TokenStr[0] = '{') then
  797. Inc(NestingLevel)
  798. else if TokenStr[0] = '}' then
  799. Dec(NestingLevel);
  800. Inc(TokenStr);
  801. end;
  802. end;
  803. SectionLength := TokenStr - TokenStart;
  804. SetLength(FCurTokenString, OldLength + SectionLength);
  805. if SectionLength > 0 then
  806. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  807. Inc(TokenStr);
  808. Result := tkComment;
  809. //WriteLn('Kommentar: "', CurTokenString, '"');
  810. if (Length(CurTokenString) > 0) and (CurTokenString[1] = '$') then
  811. begin
  812. TokenStart := @CurTokenString[2];
  813. CurPos := TokenStart;
  814. while (CurPos[0] <> ' ') and (CurPos[0] <> #0) do
  815. Inc(CurPos);
  816. SectionLength := CurPos - TokenStart;
  817. SetLength(Directive, SectionLength);
  818. if SectionLength > 0 then
  819. begin
  820. Move(TokenStart^, Directive[1], SectionLength);
  821. Directive := UpperCase(Directive);
  822. if CurPos[0] <> #0 then
  823. begin
  824. TokenStart := CurPos + 1;
  825. CurPos := TokenStart;
  826. while CurPos[0] <> #0 do
  827. Inc(CurPos);
  828. SectionLength := CurPos - TokenStart;
  829. SetLength(Param, SectionLength);
  830. if SectionLength > 0 then
  831. Move(TokenStart^, Param[1], SectionLength);
  832. end else
  833. Param := '';
  834. // WriteLn('Direktive: "', Directive, '", Param: "', Param, '"');
  835. if (Directive = 'I') or (Directive = 'INCLUDE') then
  836. begin
  837. if not PPIsSkipping then
  838. begin
  839. IncludeStackItem := TIncludeStackItem.Create;
  840. IncludeStackItem.SourceFile := CurSourceFile;
  841. IncludeStackItem.Filename := CurFilename;
  842. IncludeStackItem.Token := CurToken;
  843. IncludeStackItem.TokenString := CurTokenString;
  844. IncludeStackItem.Line := CurLine;
  845. IncludeStackItem.Row := CurRow;
  846. IncludeStackItem.TokenStr := TokenStr;
  847. FIncludeStack.Add(IncludeStackItem);
  848. FCurSourceFile := FileResolver.FindIncludeFile(Param);
  849. if not Assigned(CurSourceFile) then
  850. Error(SErrIncludeFileNotFound, [Param]);
  851. FCurFilename := Param;
  852. FCurRow := 0;
  853. end;
  854. end else if Directive = 'DEFINE' then
  855. begin
  856. if not PPIsSkipping then
  857. begin
  858. Param := UpperCase(Param);
  859. if Defines.IndexOf(Param) < 0 then
  860. Defines.Add(Param);
  861. end;
  862. end else if Directive = 'UNDEF' then
  863. begin
  864. if not PPIsSkipping then
  865. begin
  866. Param := UpperCase(Param);
  867. Index := Defines.IndexOf(Param);
  868. if Index >= 0 then
  869. Defines.Delete(Index);
  870. end;
  871. end else if Directive = 'IFDEF' then
  872. begin
  873. if PPSkipStackIndex = High(PPSkipModeStack) then
  874. Error(SErrIfXXXNestingLimitReached);
  875. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  876. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  877. Inc(PPSkipStackIndex);
  878. if PPIsSkipping then
  879. begin
  880. PPSkipMode := ppSkipAll;
  881. PPIsSkipping := true;
  882. end else
  883. begin
  884. Param := UpperCase(Param);
  885. Index := Defines.IndexOf(Param);
  886. if Index < 0 then
  887. begin
  888. PPSkipMode := ppSkipIfBranch;
  889. PPIsSkipping := true;
  890. end else
  891. PPSkipMode := ppSkipElseBranch;
  892. end;
  893. end else if Directive = 'IFNDEF' then
  894. begin
  895. if PPSkipStackIndex = High(PPSkipModeStack) then
  896. Error(SErrIfXXXNestingLimitReached);
  897. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  898. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  899. Inc(PPSkipStackIndex);
  900. if PPIsSkipping then
  901. begin
  902. PPSkipMode := ppSkipAll;
  903. PPIsSkipping := true;
  904. end else
  905. begin
  906. Param := UpperCase(Param);
  907. Index := Defines.IndexOf(Param);
  908. if Index >= 0 then
  909. begin
  910. PPSkipMode := ppSkipIfBranch;
  911. PPIsSkipping := true;
  912. end else
  913. PPSkipMode := ppSkipElseBranch;
  914. end;
  915. end else if Directive = 'IFOPT' then
  916. begin
  917. if PPSkipStackIndex = High(PPSkipModeStack) then
  918. Error(SErrIfXXXNestingLimitReached);
  919. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  920. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  921. Inc(PPSkipStackIndex);
  922. if PPIsSkipping then
  923. begin
  924. PPSkipMode := ppSkipAll;
  925. PPIsSkipping := true;
  926. end else
  927. begin
  928. { !!!: Currently, options are not supported, so they are just
  929. assumed as not being set. }
  930. PPSkipMode := ppSkipIfBranch;
  931. PPIsSkipping := true;
  932. end;
  933. end else if Directive = 'IF' then
  934. begin
  935. if PPSkipStackIndex = High(PPSkipModeStack) then
  936. Error(SErrIfXXXNestingLimitReached);
  937. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  938. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  939. Inc(PPSkipStackIndex);
  940. if PPIsSkipping then
  941. begin
  942. PPSkipMode := ppSkipAll;
  943. PPIsSkipping := true;
  944. end else
  945. begin
  946. { !!!: Currently, expressions are not supported, so they are
  947. just assumed as evaluating to false. }
  948. PPSkipMode := ppSkipIfBranch;
  949. PPIsSkipping := true;
  950. end;
  951. end else if Directive = 'ELSE' then
  952. begin
  953. if PPSkipStackIndex = 0 then
  954. Error(SErrInvalidPPElse);
  955. if PPSkipMode = ppSkipIfBranch then
  956. PPIsSkipping := false
  957. else if PPSkipMode = ppSkipElseBranch then
  958. PPIsSkipping := true;
  959. end else if Directive = 'ENDIF' then
  960. begin
  961. if PPSkipStackIndex = 0 then
  962. Error(SErrInvalidPPEndif);
  963. Dec(PPSkipStackIndex);
  964. PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
  965. PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
  966. end;
  967. end else
  968. Directive := '';
  969. end;
  970. end;
  971. 'A'..'Z', 'a'..'z', '_':
  972. begin
  973. TokenStart := TokenStr;
  974. repeat
  975. Inc(TokenStr);
  976. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  977. SectionLength := TokenStr - TokenStart;
  978. SetLength(FCurTokenString, SectionLength);
  979. if SectionLength > 0 then
  980. Move(TokenStart^, FCurTokenString[1], SectionLength);
  981. // Check if this is a keyword or identifier
  982. // !!!: Optimize this!
  983. for i := tkAbsolute to tkXOR do
  984. if CompareText(CurTokenString, TokenInfos[i]) = 0 then
  985. begin
  986. Result := i;
  987. FCurToken := Result;
  988. exit;
  989. end;
  990. Result := tkIdentifier;
  991. end;
  992. else
  993. Error(SErrInvalidCharacter, [TokenStr[0]]);
  994. end;
  995. FCurToken := Result;
  996. end;
  997. function TPascalScanner.GetCurColumn: Integer;
  998. begin
  999. Result := TokenStr - PChar(CurLine);
  1000. end;
  1001. end.