pparser.pp 56 KB

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