pparser.pp 102 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541
  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. {$mode objfpc}
  13. {$h+}
  14. unit PParser;
  15. interface
  16. uses SysUtils, PasTree, PScanner;
  17. resourcestring
  18. SErrNoSourceGiven = 'No source file specified';
  19. SErrMultipleSourceFiles = 'Please specify only one source file';
  20. SParserError = 'Error';
  21. SParserErrorAtToken = '%s at token "%s"';
  22. SParserUngetTokenError = 'Internal error: Cannot unget more tokens, history buffer is full';
  23. SParserExpectTokenError = 'Expected "%s"';
  24. SParserExpectedCommaRBracket = 'Expected "," or ")"';
  25. SParserExpectedCommaSemicolon = 'Expected "," or ";"';
  26. SParserExpectedCommaColon = 'Expected "," or ":"';
  27. SParserExpectedLBracketColon = 'Expected "(" or ":"';
  28. SParserExpectedLBracketSemicolon = 'Expected "(" or ";"';
  29. SParserExpectedColonSemicolon = 'Expected ":" or ";"';
  30. SParserExpectedSemiColonEnd = 'Expected ";" or "End"';
  31. SParserExpectedConstVarID = 'Expected "const", "var" or identifier';
  32. SParserExpectedColonID = 'Expected ":" or identifier';
  33. SParserSyntaxError = 'Syntax error';
  34. SParserTypeSyntaxError = 'Syntax error in type';
  35. SParserArrayTypeSyntaxError = 'Syntax error in array type';
  36. SParserInterfaceTokenError = 'Invalid token in interface section of unit';
  37. SParserImplementationTokenError = 'Invalid token in implementation section of unit';
  38. SParserInvalidTypeDef = 'Invalid type definition';
  39. SParserExpectedIdentifier = 'Identifier expected';
  40. type
  41. TPasTreeContainer = class
  42. protected
  43. FPackage: TPasPackage;
  44. FInterfaceOnly : Boolean;
  45. public
  46. function CreateElement(AClass: TPTreeElement; const AName: String;
  47. AParent: TPasElement; const ASourceFilename: String;
  48. ASourceLinenumber: Integer): TPasElement;overload;
  49. function CreateElement(AClass: TPTreeElement; const AName: String;
  50. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  51. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;overload;
  52. virtual; abstract;
  53. function CreateFunctionType(const AName, AResultName: String; AParent: TPasElement;
  54. UseParentAsResultParent: Boolean; const ASourceFilename: String;
  55. ASourceLinenumber: Integer): TPasFunctionType;
  56. function FindElement(const AName: String): TPasElement; virtual; abstract;
  57. function FindModule(const AName: String): TPasModule; virtual;
  58. property Package: TPasPackage read FPackage;
  59. property InterfaceOnly : Boolean Read FInterfaceOnly Write FInterFaceOnly;
  60. end;
  61. EParserError = class(Exception)
  62. private
  63. FFilename: String;
  64. FRow, FColumn: Integer;
  65. public
  66. constructor Create(const AReason, AFilename: String;
  67. ARow, AColumn: Integer);
  68. property Filename: String read FFilename;
  69. property Row: Integer read FRow;
  70. property Column: Integer read FColumn;
  71. end;
  72. function ParseSource(AEngine: TPasTreeContainer;
  73. const FPCCommandLine, OSTarget, CPUTarget: String): TPasModule;
  74. implementation
  75. uses Classes;
  76. var
  77. IsIdentStart: array[char] of boolean;
  78. const
  79. WhitespaceTokensToIgnore = [tkWhitespace, tkComment, tkLineEnding, tkTab];
  80. type
  81. TDeclType = (declNone, declConst, declResourcestring, declType, declVar, declThreadvar, declProperty);
  82. TProcType = (ptProcedure, ptFunction, ptOperator, ptConstructor, ptDestructor,
  83. ptClassProcedure, ptClassFunction);
  84. TExprKind = (ek_Normal, ek_PropertyIndex);
  85. { TPasParser }
  86. TPasParser = class
  87. private
  88. FFileResolver: TFileResolver;
  89. FScanner: TPascalScanner;
  90. FEngine: TPasTreeContainer;
  91. FCurToken: TToken;
  92. FCurTokenString: String;
  93. // UngetToken support:
  94. FTokenBuffer: array[0..1] of TToken;
  95. FTokenStringBuffer: array[0..1] of String;
  96. FTokenBufferIndex: Integer; // current index in FTokenBuffer
  97. FTokenBufferSize: Integer; // maximum valid index in FTokenBuffer
  98. procedure ParseExc(const Msg: String);
  99. protected
  100. function OpLevel(t: TToken): Integer;
  101. Function TokenToExprOp (AToken : TToken) : TExprOpCode;
  102. function CreateElement(AClass: TPTreeElement; const AName: String;
  103. AParent: TPasElement): TPasElement;overload;
  104. function CreateElement(AClass: TPTreeElement; const AName: String;
  105. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;overload;
  106. Function IsCurTokenHint(out AHint : TPasMemberHint) : Boolean; overload;
  107. Function IsCurTokenHint: Boolean; overload;
  108. Function CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
  109. function ParseParams(AParent : TPasElement;paramskind: TPasExprKind): TParamsExpr;
  110. function ParseExpIdent(AParent : TPasElement): TPasExpr;
  111. public
  112. Options : set of TPOptions;
  113. CurModule: TPasModule;
  114. constructor Create(AScanner: TPascalScanner; AFileResolver: TFileResolver;
  115. AEngine: TPasTreeContainer);
  116. function CurTokenName: String;
  117. function CurTokenText: String;
  118. procedure NextToken; // read next non whitespace, non space
  119. procedure UngetToken;
  120. procedure ExpectToken(tk: TToken);
  121. function ExpectIdentifier: String;
  122. function ParseType(Parent: TPasElement; Prefix : String): TPasType;overload;
  123. function ParseType(Parent: TPasElement): TPasType;overload;
  124. function ParseComplexType(Parent : TPasElement = Nil): TPasType;
  125. procedure ParseArrayType(Element: TPasArrayType);
  126. procedure ParseFileType(Element: TPasFileType);
  127. function isEndOfExp: Boolean;
  128. function DoParseExpression(Aparent : TPaselement;InitExpr: TPasExpr=nil): TPasExpr;
  129. function DoParseConstValueExpression(AParent : TPasElement): TPasExpr;
  130. function ParseExpression(AParent : TPaselement; Kind: TExprKind=ek_Normal): String;
  131. function ParseCommand: String; // single, not compound command like begin..end
  132. procedure AddProcOrFunction(Declarations: TPasDeclarations; AProc: TPasProcedure);
  133. function CheckIfOverloaded(AOwner: TPasClassType;
  134. const AName: String): TPasElement;
  135. procedure ParseMain(var Module: TPasModule);
  136. procedure ParseUnit(var Module: TPasModule);
  137. procedure ParseProgram(var Module: TPasModule);
  138. procedure ParseInterface;
  139. procedure ParseImplementation;
  140. procedure ParseInitialization;
  141. procedure ParseFinalization;
  142. procedure ParseDeclarations(Declarations: TPasDeclarations);
  143. procedure ParseUsesList(ASection: TPasSection);
  144. function ParseConstDecl(Parent: TPasElement): TPasConst;
  145. function ParseResourcestringDecl(Parent: TPasElement): TPasResString;
  146. function ParseTypeDecl(Parent: TPasElement): TPasType;
  147. procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList);overload;
  148. procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
  149. AVisibility : TPasMemberVisibility; ClosingBrace: Boolean);overload;
  150. procedure ParseVarDecl(Parent: TPasElement; List: TList);
  151. procedure ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
  152. procedure ParseProcedureOrFunctionHeader(Parent: TPasElement;
  153. Element: TPasProcedureType; ProcType: TProcType; OfObjectPossible: Boolean);
  154. procedure ParseProcedureBody(Parent: TPasElement);
  155. function ParseProcedureOrFunctionDecl(Parent: TPasElement;
  156. ProcType: TProcType): TPasProcedure;
  157. procedure ParseRecordDecl(Parent: TPasRecordType; IsNested: Boolean); // !!!: Optimize this. We have 3x the same wrapper code around it.
  158. function ParseClassDecl(Parent: TPasElement; const AClassName: String;
  159. AObjKind: TPasObjKind): TPasType;
  160. procedure ParseProperty(Element:TPasElement);
  161. procedure ParseProcBeginBlock(Parent: TProcedureBody);
  162. procedure ParseStatement(Parent: TPasImplBlock;
  163. out NewImplElement: TPasImplElement);
  164. procedure ParseLabels(AParent: TPasElement);
  165. property FileResolver: TFileResolver read FFileResolver;
  166. property Scanner: TPascalScanner read FScanner;
  167. property Engine: TPasTreeContainer read FEngine;
  168. property CurToken: TToken read FCurToken;
  169. property CurTokenString: String read FCurTokenString;
  170. end;
  171. function TPasTreeContainer.CreateElement(AClass: TPTreeElement;
  172. const AName: String; AParent: TPasElement; const ASourceFilename: String;
  173. ASourceLinenumber: Integer): TPasElement;
  174. begin
  175. Result := CreateElement(AClass, AName, AParent, visDefault, ASourceFilename,
  176. ASourceLinenumber);
  177. end;
  178. function TPasTreeContainer.CreateFunctionType(const AName, AResultName: String;
  179. AParent: TPasElement; UseParentAsResultParent: Boolean;
  180. const ASourceFilename: String; ASourceLinenumber: Integer): TPasFunctionType;
  181. var
  182. ResultParent: TPasElement;
  183. begin
  184. Result := TPasFunctionType(CreateElement(TPasFunctionType, AName, AParent,
  185. ASourceFilename, ASourceLinenumber));
  186. if UseParentAsResultParent then
  187. ResultParent := AParent
  188. else
  189. ResultParent := Result;
  190. TPasFunctionType(Result).ResultEl :=
  191. TPasResultElement(CreateElement(TPasResultElement, AResultName, ResultParent,
  192. ASourceFilename, ASourceLinenumber));
  193. end;
  194. function TPasTreeContainer.FindModule(const AName: String): TPasModule;
  195. begin
  196. Result := nil;
  197. end;
  198. constructor EParserError.Create(const AReason, AFilename: String;
  199. ARow, AColumn: Integer);
  200. begin
  201. inherited Create(AReason);
  202. FFilename := AFilename;
  203. FRow := ARow;
  204. FColumn := AColumn;
  205. end;
  206. procedure TPasParser.ParseExc(const Msg: String);
  207. begin
  208. raise EParserError.Create(Format(SParserErrorAtToken, [Msg, CurTokenName]) {$ifdef addlocation}+' ('+inttostr(scanner.currow)+' '+inttostr(scanner.curcolumn)+')'{$endif},
  209. Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
  210. end;
  211. constructor TPasParser.Create(AScanner: TPascalScanner;
  212. AFileResolver: TFileResolver; AEngine: TPasTreeContainer);
  213. begin
  214. inherited Create;
  215. FScanner := AScanner;
  216. FFileResolver := AFileResolver;
  217. FEngine := AEngine;
  218. end;
  219. function TPasParser.CurTokenName: String;
  220. begin
  221. if CurToken = tkIdentifier then
  222. Result := 'Identifier ' + FCurTokenString
  223. else
  224. Result := TokenInfos[CurToken];
  225. end;
  226. function TPasParser.CurTokenText: String;
  227. begin
  228. case CurToken of
  229. tkIdentifier, tkString, tkNumber, tkChar:
  230. Result := FCurTokenString;
  231. else
  232. Result := TokenInfos[CurToken];
  233. end;
  234. end;
  235. procedure TPasParser.NextToken;
  236. begin
  237. if FTokenBufferIndex < FTokenBufferSize then
  238. begin
  239. // Get token from buffer
  240. FCurToken := FTokenBuffer[FTokenBufferIndex];
  241. FCurTokenString := FTokenStringBuffer[FTokenBufferIndex];
  242. Inc(FTokenBufferIndex);
  243. //writeln('TPasParser.NextToken From Buf ',CurTokenText,' id=',FTokenBufferIndex);
  244. end else
  245. begin
  246. { We have to fetch a new token. But first check, wether there is space left
  247. in the token buffer.}
  248. if FTokenBufferSize = 2 then
  249. begin
  250. FTokenBuffer[0] := FTokenBuffer[1];
  251. FTokenStringBuffer[0] := FTokenStringBuffer[1];
  252. Dec(FTokenBufferSize);
  253. Dec(FTokenBufferIndex);
  254. end;
  255. // Fetch new token
  256. try
  257. repeat
  258. FCurToken := Scanner.FetchToken;
  259. until not (FCurToken in WhitespaceTokensToIgnore);
  260. except
  261. on e: EScannerError do
  262. raise EParserError.Create(e.Message,
  263. Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
  264. end;
  265. FCurTokenString := Scanner.CurTokenString;
  266. FTokenBuffer[FTokenBufferSize] := FCurToken;
  267. FTokenStringBuffer[FTokenBufferSize] := FCurTokenString;
  268. Inc(FTokenBufferSize);
  269. Inc(FTokenBufferIndex);
  270. //writeln('TPasParser.NextToken New ',CurTokenText,' id=',FTokenBufferIndex);
  271. end;
  272. end;
  273. procedure TPasParser.UngetToken;
  274. begin
  275. if FTokenBufferIndex = 0 then
  276. ParseExc(SParserUngetTokenError)
  277. else begin
  278. Dec(FTokenBufferIndex);
  279. if FTokenBufferIndex>0 then
  280. begin
  281. FCurToken := FTokenBuffer[FTokenBufferIndex-1];
  282. FCurTokenString := FTokenStringBuffer[FTokenBufferIndex-1];
  283. end else begin
  284. FCurToken := tkWhitespace;
  285. FCurTokenString := '';
  286. end;
  287. //writeln('TPasParser.UngetToken ',CurTokenText,' id=',FTokenBufferIndex);
  288. end;
  289. end;
  290. procedure TPasParser.ExpectToken(tk: TToken);
  291. begin
  292. NextToken;
  293. if CurToken <> tk then
  294. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tk]]));
  295. end;
  296. function TPasParser.ExpectIdentifier: String;
  297. begin
  298. ExpectToken(tkIdentifier);
  299. Result := CurTokenString;
  300. end;
  301. function TPasParser.ParseType(Parent: TPasElement): TPasType;
  302. begin
  303. Result:=ParseType(Parent,'');
  304. end;
  305. Function TPasParser.IsCurTokenHint(out AHint : TPasMemberHint) : Boolean;
  306. Var
  307. T : string;
  308. begin
  309. if CurToken=tklibrary then
  310. begin
  311. AHint:=hLibrary;
  312. Result:=True;
  313. end
  314. else if CurToken=tkIdentifier then
  315. begin
  316. T:=LowerCase(CurTokenString);
  317. Result:=True;
  318. if (T='deprecated') then ahint:=hDeprecated
  319. else if (T='platform') then ahint:=hPlatform
  320. else if (T='experimental') then ahint:=hExperimental
  321. else if (T='unimplemented') then ahint:=hUnimplemented
  322. else Result:=False;
  323. end
  324. else
  325. Result:=False;
  326. end;
  327. Function TPasParser.IsCurTokenHint: Boolean;
  328. var
  329. dummy : TPasMemberHint;
  330. begin
  331. Result:=IsCurTokenHint(dummy);
  332. end;
  333. Function TPasParser.CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
  334. Var
  335. Found : Boolean;
  336. h : TPasMemberHint;
  337. begin
  338. Result:=[];
  339. Repeat
  340. NextToken;
  341. Found:=IsCurTokenHint(h);
  342. If Found then
  343. Include(Result,h)
  344. Until Not Found;
  345. UnGetToken;
  346. If Assigned(Element) then
  347. Element.Hints:=Result;
  348. if ExpectSemiColon then
  349. ExpectToken(tkSemiColon);
  350. end;
  351. function TPasParser.ParseType(Parent: TPasElement; Prefix : String): TPasType;
  352. procedure ParseRange;
  353. begin
  354. Result := TPasRangeType(CreateElement(TPasRangeType, '', Parent));
  355. try
  356. TPasRangeType(Result).RangeStart := ParseExpression(Result);
  357. ExpectToken(tkDotDot);
  358. TPasRangeType(Result).RangeEnd := ParseExpression(Result);
  359. except
  360. Result.Free;
  361. raise;
  362. end;
  363. end;
  364. var
  365. Name, s: String;
  366. EnumValue: TPasEnumValue;
  367. Ref: TPasElement;
  368. HadPackedModifier : Boolean; // 12/04/04 - Dave - Added
  369. IsBitPacked : Boolean;
  370. begin
  371. Result := nil; // !!!: Remove in the future
  372. HadPackedModifier := False; { Assume not present }
  373. NextToken;
  374. if CurToken in [tkPacked,tkbitpacked] then { If PACKED modifier }
  375. begin { Handle PACKED modifier for all situations }
  376. IsBitPacked:=(CurToken=tkBitPacked);
  377. NextToken; { Move to next token for rest of parse }
  378. if CurToken in [tkArray, tkRecord, tkObject, tkClass] then { If allowed }
  379. HadPackedModifier := True { rememeber for later }
  380. else { otherwise, syntax error }
  381. ParseExc(Format(SParserExpectTokenError,['ARRAY, RECORD, OBJECT or CLASS']))
  382. end;
  383. case CurToken of
  384. tkIdentifier:
  385. begin
  386. Name := CurTokenString;
  387. If (Prefix<>'') then
  388. Name:=Prefix+'.'+Name;
  389. NextToken;
  390. if CurToken = tkDot then
  391. begin
  392. ExpectIdentifier;
  393. Name := Name+'.'+CurTokenString;
  394. end else
  395. UngetToken;
  396. Ref := nil;
  397. s := UpperCase(Name);
  398. if s = 'BYTE' then Name := 'Byte'
  399. else if s = 'BOOLEAN' then Name := 'Boolean'
  400. else if s = 'CHAR' then Name := 'Char'
  401. else if s = 'INTEGER' then Name := 'Integer'
  402. else if s = 'INT64' then Name := 'Int64'
  403. else if s = 'LONGINT' then Name := 'LongInt'
  404. else if s = 'LONGWORD' then Name := 'LongWord'
  405. else if s = 'SHORTINT' then Name := 'ShortInt'
  406. else if s = 'SMALLINT' then Name := 'SmallInt'
  407. else if s = 'STRING' then Name := 'String'
  408. else if s = 'WORD' then Name := 'Word'
  409. else
  410. Ref := Engine.FindElement(Name);
  411. if Assigned(Ref) then
  412. begin
  413. {Result := TPasTypeRef(CreateElement(TPasTypeRef, Name, nil));
  414. TPasTypeRef(Result).RefType := Ref as TPasType;}
  415. Result := Ref as TPasType;
  416. Result.AddRef;
  417. end else
  418. Result := TPasUnresolvedTypeRef(CreateElement(TPasUnresolvedTypeRef, Name, nil));
  419. // !!!: Doesn't make sense for resolved types
  420. if Name = 'String' then
  421. begin
  422. NextToken;
  423. if CurToken = tkSquaredBraceOpen then
  424. begin
  425. // !!!: Parse the string length value and store it
  426. repeat
  427. NextToken;
  428. until CurToken = tkSquaredBraceClose;
  429. end else
  430. UngetToken;
  431. end;
  432. end;
  433. tkCaret:
  434. begin
  435. Result := TPasPointerType(CreateElement(TPasPointerType, '', Parent));
  436. TPasPointerType(Result).DestType := ParseType(nil);
  437. end;
  438. tkFile:
  439. begin
  440. Result := TPasFileType(CreateElement(TPasFileType, '', Parent));
  441. ParseFileType(TPasFileType(Result));
  442. end;
  443. tkArray:
  444. begin
  445. Result := TPasArrayType(CreateElement(TPasArrayType, '', Parent));
  446. TPasArrayType(Result).IsPacked := HadPackedModifier;
  447. ParseArrayType(TPasArrayType(Result));
  448. end;
  449. tkBraceOpen:
  450. begin
  451. Result := TPasEnumType(CreateElement(TPasEnumType, '', Parent));
  452. while True do
  453. begin
  454. NextToken;
  455. EnumValue := TPasEnumValue(CreateElement(TPasEnumValue,
  456. CurTokenString, Result));
  457. TPasEnumType(Result).Values.Add(EnumValue);
  458. NextToken;
  459. if CurToken = tkBraceClose then
  460. break
  461. else if CurToken in [tkEqual,tkAssign] then
  462. begin
  463. EnumValue.AssignedValue:=ParseExpression(Result);
  464. NextToken;
  465. if CurToken = tkBraceClose then
  466. Break
  467. else if not (CurToken=tkComma) then
  468. ParseExc(SParserExpectedCommaRBracket);
  469. end
  470. else if not (CurToken=tkComma) then
  471. ParseExc(SParserExpectedCommaRBracket)
  472. end;
  473. end;
  474. tkSet:
  475. begin
  476. Result := TPasSetType(CreateElement(TPasSetType, '', Parent));
  477. try
  478. ExpectToken(tkOf);
  479. TPasSetType(Result).EnumType := ParseType(Result);
  480. except
  481. Result.Free;
  482. raise;
  483. end;
  484. end;
  485. tkRecord:
  486. begin
  487. Result := TPasRecordType(CreateElement(TPasRecordType, '', Parent));
  488. TPasRecordType(Result).IsPacked:=HadPackedModifier;
  489. If HadPackedModifier then
  490. TPasRecordType(Result).IsBitPacked:=IsBitPacked;
  491. try
  492. ParseRecordDecl(TPasRecordType(Result), False);
  493. except
  494. Result.Free;
  495. raise;
  496. end;
  497. end;
  498. tkProcedure:
  499. begin
  500. Result := TPasProcedureType(
  501. CreateElement(TPasProcedureType, '', Parent));
  502. try
  503. ParseProcedureOrFunctionHeader(Result,
  504. TPasProcedureType(Result), ptProcedure, True);
  505. except
  506. Result.Free;
  507. raise;
  508. end;
  509. end;
  510. tkFunction:
  511. begin
  512. Result := Engine.CreateFunctionType('', 'Result', Parent, False,
  513. Scanner.CurFilename, Scanner.CurRow);
  514. try
  515. ParseProcedureOrFunctionHeader(Result,
  516. TPasFunctionType(Result), ptFunction, True);
  517. except
  518. Result.Free;
  519. raise;
  520. end;
  521. end;
  522. else
  523. begin
  524. UngetToken;
  525. ParseRange;
  526. end;
  527. // ParseExc(SParserTypeSyntaxError);
  528. end;
  529. end;
  530. function TPasParser.ParseComplexType(Parent : TPasElement = Nil): TPasType;
  531. begin
  532. NextToken;
  533. case CurToken of
  534. tkProcedure:
  535. begin
  536. Result := TPasProcedureType(CreateElement(TPasProcedureType, '', Parent));
  537. ParseProcedureOrFunctionHeader(Result,
  538. TPasProcedureType(Result), ptProcedure, True);
  539. if CurToken = tkSemicolon then UngetToken; // Unget semicolon
  540. end;
  541. tkFunction:
  542. begin
  543. Result := Engine.CreateFunctionType('', 'Result', Parent, False,
  544. Scanner.CurFilename, Scanner.CurRow);
  545. ParseProcedureOrFunctionHeader(Result,
  546. TPasFunctionType(Result), ptFunction, True);
  547. UngetToken; // Unget semicolon
  548. end;
  549. else
  550. begin
  551. UngetToken;
  552. Result := ParseType(Parent);
  553. exit;
  554. end;
  555. end;
  556. end;
  557. procedure TPasParser.ParseArrayType(Element: TPasArrayType);
  558. Var
  559. S : String;
  560. begin
  561. NextToken;
  562. S:='';
  563. case CurToken of
  564. tkSquaredBraceOpen:
  565. begin
  566. repeat
  567. NextToken;
  568. if CurToken<>tkSquaredBraceClose then
  569. S:=S+CurTokenText;
  570. until CurToken = tkSquaredBraceClose;
  571. Element.IndexRange:=S;
  572. ExpectToken(tkOf);
  573. Element.ElType := ParseType(nil);
  574. end;
  575. tkOf:
  576. begin
  577. NextToken;
  578. if CurToken = tkConst then
  579. // ArrayEl.AppendChild(Doc.CreateElement('const'))
  580. else
  581. begin
  582. UngetToken;
  583. Element.ElType := ParseType(nil);
  584. end
  585. end
  586. else
  587. ParseExc(SParserArrayTypeSyntaxError);
  588. end;
  589. end;
  590. procedure TPasParser.ParseFileType(Element: TPasFileType);
  591. begin
  592. NextToken;
  593. If CurToken=tkOf then
  594. Element.ElType := ParseType(nil)
  595. else
  596. ungettoken;
  597. end;
  598. function TPasParser.isEndOfExp:Boolean;
  599. const
  600. EndExprToken = [
  601. tkEOF, tkBraceClose, tkSquaredBraceClose, tkSemicolon, tkComma, tkColon,
  602. tkdo, tkdownto, tkelse, tkend, tkof, tkthen, tkto
  603. ];
  604. begin
  605. Result:=(CurToken in EndExprToken) or IsCurTokenHint;
  606. end;
  607. function TPasParser.ParseParams(AParent: TPasElement;paramskind: TPasExprKind): TParamsExpr;
  608. var
  609. params : TParamsExpr;
  610. p : TPasExpr;
  611. PClose : TToken;
  612. begin
  613. Result:=nil;
  614. if paramskind in [pekArrayParams, pekSet] then begin
  615. if CurToken<>tkSquaredBraceOpen then Exit;
  616. PClose:=tkSquaredBraceClose;
  617. end else begin
  618. if CurToken<>tkBraceOpen then Exit;
  619. PClose:=tkBraceClose;
  620. end;
  621. params:=TParamsExpr.Create(AParent,paramskind);
  622. try
  623. NextToken;
  624. if not isEndOfExp then begin
  625. repeat
  626. p:=DoParseExpression(AParent);
  627. if not Assigned(p) then Exit; // bad param syntax
  628. params.AddParam(p);
  629. if not (CurToken in [tkComma, PClose]) then begin
  630. Exit;
  631. end;
  632. if CurToken = tkComma then begin
  633. NextToken;
  634. if CurToken = PClose then begin
  635. //ErrorExpected(parser, 'identifier');
  636. Exit;
  637. end;
  638. end;
  639. until CurToken=PClose;
  640. end;
  641. NextToken;
  642. Result:=params;
  643. finally
  644. if not Assigned(Result) then params.Free;
  645. end;
  646. end;
  647. Function TPasParser.TokenToExprOp (AToken : TToken) : TExprOpCode;
  648. begin
  649. Case AToken of
  650. tkMul : Result:=eopMultiply;
  651. tkPlus : Result:=eopAdd;
  652. tkMinus : Result:=eopSubtract;
  653. tkDivision : Result:=eopDivide;
  654. tkLessThan : Result:=eopLessThan;
  655. tkEqual : Result:=eopEqual;
  656. tkGreaterThan : Result:=eopGreaterThan;
  657. tkAt : Result:=eopAddress;
  658. tkNotEqual : Result:=eopNotEqual;
  659. tkLessEqualThan : Result:=eopLessthanEqual;
  660. tkGreaterEqualThan : Result:=eopGreaterThanEqual;
  661. tkPower : Result:=eopPower;
  662. tkSymmetricalDifference : Result:=eopSymmetricalDifference;
  663. tkIs : Result:=eopIs;
  664. tkAs : Result:=eopAs;
  665. tkSHR : Result:=eopSHR;
  666. tkSHL : Result:=eopSHL;
  667. tkAnd : Result:=eopAnd;
  668. tkOr : Result:=eopOR;
  669. tkXor : Result:=eopXOR;
  670. tkMod : Result:=eopMod;
  671. tkDiv : Result:=eopDiv;
  672. tkNot : Result:=eopNot;
  673. tkIn : Result:=eopIn;
  674. tkDot : Result:=eopSubIdent;
  675. tkCaret : Result:=eopDeref;
  676. else
  677. ParseExc(format('Not an operand: (%d : %s)',[AToken,TokenInfos[AToken]]));
  678. end;
  679. end;
  680. function TPasParser.ParseExpIdent(AParent : TPasElement):TPasExpr;
  681. var
  682. x : TPasExpr;
  683. prm : TParamsExpr;
  684. u : TUnaryExpr;
  685. b : TBinaryExpr;
  686. optk : TToken;
  687. begin
  688. Result:=nil;
  689. case CurToken of
  690. tkString: x:=TPrimitiveExpr.Create(AParent,pekString, CurTokenString);
  691. tkChar: x:=TPrimitiveExpr.Create(AParent,pekString, CurTokenText);
  692. tkNumber: x:=TPrimitiveExpr.Create(AParent,pekNumber, CurTokenString);
  693. tkIdentifier: x:=TPrimitiveExpr.Create(AParent,pekIdent, CurTokenText);
  694. tkfalse, tktrue: x:=TBoolConstExpr.Create(Aparent,pekBoolConst, CurToken=tktrue);
  695. tknil: x:=TNilExpr.Create(Aparent);
  696. tkSquaredBraceOpen: x:=ParseParams(AParent,pekSet);
  697. tkCaret: begin
  698. // ^A..^_ characters. See #16341
  699. NextToken;
  700. if not (length(CurTokenText)=1) or not (CurTokenText[1] in ['A'..'_']) then begin
  701. UngetToken;
  702. ParseExc(SParserExpectedIdentifier);
  703. end;
  704. x:=TPrimitiveExpr.Create(AParent,pekString, '^'+CurTokenText);
  705. end;
  706. else
  707. ParseExc(SParserExpectedIdentifier);
  708. end;
  709. if x.Kind<>pekSet then NextToken;
  710. try
  711. if x.Kind=pekIdent then begin
  712. while CurToken in [tkBraceOpen, tkSquaredBraceOpen, tkCaret] do
  713. case CurToken of
  714. tkBraceOpen: begin
  715. prm:=ParseParams(AParent,pekFuncParams);
  716. if not Assigned(prm) then Exit;
  717. prm.Value:=x;
  718. x:=prm;
  719. end;
  720. tkSquaredBraceOpen: begin
  721. prm:=ParseParams(AParent,pekArrayParams);
  722. if not Assigned(prm) then Exit;
  723. prm.Value:=x;
  724. x:=prm;
  725. end;
  726. tkCaret: begin
  727. u:=TUnaryExpr.Create(AParent,x, TokenToExprOp(CurToken));
  728. x:=u;
  729. NextToken;
  730. end;
  731. end;
  732. if CurToken in [tkDot, tkas] then begin
  733. optk:=CurToken;
  734. NextToken;
  735. b:=TBinaryExpr.Create(AParent,x, ParseExpIdent(AParent), TokenToExprOp(optk));
  736. if not Assigned(b.right) then Exit; // error
  737. x:=b;
  738. end;
  739. end;
  740. if CurToken = tkDotDot then begin
  741. NextToken;
  742. b:=TBinaryExpr.CreateRange(AParent,x, DoParseExpression(AParent));
  743. if not Assigned(b.right) then Exit; // error
  744. x:=b;
  745. end;
  746. Result:=x;
  747. finally
  748. if not Assigned(Result) then x.Free;
  749. end;
  750. end;
  751. function TPasParser.OpLevel(t: TToken): Integer;
  752. begin
  753. case t of
  754. tknot,tkAt:
  755. Result:=4;
  756. tkMul, tkDivision, tkdiv, tkmod, tkand, tkShl,tkShr, tkas, tkPower :
  757. Result:=3;
  758. tkPlus, tkMinus, tkor, tkxor:
  759. Result:=2;
  760. tkEqual, tkNotEqual, tkLessThan, tkLessEqualThan, tkGreaterThan, tkGreaterEqualThan, tkin, tkis:
  761. Result:=1;
  762. else
  763. Result:=0;
  764. end;
  765. end;
  766. function TPasParser.DoParseExpression(Aparent : TPaselement;InitExpr: TPasExpr): TPasExpr;
  767. var
  768. expstack : TList;
  769. opstack : TList;
  770. pcount : Integer;
  771. x : TPasExpr;
  772. i : Integer;
  773. tempop : TToken;
  774. NotBinary : Boolean;
  775. const
  776. PrefixSym = [tkPlus, tkMinus, tknot, tkAt]; // + - not @
  777. BinaryOP = [tkMul, tkDivision, tkdiv, tkmod,
  778. tkand, tkShl,tkShr, tkas, tkPower,
  779. tkPlus, tkMinus, tkor, tkxor, tkSymmetricalDifference,
  780. tkEqual, tkNotEqual, tkLessThan, tkLessEqualThan,
  781. tkGreaterThan, tkGreaterEqualThan, tkin, tkis];
  782. function PopExp: TPasExpr; inline;
  783. begin
  784. if expstack.Count>0 then begin
  785. Result:=TPasExpr(expstack[expstack.Count-1]);
  786. expstack.Delete(expstack.Count-1);
  787. end else
  788. Result:=nil;
  789. end;
  790. procedure PushOper(token: TToken); inline;
  791. begin
  792. opstack.Add( Pointer(PtrInt(token)) );
  793. end;
  794. function PeekOper: TToken; inline;
  795. begin
  796. if opstack.Count>0 then Result:=TToken(PtrUInt(opstack[ opstack.Count-1]))
  797. else Result:=tkEOF
  798. end;
  799. function PopOper: TToken; inline;
  800. begin
  801. Result:=PeekOper;
  802. if Result<>tkEOF then opstack.Delete(opstack.Count-1);
  803. end;
  804. procedure PopAndPushOperator;
  805. var
  806. t : TToken;
  807. xright : TPasExpr;
  808. xleft : TPasExpr;
  809. begin
  810. t:=PopOper;
  811. xright:=PopExp;
  812. xleft:=PopExp;
  813. expstack.Add(TBinaryExpr.Create(AParent,xleft, xright, TokenToExprOp(t)));
  814. end;
  815. begin
  816. Result:=nil;
  817. expstack := TList.Create;
  818. opstack := TList.Create;
  819. try
  820. repeat
  821. NotBinary:=True;
  822. pcount:=0;
  823. if not Assigned(InitExpr) then
  824. begin
  825. // the first part of the expression has been parsed externally.
  826. // this is used by Constant Expresion parser (CEP) parsing only,
  827. // whenever it makes a false assuming on constant expression type.
  828. // i.e: SI_PAD_SIZE = ((128/sizeof(longint)) - 3);
  829. //
  830. // CEP assumes that it's array or record, because the expression
  831. // starts with "(". After the first part is parsed, the CEP meets "-"
  832. // that assures, it's not an array expression. The CEP should give the
  833. // first partback to the expression parser, to get the correct
  834. // token tree according to the operations priority.
  835. //
  836. // quite ugly. type information is required for CEP to work clean
  837. while CurToken in PrefixSym do begin
  838. PushOper(CurToken);
  839. inc(pcount);
  840. NextToken;
  841. end;
  842. if CurToken = tkBraceOpen then begin
  843. NextToken;
  844. x:=DoParseExpression(AParent);
  845. if CurToken<>tkBraceClose then Exit;
  846. NextToken;
  847. end else begin
  848. x:=ParseExpIdent(AParent);
  849. end;
  850. if not Assigned(x) then Exit;
  851. expstack.Add(x);
  852. for i:=1 to pcount do begin
  853. tempop:=PopOper;
  854. expstack.Add( TUnaryExpr.Create(AParent, PopExp, TokenToExprOp(tempop) ));
  855. end;
  856. end else
  857. begin
  858. expstack.Add(InitExpr);
  859. InitExpr:=nil;
  860. end;
  861. if (CurToken in BinaryOP) then begin
  862. // Adjusting order of the operations
  863. NotBinary:=False;
  864. tempop:=PeekOper;
  865. while (opstack.Count>0) and (OpLevel(tempop)>=OpLevel(CurToken)) do begin
  866. PopAndPushOperator;
  867. tempop:=PeekOper;
  868. end;
  869. PushOper(CurToken);
  870. NextToken;
  871. end;
  872. until NotBinary or isEndOfExp;
  873. if not NotBinary then ParseExc(SParserExpectedIdentifier);
  874. while opstack.Count>0 do PopAndPushOperator;
  875. // only 1 expression should be on the stack, at the end of the correct expression
  876. if expstack.Count=1 then Result:=TPasExpr(expstack[0]);
  877. finally
  878. if not Assigned(Result) then begin
  879. // expression error!
  880. for i:=0 to expstack.Count-1 do
  881. TObject(expstack[i]).Free;
  882. end;
  883. opstack.Free;
  884. expstack.Free;
  885. end;
  886. end;
  887. function TPasParser.ParseExpression(Aparent : TPaselement;Kind: TExprKind): String;
  888. var
  889. BracketLevel: Integer;
  890. LastTokenWasWord: Boolean;
  891. ls: String;
  892. begin
  893. SetLength(Result, 0);
  894. BracketLevel := 0;
  895. LastTokenWasWord := false;
  896. while True do
  897. begin
  898. NextToken;
  899. { !!!: Does not detect when normal brackets and square brackets are mixed
  900. in a wrong way. }
  901. if CurToken in [tkBraceOpen, tkSquaredBraceOpen] then
  902. Inc(BracketLevel)
  903. else if CurToken in [tkBraceClose, tkSquaredBraceClose] then
  904. begin
  905. if BracketLevel = 0 then
  906. break;
  907. Dec(BracketLevel);
  908. end else if (BracketLevel = 0) then
  909. begin
  910. if (CurToken in [tkComma, tkSemicolon,
  911. tkColon, tkDotDot, tkthen, tkend, tkelse, tkuntil, tkfinally, tkexcept,
  912. tkof, tkbegin, tkdo, tkto, tkdownto, tkinitialization, tkfinalization])
  913. then
  914. break;
  915. if (Kind=ek_PropertyIndex) and (CurToken=tkIdentifier) then begin
  916. ls:=LowerCase(CurTokenText);
  917. if (ls='read') or (ls ='write') or (ls='default') or (ls='nodefault') or (ls='implements') then
  918. Break;
  919. end;
  920. end;
  921. if (CurTokenString<>'') and IsIdentStart[CurTokenString[1]] then
  922. begin
  923. if LastTokenWasWord then
  924. Result := Result + ' ';
  925. LastTokenWasWord:=true;
  926. end
  927. else
  928. LastTokenWasWord:=false;
  929. if CurToken=tkString then
  930. begin
  931. If (Length(CurTokenText)>0) and (CurTokenText[1]=#0) then
  932. Raise Exception.Create('First char is null : "'+CurTokenText+'"');
  933. Result := Result + ''''+StringReplace(CurTokenText,'''','''''',[rfReplaceAll])+''''
  934. end
  935. else
  936. Result := Result + CurTokenText;
  937. end;
  938. if Result='' then
  939. ParseExc(SParserSyntaxError);
  940. UngetToken;
  941. end;
  942. function GetExprIdent(p: TPasExpr): String;
  943. begin
  944. if Assigned(p) and (p is TPrimitiveExpr) and (p.Kind=pekIdent) then
  945. Result:=TPrimitiveExpr(p).Value
  946. else
  947. Result:='';
  948. end;
  949. function TPasParser.DoParseConstValueExpression(Aparent : TPaselement): TPasExpr;
  950. var
  951. x : TPasExpr;
  952. n : AnsiString;
  953. r : TRecordValues;
  954. a : TArrayValues;
  955. function lastfield:boolean;
  956. begin
  957. result:= CurToken<>tkSemicolon;
  958. if not result then
  959. begin
  960. nexttoken;
  961. if curtoken=tkbraceclose then
  962. result:=true
  963. else
  964. ungettoken;
  965. end;
  966. end;
  967. begin
  968. if CurToken <> tkBraceOpen then
  969. Result:=DoParseExpression(AParent)
  970. else begin
  971. NextToken;
  972. x:=DoParseConstValueExpression(Aparent);
  973. case CurToken of
  974. tkComma: // array of values (a,b,c);
  975. begin
  976. a:=TArrayValues.Create(AParent);
  977. a.AddValues(x);
  978. repeat
  979. NextToken;
  980. x:=DoParseConstValueExpression(AParent);
  981. a.AddValues(x);
  982. until CurToken<>tkComma;
  983. Result:=a;
  984. end;
  985. tkColon: // record field (a:xxx;b:yyy;c:zzz);
  986. begin
  987. n:=GetExprIdent(x);
  988. x.Free;
  989. r:=TRecordValues.Create(AParent);
  990. NextToken;
  991. x:=DoParseConstValueExpression(AParent);
  992. r.AddField(n, x);
  993. if not lastfield then
  994. repeat
  995. n:=ExpectIdentifier;
  996. ExpectToken(tkColon);
  997. NextToken;
  998. x:=DoParseConstValueExpression(AParent);
  999. r.AddField(n, x)
  1000. until lastfield; // CurToken<>tkSemicolon;
  1001. Result:=r;
  1002. end;
  1003. else
  1004. // Binary expression! ((128 div sizeof(longint)) - 3); ;
  1005. Result:=DoParseExpression(AParent,x);
  1006. end;
  1007. if CurToken<>tkBraceClose then ParseExc(SParserExpectedCommaRBracket);
  1008. NextToken;
  1009. end;
  1010. end;
  1011. function TPasParser.ParseCommand: String;
  1012. var
  1013. BracketLevel: Integer;
  1014. LastTokenWasWord: Boolean;
  1015. begin
  1016. SetLength(Result, 0);
  1017. BracketLevel := 0;
  1018. LastTokenWasWord := false;
  1019. while True do
  1020. begin
  1021. NextToken;
  1022. { !!!: Does not detect when normal brackets and square brackets are mixed
  1023. in a wrong way. }
  1024. if CurToken in [tkBraceOpen, tkSquaredBraceOpen] then
  1025. Inc(BracketLevel)
  1026. else if CurToken in [tkBraceClose, tkSquaredBraceClose] then
  1027. begin
  1028. if BracketLevel = 0 then
  1029. break;
  1030. Dec(BracketLevel);
  1031. end else if (BracketLevel = 0) and (CurToken in [tkComma, tkSemicolon,
  1032. tkColon, tkthen, tkend, tkelse, tkuntil, tkfinally, tkexcept, tkof, tkdo,
  1033. tkbegin, tkinitialization, tkfinalization]) then
  1034. break;
  1035. if (CurTokenString<>'') and IsIdentStart[CurTokenString[1]] then
  1036. begin
  1037. if LastTokenWasWord then
  1038. Result := Result + ' ';
  1039. LastTokenWasWord:=true;
  1040. end
  1041. else
  1042. LastTokenWasWord:=false;
  1043. if CurToken=tkString then
  1044. begin
  1045. If (Length(CurTokenText)>0) and (CurTokenText[1]=#0) then
  1046. Raise Exception.Create('First char is null : "'+CurTokenText+'"');
  1047. Result := Result + ''''+StringReplace(CurTokenText,'''','''''',[rfReplaceAll])+''''
  1048. end
  1049. else
  1050. Result := Result + CurTokenText;
  1051. end;
  1052. UngetToken;
  1053. end;
  1054. procedure TPasParser.AddProcOrFunction(Declarations: TPasDeclarations;
  1055. AProc: TPasProcedure);
  1056. var
  1057. i: Integer;
  1058. Member: TPasElement;
  1059. OverloadedProc: TPasOverloadedProc;
  1060. begin
  1061. for i := 0 to Declarations.Functions.Count - 1 do
  1062. begin
  1063. Member := TPasElement(Declarations.Functions[i]);
  1064. if CompareText(Member.Name, AProc.Name) = 0 then
  1065. begin
  1066. if Member.ClassType = TPasOverloadedProc then
  1067. TPasOverloadedProc(Member).Overloads.Add(AProc)
  1068. else
  1069. begin
  1070. OverloadedProc := TPasOverloadedProc.Create(AProc.Name, Declarations);
  1071. OverloadedProc.Overloads.Add(Member);
  1072. OverloadedProc.Overloads.Add(AProc);
  1073. Declarations.Functions[i] := OverloadedProc;
  1074. Declarations.Declarations[Declarations.Declarations.IndexOf(Member)] :=
  1075. OverloadedProc;
  1076. end;
  1077. exit;
  1078. end;
  1079. end;
  1080. // Not overloaded, so just add the proc/function to the lists
  1081. Declarations.Declarations.Add(AProc);
  1082. Declarations.Functions.Add(AProc);
  1083. end;
  1084. // Returns the parent for an element which is to be created
  1085. function TPasParser.CheckIfOverloaded(AOwner: TPasClassType;
  1086. const AName: String): TPasElement;
  1087. var
  1088. i: Integer;
  1089. Member: TPasElement;
  1090. begin
  1091. for i := 0 to AOwner.Members.Count - 1 do
  1092. begin
  1093. Member := TPasElement(AOwner.Members[i]);
  1094. if CompareText(Member.Name, AName) = 0 then
  1095. begin
  1096. if Member.ClassType = TPasOverloadedProc then
  1097. Result := Member
  1098. else
  1099. begin
  1100. Result := TPasOverloadedProc.Create(AName, AOwner);
  1101. Result.Visibility := Member.Visibility;
  1102. TPasOverloadedProc(Result).Overloads.Add(Member);
  1103. AOwner.Members[i] := Result;
  1104. end;
  1105. exit;
  1106. end;
  1107. end;
  1108. Result := AOwner;
  1109. end;
  1110. procedure TPasParser.ParseMain(var Module: TPasModule);
  1111. begin
  1112. Module:=nil;
  1113. NextToken;
  1114. case CurToken of
  1115. tkUnit: ParseUnit(Module);
  1116. tkProgram: ParseProgram(Module);
  1117. else
  1118. ParseExc(Format(SParserExpectTokenError, ['unit']));
  1119. end;
  1120. end;
  1121. // Starts after the "unit" token
  1122. procedure TPasParser.ParseUnit(var Module: TPasModule);
  1123. begin
  1124. Module := nil;
  1125. Module := TPasModule(CreateElement(TPasModule, ExpectIdentifier,
  1126. Engine.Package));
  1127. CurModule:=Module;
  1128. try
  1129. if Assigned(Engine.Package) then
  1130. begin
  1131. Module.PackageName := Engine.Package.Name;
  1132. Engine.Package.Modules.Add(Module);
  1133. end;
  1134. CheckHint(Module,True);
  1135. // ExpectToken(tkSemicolon);
  1136. ExpectToken(tkInterface);
  1137. ParseInterface;
  1138. finally
  1139. CurModule:=nil;
  1140. end;
  1141. end;
  1142. // Starts after the "program" token
  1143. procedure TPasParser.ParseProgram(var Module: TPasModule);
  1144. begin
  1145. Module := nil;
  1146. Module := TPasModule(CreateElement(TPasProgram, ExpectIdentifier,
  1147. Engine.Package));
  1148. CurModule:=Module;
  1149. try
  1150. if Assigned(Engine.Package) then
  1151. begin
  1152. Module.PackageName := Engine.Package.Name;
  1153. Engine.Package.Modules.Add(Module);
  1154. end;
  1155. NextToken;
  1156. ParseImplementation;
  1157. finally
  1158. CurModule:=nil;
  1159. end;
  1160. end;
  1161. // Starts after the "interface" token
  1162. procedure TPasParser.ParseInterface;
  1163. var
  1164. Section: TInterfaceSection;
  1165. begin
  1166. Section := TInterfaceSection(CreateElement(TInterfaceSection, '', CurModule));
  1167. CurModule.InterfaceSection := Section;
  1168. ParseDeclarations(Section);
  1169. end;
  1170. // Starts after the "implementation" token
  1171. procedure TPasParser.ParseImplementation;
  1172. var
  1173. Section: TImplementationSection;
  1174. begin
  1175. Section := TImplementationSection(CreateElement(TImplementationSection, '', CurModule));
  1176. CurModule.ImplementationSection := Section;
  1177. ParseDeclarations(Section);
  1178. end;
  1179. procedure TPasParser.ParseInitialization;
  1180. var
  1181. Section: TInitializationSection;
  1182. SubBlock: TPasImplElement;
  1183. begin
  1184. Section := TInitializationSection(CreateElement(TInitializationSection, '', CurModule));
  1185. CurModule.InitializationSection := Section;
  1186. repeat
  1187. NextToken;
  1188. if (CurToken=tkend) then
  1189. begin
  1190. ExpectToken(tkDot);
  1191. exit;
  1192. end
  1193. else if (CurToken=tkfinalization) then
  1194. begin
  1195. ParseFinalization;
  1196. exit;
  1197. end
  1198. else if CurToken<>tkSemiColon then
  1199. begin
  1200. UngetToken;
  1201. ParseStatement(Section,SubBlock);
  1202. if SubBlock=nil then
  1203. ExpectToken(tkend);
  1204. end;
  1205. until false;
  1206. end;
  1207. procedure TPasParser.ParseFinalization;
  1208. var
  1209. Section: TFinalizationSection;
  1210. SubBlock: TPasImplElement;
  1211. begin
  1212. Section := TFinalizationSection(CreateElement(TFinalizationSection, '', CurModule));
  1213. CurModule.FinalizationSection := Section;
  1214. repeat
  1215. NextToken;
  1216. if (CurToken=tkend) then
  1217. begin
  1218. ExpectToken(tkDot);
  1219. exit;
  1220. end
  1221. else if CurToken<>tkSemiColon then
  1222. begin
  1223. UngetToken;
  1224. ParseStatement(Section,SubBlock);
  1225. if SubBlock=nil then
  1226. ExpectToken(tkend);
  1227. end;
  1228. until false;
  1229. UngetToken;
  1230. end;
  1231. procedure TPasParser.ParseDeclarations(Declarations: TPasDeclarations);
  1232. var
  1233. CurBlock: TDeclType;
  1234. ConstEl: TPasConst;
  1235. ResStrEl: TPasResString;
  1236. TypeEl: TPasType;
  1237. ClassEl: TPasClassType;
  1238. List: TList;
  1239. i,j: Integer;
  1240. VarEl: TPasVariable;
  1241. PropEl : TPasProperty;
  1242. begin
  1243. CurBlock := declNone;
  1244. while True do
  1245. begin
  1246. NextToken;
  1247. //writeln('TPasParser.ParseSection Token=',Scanner.CurTokenString,' ',CurToken);
  1248. case CurToken of
  1249. tkend:
  1250. begin
  1251. ExpectToken(tkDot);
  1252. break;
  1253. end;
  1254. tkimplementation:
  1255. if (CurToken = tkImplementation) and (Declarations is TInterfaceSection) then
  1256. begin
  1257. If Not Engine.InterfaceOnly then
  1258. ParseImplementation;
  1259. break;
  1260. end;
  1261. tkinitialization:
  1262. if (Declarations is TInterfaceSection)
  1263. or (Declarations is TImplementationSection) then
  1264. begin
  1265. ParseInitialization;
  1266. break;
  1267. end;
  1268. tkfinalization:
  1269. if (Declarations is TInterfaceSection)
  1270. or (Declarations is TImplementationSection) then
  1271. begin
  1272. ParseFinalization;
  1273. break;
  1274. end;
  1275. tkUses:
  1276. if Declarations is TPasSection then
  1277. ParseUsesList(TPasSection(Declarations))
  1278. else
  1279. ParseExc(SParserSyntaxError);
  1280. tkConst:
  1281. CurBlock := declConst;
  1282. tkResourcestring:
  1283. CurBlock := declResourcestring;
  1284. tkType:
  1285. CurBlock := declType;
  1286. tkVar:
  1287. CurBlock := declVar;
  1288. tkThreadVar:
  1289. CurBlock := declThreadVar;
  1290. tkProperty:
  1291. CurBlock := declProperty;
  1292. tkProcedure:
  1293. begin
  1294. AddProcOrFunction(Declarations,
  1295. ParseProcedureOrFunctionDecl(Declarations, ptProcedure));
  1296. CurBlock := declNone;
  1297. end;
  1298. tkFunction:
  1299. begin
  1300. AddProcOrFunction(Declarations,
  1301. ParseProcedureOrFunctionDecl(Declarations, ptFunction));
  1302. CurBlock := declNone;
  1303. end;
  1304. tkConstructor:
  1305. begin
  1306. AddProcOrFunction(Declarations,
  1307. ParseProcedureOrFunctionDecl(Declarations, ptConstructor));
  1308. CurBlock := declNone;
  1309. end;
  1310. tkDestructor:
  1311. begin
  1312. AddProcOrFunction(Declarations,
  1313. ParseProcedureOrFunctionDecl(Declarations, ptDestructor));
  1314. CurBlock := declNone;
  1315. end;
  1316. tkOperator:
  1317. begin
  1318. AddProcOrFunction(Declarations,
  1319. ParseProcedureOrFunctionDecl(Declarations, ptOperator));
  1320. CurBlock := declNone;
  1321. end;
  1322. tkClass:
  1323. begin
  1324. NextToken;
  1325. case CurToken of
  1326. tkprocedure:
  1327. begin
  1328. AddProcOrFunction(Declarations,
  1329. ParseProcedureOrFunctionDecl(Declarations, ptClassProcedure));
  1330. CurBlock := declNone;
  1331. end;
  1332. tkfunction:
  1333. begin
  1334. AddProcOrFunction(Declarations,
  1335. ParseProcedureOrFunctionDecl(Declarations, ptClassFunction));
  1336. CurBlock := declNone;
  1337. end;
  1338. else
  1339. ExpectToken(tkprocedure);
  1340. end;
  1341. end;
  1342. tkIdentifier:
  1343. begin
  1344. case CurBlock of
  1345. declConst:
  1346. begin
  1347. ConstEl := ParseConstDecl(Declarations);
  1348. Declarations.Declarations.Add(ConstEl);
  1349. Declarations.Consts.Add(ConstEl);
  1350. end;
  1351. declResourcestring:
  1352. begin
  1353. ResStrEl := ParseResourcestringDecl(Declarations);
  1354. Declarations.Declarations.Add(ResStrEl);
  1355. Declarations.ResStrings.Add(ResStrEl);
  1356. end;
  1357. declType:
  1358. begin
  1359. TypeEl := ParseTypeDecl(Declarations);
  1360. if Assigned(TypeEl) then // !!!
  1361. begin
  1362. Declarations.Declarations.Add(TypeEl);
  1363. if TypeEl.ClassType = TPasClassType then
  1364. begin
  1365. // Remove previous forward declarations, if necessary
  1366. for i := 0 to Declarations.Classes.Count - 1 do
  1367. begin
  1368. ClassEl := TPasClassType(Declarations.Classes[i]);
  1369. if CompareText(ClassEl.Name, TypeEl.Name) = 0 then
  1370. begin
  1371. Declarations.Classes.Delete(i);
  1372. for j := 0 to Declarations.Declarations.Count - 1 do
  1373. if CompareText(TypeEl.Name,
  1374. TPasElement(Declarations.Declarations[j]).Name) = 0 then
  1375. begin
  1376. Declarations.Declarations.Delete(j);
  1377. break;
  1378. end;
  1379. ClassEl.Release;
  1380. break;
  1381. end;
  1382. end;
  1383. // Add the new class to the class list
  1384. Declarations.Classes.Add(TypeEl)
  1385. end else
  1386. Declarations.Types.Add(TypeEl);
  1387. end;
  1388. end;
  1389. declVar, declThreadVar:
  1390. begin
  1391. List := TList.Create;
  1392. try
  1393. try
  1394. ParseVarDecl(Declarations, List);
  1395. except
  1396. for i := 0 to List.Count - 1 do
  1397. TPasVariable(List[i]).Release;
  1398. raise;
  1399. end;
  1400. for i := 0 to List.Count - 1 do
  1401. begin
  1402. VarEl := TPasVariable(List[i]);
  1403. Declarations.Declarations.Add(VarEl);
  1404. Declarations.Variables.Add(VarEl);
  1405. end;
  1406. finally
  1407. List.Free;
  1408. end;
  1409. end;
  1410. declProperty:
  1411. begin
  1412. PropEl:=TPasProperty(CreateElement(TPasProperty, CurTokenString, Declarations));
  1413. Try
  1414. ParseProperty(PropEl)
  1415. except
  1416. Propel.Free;
  1417. Raise;
  1418. end;
  1419. Declarations.Declarations.Add(PropEl);
  1420. Declarations.properties.add(PropEl);
  1421. end;
  1422. else
  1423. ParseExc(SParserSyntaxError);
  1424. end;
  1425. end;
  1426. tkbegin:
  1427. begin
  1428. if Declarations is TProcedureBody then
  1429. begin
  1430. ParseProcBeginBlock(TProcedureBody(Declarations));
  1431. break;
  1432. end
  1433. else if (Declarations is TInterfaceSection)
  1434. or (Declarations is TImplementationSection) then
  1435. begin
  1436. ParseInitialization;
  1437. break;
  1438. end
  1439. else
  1440. ParseExc(SParserSyntaxError);
  1441. end;
  1442. tklabel:
  1443. begin
  1444. if not (Declarations is TInterfaceSection) then
  1445. ParseLabels(Declarations);
  1446. end;
  1447. else
  1448. ParseExc(SParserSyntaxError);
  1449. end;
  1450. end;
  1451. end;
  1452. // Starts after the "uses" token
  1453. procedure TPasParser.ParseUsesList(ASection: TPasSection);
  1454. function CheckUnit(AUnitName : string):TPasElement;
  1455. begin
  1456. result := Engine.FindModule(AUnitName); // should we resolve module here when "IN" filename is not known yet?
  1457. if Assigned(result) then
  1458. result.AddRef
  1459. else
  1460. Result := TPasType(CreateElement(TPasUnresolvedTypeRef, AUnitName,
  1461. ASection));
  1462. ASection.UsesList.Add(Result);
  1463. end;
  1464. var
  1465. AUnitName: String;
  1466. Element: TPasElement;
  1467. begin
  1468. If not (Asection is TImplementationSection) Then // interface,program,library,package
  1469. Element:=CheckUnit('System'); // system always implicitely first.
  1470. while True do
  1471. begin
  1472. AUnitName := ExpectIdentifier;
  1473. Element :=CheckUnit(AUnitName);
  1474. NextToken;
  1475. if CurToken = tkin then begin
  1476. // todo: store unit's file name somewhere
  1477. NextToken; // skip in
  1478. ExpectToken(tkString); // skip unit's real file name
  1479. if (Element is TPasModule) and (TPasmodule(Element).filename<>'') then
  1480. TPasModule(Element).FileName:=curtokenstring;
  1481. end;
  1482. if CurToken = tkSemicolon then
  1483. break
  1484. else if CurToken <> tkComma then
  1485. ParseExc(SParserExpectedCommaSemicolon);
  1486. end;
  1487. end;
  1488. // Starts after the variable name
  1489. function TPasParser.ParseConstDecl(Parent: TPasElement): TPasConst;
  1490. begin
  1491. Result := TPasConst(CreateElement(TPasConst, CurTokenString, Parent));
  1492. try
  1493. NextToken;
  1494. if CurToken = tkColon then
  1495. Result.VarType := ParseType(nil)
  1496. else
  1497. UngetToken;
  1498. ExpectToken(tkEqual);
  1499. //skipping the expression as a value
  1500. //Result.Value := ParseExpression;
  1501. // using new expression parser!
  1502. NextToken; // skip tkEqual
  1503. Result.Expr:=DoParseConstValueExpression(Result);
  1504. // must unget for the check to be peformed fine!
  1505. UngetToken;
  1506. CheckHint(Result,True);
  1507. except
  1508. Result.Free;
  1509. raise;
  1510. end;
  1511. end;
  1512. // Starts after the variable name
  1513. function TPasParser.ParseResourcestringDecl(Parent: TPasElement): TPasResString;
  1514. begin
  1515. Result := TPasResString(CreateElement(TPasResString, CurTokenString, Parent));
  1516. try
  1517. ExpectToken(tkEqual);
  1518. Result.Value := ParseExpression(Result);
  1519. CheckHint(Result,True);
  1520. except
  1521. Result.Free;
  1522. raise;
  1523. end;
  1524. end;
  1525. // Starts after the type name
  1526. function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType;
  1527. var
  1528. TypeName: String;
  1529. procedure ParseRange;
  1530. begin
  1531. Result := TPasRangeType(CreateElement(TPasRangeType, TypeName, Parent));
  1532. try
  1533. TPasRangeType(Result).RangeStart := ParseExpression(Result);
  1534. ExpectToken(tkDotDot);
  1535. TPasRangeType(Result).RangeEnd := ParseExpression(Result);
  1536. CheckHint(Result,True);
  1537. except
  1538. Result.Free;
  1539. raise;
  1540. end;
  1541. end;
  1542. var
  1543. EnumValue: TPasEnumValue;
  1544. Prefix : String;
  1545. HadPackedModifier : Boolean; // 12/04/04 - Dave - Added
  1546. IsBitPacked : Boolean;
  1547. begin
  1548. TypeName := CurTokenString;
  1549. ExpectToken(tkEqual);
  1550. NextToken;
  1551. HadPackedModifier := False; { Assume not present }
  1552. if CurToken in [tkPacked,tkbitpacked] then { If PACKED modifier }
  1553. begin { Handle PACKED modifier for all situations }
  1554. IsBitPacked:=CurToken=tkbitpacked;
  1555. NextToken; { Move to next token for rest of parse }
  1556. if CurToken in [tkArray, tkRecord, tkObject, tkClass] then { If allowed }
  1557. HadPackedModifier := True { rememeber for later }
  1558. else { otherwise, syntax error }
  1559. ParseExc(Format(SParserExpectTokenError,['ARRAY, RECORD, OBJECT or CLASS']))
  1560. end;
  1561. case CurToken of
  1562. tkRecord:
  1563. begin
  1564. Result := TPasRecordType(CreateElement(TPasRecordType, TypeName,
  1565. Parent));
  1566. try
  1567. ParseRecordDecl(TPasRecordType(Result), False);
  1568. CheckHint(Result,True);
  1569. TPasRecordType(Result).IsPacked := HadPackedModifier;
  1570. If HadPackedModifier then
  1571. TPasRecordType(Result).IsBitPacked:=IsBitPacked;
  1572. except
  1573. Result.Free;
  1574. raise;
  1575. end;
  1576. end;
  1577. tkObject:
  1578. begin
  1579. Result := ParseClassDecl(Parent, TypeName, okObject);
  1580. TPasClassType(Result).IsPacked := HadPackedModifier;
  1581. end;
  1582. tkClass:
  1583. begin
  1584. Result := ParseClassDecl(Parent, TypeName, okClass);
  1585. { could be TPasClassOfType }
  1586. if result is TPasClassType then
  1587. TPasClassType(Result).IsPacked := HadPackedModifier;
  1588. end;
  1589. tkInterface:
  1590. Result := ParseClassDecl(Parent, TypeName, okInterface);
  1591. tkCaret:
  1592. begin
  1593. Result := TPasPointerType(CreateElement(TPasPointerType, TypeName,
  1594. Parent));
  1595. try
  1596. TPasPointerType(Result).DestType := ParseType(nil);
  1597. CheckHint(Result,True);
  1598. except
  1599. Result.Free;
  1600. raise;
  1601. end;
  1602. end;
  1603. tkIdentifier:
  1604. begin
  1605. Prefix:=CurTokenString;
  1606. NextToken;
  1607. if CurToken = tkDot then
  1608. begin
  1609. ExpectIdentifier;
  1610. NextToken;
  1611. end
  1612. else
  1613. Prefix:='';
  1614. if (CurToken = tkSemicolon) or IsCurTokenHint then
  1615. begin
  1616. UngetToken;
  1617. UngetToken;
  1618. Result := TPasAliasType(CreateElement(TPasAliasType, TypeName,
  1619. Parent));
  1620. try
  1621. TPasAliasType(Result).DestType := ParseType(nil,Prefix);
  1622. CheckHint(Result,True);
  1623. except
  1624. Result.Free;
  1625. raise;
  1626. end;
  1627. end else if CurToken = tkSquaredBraceOpen then
  1628. begin
  1629. // !!!: Check for string type and store string length somewhere
  1630. Result := TPasAliasType(CreateElement(TPasAliasType, TypeName,
  1631. Parent));
  1632. try
  1633. TPasAliasType(Result).DestType :=
  1634. TPasUnresolvedTypeRef.Create(CurTokenString, Parent);
  1635. ParseExpression(Parent);
  1636. ExpectToken(tkSquaredBraceClose);
  1637. CheckHint(Result,True);
  1638. except
  1639. Result.Free;
  1640. raise;
  1641. end;
  1642. end
  1643. else
  1644. begin
  1645. UngetToken;
  1646. UngetToken;
  1647. ParseRange;
  1648. end;
  1649. end;
  1650. tkFile:
  1651. begin
  1652. Result := TPasFileType(CreateElement(TPasFileType, TypeName, Parent));
  1653. Try
  1654. ParseFileType(TPasFileType(Result));
  1655. CheckHint(Result,True);
  1656. Except
  1657. Result.free;
  1658. Raise;
  1659. end;
  1660. end;
  1661. tkArray:
  1662. begin
  1663. Result := TPasArrayType(CreateElement(TPasArrayType, TypeName, Parent));
  1664. try
  1665. ParseArrayType(TPasArrayType(Result));
  1666. TPasArrayType(Result).IsPacked := HadPackedModifier;
  1667. CheckHint(Result,True);
  1668. except
  1669. Result.Free;
  1670. raise;
  1671. end;
  1672. end;
  1673. tkSet:
  1674. begin
  1675. Result := TPasSetType(CreateElement(TPasSetType, TypeName, Parent));
  1676. try
  1677. ExpectToken(tkOf);
  1678. TPasSetType(Result).EnumType := ParseType(Result);
  1679. CheckHint(Result,True);
  1680. except
  1681. Result.Free;
  1682. raise;
  1683. end;
  1684. end;
  1685. tkBraceOpen:
  1686. begin
  1687. Result := TPasEnumType(CreateElement(TPasEnumType, TypeName, Parent));
  1688. try
  1689. while True do
  1690. begin
  1691. NextToken;
  1692. EnumValue := TPasEnumValue(CreateElement(TPasEnumValue,
  1693. CurTokenString, Result));
  1694. TPasEnumType(Result).Values.Add(EnumValue);
  1695. NextToken;
  1696. if CurToken = tkBraceClose then
  1697. break
  1698. else if CurToken in [tkEqual,tkAssign] then
  1699. begin
  1700. EnumValue.AssignedValue:=ParseExpression(result);
  1701. NextToken;
  1702. if CurToken = tkBraceClose then
  1703. Break
  1704. else if not (CurToken=tkComma) then
  1705. ParseExc(SParserExpectedCommaRBracket);
  1706. end
  1707. else if not (CurToken=tkComma) then
  1708. ParseExc(SParserExpectedCommaRBracket)
  1709. end;
  1710. CheckHint(Result,True);
  1711. except
  1712. Result.Free;
  1713. raise;
  1714. end;
  1715. end;
  1716. tkProcedure:
  1717. begin
  1718. Result := TPasProcedureType(CreateElement(TPasProcedureType, TypeName,
  1719. Parent));
  1720. try
  1721. ParseProcedureOrFunctionHeader(Result,
  1722. TPasProcedureType(Result), ptProcedure, True);
  1723. except
  1724. Result.Free;
  1725. raise;
  1726. end;
  1727. end;
  1728. tkFunction:
  1729. begin
  1730. Result := Engine.CreateFunctionType(TypeName, 'Result', Parent, False,
  1731. Scanner.CurFilename, Scanner.CurRow);
  1732. try
  1733. ParseProcedureOrFunctionHeader(Result,
  1734. TPasFunctionType(Result), ptFunction, True);
  1735. except
  1736. Result.Free;
  1737. raise;
  1738. end;
  1739. end;
  1740. tkType:
  1741. begin
  1742. Result := TPasTypeAliasType(CreateElement(TPasTypeAliasType, TypeName,
  1743. Parent));
  1744. try
  1745. TPasTypeAliasType(Result).DestType := ParseType(nil);
  1746. CheckHint(Result,True);
  1747. except
  1748. Result.Free;
  1749. raise;
  1750. end;
  1751. end;
  1752. else
  1753. begin
  1754. UngetToken;
  1755. ParseRange;
  1756. end;
  1757. end;
  1758. end;
  1759. // Starts after the variable name
  1760. procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList);
  1761. begin
  1762. ParseInlineVarDecl(Parent, VarList, visDefault, False);
  1763. end;
  1764. procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
  1765. AVisibility: TPasMemberVisibility; ClosingBrace: Boolean);
  1766. var
  1767. VarNames: TStringList;
  1768. i: Integer;
  1769. VarType: TPasType;
  1770. VarEl: TPasVariable;
  1771. H : TPasMemberHints;
  1772. begin
  1773. VarNames := TStringList.Create;
  1774. try
  1775. while True do
  1776. begin
  1777. VarNames.Add(CurTokenString);
  1778. NextToken;
  1779. if CurToken = tkColon then
  1780. break
  1781. else if CurToken <> tkComma then
  1782. ParseExc(SParserExpectedCommaColon);
  1783. ExpectIdentifier;
  1784. end;
  1785. VarType := ParseComplexType(Parent);
  1786. H:=CheckHint(Nil,False);
  1787. NextToken;
  1788. for i := 0 to VarNames.Count - 1 do
  1789. begin
  1790. VarEl := TPasVariable(CreateElement(TPasVariable, VarNames[i], Parent,
  1791. AVisibility));
  1792. VarEl.VarType := VarType;
  1793. VarEl.Hints:=H;
  1794. if i > 0 then
  1795. VarType.AddRef;
  1796. VarList.Add(VarEl);
  1797. end;
  1798. // Records may be terminated with end, no semicolon
  1799. if (CurToken <> tkEnd) and (CurToken <> tkSemicolon) and not
  1800. (ClosingBrace and (CurToken = tkBraceClose)) then
  1801. ParseExc(SParserExpectedSemiColonEnd);
  1802. finally
  1803. VarNames.Free;
  1804. end;
  1805. end;
  1806. // Starts after the variable name
  1807. procedure TPasParser.ParseVarDecl(Parent: TPasElement; List: TList);
  1808. var
  1809. i: Integer;
  1810. VarType: TPasType;
  1811. Value, S: String;
  1812. M: string;
  1813. H : TPasMemberHints;
  1814. begin
  1815. while True do
  1816. begin
  1817. List.Add(CreateElement(TPasVariable, CurTokenString, Parent));
  1818. NextToken;
  1819. if CurToken = tkColon then
  1820. break
  1821. else if CurToken <> tkComma then
  1822. ParseExc(SParserExpectedCommaColon);
  1823. ExpectIdentifier;
  1824. end;
  1825. VarType := ParseComplexType;
  1826. for i := 0 to List.Count - 1 do
  1827. begin
  1828. TPasVariable(List[i]).VarType := VarType;
  1829. if i > 0 then
  1830. VarType.AddRef;
  1831. end;
  1832. //writeln('TPasParser.ParseVarDecl ',CurTokenText);
  1833. NextToken;
  1834. // Writeln(LastVar,': Parsed complex type: ',CurtokenText);
  1835. // NextToken;
  1836. // Writeln(LastVar,': Parsed complex type, next: ',CurtokenText);
  1837. If CurToken=tkEqual then
  1838. begin
  1839. Value := ParseExpression(Parent);
  1840. for i := 0 to List.Count - 1 do
  1841. TPasVariable(List[i]).Value := Value;
  1842. NextToken;
  1843. end;
  1844. if CurToken = tkAbsolute then
  1845. begin
  1846. ExpectIdentifier;
  1847. S:=CurTokenText;
  1848. NextToken;
  1849. if CurToken=tkDot then
  1850. begin
  1851. ExpectIdentifier;
  1852. S:=S+'.'+CurTokenText;
  1853. end
  1854. else
  1855. UnGetToken;
  1856. For I:=0 to List.Count-1 do
  1857. TPasVariable(List[i]).AbsoluteLocation:=S;
  1858. end else
  1859. UngetToken;
  1860. H:=CheckHint(Nil,True);
  1861. If (H<>[]) then
  1862. for i := 0 to List.Count - 1 do
  1863. TPasVariable(List[i]).Hints:=H;
  1864. M := '';
  1865. while True do
  1866. begin
  1867. NextToken;
  1868. if CurToken = tkIdentifier then
  1869. begin
  1870. s := UpperCase(CurTokenText);
  1871. if s = 'CVAR' then
  1872. begin
  1873. M := M + '; cvar';
  1874. ExpectToken(tkSemicolon);
  1875. end
  1876. else if (s = 'EXTERNAL') or (s = 'PUBLIC') or (s = 'EXPORT') then
  1877. begin
  1878. M := M + ';' + CurTokenText;
  1879. if s = 'EXTERNAL' then
  1880. begin
  1881. NextToken;
  1882. if ((CurToken = tkString) or (CurToken = tkIdentifier)) and (UpperCase(CurTokenText)<> 'NAME') then
  1883. begin
  1884. // !!!: Is this really correct for tkString?
  1885. M := M + ' ' + CurTokenText;
  1886. NextToken;
  1887. end;
  1888. end
  1889. else
  1890. NextToken;
  1891. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'NAME') then
  1892. begin
  1893. M := M + ' name ';
  1894. NextToken;
  1895. if (CurToken = tkString) or (CurToken = tkIdentifier) then
  1896. // !!!: Is this really correct for tkString?
  1897. M := M + CurTokenText
  1898. else
  1899. ParseExc(SParserSyntaxError);
  1900. H:=CheckHint(Nil,True);
  1901. If (H<>[]) then
  1902. for i := 0 to List.Count - 1 do
  1903. TPasVariable(List[i]).Hints:=H;
  1904. // ExpectToken(tkSemicolon);
  1905. end
  1906. else if CurToken <> tkSemicolon then
  1907. ParseExc(SParserSyntaxError);
  1908. end else
  1909. begin
  1910. UngetToken;
  1911. break;
  1912. end
  1913. end else
  1914. begin
  1915. UngetToken;
  1916. break;
  1917. end;
  1918. end; // while
  1919. if M <> '' then
  1920. for i := 0 to List.Count - 1 do
  1921. TPasVariable(List[i]).Modifiers := M;
  1922. end;
  1923. // Starts after the opening bracket token
  1924. procedure TPasParser.ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
  1925. var
  1926. ArgNames: TStringList;
  1927. IsUntyped: Boolean;
  1928. Name, Value: String;
  1929. i: Integer;
  1930. Arg: TPasArgument;
  1931. Access: TArgumentAccess;
  1932. ArgType: TPasType;
  1933. begin
  1934. while True do
  1935. begin
  1936. ArgNames := TStringList.Create;
  1937. Access := argDefault;
  1938. IsUntyped := False;
  1939. ArgType := nil;
  1940. while True do
  1941. begin
  1942. NextToken;
  1943. if CurToken = tkConst then
  1944. begin
  1945. Access := argConst;
  1946. Name := ExpectIdentifier;
  1947. end else if CurToken = tkVar then
  1948. begin
  1949. Access := ArgVar;
  1950. Name := ExpectIdentifier;
  1951. end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OUT') then
  1952. begin
  1953. Access := ArgOut;
  1954. Name := ExpectIdentifier;
  1955. end else if CurToken = tkIdentifier then
  1956. Name := CurTokenString
  1957. else
  1958. ParseExc(SParserExpectedConstVarID);
  1959. ArgNames.Add(Name);
  1960. NextToken;
  1961. if CurToken = tkColon then
  1962. break
  1963. else if ((CurToken = tkSemicolon) or (CurToken = tkBraceClose)) and
  1964. (Access <> argDefault) then
  1965. begin
  1966. // found an untyped const or var argument
  1967. UngetToken;
  1968. IsUntyped := True;
  1969. break
  1970. end
  1971. else if CurToken <> tkComma then
  1972. ParseExc(SParserExpectedCommaColon);
  1973. end;
  1974. SetLength(Value, 0);
  1975. if not IsUntyped then
  1976. begin
  1977. ArgType := ParseType(nil);
  1978. NextToken;
  1979. if CurToken = tkEqual then
  1980. begin
  1981. Value := ParseExpression(Parent);
  1982. end else
  1983. UngetToken;
  1984. end;
  1985. for i := 0 to ArgNames.Count - 1 do
  1986. begin
  1987. Arg := TPasArgument(CreateElement(TPasArgument, ArgNames[i], Parent));
  1988. Arg.Access := Access;
  1989. Arg.ArgType := ArgType;
  1990. if (i > 0) and Assigned(ArgType) then
  1991. ArgType.AddRef;
  1992. Arg.Value := Value;
  1993. Args.Add(Arg);
  1994. end;
  1995. ArgNames.Free;
  1996. NextToken;
  1997. if CurToken = EndToken then
  1998. break;
  1999. end;
  2000. end;
  2001. // Next token is expected to be a "(", ";" or for a function ":". The caller
  2002. // will get the token after the final ";" as next token.
  2003. procedure TPasParser.ParseProcedureOrFunctionHeader(Parent: TPasElement;
  2004. Element: TPasProcedureType; ProcType: TProcType; OfObjectPossible: Boolean);
  2005. procedure ConsumeSemi;
  2006. begin
  2007. NextToken;
  2008. if (CurToken <> tksemicolon) and IsCurTokenHint then
  2009. ungettoken;
  2010. end;
  2011. Var
  2012. Tok : String;
  2013. i: Integer;
  2014. Proc: TPasProcedure;
  2015. ahint : TPasMemberHint;
  2016. begin
  2017. NextToken;
  2018. case ProcType of
  2019. ptFunction,ptClassFunction:
  2020. begin
  2021. if CurToken = tkBraceOpen then
  2022. begin
  2023. NextToken;
  2024. if (CurToken <> tkBraceClose) then
  2025. begin
  2026. UngetToken;
  2027. ParseArgList(Parent, Element.Args, tkBraceClose);
  2028. end;
  2029. ExpectToken(tkColon);
  2030. end else if CurToken <> tkColon then
  2031. ParseExc(SParserExpectedLBracketColon);
  2032. if Assigned(Element) then // !!!
  2033. TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
  2034. else
  2035. ParseType(nil);
  2036. end;
  2037. ptProcedure,ptConstructor,ptDestructor,ptClassProcedure:
  2038. begin
  2039. if CurToken = tkBraceOpen then
  2040. begin
  2041. NextToken;
  2042. if (CurToken = tkBraceClose) then
  2043. else
  2044. begin
  2045. UngetToken;
  2046. ParseArgList(Element, Element.Args, tkBraceClose);
  2047. end
  2048. end else if (CurToken = tkSemicolon)
  2049. or (OfObjectPossible and (CurToken in [tkOf,tkEqual]))
  2050. then
  2051. UngetToken
  2052. else
  2053. ParseExc(SParserExpectedLBracketSemicolon);
  2054. end;
  2055. ptOperator:
  2056. begin
  2057. ParseArgList(Element, Element.Args, tkBraceClose);
  2058. NextToken;
  2059. if (CurToken=tkIdentifier) then
  2060. begin
  2061. TPasFunctionType(Element).ResultEl.Name := CurTokenName;
  2062. ExpectToken(tkColon);
  2063. end
  2064. else if (CurToken=tkColon) then
  2065. TPasFunctionType(Element).ResultEl.Name := 'Result'
  2066. else
  2067. ParseExc(SParserExpectedColonID);
  2068. if Assigned(Element) then // !!!
  2069. TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
  2070. else
  2071. ParseType(nil);
  2072. end;
  2073. end;
  2074. NextToken;
  2075. if OfObjectPossible and (CurToken = tkOf) then
  2076. begin
  2077. ExpectToken(tkObject);
  2078. Element.IsOfObject := True;
  2079. end else
  2080. UngetToken;
  2081. NextToken;
  2082. if CurToken = tkEqual then
  2083. begin
  2084. // for example: const p: procedure = nil;
  2085. UngetToken;
  2086. exit;
  2087. end else
  2088. UngetToken;
  2089. ExpectToken(tkSemicolon);
  2090. while True do
  2091. begin
  2092. // CheckHint(Element,False);
  2093. NextToken;
  2094. if (CurToken = tkIdentifier) or (CurToken=tklibrary) then // library is a token and a directive.
  2095. begin
  2096. Tok:=UpperCase(CurTokenString);
  2097. If (Tok='CDECL') then
  2098. begin
  2099. TPasProcedure(Parent).CallingConvention:=ccCDecl;
  2100. ExpectToken(tkSemicolon);
  2101. end
  2102. else If (Tok='EXPORT') then
  2103. begin
  2104. TPasProcedure(Parent).AddModifier(pmExported);
  2105. ExpectToken(tkSemicolon);
  2106. end
  2107. else if (Tok='PASCAL') then
  2108. begin
  2109. TPasProcedure(Parent).CallingConvention:=ccPascal;
  2110. ExpectToken(tkSemicolon);
  2111. end
  2112. else if (Tok='STDCALL') then
  2113. begin
  2114. TPasProcedure(Parent).CallingConvention:=ccStdCall;
  2115. ExpectToken(tkSemicolon);
  2116. end
  2117. else if (Tok='OLDFPCCALL') then
  2118. begin
  2119. TPasProcedure(Parent).CallingConvention:=ccOldFPCCall;
  2120. ExpectToken(tkSemicolon);
  2121. end
  2122. else if (Tok='EXTDECL') then
  2123. begin
  2124. // extdecl is a common macro for external functions
  2125. TPasProcedure(Parent).AddModifier(pmExternal);
  2126. ExpectToken(tkSemicolon);
  2127. end
  2128. else if (Tok='EXTERNAL') then
  2129. begin
  2130. TPasProcedure(Parent).AddModifier(pmExternal);
  2131. NextToken;
  2132. if CurToken in [tkString,tkIdentifier] then
  2133. begin
  2134. NextToken;
  2135. Tok:=UpperCase(CurTokenString);
  2136. if Tok='NAME' then
  2137. begin
  2138. NextToken;
  2139. if not (CurToken in [tkString,tkIdentifier]) then
  2140. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkString]]));
  2141. end;
  2142. end else
  2143. UngetToken;
  2144. ExpectToken(tkSemicolon);
  2145. end
  2146. else if (Tok='REGISTER') then
  2147. begin
  2148. TPasProcedure(Parent).CallingConvention:=ccRegister;
  2149. ExpectToken(tkSemicolon);
  2150. end
  2151. else if (Tok='COMPILERPROC') then
  2152. begin
  2153. TPasProcedure(Parent).AddModifier(pmCompilerProc);
  2154. ExpectToken(tkSemicolon);
  2155. end
  2156. else if (Tok='VARARGS') then
  2157. begin
  2158. TPasProcedure(Parent).AddModifier(pmVarArgs);
  2159. ExpectToken(tkSemicolon);
  2160. end
  2161. else if IsCurTokenHint(ahint) then // deprecated,platform,experimental,library, unimplemented etc
  2162. begin
  2163. element.hints:=element.hints+[ahint];
  2164. consumesemi;
  2165. end
  2166. else if (tok='OVERLOAD') then
  2167. begin
  2168. TPasProcedure(Parent).AddModifier(pmOverload);
  2169. ExpectToken(tkSemicolon);
  2170. end
  2171. else if (tok='INLINE') then
  2172. begin
  2173. TPasProcedure(Parent).AddModifier(pmInline);
  2174. ExpectToken(tkSemicolon);
  2175. end
  2176. else if (tok='ASSEMBLER') then
  2177. begin
  2178. TPasProcedure(Parent).AddModifier(pmAssembler);
  2179. ExpectToken(tkSemicolon);
  2180. end
  2181. else if (tok = 'EXTERNAL') then
  2182. repeat
  2183. NextToken;
  2184. until CurToken = tkSemicolon
  2185. else if (tok = 'PUBLIC') then
  2186. begin
  2187. NextToken;
  2188. { Should be token Name,
  2189. if not we're in a class and the public section starts }
  2190. If (Uppercase(CurTokenString)<>'NAME') then
  2191. begin
  2192. UngetToken;
  2193. UngetToken;
  2194. Break;
  2195. end
  2196. else
  2197. begin
  2198. NextToken; // Should be export name string.
  2199. ExpectToken(tkSemicolon);
  2200. end;
  2201. end
  2202. else if (tok = 'FORWARD') then
  2203. begin
  2204. if (Parent.Parent is TInterfaceSection) then
  2205. begin
  2206. UngetToken;
  2207. break;
  2208. end;
  2209. if Parent is TPasProcedure then
  2210. TPasProcedure(Parent).AddModifier(pmForward);
  2211. ExpectToken(tkSemicolon);
  2212. end
  2213. else
  2214. begin
  2215. UnGetToken;
  2216. Break;
  2217. end
  2218. end
  2219. else if (CurToken = tkInline) then
  2220. begin
  2221. if Parent is TPasProcedure then
  2222. TPasProcedure(Parent).AddModifier(pmInline);
  2223. ExpectToken(tkSemicolon);
  2224. end
  2225. else if (CurToken = tkSquaredBraceOpen) then
  2226. begin
  2227. repeat
  2228. NextToken
  2229. until CurToken = tkSquaredBraceClose;
  2230. ExpectToken(tkSemicolon);
  2231. end
  2232. else
  2233. begin
  2234. UngetToken;
  2235. break;
  2236. end;
  2237. end;
  2238. if (ProcType = ptOperator) and (Parent is TPasProcedure) then
  2239. begin
  2240. Proc:=TPasProcedure(Parent);
  2241. Proc.Name := Proc.Name + '(';
  2242. for i := 0 to Proc.ProcType.Args.Count - 1 do
  2243. begin
  2244. if i > 0 then
  2245. Proc.Name := Proc.Name + ', ';
  2246. Proc.Name := Proc.Name +
  2247. TPasArgument(Proc.ProcType.Args[i]).ArgType.Name;
  2248. end;
  2249. Proc.Name := Proc.Name + '): ' +
  2250. TPasFunctionType(Proc.ProcType).ResultEl.ResultType.Name;
  2251. end;
  2252. if (Parent is TPasProcedure)
  2253. and (not TPasProcedure(Parent).IsForward)
  2254. and (not TPasProcedure(Parent).IsExternal)
  2255. and ((Parent.Parent is TImplementationSection)
  2256. or (Parent.Parent is TProcedureBody))
  2257. then
  2258. ParseProcedureBody(Parent);
  2259. end;
  2260. // starts after the semicolon
  2261. procedure TPasParser.ParseProcedureBody(Parent: TPasElement);
  2262. var
  2263. Body: TProcedureBody;
  2264. begin
  2265. Body := TProcedureBody(CreateElement(TProcedureBody, '', Parent));
  2266. ParseDeclarations(Body);
  2267. end;
  2268. procedure TPasParser.ParseProperty(Element:TPasElement);
  2269. var
  2270. isArray : Boolean;
  2271. procedure MaybeReadFullyQualifiedIdentifier(Var r : String);
  2272. begin
  2273. while True do
  2274. begin
  2275. NextToken;
  2276. if CurToken = tkDot then
  2277. begin
  2278. ExpectIdentifier;
  2279. R:=R + '.' + CurTokenString;
  2280. end
  2281. else
  2282. break;
  2283. end;
  2284. end;
  2285. function GetAccessorName: String;
  2286. begin
  2287. ExpectIdentifier;
  2288. Result := CurTokenString;
  2289. MaybeReadFullyQualifiedIdentifier(Result);
  2290. if CurToken = tkSquaredBraceOpen then begin
  2291. Result := Result + '[';
  2292. NextToken;
  2293. if CurToken in [tkIdentifier, tkNumber] then begin
  2294. Result := Result + CurTokenString;
  2295. end;
  2296. ExpectToken(tkSquaredBraceClose);
  2297. Result := Result + ']';
  2298. end else
  2299. UngetToken;
  2300. //MaybeReadFullyQualifiedIdentifier(Result);
  2301. //writeln(Result);
  2302. end;
  2303. var
  2304. us : String;
  2305. h : TPasMemberHint;
  2306. begin
  2307. isArray:=False;
  2308. NextToken;
  2309. // if array prop then parse [ arg1:type1;... ]
  2310. if CurToken = tkSquaredBraceOpen then begin
  2311. isArray:=True;
  2312. // !!!: Parse array properties correctly
  2313. ParseArgList(Element, TPasProperty(Element).Args, tkSquaredBraceClose);
  2314. NextToken;
  2315. end;
  2316. if CurToken = tkColon then begin
  2317. // if ":prop_data_type" if supplied then read it
  2318. // read property type
  2319. TPasProperty(Element).VarType := ParseType(Element);
  2320. NextToken;
  2321. end;
  2322. if CurToken <> tkSemicolon then begin
  2323. // if indexed prop then read the index value
  2324. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'INDEX') then begin
  2325. // read 'index' access modifier
  2326. TPasProperty(Element).IndexValue := ParseExpression(Element,ek_PropertyIndex);
  2327. end else
  2328. // not indexed prop will be recheck for another token
  2329. UngetToken;
  2330. NextToken;
  2331. end;
  2332. // if the accessors list is not finished
  2333. if CurToken <> tkSemicolon then begin
  2334. // read 'read' access modifier
  2335. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'READ') then
  2336. TPasProperty(Element).ReadAccessorName := GetAccessorName
  2337. else
  2338. // not read accessor will be recheck for another token
  2339. UngetToken;
  2340. NextToken;
  2341. end;
  2342. // if the accessors list is not finished
  2343. if CurToken <> tkSemicolon then begin
  2344. // read 'write' access modifier
  2345. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'WRITE') then
  2346. TPasProperty(Element).WriteAccessorName := GetAccessorName
  2347. else
  2348. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'IMPLEMENTS') then
  2349. TPasProperty(Element).ImplementsName := GetAccessorName
  2350. else
  2351. // not write accessor will be recheck for another token
  2352. UngetToken;
  2353. NextToken;
  2354. end;
  2355. // if the specifiers list is not finished
  2356. if CurToken <> tkSemicolon then begin
  2357. // read 'stored' access modifier
  2358. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'STORED') then begin
  2359. NextToken;
  2360. if CurToken = tkTrue then
  2361. TPasProperty(Element).StoredAccessorName := 'True'
  2362. else if CurToken = tkFalse then
  2363. TPasProperty(Element).StoredAccessorName := 'False'
  2364. else if CurToken = tkIdentifier then
  2365. TPasProperty(Element).StoredAccessorName := CurTokenString
  2366. else
  2367. ParseExc(SParserSyntaxError);
  2368. end else
  2369. // not stored accessor will be recheck for another token
  2370. UngetToken;
  2371. NextToken;
  2372. end;
  2373. // if the specifiers list is not finished
  2374. if (CurToken <> tkSemicolon) and (CurToken = tkIdentifier) then begin
  2375. us:=UpperCase(CurTokenText);
  2376. if (us = 'DEFAULT') then begin
  2377. if isArray then ParseExc('Array properties cannot have default value');
  2378. // read 'default' value modifier -> ParseExpression(DEFAULT <value>)
  2379. TPasProperty(Element).DefaultValue := ParseExpression(Element);
  2380. NextToken;
  2381. end else if (us = 'NODEFAULT') then begin
  2382. // read 'nodefault' modifier
  2383. TPasProperty(Element).IsNodefault:=true;
  2384. end else
  2385. // not "default <value>" prop will be recheck for another token
  2386. UngetToken;
  2387. NextToken;
  2388. end;
  2389. // after NODEFAULT may be a ";"
  2390. if CurToken = tkSemicolon then begin
  2391. // read semicolon
  2392. NextToken;
  2393. end;
  2394. if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then begin
  2395. if not isArray then ParseExc('The default property must be an array property');
  2396. // what is after DEFAULT token at the end
  2397. NextToken;
  2398. if CurToken = tkSemicolon then begin
  2399. // ";" then DEFAULT=prop
  2400. TPasProperty(Element).IsDefault := True;
  2401. NextToken;
  2402. end
  2403. end;
  2404. while IsCurTokenHint(h) do begin
  2405. Element.Hints:=Element.Hints+[h];
  2406. NextToken;
  2407. // there can be multiple hints, separated by the, i.e.:
  2408. // property Prop: integer read FMyProp write FMyProp; platform; library deprecated;
  2409. if CurToken=tkSemicolon then
  2410. NextToken;
  2411. end;
  2412. // property parsing must finish at the LAST Semicolon of the property
  2413. // since we're parsing "one-step" ahead of the semicolon. we must return one-step
  2414. UngetToken;
  2415. end;
  2416. // Starts after the "begin" token
  2417. procedure TPasParser.ParseProcBeginBlock(Parent: TProcedureBody);
  2418. var
  2419. BeginBlock: TPasImplBeginBlock;
  2420. SubBlock: TPasImplElement;
  2421. begin
  2422. //writeln('TPasParser.ParseProcBeginBlock ');
  2423. BeginBlock := TPasImplBeginBlock(CreateElement(TPasImplBeginBlock, '', Parent));
  2424. Parent.Body := BeginBlock;
  2425. repeat
  2426. NextToken;
  2427. if CurToken=tkend then
  2428. break
  2429. else if CurToken<>tkSemiColon then
  2430. begin
  2431. UngetToken;
  2432. ParseStatement(BeginBlock,SubBlock);
  2433. if SubBlock=nil then
  2434. ExpectToken(tkend);
  2435. end;
  2436. until false;
  2437. ExpectToken(tkSemicolon);
  2438. end;
  2439. // Next token is start of (compound) statement
  2440. // After parsing CurToken is on last token of statement
  2441. procedure TPasParser.ParseStatement(Parent: TPasImplBlock;
  2442. out NewImplElement: TPasImplElement);
  2443. var
  2444. CurBlock: TPasImplBlock;
  2445. {$IFDEF VerbosePasParser}
  2446. function i: string;
  2447. var
  2448. c: TPasElement;
  2449. begin
  2450. Result:='ParseImplCompoundStatement ';
  2451. c:=CurBlock;
  2452. while c<>nil do begin
  2453. Result:=Result+' ';
  2454. c:=c.Parent;
  2455. end;
  2456. end;
  2457. {$ENDIF}
  2458. function CloseBlock: boolean; // true if parent reached
  2459. begin
  2460. CurBlock:=CurBlock.Parent as TPasImplBlock;
  2461. Result:=CurBlock=Parent;
  2462. end;
  2463. function CloseStatement(CloseIfs: boolean): boolean; // true if parent reached
  2464. begin
  2465. if CurBlock=Parent then exit(true);
  2466. while CurBlock.CloseOnSemicolon
  2467. or (CloseIfs and (CurBlock is TPasImplIfElse)) do
  2468. if CloseBlock then exit(true);
  2469. Result:=false;
  2470. end;
  2471. procedure CreateBlock(NewBlock: TPasImplBlock);
  2472. begin
  2473. CurBlock:=NewBlock;
  2474. if NewImplElement=nil then NewImplElement:=CurBlock;
  2475. end;
  2476. var
  2477. Condition: String;
  2478. Command: String;
  2479. StartValue: String;
  2480. VarName: String;
  2481. EndValue: String;
  2482. Expr: String;
  2483. SubBlock: TPasImplElement;
  2484. CmdElem: TPasImplCommand;
  2485. TypeName: String;
  2486. ForDownTo: Boolean;
  2487. begin
  2488. NewImplElement:=nil;
  2489. CurBlock := Parent;
  2490. while True do
  2491. begin
  2492. NextToken;
  2493. //WriteLn(i,'Token=',CurTokenText);
  2494. case CurToken of
  2495. tkbegin:
  2496. CreateBlock(CurBlock.AddBeginBlock);
  2497. tkrepeat:
  2498. CreateBlock(CurBlock.AddRepeatUntil);
  2499. tkIf:
  2500. begin
  2501. Condition:=ParseExpression(Parent);
  2502. //WriteLn(i,'IF Condition="',Condition,'" Token=',CurTokenText);
  2503. CreateBlock(CurBlock.AddIfElse(Condition));
  2504. ExpectToken(tkthen);
  2505. end;
  2506. tkelse:
  2507. if (CurBlock is TPasImplIfElse) then
  2508. begin
  2509. if TPasImplIfElse(CurBlock).IfBranch=nil then
  2510. begin
  2511. // empty then => add dummy command
  2512. CurBlock.AddCommand('');
  2513. end;
  2514. end else if (CurBlock is TPasImplTryExcept) then
  2515. begin
  2516. CloseBlock;
  2517. CurBlock:=TPasImplTry(CurBlock).AddExceptElse;
  2518. end else
  2519. ParseExc(SParserSyntaxError);
  2520. tkwhile:
  2521. begin
  2522. // while Condition do
  2523. Condition:=ParseExpression(Parent);
  2524. //WriteLn(i,'WHILE Condition="',Condition,'" Token=',CurTokenText);
  2525. CreateBlock(CurBlock.AddWhileDo(Condition));
  2526. ExpectToken(tkdo);
  2527. end;
  2528. tkfor:
  2529. begin
  2530. // for VarName := StartValue to EndValue do
  2531. ExpectIdentifier;
  2532. VarName:=CurTokenString;
  2533. ExpectToken(tkAssign);
  2534. StartValue:=ParseExpression(Parent);
  2535. //writeln(i,'FOR Start=',StartValue);
  2536. NextToken;
  2537. if CurToken=tkTo then
  2538. ForDownTo:=false
  2539. else if CurToken=tkdownto then
  2540. ForDownTo:=true
  2541. else
  2542. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkTo]]));
  2543. EndValue:=ParseExpression(Parent);
  2544. CreateBlock(CurBlock.AddForLoop(VarName,StartValue,EndValue,ForDownTo));
  2545. //WriteLn(i,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);
  2546. ExpectToken(tkdo);
  2547. end;
  2548. tkwith:
  2549. begin
  2550. // with Expr do
  2551. // with Expr, Expr do
  2552. Expr:=ParseExpression(Parent);
  2553. //writeln(i,'WITH Expr="',Expr,'" Token=',CurTokenText);
  2554. CreateBlock(CurBlock.AddWithDo(Expr));
  2555. repeat
  2556. NextToken;
  2557. if CurToken=tkdo then break;
  2558. if CurToken<>tkComma then
  2559. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkdo]]));
  2560. Expr:=ParseExpression(Parent);
  2561. //writeln(i,'WITH ...,Expr="',Expr,'" Token=',CurTokenText);
  2562. TPasImplWithDo(CurBlock).AddExpression(Expr);
  2563. until false;
  2564. end;
  2565. tkcase:
  2566. begin
  2567. Expr:=ParseExpression(Parent);
  2568. //writeln(i,'CASE OF Expr="',Expr,'" Token=',CurTokenText);
  2569. ExpectToken(tkof);
  2570. CreateBlock(CurBlock.AddCaseOf(Expr));
  2571. repeat
  2572. NextToken;
  2573. //writeln(i,'CASE OF Token=',CurTokenText);
  2574. case CurToken of
  2575. tkend:
  2576. break; // end without else
  2577. tkelse:
  2578. begin
  2579. // create case-else block
  2580. CurBlock:=TPasImplCaseOf(CurBlock).AddElse;
  2581. break;
  2582. end
  2583. else
  2584. UngetToken;
  2585. // read case values
  2586. repeat
  2587. Expr:=ParseExpression(Parent);
  2588. //writeln(i,'CASE value="',Expr,'" Token=',CurTokenText);
  2589. if CurBlock is TPasImplCaseStatement then
  2590. TPasImplCaseStatement(CurBlock).Expressions.Add(Expr)
  2591. else
  2592. CurBlock:=TPasImplCaseOf(CurBlock).AddCase(Expr);
  2593. NextToken;
  2594. if CurToken=tkDotDot then
  2595. begin
  2596. Expr:=Expr+'..'+ParseExpression(Parent);
  2597. NextToken;
  2598. end;
  2599. //writeln(i,'CASE after value Token=',CurTokenText);
  2600. if CurToken=tkColon then break;
  2601. if CurToken<>tkComma then
  2602. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkComma]]));
  2603. until false;
  2604. // read statement
  2605. ParseStatement(CurBlock,SubBlock);
  2606. CloseBlock;
  2607. if CurToken<>tkSemicolon then
  2608. begin
  2609. NextToken;
  2610. if not (CurToken in [tkSemicolon,tkelse,tkend]) then
  2611. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkSemicolon]]));
  2612. if CurToken<>tkSemicolon then
  2613. UngetToken;
  2614. end;
  2615. end;
  2616. until false;
  2617. if CurToken=tkend then
  2618. begin
  2619. if CloseBlock then break;
  2620. if CloseStatement(false) then break;
  2621. end;
  2622. end;
  2623. tktry:
  2624. CreateBlock(CurBlock.AddTry);
  2625. tkfinally:
  2626. begin
  2627. if CloseStatement(true) then
  2628. begin
  2629. UngetToken;
  2630. break;
  2631. end;
  2632. if CurBlock is TPasImplTry then
  2633. begin
  2634. CurBlock:=TPasImplTry(CurBlock).AddFinally;
  2635. end else
  2636. ParseExc(SParserSyntaxError);
  2637. end;
  2638. tkexcept:
  2639. begin
  2640. if CloseStatement(true) then
  2641. begin
  2642. UngetToken;
  2643. break;
  2644. end;
  2645. if CurBlock is TPasImplTry then
  2646. begin
  2647. //writeln(i,'EXCEPT');
  2648. CurBlock:=TPasImplTry(CurBlock).AddExcept;
  2649. end else
  2650. ParseExc(SParserSyntaxError);
  2651. end;
  2652. tkon:
  2653. begin
  2654. // in try except:
  2655. // on E: Exception do
  2656. // on Exception do
  2657. if CurBlock is TPasImplTryExcept then
  2658. begin
  2659. VarName:='';
  2660. TypeName:=ParseExpression(Parent);
  2661. //writeln(i,'ON t=',TypeName,' Token=',CurTokenText);
  2662. NextToken;
  2663. if CurToken=tkColon then
  2664. begin
  2665. VarName:=TypeName;
  2666. TypeName:=ParseExpression(Parent);
  2667. //writeln(i,'ON v=',VarName,' t=',TypeName,' Token=',CurTokenText);
  2668. end else
  2669. UngetToken;
  2670. CurBlock:=TPasImplTryExcept(CurBlock).AddExceptOn(VarName,TypeName);
  2671. ExpectToken(tkDo);
  2672. end else
  2673. ParseExc(SParserSyntaxError);
  2674. end;
  2675. tkraise:
  2676. CreateBlock(CurBlock.AddRaise);
  2677. tkend:
  2678. begin
  2679. if CloseStatement(true) then
  2680. begin
  2681. UngetToken;
  2682. break;
  2683. end;
  2684. if CurBlock is TPasImplBeginBlock then
  2685. begin
  2686. if CloseBlock then break; // close end
  2687. if CloseStatement(false) then break;
  2688. end else if CurBlock is TPasImplCaseElse then
  2689. begin
  2690. if CloseBlock then break; // close else
  2691. if CloseBlock then break; // close caseof
  2692. if CloseStatement(false) then break;
  2693. end else if CurBlock is TPasImplTryHandler then
  2694. begin
  2695. if CloseBlock then break; // close finally/except
  2696. if CloseBlock then break; // close try
  2697. if CloseStatement(false) then break;
  2698. end else
  2699. ParseExc(SParserSyntaxError);
  2700. end;
  2701. tkSemiColon:
  2702. if CloseStatement(true) then break;
  2703. tkuntil:
  2704. begin
  2705. if CloseStatement(true) then
  2706. begin
  2707. UngetToken;
  2708. break;
  2709. end;
  2710. if CurBlock is TPasImplRepeatUntil then
  2711. begin
  2712. Condition:=ParseExpression(Parent);
  2713. TPasImplRepeatUntil(CurBlock).Condition:=Condition;
  2714. //WriteLn(i,'UNTIL Condition="',Condition,'" Token=',CurTokenString);
  2715. if CloseBlock then break;
  2716. end else
  2717. ParseExc(SParserSyntaxError);
  2718. end;
  2719. else
  2720. UngetToken;
  2721. Command:='';
  2722. NextToken;
  2723. // testing for label mark
  2724. if CurToken=tkIdentifier then
  2725. begin
  2726. Command:=CurTokenText;
  2727. NextToken;
  2728. // testing for the goto mark
  2729. if CurToken=tkColon then
  2730. begin
  2731. CurBlock.AddLabelMark(Command);
  2732. end
  2733. else
  2734. begin
  2735. Command:='';
  2736. UngetToken;
  2737. UngetToken;
  2738. end;
  2739. end else
  2740. UngetToken;
  2741. if Command='' then
  2742. begin
  2743. // parsing the assignment statement or call expression
  2744. Command:=ParseCommand;
  2745. //WriteLn(i,'COMMAND="',Command,'" Token=',CurTokenString);
  2746. if Command='' then
  2747. ParseExc(SParserSyntaxError);
  2748. CmdElem:=CurBlock.AddCommand(Command);
  2749. if NewImplElement=nil then NewImplElement:=CmdElem;
  2750. if CloseStatement(false) then break;
  2751. end;
  2752. end;
  2753. end;
  2754. end;
  2755. procedure TPasParser.ParseLabels(AParent: TPasElement);
  2756. var
  2757. Labels: TPasLabels;
  2758. begin
  2759. Labels:=TPasLabels(CreateElement(TPasLabels, '', AParent));
  2760. repeat
  2761. Labels.Labels.Add(ExpectIdentifier);
  2762. NextToken;
  2763. if not (CurToken in [tkSemicolon, tkComma]) then
  2764. ParseExc(Format(SParserExpectTokenError, [TokenInfos[tkSemicolon]]));
  2765. until CurToken=tkSemicolon;
  2766. end;
  2767. // Starts after the "procedure" or "function" token
  2768. function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
  2769. ProcType: TProcType): TPasProcedure;
  2770. function ExpectProcName: string;
  2771. begin
  2772. Result:=ExpectIdentifier;
  2773. //writeln('ExpectProcName ',Parent.Classname);
  2774. if Parent is TImplementationSection then
  2775. begin
  2776. NextToken;
  2777. if CurToken=tkDot then
  2778. begin
  2779. Result:=Result+'.'+ExpectIdentifier;
  2780. end else
  2781. UngetToken;
  2782. end;
  2783. end;
  2784. var
  2785. Name: String;
  2786. begin
  2787. case ProcType of
  2788. ptFunction:
  2789. begin
  2790. Name := ExpectProcName;
  2791. Result := TPasFunction(CreateElement(TPasFunction, Name, Parent));
  2792. Result.ProcType := Engine.CreateFunctionType('', 'Result', Result, True,
  2793. Scanner.CurFilename, Scanner.CurRow);
  2794. end;
  2795. ptClassFunction:
  2796. begin
  2797. Name := ExpectProcName;
  2798. Result := TPasClassFunction(CreateElement(TPasClassFunction, Name, Parent));
  2799. Result.ProcType := Engine.CreateFunctionType('', 'Result', Result, True,
  2800. Scanner.CurFilename, Scanner.CurRow);
  2801. end;
  2802. ptProcedure:
  2803. begin
  2804. Name := ExpectProcName;
  2805. Result := TPasProcedure(CreateElement(TPasProcedure, Name, Parent));
  2806. Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  2807. Result));
  2808. end;
  2809. ptClassProcedure:
  2810. begin
  2811. Name := ExpectProcName;
  2812. Result := TPasClassProcedure(CreateElement(TPasClassProcedure, Name, Parent));
  2813. Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  2814. Result));
  2815. end;
  2816. ptOperator:
  2817. begin
  2818. NextToken;
  2819. Name := 'operator ' + TokenInfos[CurToken];
  2820. Result := TPasOperator(CreateElement(TPasOperator, Name, Parent));
  2821. Result.ProcType := Engine.CreateFunctionType('', '__INVALID__', Result,
  2822. True, Scanner.CurFilename, Scanner.CurRow);
  2823. end;
  2824. ptConstructor:
  2825. begin
  2826. Name := ExpectProcName;
  2827. Result := TPasConstructor(CreateElement(TPasConstructor, Name, Parent));
  2828. Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  2829. Result));
  2830. end;
  2831. ptDestructor:
  2832. begin
  2833. Name := ExpectProcName;
  2834. Result := TPasDestructor(CreateElement(TPasDestructor, Name, Parent));
  2835. Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  2836. Result));
  2837. end;
  2838. end;
  2839. //writeln('TPasParser.ParseProcedureOrFunctionDecl Name="',Name,'" Token=',CurTokenText);
  2840. ParseProcedureOrFunctionHeader(Result, Result.ProcType, ProcType, False);
  2841. end;
  2842. // Starts after the "record" token
  2843. procedure TPasParser.ParseRecordDecl(Parent: TPasRecordType; IsNested: Boolean);
  2844. var
  2845. VariantName: String;
  2846. Variant: TPasVariant;
  2847. begin
  2848. while True do
  2849. begin
  2850. if IsNested then
  2851. begin
  2852. if CurToken = tkBraceClose then
  2853. break;
  2854. NextToken;
  2855. if CurToken = tkBraceClose then
  2856. break;
  2857. end else
  2858. begin
  2859. if CurToken = tkEnd then
  2860. break;
  2861. NextToken;
  2862. if CurToken = tkEnd then
  2863. break;
  2864. end;
  2865. if CurToken = tkCase then
  2866. begin
  2867. ExpectToken(tkIdentifier);
  2868. VariantName := CurTokenString;
  2869. NextToken;
  2870. if CurToken = tkColon then
  2871. Parent.VariantName := VariantName
  2872. else
  2873. begin
  2874. UngetToken;
  2875. UngetToken;
  2876. end;
  2877. Parent.VariantType := ParseType(Parent);
  2878. Parent.Variants := TList.Create;
  2879. ExpectToken(tkOf);
  2880. while True do
  2881. begin
  2882. Variant := TPasVariant(CreateElement(TPasVariant, '', Parent));
  2883. Parent.Variants.Add(Variant);
  2884. Variant.Values := TStringList.Create;
  2885. while True do
  2886. begin
  2887. Variant.Values.Add(ParseExpression(Parent));
  2888. NextToken;
  2889. if CurToken = tkColon then
  2890. break
  2891. else if CurToken <> tkComma then
  2892. ParseExc(SParserExpectedCommaColon);
  2893. end;
  2894. ExpectToken(tkBraceOpen);
  2895. Variant.Members := TPasRecordType(CreateElement(TPasRecordType, '',
  2896. Variant));
  2897. try
  2898. ParseRecordDecl(Variant.Members, True);
  2899. except
  2900. Variant.Members.Free;
  2901. raise;
  2902. end;
  2903. NextToken;
  2904. if CurToken = tkSemicolon then
  2905. NextToken;
  2906. if (CurToken = tkEnd) or (CurToken = tkBraceClose) then
  2907. break
  2908. else
  2909. UngetToken;
  2910. end
  2911. end else
  2912. ParseInlineVarDecl(Parent, Parent.Members, visDefault, IsNested);
  2913. end;
  2914. end;
  2915. // Starts after the "class" token
  2916. function TPasParser.ParseClassDecl(Parent: TPasElement;
  2917. const AClassName: String; AObjKind: TPasObjKind): TPasType;
  2918. var
  2919. CurVisibility: TPasMemberVisibility;
  2920. procedure ProcessMethod(const MethodTypeName: String; HasReturnValue: Boolean);
  2921. var
  2922. Owner: TPasElement;
  2923. Proc: TPasProcedure;
  2924. s: String;
  2925. pt: TProcType;
  2926. begin
  2927. ExpectIdentifier;
  2928. Owner := CheckIfOverloaded(TPasClassType(Result), CurTokenString);
  2929. if HasReturnValue then
  2930. begin
  2931. Proc := TPasFunction(CreateElement(TPasFunction, CurTokenString, Owner,
  2932. CurVisibility));
  2933. Proc.ProcType := Engine.CreateFunctionType('', 'Result', Proc, True,
  2934. Scanner.CurFilename, Scanner.CurRow);
  2935. end else
  2936. begin
  2937. // !!!: The following is more than ugly
  2938. if MethodTypeName = 'constructor' then
  2939. Proc := TPasConstructor(CreateElement(TPasConstructor, CurTokenString,
  2940. Owner, CurVisibility))
  2941. else if MethodTypeName = 'destructor' then
  2942. Proc := TPasDestructor(CreateElement(TPasDestructor, CurTokenString,
  2943. Owner, CurVisibility))
  2944. else
  2945. Proc := TPasProcedure(CreateElement(TPasProcedure, CurTokenString,
  2946. Owner, CurVisibility));
  2947. Proc.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
  2948. Proc, CurVisibility));
  2949. end;
  2950. if Owner.ClassType = TPasOverloadedProc then
  2951. TPasOverloadedProc(Owner).Overloads.Add(Proc)
  2952. else
  2953. TPasClassType(Result).Members.Add(Proc);
  2954. if HasReturnValue then
  2955. pt := ptFunction
  2956. else
  2957. pt := ptProcedure;
  2958. ParseProcedureOrFunctionHeader(Proc, Proc.ProcType, pt, False);
  2959. while True do
  2960. begin
  2961. NextToken;
  2962. if CurToken = tkIdentifier then
  2963. begin
  2964. s := UpperCase(CurTokenString);
  2965. if s = 'VIRTUAL' then
  2966. Proc.AddModifier(pmVirtual)
  2967. else if s = 'DYNAMIC' then
  2968. Proc.AddModifier(pmDynamic)
  2969. else if s = 'ABSTRACT' then
  2970. Proc.AddModifier(pmAbstract)
  2971. else if s = 'OVERRIDE' then
  2972. Proc.AddModifier(pmOverride)
  2973. else if s = 'REINTRODUCE' then
  2974. Proc.AddModifier(pmReintroduce)
  2975. else if s = 'OVERLOAD' then
  2976. Proc.AddModifier(pmOverload)
  2977. else if s = 'STATIC' then
  2978. Proc.AddModifier(pmStatic)
  2979. else if s = 'MESSAGE' then begin
  2980. Proc.AddModifier(pmMessage);
  2981. repeat
  2982. NextToken;
  2983. If CurToken<>tkSemicolon then
  2984. begin
  2985. Proc.MessageName:=CurtokenString;
  2986. If (CurToken=tkString) then
  2987. Proc.Messagetype:=pmtString;
  2988. end;
  2989. until CurToken = tkSemicolon;
  2990. UngetToken;
  2991. end
  2992. else if s = 'CDECL' then
  2993. Proc.CallingConvention:=ccCDecl
  2994. else if s = 'PASCAL' then
  2995. Proc.CallingConvention:=ccPascal
  2996. else if s = 'STDCALL' then
  2997. Proc.CallingConvention:=ccStdCall
  2998. else if s = 'OLDFPCCALL' then
  2999. Proc.CallingConvention:=ccOldFPCCall
  3000. else if s = 'EXTDECL' then
  3001. Proc.AddModifier(pmExtdecl)
  3002. else if s = 'DEPRECATED' then
  3003. Proc.Hints:=Proc.Hints+[hDeprecated]
  3004. else if s = 'EXPORT' then
  3005. Proc.AddModifier(pmExported)
  3006. else
  3007. begin
  3008. UngetToken;
  3009. break;
  3010. end;
  3011. ExpectToken(tkSemicolon);
  3012. end else
  3013. begin
  3014. UngetToken;
  3015. break;
  3016. end;
  3017. end;
  3018. end;
  3019. var
  3020. s, SourceFilename: String;
  3021. i, SourceLinenumber: Integer;
  3022. VarList: TList;
  3023. Element: TPasElement;
  3024. isStrict: Boolean;
  3025. begin
  3026. isStrict:=False;
  3027. // Save current parsing position to get it correct in all cases
  3028. SourceFilename := Scanner.CurFilename;
  3029. SourceLinenumber := Scanner.CurRow;
  3030. NextToken;
  3031. if (AObjKind = okClass) and (CurToken = tkOf) then
  3032. begin
  3033. Result := TPasClassOfType(Engine.CreateElement(TPasClassOfType, AClassName,
  3034. Parent, SourceFilename, SourceLinenumber));
  3035. ExpectIdentifier;
  3036. UngetToken; // Only names are allowed as following type
  3037. TPasClassOfType(Result).DestType := ParseType(Result);
  3038. ExpectToken(tkSemicolon);
  3039. exit;
  3040. end;
  3041. Result := TPasClassType(Engine.CreateElement(TPasClassType, AClassName,
  3042. Parent, SourceFilename, SourceLinenumber));
  3043. try
  3044. TPasClassType(Result).ObjKind := AObjKind;
  3045. // nettism/new delphi features
  3046. if (CurToken = tkIdentifier) and (AObjKind = okClass) then begin
  3047. s := LowerCase(CurTokenString);
  3048. if (s = 'sealed') or (s = 'abstract') then begin
  3049. TPasClassType(Result).Modifiers.Add(s);
  3050. NextToken;
  3051. end;
  3052. end;
  3053. // Parse ancestor list
  3054. if CurToken = tkBraceOpen then
  3055. begin
  3056. TPasClassType(Result).AncestorType := ParseType(nil);
  3057. {$ifdef Inheritancewarnings}
  3058. s:=TPasClassType(Result).AncestorType.pathname;
  3059. if pos('#',s)=0 then
  3060. begin
  3061. writeln('Note: ', TPasClassType(Result).pathname,'''s ancestor ',s, ' at ',sourcefilename,':',sourcelinenumber,' cannot be resolved fully');
  3062. end;
  3063. {$endif}
  3064. while True do
  3065. begin
  3066. NextToken;
  3067. if CurToken = tkBraceClose then
  3068. break;
  3069. UngetToken;
  3070. ExpectToken(tkComma);
  3071. //ExpectIdentifier;
  3072. Element:=ParseType(Nil); // search interface.
  3073. if assigned(element) then
  3074. TPasClassType(Result).Interfaces.add(element);
  3075. // !!!: Store interface name
  3076. end;
  3077. NextToken;
  3078. end
  3079. else
  3080. TPasClassType(Result).isForward:=CurToken=tkSemicolon;
  3081. if CurToken <> tkSemicolon then
  3082. begin
  3083. if ( AObjKind = okInterface ) and ( CurToken = tkSquaredBraceOpen ) then
  3084. begin
  3085. ExpectToken(tkString);
  3086. TPasClassType(Result).InterfaceGUID := CurTokenString;
  3087. ExpectToken(tkSquaredBraceClose);
  3088. end;
  3089. CurVisibility := visDefault;
  3090. while CurToken <> tkEnd do
  3091. begin
  3092. case CurToken of
  3093. tkIdentifier:
  3094. begin
  3095. s := LowerCase(CurTokenString);
  3096. if s = 'strict' then
  3097. begin
  3098. isStrict:=True;
  3099. NextToken;
  3100. s := LowerCase(CurTokenString);
  3101. end
  3102. else
  3103. isStrict:=False;
  3104. if s = 'private' then
  3105. CurVisibility := visPrivate
  3106. else if s = 'protected' then
  3107. CurVisibility := visProtected
  3108. else if s = 'public' then
  3109. CurVisibility := visPublic
  3110. else if s = 'published' then
  3111. CurVisibility := visPublished
  3112. else if s = 'automated' then
  3113. CurVisibility := visAutomated
  3114. else
  3115. begin
  3116. VarList := TList.Create;
  3117. try
  3118. ParseInlineVarDecl(Result, VarList, CurVisibility, False);
  3119. for i := 0 to VarList.Count - 1 do
  3120. begin
  3121. Element := TPasElement(VarList[i]);
  3122. Element.Visibility := CurVisibility;
  3123. TPasClassType(Result).Members.Add(Element);
  3124. end;
  3125. finally
  3126. VarList.Free;
  3127. end;
  3128. end;
  3129. if isStrict then
  3130. begin
  3131. case CurVisibility of
  3132. visPrivate : CurVisibility:=visStrictPrivate;
  3133. visProtected : CurVisibility:=visStrictProtected;
  3134. else
  3135. ParseExc('strange strict visiblity');
  3136. end;
  3137. end;
  3138. end;
  3139. tkProcedure:
  3140. ProcessMethod('procedure', False);
  3141. tkFunction:
  3142. ProcessMethod('function', True);
  3143. tkConstructor:
  3144. ProcessMethod('constructor', False);
  3145. tkDestructor:
  3146. ProcessMethod('destructor', False);
  3147. tkProperty:
  3148. begin
  3149. ExpectIdentifier;
  3150. Element := CreateElement(TPasProperty, CurTokenString, Result, CurVisibility);
  3151. TPasClassType(Result).Members.Add(Element);
  3152. ParseProperty(Element);
  3153. end;
  3154. tkVar: // vars (nettism/new delphi features)
  3155. if AObjKind<>okClass then ExpectToken(tkSemicolon);
  3156. //todo: class vars
  3157. end; // end case
  3158. NextToken;
  3159. end;
  3160. // Eat semicolon after class...end
  3161. CheckHint(result,true);
  3162. // ExpectToken(tkSemicolon);
  3163. end;
  3164. except
  3165. Result.Free;
  3166. raise;
  3167. end;
  3168. end;
  3169. function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
  3170. AParent: TPasElement): TPasElement;
  3171. begin
  3172. Result := Engine.CreateElement(AClass, AName, AParent,
  3173. Scanner.CurFilename, Scanner.CurRow);
  3174. end;
  3175. function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
  3176. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  3177. begin
  3178. Result := Engine.CreateElement(AClass, AName, AParent, AVisibility,
  3179. Scanner.CurFilename, Scanner.CurRow);
  3180. end;
  3181. function ParseSource(AEngine: TPasTreeContainer;
  3182. const FPCCommandLine, OSTarget, CPUTarget: String): TPasModule;
  3183. var
  3184. FileResolver: TFileResolver;
  3185. Parser: TPasParser;
  3186. Start, CurPos: PChar;
  3187. Filename: String;
  3188. Scanner: TPascalScanner;
  3189. procedure ProcessCmdLinePart;
  3190. var
  3191. l: Integer;
  3192. s: String;
  3193. begin
  3194. l := CurPos - Start;
  3195. SetLength(s, l);
  3196. if l > 0 then
  3197. Move(Start^, s[1], l)
  3198. else
  3199. exit;
  3200. if s[1] = '-' then
  3201. begin
  3202. case s[2] of
  3203. 'd': // -d define
  3204. Scanner.Defines.Append(UpperCase(Copy(s, 3, Length(s))));
  3205. 'F': // -F
  3206. if s[3] = 'i' then // -Fi include path
  3207. FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
  3208. 'I': // -I include path
  3209. FileResolver.AddIncludePath(Copy(s, 3, Length(s)));
  3210. 'S': // -S mode
  3211. if s[3]='d' then
  3212. begin // -Sd mode delphi
  3213. include(Scanner.Options,po_delphi);
  3214. include(Parser.Options,po_delphi);
  3215. end;
  3216. end;
  3217. end else
  3218. if Filename <> '' then
  3219. raise Exception.Create(SErrMultipleSourceFiles)
  3220. else
  3221. Filename := s;
  3222. end;
  3223. var
  3224. s: String;
  3225. begin
  3226. Result := nil;
  3227. FileResolver := nil;
  3228. Scanner := nil;
  3229. Parser := nil;
  3230. try
  3231. FileResolver := TFileResolver.Create;
  3232. Scanner := TPascalScanner.Create(FileResolver);
  3233. Scanner.Defines.Append('FPK');
  3234. Scanner.Defines.Append('FPC');
  3235. // TargetOS
  3236. s := UpperCase(OSTarget);
  3237. Scanner.Defines.Append(s);
  3238. if s = 'LINUX' then
  3239. Scanner.Defines.Append('UNIX')
  3240. else if s = 'FREEBSD' then
  3241. begin
  3242. Scanner.Defines.Append('BSD');
  3243. Scanner.Defines.Append('UNIX');
  3244. end else if s = 'NETBSD' then
  3245. begin
  3246. Scanner.Defines.Append('BSD');
  3247. Scanner.Defines.Append('UNIX');
  3248. end else if s = 'SUNOS' then
  3249. begin
  3250. Scanner.Defines.Append('SOLARIS');
  3251. Scanner.Defines.Append('UNIX');
  3252. end else if s = 'GO32V2' then
  3253. Scanner.Defines.Append('DPMI')
  3254. else if s = 'BEOS' then
  3255. Scanner.Defines.Append('UNIX')
  3256. else if s = 'QNX' then
  3257. Scanner.Defines.Append('UNIX');
  3258. // TargetCPU
  3259. s := UpperCase(CPUTarget);
  3260. Scanner.Defines.Append('CPU'+s);
  3261. if (s='x86_64') then
  3262. Scanner.Defines.Append('CPU64')
  3263. else
  3264. Scanner.Defines.Append('CPU32');
  3265. Parser := TPasParser.Create(Scanner, FileResolver, AEngine);
  3266. Filename := '';
  3267. if FPCCommandLine<>'' then
  3268. begin
  3269. Start := @FPCCommandLine[1];
  3270. CurPos := Start;
  3271. while CurPos[0] <> #0 do
  3272. begin
  3273. if CurPos[0] = ' ' then
  3274. begin
  3275. ProcessCmdLinePart;
  3276. Start := CurPos + 1;
  3277. end;
  3278. Inc(CurPos);
  3279. end;
  3280. ProcessCmdLinePart;
  3281. end;
  3282. if Filename = '' then
  3283. raise Exception.Create(SErrNoSourceGiven);
  3284. Scanner.OpenFile(Filename);
  3285. Parser.ParseMain(Result);
  3286. finally
  3287. Parser.Free;
  3288. Scanner.Free;
  3289. FileResolver.Free;
  3290. end;
  3291. end;
  3292. procedure DoInit;
  3293. var
  3294. c: Char;
  3295. begin
  3296. for c:=low(char) to high(char) do
  3297. begin
  3298. IsIdentStart[c]:=c in ['a'..'z','A'..'Z','_'];
  3299. end;
  3300. end;
  3301. initialization
  3302. DoInit;
  3303. end.