pscanner.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  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. type
  21. TToken = (
  22. tkEOF,
  23. tkWhitespace,
  24. tkComment,
  25. tkIdentifier,
  26. tkString,
  27. tkNumber,
  28. tkChar,
  29. // Simple (one-character) tokens
  30. tkBraceOpen, // '('
  31. tkBraceClose, // ')'
  32. tkMul, // '*'
  33. tkPlus, // '+'
  34. tkComma, // ','
  35. tkMinus, // '-'
  36. tkDot, // '.'
  37. tkDivision, // '/'
  38. tkColon, // ':'
  39. tkSemicolon, // ';'
  40. tkEqual, // '='
  41. tkSquaredBraceOpen, // '['
  42. tkSquaredBraceClose,// ']'
  43. tkCaret, // '^'
  44. // Two-character tokens
  45. tkDotDot, // '..'
  46. tkAssign, // ':='
  47. // Reserved words
  48. tkabsolute,
  49. tkand,
  50. tkarray,
  51. tkas,
  52. tkasm,
  53. tkbegin,
  54. tkbreak,
  55. tkcase,
  56. tkclass,
  57. tkconst,
  58. tkconstructor,
  59. tkcontinue,
  60. tkdestructor,
  61. tkdispose,
  62. tkdiv,
  63. tkdo,
  64. tkdownto,
  65. tkelse,
  66. tkend,
  67. tkexcept,
  68. tkexit,
  69. tkexports,
  70. tkfalse,
  71. tkfinalization,
  72. tkfinally,
  73. tkfor,
  74. tkfunction,
  75. tkgoto,
  76. tkif,
  77. tkimplementation,
  78. tkin,
  79. tkinherited,
  80. tkinitialization,
  81. tkinline,
  82. tkinterface,
  83. tkis,
  84. tklabel,
  85. tklibrary,
  86. tkmod,
  87. tknew,
  88. tknil,
  89. tknot,
  90. tkobject,
  91. tkof,
  92. tkon,
  93. tkoperator,
  94. tkor,
  95. tkpacked,
  96. tkprocedure,
  97. tkprogram,
  98. tkproperty,
  99. tkraise,
  100. tkrecord,
  101. tkrepeat,
  102. tkResourceString,
  103. tkself,
  104. tkset,
  105. tkshl,
  106. tkshr,
  107. // tkstring,
  108. tkthen,
  109. tkto,
  110. tktrue,
  111. tktry,
  112. tktype,
  113. tkunit,
  114. tkuntil,
  115. tkuses,
  116. tkvar,
  117. tkwhile,
  118. tkwith,
  119. tkxor);
  120. TLineReader = class
  121. public
  122. function IsEOF: Boolean; virtual; abstract;
  123. function ReadLine: String; virtual; abstract;
  124. end;
  125. TFileLineReader = class(TLineReader)
  126. private
  127. FTextFile: Text;
  128. FileOpened: Boolean;
  129. public
  130. constructor Create(const AFilename: String);
  131. destructor Destroy; override;
  132. function IsEOF: Boolean; override;
  133. function ReadLine: String; override;
  134. end;
  135. TFileResolver = class
  136. private
  137. FIncludePaths: TStringList;
  138. public
  139. constructor Create;
  140. destructor Destroy; override;
  141. procedure AddIncludePath(const APath: String);
  142. function FindSourceFile(const AName: String): TLineReader;
  143. function FindIncludeFile(const AName: String): TLineReader;
  144. end;
  145. EScannerError = class(Exception);
  146. TPascalScanner = class
  147. private
  148. FFileResolver: TFileResolver;
  149. FCurSourceFile: TLineReader;
  150. FCurFilename: String;
  151. FCurRow: Integer;
  152. FCurToken: TToken;
  153. FCurTokenString: String;
  154. FCurLine: String;
  155. TokenStr: PChar;
  156. FIncludeStack: TList;
  157. function GetCurColumn: Integer;
  158. protected
  159. procedure Error(const Msg: String);
  160. procedure Error(const Msg: String; Args: array of Const);
  161. function DoFetchToken: TToken;
  162. public
  163. constructor Create(AFileResolver: TFileResolver; const AFilename: String);
  164. destructor Destroy; override;
  165. function FetchToken: TToken;
  166. property FileResolver: TFileResolver read FFileResolver;
  167. property CurSourceFile: TLineReader read FCurSourceFile;
  168. property CurFilename: String read FCurFilename;
  169. property CurLine: String read FCurLine;
  170. property CurRow: Integer read FCurRow;
  171. property CurColumn: Integer read GetCurColumn;
  172. property CurToken: TToken read FCurToken;
  173. property CurTokenString: String read FCurTokenString;
  174. end;
  175. const
  176. TokenInfos: array[TToken] of String = (
  177. 'EOF',
  178. 'Whitespace',
  179. 'Comment',
  180. 'Identifier',
  181. 'String',
  182. 'Number',
  183. 'Character',
  184. '(',
  185. ')',
  186. '*',
  187. '+',
  188. ',',
  189. '-',
  190. '.',
  191. '/',
  192. ':',
  193. ';',
  194. '=',
  195. '[',
  196. ']',
  197. '^',
  198. '..',
  199. ':=',
  200. // Reserved words
  201. 'absolute',
  202. 'and',
  203. 'array',
  204. 'as',
  205. 'asm',
  206. 'begin',
  207. 'break',
  208. 'case',
  209. 'class',
  210. 'const',
  211. 'constructor',
  212. 'continue',
  213. 'destructor',
  214. 'dispose',
  215. 'div',
  216. 'do',
  217. 'downto',
  218. 'else',
  219. 'end',
  220. 'except',
  221. 'exit',
  222. 'exports',
  223. 'false',
  224. 'finalization',
  225. 'finally',
  226. 'for',
  227. 'function',
  228. 'goto',
  229. 'if',
  230. 'implementation',
  231. 'in',
  232. 'inherited',
  233. 'initialization',
  234. 'inline',
  235. 'interface',
  236. 'is',
  237. 'label',
  238. 'library',
  239. 'mod',
  240. 'new',
  241. 'nil',
  242. 'not',
  243. 'object',
  244. 'of',
  245. 'on',
  246. 'operator',
  247. 'or',
  248. 'packed',
  249. 'procedure',
  250. 'program',
  251. 'property',
  252. 'raise',
  253. 'record',
  254. 'repeat',
  255. 'resourcestring',
  256. 'self',
  257. 'set',
  258. 'shl',
  259. 'shr',
  260. // 'string',
  261. 'then',
  262. 'to',
  263. 'true',
  264. 'try',
  265. 'type',
  266. 'unit',
  267. 'until',
  268. 'uses',
  269. 'var',
  270. 'while',
  271. 'with',
  272. 'xor'
  273. );
  274. implementation
  275. type
  276. TIncludeStackItem = class
  277. SourceFile: TLineReader;
  278. Filename: String;
  279. Token: TToken;
  280. TokenString: String;
  281. Line: String;
  282. Row: Integer;
  283. TokenStr: PChar;
  284. end;
  285. constructor TFileLineReader.Create(const AFilename: String);
  286. begin
  287. inherited Create;
  288. Assign(FTextFile, AFilename);
  289. Reset(FTextFile);
  290. FileOpened := True;
  291. end;
  292. destructor TFileLineReader.Destroy;
  293. begin
  294. if FileOpened then
  295. Close(FTextFile);
  296. inherited Destroy;
  297. end;
  298. function TFileLineReader.IsEOF: Boolean;
  299. begin
  300. Result := EOF(FTextFile);
  301. end;
  302. function TFileLineReader.ReadLine: String;
  303. begin
  304. ReadLn(FTextFile, Result);
  305. end;
  306. constructor TFileResolver.Create;
  307. begin
  308. inherited Create;
  309. FIncludePaths := TStringList.Create;
  310. end;
  311. destructor TFileResolver.Destroy;
  312. begin
  313. FIncludePaths.Free;
  314. inherited Destroy;
  315. end;
  316. procedure TFileResolver.AddIncludePath(const APath: String);
  317. begin
  318. FIncludePaths.Add(IncludeTrailingPathDelimiter(APath));
  319. end;
  320. function TFileResolver.FindSourceFile(const AName: String): TLineReader;
  321. begin
  322. try
  323. Result := TFileLineReader.Create(AName);
  324. except
  325. Result := nil;
  326. end;
  327. end;
  328. function TFileResolver.FindIncludeFile(const AName: String): TLineReader;
  329. var
  330. i: Integer;
  331. begin
  332. Result := nil;
  333. try
  334. Result := TFileLineReader.Create(AName);
  335. except
  336. for i := 0 to FIncludePaths.Count - 1 do
  337. try
  338. Result := TFileLineReader.Create(FIncludePaths[i] + AName);
  339. break;
  340. except
  341. end;
  342. end;
  343. end;
  344. constructor TPascalScanner.Create(AFileResolver: TFileResolver;
  345. const AFilename: String);
  346. begin
  347. inherited Create;
  348. FFileResolver := AFileResolver;
  349. FCurSourceFile := FileResolver.FindSourceFile(AFilename);
  350. FCurFilename := AFilename;
  351. FIncludeStack := TList.Create;
  352. end;
  353. destructor TPascalScanner.Destroy;
  354. begin
  355. // Dont' free the first element, because it is CurSourceFile
  356. while FIncludeStack.Count > 1 do
  357. TFileResolver(FIncludeStack[1]).Free;
  358. FIncludeStack.Free;
  359. CurSourceFile.Free;
  360. inherited Destroy;
  361. end;
  362. function TPascalScanner.FetchToken: TToken;
  363. var
  364. IncludeStackItem: TIncludeStackItem;
  365. begin
  366. while True do
  367. begin
  368. Result := DoFetchToken;
  369. if FCurToken = tkEOF then
  370. if FIncludeStack.Count > 0 then
  371. begin
  372. CurSourceFile.Free;
  373. IncludeStackItem :=
  374. TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
  375. FIncludeStack.Delete(FIncludeStack.Count - 1);
  376. FCurSourceFile := IncludeStackItem.SourceFile;
  377. FCurFilename := IncludeStackItem.Filename;
  378. FCurToken := IncludeStackItem.Token;
  379. FCurTokenString := IncludeStackItem.TokenString;
  380. FCurLine := IncludeStackItem.Line;
  381. FCurRow := IncludeStackItem.Row;
  382. TokenStr := IncludeStackItem.TokenStr;
  383. IncludeStackItem.Free;
  384. Result := FCurToken;
  385. end else
  386. break
  387. else
  388. break;
  389. end;
  390. end;
  391. procedure TPascalScanner.Error(const Msg: String);
  392. begin
  393. raise EScannerError.Create(Msg);
  394. end;
  395. procedure TPascalScanner.Error(const Msg: String; Args: array of Const);
  396. begin
  397. raise EScannerError.CreateFmt(Msg, Args);
  398. end;
  399. function TPascalScanner.DoFetchToken: TToken;
  400. function FetchLine: Boolean;
  401. begin
  402. if CurSourceFile.IsEOF then
  403. begin
  404. FCurLine := '';
  405. TokenStr := nil;
  406. Result := False;
  407. end else
  408. begin
  409. FCurLine := CurSourceFile.ReadLine;
  410. TokenStr := PChar(CurLine);
  411. Result := True;
  412. Inc(FCurRow);
  413. end;
  414. end;
  415. var
  416. TokenStart, CurPos: PChar;
  417. i: TToken;
  418. OldLength, SectionLength, NestingLevel: Integer;
  419. Directive, Param: String;
  420. IncludeStackItem: TIncludeStackItem;
  421. begin
  422. if TokenStr = nil then
  423. if not FetchLine then
  424. begin
  425. Result := tkEOF;
  426. FCurToken := Result;
  427. exit;
  428. end;
  429. FCurTokenString := '';
  430. case TokenStr[0] of
  431. #0: // Empty line
  432. begin
  433. FetchLine;
  434. Result := tkWhitespace;
  435. end;
  436. #9, ' ':
  437. begin
  438. Result := tkWhitespace;
  439. repeat
  440. Inc(TokenStr);
  441. if TokenStr[0] = #0 then
  442. if not FetchLine then
  443. begin
  444. FCurToken := Result;
  445. exit;
  446. end;
  447. until not (TokenStr[0] in [#9, ' ']);
  448. end;
  449. '#':
  450. begin
  451. TokenStart := TokenStr;
  452. Inc(TokenStr);
  453. if TokenStr[0] = '$' then
  454. begin
  455. Inc(TokenStr);
  456. repeat
  457. Inc(TokenStr);
  458. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'F']);
  459. end else
  460. repeat
  461. Inc(TokenStr);
  462. until not (TokenStr[0] in ['0'..'9']);
  463. SectionLength := TokenStr - TokenStart;
  464. SetLength(FCurTokenString, SectionLength);
  465. if SectionLength > 0 then
  466. Move(TokenStart^, FCurTokenString[1], SectionLength);
  467. Result := tkChar;
  468. end;
  469. '$':
  470. begin
  471. TokenStart := TokenStr;
  472. repeat
  473. Inc(TokenStr);
  474. until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'F']);
  475. SectionLength := TokenStr - TokenStart;
  476. SetLength(FCurTokenString, SectionLength);
  477. if SectionLength > 0 then
  478. Move(TokenStart^, FCurTokenString[1], SectionLength);
  479. Result := tkNumber;
  480. end;
  481. '''':
  482. begin
  483. Inc(TokenStr);
  484. TokenStart := TokenStr;
  485. OldLength := 0;
  486. FCurTokenString := '';
  487. while True do
  488. begin
  489. if TokenStr[0] = '''' then
  490. if TokenStr[1] = '''' then
  491. begin
  492. SectionLength := TokenStr - TokenStart + 1;
  493. SetLength(FCurTokenString, OldLength + SectionLength);
  494. if SectionLength > 1 then
  495. Move(TokenStart^, FCurTokenString[OldLength + 1],
  496. SectionLength);
  497. Inc(OldLength, SectionLength);
  498. Inc(TokenStr);
  499. TokenStart := TokenStr;
  500. end else
  501. break;
  502. if TokenStr[0] = #0 then
  503. Error(SErrOpenString);
  504. Inc(TokenStr);
  505. end;
  506. SectionLength := TokenStr - TokenStart;
  507. SetLength(FCurTokenString, OldLength + SectionLength);
  508. if SectionLength > 0 then
  509. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  510. Inc(TokenStr);
  511. Result := tkString;
  512. end;
  513. '(':
  514. begin
  515. Inc(TokenStr);
  516. if TokenStr[0] = '*' then
  517. begin
  518. // Old-style multi-line comment
  519. Inc(TokenStr);
  520. while (TokenStr[0] <> '*') or (TokenStr[1] <> ')') do
  521. begin
  522. if TokenStr[0] = #0 then
  523. begin
  524. if not FetchLine then
  525. begin
  526. Result := tkEOF;
  527. FCurToken := Result;
  528. exit;
  529. end;
  530. end else
  531. Inc(TokenStr);
  532. end;
  533. Inc(TokenStr, 2);
  534. Result := tkComment;
  535. end else
  536. Result := tkBraceOpen;
  537. end;
  538. ')':
  539. begin
  540. Inc(TokenStr);
  541. Result := tkBraceClose;
  542. end;
  543. '*':
  544. begin
  545. Inc(TokenStr);
  546. Result := tkMul;
  547. end;
  548. '+':
  549. begin
  550. Inc(TokenStr);
  551. Result := tkPlus;
  552. end;
  553. ',':
  554. begin
  555. Inc(TokenStr);
  556. Result := tkComma;
  557. end;
  558. '-':
  559. begin
  560. Inc(TokenStr);
  561. Result := tkMinus;
  562. end;
  563. '.':
  564. begin
  565. Inc(TokenStr);
  566. if TokenStr[0] = '.' then
  567. begin
  568. Inc(TokenStr);
  569. Result := tkDotDot;
  570. end else
  571. Result := tkDot;
  572. end;
  573. '/':
  574. begin
  575. Inc(TokenStr);
  576. if TokenStr[0] = '/' then // Single-line comment
  577. begin
  578. Inc(TokenStr);
  579. TokenStart := TokenStr;
  580. FCurTokenString := '';
  581. while TokenStr[0] <> #0 do
  582. Inc(TokenStr);
  583. SectionLength := TokenStr - TokenStart;
  584. SetLength(FCurTokenString, SectionLength);
  585. if SectionLength > 0 then
  586. Move(TokenStart^, FCurTokenString[1], SectionLength);
  587. Result := tkComment;
  588. //WriteLn('Einzeiliger Kommentar: "', CurTokenString, '"');
  589. end else
  590. Result := tkDivision;
  591. end;
  592. '0'..'9':
  593. begin
  594. TokenStart := TokenStr;
  595. repeat
  596. Inc(TokenStr);
  597. until not (TokenStr[0] in ['0'..'9', '.', 'e', 'E']);
  598. SectionLength := TokenStr - TokenStart;
  599. SetLength(FCurTokenString, SectionLength);
  600. if SectionLength > 0 then
  601. Move(TokenStart^, FCurTokenString[1], SectionLength);
  602. Result := tkNumber;
  603. end;
  604. ':':
  605. begin
  606. Inc(TokenStr);
  607. if TokenStr[0] = '=' then
  608. begin
  609. Inc(TokenStr);
  610. Result := tkAssign;
  611. end else
  612. Result := tkColon;
  613. end;
  614. ';':
  615. begin
  616. Inc(TokenStr);
  617. Result := tkSemicolon;
  618. end;
  619. '=':
  620. begin
  621. Inc(TokenStr);
  622. Result := tkEqual;
  623. end;
  624. '[':
  625. begin
  626. Inc(TokenStr);
  627. Result := tkSquaredBraceOpen;
  628. end;
  629. ']':
  630. begin
  631. Inc(TokenStr);
  632. Result := tkSquaredBraceClose;
  633. end;
  634. '^':
  635. begin
  636. Inc(TokenStr);
  637. Result := tkCaret;
  638. end;
  639. '{': // Multi-line comment
  640. begin
  641. Inc(TokenStr);
  642. TokenStart := TokenStr;
  643. FCurTokenString := '';
  644. OldLength := 0;
  645. NestingLevel := 0;
  646. while (TokenStr[0] <> '}') or (NestingLevel > 0) do
  647. begin
  648. if TokenStr[0] = #0 then
  649. begin
  650. SectionLength := TokenStr - TokenStart + 1;
  651. SetLength(FCurTokenString, OldLength + SectionLength);
  652. if SectionLength > 1 then
  653. Move(TokenStart^, FCurTokenString[OldLength + 1],
  654. SectionLength - 1);
  655. Inc(OldLength, SectionLength);
  656. FCurTokenString[OldLength] := #10;
  657. if not FetchLine then
  658. begin
  659. Result := tkEOF;
  660. FCurToken := Result;
  661. exit;
  662. end;
  663. TokenStart := TokenStr;
  664. end else
  665. begin
  666. if TokenStr[0] = '{' then
  667. Inc(NestingLevel)
  668. else if TokenStr[0] = '}' then
  669. Dec(NestingLevel);
  670. Inc(TokenStr);
  671. end;
  672. end;
  673. SectionLength := TokenStr - TokenStart;
  674. SetLength(FCurTokenString, OldLength + SectionLength);
  675. if SectionLength > 0 then
  676. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  677. Inc(TokenStr);
  678. Result := tkComment;
  679. //WriteLn('Kommentar: "', CurTokenString, '"');
  680. if (Length(CurTokenString) > 0) and (CurTokenString[1] = '$') then
  681. begin
  682. TokenStart := @CurTokenString[2];
  683. CurPos := TokenStart;
  684. while (CurPos[0] <> ' ') and (CurPos[0] <> #0) do
  685. Inc(CurPos);
  686. SectionLength := CurPos - TokenStart;
  687. SetLength(Directive, SectionLength);
  688. if SectionLength > 0 then
  689. begin
  690. Move(TokenStart^, Directive[1], SectionLength);
  691. Directive := UpperCase(Directive);
  692. if CurPos[0] <> #0 then
  693. begin
  694. TokenStart := CurPos + 1;
  695. CurPos := TokenStart;
  696. while CurPos[0] <> #0 do
  697. Inc(CurPos);
  698. SectionLength := CurPos - TokenStart;
  699. SetLength(Param, SectionLength);
  700. if SectionLength > 0 then
  701. Move(TokenStart^, Param[1], SectionLength);
  702. end else
  703. Param := '';
  704. // WriteLn('Direktive: "', Directive, '", Param: "', Param, '"');
  705. if (Directive = 'I') or (Directive = 'INCLUDE') then
  706. begin
  707. IncludeStackItem := TIncludeStackItem.Create;
  708. IncludeStackItem.SourceFile := CurSourceFile;
  709. IncludeStackItem.Filename := CurFilename;
  710. IncludeStackItem.Token := CurToken;
  711. IncludeStackItem.TokenString := CurTokenString;
  712. IncludeStackItem.Line := CurLine;
  713. IncludeStackItem.Row := CurRow;
  714. IncludeStackItem.TokenStr := TokenStr;
  715. FIncludeStack.Add(IncludeStackItem);
  716. FCurSourceFile := FileResolver.FindIncludeFile(Param);
  717. if not Assigned(CurSourceFile) then
  718. Error(SErrIncludeFileNotFound, [Param]);
  719. FCurFilename := Param;
  720. FCurRow := 0;
  721. end;
  722. end else
  723. Directive := '';
  724. end;
  725. end;
  726. 'A'..'Z', 'a'..'z', '_':
  727. begin
  728. TokenStart := TokenStr;
  729. repeat
  730. Inc(TokenStr);
  731. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  732. SectionLength := TokenStr - TokenStart;
  733. SetLength(FCurTokenString, SectionLength);
  734. if SectionLength > 0 then
  735. Move(TokenStart^, FCurTokenString[1], SectionLength);
  736. // Check if this is a keyword or identifier
  737. // !!!: Optimize this!
  738. for i := tkAbsolute to tkXOR do
  739. if CompareText(CurTokenString, TokenInfos[i]) = 0 then
  740. begin
  741. Result := i;
  742. FCurToken := Result;
  743. exit;
  744. end;
  745. Result := tkIdentifier;
  746. end;
  747. else
  748. Error(SErrInvalidCharacter, [TokenStr[0]]);
  749. end;
  750. FCurToken := Result;
  751. end;
  752. function TPascalScanner.GetCurColumn: Integer;
  753. begin
  754. Result := TokenStr - PChar(CurLine);
  755. end;
  756. end.
  757. {
  758. $Log$
  759. Revision 1.1 2003-03-13 21:47:42 sg
  760. * First version as part of FCL
  761. }