pscanner.pp 26 KB

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