pparser.pp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188
  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. // !!!: Store this information
  1121. ExpectIdentifier;
  1122. end else
  1123. UngetToken;
  1124. ExpectToken(tkSemicolon);
  1125. M := '';
  1126. while True do
  1127. begin
  1128. NextToken;
  1129. if CurToken = tkIdentifier then
  1130. begin
  1131. s := UpperCase(CurTokenText);
  1132. if s = 'CVAR' then
  1133. begin
  1134. M := M + '; cvar';
  1135. ExpectToken(tkSemicolon);
  1136. end
  1137. else if (s = 'EXTERNAL') or (s = 'PUBLIC') or (s = 'EXPORT') then
  1138. begin
  1139. M := M + ';' + CurTokenText;
  1140. if s = 'EXTERNAL' then
  1141. begin
  1142. NextToken;
  1143. if ((CurToken = tkString) or (CurToken = tkIdentifier)) and (UpperCase(CurTokenText)<> 'NAME') then
  1144. begin
  1145. // !!!: Is this really correct for tkString?
  1146. M := M + ' ' + CurTokenText;
  1147. NextToken;
  1148. end;
  1149. end
  1150. else
  1151. NextToken;
  1152. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'NAME') then
  1153. begin
  1154. M := M + ' name ';
  1155. NextToken;
  1156. if (CurToken = tkString) or (CurToken = tkIdentifier) then
  1157. // !!!: Is this really correct for tkString?
  1158. M := M + CurTokenText
  1159. else
  1160. ParseExc(SParserSyntaxError);
  1161. ExpectToken(tkSemicolon);
  1162. end
  1163. else if CurToken <> tkSemicolon then
  1164. ParseExc(SParserSyntaxError);
  1165. end else
  1166. begin
  1167. UngetToken;
  1168. break;
  1169. end
  1170. end else
  1171. begin
  1172. UngetToken;
  1173. break;
  1174. end;
  1175. end; // while
  1176. if M <> '' then
  1177. for i := 0 to List.Count - 1 do
  1178. TPasVariable(List[i]).Modifiers := M;
  1179. end;
  1180. // Starts after the opening bracket token
  1181. procedure TPasParser.ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
  1182. var
  1183. ArgNames: TStringList;
  1184. IsUntyped: Boolean;
  1185. Name, Value: String;
  1186. i: Integer;
  1187. Arg: TPasArgument;
  1188. Access: TArgumentAccess;
  1189. ArgType: TPasType;
  1190. begin
  1191. while True do
  1192. begin
  1193. ArgNames := TStringList.Create;
  1194. Access := argDefault;
  1195. IsUntyped := False;
  1196. ArgType := nil;
  1197. while True do
  1198. begin
  1199. NextToken;
  1200. if CurToken = tkConst then
  1201. begin
  1202. Access := argConst;
  1203. Name := ExpectIdentifier;
  1204. end else if CurToken = tkVar then
  1205. begin
  1206. Access := ArgVar;
  1207. Name := ExpectIdentifier;
  1208. end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OUT') then
  1209. begin
  1210. Access := ArgOut;
  1211. Name := ExpectIdentifier;
  1212. end else if CurToken = tkIdentifier then
  1213. Name := CurTokenString
  1214. else
  1215. ParseExc(SParserExpectedConstVarID);
  1216. ArgNames.Add(Name);
  1217. NextToken;
  1218. if CurToken = tkColon then
  1219. break
  1220. else if ((CurToken = tkSemicolon) or (CurToken = tkBraceClose)) and
  1221. (Access <> argDefault) then
  1222. begin
  1223. // found an untyped const or var argument
  1224. UngetToken;
  1225. IsUntyped := True;
  1226. break
  1227. end
  1228. else if CurToken <> tkComma then
  1229. ParseExc(SParserExpectedCommaColon);
  1230. end;
  1231. SetLength(Value, 0);
  1232. if not IsUntyped then
  1233. begin
  1234. ArgType := ParseType(nil);
  1235. NextToken;
  1236. if CurToken = tkEqual then
  1237. begin
  1238. Value := ParseExpression;
  1239. end else
  1240. UngetToken;
  1241. end;
  1242. for i := 0 to ArgNames.Count - 1 do
  1243. begin
  1244. Arg := TPasArgument(CreateElement(TPasArgument, ArgNames[i], Parent));
  1245. Arg.Access := Access;
  1246. Arg.ArgType := ArgType;
  1247. if (i > 0) and Assigned(ArgType) then
  1248. ArgType.AddRef;
  1249. Arg.Value := Value;
  1250. Args.Add(Arg);
  1251. end;
  1252. ArgNames.Free;
  1253. NextToken;
  1254. if CurToken = EndToken then
  1255. break;
  1256. end;
  1257. end;
  1258. // Next token is expected to be a "(", ";" or for a function ":". The caller
  1259. // will get the token after the final ";" as next token.
  1260. procedure TPasParser.ParseProcedureOrFunctionHeader(Parent: TPasElement;
  1261. Element: TPasProcedureType; ProcType: TProcType; OfObjectPossible: Boolean);
  1262. Var
  1263. Tok : String;
  1264. begin
  1265. NextToken;
  1266. case ProcType of
  1267. ptFunction:
  1268. begin
  1269. if CurToken = tkBraceOpen then
  1270. begin
  1271. NextToken;
  1272. if (CurToken = tkBraceClose) then
  1273. else
  1274. begin
  1275. UngetToken;
  1276. ParseArgList(Parent, Element.Args, tkBraceClose);
  1277. end;
  1278. ExpectToken(tkColon);
  1279. end else if CurToken <> tkColon then
  1280. ParseExc(SParserExpectedLBracketColon);
  1281. if Assigned(Element) then // !!!
  1282. TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
  1283. else
  1284. ParseType(nil);
  1285. end;
  1286. ptProcedure:
  1287. begin
  1288. if CurToken = tkBraceOpen then
  1289. begin
  1290. NextToken;
  1291. if (CurToken = tkBraceClose) then
  1292. else
  1293. begin
  1294. UngetToken;
  1295. ParseArgList(Element, Element.Args, tkBraceClose);
  1296. end
  1297. end else if (CurToken = tkSemicolon) or (OfObjectPossible and (CurToken = tkOf)) then
  1298. UngetToken
  1299. else
  1300. ParseExc(SParserExpectedLBracketSemicolon);
  1301. end;
  1302. ptOperator:
  1303. begin
  1304. ParseArgList(Element, Element.Args, tkBraceClose);
  1305. NextToken;
  1306. if (CurToken=tkIdentifier) then begin
  1307. TPasFunctionType(Element).ResultEl.Name := CurTokenName;
  1308. ExpectToken(tkColon);
  1309. end
  1310. else if (CurToken=tkColon) then
  1311. TPasFunctionType(Element).ResultEl.Name := 'Result'
  1312. else
  1313. ParseExc(SParserExpectedColonID);
  1314. if Assigned(Element) then // !!!
  1315. TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
  1316. else
  1317. ParseType(nil);
  1318. end;
  1319. end;
  1320. NextToken;
  1321. if OfObjectPossible and (CurToken = tkOf) then
  1322. begin
  1323. ExpectToken(tkObject);
  1324. Element.IsOfObject := True;
  1325. end else
  1326. UngetToken;
  1327. NextToken;
  1328. if CurToken = tkEqual then
  1329. begin
  1330. // for example: const p: procedure = nil;
  1331. UngetToken;
  1332. exit;
  1333. end else
  1334. UngetToken;
  1335. ExpectToken(tkSemicolon);
  1336. while True do
  1337. begin
  1338. NextToken;
  1339. if (CurToken = tkIdentifier) then
  1340. begin
  1341. Tok:=UpperCase(CurTokenString);
  1342. If (Tok='CDECL') then
  1343. begin
  1344. { El['calling-conv'] := 'cdecl';}
  1345. ExpectToken(tkSemicolon);
  1346. end
  1347. else if (Tok='PASCAL') then
  1348. begin
  1349. { El['calling-conv'] := 'pascal';}
  1350. ExpectToken(tkSemicolon);
  1351. end
  1352. else if (Tok='STDCALL') then
  1353. begin
  1354. { El['calling-conv'] := 'stdcall';}
  1355. ExpectToken(tkSemicolon);
  1356. end
  1357. else if (Tok='OLDFPCCALL') then
  1358. begin
  1359. { El['calling-conv'] := 'oldfpccall';}
  1360. ExpectToken(tkSemicolon);
  1361. end
  1362. else if (Tok='EXTDECL') then
  1363. begin
  1364. { El['calling-conv'] := 'extdecl';}
  1365. ExpectToken(tkSemicolon);
  1366. end
  1367. else if (Tok='REGISTER') then
  1368. begin
  1369. { El['calling-conv'] := 'register';}
  1370. ExpectToken(tkSemicolon);
  1371. end
  1372. else if (Tok='COMPILERPROC') then
  1373. begin
  1374. { El['calling-conv'] := 'compilerproc';}
  1375. ExpectToken(tkSemicolon);
  1376. end
  1377. else if (Tok='VARARGS') then
  1378. begin
  1379. { 'varargs': needs CDECL & EXTERNAL }
  1380. ExpectToken(tkSemicolon);
  1381. end
  1382. else if (tok='DEPRECATED') then
  1383. begin
  1384. { El['calling-conv'] := 'deprecated';}
  1385. ExpectToken(tkSemicolon);
  1386. end
  1387. else if (tok='OVERLOAD') then
  1388. begin
  1389. TPasProcedure(Parent).IsOverload := True;
  1390. ExpectToken(tkSemicolon);
  1391. end
  1392. else if (tok='INLINE') then
  1393. begin
  1394. ExpectToken(tkSemicolon);
  1395. end
  1396. else if (tok='ASSEMBLER') then
  1397. begin
  1398. ExpectToken(tkSemicolon);
  1399. end
  1400. else if (tok = 'EXTERNAL') then
  1401. repeat
  1402. NextToken;
  1403. until CurToken = tkSemicolon
  1404. else if (tok = 'PUBLIC') then
  1405. begin
  1406. NextToken;
  1407. { Should be token Name,
  1408. if not we're in a class and the public section starts }
  1409. If (Uppercase(CurTokenString)<>'NAME') then
  1410. begin
  1411. UngetToken;
  1412. UngetToken;
  1413. Break;
  1414. end
  1415. else
  1416. begin
  1417. NextToken; // Should be export name string.
  1418. ExpectToken(tkSemicolon);
  1419. end;
  1420. end
  1421. else
  1422. begin
  1423. UnGetToken;
  1424. Break;
  1425. end
  1426. end
  1427. else if (CurToken = tkInline) then
  1428. begin
  1429. { TPasProcedure(Parent).IsInline := True;}
  1430. ExpectToken(tkSemicolon);
  1431. end
  1432. else if (CurToken = tkSquaredBraceOpen) then
  1433. begin
  1434. repeat
  1435. NextToken
  1436. until CurToken = tkSquaredBraceClose;
  1437. ExpectToken(tkSemicolon);
  1438. end
  1439. else
  1440. begin
  1441. UngetToken;
  1442. break;
  1443. end;
  1444. end;
  1445. end;
  1446. procedure TPasParser.ParseProperty(Element:TPasElement);
  1447. function GetAccessorName: String;
  1448. begin
  1449. ExpectIdentifier;
  1450. Result := CurTokenString;
  1451. while True do begin
  1452. NextToken;
  1453. if CurToken = tkDot then begin
  1454. ExpectIdentifier;
  1455. Result := Result + '.' + CurTokenString;
  1456. end else
  1457. break;
  1458. end;
  1459. if CurToken = tkSquaredBraceOpen then begin
  1460. Result := Result + '[';
  1461. NextToken;
  1462. if CurToken in [tkIdentifier, tkNumber] then begin
  1463. Result := Result + CurTokenString;
  1464. end;
  1465. ExpectToken(tkSquaredBraceClose);
  1466. Result := Result + ']';
  1467. end else
  1468. UngetToken;
  1469. // writeln(Result);
  1470. end;
  1471. begin
  1472. NextToken;
  1473. // if array prop then parse [ arg1:type1;... ]
  1474. if CurToken = tkSquaredBraceOpen then begin
  1475. // !!!: Parse array properties correctly
  1476. ParseArgList(Element, TPasProperty(Element).Args, tkSquaredBraceClose);
  1477. NextToken;
  1478. end;
  1479. if CurToken = tkColon then begin
  1480. // if ":prop_data_type" if supplied then read it
  1481. // read property type
  1482. TPasProperty(Element).VarType := ParseType(Element);
  1483. NextToken;
  1484. end;
  1485. if CurToken <> tkSemicolon then begin
  1486. // if indexed prop then read the index value
  1487. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'INDEX') then
  1488. // read 'index' access modifier
  1489. TPasProperty(Element).IndexValue := ParseExpression
  1490. else
  1491. // not indexed prop will be recheck for another token
  1492. UngetToken;
  1493. NextToken;
  1494. end;
  1495. // if the accessors list is not finished
  1496. if CurToken <> tkSemicolon then begin
  1497. // read 'read' access modifier
  1498. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'READ') then
  1499. TPasProperty(Element).ReadAccessorName := GetAccessorName
  1500. else
  1501. // not read accessor 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 'write' access modifier
  1508. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'WRITE') then
  1509. TPasProperty(Element).WriteAccessorName := GetAccessorName
  1510. else
  1511. // not write accessor will be recheck for another token
  1512. UngetToken;
  1513. NextToken;
  1514. end;
  1515. // if the specifiers list is not finished
  1516. if CurToken <> tkSemicolon then begin
  1517. // read 'stored' access modifier
  1518. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'STORED') then begin
  1519. NextToken;
  1520. if CurToken = tkTrue then
  1521. TPasProperty(Element).StoredAccessorName := 'True'
  1522. else if CurToken = tkFalse then
  1523. TPasProperty(Element).StoredAccessorName := 'False'
  1524. else if CurToken = tkIdentifier then
  1525. TPasProperty(Element).StoredAccessorName := CurTokenString
  1526. else
  1527. ParseExc(SParserSyntaxError);
  1528. end else
  1529. // not stored accessor will be recheck for another token
  1530. UngetToken;
  1531. NextToken;
  1532. end;
  1533. // if the specifiers list is not finished
  1534. if CurToken <> tkSemicolon then begin
  1535. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then
  1536. // read 'default' value modifier -> ParseExpression(DEFAULT <value>)
  1537. TPasProperty(Element).DefaultValue := ParseExpression
  1538. else
  1539. // not "default <value>" prop 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) = 'NODEFAULT') then begin
  1546. // read 'nodefault' modifier
  1547. TPasProperty(Element).IsNodefault:=true;
  1548. end;
  1549. // stop recheck for specifiers - start from next token
  1550. NextToken;
  1551. end;
  1552. // after NODEFAULT may be a ";"
  1553. if CurToken = tkSemicolon then begin
  1554. // read semicolon
  1555. NextToken;
  1556. end;
  1557. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then begin
  1558. // what is after DEFAULT token at the end
  1559. NextToken;
  1560. if CurToken = tkSemicolon then begin
  1561. // ";" then DEFAULT=prop
  1562. TPasProperty(Element).IsDefault := True;
  1563. UngetToken;
  1564. end else begin
  1565. // "!;" then a step back to get phrase "DEFAULT <value>"
  1566. UngetToken;
  1567. // DefaultValue -> ParseExpression(DEFAULT <value>) and stay on the <value>
  1568. TPasProperty(Element).DefaultValue := ParseExpression;
  1569. end;
  1570. //!! there may be DEPRECATED token
  1571. NextToken;
  1572. end;
  1573. // after DEFAULT may be a ";"
  1574. if CurToken = tkSemicolon then begin
  1575. // read semicolon
  1576. NextToken;
  1577. end;
  1578. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEPRECATED') then begin
  1579. // nothing to do on DEPRECATED - just to accept
  1580. // NextToken;
  1581. end else
  1582. UngetToken;;
  1583. //!! else
  1584. // not DEFAULT prop accessor will be recheck for another token
  1585. //!! UngetToken;
  1586. {
  1587. if CurToken = tkSemicolon then begin
  1588. // read semicolon
  1589. NextToken;
  1590. end;
  1591. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEPRECATED') then begin
  1592. // nothing to do - just to process
  1593. NextToken;
  1594. end;
  1595. if CurToken = tkSemicolon then begin
  1596. // read semicolon
  1597. NextToken;
  1598. end;
  1599. }
  1600. end;
  1601. // Starts after the "procedure" or "function" token
  1602. function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
  1603. ProcType: TProcType): TPasProcedure;
  1604. var
  1605. Name: String;
  1606. i: Integer;
  1607. begin
  1608. case ProcType of
  1609. ptFunction:
  1610. begin
  1611. Name := ExpectIdentifier;
  1612. Result := TPasFunction(CreateElement(TPasFunction, Name, Parent));
  1613. Result.ProcType := Engine.CreateFunctionType('', 'Result', Result, True,
  1614. Scanner.CurFilename, Scanner.CurRow);
  1615. end;
  1616. ptProcedure:
  1617. begin
  1618. Name := ExpectIdentifier;
  1619. Result := TPasProcedure(CreateElement(TPasProcedure, Name, Parent));
  1620. Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  1621. Result));
  1622. end;
  1623. ptOperator:
  1624. begin
  1625. NextToken;
  1626. Name := 'operator ' + TokenInfos[CurToken];
  1627. Result := TPasOperator(CreateElement(TPasOperator, Name, Parent));
  1628. Result.ProcType := Engine.CreateFunctionType('', '__INVALID__', Result,
  1629. True, Scanner.CurFilename, Scanner.CurRow);
  1630. end;
  1631. end;
  1632. ParseProcedureOrFunctionHeader(Result, Result.ProcType, ProcType, False);
  1633. if ProcType = ptOperator then
  1634. begin
  1635. Result.Name := Result.Name + '(';
  1636. for i := 0 to Result.ProcType.Args.Count - 1 do
  1637. begin
  1638. if i > 0 then
  1639. Result.Name := Result.Name + ', ';
  1640. Result.Name := Result.Name +
  1641. TPasArgument(Result.ProcType.Args[i]).ArgType.Name;
  1642. end;
  1643. Result.Name := Result.Name + '): ' +
  1644. TPasFunctionType(Result.ProcType).ResultEl.ResultType.Name;
  1645. end;
  1646. end;
  1647. // Starts after the "record" token
  1648. procedure TPasParser.ParseRecordDecl(Parent: TPasRecordType; IsNested: Boolean);
  1649. var
  1650. VariantName: String;
  1651. Variant: TPasVariant;
  1652. begin
  1653. while True do
  1654. begin
  1655. if IsNested then
  1656. begin
  1657. if CurToken = tkBraceClose then
  1658. break;
  1659. NextToken;
  1660. if CurToken = tkBraceClose then
  1661. break;
  1662. end else
  1663. begin
  1664. if CurToken = tkEnd then
  1665. break;
  1666. NextToken;
  1667. if CurToken = tkEnd then
  1668. break;
  1669. end;
  1670. if CurToken = tkCase then
  1671. begin
  1672. ExpectToken(tkIdentifier);
  1673. VariantName := CurTokenString;
  1674. NextToken;
  1675. if CurToken = tkColon then
  1676. Parent.VariantName := VariantName
  1677. else
  1678. begin
  1679. UngetToken;
  1680. UngetToken;
  1681. end;
  1682. Parent.VariantType := ParseType(Parent);
  1683. Parent.Variants := TList.Create;
  1684. ExpectToken(tkOf);
  1685. while True do
  1686. begin
  1687. Variant := TPasVariant(CreateElement(TPasVariant, '', Parent));
  1688. Parent.Variants.Add(Variant);
  1689. Variant.Values := TStringList.Create;
  1690. while True do
  1691. begin
  1692. Variant.Values.Add(ParseExpression);
  1693. NextToken;
  1694. if CurToken = tkColon then
  1695. break
  1696. else if CurToken <> tkComma then
  1697. ParseExc(SParserExpectedCommaColon);
  1698. end;
  1699. ExpectToken(tkBraceOpen);
  1700. Variant.Members := TPasRecordType(CreateElement(TPasRecordType, '',
  1701. Variant));
  1702. try
  1703. ParseRecordDecl(Variant.Members, True);
  1704. except
  1705. Variant.Members.Free;
  1706. raise;
  1707. end;
  1708. NextToken;
  1709. if CurToken = tkSemicolon then
  1710. NextToken;
  1711. if (CurToken = tkEnd) or (CurToken = tkBraceClose) then
  1712. break
  1713. else
  1714. UngetToken;
  1715. end
  1716. end else
  1717. ParseInlineVarDecl(Parent, Parent.Members, visDefault, IsNested);
  1718. end;
  1719. end;
  1720. // Starts after the "class" token
  1721. function TPasParser.ParseClassDecl(Parent: TPasElement;
  1722. const AClassName: String; AObjKind: TPasObjKind): TPasType;
  1723. var
  1724. CurVisibility: TPasMemberVisibility;
  1725. procedure ProcessMethod(const MethodTypeName: String; HasReturnValue: Boolean);
  1726. var
  1727. Owner: TPasElement;
  1728. Proc: TPasProcedure;
  1729. s: String;
  1730. pt: TProcType;
  1731. begin
  1732. ExpectIdentifier;
  1733. Owner := CheckIfOverloaded(TPasClassType(Result), CurTokenString);
  1734. if HasReturnValue then
  1735. begin
  1736. Proc := TPasFunction(CreateElement(TPasFunction, CurTokenString, Owner,
  1737. CurVisibility));
  1738. Proc.ProcType := Engine.CreateFunctionType('', 'Result', Proc, True,
  1739. Scanner.CurFilename, Scanner.CurRow);
  1740. end else
  1741. begin
  1742. // !!!: The following is more than ugly
  1743. if MethodTypeName = 'constructor' then
  1744. Proc := TPasConstructor(CreateElement(TPasConstructor, CurTokenString,
  1745. Owner, CurVisibility))
  1746. else if MethodTypeName = 'destructor' then
  1747. Proc := TPasDestructor(CreateElement(TPasDestructor, CurTokenString,
  1748. Owner, CurVisibility))
  1749. else
  1750. Proc := TPasProcedure(CreateElement(TPasProcedure, CurTokenString,
  1751. Owner, CurVisibility));
  1752. Proc.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  1753. Proc, CurVisibility));
  1754. end;
  1755. if Owner.ClassType = TPasOverloadedProc then
  1756. TPasOverloadedProc(Owner).Overloads.Add(Proc)
  1757. else
  1758. TPasClassType(Result).Members.Add(Proc);
  1759. if HasReturnValue then
  1760. pt := ptFunction
  1761. else
  1762. pt := ptProcedure;
  1763. ParseProcedureOrFunctionHeader(Proc, Proc.ProcType, pt, False);
  1764. while True do
  1765. begin
  1766. NextToken;
  1767. if CurToken = tkIdentifier then
  1768. begin
  1769. s := UpperCase(CurTokenString);
  1770. if s = 'VIRTUAL' then
  1771. Proc.IsVirtual := True
  1772. else if s = 'DYNAMIC' then
  1773. Proc.IsDynamic := True
  1774. else if s = 'ABSTRACT' then
  1775. Proc.IsAbstract := True
  1776. else if s = 'OVERRIDE' then
  1777. Proc.IsOverride := True
  1778. else if s = 'REINTRODUCE' then
  1779. Proc.IsReintroduced := True
  1780. else if s = 'OVERLOAD' then
  1781. Proc.IsOverload := True
  1782. else if s = 'STATIC' then
  1783. Proc.IsStatic := True
  1784. else if s = 'MESSAGE' then begin
  1785. Proc.IsMessage := True;
  1786. repeat
  1787. NextToken;
  1788. until CurToken = tkSemicolon;
  1789. UngetToken;
  1790. end
  1791. else if s = 'CDECL' then
  1792. { El['calling-conv'] := 'cdecl';}
  1793. else if s = 'PASCAL' then
  1794. { El['calling-conv'] := 'cdecl';}
  1795. else if s = 'STDCALL' then
  1796. { El['calling-conv'] := 'stdcall';}
  1797. else if s = 'OLDFPCCALL' then
  1798. { El['calling-conv'] := 'oldfpccall';}
  1799. else if s = 'EXTDECL' then
  1800. { El['calling-conv'] := 'extdecl';}
  1801. else if s = 'DEPRECATED' then
  1802. { El['calling-conv'] := 'deprecated';}
  1803. else
  1804. begin
  1805. UngetToken;
  1806. break;
  1807. end;
  1808. ExpectToken(tkSemicolon);
  1809. end else
  1810. begin
  1811. UngetToken;
  1812. break;
  1813. end;
  1814. end;
  1815. end;
  1816. var
  1817. s, SourceFilename: String;
  1818. i, SourceLinenumber: Integer;
  1819. VarList: TList;
  1820. Element: TPasElement;
  1821. begin
  1822. // Save current parsing position to get it correct in all cases
  1823. SourceFilename := Scanner.CurFilename;
  1824. SourceLinenumber := Scanner.CurRow;
  1825. NextToken;
  1826. if (AObjKind = okClass) and (CurToken = tkOf) then
  1827. begin
  1828. Result := TPasClassOfType(Engine.CreateElement(TPasClassOfType, AClassName,
  1829. Parent, SourceFilename, SourceLinenumber));
  1830. ExpectIdentifier;
  1831. UngetToken; // Only names are allowed as following type
  1832. TPasClassOfType(Result).DestType := ParseType(Result);
  1833. ExpectToken(tkSemicolon);
  1834. exit;
  1835. end;
  1836. Result := TPasClassType(Engine.CreateElement(TPasClassType, AClassName,
  1837. Parent, SourceFilename, SourceLinenumber));
  1838. try
  1839. TPasClassType(Result).ObjKind := AObjKind;
  1840. // Parse ancestor list
  1841. if CurToken = tkBraceOpen then
  1842. begin
  1843. TPasClassType(Result).AncestorType := ParseType(nil);
  1844. while True do
  1845. begin
  1846. NextToken;
  1847. if CurToken = tkBraceClose then
  1848. break;
  1849. UngetToken;
  1850. ExpectToken(tkComma);
  1851. ExpectIdentifier;
  1852. // !!!: Store interface name
  1853. end;
  1854. NextToken;
  1855. end;
  1856. if CurToken <> tkSemicolon then
  1857. begin
  1858. CurVisibility := visDefault;
  1859. while CurToken <> tkEnd do
  1860. begin
  1861. case CurToken of
  1862. tkIdentifier:
  1863. begin
  1864. s := LowerCase(CurTokenString);
  1865. if s = 'private' then
  1866. CurVisibility := visPrivate
  1867. else if s = 'protected' then
  1868. CurVisibility := visProtected
  1869. else if s = 'public' then
  1870. CurVisibility := visPublic
  1871. else if s = 'published' then
  1872. CurVisibility := visPublished
  1873. else if s = 'automated' then
  1874. CurVisibility := visAutomated
  1875. else
  1876. begin
  1877. VarList := TList.Create;
  1878. try
  1879. ParseInlineVarDecl(Result, VarList, CurVisibility, False);
  1880. for i := 0 to VarList.Count - 1 do
  1881. begin
  1882. Element := TPasElement(VarList[i]);
  1883. Element.Visibility := CurVisibility;
  1884. TPasClassType(Result).Members.Add(Element);
  1885. end;
  1886. finally
  1887. VarList.Free;
  1888. end;
  1889. end;
  1890. end;
  1891. tkProcedure:
  1892. ProcessMethod('procedure', False);
  1893. tkFunction:
  1894. ProcessMethod('function', True);
  1895. tkConstructor:
  1896. ProcessMethod('constructor', False);
  1897. tkDestructor:
  1898. ProcessMethod('destructor', False);
  1899. tkProperty:
  1900. begin
  1901. ExpectIdentifier;
  1902. Element := CreateElement(TPasProperty, CurTokenString, Result, CurVisibility);
  1903. TPasClassType(Result).Members.Add(Element);
  1904. ParseProperty(Element);
  1905. end;
  1906. end; // end case
  1907. NextToken;
  1908. end;
  1909. // Eat semicolon after class...end
  1910. ExpectToken(tkSemicolon);
  1911. end;
  1912. except
  1913. Result.Free;
  1914. raise;
  1915. end;
  1916. end;
  1917. function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
  1918. AParent: TPasElement): TPasElement;
  1919. begin
  1920. Result := Engine.CreateElement(AClass, AName, AParent,
  1921. Scanner.CurFilename, Scanner.CurRow);
  1922. end;
  1923. function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
  1924. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  1925. begin
  1926. Result := Engine.CreateElement(AClass, AName, AParent, AVisibility,
  1927. Scanner.CurFilename, Scanner.CurRow);
  1928. end;
  1929. function ParseSource(AEngine: TPasTreeContainer;
  1930. const FPCCommandLine, OSTarget, CPUTarget: String): TPasModule;
  1931. var
  1932. FileResolver: TFileResolver;
  1933. Parser: TPasParser;
  1934. Start, CurPos: PChar;
  1935. Filename: String;
  1936. Scanner: TPascalScanner;
  1937. procedure ProcessCmdLinePart;
  1938. var
  1939. l: Integer;
  1940. s: String;
  1941. begin
  1942. l := CurPos - Start;
  1943. SetLength(s, l);
  1944. if l > 0 then
  1945. Move(Start^, s[1], l)
  1946. else
  1947. exit;
  1948. if s[1] = '-' then
  1949. begin
  1950. case s[2] of
  1951. 'd':
  1952. Scanner.Defines.Append(UpperCase(Copy(s, 3, Length(s))));
  1953. 'F':
  1954. if s[3] = 'i' then
  1955. FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
  1956. 'S':
  1957. if s[3]='d' then
  1958. begin
  1959. include(Scanner.Options,po_delphi);
  1960. include(Parser.Options,po_delphi);
  1961. end;
  1962. end;
  1963. end else
  1964. if Filename <> '' then
  1965. raise Exception.Create(SErrMultipleSourceFiles)
  1966. else
  1967. Filename := s;
  1968. end;
  1969. var
  1970. s: String;
  1971. begin
  1972. Result := nil;
  1973. FileResolver := nil;
  1974. Scanner := nil;
  1975. Parser := nil;
  1976. try
  1977. FileResolver := TFileResolver.Create;
  1978. Scanner := TPascalScanner.Create(FileResolver);
  1979. Scanner.Defines.Append('FPK');
  1980. Scanner.Defines.Append('FPC');
  1981. s := UpperCase(OSTarget);
  1982. Scanner.Defines.Append(s);
  1983. if s = 'LINUX' then
  1984. Scanner.Defines.Append('UNIX')
  1985. else if s = 'FREEBSD' then
  1986. begin
  1987. Scanner.Defines.Append('BSD');
  1988. Scanner.Defines.Append('UNIX');
  1989. end else if s = 'NETBSD' then
  1990. begin
  1991. Scanner.Defines.Append('BSD');
  1992. Scanner.Defines.Append('UNIX');
  1993. end else if s = 'SUNOS' then
  1994. begin
  1995. Scanner.Defines.Append('SOLARIS');
  1996. Scanner.Defines.Append('UNIX');
  1997. end else if s = 'GO32V2' then
  1998. Scanner.Defines.Append('DPMI')
  1999. else if s = 'BEOS' then
  2000. Scanner.Defines.Append('UNIX')
  2001. else if s = 'QNX' then
  2002. Scanner.Defines.Append('UNIX');
  2003. Parser := TPasParser.Create(Scanner, FileResolver, AEngine);
  2004. Filename := '';
  2005. if FPCCommandLine<>'' then
  2006. begin
  2007. Start := @FPCCommandLine[1];
  2008. CurPos := Start;
  2009. while CurPos[0] <> #0 do
  2010. begin
  2011. if CurPos[0] = ' ' then
  2012. begin
  2013. ProcessCmdLinePart;
  2014. Start := CurPos + 1;
  2015. end;
  2016. Inc(CurPos);
  2017. end;
  2018. ProcessCmdLinePart;
  2019. end;
  2020. if Filename = '' then
  2021. raise Exception.Create(SErrNoSourceGiven);
  2022. Scanner.OpenFile(Filename);
  2023. Parser.ParseMain(Result);
  2024. finally
  2025. Parser.Free;
  2026. Scanner.Free;
  2027. FileResolver.Free;
  2028. end;
  2029. end;
  2030. end.