pparser.pp 53 KB

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