pparser.pp 44 KB

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