pscanner.pp 27 KB

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