pparser.pp 61 KB

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