pparser.pp 50 KB

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