pscanner.pp 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  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. TokenStart := TokenStr;
  517. repeat
  518. Inc(TokenStr);
  519. until not (TokenStr[0] in ['0','1']);
  520. SectionLength := TokenStr - TokenStart;
  521. SetLength(FCurTokenString, SectionLength);
  522. if SectionLength > 0 then
  523. Move(TokenStart^, FCurTokenString[1], SectionLength);
  524. Result := tkNumber;
  525. end;
  526. '''':
  527. begin
  528. Inc(TokenStr);
  529. TokenStart := TokenStr;
  530. OldLength := 0;
  531. FCurTokenString := '';
  532. while True do
  533. begin
  534. if TokenStr[0] = '''' then
  535. if TokenStr[1] = '''' then
  536. begin
  537. SectionLength := TokenStr - TokenStart + 1;
  538. SetLength(FCurTokenString, OldLength + SectionLength);
  539. if SectionLength > 1 then
  540. Move(TokenStart^, FCurTokenString[OldLength + 1],
  541. SectionLength);
  542. Inc(OldLength, SectionLength);
  543. Inc(TokenStr);
  544. TokenStart := TokenStr;
  545. end else
  546. break;
  547. if TokenStr[0] = #0 then
  548. Error(SErrOpenString);
  549. Inc(TokenStr);
  550. end;
  551. SectionLength := TokenStr - TokenStart;
  552. SetLength(FCurTokenString, OldLength + SectionLength);
  553. if SectionLength > 0 then
  554. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  555. Inc(TokenStr);
  556. Result := tkString;
  557. end;
  558. '(':
  559. begin
  560. Inc(TokenStr);
  561. if TokenStr[0] = '*' then
  562. begin
  563. // Old-style multi-line comment
  564. Inc(TokenStr);
  565. while (TokenStr[0] <> '*') or (TokenStr[1] <> ')') do
  566. begin
  567. if TokenStr[0] = #0 then
  568. begin
  569. if not FetchLine then
  570. begin
  571. Result := tkEOF;
  572. FCurToken := Result;
  573. exit;
  574. end;
  575. end else
  576. Inc(TokenStr);
  577. end;
  578. Inc(TokenStr, 2);
  579. Result := tkComment;
  580. end else
  581. Result := tkBraceOpen;
  582. end;
  583. ')':
  584. begin
  585. Inc(TokenStr);
  586. Result := tkBraceClose;
  587. end;
  588. '*':
  589. begin
  590. Inc(TokenStr);
  591. Result := tkMul;
  592. end;
  593. '+':
  594. begin
  595. Inc(TokenStr);
  596. Result := tkPlus;
  597. end;
  598. ',':
  599. begin
  600. Inc(TokenStr);
  601. Result := tkComma;
  602. end;
  603. '-':
  604. begin
  605. Inc(TokenStr);
  606. Result := tkMinus;
  607. end;
  608. '.':
  609. begin
  610. Inc(TokenStr);
  611. if TokenStr[0] = '.' then
  612. begin
  613. Inc(TokenStr);
  614. Result := tkDotDot;
  615. end else
  616. Result := tkDot;
  617. end;
  618. '/':
  619. begin
  620. Inc(TokenStr);
  621. if TokenStr[0] = '/' then // Single-line comment
  622. begin
  623. Inc(TokenStr);
  624. TokenStart := TokenStr;
  625. FCurTokenString := '';
  626. while TokenStr[0] <> #0 do
  627. Inc(TokenStr);
  628. SectionLength := TokenStr - TokenStart;
  629. SetLength(FCurTokenString, SectionLength);
  630. if SectionLength > 0 then
  631. Move(TokenStart^, FCurTokenString[1], SectionLength);
  632. Result := tkComment;
  633. //WriteLn('Einzeiliger Kommentar: "', CurTokenString, '"');
  634. end else
  635. Result := tkDivision;
  636. end;
  637. '0'..'9':
  638. begin
  639. TokenStart := TokenStr;
  640. while True do
  641. begin
  642. Inc(TokenStr);
  643. case TokenStr[0] of
  644. '.':
  645. begin
  646. if TokenStr[1] in ['0'..'9', 'e', 'E'] then
  647. begin
  648. Inc(TokenStr);
  649. repeat
  650. Inc(TokenStr);
  651. until not (TokenStr[0] in ['0'..'9', 'e', 'E']);
  652. end;
  653. break;
  654. end;
  655. '0'..'9': ;
  656. 'e', 'E':
  657. begin
  658. Inc(TokenStr);
  659. if TokenStr[0] = '-' then
  660. Inc(TokenStr);
  661. while TokenStr[0] in ['0'..'9'] do
  662. Inc(TokenStr);
  663. break;
  664. end;
  665. else
  666. break;
  667. end;
  668. end;
  669. SectionLength := TokenStr - TokenStart;
  670. SetLength(FCurTokenString, SectionLength);
  671. if SectionLength > 0 then
  672. Move(TokenStart^, FCurTokenString[1], SectionLength);
  673. Result := tkNumber;
  674. end;
  675. ':':
  676. begin
  677. Inc(TokenStr);
  678. if TokenStr[0] = '=' then
  679. begin
  680. Inc(TokenStr);
  681. Result := tkAssign;
  682. end else
  683. Result := tkColon;
  684. end;
  685. ';':
  686. begin
  687. Inc(TokenStr);
  688. Result := tkSemicolon;
  689. end;
  690. '<':
  691. begin
  692. Inc(TokenStr);
  693. if TokenStr[0] = '>' then
  694. begin
  695. Inc(TokenStr);
  696. Result := tkNotEqual;
  697. end else
  698. Result := tkLessThan;
  699. end;
  700. '=':
  701. begin
  702. Inc(TokenStr);
  703. Result := tkEqual;
  704. end;
  705. '>':
  706. begin
  707. Inc(TokenStr);
  708. Result := tkGreaterThan;
  709. end;
  710. '@':
  711. begin
  712. Inc(TokenStr);
  713. Result := tkAt;
  714. end;
  715. '[':
  716. begin
  717. Inc(TokenStr);
  718. Result := tkSquaredBraceOpen;
  719. end;
  720. ']':
  721. begin
  722. Inc(TokenStr);
  723. Result := tkSquaredBraceClose;
  724. end;
  725. '^':
  726. begin
  727. Inc(TokenStr);
  728. Result := tkCaret;
  729. end;
  730. '{': // Multi-line comment
  731. begin
  732. Inc(TokenStr);
  733. TokenStart := TokenStr;
  734. FCurTokenString := '';
  735. OldLength := 0;
  736. NestingLevel := 0;
  737. while (TokenStr[0] <> '}') or (NestingLevel > 0) do
  738. begin
  739. if TokenStr[0] = #0 then
  740. begin
  741. SectionLength := TokenStr - TokenStart + 1;
  742. SetLength(FCurTokenString, OldLength + SectionLength);
  743. if SectionLength > 1 then
  744. Move(TokenStart^, FCurTokenString[OldLength + 1],
  745. SectionLength - 1);
  746. Inc(OldLength, SectionLength);
  747. FCurTokenString[OldLength] := #10;
  748. if not FetchLine then
  749. begin
  750. Result := tkEOF;
  751. FCurToken := Result;
  752. exit;
  753. end;
  754. TokenStart := TokenStr;
  755. end else
  756. begin
  757. if TokenStr[0] = '{' then
  758. Inc(NestingLevel)
  759. else if TokenStr[0] = '}' then
  760. Dec(NestingLevel);
  761. Inc(TokenStr);
  762. end;
  763. end;
  764. SectionLength := TokenStr - TokenStart;
  765. SetLength(FCurTokenString, OldLength + SectionLength);
  766. if SectionLength > 0 then
  767. Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
  768. Inc(TokenStr);
  769. Result := tkComment;
  770. //WriteLn('Kommentar: "', CurTokenString, '"');
  771. if (Length(CurTokenString) > 0) and (CurTokenString[1] = '$') then
  772. begin
  773. TokenStart := @CurTokenString[2];
  774. CurPos := TokenStart;
  775. while (CurPos[0] <> ' ') and (CurPos[0] <> #0) do
  776. Inc(CurPos);
  777. SectionLength := CurPos - TokenStart;
  778. SetLength(Directive, SectionLength);
  779. if SectionLength > 0 then
  780. begin
  781. Move(TokenStart^, Directive[1], SectionLength);
  782. Directive := UpperCase(Directive);
  783. if CurPos[0] <> #0 then
  784. begin
  785. TokenStart := CurPos + 1;
  786. CurPos := TokenStart;
  787. while CurPos[0] <> #0 do
  788. Inc(CurPos);
  789. SectionLength := CurPos - TokenStart;
  790. SetLength(Param, SectionLength);
  791. if SectionLength > 0 then
  792. Move(TokenStart^, Param[1], SectionLength);
  793. end else
  794. Param := '';
  795. // WriteLn('Direktive: "', Directive, '", Param: "', Param, '"');
  796. if (Directive = 'I') or (Directive = 'INCLUDE') then
  797. begin
  798. if not PPIsSkipping then
  799. begin
  800. IncludeStackItem := TIncludeStackItem.Create;
  801. IncludeStackItem.SourceFile := CurSourceFile;
  802. IncludeStackItem.Filename := CurFilename;
  803. IncludeStackItem.Token := CurToken;
  804. IncludeStackItem.TokenString := CurTokenString;
  805. IncludeStackItem.Line := CurLine;
  806. IncludeStackItem.Row := CurRow;
  807. IncludeStackItem.TokenStr := TokenStr;
  808. FIncludeStack.Add(IncludeStackItem);
  809. FCurSourceFile := FileResolver.FindIncludeFile(Param);
  810. if not Assigned(CurSourceFile) then
  811. Error(SErrIncludeFileNotFound, [Param]);
  812. FCurFilename := Param;
  813. FCurRow := 0;
  814. end;
  815. end else if Directive = 'DEFINE' then
  816. begin
  817. if not PPIsSkipping then
  818. begin
  819. Param := UpperCase(Param);
  820. if Defines.IndexOf(Param) < 0 then
  821. Defines.Add(Param);
  822. end;
  823. end else if Directive = 'UNDEF' then
  824. begin
  825. if not PPIsSkipping then
  826. begin
  827. Param := UpperCase(Param);
  828. Index := Defines.IndexOf(Param);
  829. if Index >= 0 then
  830. Defines.Delete(Index);
  831. end;
  832. end else if Directive = 'IFDEF' then
  833. begin
  834. if PPSkipStackIndex = High(PPSkipModeStack) then
  835. Error(SErrIfXXXNestingLimitReached);
  836. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  837. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  838. Inc(PPSkipStackIndex);
  839. if PPIsSkipping then
  840. begin
  841. PPSkipMode := ppSkipAll;
  842. PPIsSkipping := True;
  843. end else
  844. begin
  845. Param := UpperCase(Param);
  846. Index := Defines.IndexOf(Param);
  847. if Index < 0 then
  848. begin
  849. PPSkipMode := ppSkipIfBranch;
  850. PPIsSkipping := True;
  851. end else
  852. PPSkipMode := ppSkipElseBranch;
  853. end;
  854. end else if Directive = 'IFNDEF' then
  855. begin
  856. if PPSkipStackIndex = High(PPSkipModeStack) then
  857. Error(SErrIfXXXNestingLimitReached);
  858. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  859. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  860. Inc(PPSkipStackIndex);
  861. if PPIsSkipping then
  862. begin
  863. PPSkipMode := ppSkipAll;
  864. PPIsSkipping := True;
  865. end else
  866. begin
  867. Param := UpperCase(Param);
  868. Index := Defines.IndexOf(Param);
  869. if Index >= 0 then
  870. begin
  871. PPSkipMode := ppSkipIfBranch;
  872. PPIsSkipping := True;
  873. end else
  874. PPSkipMode := ppSkipElseBranch;
  875. end;
  876. end else if Directive = 'IFOPT' then
  877. begin
  878. if PPSkipStackIndex = High(PPSkipModeStack) then
  879. Error(SErrIfXXXNestingLimitReached);
  880. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  881. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  882. Inc(PPSkipStackIndex);
  883. if PPIsSkipping then
  884. begin
  885. PPSkipMode := ppSkipAll;
  886. PPIsSkipping := True;
  887. end else
  888. begin
  889. { !!!: Currently, options are not supported, so they are just
  890. assumed as not being set. }
  891. PPSkipMode := ppSkipIfBranch;
  892. PPIsSkipping := True;
  893. end;
  894. end else if Directive = 'IF' then
  895. begin
  896. if PPSkipStackIndex = High(PPSkipModeStack) then
  897. Error(SErrIfXXXNestingLimitReached);
  898. PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
  899. PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
  900. Inc(PPSkipStackIndex);
  901. if PPIsSkipping then
  902. begin
  903. PPSkipMode := ppSkipAll;
  904. PPIsSkipping := True;
  905. end else
  906. begin
  907. { !!!: Currently, expressions are not supported, so they are
  908. just assumed as evaluating to false. }
  909. PPSkipMode := ppSkipIfBranch;
  910. PPIsSkipping := True;
  911. end;
  912. end else if Directive = 'ELSE' then
  913. begin
  914. if PPSkipStackIndex = 0 then
  915. Error(SErrInvalidPPElse);
  916. if PPSkipMode = ppSkipIfBranch then
  917. PPIsSkipping := False
  918. else if PPSkipMode = ppSkipElseBranch then
  919. PPIsSkipping := True;
  920. end else if Directive = 'ENDIF' then
  921. begin
  922. if PPSkipStackIndex = 0 then
  923. Error(SErrInvalidPPEndif);
  924. Dec(PPSkipStackIndex);
  925. PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
  926. PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
  927. end;
  928. end else
  929. Directive := '';
  930. end;
  931. end;
  932. 'A'..'Z', 'a'..'z', '_':
  933. begin
  934. TokenStart := TokenStr;
  935. repeat
  936. Inc(TokenStr);
  937. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  938. SectionLength := TokenStr - TokenStart;
  939. SetLength(FCurTokenString, SectionLength);
  940. if SectionLength > 0 then
  941. Move(TokenStart^, FCurTokenString[1], SectionLength);
  942. // Check if this is a keyword or identifier
  943. // !!!: Optimize this!
  944. for i := tkAbsolute to tkXOR do
  945. if CompareText(CurTokenString, TokenInfos[i]) = 0 then
  946. begin
  947. Result := i;
  948. FCurToken := Result;
  949. exit;
  950. end;
  951. Result := tkIdentifier;
  952. end;
  953. else
  954. Error(SErrInvalidCharacter, [TokenStr[0]]);
  955. end;
  956. FCurToken := Result;
  957. end;
  958. function TPascalScanner.GetCurColumn: Integer;
  959. begin
  960. Result := TokenStr - PChar(CurLine);
  961. end;
  962. end.
  963. {
  964. $Log$
  965. Revision 1.5 2003-10-25 16:24:29 michael
  966. + FPC also accepts binary numbers starting with %
  967. Revision 1.4 2003/09/02 13:26:06 mattias
  968. MG: added IF directive skipping
  969. Revision 1.3 2003/04/04 08:01:55 michael
  970. + Patch from Jeff Pohlmeyer to read less than and larger than
  971. Revision 1.2 2003/03/27 16:32:48 sg
  972. * Added $IFxxx support
  973. * Lots of small fixes
  974. Revision 1.1 2003/03/13 21:47:42 sg
  975. * First version as part of FCL
  976. }