pscanner.pp 22 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. {
  2. $Id$
  3. This file is part of the Free Component Library
  4. Pascal source lexical scanner
  5. Copyright (c) 2003 by
  6. Areca Systems GmbH / Sebastian Guenther, [email protected]
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit PScanner;
  14. interface
  15. uses SysUtils, Classes;
  16. resourcestring
  17. SErrInvalidCharacter = 'Invalid character ''%s''';
  18. SErrOpenString = 'String exceeds end of line';
  19. SErrIncludeFileNotFound = 'Could not find include file ''%s''';
  20. SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
  21. SErrInvalidPPElse = '$ELSE without matching $IFxxx';
  22. SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
  23. type
  24. TToken = (
  25. tkEOF,
  26. tkWhitespace,
  27. tkComment,
  28. tkIdentifier,
  29. tkString,
  30. tkNumber,
  31. tkChar,
  32. // Simple (one-character) tokens
  33. tkBraceOpen, // '('
  34. tkBraceClose, // ')'
  35. tkMul, // '*'
  36. tkPlus, // '+'
  37. tkComma, // ','
  38. tkMinus, // '-'
  39. tkDot, // '.'
  40. tkDivision, // '/'
  41. tkColon, // ':'
  42. tkSemicolon, // ';'
  43. tkLessThan, // '<'
  44. tkEqual, // '='
  45. tkGreaterThan, // '>'
  46. tkAt, // '@'
  47. tkSquaredBraceOpen, // '['
  48. tkSquaredBraceClose,// ']'
  49. tkCaret, // '^'
  50. // Two-character tokens
  51. tkDotDot, // '..'
  52. tkAssign, // ':='
  53. tkNotEqual, // '<>'
  54. // Reserved words
  55. tkabsolute,
  56. tkand,
  57. tkarray,
  58. tkas,
  59. tkasm,
  60. tkbegin,
  61. tkbreak,
  62. tkcase,
  63. tkclass,
  64. tkconst,
  65. tkconstructor,
  66. tkcontinue,
  67. tkdestructor,
  68. tkdispose,
  69. tkdiv,
  70. tkdo,
  71. tkdownto,
  72. tkelse,
  73. tkend,
  74. tkexcept,
  75. tkexit,
  76. tkexports,
  77. tkfalse,
  78. tkfinalization,
  79. tkfinally,
  80. tkfor,
  81. tkfunction,
  82. tkgoto,
  83. tkif,
  84. tkimplementation,
  85. tkin,
  86. tkinherited,
  87. tkinitialization,
  88. tkinline,
  89. tkinterface,
  90. tkis,
  91. tklabel,
  92. tklibrary,
  93. tkmod,
  94. tknew,
  95. tknil,
  96. tknot,
  97. tkobject,
  98. tkof,
  99. tkon,
  100. tkoperator,
  101. tkor,
  102. tkpacked,
  103. tkprocedure,
  104. tkprogram,
  105. tkproperty,
  106. tkraise,
  107. tkrecord,
  108. tkrepeat,
  109. tkResourceString,
  110. tkself,
  111. tkset,
  112. tkshl,
  113. tkshr,
  114. // tkstring,
  115. tkthen,
  116. tkto,
  117. tktrue,
  118. tktry,
  119. tktype,
  120. tkunit,
  121. tkuntil,
  122. tkuses,
  123. tkvar,
  124. tkwhile,
  125. tkwith,
  126. tkxor);
  127. TLineReader = class
  128. public
  129. function IsEOF: Boolean; virtual; abstract;
  130. function ReadLine: String; virtual; abstract;
  131. end;
  132. TFileLineReader = class(TLineReader)
  133. private
  134. FTextFile: Text;
  135. FileOpened: Boolean;
  136. public
  137. constructor Create(const AFilename: String);
  138. destructor Destroy; override;
  139. function IsEOF: Boolean; override;
  140. function ReadLine: String; override;
  141. end;
  142. TFileResolver = class
  143. private
  144. FIncludePaths: TStringList;
  145. public
  146. constructor Create;
  147. destructor Destroy; override;
  148. procedure AddIncludePath(const APath: String);
  149. function FindSourceFile(const AName: String): TLineReader;
  150. function FindIncludeFile(const AName: String): TLineReader;
  151. end;
  152. EScannerError = class(Exception);
  153. TPascalScannerPPSkipMode = (ppSkipNone, ppSkipIfBranch, ppSkipElseBranch,
  154. ppSkipAll);
  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. constructor Create(AFileResolver: TFileResolver);
  180. destructor Destroy; override;
  181. procedure OpenFile(const AFilename: String);
  182. function FetchToken: TToken;
  183. property FileResolver: TFileResolver read FFileResolver;
  184. property CurSourceFile: TLineReader read FCurSourceFile;
  185. property CurFilename: String read FCurFilename;
  186. property CurLine: String read FCurLine;
  187. property CurRow: Integer read FCurRow;
  188. property CurColumn: Integer read GetCurColumn;
  189. property CurToken: TToken read FCurToken;
  190. property CurTokenString: String read FCurTokenString;
  191. property Defines: TStrings read FDefines;
  192. end;
  193. const
  194. TokenInfos: array[TToken] of String = (
  195. 'EOF',
  196. 'Whitespace',
  197. 'Comment',
  198. 'Identifier',
  199. 'String',
  200. 'Number',
  201. 'Character',
  202. '(',
  203. ')',
  204. '*',
  205. '+',
  206. ',',
  207. '-',
  208. '.',
  209. '/',
  210. ':',
  211. ';',
  212. '<',
  213. '=',
  214. '>',
  215. '@',
  216. '[',
  217. ']',
  218. '^',
  219. '..',
  220. ':=',
  221. '<>',
  222. // Reserved words
  223. 'absolute',
  224. 'and',
  225. 'array',
  226. 'as',
  227. 'asm',
  228. 'begin',
  229. 'break',
  230. 'case',
  231. 'class',
  232. 'const',
  233. 'constructor',
  234. 'continue',
  235. 'destructor',
  236. 'dispose',
  237. 'div',
  238. 'do',
  239. 'downto',
  240. 'else',
  241. 'end',
  242. 'except',
  243. 'exit',
  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. 'new',
  263. 'nil',
  264. 'not',
  265. 'object',
  266. 'of',
  267. 'on',
  268. 'operator',
  269. 'or',
  270. 'packed',
  271. 'procedure',
  272. 'program',
  273. 'property',
  274. 'raise',
  275. 'record',
  276. 'repeat',
  277. 'resourcestring',
  278. 'self',
  279. 'set',
  280. 'shl',
  281. 'shr',
  282. // 'string',
  283. 'then',
  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(APath));
  341. end;
  342. function TFileResolver.FindSourceFile(const AName: String): TLineReader;
  343. begin
  344. if not FileExists(AName) then
  345. Result := nil
  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. begin
  357. Result := nil;
  358. try
  359. Result := TFileLineReader.Create(AName);
  360. except
  361. for i := 0 to FIncludePaths.Count - 1 do
  362. try
  363. Result := TFileLineReader.Create(FIncludePaths[i] + AName);
  364. break;
  365. except
  366. end;
  367. end;
  368. end;
  369. constructor TPascalScanner.Create(AFileResolver: TFileResolver);
  370. begin
  371. inherited Create;
  372. FFileResolver := AFileResolver;
  373. FIncludeStack := TList.Create;
  374. FDefines := TStringList.Create;
  375. end;
  376. destructor TPascalScanner.Destroy;
  377. begin
  378. FDefines.Free;
  379. // Dont' free the first element, because it is CurSourceFile
  380. while FIncludeStack.Count > 1 do
  381. begin
  382. TFileResolver(FIncludeStack[1]).Free;
  383. FIncludeStack.Delete(1);
  384. end;
  385. FIncludeStack.Free;
  386. CurSourceFile.Free;
  387. inherited Destroy;
  388. end;
  389. procedure TPascalScanner.OpenFile(const AFilename: String);
  390. begin
  391. FCurSourceFile := FileResolver.FindSourceFile(AFilename);
  392. FCurFilename := AFilename;
  393. end;
  394. function TPascalScanner.FetchToken: TToken;
  395. var
  396. IncludeStackItem: TIncludeStackItem;
  397. begin
  398. while True do
  399. begin
  400. Result := DoFetchToken;
  401. if FCurToken = tkEOF then
  402. if FIncludeStack.Count > 0 then
  403. begin
  404. CurSourceFile.Free;
  405. IncludeStackItem :=
  406. TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
  407. FIncludeStack.Delete(FIncludeStack.Count - 1);
  408. FCurSourceFile := IncludeStackItem.SourceFile;
  409. FCurFilename := IncludeStackItem.Filename;
  410. FCurToken := IncludeStackItem.Token;
  411. FCurTokenString := IncludeStackItem.TokenString;
  412. FCurLine := IncludeStackItem.Line;
  413. FCurRow := IncludeStackItem.Row;
  414. TokenStr := IncludeStackItem.TokenStr;
  415. IncludeStackItem.Free;
  416. Result := FCurToken;
  417. end else
  418. break
  419. else
  420. if not PPIsSkipping then
  421. break;
  422. end;
  423. end;
  424. procedure TPascalScanner.Error(const Msg: String);
  425. begin
  426. raise EScannerError.Create(Msg);
  427. end;
  428. procedure TPascalScanner.Error(const Msg: String; Args: array of Const);
  429. begin
  430. raise EScannerError.CreateFmt(Msg, Args);
  431. end;
  432. function TPascalScanner.DoFetchToken: TToken;
  433. function FetchLine: Boolean;
  434. begin
  435. if CurSourceFile.IsEOF then
  436. begin
  437. FCurLine := '';
  438. TokenStr := nil;
  439. Result := False;
  440. end else
  441. begin
  442. FCurLine := CurSourceFile.ReadLine;
  443. TokenStr := PChar(CurLine);
  444. Result := True;
  445. Inc(FCurRow);
  446. end;
  447. end;
  448. var
  449. TokenStart, CurPos: PChar;
  450. i: TToken;
  451. OldLength, SectionLength, NestingLevel, Index: Integer;
  452. Directive, Param: String;
  453. IncludeStackItem: TIncludeStackItem;
  454. begin
  455. if TokenStr = nil then
  456. if not FetchLine then
  457. begin
  458. Result := tkEOF;
  459. FCurToken := Result;
  460. exit;
  461. end;
  462. FCurTokenString := '';
  463. case TokenStr[0] of
  464. #0: // Empty line
  465. begin
  466. FetchLine;
  467. Result := tkWhitespace;
  468. end;
  469. #9, ' ':
  470. begin
  471. Result := tkWhitespace;
  472. repeat
  473. Inc(TokenStr);
  474. if TokenStr[0] = #0 then
  475. if not FetchLine then
  476. begin
  477. FCurToken := Result;
  478. exit;
  479. end;
  480. until not (TokenStr[0] in [#9, ' ']);
  481. end;
  482. '#':
  483. begin
  484. TokenStart := TokenStr;
  485. Inc(TokenStr);
  486. if TokenStr[0] = '$' then
  487. begin
  488. Inc(TokenStr);
  489. repeat
  490. Inc(TokenStr);
  491. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'F']);
  492. end else
  493. repeat
  494. Inc(TokenStr);
  495. until not (TokenStr[0] in ['0'..'9']);
  496. SectionLength := TokenStr - TokenStart;
  497. SetLength(FCurTokenString, SectionLength);
  498. if SectionLength > 0 then
  499. Move(TokenStart^, FCurTokenString[1], SectionLength);
  500. Result := tkChar;
  501. end;
  502. '$':
  503. begin
  504. TokenStart := TokenStr;
  505. repeat
  506. Inc(TokenStr);
  507. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'F']);
  508. SectionLength := TokenStr - TokenStart;
  509. SetLength(FCurTokenString, SectionLength);
  510. if SectionLength > 0 then
  511. Move(TokenStart^, FCurTokenString[1], SectionLength);
  512. Result := tkNumber;
  513. end;
  514. '''':
  515. begin
  516. Inc(TokenStr);
  517. TokenStart := TokenStr;
  518. OldLength := 0;
  519. FCurTokenString := '';
  520. while True do
  521. begin
  522. if TokenStr[0] = '''' then
  523. if TokenStr[1] = '''' then
  524. begin
  525. SectionLength := TokenStr - TokenStart + 1;
  526. SetLength(FCurTokenString, OldLength + SectionLength);
  527. if SectionLength > 1 then
  528. Move(TokenStart^, FCurTokenString[OldLength + 1],
  529. SectionLength);
  530. Inc(OldLength, SectionLength);
  531. Inc(TokenStr);
  532. TokenStart := TokenStr;
  533. end else
  534. break;
  535. if TokenStr[0] = #0 then
  536. Error(SErrOpenString);
  537. Inc(TokenStr);
  538. end;
  539. SectionLength := TokenStr - TokenStart;
  540. SetLength(FCurTokenString, OldLength + SectionLength);
  541. if SectionLength > 0 then
  542. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  543. Inc(TokenStr);
  544. Result := tkString;
  545. end;
  546. '(':
  547. begin
  548. Inc(TokenStr);
  549. if TokenStr[0] = '*' then
  550. begin
  551. // Old-style multi-line comment
  552. Inc(TokenStr);
  553. while (TokenStr[0] <> '*') or (TokenStr[1] <> ')') do
  554. begin
  555. if TokenStr[0] = #0 then
  556. begin
  557. if not FetchLine then
  558. begin
  559. Result := tkEOF;
  560. FCurToken := Result;
  561. exit;
  562. end;
  563. end else
  564. Inc(TokenStr);
  565. end;
  566. Inc(TokenStr, 2);
  567. Result := tkComment;
  568. end else
  569. Result := tkBraceOpen;
  570. end;
  571. ')':
  572. begin
  573. Inc(TokenStr);
  574. Result := tkBraceClose;
  575. end;
  576. '*':
  577. begin
  578. Inc(TokenStr);
  579. Result := tkMul;
  580. end;
  581. '+':
  582. begin
  583. Inc(TokenStr);
  584. Result := tkPlus;
  585. end;
  586. ',':
  587. begin
  588. Inc(TokenStr);
  589. Result := tkComma;
  590. end;
  591. '-':
  592. begin
  593. Inc(TokenStr);
  594. Result := tkMinus;
  595. end;
  596. '.':
  597. begin
  598. Inc(TokenStr);
  599. if TokenStr[0] = '.' then
  600. begin
  601. Inc(TokenStr);
  602. Result := tkDotDot;
  603. end else
  604. Result := tkDot;
  605. end;
  606. '/':
  607. begin
  608. Inc(TokenStr);
  609. if TokenStr[0] = '/' then // Single-line comment
  610. begin
  611. Inc(TokenStr);
  612. TokenStart := TokenStr;
  613. FCurTokenString := '';
  614. while TokenStr[0] <> #0 do
  615. Inc(TokenStr);
  616. SectionLength := TokenStr - TokenStart;
  617. SetLength(FCurTokenString, SectionLength);
  618. if SectionLength > 0 then
  619. Move(TokenStart^, FCurTokenString[1], SectionLength);
  620. Result := tkComment;
  621. //WriteLn('Einzeiliger Kommentar: "', CurTokenString, '"');
  622. end else
  623. Result := tkDivision;
  624. end;
  625. '0'..'9':
  626. begin
  627. TokenStart := TokenStr;
  628. while True do
  629. begin
  630. Inc(TokenStr);
  631. case TokenStr[0] of
  632. '.':
  633. begin
  634. if TokenStr[1] in ['0'..'9', 'e', 'E'] then
  635. begin
  636. Inc(TokenStr);
  637. repeat
  638. Inc(TokenStr);
  639. until not (TokenStr[0] in ['0'..'9', 'e', 'E']);
  640. end;
  641. break;
  642. end;
  643. '0'..'9': ;
  644. 'e', 'E':
  645. begin
  646. Inc(TokenStr);
  647. if TokenStr[0] = '-' then
  648. Inc(TokenStr);
  649. while TokenStr[0] in ['0'..'9'] do
  650. Inc(TokenStr);
  651. break;
  652. end;
  653. else
  654. break;
  655. end;
  656. end;
  657. SectionLength := TokenStr - TokenStart;
  658. SetLength(FCurTokenString, SectionLength);
  659. if SectionLength > 0 then
  660. Move(TokenStart^, FCurTokenString[1], SectionLength);
  661. Result := tkNumber;
  662. end;
  663. ':':
  664. begin
  665. Inc(TokenStr);
  666. if TokenStr[0] = '=' then
  667. begin
  668. Inc(TokenStr);
  669. Result := tkAssign;
  670. end else
  671. Result := tkColon;
  672. end;
  673. ';':
  674. begin
  675. Inc(TokenStr);
  676. Result := tkSemicolon;
  677. end;
  678. '<':
  679. begin
  680. Inc(TokenStr);
  681. if TokenStr[0] = '>' then
  682. begin
  683. Inc(TokenStr);
  684. Result := tkNotEqual;
  685. end else
  686. Result := tkLessThan;
  687. end;
  688. '=':
  689. begin
  690. Inc(TokenStr);
  691. Result := tkEqual;
  692. end;
  693. '>':
  694. begin
  695. Inc(TokenStr);
  696. Result := tkGreaterThan;
  697. end;
  698. '@':
  699. begin
  700. Inc(TokenStr);
  701. Result := tkAt;
  702. end;
  703. '[':
  704. begin
  705. Inc(TokenStr);
  706. Result := tkSquaredBraceOpen;
  707. end;
  708. ']':
  709. begin
  710. Inc(TokenStr);
  711. Result := tkSquaredBraceClose;
  712. end;
  713. '^':
  714. begin
  715. Inc(TokenStr);
  716. Result := tkCaret;
  717. end;
  718. '{': // Multi-line comment
  719. begin
  720. Inc(TokenStr);
  721. TokenStart := TokenStr;
  722. FCurTokenString := '';
  723. OldLength := 0;
  724. NestingLevel := 0;
  725. while (TokenStr[0] <> '}') or (NestingLevel > 0) do
  726. begin
  727. if TokenStr[0] = #0 then
  728. begin
  729. SectionLength := TokenStr - TokenStart + 1;
  730. SetLength(FCurTokenString, OldLength + SectionLength);
  731. if SectionLength > 1 then
  732. Move(TokenStart^, FCurTokenString[OldLength + 1],
  733. SectionLength - 1);
  734. Inc(OldLength, SectionLength);
  735. FCurTokenString[OldLength] := #10;
  736. if not FetchLine then
  737. begin
  738. Result := tkEOF;
  739. FCurToken := Result;
  740. exit;
  741. end;
  742. TokenStart := TokenStr;
  743. end else
  744. begin
  745. if TokenStr[0] = '{' then
  746. Inc(NestingLevel)
  747. else if TokenStr[0] = '}' then
  748. Dec(NestingLevel);
  749. Inc(TokenStr);
  750. end;
  751. end;
  752. SectionLength := TokenStr - TokenStart;
  753. SetLength(FCurTokenString, OldLength + SectionLength);
  754. if SectionLength > 0 then
  755. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  756. Inc(TokenStr);
  757. Result := tkComment;
  758. //WriteLn('Kommentar: "', CurTokenString, '"');
  759. if (Length(CurTokenString) > 0) and (CurTokenString[1] = '$') then
  760. begin
  761. TokenStart := @CurTokenString[2];
  762. CurPos := TokenStart;
  763. while (CurPos[0] <> ' ') and (CurPos[0] <> #0) do
  764. Inc(CurPos);
  765. SectionLength := CurPos - TokenStart;
  766. SetLength(Directive, SectionLength);
  767. if SectionLength > 0 then
  768. begin
  769. Move(TokenStart^, Directive[1], SectionLength);
  770. Directive := UpperCase(Directive);
  771. if CurPos[0] <> #0 then
  772. begin
  773. TokenStart := CurPos + 1;
  774. CurPos := TokenStart;
  775. while CurPos[0] <> #0 do
  776. Inc(CurPos);
  777. SectionLength := CurPos - TokenStart;
  778. SetLength(Param, SectionLength);
  779. if SectionLength > 0 then
  780. Move(TokenStart^, Param[1], SectionLength);
  781. end else
  782. Param := '';
  783. // WriteLn('Direktive: "', Directive, '", Param: "', Param, '"');
  784. if (Directive = 'I') or (Directive = 'INCLUDE') then
  785. begin
  786. if not PPIsSkipping then
  787. begin
  788. IncludeStackItem := TIncludeStackItem.Create;
  789. IncludeStackItem.SourceFile := CurSourceFile;
  790. IncludeStackItem.Filename := CurFilename;
  791. IncludeStackItem.Token := CurToken;
  792. IncludeStackItem.TokenString := CurTokenString;
  793. IncludeStackItem.Line := CurLine;
  794. IncludeStackItem.Row := CurRow;
  795. IncludeStackItem.TokenStr := TokenStr;
  796. FIncludeStack.Add(IncludeStackItem);
  797. FCurSourceFile := FileResolver.FindIncludeFile(Param);
  798. if not Assigned(CurSourceFile) then
  799. Error(SErrIncludeFileNotFound, [Param]);
  800. FCurFilename := Param;
  801. FCurRow := 0;
  802. end;
  803. end else if Directive = 'DEFINE' then
  804. begin
  805. if not PPIsSkipping then
  806. begin
  807. Param := UpperCase(Param);
  808. if Defines.IndexOf(Param) < 0 then
  809. Defines.Add(Param);
  810. end;
  811. end else if Directive = 'UNDEF' then
  812. begin
  813. if not PPIsSkipping then
  814. begin
  815. Param := UpperCase(Param);
  816. Index := Defines.IndexOf(Param);
  817. if Index >= 0 then
  818. Defines.Delete(Index);
  819. end;
  820. end else if Directive = 'IFDEF' then
  821. begin
  822. if PPSkipStackIndex = High(PPSkipModeStack) then
  823. Error(SErrIfXXXNestingLimitReached);
  824. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  825. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  826. Inc(PPSkipStackIndex);
  827. if PPIsSkipping then
  828. begin
  829. PPSkipMode := ppSkipAll;
  830. PPIsSkipping := True;
  831. end else
  832. begin
  833. Param := UpperCase(Param);
  834. Index := Defines.IndexOf(Param);
  835. if Index < 0 then
  836. begin
  837. PPSkipMode := ppSkipIfBranch;
  838. PPIsSkipping := True;
  839. end else
  840. PPSkipMode := ppSkipElseBranch;
  841. end;
  842. end else if Directive = 'IFNDEF' then
  843. begin
  844. if PPSkipStackIndex = High(PPSkipModeStack) then
  845. Error(SErrIfXXXNestingLimitReached);
  846. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  847. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  848. Inc(PPSkipStackIndex);
  849. if PPIsSkipping then
  850. begin
  851. PPSkipMode := ppSkipAll;
  852. PPIsSkipping := True;
  853. end else
  854. begin
  855. Param := UpperCase(Param);
  856. Index := Defines.IndexOf(Param);
  857. if Index >= 0 then
  858. begin
  859. PPSkipMode := ppSkipIfBranch;
  860. PPIsSkipping := True;
  861. end else
  862. PPSkipMode := ppSkipElseBranch;
  863. end;
  864. end else if Directive = 'IFOPT' then
  865. begin
  866. if PPSkipStackIndex = High(PPSkipModeStack) then
  867. Error(SErrIfXXXNestingLimitReached);
  868. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  869. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  870. Inc(PPSkipStackIndex);
  871. if PPIsSkipping then
  872. begin
  873. PPSkipMode := ppSkipAll;
  874. PPIsSkipping := True;
  875. end else
  876. begin
  877. { !!!: Currently, options are not supported, so they are just
  878. assumed as not being set. }
  879. PPSkipMode := ppSkipIfBranch;
  880. PPIsSkipping := True;
  881. end;
  882. end else if Directive = 'ELSE' then
  883. begin
  884. if PPSkipStackIndex = 0 then
  885. Error(SErrInvalidPPElse);
  886. if PPSkipMode = ppSkipIfBranch then
  887. PPIsSkipping := False
  888. else if PPSkipMode = ppSkipElseBranch then
  889. PPIsSkipping := True;
  890. end else if Directive = 'ENDIF' then
  891. begin
  892. if PPSkipStackIndex = 0 then
  893. Error(SErrInvalidPPEndif);
  894. Dec(PPSkipStackIndex);
  895. PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
  896. PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
  897. end;
  898. end else
  899. Directive := '';
  900. end;
  901. end;
  902. 'A'..'Z', 'a'..'z', '_':
  903. begin
  904. TokenStart := TokenStr;
  905. repeat
  906. Inc(TokenStr);
  907. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  908. SectionLength := TokenStr - TokenStart;
  909. SetLength(FCurTokenString, SectionLength);
  910. if SectionLength > 0 then
  911. Move(TokenStart^, FCurTokenString[1], SectionLength);
  912. // Check if this is a keyword or identifier
  913. // !!!: Optimize this!
  914. for i := tkAbsolute to tkXOR do
  915. if CompareText(CurTokenString, TokenInfos[i]) = 0 then
  916. begin
  917. Result := i;
  918. FCurToken := Result;
  919. exit;
  920. end;
  921. Result := tkIdentifier;
  922. end;
  923. else
  924. Error(SErrInvalidCharacter, [TokenStr[0]]);
  925. end;
  926. FCurToken := Result;
  927. end;
  928. function TPascalScanner.GetCurColumn: Integer;
  929. begin
  930. Result := TokenStr - PChar(CurLine);
  931. end;
  932. end.
  933. {
  934. $Log$
  935. Revision 1.3 2003-04-04 08:01:55 michael
  936. + Patch from Jeff Pohlmeyer to read less than and larger than
  937. Revision 1.2 2003/03/27 16:32:48 sg
  938. * Added $IFxxx support
  939. * Lots of small fixes
  940. Revision 1.1 2003/03/13 21:47:42 sg
  941. * First version as part of FCL
  942. }