2
0

pparser.pp 52 KB

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