pparser.pp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567
  1. {
  2. $Id$
  3. This file is part of the Free Component Library
  4. Pascal source parser
  5. Copyright (c) 2000-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 PParser;
  14. interface
  15. uses SysUtils, PasTree;
  16. resourcestring
  17. SErrNoSourceGiven = 'No source file specified';
  18. SErrMultipleSourceFiles = 'Please specify only one source file';
  19. SParserError = 'Error';
  20. SParserErrorAtToken = '%s at token "%s"';
  21. SParserUngetTokenError = 'Internal error: Cannot unget more tokens, history buffer is full';
  22. SParserExpectTokenError = 'Expected "%s"';
  23. SParserExpectedCommaRBracket = 'Expected "," or ")"';
  24. SParserExpectedCommaSemicolon = 'Expected "," or ";"';
  25. SParserExpectedCommaColon = 'Expected "," or ":"';
  26. SParserExpectedLBracketColon = 'Expected "(" or ":"';
  27. SParserExpectedLBracketSemicolon = 'Expected "(" or ";"';
  28. SParserExpectedColonSemicolon = 'Expected ":" or ";"';
  29. SParserExpectedSemiColonEnd = 'Expected ";" or "End"';
  30. SParserExpectedConstVarID = 'Expected "const", "var" or identifier';
  31. SParserSyntaxError = 'Syntax error';
  32. SParserTypeSyntaxError = 'Syntax error in type';
  33. SParserArrayTypeSyntaxError = 'Syntax error in array type';
  34. SParserInterfaceTokenError = 'Invalid token in interface section of unit';
  35. SParserInvalidTypeDef = 'Invalid type definition';
  36. type
  37. TPasTreeContainer = class
  38. protected
  39. FPackage: TPasPackage;
  40. public
  41. function CreateElement(AClass: TPTreeElement; const AName: String;
  42. AParent: TPasElement): TPasElement;
  43. function CreateElement(AClass: TPTreeElement; const AName: String;
  44. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  45. virtual; abstract;
  46. function CreateFunctionType(const AName: String; AParent: TPasElement;
  47. UseParentAsResultParent: Boolean): TPasFunctionType;
  48. function FindElement(const AName: String): TPasElement; virtual; abstract;
  49. function FindModule(const AName: String): TPasModule; virtual;
  50. property Package: TPasPackage read FPackage;
  51. end;
  52. EParserError = class(Exception)
  53. private
  54. FFilename: String;
  55. FRow, FColumn: Integer;
  56. public
  57. constructor Create(const AReason, AFilename: String;
  58. ARow, AColumn: Integer);
  59. property Filename: String read FFilename;
  60. property Row: Integer read FRow;
  61. property Column: Integer read FColumn;
  62. end;
  63. function ParseSource(AEngine: TPasTreeContainer;
  64. const FPCCommandLine: String): TPasModule;
  65. implementation
  66. uses Classes, PScanner;
  67. type
  68. TDeclType = (declNone, declConst, declResourcestring, declType, declVar);
  69. TPasParser = class
  70. private
  71. FFileResolver: TFileResolver;
  72. FScanner: TPascalScanner;
  73. FEngine: TPasTreeContainer;
  74. FCurToken: TToken;
  75. FCurTokenString: String;
  76. // UngetToken support:
  77. FTokenBuffer: array[0..1] of TToken;
  78. FTokenStringBuffer: array[0..1] of String;
  79. FTokenBufferIndex, FTokenBufferSize: Integer;
  80. function GetCurColumn: Integer;
  81. procedure ParseExc(const Msg: String);
  82. public
  83. constructor Create(AFileResolver: TFileResolver; AEngine: TPasTreeContainer;
  84. const AFilename: String);
  85. destructor Destroy; override;
  86. function CurTokenName: String;
  87. function CurTokenText: String;
  88. procedure NextToken;
  89. procedure UngetToken;
  90. procedure ExpectToken(tk: TToken);
  91. function ExpectIdentifier: String;
  92. function ParseType(Parent: TPasElement): TPasType;
  93. function ParseComplexType: TPasType;
  94. procedure ParseArrayType(Element: TPasArrayType);
  95. function ParseExpression: String;
  96. procedure AddProcOrFunction(ASection: TPasSection; AProc: TPasProcedure);
  97. function CheckIfOverloaded(AOwner: TPasClassType;
  98. const AName: String): TPasElement;
  99. procedure ParseMain(var Module: TPasModule);
  100. procedure ParseUnit(var Module: TPasModule);
  101. procedure ParseUsesList(ASection: TPasSection);
  102. function ParseConstDecl(Parent: TPasElement): TPasConst;
  103. function ParseResourcestringDecl(Parent: TPasElement): TPasResString;
  104. function ParseTypeDecl(Parent: TPasElement): TPasType;
  105. procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
  106. AVisibility : TPasMemberVisibility);
  107. procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList);
  108. procedure ParseVarDecl(Parent: TPasElement; List: TList);
  109. procedure ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
  110. procedure ParseProcedureOrFunctionHeader(Parent: TPasElement;
  111. Element: TPasProcedureType; IsFunction, OfObjectPossible: Boolean);
  112. function ParseProcedureOrFunctionDecl(Parent: TPasElement;
  113. IsFunction: Boolean): TPasProcedure;
  114. procedure ParseRecordDecl(Parent: TPasRecordType);
  115. function ParseClassDecl(Parent: TPasElement; const AClassName: String;
  116. AObjKind: TPasObjKind): TPasType;
  117. property FileResolver: TFileResolver read FFileResolver;
  118. property Scanner: TPascalScanner read FScanner;
  119. property Engine: TPasTreeContainer read FEngine;
  120. property CurToken: TToken read FCurToken;
  121. property CurTokenString: String read FCurTokenString;
  122. end;
  123. function TPasTreeContainer.CreateElement(AClass: TPTreeElement;
  124. const AName: String; AParent: TPasElement): TPasElement;
  125. begin
  126. Result := CreateElement(AClass, AName, AParent, visDefault);
  127. end;
  128. function TPasTreeContainer.CreateFunctionType(const AName: String;
  129. AParent: TPasElement; UseParentAsResultParent: Boolean): TPasFunctionType;
  130. var
  131. ResultParent: TPasElement;
  132. begin
  133. Result := TPasFunctionType(CreateElement(TPasFunctionType, AName, AParent));
  134. if UseParentAsResultParent then
  135. ResultParent := AParent
  136. else
  137. ResultParent := Result;
  138. TPasFunctionType(Result).ResultEl :=
  139. TPasResultElement(CreateElement(TPasResultElement, 'Result', ResultParent));
  140. end;
  141. function TPasTreeContainer.FindModule(const AName: String): TPasModule;
  142. begin
  143. Result := nil;
  144. end;
  145. constructor EParserError.Create(const AReason, AFilename: String;
  146. ARow, AColumn: Integer);
  147. begin
  148. inherited Create(AReason);
  149. FFilename := AFilename;
  150. FRow := ARow;
  151. FColumn := AColumn;
  152. end;
  153. procedure TPasParser.ParseExc(const Msg: String);
  154. begin
  155. raise EParserError.Create(Format(SParserErrorAtToken, [Msg, CurTokenName]),
  156. Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
  157. end;
  158. constructor TPasParser.Create(AFileResolver: TFileResolver;
  159. AEngine: TPasTreeContainer; const AFilename: String);
  160. begin
  161. inherited Create;
  162. FFileResolver := AFileResolver;
  163. FEngine := AEngine;
  164. FScanner := TPascalScanner.Create(FileResolver, AFilename);
  165. end;
  166. destructor TPasParser.Destroy;
  167. begin
  168. Scanner.Free;
  169. inherited Destroy;
  170. end;
  171. function TPasParser.CurTokenName: String;
  172. begin
  173. if CurToken = tkIdentifier then
  174. Result := 'Identifier ' + Scanner.CurTokenString
  175. else
  176. Result := TokenInfos[CurToken];
  177. end;
  178. function TPasParser.CurTokenText: String;
  179. begin
  180. case CurToken of
  181. tkIdentifier, tkString, tkNumber, tkChar:
  182. Result := Scanner.CurTokenString;
  183. else
  184. Result := TokenInfos[CurToken];
  185. end;
  186. end;
  187. procedure TPasParser.NextToken;
  188. begin
  189. if FTokenBufferIndex < FTokenBufferSize then
  190. begin
  191. // Get token from buffer
  192. FCurToken := FTokenBuffer[FTokenBufferIndex];
  193. FCurTokenString := FTokenStringBuffer[FTokenBufferIndex];
  194. Inc(FTokenBufferIndex);
  195. end else
  196. begin
  197. { We have to fetch a new token. But first check, wether there is space left
  198. in the token buffer.}
  199. if FTokenBufferSize = 2 then
  200. begin
  201. FTokenBuffer[0] := FTokenBuffer[1];
  202. FTokenStringBuffer[0] := FTokenStringBuffer[1];
  203. Dec(FTokenBufferSize);
  204. Dec(FTokenBufferIndex);
  205. end;
  206. // Fetch new token
  207. repeat
  208. FCurToken := Scanner.FetchToken;
  209. //WriteLn('Token: ', TokenInfos[CurToken], ' ', Scanner.CurTokenString);
  210. until not (FCurToken in [tkWhitespace, tkComment]);
  211. FCurTokenString := Scanner.CurTokenString;
  212. FTokenBuffer[FTokenBufferSize] := FCurToken;
  213. FTokenStringBuffer[FTokenBufferSize] := FCurTokenString;
  214. Inc(FTokenBufferSize);
  215. Inc(FTokenBufferIndex);
  216. end;
  217. end;
  218. procedure TPasParser.UngetToken;
  219. begin
  220. if FTokenBufferIndex = 0 then
  221. ParseExc(SParserUngetTokenError)
  222. else
  223. Dec(FTokenBufferIndex);
  224. end;
  225. procedure TPasParser.ExpectToken(tk: TToken);
  226. begin
  227. NextToken;
  228. if CurToken <> tk then
  229. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tk]]));
  230. end;
  231. function TPasParser.ExpectIdentifier: String;
  232. begin
  233. ExpectToken(tkIdentifier);
  234. Result := CurTokenString;
  235. end;
  236. function TPasParser.ParseType(Parent: TPasElement): TPasType;
  237. var
  238. TypeToken: TToken;
  239. Name, s: String;
  240. EnumValue: TPasEnumValue;
  241. Ref: TPasElement;
  242. begin
  243. Result := nil; // !!!: Remove in the future
  244. NextToken;
  245. case CurToken of
  246. tkIdentifier:
  247. begin
  248. TypeToken := CurToken;
  249. Name := CurTokenString;
  250. NextToken;
  251. if CurToken = tkDot then
  252. begin
  253. ExpectIdentifier;
  254. Name := CurTokenString;
  255. end else
  256. UngetToken;
  257. Ref := nil;
  258. s := UpperCase(Name);
  259. if s = 'BYTE' then Name := 'Byte'
  260. else if s = 'BOOLEAN' then Name := 'Boolean'
  261. else if s = 'CHAR' then Name := 'Char'
  262. else if s = 'INTEGER' then Name := 'Integer'
  263. else if s = 'INT64' then Name := 'Int64'
  264. else if s = 'LONGINT' then Name := 'LongInt'
  265. else if s = 'LONGWORD' then Name := 'LongWord'
  266. else if s = 'SHORTINT' then Name := 'ShortInt'
  267. else if s = 'SMALLINT' then Name := 'SmallInt'
  268. else if s = 'STRING' then Name := 'String'
  269. else if s = 'WORD' then Name := 'Word'
  270. else
  271. Ref := Engine.FindElement(Name);
  272. if Assigned(Ref) then
  273. begin
  274. {Result := TPasTypeRef(Engine.CreateElement(TPasTypeRef, Name, nil));
  275. TPasTypeRef(Result).RefType := Ref as TPasType;}
  276. Result := Ref as TPasType;
  277. Result.AddRef;
  278. end else
  279. Result := TPasUnresolvedTypeRef(Engine.CreateElement(TPasUnresolvedTypeRef, Name, nil));
  280. // !!!: Doesn't make sense for resolved types
  281. if Name = 'String' then
  282. begin
  283. NextToken;
  284. if CurToken = tkSquaredBraceOpen then
  285. begin
  286. // !!!: Parse the string length value and store it
  287. repeat
  288. NextToken;
  289. until CurToken = tkSquaredBraceClose;
  290. end else
  291. UngetToken;
  292. end;
  293. end;
  294. tkCaret:
  295. begin
  296. Result := TPasPointerType(
  297. Engine.CreateElement(TPasPointerType, '', Parent));
  298. TPasPointerType(Result).DestType := ParseType(nil);
  299. end;
  300. tkArray:
  301. begin
  302. Result := TPasArrayType(Engine.CreateElement(TPasArrayType, '', Parent));
  303. ParseArrayType(TPasArrayType(Result));
  304. end;
  305. tkBraceOpen:
  306. begin
  307. Result := TPasEnumType(Engine.CreateElement(TPasEnumType, '', Parent));
  308. while True do
  309. begin
  310. NextToken;
  311. EnumValue := TPasEnumValue(Engine.CreateElement(TPasEnumValue,
  312. CurTokenString, Result));
  313. TPasEnumType(Result).Values.Add(EnumValue);
  314. NextToken;
  315. if CurToken = tkBraceClose then
  316. break
  317. else if CurToken <> tkComma then
  318. ParseExc(SParserExpectedCommaRBracket);
  319. end;
  320. end;
  321. tkRecord:
  322. begin
  323. Result := TPasRecordType(
  324. Engine.CreateElement(TPasRecordType, '', Parent));
  325. ParseRecordDecl(TPasRecordType(Result));
  326. UngetToken;
  327. end;
  328. else
  329. ParseExc(SParserTypeSyntaxError);
  330. end;
  331. end;
  332. function TPasParser.ParseComplexType: TPasType;
  333. begin
  334. NextToken;
  335. case CurToken of
  336. tkProcedure:
  337. begin
  338. Result := TPasProcedureType(
  339. Engine.CreateElement(TPasProcedureType, '', nil));
  340. ParseProcedureOrFunctionHeader(Result,
  341. TPasProcedureType(Result), False, True);
  342. UngetToken; // Unget semicolon
  343. end;
  344. tkFunction:
  345. begin
  346. Result := Engine.CreateFunctionType('', nil, False);
  347. ParseProcedureOrFunctionHeader(Result,
  348. TPasFunctionType(Result), True, True);
  349. UngetToken; // Unget semicolon
  350. end;
  351. else
  352. begin
  353. UngetToken;
  354. Result := ParseType(nil);
  355. exit;
  356. end;
  357. end;
  358. end;
  359. procedure TPasParser.ParseArrayType(Element: TPasArrayType);
  360. Var
  361. S : String;
  362. begin
  363. NextToken;
  364. S:='';
  365. case CurToken of
  366. tkSquaredBraceOpen:
  367. begin
  368. repeat
  369. NextToken;
  370. if CurToken<>tkSquaredBraceClose then
  371. S:=S+CurTokenText;
  372. until CurToken = tkSquaredBraceClose;
  373. Element.IndexRange:=S;
  374. ExpectToken(tkOf);
  375. Element.ElType := ParseType(nil);
  376. end;
  377. tkOf:
  378. begin
  379. NextToken;
  380. if CurToken = tkConst then
  381. // ArrayEl.AppendChild(Doc.CreateElement('const'))
  382. else
  383. begin
  384. UngetToken;
  385. Element.ElType := ParseType(nil);
  386. end
  387. end
  388. else
  389. ParseExc(SParserArrayTypeSyntaxError);
  390. end;
  391. end;
  392. function TPasParser.ParseExpression: String;
  393. var
  394. BracketLevel: Integer;
  395. MayAppendSpace, AppendSpace, NextAppendSpace: Boolean;
  396. begin
  397. SetLength(Result, 0);
  398. BracketLevel := 0;
  399. MayAppendSpace := False;
  400. AppendSpace := False;
  401. while True do
  402. begin
  403. NextToken;
  404. { !!!: Does not detect when normal brackets and square brackets are mixed
  405. in a wrong way. }
  406. if CurToken in [tkBraceOpen, tkSquaredBraceOpen] then
  407. Inc(BracketLevel)
  408. else if CurToken in [tkBraceClose, tkSquaredBraceClose] then
  409. begin
  410. if BracketLevel = 0 then
  411. break;
  412. Dec(BracketLevel);
  413. end else if (CurToken in [tkComma, tkSemicolon, tkColon, tkSquaredBraceClose,
  414. tkDotDot]) and (BracketLevel = 0) then
  415. break;
  416. if MayAppendSpace then
  417. begin
  418. NextAppendSpace := False;
  419. case CurToken of
  420. tkBraceOpen, tkBraceClose, tkDivision, tkEqual, tkCaret, tkAnd, tkAs,
  421. tkDiv, tkIn, tkIs, tkMinus, tkMod, tkMul, tkNot, tkOf, tkOn,
  422. tkOr, tkPlus, tkSHL, tkSHR, tkXOR:
  423. { tkPlus.._ASSIGNMENT, _UNEQUAL, tkPlusASN.._XORASN, _AS, _AT, _IN, _IS,
  424. tkOf, _ON, _OR, _AND, _DIV, _MOD, _NOT, _SHL, _SHR, _XOR:}
  425. begin
  426. AppendSpace := True;
  427. NextAppendSpace := True;
  428. end;
  429. end;
  430. if AppendSpace then
  431. Result := Result + ' ';
  432. AppendSpace := NextAppendSpace;
  433. end else
  434. MayAppendSpace := True;
  435. Result := Result + CurTokenText;
  436. end;
  437. UngetToken;
  438. end;
  439. procedure TPasParser.AddProcOrFunction(ASection: TPasSection;
  440. AProc: TPasProcedure);
  441. var
  442. i: Integer;
  443. Member: TPasElement;
  444. OverloadedProc: TPasOverloadedProc;
  445. begin
  446. for i := 0 to ASection.Functions.Count - 1 do
  447. begin
  448. Member := TPasElement(ASection.Functions[i]);
  449. if CompareText(Member.Name, AProc.Name) = 0 then
  450. begin
  451. if Member.ClassType = TPasOverloadedProc then
  452. TPasOverloadedProc(Member).Overloads.Add(AProc)
  453. else
  454. begin
  455. OverloadedProc := TPasOverloadedProc.Create(AProc.Name, ASection);
  456. OverloadedProc.Overloads.Add(Member);
  457. OverloadedProc.Overloads.Add(AProc);
  458. ASection.Functions[i] := OverloadedProc;
  459. ASection.Declarations[ASection.Declarations.IndexOf(Member)] :=
  460. OverloadedProc;
  461. end;
  462. exit;
  463. end;
  464. end;
  465. // Not overloaded, so just add the proc/function to the lists
  466. ASection.Declarations.Add(AProc);
  467. ASection.Functions.Add(AProc);
  468. end;
  469. // Returns the parent for an element which is to be created
  470. function TPasParser.CheckIfOverloaded(AOwner: TPasClassType;
  471. const AName: String): TPasElement;
  472. var
  473. i: Integer;
  474. Member: TPasElement;
  475. begin
  476. for i := 0 to AOwner.Members.Count - 1 do
  477. begin
  478. Member := TPasElement(AOwner.Members[i]);
  479. if CompareText(Member.Name, AName) = 0 then
  480. begin
  481. if Member.ClassType = TPasOverloadedProc then
  482. Result := Member
  483. else
  484. begin
  485. Result := TPasOverloadedProc.Create(AName, AOwner);
  486. Result.Visibility := Member.Visibility;
  487. TPasOverloadedProc(Result).Overloads.Add(Member);
  488. AOwner.Members[i] := Result;
  489. end;
  490. exit;
  491. end;
  492. end;
  493. Result := AOwner;
  494. end;
  495. procedure TPasParser.ParseMain(var Module: TPasModule);
  496. begin
  497. NextToken;
  498. case CurToken of
  499. tkUnit: ParseUnit(Module);
  500. else
  501. ParseExc(Format(SParserExpectTokenError, ['unit']));
  502. end;
  503. end;
  504. // Starts after the "unit" token
  505. procedure TPasParser.ParseUnit(var Module: TPasModule);
  506. var
  507. CurBlock: TDeclType;
  508. Section: TPasSection;
  509. ConstEl: TPasConst;
  510. ResStrEl: TPasResString;
  511. TypeEl: TPasType;
  512. ClassEl: TPasClassType;
  513. List: TList;
  514. i: Integer;
  515. VarEl: TPasVariable;
  516. begin
  517. Module := nil;
  518. Module := TPasModule(Engine.
  519. CreateElement(TPasModule, ExpectIdentifier, Engine.Package));
  520. if Assigned(Engine.Package) then
  521. begin
  522. Module.PackageName := Engine.Package.Name;
  523. Engine.Package.Modules.Add(Module);
  524. end;
  525. ExpectToken(tkSemicolon);
  526. ExpectToken(tkInterface);
  527. Section := TPasSection(Engine.CreateElement(TPasSection, '', Module));
  528. Module.InterfaceSection := Section;
  529. CurBlock := declNone;
  530. while True do
  531. begin
  532. NextToken;
  533. if CurToken = tkImplementation then
  534. break;
  535. case CurToken of
  536. tkUses:
  537. ParseUsesList(Section);
  538. tkConst:
  539. CurBlock := declConst;
  540. tkResourcestring:
  541. CurBlock := declResourcestring;
  542. tkType:
  543. CurBlock := declType;
  544. tkVar:
  545. CurBlock := declVar;
  546. tkProcedure:
  547. begin
  548. AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, False));
  549. CurBlock := declNone;
  550. end;
  551. tkFunction:
  552. begin
  553. AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, True));
  554. CurBlock := declNone;
  555. end;
  556. tkOperator:
  557. begin
  558. // !!!: Not supported yet
  559. i := 0;
  560. repeat
  561. NextToken;
  562. if CurToken = tkBraceOpen then
  563. Inc(i)
  564. else if CurToken = tkBraceClose then
  565. Dec(i);
  566. until (CurToken = tkSemicolon) and (i = 0);
  567. CurBlock := declNone;
  568. end;
  569. tkIdentifier:
  570. begin
  571. case CurBlock of
  572. declConst:
  573. begin
  574. ConstEl := ParseConstDecl(Section);
  575. Section.Declarations.Add(ConstEl);
  576. Section.Consts.Add(ConstEl);
  577. end;
  578. declResourcestring:
  579. begin
  580. ResStrEl := ParseResourcestringDecl(Section);
  581. Section.Declarations.Add(ResStrEl);
  582. Section.ResStrings.Add(ResStrEl);
  583. end;
  584. declType:
  585. begin
  586. TypeEl := ParseTypeDecl(Section);
  587. if Assigned(TypeEl) then // !!!
  588. begin
  589. Section.Declarations.Add(TypeEl);
  590. if TypeEl.ClassType = TPasClassType then
  591. begin
  592. // Remove previous forward declarations, if necessary
  593. for i := 0 to Section.Classes.Count - 1 do
  594. begin
  595. ClassEl := TPasClassType(Section.Classes[i]);
  596. if CompareText(ClassEl.Name, TypeEl.Name) = 0 then
  597. begin
  598. Section.Classes.Delete(i);
  599. for i := 0 to Section.Declarations.Count - 1 do
  600. if CompareText(TypeEl.Name,
  601. TPasElement(Section.Declarations[i]).Name) = 0 then
  602. begin
  603. Section.Declarations.Delete(i);
  604. break;
  605. end;
  606. ClassEl.Release;
  607. break;
  608. end;
  609. end;
  610. // Add the new class to the class list
  611. Section.Classes.Add(TypeEl)
  612. end else
  613. Section.Types.Add(TypeEl);
  614. end;
  615. end;
  616. declVar:
  617. begin
  618. List := TList.Create;
  619. try
  620. ParseVarDecl(Section, List);
  621. for i := 0 to List.Count - 1 do
  622. begin
  623. VarEl := TPasVariable(List[i]);
  624. Section.Declarations.Add(VarEl);
  625. Section.Variables.Add(VarEl);
  626. end;
  627. finally
  628. List.Free;
  629. end;
  630. end;
  631. else
  632. ParseExc(SParserSyntaxError);
  633. end;
  634. end;
  635. else
  636. ParseExc(SParserInterfaceTokenError);
  637. end;
  638. end;
  639. end;
  640. // Starts after the "uses" token
  641. procedure TPasParser.ParseUsesList(ASection: TPasSection);
  642. var
  643. UnitName: String;
  644. Element: TPasElement;
  645. begin
  646. while True do
  647. begin
  648. UnitName := ExpectIdentifier;
  649. Element := Engine.FindModule(UnitName);
  650. if Assigned(Element) then
  651. Element.AddRef
  652. else
  653. Element := TPasType(Engine.CreateElement(TPasUnresolvedTypeRef,
  654. UnitName, ASection));
  655. ASection.UsesList.Add(Element);
  656. NextToken;
  657. if CurToken = tkSemicolon then
  658. break
  659. else if CurToken <> tkComma then
  660. ParseExc(SParserExpectedCommaSemicolon);
  661. end;
  662. end;
  663. // Starts after the variable name
  664. function TPasParser.ParseConstDecl(Parent: TPasElement): TPasConst;
  665. begin
  666. Result := TPasConst(Engine.CreateElement(TPasConst, CurTokenString, Parent));
  667. NextToken;
  668. if CurToken = tkColon then
  669. Result.VarType := ParseType(nil)
  670. else
  671. UngetToken;
  672. ExpectToken(tkEqual);
  673. Result.Value := ParseExpression;
  674. ExpectToken(tkSemicolon);
  675. end;
  676. // Starts after the variable name
  677. function TPasParser.ParseResourcestringDecl(Parent: TPasElement): TPasResString;
  678. begin
  679. Result := TPasResString(
  680. Engine.CreateElement(TPasResString, CurTokenString, Parent));
  681. ExpectToken(tkEqual);
  682. ExpectToken(tkString);
  683. Result.Value := CurTokenString;
  684. ExpectToken(tkSemicolon);
  685. end;
  686. // Starts after the type name
  687. function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType;
  688. var
  689. TypeName: String;
  690. procedure ParseRange;
  691. begin
  692. Result := TPasRangeType(Engine.CreateElement(TPasRangeType, TypeName, Parent));
  693. TPasRangeType(Result).RangeStart := ParseExpression;
  694. ExpectToken(tkDotDot);
  695. TPasRangeType(Result).RangeEnd := ParseExpression;
  696. ExpectToken(tkSemicolon);
  697. end;
  698. var
  699. EnumValue: TPasEnumValue;
  700. begin
  701. TypeName := CurTokenString;
  702. ExpectToken(tkEqual);
  703. NextToken;
  704. case CurToken of
  705. tkRecord:
  706. begin
  707. Result := TPasRecordType(
  708. Engine.CreateElement(TPasRecordType, TypeName, Parent));
  709. ParseRecordDecl(TPasRecordType(Result));
  710. end;
  711. tkPacked:
  712. begin
  713. Result := TPasRecordType(
  714. Engine.CreateElement(TPasRecordType, TypeName, Parent));
  715. TPasRecordType(Result).IsPacked := True;
  716. ExpectToken(tkRecord);
  717. ParseRecordDecl(TPasRecordType(Result));
  718. end;
  719. tkObject:
  720. Result := ParseClassDecl(Parent, TypeName, okObject);
  721. tkClass:
  722. Result := ParseClassDecl(Parent, TypeName, okClass);
  723. tkInterface:
  724. Result := ParseClassDecl(Parent, TypeName, okInterface);
  725. tkCaret:
  726. begin
  727. Result := TPasPointerType(
  728. Engine.CreateElement(TPasPointerType, TypeName, Parent));
  729. TPasPointerType(Result).DestType := ParseType(nil);
  730. ExpectToken(tkSemicolon);
  731. end;
  732. tkIdentifier:
  733. begin
  734. NextToken;
  735. if CurToken = tkSemicolon then
  736. begin
  737. UngetToken;
  738. UngetToken;
  739. Result := TPasAliasType(
  740. Engine.CreateElement(TPasAliasType, TypeName, Parent));
  741. TPasAliasType(Result).DestType := ParseType(nil);
  742. ExpectToken(tkSemicolon);
  743. end else
  744. begin
  745. UngetToken;
  746. UngetToken;
  747. ParseRange;
  748. end;
  749. end;
  750. { _STRING, _FILE:
  751. begin
  752. Result := TPasAliasType(
  753. Engine.CreateElement(TPasAliasType, TypeName, Parent));
  754. UngetToken;
  755. TPasAliasType(Result).DestType := ParseType(nil);
  756. ExpectToken(tkSemicolon);
  757. end;}
  758. tkArray:
  759. begin
  760. Result := TPasArrayType(
  761. Engine.CreateElement(TPasArrayType, TypeName, Parent));
  762. ParseArrayType(TPasArrayType(Result));
  763. ExpectToken(tkSemicolon);
  764. end;
  765. tkSet:
  766. begin
  767. Result := TPasSetType(
  768. Engine.CreateElement(TPasSetType, TypeName, Parent));
  769. ExpectToken(tkOf);
  770. TPasSetType(Result).EnumType := ParseType(Result);
  771. ExpectToken(tkSemicolon);
  772. end;
  773. tkBraceOpen:
  774. begin
  775. Result := TPasEnumType(
  776. Engine.CreateElement(TPasEnumType, TypeName, Parent));
  777. while True do
  778. begin
  779. NextToken;
  780. EnumValue := TPasEnumValue(
  781. Engine.CreateElement(TPasEnumValue, CurTokenString, Result));
  782. TPasEnumType(Result).Values.Add(EnumValue);
  783. NextToken;
  784. if CurToken = tkBraceClose then
  785. break
  786. else if CurToken <> tkComma then
  787. ParseExc(SParserExpectedCommaRBracket);
  788. end;
  789. ExpectToken(tkSemicolon);
  790. end;
  791. tkProcedure:
  792. begin
  793. Result := TPasProcedureType(
  794. Engine.CreateElement(TPasProcedureType, TypeName, Parent));
  795. ParseProcedureOrFunctionHeader(Result,
  796. TPasProcedureType(Result), False, True);
  797. end;
  798. tkFunction:
  799. begin
  800. Result := Engine.CreateFunctionType(TypeName, Parent, False);
  801. ParseProcedureOrFunctionHeader(Result,
  802. TPasFunctionType(Result), True, True);
  803. end;
  804. tkType:
  805. begin
  806. Result := TPasTypeAliasType(
  807. Engine.CreateElement(TPasTypeAliasType, TypeName, Parent));
  808. TPasTypeAliasType(Result).DestType := ParseType(nil);
  809. ExpectToken(tkSemicolon);
  810. end;
  811. else
  812. begin
  813. UngetToken;
  814. ParseRange;
  815. end;
  816. end;
  817. end;
  818. // Starts after the variable name
  819. procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList);
  820. begin
  821. ParseInlineVarDecl(Parent,Varlist,visDefault);
  822. end;
  823. procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
  824. AVisibility : TPasMemberVisibility);
  825. var
  826. VarNames: TStringList;
  827. i: Integer;
  828. VarType: TPasType;
  829. VarEl: TPasVariable;
  830. begin
  831. VarNames := TStringList.Create;
  832. try
  833. while True do
  834. begin
  835. VarNames.Add(CurTokenString);
  836. NextToken;
  837. if CurToken = tkColon then
  838. break
  839. else if CurToken <> tkComma then
  840. ParseExc(SParserExpectedCommaColon);
  841. ExpectIdentifier;
  842. end;
  843. VarType := ParseType(nil);
  844. for i := 0 to VarNames.Count - 1 do
  845. begin
  846. VarEl := TPasVariable(
  847. Engine.CreateElement(TPasVariable, VarNames[i], Parent, AVisibility));
  848. VarEl.VarType := VarType;
  849. if i > 0 then
  850. VarType.AddRef;
  851. VarList.Add(VarEl);
  852. end;
  853. NextToken;
  854. // Records may be terminated with end, no semicolon
  855. If (CurToken<>tkEnd) and (CurToken<>tkSemicolon) then
  856. ParseExc(SParserExpectedSemiColonEnd)
  857. finally
  858. VarNames.Free;
  859. end;
  860. end;
  861. // Starts after the variable name
  862. procedure TPasParser.ParseVarDecl(Parent: TPasElement; List: TList);
  863. var
  864. i: Integer;
  865. VarType: TPasType;
  866. Value, S: String;
  867. U,M: string;
  868. begin
  869. while True do
  870. begin
  871. List.Add(Engine.CreateElement(TPasVariable, CurTokenString, Parent));
  872. NextToken;
  873. if CurToken = tkColon then
  874. break
  875. else if CurToken <> tkComma then
  876. ParseExc(SParserExpectedCommaColon);
  877. ExpectIdentifier;
  878. end;
  879. VarType := ParseComplexType;
  880. for i := 0 to List.Count - 1 do
  881. begin
  882. TPasVariable(List[i]).VarType := VarType;
  883. if i > 0 then
  884. VarType.AddRef;
  885. end;
  886. NextToken;
  887. If CurToken=tkEqual then
  888. begin
  889. Value := ParseExpression;
  890. for i := 0 to List.Count - 1 do
  891. TPasVariable(List[i]).Value := Value;
  892. end
  893. else
  894. UngetToken;
  895. NextToken;
  896. if CurToken = tkAbsolute then
  897. begin
  898. // !!!: Store this information
  899. ExpectIdentifier;
  900. end else
  901. UngetToken;
  902. ExpectToken(tkSemicolon);
  903. M := '';
  904. while True do
  905. begin
  906. NextToken;
  907. if CurToken = tkIdentifier then
  908. begin
  909. s := UpperCase(CurTokenText);
  910. if s = 'CVAR' then
  911. begin
  912. M := M + '; cvar';
  913. ExpectToken(tkSemicolon);
  914. end else if (s = 'EXTERNAL') or (s = 'PUBLIC') or (s = 'EXPORT') then
  915. begin
  916. M := M + ';' + CurTokenText;
  917. if s = 'EXTERNAL' then
  918. begin
  919. NextToken;
  920. if (CurToken = tkString) or (CurToken = tkIdentifier) then
  921. begin
  922. // !!!: Is this really correct for tkString?
  923. M := M + ' ' + CurTokenText;
  924. NextToken;
  925. end;
  926. end else
  927. NextToken;
  928. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'NAME') then
  929. begin
  930. M := M + ' name ';
  931. NextToken;
  932. if (CurToken = tkString) or (CurToken = tkIdentifier) then
  933. // !!!: Is this really correct for tkString?
  934. M := M + CurTokenText
  935. else
  936. ParseExc(SParserSyntaxError);
  937. ExpectToken(tkSemicolon);
  938. end else if CurToken <> tkSemicolon then
  939. ParseExc(SParserSyntaxError);
  940. end else
  941. begin
  942. UngetToken;
  943. break;
  944. end
  945. end else
  946. begin
  947. UngetToken;
  948. break;
  949. end;
  950. end; // while
  951. if M <> '' then
  952. for i := 0 to List.Count - 1 do
  953. TPasVariable(List[i]).Modifiers := M;
  954. end;
  955. // Starts after the opening bracket token
  956. procedure TPasParser.ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
  957. var
  958. ArgNames: TStringList;
  959. IsUntyped: Boolean;
  960. Name, Value: String;
  961. i: Integer;
  962. Arg: TPasArgument;
  963. Access: TArgumentAccess;
  964. ArgType: TPasType;
  965. begin
  966. while True do
  967. begin
  968. ArgNames := TStringList.Create;
  969. Access := argDefault;
  970. IsUntyped := False;
  971. ArgType := nil;
  972. while True do
  973. begin
  974. NextToken;
  975. if CurToken = tkConst then
  976. begin
  977. Access := argConst;
  978. Name := ExpectIdentifier;
  979. end else if CurToken = tkVar then
  980. begin
  981. Access := ArgVar;
  982. Name := ExpectIdentifier;
  983. end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OUT') then
  984. begin
  985. Access := ArgOut;
  986. Name := ExpectIdentifier;
  987. end else if CurToken = tkIdentifier then
  988. Name := CurTokenString
  989. else
  990. ParseExc(SParserExpectedConstVarID);
  991. ArgNames.Add(Name);
  992. NextToken;
  993. if CurToken = tkColon then
  994. break
  995. else if ((CurToken = tkSemicolon) or (CurToken = tkBraceClose)) and
  996. (Access <> argDefault) then
  997. begin
  998. // found an untyped const or var argument
  999. UngetToken;
  1000. IsUntyped := True;
  1001. break
  1002. end
  1003. else if CurToken <> tkComma then
  1004. ParseExc(SParserExpectedCommaColon);
  1005. end;
  1006. SetLength(Value, 0);
  1007. if not IsUntyped then
  1008. begin
  1009. ArgType := ParseType(nil);
  1010. NextToken;
  1011. if CurToken = tkEqual then
  1012. begin
  1013. Value := ParseExpression;
  1014. end else
  1015. UngetToken;
  1016. end;
  1017. for i := 0 to ArgNames.Count - 1 do
  1018. begin
  1019. Arg := TPasArgument(
  1020. Engine.CreateElement(TPasArgument, ArgNames[i], Parent));
  1021. Arg.Access := Access;
  1022. Arg.ArgType := ArgType;
  1023. if (i > 0) and Assigned(ArgType) then
  1024. ArgType.AddRef;
  1025. Arg.Value := Value;
  1026. Args.Add(Arg);
  1027. end;
  1028. ArgNames.Free;
  1029. NextToken;
  1030. if CurToken = EndToken then
  1031. break;
  1032. end;
  1033. end;
  1034. // Next token is expected to be a "(", ";" or for a function ":". The caller
  1035. // will get the token after the final ";" as next token.
  1036. procedure TPasParser.ParseProcedureOrFunctionHeader(Parent: TPasElement;
  1037. Element: TPasProcedureType; IsFunction, OfObjectPossible: Boolean);
  1038. begin
  1039. NextToken;
  1040. if IsFunction then
  1041. begin
  1042. if CurToken = tkBraceOpen then
  1043. begin
  1044. ParseArgList(Parent, Element.Args, tkBraceClose);
  1045. ExpectToken(tkColon);
  1046. end else if CurToken <> tkColon then
  1047. ParseExc(SParserExpectedLBracketColon);
  1048. if Assigned(Element) then // !!!
  1049. TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
  1050. else
  1051. ParseType(nil);
  1052. end else
  1053. begin
  1054. if CurToken = tkBraceOpen then
  1055. begin
  1056. ParseArgList(Element, Element.Args, tkBraceClose);
  1057. end else if (CurToken = tkSemicolon) or (OfObjectPossible and (CurToken = tkOf)) then
  1058. UngetToken
  1059. else
  1060. ParseExc(SParserExpectedLBracketSemicolon);
  1061. end;
  1062. NextToken;
  1063. if OfObjectPossible and (CurToken = tkOf) then
  1064. begin
  1065. ExpectToken(tkObject);
  1066. Element.IsOfObject := True;
  1067. end else
  1068. UngetToken;
  1069. ExpectToken(tkSemicolon);
  1070. while True do
  1071. begin
  1072. NextToken;
  1073. if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'CDECL') then
  1074. begin
  1075. { El['calling-conv'] := 'cdecl';}
  1076. ExpectToken(tkSemicolon);
  1077. end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'STDCALL') then
  1078. begin
  1079. { El['calling-conv'] := 'stdcall';}
  1080. ExpectToken(tkSemicolon);
  1081. end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'EXTERNAL') then
  1082. begin
  1083. repeat
  1084. NextToken
  1085. until CurToken = tkSemicolon;
  1086. end else if Parent.InheritsFrom(TPasProcedure) and
  1087. (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OVERLOAD') then
  1088. begin
  1089. TPasProcedure(Parent).IsOverload := True;
  1090. ExpectToken(tkSemicolon);
  1091. end else
  1092. begin
  1093. UngetToken;
  1094. break;
  1095. end;
  1096. end;
  1097. end;
  1098. // Starts after the "procedure" or "function" token
  1099. function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
  1100. IsFunction: Boolean): TPasProcedure;
  1101. var
  1102. Name: String;
  1103. begin
  1104. Name := ExpectIdentifier;
  1105. if IsFunction then
  1106. begin
  1107. Result := TPasFunction(Engine.CreateElement(TPasFunction, Name, Parent));
  1108. Result.ProcType := Engine.CreateFunctionType('', Result, True);
  1109. end else
  1110. begin
  1111. Result := TPasProcedure(Engine.CreateElement(TPasProcedure, Name, Parent));
  1112. Result.ProcType := TPasProcedureType(
  1113. Engine.CreateElement(TPasProcedureType, '', Result));
  1114. end;
  1115. ParseProcedureOrFunctionHeader(Result, Result.ProcType, IsFunction, False);
  1116. end;
  1117. // Starts after the "record" token
  1118. procedure TPasParser.ParseRecordDecl(Parent: TPasRecordType);
  1119. Var
  1120. CCount : Integer;
  1121. begin
  1122. while True do
  1123. begin
  1124. if CurToken = tkEnd then
  1125. break;
  1126. NextToken;
  1127. if CurToken = tkEnd then
  1128. break
  1129. else if CurToken = tkCase then
  1130. begin
  1131. CCount:=0;
  1132. Repeat
  1133. NextToken;
  1134. If CurToken=tkBraceOpen then
  1135. inc(CCount)
  1136. else If CurToken=tkBraceClose then
  1137. Dec(CCount)
  1138. until (CCount=0) and (CurToken=tkEnd);
  1139. Break;
  1140. end
  1141. else
  1142. ParseInlineVarDecl(Parent, Parent.Members);
  1143. end;
  1144. ExpectToken(tkSemicolon);
  1145. end;
  1146. // Starts after the "class" token
  1147. function TPasParser.ParseClassDecl(Parent: TPasElement;
  1148. const AClassName: String; AObjKind: TPasObjKind): TPasType;
  1149. var
  1150. CurVisibility: TPasMemberVisibility;
  1151. procedure ProcessMethod(const MethodTypeName: String; HasReturnValue: Boolean);
  1152. var
  1153. Owner: TPasElement;
  1154. Proc: TPasProcedure;
  1155. s: String;
  1156. begin
  1157. ExpectIdentifier;
  1158. Owner := CheckIfOverloaded(TPasClassType(Result), CurTokenString);
  1159. if HasReturnValue then
  1160. begin
  1161. Proc := TPasFunction(
  1162. Engine.CreateElement(TPasFunction, CurTokenString, Owner, CurVisibility));
  1163. Proc.ProcType := Engine.CreateFunctionType( '', Proc, True);
  1164. end else
  1165. begin
  1166. // !!!: The following is more than ugly
  1167. if MethodTypeName = 'constructor' then
  1168. Proc := TPasConstructor(
  1169. Engine.CreateElement(TPasConstructor, CurTokenString, Owner, CurVisibility))
  1170. else if MethodTypeName = 'destructor' then
  1171. Proc := TPasDestructor(
  1172. Engine.CreateElement(TPasDestructor, CurTokenString, Owner, CurVisibility))
  1173. else
  1174. Proc := TPasProcedure(
  1175. Engine.CreateElement(TPasProcedure, CurTokenString, Owner, CurVisibility));
  1176. Proc.ProcType := TPasProcedureType(
  1177. Engine.CreateElement(TPasProcedureType, '', Proc, CurVisibility));
  1178. end;
  1179. if Owner.ClassType = TPasOverloadedProc then
  1180. TPasOverloadedProc(Owner).Overloads.Add(Proc)
  1181. else
  1182. TPasClassType(Result).Members.Add(Proc);
  1183. ParseProcedureOrFunctionHeader(Proc, Proc.ProcType, HasReturnValue, False);
  1184. while True do
  1185. begin
  1186. NextToken;
  1187. if CurToken = tkIdentifier then
  1188. begin
  1189. s := UpperCase(CurTokenString);
  1190. if s = 'VIRTUAL' then
  1191. Proc.IsVirtual := True
  1192. else if s = 'DYNAMIC' then
  1193. Proc.IsDynamic := True
  1194. else if s = 'ABSTRACT' then
  1195. Proc.IsAbstract := True
  1196. else if s = 'OVERRIDE' then
  1197. Proc.IsOverride := True
  1198. else if s = 'OVERLOAD' then
  1199. Proc.IsOverload := True
  1200. else if s = 'MESSAGE' then
  1201. begin
  1202. Proc.IsMessage := True;
  1203. repeat
  1204. NextToken;
  1205. until CurToken = tkSemicolon;
  1206. UngetToken;
  1207. end else if s = 'CDECL' then
  1208. { El['calling-conv'] := 'cdecl';}
  1209. else if s = 'STDCALL' then
  1210. { El['calling-conv'] := 'stdcall';}
  1211. else
  1212. begin
  1213. UngetToken;
  1214. break;
  1215. end;
  1216. ExpectToken(tkSemicolon);
  1217. end else
  1218. begin
  1219. UngetToken;
  1220. break;
  1221. end;
  1222. end;
  1223. end;
  1224. function GetAccessorName: String;
  1225. begin
  1226. ExpectIdentifier;
  1227. Result := CurTokenString;
  1228. while True do
  1229. begin
  1230. NextToken;
  1231. if CurToken = tkDot then
  1232. begin
  1233. ExpectIdentifier;
  1234. Result := Result + '.' + CurTokenString;
  1235. end else
  1236. break;
  1237. end;
  1238. UngetToken;
  1239. end;
  1240. var
  1241. s: String;
  1242. i: Integer;
  1243. VarList: TList;
  1244. Element: TPasElement;
  1245. begin
  1246. NextToken;
  1247. if (AObjKind = okClass) and (CurToken = tkOf) then
  1248. begin
  1249. Result := TPasClassOfType(
  1250. Engine.CreateElement(TPasClassOfType, AClassName, Parent));
  1251. ExpectIdentifier;
  1252. UngetToken; // Only names are allowed as following type
  1253. TPasClassOfType(Result).DestType := ParseType(Result);
  1254. ExpectToken(tkSemicolon);
  1255. exit;
  1256. end;
  1257. Result := TPasClassType(
  1258. Engine.CreateElement(TPasClassType, AClassName, Parent));
  1259. TPasClassType(Result).ObjKind := AObjKind;
  1260. if CurToken = tkBraceOpen then
  1261. begin
  1262. TPasClassType(Result).AncestorType := ParseType(nil);
  1263. while True do
  1264. begin
  1265. NextToken;
  1266. if CurToken = tkBraceClose then
  1267. break;
  1268. UngetToken;
  1269. ExpectToken(tkComma);
  1270. ExpectIdentifier;
  1271. // !!!: Store interface name
  1272. end;
  1273. NextToken;
  1274. end;
  1275. if CurToken <> tkSemicolon then
  1276. begin
  1277. CurVisibility := visDefault;
  1278. while CurToken <> tkEnd do
  1279. begin
  1280. case CurToken of
  1281. tkIdentifier:
  1282. begin
  1283. s := LowerCase(CurTokenString);
  1284. if s = 'private' then
  1285. CurVisibility := visPrivate
  1286. else if s = 'protected' then
  1287. CurVisibility := visProtected
  1288. else if s = 'public' then
  1289. CurVisibility := visPublic
  1290. else if s = 'published' then
  1291. CurVisibility := visPublished
  1292. else if s = 'automated' then
  1293. CurVisibility := visAutomated
  1294. else
  1295. begin
  1296. VarList := TList.Create;
  1297. try
  1298. ParseInlineVarDecl(Result, VarList, CurVisibility);
  1299. for i := 0 to VarList.Count - 1 do
  1300. begin
  1301. Element := TPasElement(VarList[i]);
  1302. Element.Visibility := CurVisibility;
  1303. TPasClassType(Result).Members.Add(Element);
  1304. end;
  1305. finally
  1306. VarList.Free;
  1307. end;
  1308. end;
  1309. end;
  1310. tkProcedure:
  1311. ProcessMethod('procedure', False);
  1312. tkFunction:
  1313. ProcessMethod('function', True);
  1314. tkConstructor:
  1315. ProcessMethod('constructor', False);
  1316. tkDestructor:
  1317. ProcessMethod('destructor', False);
  1318. tkProperty:
  1319. begin
  1320. ExpectIdentifier;
  1321. Element := Engine.CreateElement(TPasProperty,
  1322. CurTokenString, Result, CurVisibility);
  1323. TPasClassType(Result).Members.Add(Element);
  1324. NextToken;
  1325. // !!!: Parse array properties correctly
  1326. if CurToken = tkSquaredBraceOpen then
  1327. begin
  1328. ParseArgList(Element, TPasProperty(Element).Args, tkSquaredBraceClose);
  1329. NextToken;
  1330. end;
  1331. if CurToken = tkColon then
  1332. begin
  1333. TPasProperty(Element).VarType := ParseType(Element);
  1334. NextToken;
  1335. if CurToken <> tkSemicolon then
  1336. begin
  1337. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'READ') then
  1338. TPasProperty(Element).ReadAccessorName := GetAccessorName
  1339. else
  1340. UngetToken;
  1341. NextToken;
  1342. if CurToken <> tkSemicolon then
  1343. begin
  1344. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'WRITE') then
  1345. TPasProperty(Element).WriteAccessorName := GetAccessorName
  1346. else
  1347. UngetToken;
  1348. NextToken;
  1349. if CurToken <> tkSemicolon then
  1350. begin
  1351. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'STORED') then
  1352. begin
  1353. NextToken;
  1354. if CurToken = tkTrue then
  1355. TPasProperty(Element).StoredAccessorName := 'True'
  1356. else if CurToken = tkFalse then
  1357. TPasProperty(Element).StoredAccessorName := 'False'
  1358. else if CurToken = tkIdentifier then
  1359. TPasProperty(Element).StoredAccessorName := CurTokenString
  1360. else
  1361. ParseExc(SParserSyntaxError);
  1362. end else
  1363. UngetToken;
  1364. end;
  1365. end;
  1366. end;
  1367. end;
  1368. NextToken;
  1369. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then
  1370. begin
  1371. NextToken;
  1372. if CurToken = tkSemicolon then
  1373. begin
  1374. TPasProperty(Element).IsDefault := True;
  1375. UngetToken;
  1376. end else
  1377. begin
  1378. UngetToken;
  1379. TPasProperty(Element).DefaultValue := ParseExpression;
  1380. end;
  1381. end else
  1382. UngetToken;
  1383. end;
  1384. end;
  1385. NextToken;
  1386. end;
  1387. // Eat semicolon after class...end
  1388. ExpectToken(tkSemicolon);
  1389. end;
  1390. end;
  1391. function ParseSource(AEngine: TPasTreeContainer;
  1392. const FPCCommandLine: String): TPasModule;
  1393. var
  1394. FileResolver: TFileResolver;
  1395. Parser: TPasParser;
  1396. Start, CurPos: PChar;
  1397. Filename: String;
  1398. procedure ProcessCmdLinePart;
  1399. var
  1400. l: Integer;
  1401. s: String;
  1402. begin
  1403. l := CurPos - Start;
  1404. SetLength(s, l);
  1405. if l > 0 then
  1406. Move(Start^, s[1], l)
  1407. else
  1408. exit;
  1409. if s[1] = '-' then
  1410. begin
  1411. if s[2] = 'F' then
  1412. if s[3] = 'i' then
  1413. FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
  1414. end else
  1415. if Filename <> '' then
  1416. raise Exception.Create(SErrMultipleSourceFiles)
  1417. else
  1418. Filename := s;
  1419. end;
  1420. begin
  1421. FileResolver := TFileResolver.Create;
  1422. try
  1423. Filename := '';
  1424. Start := @FPCCommandLine[1];
  1425. CurPos := Start;
  1426. while CurPos[0] <> #0 do
  1427. begin
  1428. if CurPos[0] = ' ' then
  1429. begin
  1430. ProcessCmdLinePart;
  1431. Start := CurPos + 1;
  1432. end;
  1433. Inc(CurPos);
  1434. end;
  1435. ProcessCmdLinePart;
  1436. if Filename = '' then
  1437. raise Exception.Create(SErrNoSourceGiven);
  1438. Parser := TPasParser.Create(FileResolver, AEngine, Filename);
  1439. Parser.ParseMain(Result);
  1440. Parser.Free;
  1441. finally
  1442. FileResolver.Free;
  1443. end;
  1444. end;
  1445. end.
  1446. {
  1447. $Log$
  1448. Revision 1.1 2003-03-13 21:47:42 sg
  1449. * First version as part of FCL
  1450. }