pscanner.pp 27 KB

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