webidlscanner.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. {
  2. This file is part of the Free Component Library
  3. WEBIDL source lexical scanner
  4. Copyright (c) 2018 by Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. unit webidlscanner;
  14. interface
  15. uses SysUtils, Classes;
  16. type
  17. TWebIDLVersion = (v1,v2);
  18. TIDLToken = (
  19. tkEOF,
  20. tkUnknown ,
  21. tkComment,
  22. tkWhitespace,
  23. tkString,
  24. tkNumberInteger,
  25. tkNumberFloat,
  26. // Simple (one-character) tokens
  27. tkDot, // '.',
  28. tkSemiColon, // ';'
  29. tkComma, // ','
  30. tkColon, // ':'
  31. tkBracketOpen, // '('
  32. tkBracketClose, // ')'
  33. tkCurlyBraceOpen, // '{'
  34. tkCurlyBraceClose, // '}'
  35. tkSquaredBraceOpen, // '['
  36. tkSquaredBraceClose, // ']'
  37. tkLess, // '<'
  38. tkEqual, // '='
  39. tkLarger, // '>'
  40. tkQuestionmark, // '?'
  41. tkminus, // '-'
  42. tkIdentifier, // Any identifier
  43. tkTrue,
  44. tkFalse,
  45. tkNull,
  46. tkAny,
  47. tkAttribute,
  48. tkCallback,
  49. tkConst,
  50. tkDeleter,
  51. tkDictionary,
  52. tkEllipsis,
  53. tkEnum,
  54. tkGetter,
  55. tkImplements,
  56. tkInfinity,
  57. tkInherit,
  58. tkInterface,
  59. tkIterable,
  60. tkLegacyCaller,
  61. tkNan,
  62. tkNegInfinity,
  63. tkOptional,
  64. tkOr,
  65. tkPartial,
  66. tkReadOnly,
  67. tkRequired,
  68. tkSetter,
  69. tkStatic,
  70. tkStringifier,
  71. tkSerializer,
  72. tkTypedef,
  73. tkUnrestricted,
  74. tkPromise,
  75. tkFrozenArray,
  76. tkByteString,
  77. tkDOMString,
  78. tkUSVString,
  79. tkboolean,
  80. tkbyte,
  81. tkdouble,
  82. tkfloat,
  83. tklong,
  84. tkobject,
  85. tkoctet,
  86. tkunsigned,
  87. tkvoid,
  88. tkShort,
  89. tkSequence,
  90. tkStringToken,
  91. tkMixin,
  92. tkIncludes,
  93. tkMapLike,
  94. tkRecord,
  95. tkSetLike,
  96. tkOther,
  97. tkConstructor
  98. );
  99. TIDLTokens = Set of TIDLToken;
  100. EWebIDLScanner = class(EParserError);
  101. Const
  102. V2Tokens = [tkMixin,tkIncludes,tkMapLike,tkRecord,tkSetLike,tkFrozenArray,tkConstructor];
  103. V1Tokens = [tkImplements];
  104. VersionNonTokens : Array[TWebIDLVersion] of TIDLTokens = (V2Tokens,V1Tokens);
  105. Type
  106. TWebIDLScannerSkipMode = (wisSkipNone, wisSkipIfBranch, wisSkipElseBranch, wisSkipAll);
  107. { TWebIDLScanner }
  108. TWebIDLScanner = class
  109. private
  110. FSource : TStringList;
  111. FCurRow: Integer;
  112. FCurToken: TIDLToken;
  113. FCurTokenString: UTF8string;
  114. FCurLine: UTF8string;
  115. FVersion: TWebIDLVersion;
  116. TokenStr: PChar;
  117. // Preprocessor #IFxxx skipping data
  118. FSkipMode: TWebIDLScannerSkipMode;
  119. FIsSkipping: Boolean;
  120. FSkipStackIndex: Integer;
  121. FSkipModeStack: array[0..255] of TWebIDLScannerSkipMode;
  122. FIsSkippingStack: array[0..255] of Boolean;
  123. function DetermineToken: TIDLToken;
  124. function DetermineToken2: TIDLToken;
  125. function FetchLine: Boolean;
  126. function GetCurColumn: Integer;
  127. function ReadComment: UTF8String;
  128. function ReadIdent: UTF8String;
  129. function ReadNumber(var S: UTF8String): TIDLToken;
  130. protected
  131. Function GetErrorPos : String;
  132. procedure Error(const Msg: string);overload;
  133. procedure Error(const Msg: string; Const Args: array of Const);overload;
  134. function ReadString: UTF8String; virtual;
  135. function DoFetchToken: TIDLToken;
  136. procedure HandleDirective; virtual;
  137. procedure HandleIfDef; virtual;
  138. procedure HandleElse; virtual;
  139. procedure HandleEndIf; virtual;
  140. procedure PushSkipMode; virtual;
  141. function IsDefined(const aName: string): boolean; virtual;
  142. procedure SkipWhitespace;
  143. procedure SkipLineBreak;
  144. public
  145. constructor Create(Source: TStream); overload;
  146. constructor Create(const Source: UTF8String); overload;
  147. constructor CreateFile(const aFileName: UTF8String);
  148. destructor Destroy; override;
  149. function FetchToken: TIDLToken;
  150. property CurLine: UTF8String read FCurLine;
  151. property CurRow: Integer read FCurRow;
  152. property CurColumn: Integer read GetCurColumn;
  153. property CurToken: TIDLToken read FCurToken;
  154. property CurTokenString: UTF8String read FCurTokenString;
  155. Property Version : TWebIDLVersion Read FVersion Write FVersion;
  156. end;
  157. const
  158. TokenInfos: array[TIDLToken] of string = (
  159. '',
  160. '',
  161. '',
  162. '',
  163. '',
  164. '',
  165. '',
  166. // Simple (one-character) tokens
  167. '.',
  168. ';',
  169. ',', // ','
  170. ':', // ':'
  171. '(', // '('
  172. ')', // ')'
  173. '{', // '{'
  174. '}', // '}'
  175. '[', // '['
  176. ']', // ']'
  177. '<',
  178. '=',
  179. '>',
  180. '?',
  181. '-',
  182. '', // Any identifier
  183. 'true',
  184. 'false',
  185. 'null',
  186. 'any',
  187. 'attribute',
  188. 'callback',
  189. 'const',
  190. 'deleter',
  191. 'dictionary',
  192. 'ellipsis',
  193. 'enum',
  194. 'getter',
  195. 'implements',
  196. 'Infinity',
  197. 'inherit',
  198. 'interface',
  199. 'iterable',
  200. 'legacycaller',
  201. 'NaN',
  202. '-Infinity',
  203. 'optional',
  204. 'or',
  205. 'partial',
  206. 'readonly',
  207. 'required',
  208. 'setter',
  209. 'static',
  210. 'stringifier',
  211. 'serializer',
  212. 'typedef',
  213. 'unrestricted',
  214. 'Promise',
  215. 'FrozenArray',
  216. 'ByteString',
  217. 'DOMString',
  218. 'USVString',
  219. 'boolean',
  220. 'byte',
  221. 'double',
  222. 'float',
  223. 'long',
  224. 'object',
  225. 'octet',
  226. 'unsigned',
  227. 'void',
  228. 'short',
  229. 'sequence',
  230. 'string',
  231. 'mixin',
  232. 'includes',
  233. 'maplike',
  234. 'record',
  235. 'setlike',
  236. 'other',
  237. 'constructor'
  238. );
  239. Function GetTokenName(aToken : TIDLToken) : String;
  240. Function GetTokenNames(aTokenList : TIDLTokens) : String;
  241. implementation
  242. uses typinfo;
  243. Resourcestring
  244. SErrUnknownTerminator = 'Unknown terminator: "%s"';
  245. SErrInvalidCharacter = 'Invalid character at line %d, pos %d: ''%s''';
  246. SUnterminatedComment = 'Unterminated comment at line %d, pos %d: ''%s''';
  247. SErrOpenString = 'string exceeds end of line';
  248. SErrInvalidEllipsis = 'Invalid ellipsis token';
  249. SErrUnknownToken = 'Unknown token, expected number or minus : "%s"';
  250. // SerrExpectedTokenButWasIdentifier = 'Invalid terminator: "%s"';
  251. Function GetTokenName(aToken : TIDLToken) : String;
  252. begin
  253. Result:=TokenInfos[aToken];
  254. if Result='' then
  255. begin
  256. Result:=GetEnumName(TypeInfo(TIDLToken),Ord(aToken));
  257. Delete(Result,1,2);
  258. end;
  259. end;
  260. Function GetTokenNames(aTokenList : TIDLTokens) : String;
  261. Var
  262. T : TIDLToken;
  263. begin
  264. Result:='';
  265. For T in aTokenList do
  266. begin
  267. if (Result<>'') then
  268. Result:=Result+',';
  269. Result:=Result+GetTokenName(T);
  270. end;
  271. end;
  272. constructor TWebIDLScanner.Create(Source: TStream);
  273. begin
  274. FSource:=TStringList.Create;
  275. FSource.LoadFromStream(Source);
  276. end;
  277. constructor TWebIDLScanner.Create(const Source: UTF8String);
  278. begin
  279. FSource:=TStringList.Create;
  280. FSource.Text:=Source;
  281. end;
  282. constructor TWebIDLScanner.CreateFile(const aFileName: UTF8String);
  283. begin
  284. FSource:=TStringList.Create;
  285. FSource.LoadFromFile(aFileName);
  286. end;
  287. destructor TWebIDLScanner.Destroy;
  288. begin
  289. FreeAndNil(FSource);
  290. Inherited;
  291. end;
  292. function TWebIDLScanner.FetchToken: TIDLToken;
  293. begin
  294. Result:=DoFetchToken;
  295. end;
  296. procedure TWebIDLScanner.Error(const Msg: string);
  297. begin
  298. raise EWebIDLScanner.Create(GetErrorPos+Msg);
  299. end;
  300. procedure TWebIDLScanner.Error(const Msg: string; const Args: array of const);
  301. begin
  302. raise EWebIDLScanner.Create(GetErrorPos+Format(Msg, Args));
  303. end;
  304. function TWebIDLScanner.ReadString : UTF8String;
  305. Var
  306. C : Char;
  307. I, OldLength, SectionLength: Integer;
  308. S : UTF8String;
  309. TokenStart: PChar;
  310. begin
  311. C:=TokenStr[0];
  312. Inc(TokenStr);
  313. TokenStart := TokenStr;
  314. OldLength := 0;
  315. Result := '';
  316. while not (TokenStr[0] in [#0,C]) do
  317. begin
  318. if (TokenStr[0]='\') then
  319. begin
  320. // Save length
  321. SectionLength := TokenStr - TokenStart;
  322. Inc(TokenStr);
  323. // Read escaped token
  324. Case TokenStr[0] of
  325. '"' : S:='"';
  326. '''' : S:='''';
  327. 't' : S:=#9;
  328. 'b' : S:=#8;
  329. 'n' : S:=#10;
  330. 'r' : S:=#13;
  331. 'f' : S:=#12;
  332. '\' : S:='\';
  333. '/' : S:='/';
  334. 'u' : begin
  335. S:='0000';
  336. For I:=1 to 4 do
  337. begin
  338. Inc(TokenStr);
  339. Case TokenStr[0] of
  340. '0'..'9','A'..'F','a'..'f' :
  341. S[i]:=Upcase(TokenStr[0]);
  342. else
  343. Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
  344. end;
  345. end;
  346. // WideChar takes care of conversion...
  347. S:=Utf8Encode(WideString(WideChar(StrToInt('$'+S))))
  348. end;
  349. #0 : Error(SErrOpenString);
  350. else
  351. Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
  352. end;
  353. SetLength(Result, OldLength + SectionLength+1+Length(S));
  354. if SectionLength > 0 then
  355. Move(TokenStart^, Result[OldLength + 1], SectionLength);
  356. Move(S[1],Result[OldLength + SectionLength+1],Length(S));
  357. Inc(OldLength, SectionLength+Length(S));
  358. // Next char
  359. // Inc(TokenStr);
  360. TokenStart := TokenStr+1;
  361. end;
  362. if TokenStr[0] = #0 then
  363. Error(SErrOpenString);
  364. Inc(TokenStr);
  365. end;
  366. if TokenStr[0] = #0 then
  367. Error(SErrOpenString);
  368. SectionLength := TokenStr - TokenStart;
  369. SetLength(Result, OldLength + SectionLength);
  370. if SectionLength > 0 then
  371. Move(TokenStart^, Result[OldLength + 1], SectionLength);
  372. Inc(TokenStr);
  373. end;
  374. function TWebIDLScanner.ReadIdent: UTF8String;
  375. Var
  376. TokenStart : PChar;
  377. SectionLength : Integer;
  378. begin
  379. Result:='';
  380. if TokenStr[0]='_' then
  381. Inc(TokenStr);
  382. if TokenStr[0]=#0 then
  383. Exit;
  384. TokenStart := TokenStr;
  385. repeat
  386. Inc(TokenStr);
  387. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  388. SectionLength := TokenStr - TokenStart;
  389. SetString(Result, TokenStart, SectionLength);
  390. end;
  391. function TWebIDLScanner.FetchLine: Boolean;
  392. begin
  393. Result:=FCurRow<FSource.Count;
  394. if Result then
  395. begin
  396. FCurLine:=FSource[FCurRow];
  397. TokenStr:=PChar(FCurLine);
  398. Inc(FCurRow);
  399. end
  400. else
  401. begin
  402. FCurLine:='';
  403. TokenStr:=nil;
  404. end;
  405. end;
  406. function TWebIDLScanner.ReadNumber(var S : UTF8String) : TIDLToken;
  407. Var
  408. TokenStart : PChar;
  409. SectionLength : Integer;
  410. isHex : Boolean;
  411. begin
  412. isHex:=False;
  413. TokenStart := TokenStr;
  414. Result:=tkNumberInteger;
  415. while true do
  416. begin
  417. Inc(TokenStr);
  418. SectionLength := TokenStr - TokenStart;
  419. case TokenStr[0] of
  420. 'x':
  421. begin
  422. isHex:=True;
  423. end;
  424. 'I':
  425. begin
  426. repeat
  427. Inc(TokenStr);
  428. until not (TokenStr[0] in ['i','n','f','t','y']);
  429. Result:=tkNegInfinity; // We'll check at the end if the string is actually correct
  430. break;
  431. end;
  432. '.':
  433. begin
  434. Result:=tkNumberFloat;
  435. if TokenStr[1] in ['0'..'9', 'e', 'E'] then
  436. begin
  437. Inc(TokenStr);
  438. repeat
  439. Inc(TokenStr);
  440. until not (TokenStr[0] in ['0'..'9', 'e', 'E','-','+']);
  441. end;
  442. break;
  443. end;
  444. '0'..'9':
  445. begin
  446. end;
  447. 'a'..'d','f',
  448. 'A'..'D','F':
  449. begin
  450. if Not isHex then
  451. Error(SErrUnknownToken,[S]);
  452. end;
  453. 'e', 'E':
  454. begin
  455. if not IsHex then
  456. begin
  457. Inc(TokenStr);
  458. if TokenStr[0] in ['-','+'] then
  459. Inc(TokenStr);
  460. while TokenStr[0] in ['0'..'9'] do
  461. Inc(TokenStr);
  462. break;
  463. end;
  464. end;
  465. else
  466. if (SectionLength=1) and (TokenStart[0]='-') then
  467. result:=tkMinus;
  468. break;
  469. end;
  470. end;
  471. SectionLength := TokenStr - TokenStart;
  472. S:='';
  473. SetString(S, TokenStart, SectionLength);
  474. if (Result=tkNegInfinity) and (S<>'-Infinity') then
  475. Error(SErrUnknownToken,[S]);
  476. if (Result=tkMinus) and (S<>'-') then
  477. Error(SErrUnknownTerminator,[s]);
  478. end;
  479. function TWebIDLScanner.GetErrorPos: String;
  480. begin
  481. Result:=Format('Scanner error at line %d, pos %d: ',[CurRow,CurColumn]);
  482. end;
  483. function TWebIDLScanner.ReadComment : UTF8String;
  484. Var
  485. TokenStart : PChar;
  486. SectionLength : Integer;
  487. EOC,IsStar : Boolean;
  488. S : String;
  489. begin
  490. Result:='';
  491. TokenStart:=TokenStr;
  492. Inc(TokenStr);
  493. Case Tokenstr[0] of
  494. '/' : begin
  495. SectionLength := Length(FCurLine)- (TokenStr - PChar(FCurLine));
  496. Inc(TokenStr);
  497. SetString(Result, TokenStr, SectionLength);
  498. Fetchline;
  499. end;
  500. '*' :
  501. begin
  502. IsStar:=False;
  503. Inc(TokenStr);
  504. TokenStart:=TokenStr;
  505. Repeat
  506. if (TokenStr[0]=#0) then
  507. begin
  508. SectionLength := (TokenStr - TokenStart);
  509. S:='';
  510. SetString(S, TokenStart, SectionLength);
  511. Result:=Result+S;
  512. if not fetchLine then
  513. Error(SUnterminatedComment, [CurRow,CurCOlumn,TokenStr[0]]);
  514. TokenStart:=TokenStr;
  515. end;
  516. IsStar:=TokenStr[0]='*';
  517. Inc(TokenStr);
  518. EOC:=(isStar and (TokenStr[0]='/'));
  519. Until EOC;
  520. if EOC then
  521. begin
  522. SectionLength := (TokenStr - TokenStart-1);
  523. S:='';
  524. SetString(S, TokenStart, SectionLength);
  525. Result:=Result+S;
  526. Inc(TokenStr);
  527. end;
  528. end;
  529. else
  530. Error(SErrInvalidCharacter, [CurRow,CurCOlumn,TokenStr[0]]);
  531. end;
  532. end;
  533. function TWebIDLScanner.DetermineToken : TIDLToken;
  534. begin
  535. Result:=High(TIDLToken);
  536. While (Result<>tkIdentifier) and (TokenInfos[result]<>FCurTokenString) do
  537. Result:=Pred(Result);
  538. if Result in VersionNonTokens[Version] then
  539. Result:=tkIdentifier;
  540. // if Result=tkIdentifier then
  541. // Error(SErrExpectedTokenButWasIdentifier,[FCurTokenString]);
  542. end;
  543. function TWebIDLScanner.DetermineToken2 : TIDLToken;
  544. Const
  545. InfTokens = [tkNan,tkInfinity,tkNegInfinity,tkByteString,tkUSVString,tkDOMString,tkPromise,tkFrozenArray];
  546. begin
  547. For Result in InfTokens do
  548. if (TokenInfos[result]=FCurTokenString) then exit;
  549. Result:=tkIdentifier;
  550. end;
  551. function TWebIDLScanner.DoFetchToken: TIDLToken;
  552. Procedure SetSingleToken(tk : TIDLToken);
  553. begin
  554. FCurTokenString:=TokenStr[0];
  555. Inc(TokenStr);
  556. Result :=tk;
  557. end;
  558. begin
  559. repeat
  560. if TokenStr = nil then
  561. if not FetchLine then
  562. begin
  563. Result := tkEOF;
  564. FCurToken := Result;
  565. exit;
  566. end;
  567. FCurTokenString := '';
  568. case TokenStr[0] of
  569. #0: // Empty line
  570. begin
  571. if not FetchLine then
  572. Result:=tkEOF
  573. else
  574. Result := tkWhitespace;
  575. end;
  576. #9, ' ':
  577. begin
  578. Result := tkWhitespace;
  579. repeat
  580. Inc(TokenStr);
  581. if TokenStr[0] = #0 then
  582. if not FetchLine then
  583. begin
  584. FCurToken := Result;
  585. exit;
  586. end;
  587. until not (TokenStr[0] in [#9, ' ']);
  588. end;
  589. '"':
  590. begin
  591. FCurTokenString:=ReadString;
  592. Result := tkString;
  593. end;
  594. ',':
  595. begin
  596. Inc(TokenStr);
  597. Result := tkComma;
  598. end;
  599. '0'..'9','-':
  600. begin
  601. Result := ReadNumber(FCurTokenString);
  602. end;
  603. ':': SetSingleToken(tkColon);
  604. '(': SetSingleToken(tkBracketOpen);
  605. ')': SetSingleToken(tkBracketClose);
  606. '{': SetSingleToken(tkCurlyBraceOpen);
  607. '}': SetSingleToken(tkCurlyBraceClose);
  608. '[': SetSingleToken(tkSquaredBraceOpen);
  609. ']': SetSingleToken(tkSquaredBraceClose);
  610. '<': SetSingleToken(tkLess);
  611. '=': SetSingleToken(tkEqual);
  612. '>': SetSingleToken(tkLarger);
  613. '?' : SetSingleToken(tkQuestionmark);
  614. ';' : SetSingleToken(tkSemicolon);
  615. '.' :
  616. begin
  617. inc(TokenStr);
  618. if TokenStr[0]<>'.' then
  619. begin
  620. Dec(Tokenstr);// Setsingletoken advances
  621. SetSingleToken(tkDot);
  622. end
  623. else
  624. begin
  625. inc(TokenStr);
  626. if TokenStr[0]<>'.' then
  627. Error(SErrInvalidEllipsis);
  628. inc(TokenStr);
  629. FCurTokenString:='...';
  630. Result:=tkEllipsis;
  631. end;
  632. end;
  633. '/' :
  634. begin
  635. FCurTokenString:=ReadComment;
  636. Result:=tkComment;
  637. end;
  638. 'a'..'z':
  639. begin
  640. FCurTokenString:=ReadIdent;
  641. Result:=DetermineToken;
  642. end;
  643. 'A'..'Z','_':
  644. begin
  645. FCurTokenString:=ReadIdent;
  646. Result:=DetermineToken2;
  647. end;
  648. '#':
  649. begin
  650. Result:=tkComment;
  651. HandleDirective;
  652. end
  653. else
  654. Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
  655. end;
  656. until FSkipMode=wisSkipNone;
  657. FCurToken := Result;
  658. end;
  659. procedure TWebIDLScanner.HandleDirective;
  660. var
  661. p: PChar;
  662. aDirective: string;
  663. begin
  664. inc(TokenStr);
  665. p:=TokenStr;
  666. while TokenStr^ in ['a'..'z','A'..'Z','_','0'..'9'] do inc(TokenStr);
  667. SetString(aDirective, p, TokenStr-p);
  668. SkipWhitespace;
  669. case lowercase(aDirective) of
  670. 'ifdef': HandleIfDef;
  671. 'else': HandleElse;
  672. 'endif': HandleEndIf;
  673. end;
  674. SkipWhitespace;
  675. SkipLineBreak;
  676. end;
  677. procedure TWebIDLScanner.HandleIfDef;
  678. var
  679. StartP: PChar;
  680. aName: string;
  681. begin
  682. PushSkipMode;
  683. if FIsSkipping then
  684. FSkipMode := wisSkipAll
  685. else
  686. begin
  687. StartP:=TokenStr;
  688. while TokenStr^ in ['a'..'z','A'..'Z','0'..'9','_'] do
  689. inc(TokenStr);
  690. SetString(aName,StartP,TokenStr-StartP);
  691. if IsDefined(aName) then
  692. FSkipMode := wisSkipElseBranch
  693. else
  694. begin
  695. FSkipMode := wisSkipIfBranch;
  696. FIsSkipping := true;
  697. end;
  698. //If LogEvent(sleConditionals) then
  699. // if FSkipMode=wisSkipElseBranch then
  700. // DoLog(mtInfo,nLogIFDefAccepted,sLogIFDefAccepted,[aName])
  701. // else
  702. // DoLog(mtInfo,nLogIFDefRejected,sLogIFDefRejected,[aName]);
  703. end;
  704. end;
  705. procedure TWebIDLScanner.HandleElse;
  706. begin
  707. if FSkipStackIndex = 0 then
  708. Error('Invalid #Else');
  709. if FSkipMode = wisSkipIfBranch then
  710. FIsSkipping := false
  711. else if FSkipMode = wisSkipElseBranch then
  712. FIsSkipping := true;
  713. end;
  714. procedure TWebIDLScanner.HandleEndIf;
  715. begin
  716. if FSkipStackIndex = 0 then
  717. Error('Invalid #EndIf');
  718. Dec(FSkipStackIndex);
  719. FSkipMode := FSkipModeStack[FSkipStackIndex];
  720. FIsSkipping := FIsSkippingStack[FSkipStackIndex];
  721. end;
  722. procedure TWebIDLScanner.PushSkipMode;
  723. begin
  724. if FSkipStackIndex = High(FSkipModeStack) then
  725. Error('Nesting of #IFxxx too deep');
  726. FSkipModeStack[FSkipStackIndex] := FSkipMode;
  727. FIsSkippingStack[FSkipStackIndex] := FIsSkipping;
  728. Inc(FSkipStackIndex);
  729. end;
  730. function TWebIDLScanner.IsDefined(const aName: string): boolean;
  731. begin
  732. Result:=false;
  733. if aName='' then ;
  734. end;
  735. procedure TWebIDLScanner.SkipWhitespace;
  736. begin
  737. while TokenStr^ in [' ',#9] do
  738. inc(TokenStr);
  739. end;
  740. procedure TWebIDLScanner.SkipLineBreak;
  741. begin
  742. case TokenStr^ of
  743. #10: inc(TokenStr);
  744. #13:
  745. begin
  746. inc(TokenStr);
  747. if TokenStr^=#10 then
  748. inc(TokenStr);
  749. end;
  750. end;
  751. end;
  752. function TWebIDLScanner.GetCurColumn: Integer;
  753. begin
  754. Result := TokenStr - PChar(CurLine);
  755. end;
  756. end.