pparser.pp 57 KB

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