pparser.pp 60 KB

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