123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544 |
- {
- This file is part of the Free Component Library
- Pascal source parser
- Copyright (c) 2000-2005 by
- Areca Systems GmbH / Sebastian Guenther, [email protected]
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}
- {$h+}
- unit PParser;
- interface
- uses SysUtils, Classes, PasTree, PScanner;
- // message numbers
- const
- nErrNoSourceGiven = 2001;
- nErrMultipleSourceFiles = 2002;
- nParserError = 2003;
- nParserErrorAtToken = 2004;
- nParserUngetTokenError = 2005;
- nParserExpectTokenError = 2006;
- nParserForwardNotInterface = 2007;
- nParserExpectVisibility = 2008;
- nParserStrangeVisibility = 2009;
- nParserExpectToken2Error = 2010;
- nParserExpectedCommaRBracket = 2011;
- nParserExpectedCommaSemicolon = 2012;
- nParserExpectedAssignIn = 2013;
- nParserExpectedCommaColon = 2014;
- nErrUnknownOperatorType = 2015;
- nParserOnlyOneArgumentCanHaveDefault = 2016;
- nParserExpectedLBracketColon = 2017;
- nParserExpectedSemiColonEnd = 2018;
- nParserExpectedConstVarID = 2019;
- nParserExpectedNested = 2020;
- nParserExpectedColonID = 2021;
- nParserSyntaxError = 2022;
- nParserTypeSyntaxError = 2023;
- nParserArrayTypeSyntaxError = 2024;
- nParserExpectedIdentifier = 2026;
- nParserNotAProcToken = 2026;
- nRangeExpressionExpected = 2027;
- nParserExpectCase = 2028;
- nParserHelperNotAllowed = 2029;
- nLogStartImplementation = 2030;
- nLogStartInterface = 2031;
- nParserNoConstructorAllowed = 2032;
- nParserNoFieldsAllowed = 2033;
- nParserInvalidRecordVisibility = 2034;
- nErrRecordConstantsNotAllowed = 2035;
- nErrRecordMethodsNotAllowed = 2036;
- nErrRecordPropertiesNotAllowed = 2037;
- nErrRecordVisibilityNotAllowed = 2038;
- nParserTypeNotAllowedHere = 2039;
- nParserNotAnOperand = 2040;
- nParserArrayPropertiesCannotHaveDefaultValue = 2041;
- nParserDefaultPropertyMustBeArray = 2042;
- nParserUnknownProcedureType = 2043;
- nParserGenericArray1Element = 2044;
- nParserGenericClassOrArray = 2045;
- nParserDuplicateIdentifier = 2046;
- nParserDefaultParameterRequiredFor = 2047;
- nParserOnlyOneVariableCanBeInitialized = 2048;
- nParserExpectedTypeButGot = 2049;
- nParserPropertyArgumentsCanNotHaveDefaultValues = 2050;
- nParserExpectedExternalClassName = 2051;
- // resourcestring patterns of messages
- resourcestring
- SErrNoSourceGiven = 'No source file specified';
- SErrMultipleSourceFiles = 'Please specify only one source file';
- SParserError = 'Error';
- SParserErrorAtToken = '%s at token "%s" in file %s at line %d column %d';
- SParserUngetTokenError = 'Internal error: Cannot unget more tokens, history buffer is full';
- SParserExpectTokenError = 'Expected "%s"';
- SParserForwardNotInterface = 'The use of a FORWARD procedure modifier is not allowed in the interface';
- SParserExpectVisibility = 'Expected visibility specifier';
- SParserStrangeVisibility = 'Strange strict visibility encountered : "%s"';
- SParserExpectToken2Error = 'Expected "%s" or "%s"';
- SParserExpectedCommaRBracket = 'Expected "," or ")"';
- SParserExpectedCommaSemicolon = 'Expected "," or ";"';
- SParserExpectedAssignIn = 'Expected := or in';
- SParserExpectedCommaColon = 'Expected "," or ":"';
- SErrUnknownOperatorType = 'Unknown operator type: %s';
- SParserOnlyOneArgumentCanHaveDefault = 'A default value can only be assigned to 1 parameter';
- SParserExpectedLBracketColon = 'Expected "(" or ":"';
- SParserExpectedSemiColonEnd = 'Expected ";" or "End"';
- SParserExpectedConstVarID = 'Expected "const", "var" or identifier';
- SParserExpectedNested = 'Expected nested keyword';
- SParserExpectedColonID = 'Expected ":" or identifier';
- SParserSyntaxError = 'Syntax error';
- SParserTypeSyntaxError = 'Syntax error in type';
- SParserArrayTypeSyntaxError = 'Syntax error in array type';
- SParserExpectedIdentifier = 'Identifier expected';
- SParserNotAProcToken = 'Not a procedure or function token';
- SRangeExpressionExpected = 'Range expression expected';
- SParserExpectCase = 'Case label expression expected';
- SParserHelperNotAllowed = 'Helper objects not allowed for "%s"';
- SLogStartImplementation = 'Start parsing implementation section.';
- SLogStartInterface = 'Start parsing interface section';
- SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Record helpers';
- SParserNoFieldsAllowed = 'Fields are not allowed in Interfaces';
- SParserInvalidRecordVisibility = 'Records can only have public and (strict) private as visibility specifiers';
- SErrRecordConstantsNotAllowed = 'Record constants not allowed at this location.';
- SErrRecordMethodsNotAllowed = 'Record methods not allowed at this location.';
- SErrRecordPropertiesNotAllowed = 'Record properties not allowed at this location.';
- SErrRecordVisibilityNotAllowed = 'Record visibilities not allowed at this location.';
- SParserTypeNotAllowedHere = 'Type "%s" not allowed here';
- SParserNotAnOperand = 'Not an operand: (%d : %s)';
- SParserArrayPropertiesCannotHaveDefaultValue = 'Array properties cannot have default value';
- SParserDefaultPropertyMustBeArray = 'The default property must be an array property';
- SParserUnknownProcedureType = 'Unknown procedure type "%d"';
- SParserGenericArray1Element = 'Generic arrays can have only 1 template element';
- SParserGenericClassOrArray = 'Generic can only be used with classes or arrays';
- SParserDuplicateIdentifier = 'Duplicate identifier "%s"';
- SParserDefaultParameterRequiredFor = 'Default parameter required for "%s"';
- SParserOnlyOneVariableCanBeInitialized = 'Only one variable can be initialized';
- SParserExpectedTypeButGot = 'Expected type, but got %s';
- SParserPropertyArgumentsCanNotHaveDefaultValues = 'Property arguments can not have default values';
- SParserExpectedExternalClassName = 'Expected external class name';
- type
- TPasScopeType = (
- stModule, // e.g. unit, program, library
- stUsesList,
- stTypeSection,
- stTypeDef, // e.g. a TPasType
- stConstDef, // e.g. a TPasConst
- stProcedure, // also method, procedure, constructor, destructor, ...
- stProcedureHeader,
- stExceptOnExpr,
- stExceptOnStatement,
- stDeclaration, // e.g. a TPasProperty, TPasVariable, TPasArgument
- stAncestors // the list of ancestors and interfaces of a class
- );
- TPasScopeTypes = set of TPasScopeType;
- TPasParserLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
- TPParserLogEvent = (pleInterface,pleImplementation);
- TPParserLogEvents = set of TPParserLogEvent;
- TPasParser = Class;
- { TPasTreeContainer }
- TPasTreeContainer = class
- private
- FCurrentParser: TPasParser;
- FNeedComments: Boolean;
- FOnLog: TPasParserLogHandler;
- FPParserLogEvents: TPParserLogEvents;
- FScannerLogEvents: TPScannerLogEvents;
- protected
- FPackage: TPasPackage;
- FInterfaceOnly : Boolean;
- procedure SetCurrentParser(AValue: TPasParser); virtual;
- public
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; const ASourceFilename: String;
- ASourceLinenumber: Integer): TPasElement;overload;
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;overload;
- virtual; abstract;
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASrcPos: TPasSourcePos): TPasElement; overload;
- virtual;
- function CreateFunctionType(const AName, AResultName: String; AParent: TPasElement;
- UseParentAsResultParent: Boolean; const ASrcPos: TPasSourcePos): TPasFunctionType;
- function FindElement(const AName: String): TPasElement; virtual; abstract;
- procedure FinishScope(ScopeType: TPasScopeType; El: TPasElement); virtual;
- function FindModule(const AName: String): TPasModule; virtual;
- property Package: TPasPackage read FPackage;
- property InterfaceOnly : Boolean Read FInterfaceOnly Write FInterFaceOnly;
- property ScannerLogEvents : TPScannerLogEvents Read FScannerLogEvents Write FScannerLogEvents;
- property ParserLogEvents : TPParserLogEvents Read FPParserLogEvents Write FPParserLogEvents;
- property OnLog : TPasParserLogHandler Read FOnLog Write FOnLog;
- property CurrentParser : TPasParser Read FCurrentParser Write SetCurrentParser;
- property NeedComments : Boolean Read FNeedComments Write FNeedComments;
- end;
- EParserError = class(Exception)
- private
- FFilename: String;
- FRow, FColumn: Integer;
- public
- constructor Create(const AReason, AFilename: String;
- ARow, AColumn: Integer);
- property Filename: String read FFilename;
- property Row: Integer read FRow;
- property Column: Integer read FColumn;
- end;
- TProcType = (ptProcedure, ptFunction, ptOperator, ptClassOperator, ptConstructor, ptDestructor,
- ptClassProcedure, ptClassFunction, ptClassConstructor, ptClassDestructor);
- TExprKind = (ek_Normal, ek_PropertyIndex);
- TIndentAction = (iaNone,iaIndent,iaUndent);
- { TPasParser }
- TPasParser = class
- private
- FCurModule: TPasModule;
- FFileResolver: TBaseFileResolver;
- FImplicitUses: TStrings;
- FLastMsg: string;
- FLastMsgArgs: TMessageArgs;
- FLastMsgNumber: integer;
- FLastMsgPattern: string;
- FLastMsgType: TMessageType;
- FLogEvents: TPParserLogEvents;
- FOnLog: TPasParserLogHandler;
- FOptions: TPOptions;
- FScanner: TPascalScanner;
- FEngine: TPasTreeContainer;
- FCurToken: TToken;
- FCurTokenString: String;
- FCurComments : TStrings;
- FSavedComments : String;
- // UngetToken support:
- FTokenBuffer: array[0..1] of TToken;
- FTokenStringBuffer: array[0..1] of String;
- FCommentsBuffer: array[0..1] of TStrings;
- FTokenBufferIndex: Integer; // current index in FTokenBuffer
- FTokenBufferSize: Integer; // maximum valid index in FTokenBuffer
- FDumpIndent : String;
- function CheckOverloadList(AList: TFPList; AName: String; out OldMember: TPasElement): TPasOverloadedProc;
- procedure DumpCurToken(Const Msg : String; IndentAction : TIndentAction = iaNone);
- function GetCurrentModeSwitches: TModeSwitches;
- Procedure SetCurrentModeSwitches(AValue: TModeSwitches);
- function GetVariableModifiers(Parent: TPasElement; Out VarMods: TVariableModifiers; Out LibName, ExportName: TPasExpr; ExternalClass : Boolean): string;
- function GetVariableValueAndLocation(Parent : TPasElement; Out Value : TPasExpr; Out Location: String): Boolean;
- procedure HandleProcedureModifier(Parent: TPasElement; pm : TProcedureModifier);
- procedure HandleProcedureTypeModifier(ProcType: TPasProcedureType; ptm : TProcTypeModifier);
- procedure ParseClassLocalConsts(AType: TPasClassType; AVisibility: TPasMemberVisibility);
- procedure ParseClassLocalTypes(AType: TPasClassType; AVisibility: TPasMemberVisibility);
- procedure ParseVarList(Parent: TPasElement; VarList: TFPList; AVisibility: TPasMemberVisibility; Full: Boolean);
- procedure SetOptions(AValue: TPOptions);
- protected
- Function SaveComments : String;
- Function SaveComments(Const AValue : String) : String;
- function LogEvent(E : TPParserLogEvent) : Boolean; inline;
- Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Msg : String; SkipSourceInfo : Boolean = False);overload;
- Procedure DoLog(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
- function GetProcTypeFromToken(tk: TToken; IsClass: Boolean=False ): TProcType;
- procedure ParseAsmBlock(AsmBlock: TPasImplAsmStatement); virtual;
- procedure ParseRecordFieldList(ARec: TPasRecordType; AEndToken: TToken; AllowMethods : Boolean);
- procedure ParseRecordVariantParts(ARec: TPasRecordType; AEndToken: TToken);
- function GetProcedureClass(ProcType : TProcType): TPTreeElement;
- procedure ParseClassFields(AType: TPasClassType; const AVisibility: TPasMemberVisibility; IsClassField : Boolean);
- procedure ParseClassMembers(AType: TPasClassType);
- procedure ProcessMethod(AType: TPasClassType; IsClass : Boolean; AVisibility : TPasMemberVisibility);
- procedure ReadGenericArguments(List : TFPList;Parent : TPasElement);
- function CheckProcedureArgs(Parent: TPasElement;
- Args: TFPList; // list of TPasArgument
- Mandatory: Boolean): boolean;
- function CheckVisibility(S: String; var AVisibility: TPasMemberVisibility): Boolean;
- procedure ParseExc(MsgNumber: integer; const Msg: String);
- procedure ParseExc(MsgNumber: integer; const Fmt: String; Args : Array of const);
- procedure ParseExcExpectedIdentifier;
- procedure ParseExcSyntaxError;
- procedure ParseExcTokenError(const Arg: string);
- function OpLevel(t: TToken): Integer;
- Function TokenToExprOp (AToken : TToken) : TExprOpCode;
- function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement): TPasElement;overload;
- function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement; const ASrcPos: TPasSourcePos): TPasElement;overload;
- function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;overload;
- function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement; AVisibility: TPasMemberVisibility; const ASrcPos: TPasSourcePos): TPasElement;overload;
- function CreatePrimitiveExpr(AParent: TPasElement; AKind: TPasExprKind; const AValue: String): TPrimitiveExpr;
- function CreateBoolConstExpr(AParent: TPasElement; AKind: TPasExprKind; const ABoolValue : Boolean): TBoolConstExpr;
- function CreateBinaryExpr(AParent : TPasElement; xleft, xright: TPasExpr; AOpCode: TExprOpCode): TBinaryExpr;
- procedure AddToBinaryExprChain(var ChainFirst: TPasExpr;
- Element: TPasExpr; AOpCode: TExprOpCode);
- procedure AddParamsToBinaryExprChain(var ChainFirst: TPasExpr;
- Params: TParamsExpr);
- {$IFDEF VerbosePasParser}
- procedure WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr);
- {$ENDIF}
- function CreateUnaryExpr(AParent : TPasElement; AOperand: TPasExpr; AOpCode: TExprOpCode): TUnaryExpr;
- function CreateArrayValues(AParent : TPasElement): TArrayValues;
- function CreateFunctionType(const AName, AResultName: String; AParent: TPasElement;
- UseParentAsResultParent: Boolean; const NamePos: TPasSourcePos): TPasFunctionType;
- function CreateInheritedExpr(AParent : TPasElement): TInheritedExpr;
- function CreateSelfExpr(AParent : TPasElement): TSelfExpr;
- function CreateNilExpr(AParent : TPasElement): TNilExpr;
- function CreateRecordValues(AParent : TPasElement): TRecordValues;
- Function IsCurTokenHint(out AHint : TPasMemberHint) : Boolean; overload;
- Function IsCurTokenHint: Boolean; overload;
- Function TokenIsCallingConvention(const S : String; out CC : TCallingConvention) : Boolean; virtual;
- Function TokenIsProcedureModifier(Parent : TPasElement; const S : String; Out PM : TProcedureModifier) : Boolean; virtual;
- Function TokenIsProcedureTypeModifier(Parent : TPasElement; const S : String; Out PTM : TProcTypeModifier) : Boolean; virtual;
- Function CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
- function ParseParams(AParent : TPasElement;paramskind: TPasExprKind; AllowFormatting : Boolean = False): TParamsExpr;
- function ParseExpIdent(AParent : TPasElement): TPasExpr;
- procedure DoParseClassType(AType: TPasClassType);
- function DoParseExpression(AParent: TPaselement;InitExpr: TPasExpr=nil; AllowEqual : Boolean = True): TPasExpr;
- function DoParseConstValueExpression(AParent: TPasElement): TPasExpr;
- function CheckPackMode: TPackMode;
- function CheckUseUnit(ASection: TPasSection; AUnitName : string): TPasElement;
- procedure CheckImplicitUsedUnits(ASection: TPasSection);
- // Overload handling
- procedure AddProcOrFunction(Decs: TPasDeclarations; AProc: TPasProcedure);
- function CheckIfOverloaded(AParent: TPasElement; const AName: String): TPasElement;
- public
- constructor Create(AScanner: TPascalScanner; AFileResolver: TBaseFileResolver; AEngine: TPasTreeContainer);
- Destructor Destroy; override;
- procedure SetLastMsg(MsgType: TMessageType; MsgNumber: integer; Const Fmt : String; Args : Array of const);
- // General parsing routines
- function CurTokenName: String;
- function CurTokenText: String;
- Function CurComments : TStrings;
- Function SavedComments : String;
- procedure NextToken; // read next non whitespace, non space
- procedure UngetToken;
- procedure CheckToken(tk: TToken);
- procedure ExpectToken(tk: TToken);
- function ExpectIdentifier: String;
- Function CurTokenIsIdentifier(Const S : String) : Boolean;
- // Expression parsing
- function isEndOfExp(AllowEqual : Boolean = False): Boolean;
- // Type declarations
- function ParseComplexType(Parent : TPasElement = Nil): TPasType;
- function ParseTypeDecl(Parent: TPasElement): TPasType;
- function ParseType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String = ''; Full: Boolean = false; GenericArgs: TFPList = nil): TPasType;
- function ParseReferenceToProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasProcedureType;
- function ParseProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; const PT: TProcType): TPasProcedureType;
- function ParseStringType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasAliasType;
- function ParseSimpleType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; IsFull : Boolean = False): TPasType;
- function ParseAliasType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasTypeAliasType;
- function ParsePointerType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasPointerType;
- Function ParseArrayType(Parent : TPasElement; Const NamePos: TPasSourcePos; Const TypeName : String; PackMode : TPackMode) : TPasArrayType;
- Function ParseFileType(Parent : TPasElement; Const NamePos: TPasSourcePos; Const TypeName : String) : TPasFileType;
- Function ParseRecordDecl(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName : string; const Packmode : TPackMode = pmNone) : TPasRecordType;
- function ParseEnumType(Parent: TPasElement; Const NamePos: TPasSourcePos; const TypeName: String): TPasEnumType;
- function ParseSetType(Parent: TPasElement; Const NamePos: TPasSourcePos; const TypeName: String; AIsPacked : Boolean = False): TPasSetType;
- function ParseSpecializeType(Parent: TPasElement; Const TypeName: String): TPasClassType;
- Function ParseClassDecl(Parent: TPasElement; Const NamePos: TPasSourcePos; Const AClassName: String; AObjKind: TPasObjKind; PackMode : TPackMode= pmNone; GenericArgs: TFPList = nil): TPasType;
- Function ParseProperty(Parent : TPasElement; Const AName : String; AVisibility : TPasMemberVisibility; IsClassField: boolean) : TPasProperty;
- function ParseRangeType(AParent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; Full: Boolean = True): TPasRangeType;
- procedure ParseExportDecl(Parent: TPasElement; List: TFPList);
- // Constant declarations
- function ParseConstDecl(Parent: TPasElement): TPasConst;
- function ParseResourcestringDecl(Parent: TPasElement): TPasResString;
- // Variable handling. This includes parts of records
- procedure ParseVarDecl(Parent: TPasElement; List: TFPList);
- procedure ParseInlineVarDecl(Parent: TPasElement; List: TFPList; AVisibility : TPasMemberVisibility = visDefault; ClosingBrace: Boolean = False);
- // Main scope parsing
- procedure ParseMain(var Module: TPasModule);
- procedure ParseUnit(var Module: TPasModule);
- procedure ParseProgram(var Module: TPasModule; SkipHeader : Boolean = False);
- procedure ParseLibrary(var Module: TPasModule);
- procedure ParseOptionalUsesList(ASection: TPasSection);
- procedure ParseUsesList(ASection: TPasSection);
- procedure ParseInterface;
- procedure ParseImplementation;
- procedure ParseInitialization;
- procedure ParseFinalization;
- procedure ParseDeclarations(Declarations: TPasDeclarations);
- procedure ParseStatement(Parent: TPasImplBlock; out NewImplElement: TPasImplElement);
- procedure ParseLabels(AParent: TPasElement);
- procedure ParseProcBeginBlock(Parent: TProcedureBody);
- procedure ParseProcAsmBlock(Parent: TProcedureBody);
- // Function/Procedure declaration
- function ParseProcedureOrFunctionDecl(Parent: TPasElement; ProcType: TProcType;AVisibility : TPasMemberVisibility = VisDefault): TPasProcedure;
- procedure ParseArgList(Parent: TPasElement;
- Args: TFPList; // list of TPasArgument
- EndToken: TToken);
- procedure ParseProcedureOrFunctionHeader(Parent: TPasElement; Element: TPasProcedureType; ProcType: TProcType; OfObjectPossible: Boolean);
- procedure ParseProcedureBody(Parent: TPasElement);
- // Properties for external access
- property FileResolver: TBaseFileResolver read FFileResolver;
- property Scanner: TPascalScanner read FScanner;
- property Engine: TPasTreeContainer read FEngine;
- property CurToken: TToken read FCurToken;
- property CurTokenString: String read FCurTokenString;
- Property Options : TPOptions Read FOptions Write SetOptions;
- Property CurrentModeswitches : TModeSwitches Read GetCurrentModeSwitches Write SetCurrentModeSwitches;
- Property CurModule : TPasModule Read FCurModule;
- Property LogEvents : TPParserLogEvents Read FLogEvents Write FLogEvents;
- Property OnLog : TPasParserLogHandler Read FOnLog Write FOnLog;
- property ImplicitUses: TStrings read FImplicitUses;
- property LastMsg: string read FLastMsg write FLastMsg;
- property LastMsgNumber: integer read FLastMsgNumber write FLastMsgNumber;
- property LastMsgType: TMessageType read FLastMsgType write FLastMsgType;
- property LastMsgPattern: string read FLastMsgPattern write FLastMsgPattern;
- property LastMsgArgs: TMessageArgs read FLastMsgArgs write FLastMsgArgs;
- end;
- function ParseSource(AEngine: TPasTreeContainer;
- const FPCCommandLine, OSTarget, CPUTarget: String;
- UseStreams : Boolean = False): TPasModule;
- Function IsHintToken(T : String; Out AHint : TPasMemberHint) : boolean;
- Function IsProcModifier(S : String; Out PM : TProcedureModifier) : Boolean;
- Function IsCallingConvention(S : String; out CC : TCallingConvention) : Boolean;
- Function TokenToAssignKind( tk : TToken) : TAssignKind;
- implementation
- const
- WhitespaceTokensToIgnore = [tkWhitespace, tkComment, tkLineEnding, tkTab];
- type
- TDeclType = (declNone, declConst, declResourcestring, declType,
- declVar, declThreadvar, declProperty, declExports);
- Function IsHintToken(T : String; Out AHint : TPasMemberHint) : boolean;
- Const
- MemberHintTokens : Array[TPasMemberHint] of string =
- ('deprecated','library','platform','experimental','unimplemented');
- Var
- I : TPasMemberHint;
- begin
- t:=LowerCase(t);
- Result:=False;
- For I:=Low(TPasMemberHint) to High(TPasMemberHint) do
- begin
- result:=(t=MemberHintTokens[i]);
- if Result then
- begin
- aHint:=I;
- exit;
- end;
- end;
- end;
- Function IsCallingConvention(S : String; out CC : TCallingConvention) : Boolean;
- Var
- CCNames : Array[TCallingConvention] of String
- = ('','register','pascal','cdecl','stdcall','oldfpccall','safecall','syscall');
- Var
- C : TCallingConvention;
- begin
- S:=Lowercase(s);
- Result:=False;
- for C:=Low(TCallingConvention) to High(TCallingConvention) do
- begin
- Result:=(CCNames[c]<>'') and (s=CCnames[c]);
- If Result then
- begin
- CC:=C;
- exit;
- end;
- end;
- end;
- Function IsProcModifier(S : String; Out PM : TProcedureModifier) : Boolean;
- Var
- P : TProcedureModifier;
- begin
- S:=LowerCase(S);
- Result:=False;
- For P:=Low(TProcedureModifier) to High(TProcedureModifier) do
- begin
- Result:=s=ModifierNames[P];
- If Result then
- begin
- PM:=P;
- exit;
- end;
- end;
- end;
- Function TokenToAssignKind( tk : TToken) : TAssignKind;
- begin
- case tk of
- tkAssign : Result:=akDefault;
- tkAssignPlus : Result:=akAdd;
- tkAssignMinus : Result:=akMinus;
- tkAssignMul : Result:=akMul;
- tkAssignDivision : Result:=akDivision;
- else
- Raise Exception.CreateFmt('Not an assignment token : %s',[TokenInfos[tk]]);
- end;
- end;
- function ParseSource(AEngine: TPasTreeContainer;
- const FPCCommandLine, OSTarget, CPUTarget: String;
- UseStreams : Boolean = False): TPasModule;
- var
- FileResolver: TFileResolver;
- Parser: TPasParser;
- Start, CurPos: PChar;
- Filename: String;
- Scanner: TPascalScanner;
- procedure ProcessCmdLinePart;
- var
- l: Integer;
- s: String;
- begin
- l := CurPos - Start;
- SetLength(s, l);
- if l > 0 then
- Move(Start^, s[1], l)
- else
- exit;
- if (s[1] = '-') and (length(s)>1) then
- begin
- case s[2] of
- 'd': // -d define
- Scanner.AddDefine(UpperCase(Copy(s, 3, Length(s))));
- 'F': // -F
- if (length(s)>2) and (s[3] = 'i') then // -Fi include path
- FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
- 'I': // -I include path
- FileResolver.AddIncludePath(Copy(s, 3, Length(s)));
- 'S': // -S mode
- if (length(s)>2) then
- case S[3] of
- 'c' : Scanner.Options:=Scanner.Options+[po_cassignments];
- 'd' : Scanner.SetCompilerMode('DELPHI');
- '2' : Scanner.SetCompilerMode('OBJFPC');
- end;
- 'M' :
- begin
- delete(S,1,2);
- Scanner.SetCompilerMode(S);
- end;
- end;
- end else
- if Filename <> '' then
- raise Exception.Create(SErrMultipleSourceFiles)
- else
- Filename := s;
- end;
- var
- s: String;
- begin
- Result := nil;
- FileResolver := nil;
- Scanner := nil;
- Parser := nil;
- try
- FileResolver := TFileResolver.Create;
- FileResolver.UseStreams:=UseStreams;
- Scanner := TPascalScanner.Create(FileResolver);
- Scanner.AddDefine('FPK');
- Scanner.AddDefine('FPC');
- SCanner.LogEvents:=AEngine.ScannerLogEvents;
- SCanner.OnLog:=AEngine.Onlog;
- // TargetOS
- s := UpperCase(OSTarget);
- Scanner.AddDefine(s);
- if s = 'LINUX' then
- Scanner.AddDefine('UNIX')
- else if s = 'FREEBSD' then
- begin
- Scanner.AddDefine('BSD');
- Scanner.AddDefine('UNIX');
- end else if s = 'NETBSD' then
- begin
- Scanner.AddDefine('BSD');
- Scanner.AddDefine('UNIX');
- end else if s = 'SUNOS' then
- begin
- Scanner.AddDefine('SOLARIS');
- Scanner.AddDefine('UNIX');
- end else if s = 'GO32V2' then
- Scanner.AddDefine('DPMI')
- else if s = 'BEOS' then
- Scanner.AddDefine('UNIX')
- else if s = 'QNX' then
- Scanner.AddDefine('UNIX')
- else if s = 'AROS' then
- Scanner.AddDefine('HASAMIGA')
- else if s = 'MORPHOS' then
- Scanner.AddDefine('HASAMIGA')
- else if s = 'AMIGA' then
- Scanner.AddDefine('HASAMIGA');
- // TargetCPU
- s := UpperCase(CPUTarget);
- Scanner.AddDefine('CPU'+s);
- if (s='X86_64') then
- Scanner.AddDefine('CPU64')
- else
- Scanner.AddDefine('CPU32');
- Parser := TPasParser.Create(Scanner, FileResolver, AEngine);
- Filename := '';
- Parser.LogEvents:=AEngine.ParserLogEvents;
- Parser.OnLog:=AEngine.Onlog;
- if FPCCommandLine<>'' then
- begin
- Start := @FPCCommandLine[1];
- CurPos := Start;
- while CurPos[0] <> #0 do
- begin
- if CurPos[0] = ' ' then
- begin
- ProcessCmdLinePart;
- Start := CurPos + 1;
- end;
- Inc(CurPos);
- end;
- ProcessCmdLinePart;
- end;
- if Filename = '' then
- raise Exception.Create(SErrNoSourceGiven);
- FileResolver.AddIncludePath(ExtractFilePath(FileName));
- Scanner.OpenFile(Filename);
- Parser.ParseMain(Result);
- finally
- Parser.Free;
- Scanner.Free;
- FileResolver.Free;
- end;
- end;
- { ---------------------------------------------------------------------
- TPasTreeContainer
- ---------------------------------------------------------------------}
- procedure TPasTreeContainer.SetCurrentParser(AValue: TPasParser);
- begin
- if FCurrentParser=AValue then Exit;
- FCurrentParser:=AValue;
- end;
- function TPasTreeContainer.CreateElement(AClass: TPTreeElement;
- const AName: String; AParent: TPasElement; const ASourceFilename: String;
- ASourceLinenumber: Integer): TPasElement;
- begin
- Result := CreateElement(AClass, AName, AParent, visDefault, ASourceFilename,
- ASourceLinenumber);
- end;
- function TPasTreeContainer.CreateElement(AClass: TPTreeElement;
- const AName: String; AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASrcPos: TPasSourcePos): TPasElement;
- begin
- Result := CreateElement(AClass, AName, AParent, AVisibility, ASrcPos.FileName,
- ASrcPos.Row);
- end;
- function TPasTreeContainer.CreateFunctionType(const AName, AResultName: String;
- AParent: TPasElement; UseParentAsResultParent: Boolean;
- const ASrcPos: TPasSourcePos): TPasFunctionType;
- var
- ResultParent: TPasElement;
- begin
- Result := TPasFunctionType(CreateElement(TPasFunctionType, AName, AParent,
- visDefault, ASrcPos));
- if UseParentAsResultParent then
- ResultParent := AParent
- else
- ResultParent := Result;
- TPasFunctionType(Result).ResultEl :=
- TPasResultElement(CreateElement(TPasResultElement, AResultName, ResultParent,
- visDefault, ASrcPos));
- end;
- procedure TPasTreeContainer.FinishScope(ScopeType: TPasScopeType;
- El: TPasElement);
- begin
- if ScopeType=stModule then ;
- if El=nil then ;
- end;
- function TPasTreeContainer.FindModule(const AName: String): TPasModule;
- begin
- if AName='' then ;
- Result := nil;
- end;
- { ---------------------------------------------------------------------
- EParserError
- ---------------------------------------------------------------------}
- constructor EParserError.Create(const AReason, AFilename: String;
- ARow, AColumn: Integer);
- begin
- inherited Create(AReason);
- FFilename := AFilename;
- FRow := ARow;
- FColumn := AColumn;
- end;
- { ---------------------------------------------------------------------
- TPasParser
- ---------------------------------------------------------------------}
- procedure TPasParser.ParseExc(MsgNumber: integer; const Msg: String);
- begin
- ParseExc(MsgNumber,Msg,[]);
- end;
- procedure TPasParser.ParseExc(MsgNumber: integer; const Fmt: String;
- Args: array of const);
- begin
- {$IFDEF VerbosePasParser}
- writeln('TPasParser.ParseExc Token="',CurTokenText,'"');
- {$ENDIF}
- SetLastMsg(mtError,MsgNumber,Fmt,Args);
- raise EParserError.Create(SafeFormat(SParserErrorAtToken,
- [FLastMsg, CurTokenName, Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn])
- {$ifdef addlocation}+' ('+inttostr(scanner.currow)+' '+inttostr(scanner.curcolumn)+')'{$endif},
- Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
- end;
- procedure TPasParser.ParseExcExpectedIdentifier;
- begin
- ParseExc(nParserExpectedIdentifier,SParserExpectedIdentifier);
- end;
- procedure TPasParser.ParseExcSyntaxError;
- begin
- ParseExc(nParserSyntaxError,SParserSyntaxError);
- end;
- procedure TPasParser.ParseExcTokenError(const Arg: string);
- begin
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,[Arg]);
- end;
- constructor TPasParser.Create(AScanner: TPascalScanner;
- AFileResolver: TBaseFileResolver; AEngine: TPasTreeContainer);
- begin
- inherited Create;
- FScanner := AScanner;
- FFileResolver := AFileResolver;
- FEngine := AEngine;
- FCommentsBuffer[0]:=TStringList.Create;
- FCommentsBuffer[1]:=TStringList.Create;
- if Assigned(FEngine) then
- begin
- FEngine.CurrentParser:=Self;
- If FEngine.NeedComments then
- FScanner.SkipComments:=Not FEngine.NeedComments;
- end;
- FImplicitUses := TStringList.Create;
- FImplicitUses.Add('System'); // system always implicitely first.
- end;
- destructor TPasParser.Destroy;
- begin
- if Assigned(FEngine) then
- begin
- FEngine.CurrentParser:=Nil;
- FEngine:=nil;
- end;
- FreeAndNil(FImplicitUses);
- FreeAndNil(FCommentsBuffer[0]);
- FreeAndNil(FCommentsBuffer[1]);
- inherited Destroy;
- end;
- function TPasParser.CurTokenName: String;
- begin
- if CurToken = tkIdentifier then
- Result := 'Identifier ' + FCurTokenString
- else
- Result := TokenInfos[CurToken];
- end;
- function TPasParser.CurTokenText: String;
- begin
- case CurToken of
- tkIdentifier, tkString, tkNumber, tkChar:
- Result := FCurTokenString;
- else
- Result := TokenInfos[CurToken];
- end;
- end;
- function TPasParser.CurComments: TStrings;
- begin
- Result:=FCurComments;
- end;
- function TPasParser.SavedComments: String;
- begin
- Result:=FSavedComments;
- end;
- procedure TPasParser.NextToken;
- Var
- T : TStrings;
- begin
- if FTokenBufferIndex < FTokenBufferSize then
- begin
- // Get token from buffer
- FCurToken := FTokenBuffer[FTokenBufferIndex];
- FCurTokenString := FTokenStringBuffer[FTokenBufferIndex];
- FCurComments:=FCommentsBuffer[FTokenBufferIndex];
- Inc(FTokenBufferIndex);
- //writeln('TPasParser.NextToken From Buf ',CurTokenText,' id=',FTokenBufferIndex);
- end else
- begin
- { We have to fetch a new token. But first check, wether there is space left
- in the token buffer.}
- if FTokenBufferSize = 2 then
- begin
- FTokenBuffer[0] := FTokenBuffer[1];
- FTokenStringBuffer[0] := FTokenStringBuffer[1];
- T:=FCommentsBuffer[0];
- FCommentsBuffer[0]:=FCommentsBuffer[1];
- FCommentsBuffer[1]:=T;
- Dec(FTokenBufferSize);
- Dec(FTokenBufferIndex);
- end;
- // Fetch new token
- try
- FCommentsBuffer[FTokenBufferSize].Clear;
- repeat
- FCurToken := Scanner.FetchToken;
- if FCurToken=tkComment then
- FCommentsBuffer[FTokenBufferSize].Add(Scanner.CurTokenString);
- until not (FCurToken in WhitespaceTokensToIgnore);
- except
- on e: EScannerError do
- begin
- if po_KeepScannerError in Options then
- raise e
- else
- begin
- FLastMsgType := mtError;
- FLastMsgNumber := Scanner.LastMsgNumber;
- FLastMsgPattern := Scanner.LastMsgPattern;
- FLastMsg := Scanner.LastMsg;
- FLastMsgArgs := Scanner.LastMsgArgs;
- raise EParserError.Create(e.Message,
- Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
- end;
- end;
- end;
- FCurTokenString := Scanner.CurTokenString;
- FTokenBuffer[FTokenBufferSize] := FCurToken;
- FTokenStringBuffer[FTokenBufferSize] := FCurTokenString;
- FCurComments:=FCommentsBuffer[FTokenBufferSize];
- Inc(FTokenBufferSize);
- Inc(FTokenBufferIndex);
- // writeln('TPasParser.NextToken New ',CurTokenText,' id=',FTokenBufferIndex,' comments = ',FCurComments.text);
- end;
- end;
- procedure TPasParser.UngetToken;
- begin
- if FTokenBufferIndex = 0 then
- ParseExc(nParserUngetTokenError,SParserUngetTokenError)
- else begin
- Dec(FTokenBufferIndex);
- if FTokenBufferIndex>0 then
- begin
- FCurToken := FTokenBuffer[FTokenBufferIndex-1];
- FCurTokenString := FTokenStringBuffer[FTokenBufferIndex-1];
- FCurComments:=FCommentsBuffer[FTokenBufferIndex-1];
- end else begin
- FCurToken := tkWhitespace;
- FCurTokenString := '';
- FCurComments.Clear;
- end;
- //writeln('TPasParser.UngetToken ',CurTokenText,' id=',FTokenBufferIndex);
- end;
- end;
- procedure TPasParser.CheckToken(tk: TToken);
- begin
- if (CurToken<>tk) then
- begin
- {$IFDEF VerbosePasParser}
- writeln('TPasParser.ParseExcTokenError String="',CurTokenString,'" Text="',CurTokenText,'" CurToken=',CurToken,' tk=',tk);
- {$ENDIF}
- ParseExcTokenError(TokenInfos[tk]);
- end;
- end;
- procedure TPasParser.ExpectToken(tk: TToken);
- begin
- NextToken;
- CheckToken(tk);
- end;
- function TPasParser.ExpectIdentifier: String;
- begin
- ExpectToken(tkIdentifier);
- Result := CurTokenString;
- end;
- function TPasParser.CurTokenIsIdentifier(const S: String): Boolean;
- begin
- Result:=(Curtoken=tkIdentifier) and (CompareText(S,CurtokenText)=0);
- end;
- function TPasParser.IsCurTokenHint(out AHint: TPasMemberHint): Boolean;
- begin
- Result:=CurToken=tklibrary;
- if Result then
- AHint:=hLibrary
- else if (CurToken=tkIdentifier) then
- Result:=IsHintToken(CurTokenString,ahint);
- end;
- function TPasParser.IsCurTokenHint: Boolean;
- var
- dummy : TPasMemberHint;
- begin
- Result:=IsCurTokenHint(dummy);
- end;
- function TPasParser.TokenIsCallingConvention(const S: String; out
- CC: TCallingConvention): Boolean;
- begin
- Result:=IsCallingConvention(S,CC);
- end;
- function TPasParser.TokenIsProcedureModifier(Parent: TPasElement;
- const S: String; out PM: TProcedureModifier): Boolean;
- begin
- Result:=IsProcModifier(S,PM);
- if Result and (PM in [pmPublic,pmForward]) then
- begin
- While (Parent<>Nil) and Not ((Parent is TPasClassType) or (Parent is TPasRecordType)) do
- Parent:=Parent.Parent;
- Result:=Not Assigned(Parent);
- end;
- end;
- function TPasParser.TokenIsProcedureTypeModifier(Parent: TPasElement;
- const S: String; out PTM: TProcTypeModifier): Boolean;
- begin
- if CompareText(S,ProcTypeModifiers[ptmVarargs])=0 then
- begin
- Result:=true;
- PTM:=ptmVarargs;
- end
- else if CompareText(S,ProcTypeModifiers[ptmStatic])=0 then
- begin
- Result:=true;
- PTM:=ptmStatic;
- end
- else
- Result:=false;
- if Parent=nil then;
- end;
- function TPasParser.CheckHint(Element: TPasElement; ExpectSemiColon: Boolean
- ): TPasMemberHints;
- Var
- Found : Boolean;
- h : TPasMemberHint;
- begin
- Result:=[];
- Repeat
- NextToken;
- Found:=IsCurTokenHint(h);
- If Found then
- begin
- Include(Result,h);
- if (h=hDeprecated) then
- begin
- NextToken;
- if (Curtoken<>tkString) then
- UnGetToken
- else if assigned(Element) then
- Element.HintMessage:=CurTokenString;
- end;
- end;
- Until Not Found;
- UnGetToken;
- If Assigned(Element) then
- Element.Hints:=Result;
- if ExpectSemiColon then
- ExpectToken(tkSemiColon);
- end;
- function TPasParser.CheckPackMode: TPackMode;
- begin
- NextToken;
- Case CurToken of
- tkPacked : Result:=pmPacked;
- tkbitpacked : Result:=pmBitPacked;
- else
- result:=pmNone;
- end;
- if (Result<>pmNone) then
- begin
- NextToken;
- if Not (CurToken in [tkArray, tkRecord, tkObject, tkClass, tkSet]) then
- ParseExcTokenError('SET, ARRAY, RECORD, OBJECT or CLASS');
- end;
- end;
- Function IsSimpleTypeToken(Var AName : String) : Boolean;
- Const
- SimpleTypeCount = 15;
- SimpleTypeNames : Array[1..SimpleTypeCount] of string =
- ('byte','boolean','char','integer','int64','longint','longword','double',
- 'shortint','smallint','string','word','qword','cardinal','widechar');
- SimpleTypeCaseNames : Array[1..SimpleTypeCount] of string =
- ('Byte','Boolean','Char','Integer','Int64','LongInt','LongWord','Double',
- 'ShortInt','SmallInt','String','Word','QWord','Cardinal','WideChar');
- Var
- S : String;
- I : Integer;
- begin
- S:=LowerCase(AName);
- I:=SimpleTypeCount;
- While (I>0) and (s<>SimpleTypeNames[i]) do
- Dec(I);
- Result:=(I>0);
- if Result Then
- AName:=SimpleTypeCaseNames[I];
- end;
- function TPasParser.ParseStringType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String): TPasAliasType;
- Var
- S : String;
- ok: Boolean;
- begin
- Result := TPasAliasType(CreateElement(TPasAliasType, TypeName, Parent, NamePos));
- ok:=false;
- try
- If (Result.Name='') then
- Result.Name:='string';
- NextToken;
- if CurToken=tkSquaredBraceOpen then
- begin
- S:='';
- NextToken;
- While Not (Curtoken in [tkSquaredBraceClose,tkEOF]) do
- begin
- S:=S+CurTokenString;
- NextToken;
- end;
- end
- else
- UngetToken;
- Result.DestType:=TPasStringType(CreateElement(TPasStringType,'string',Parent));
- TPasStringType(Result.DestType).LengthExpr:=S;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- function TPasParser.ParseSimpleType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String; IsFull: Boolean
- ): TPasType;
- Type
- TSimpleTypeKind = (stkAlias,stkString,stkRange,stkSpecialize);
- Var
- Ref: TPasElement;
- K : TSimpleTypeKind;
- Name : String;
- SS : Boolean;
- CT : TPasClassType;
- begin
- Name := CurTokenString;
- NextToken;
- while CurToken=tkDot do
- begin
- ExpectIdentifier;
- Name := Name+'.'+CurTokenString;
- NextToken;
- end;
- // Current token is first token after identifier.
- if IsFull then
- begin
- if (CurToken=tkSemicolon) or isCurTokenHint then // Type A = B;
- K:=stkAlias
- else if (CurToken=tkSquaredBraceOpen) then
- begin
- // Todo: check via resolver
- if ((LowerCase(Name)='string') or (LowerCase(Name)='ansistring')) then // Type A = String[12];
- K:=stkString
- else
- ParseExcSyntaxError;
- end
- else if (CurToken in [tkBraceOpen,tkDotDot]) then // Type A = B..C;
- K:=stkRange
- else if (CurToken = tkLessThan) then // A = B<t>;
- K:=stkSpecialize
- else
- ParseExcTokenError(';');
- UnGetToken;
- end
- else if (CurToken = tkLessThan) then // A = B<t>;
- begin
- K:=stkSpecialize;
- UnGetToken;
- end
- else if (CurToken in [tkBraceOpen,tkDotDot]) then // A: B..C;
- begin
- K:=stkRange;
- UnGetToken;
- end
- else
- begin
- UnGetToken;
- K:=stkAlias;
- if (not (po_resolvestandardtypes in Options)) and (LowerCase(Name)='string') then
- K:=stkString;
- end;
- Case K of
- stkString:
- begin
- Result:=ParseStringType(Parent,NamePos,TypeName);
- end;
- stkSpecialize:
- begin
- CT := TPasClassType(CreateElement(TPasClassType, TypeName, Parent, Scanner.CurSourcePos));
- try
- CT.ObjKind := okSpecialize;
- CT.AncestorType := TPasUnresolvedTypeRef.Create(Name,Parent);
- CT.IsShortDefinition:=True;
- ReadGenericArguments(CT.GenericTemplateTypes,CT);
- Result:=CT;
- CT:=Nil;
- Finally
- FreeAndNil(CT);
- end;
- end;
- stkRange:
- begin
- UnGetToken;
- Result:=ParseRangeType(Parent,NamePos,TypeName,False);
- end;
- stkAlias:
- begin
- Ref:=Nil;
- SS:=(not (po_resolvestandardtypes in FOptions)) and isSimpleTypeToken(Name);
- if not SS then
- begin
- Ref:=Engine.FindElement(Name);
- if Ref=nil then
- begin
- {$IFDEF VerbosePasResolver}
- if po_resolvestandardtypes in FOptions then
- begin
- writeln('ERROR: TPasParser.ParseSimpleType resolver failed to raise an error');
- ParseExcExpectedIdentifier;
- end;
- {$ENDIF}
- end
- else if not (Ref is TPasType) then
- ParseExc(nParserExpectedTypeButGot,SParserExpectedTypeButGot,[Ref.ElementTypeName]);
- end;
- if (Ref=Nil) then
- Ref:=TPasUnresolvedTypeRef(CreateElement(TPasUnresolvedTypeRef,Name,Parent))
- else
- Ref.AddRef;
- if isFull then
- begin
- Result := TPasAliasType(CreateElement(TPasAliasType, TypeName, Parent, NamePos));
- TPasAliasType(Result).DestType:=Ref as TPasType;
- end
- else
- Result:=Ref as TPasType
- end;
- end;
- end;
- // On entry, we're on the TYPE token
- function TPasParser.ParseAliasType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String): TPasTypeAliasType;
- var
- ok: Boolean;
- begin
- Result := TPasTypeAliasType(CreateElement(TPasTypeAliasType, TypeName, Parent, NamePos));
- ok:=false;
- try
- Result.DestType := ParseType(Result,NamePos,'');
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- function TPasParser.ParsePointerType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String): TPasPointerType;
- var
- ok: Boolean;
- begin
- Result := TPasPointerType(CreateElement(TPasPointerType, TypeName, Parent, NamePos));
- ok:=false;
- Try
- TPasPointerType(Result).DestType := ParseType(Result,Scanner.CurSourcePos);
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- function TPasParser.ParseEnumType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String): TPasEnumType;
- Var
- EnumValue: TPasEnumValue;
- ok: Boolean;
- begin
- Result := TPasEnumType(CreateElement(TPasEnumType, TypeName, Parent, NamePos));
- ok:=false;
- try
- while True do
- begin
- NextToken;
- SaveComments;
- EnumValue := TPasEnumValue(CreateElement(TPasEnumValue, CurTokenString, Result));
- Result.Values.Add(EnumValue);
- NextToken;
- if CurToken = tkBraceClose then
- break
- else if CurToken in [tkEqual,tkAssign] then
- begin
- NextToken;
- EnumValue.Value:=DoParseExpression(Result);
- // UngetToken;
- if CurToken = tkBraceClose then
- Break
- else if not (CurToken=tkComma) then
- ParseExc(nParserExpectedCommaRBracket,SParserExpectedCommaRBracket);
- end
- else if not (CurToken=tkComma) then
- ParseExc(nParserExpectedCommaRBracket,SParserExpectedCommaRBracket)
- end;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- Engine.FinishScope(stTypeDef,Result);
- end;
- function TPasParser.ParseSetType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String; AIsPacked : Boolean = False): TPasSetType;
- var
- ok: Boolean;
- begin
- Result := TPasSetType(CreateElement(TPasSetType, TypeName, Parent, NamePos));
- Result.IsPacked:=AIsPacked;
- ok:=false;
- try
- ExpectToken(tkOf);
- Result.EnumType := ParseType(Result,Scanner.CurSourcePos);
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- Engine.FinishScope(stTypeDef,Result);
- end;
- function TPasParser.ParseType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String = ''; Full: Boolean = false; GenericArgs : TFPList = Nil
- ): TPasType;
- Const
- // These types are allowed only when full type declarations
- FullTypeTokens = [tkGeneric,{tkSpecialize,}tkClass,tkInterface,tkDispInterface,tkType];
- // Parsing of these types already takes care of hints
- NoHintTokens = [tkProcedure,tkFunction];
- var
- PM : TPackMode;
- CH , isHelper,ok: Boolean; // Check hint ?
- begin
- Result := nil;
- // NextToken and check pack mode
- Pm:=CheckPackMode;
- if Full then
- CH:=Not (CurToken in NoHintTokens)
- else
- begin
- CH:=False;
- if (CurToken in FullTypeTokens) then
- ParseExc(nParserTypeNotAllowedHere,SParserTypeNotAllowedHere,[CurtokenText]);
- end;
- ok:=false;
- Try
- case CurToken of
- // types only allowed when full
- tkObject: Result := ParseClassDecl(Parent, NamePos, TypeName, okObject,PM);
- tkDispInterface:
- Result := ParseClassDecl(Parent, NamePos, TypeName, okDispInterface);
- tkInterface:
- Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface);
- tkSpecialize: Result:=ParseSpecializeType(Parent,TypeName);
- tkClass: Result := ParseClassDecl(Parent, NamePos, TypeName, okClass, PM, GenericArgs);
- tkType:
- begin
- NextToken;
- isHelper:=CurTokenIsIdentifier('helper');
- UnGetToken;
- if isHelper then
- Result:=ParseClassDecl(Parent,NamePos,TypeName,okTypeHelper,PM)
- else
- Result:=ParseAliasType(Parent,NamePos,TypeName);
- end;
- // Always allowed
- tkIdentifier:
- begin
- if CurTokenIsIdentifier('reference') then
- begin
- CH:=False;
- Result:=ParseReferencetoProcedureType(Parent,NamePos,TypeName)
- end
- else
- Result:=ParseSimpleType(Parent,NamePos,TypeName,Full);
- end;
- tkCaret: Result:=ParsePointerType(Parent,NamePos,TypeName);
- tkFile: Result:=ParseFileType(Parent,NamePos,TypeName);
- tkArray: Result:=ParseArrayType(Parent,NamePos,TypeName,pm);
- tkBraceOpen: Result:=ParseEnumType(Parent,NamePos,TypeName);
- tkSet: Result:=ParseSetType(Parent,NamePos,TypeName,pm=pmPacked);
- tkProcedure: Result:=ParseProcedureType(Parent,NamePos,TypeName,ptProcedure);
- tkFunction: Result:=ParseProcedureType(Parent,NamePos,TypeName,ptFunction);
- tkRecord:
- begin
- NextToken;
- if CurTokenIsIdentifier('Helper') then
- begin
- UnGetToken;
- Result:=ParseClassDecl(Parent,NamePos,TypeName,okRecordHelper,PM);
- end
- else
- begin
- UnGetToken;
- Result := ParseRecordDecl(Parent,NamePos,TypeName,PM);
- end;
- end;
- tkNumber,tkMinus,tkChar:
- begin
- UngetToken;
- Result:=ParseRangeType(Parent,NamePos,TypeName,Full);
- end;
- else
- ParseExcExpectedIdentifier;
- end;
- if CH then
- CheckHint(Result,True);
- ok:=true;
- finally
- if not ok then
- if Result<>nil then
- Result.Release;
- end;
- end;
- function TPasParser.ParseReferenceToProcedureType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String
- ): TPasProcedureType;
- begin
- if not CurTokenIsIdentifier('reference') then
- ParseExcTokenError('reference');
- ExpectToken(tkTo);
- NextToken;
- Case CurToken of
- tkprocedure : Result:=ParseProcedureType(Parent,NamePos,TypeName,ptProcedure);
- tkfunction : Result:=ParseProcedureType(Parent,NamePos,TypeName,ptFunction);
- else
- ParseExcTokenError('procedure or function');
- end;
- Result.IsReferenceTo:=True;
- end;
- function TPasParser.ParseComplexType(Parent : TPasElement = Nil): TPasType;
- begin
- NextToken;
- case CurToken of
- tkProcedure:
- begin
- Result := TPasProcedureType(CreateElement(TPasProcedureType, '', Parent));
- ParseProcedureOrFunctionHeader(Result, TPasProcedureType(Result), ptProcedure, True);
- if CurToken = tkSemicolon then
- UngetToken; // Unget semicolon
- end;
- tkFunction:
- begin
- Result := CreateFunctionType('', 'Result', Parent, False, Scanner.CurSourcePos);
- ParseProcedureOrFunctionHeader(Result, TPasFunctionType(Result), ptFunction, True);
- if CurToken = tkSemicolon then
- UngetToken; // Unget semicolon
- end;
- else
- UngetToken;
- Result := ParseType(Parent,Scanner.CurSourcePos);
- end;
- end;
- function TPasParser.ParseArrayType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String; PackMode: TPackMode
- ): TPasArrayType;
- Var
- S : String;
- ok: Boolean;
- RangeExpr: TPasExpr;
- begin
- Result := TPasArrayType(CreateElement(TPasArrayType, TypeName, Parent, NamePos));
- ok:=false;
- try
- Result.PackMode:=PackMode;
- NextToken;
- S:='';
- case CurToken of
- tkSquaredBraceOpen:
- begin
- repeat
- NextToken;
- if po_arrayrangeexpr in Options then
- begin
- RangeExpr:=DoParseExpression(Result);
- Result.AddRange(RangeExpr);
- end
- else if CurToken<>tkSquaredBraceClose then
- S:=S+CurTokenText;
- if CurToken=tkSquaredBraceClose then
- break
- else if CurToken=tkComma then
- continue
- else if po_arrayrangeexpr in Options then
- ParseExcTokenError(']');
- until false;
- Result.IndexRange:=S;
- ExpectToken(tkOf);
- Result.ElType := ParseType(Result,Scanner.CurSourcePos);
- end;
- tkOf:
- begin
- NextToken;
- if CurToken = tkConst then
- else
- begin
- UngetToken;
- Result.ElType := ParseType(Result,Scanner.CurSourcePos);
- end
- end
- else
- ParseExc(nParserArrayTypeSyntaxError,SParserArrayTypeSyntaxError);
- end;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- Engine.FinishScope(stTypeDef,Result);
- end;
- function TPasParser.ParseFileType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String): TPasFileType;
- begin
- Result:=TPasFileType(CreateElement(TPasFileType, TypeName, Parent, NamePos));
- NextToken;
- If CurToken=tkOf then
- Result.ElType := ParseType(Result,Scanner.CurSourcePos)
- else
- ungettoken;
- end;
- function TPasParser.isEndOfExp(AllowEqual : Boolean = False):Boolean;
- const
- EndExprToken = [
- tkEOF, tkBraceClose, tkSquaredBraceClose, tkSemicolon, tkComma, tkColon,
- tkdo, tkdownto, tkelse, tkend, tkof, tkthen, tkto
- ];
- begin
- Result:=(CurToken in EndExprToken) or IsCurTokenHint;
- if Not (Result or AllowEqual) then
- Result:=(Curtoken=tkEqual);
- end;
- function TPasParser.ParseParams(AParent: TPasElement; paramskind: TPasExprKind;
- AllowFormatting: Boolean = False): TParamsExpr;
- var
- params : TParamsExpr;
- p : TPasExpr;
- PClose : TToken;
- begin
- Result:=nil;
- if paramskind in [pekArrayParams, pekSet] then begin
- if CurToken<>tkSquaredBraceOpen then
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,['[']);
- PClose:=tkSquaredBraceClose;
- end else begin
- if CurToken<>tkBraceOpen then
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,['(']);
- PClose:=tkBraceClose;
- end;
- params:=TParamsExpr(CreateElement(TParamsExpr,'',AParent));
- try
- params.Kind:=paramskind;
- NextToken;
- if not isEndOfExp then begin
- repeat
- p:=DoParseExpression(params);
- if not Assigned(p) then
- ParseExcSyntaxError;
- params.AddParam(p);
- if (CurToken=tkColon) then
- if Not AllowFormatting then
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,[','])
- else
- begin
- NextToken;
- p.format1:=DoParseExpression(p);
- if (CurToken=tkColon) then
- begin
- NextToken;
- p.format2:=DoParseExpression(p);
- end;
- end;
- if not (CurToken in [tkComma, PClose]) then
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,[',']);
- if CurToken = tkComma then begin
- NextToken;
- if CurToken = PClose then begin
- //ErrorExpected(parser, 'identifier');
- ParseExcSyntaxError;
- end;
- end;
- until CurToken=PClose;
- end;
- NextToken;
- Result:=params;
- finally
- if not Assigned(Result) then params.Release;
- end;
- end;
- function TPasParser.TokenToExprOp(AToken: TToken): TExprOpCode;
- begin
- Case AToken of
- tkMul : Result:=eopMultiply;
- tkPlus : Result:=eopAdd;
- tkMinus : Result:=eopSubtract;
- tkDivision : Result:=eopDivide;
- tkLessThan : Result:=eopLessThan;
- tkEqual : Result:=eopEqual;
- tkGreaterThan : Result:=eopGreaterThan;
- tkAt : Result:=eopAddress;
- tkNotEqual : Result:=eopNotEqual;
- tkLessEqualThan : Result:=eopLessthanEqual;
- tkGreaterEqualThan : Result:=eopGreaterThanEqual;
- tkPower : Result:=eopPower;
- tkSymmetricalDifference : Result:=eopSymmetricalDifference;
- tkIs : Result:=eopIs;
- tkAs : Result:=eopAs;
- tkSHR : Result:=eopSHR;
- tkSHL : Result:=eopSHL;
- tkAnd : Result:=eopAnd;
- tkOr : Result:=eopOR;
- tkXor : Result:=eopXOR;
- tkMod : Result:=eopMod;
- tkDiv : Result:=eopDiv;
- tkNot : Result:=eopNot;
- tkIn : Result:=eopIn;
- tkDot : Result:=eopSubIdent;
- tkCaret : Result:=eopDeref;
- else
- ParseExc(nParserNotAnOperand,SParserNotAnOperand,[AToken,TokenInfos[AToken]]);
- end;
- end;
- function TPasParser.ParseExpIdent(AParent: TPasElement): TPasExpr;
- Function IsWriteOrstr(P : TPasExpr) : boolean;
- Var
- N : String;
- begin
- Result:=P is TPrimitiveExpr;
- if Result then
- begin
- N:=LowerCase(TPrimitiveExpr(P).Value);
- // We should actually resolve this to system.NNN
- Result:=(N='write') or (N='str') or (N='writeln');
- end;
- end;
- Procedure HandleSelf(Var Last: TPasExpr);
- Var
- b : TBinaryExpr;
- optk : TToken;
- begin
- NextToken;
- if CurToken = tkDot then
- begin // self.Write(EscapeText(AText));
- optk:=CurToken;
- NextToken;
- b:=CreateBinaryExpr(AParent,Last, ParseExpIdent(AParent), TokenToExprOp(optk));
- if not Assigned(b.right) then
- begin
- b.Release;
- ParseExcExpectedIdentifier;
- end;
- Last:=b;
- end;
- UngetToken;
- end;
- var
- Last,func, Expr: TPasExpr;
- prm : TParamsExpr;
- b : TBinaryExpr;
- optk : TToken;
- ok: Boolean;
- begin
- Result:=nil;
- case CurToken of
- tkString: Last:=CreatePrimitiveExpr(AParent,pekString,CurTokenString);
- tkChar: Last:=CreatePrimitiveExpr(AParent,pekString, CurTokenText);
- tkNumber: Last:=CreatePrimitiveExpr(AParent,pekNumber, CurTokenString);
- tkIdentifier:
- begin
- if CompareText(CurTokenText,'self')=0 then
- begin
- Last:=CreateSelfExpr(AParent);
- HandleSelf(Last)
- end
- Else
- Last:=CreatePrimitiveExpr(AParent,pekIdent, CurTokenText)
- end;
- tkfalse, tktrue: Last:=CreateBoolConstExpr(Aparent,pekBoolConst, CurToken=tktrue);
- tknil: Last:=CreateNilExpr(AParent);
- tkSquaredBraceOpen: Last:=ParseParams(AParent,pekSet);
- tkinherited:
- begin
- //inherited; inherited function
- Last:=CreateInheritedExpr(AParent);
- NextToken;
- if (CurToken=tkIdentifier) then
- begin
- b:=CreateBinaryExpr(AParent,Last, DoParseExpression(AParent), eopNone);
- if not Assigned(b.right) then
- begin
- b.Release;
- ParseExcExpectedIdentifier;
- end;
- Last:=b;
- end;
- UngetToken;
- end;
- tkself:
- begin
- Last:=CreateSelfExpr(AParent);
- HandleSelf(Last);
- end;
- tkAt:
- begin
- // P:=@function;
- NextToken;
- if (length(CurTokenText)=0) or not (CurTokenText[1] in ['A'..'_']) then
- begin
- UngetToken;
- ParseExcExpectedIdentifier;
- end;
- Last:=CreatePrimitiveExpr(AParent,pekString, '@'+CurTokenText);
- end;
- tkCaret:
- begin
- // ^A..^_ characters. See #16341
- NextToken;
- if not (length(CurTokenText)=1) or not (CurTokenText[1] in ['A'..'_']) then
- begin
- UngetToken;
- ParseExcExpectedIdentifier;
- end;
- Last:=CreatePrimitiveExpr(AParent,pekString, '^'+CurTokenText);
- end;
- else
- ParseExcExpectedIdentifier;
- end;
- Result:=Last;
- func:=Last;
-
- if Last.Kind<>pekSet then NextToken;
- ok:=false;
- try
- if Last.Kind in [pekIdent,pekSelf] then
- begin
- while CurToken in [tkDot] do
- begin
- NextToken;
- if CurToken in [tkIdentifier,tktrue,tkfalse] then // true and false are also identifiers
- begin
- expr:=CreatePrimitiveExpr(AParent,pekIdent,CurTokenString);
- AddToBinaryExprChain(Result,expr,eopSubIdent);
- func:=expr;
- NextToken;
- end
- else
- begin
- UngetToken;
- ParseExcExpectedIdentifier;
- end;
- end;
- repeat
- case CurToken of
- tkBraceOpen,tkSquaredBraceOpen:
- begin
- if CurToken=tkBraceOpen then
- prm:=ParseParams(AParent,pekFuncParams,isWriteOrStr(func))
- else
- prm:=ParseParams(AParent,pekArrayParams);
- if not Assigned(prm) then Exit;
- AddParamsToBinaryExprChain(Result,prm);
- end;
- tkCaret:
- begin
- Result:=CreateUnaryExpr(AParent,Result,TokenToExprOp(CurToken));
- NextToken;
- end;
- else
- break;
- end;
- until false;
- // Needed for TSDOBaseDataObjectClass(Self.ClassType).Create
- if CurToken in [tkDot,tkas] then
- begin
- optk:=CurToken;
- NextToken;
- Expr:=ParseExpIdent(AParent);
- if Expr=nil then
- ParseExcExpectedIdentifier;
- if optk=tkDot then
- AddToBinaryExprChain(Result,Expr,TokenToExprOp(optk))
- else
- begin
- // a as b
- Result:=CreateBinaryExpr(AParent,Result,Expr,TokenToExprOp(tkas));
- end;
- end;
- end;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- function TPasParser.OpLevel(t: TToken): Integer;
- begin
- case t of
- // tkDot:
- // Result:=5;
- tknot,tkAt:
- Result:=4;
- tkMul, tkDivision, tkdiv, tkmod, tkand, tkShl,tkShr, tkas, tkPower :
- Result:=3;
- tkPlus, tkMinus, tkor, tkxor:
- Result:=2;
- tkEqual, tkNotEqual, tkLessThan, tkLessEqualThan, tkGreaterThan, tkGreaterEqualThan, tkin, tkis:
- Result:=1;
- else
- Result:=0;
- end;
- end;
- function TPasParser.DoParseExpression(AParent : TPaselement;InitExpr: TPasExpr; AllowEqual : Boolean = True): TPasExpr;
- var
- expstack : TFPList;
- opstack : array of TToken;
- opstackTop: integer;
- pcount : Integer;
- x : TPasExpr;
- i : Integer;
- tempop : TToken;
- NotBinary : Boolean;
- const
- PrefixSym = [tkPlus, tkMinus, tknot, tkAt]; // + - not @
- BinaryOP = [tkMul, tkDivision, tkdiv, tkmod, tkDotDot,
- tkand, tkShl,tkShr, tkas, tkPower,
- tkPlus, tkMinus, tkor, tkxor, tkSymmetricalDifference,
- tkEqual, tkNotEqual, tkLessThan, tkLessEqualThan,
- tkGreaterThan, tkGreaterEqualThan, tkin, tkis];
- function PopExp: TPasExpr; inline;
- begin
- if expstack.Count>0 then begin
- Result:=TPasExpr(expstack[expstack.Count-1]);
- expstack.Delete(expstack.Count-1);
- end else
- Result:=nil;
- end;
- procedure PushOper(token: TToken); inline;
- begin
- inc(opstackTop);
- if opstackTop=length(opstack) then
- SetLength(opstack,length(opstack)*2+4);
- opstack[opstackTop]:=token;
- end;
- function PeekOper: TToken; inline;
- begin
- if opstackTop>=0 then Result:=opstack[opstackTop]
- else Result:=tkEOF;
- end;
- function PopOper: TToken; inline;
- begin
- Result:=PeekOper;
- if Result<>tkEOF then dec(opstackTop);
- end;
- procedure PopAndPushOperator;
- var
- t : TToken;
- xright : TPasExpr;
- xleft : TPasExpr;
- bin : TBinaryExpr;
- begin
- t:=PopOper;
- xright:=PopExp;
- xleft:=PopExp;
- if t=tkDotDot then
- begin
- bin:=CreateBinaryExpr(AParent,xleft,xright,eopNone);
- bin.Kind:=pekRange;
- end
- else
- bin:=CreateBinaryExpr(AParent,xleft,xright,TokenToExprOp(t));
- expstack.Add(bin);
- end;
- Var
- AllowedBinaryOps : Set of TToken;
- begin
- AllowedBinaryOps:=BinaryOP;
- if Not AllowEqual then
- Exclude(AllowedBinaryOps,tkEqual);
- //DumpCurToken('Entry',iaIndent);
- Result:=nil;
- expstack := TFPList.Create;
- SetLength(opstack,4);
- opstackTop:=-1;
- try
- repeat
- NotBinary:=True;
- pcount:=0;
- if not Assigned(InitExpr) then
- begin
- // the first part of the expression has been parsed externally.
- // this is used by Constant Expression parser (CEP) parsing only,
- // whenever it makes a false assuming on constant expression type.
- // i.e: SI_PAD_SIZE = ((128/sizeof(longint)) - 3);
- //
- // CEP assumes that it's array or record, because the expression
- // starts with "(". After the first part is parsed, the CEP meets "-"
- // that assures, it's not an array expression. The CEP should give the
- // first part back to the expression parser, to get the correct
- // token tree according to the operations priority.
- //
- // quite ugly. type information is required for CEP to work clean
- while CurToken in PrefixSym do
- begin
- PushOper(CurToken);
- inc(pcount);
- NextToken;
- end;
- if (CurToken = tkBraceOpen) then
- begin
- NextToken;
- x:=DoParseExpression(AParent);
- if (CurToken<>tkBraceClose) then
- begin
- x.Release;
- CheckToken(tkBraceClose);
- end;
- NextToken;
- // for expressions like (ppdouble)^^;
- while (x<>Nil) and (CurToken=tkCaret) do
- begin
- NextToken;
- x:=CreateUnaryExpr(AParent,x, TokenToExprOp(tkCaret));
- end;
- // for expressions like (TObject(m)).Free;
- if (x<>Nil) and (CurToken=tkDot) then
- begin
- NextToken;
- x:=CreateBinaryExpr(AParent,x, ParseExpIdent(AParent), TokenToExprOp(tkDot));
- end;
- end
- else
- begin
- x:=ParseExpIdent(AParent);
- end;
- if not Assigned(x) then
- ParseExcSyntaxError;
- expstack.Add(x);
- for i:=1 to pcount do
- begin
- tempop:=PopOper;
- x:=popexp;
- if (tempop=tkMinus) and (x.Kind=pekRange) then
- begin
- TBinaryExpr(x).Left:=CreateUnaryExpr(x, TBinaryExpr(x).left, eopSubtract);
- expstack.Add(x);
- end
- else
- expstack.Add(CreateUnaryExpr(AParent, x, TokenToExprOp(tempop) ));
- end;
- end
- else
- begin
- expstack.Add(InitExpr);
- InitExpr:=nil;
- end;
- if (CurToken in AllowedBinaryOPs) then
- begin
- // Adjusting order of the operations
- NotBinary:=False;
- tempop:=PeekOper;
- while (opstackTop>=0) and (OpLevel(tempop)>=OpLevel(CurToken)) do begin
- PopAndPushOperator;
- tempop:=PeekOper;
- end;
- PushOper(CurToken);
- NextToken;
- end;
- //Writeln('Bin ',NotBinary ,' or EOE ',isEndOfExp, ' Ex ',Assigned(x),' stack ',ExpStack.Count);
- until NotBinary or isEndOfExp(AllowEqual);
- if not NotBinary then ParseExcExpectedIdentifier;
- while opstackTop>=0 do PopAndPushOperator;
- // only 1 expression should be on the stack, at the end of the correct expression
- if expstack.Count<>1 then
- ParseExcSyntaxError;
- if expstack.Count=1 then
- begin
- Result:=TPasExpr(expstack[0]);
- Result.Parent:=AParent;
- end;
- finally
- {if Not Assigned(Result) then
- DumpCurToken('Exiting (no result)',iaUndent)
- else
- DumpCurtoken('Exiting (Result: "'+Result.GetDeclaration(true)+'") ',iaUndent);}
- if not Assigned(Result) then begin
- // expression error!
- for i:=0 to expstack.Count-1 do
- TPasExpr(expstack[i]).Release;
- end;
- SetLength(opstack,0);
- expstack.Free;
- end;
- end;
- function GetExprIdent(p: TPasExpr): String;
- begin
- Result:='';
- if not Assigned(p) then exit;
- if (p.ClassType=TPrimitiveExpr) and (p.Kind=pekIdent) then
- Result:=TPrimitiveExpr(p).Value
- else if (p.ClassType=TSelfExpr) then
- Result:='Self';
- end;
- function TPasParser.DoParseConstValueExpression(AParent: TPasElement): TPasExpr;
- var
- x : TPasExpr;
- n : AnsiString;
- r : TRecordValues;
- a : TArrayValues;
- function lastfield:boolean;
- begin
- result:= CurToken<>tkSemicolon;
- if not result then
- begin
- nexttoken;
- if curtoken=tkbraceclose then
- result:=true
- else
- ungettoken;
- end;
- end;
- begin
- if CurToken <> tkBraceOpen then
- Result:=DoParseExpression(AParent)
- else begin
- Result:=nil;
- NextToken;
- x:=DoParseConstValueExpression(AParent);
- case CurToken of
- tkComma: // array of values (a,b,c);
- try
- a:=CreateArrayValues(AParent);
- a.AddValues(x);
- x:=nil;
- repeat
- NextToken;
- x:=DoParseConstValueExpression(AParent);
- a.AddValues(x);
- x:=nil;
- until CurToken<>tkComma;
- Result:=a;
- finally
- if Result=nil then
- begin
- a.Free;
- x.Free;
- end;
- end;
- tkColon: // record field (a:xxx;b:yyy;c:zzz);
- begin
- r:=nil;
- try
- n:=GetExprIdent(x);
- ReleaseAndNil(TPasElement(x));
- r:=CreateRecordValues(AParent);
- NextToken;
- x:=DoParseConstValueExpression(AParent);
- r.AddField(n, x);
- x:=nil;
- if not lastfield then
- repeat
- n:=ExpectIdentifier;
- ExpectToken(tkColon);
- NextToken;
- x:=DoParseConstValueExpression(AParent);
- r.AddField(n, x);
- x:=nil;
- until lastfield; // CurToken<>tkSemicolon;
- Result:=r;
- finally
- if Result=nil then
- begin
- r.Free;
- x.Free;
- end;
- end;
- end;
- else
- // Binary expression! ((128 div sizeof(longint)) - 3);
- Result:=DoParseExpression(AParent,x);
- if CurToken<>tkBraceClose then
- begin
- ReleaseAndNil(TPasElement(Result));
- ParseExc(nParserExpectedCommaRBracket,SParserExpectedCommaRBracket);
- end;
- NextToken;
- if CurToken <> tkSemicolon then // the continue of expression
- Result:=DoParseExpression(AParent,Result);
- Exit;
- end;
- if CurToken<>tkBraceClose then
- begin
- ReleaseAndNil(TPasElement(Result));
- ParseExc(nParserExpectedCommaRBracket,SParserExpectedCommaRBracket);
- end;
- NextToken;
- end;
- end;
- function TPasParser.CheckOverloadList(AList: TFPList; AName: String; out
- OldMember: TPasElement): TPasOverloadedProc;
- Var
- I : Integer;
- begin
- Result:=Nil;
- I:=0;
- While (Result=Nil) and (I<AList.Count) do
- begin
- OldMember:=TPasElement(AList[i]);
- if CompareText(OldMember.Name, AName) = 0 then
- begin
- if OldMember is TPasOverloadedProc then
- Result:=TPasOverloadedProc(OldMember)
- else
- begin
- Result:=TPasOverloadedProc(CreateElement(TPasOverloadedProc, AName, OldMember.Parent));
- Result.Visibility:=OldMember.Visibility;
- Result.Overloads.Add(OldMember);
- Result.SourceFilename:=OldMember.SourceFilename;
- Result.SourceLinenumber:=OldMember.SourceLinenumber;
- Result.DocComment:=Oldmember.DocComment;
- AList[i] := Result;
- end;
- end;
- Inc(I);
- end;
- If Result=Nil then
- OldMember:=Nil;
- end;
- procedure TPasParser.AddProcOrFunction(Decs: TPasDeclarations;
- AProc: TPasProcedure);
- var
- I : Integer;
- OldMember: TPasElement;
- OverloadedProc: TPasOverloadedProc;
- begin
- With Decs do
- begin
- if not (po_nooverloadedprocs in Options) then
- OverloadedProc:=CheckOverloadList(Functions,AProc.Name,OldMember)
- else
- OverloadedProc:=nil;
- If (OverloadedProc<>Nil) then
- begin
- OverLoadedProc.Overloads.Add(AProc);
- if (OldMember<>OverloadedProc) then
- begin
- I:=Declarations.IndexOf(OldMember);
- If I<>-1 then
- Declarations[i]:=OverloadedProc;
- end;
- end
- else
- begin
- Declarations.Add(AProc);
- Functions.Add(AProc);
- end;
- end;
- end;
- // Return the parent of a function declaration. This is AParent,
- // except when AParent is a class, and the function is overloaded.
- // Then the parent is the overload object.
- function TPasParser.CheckIfOverloaded(AParent: TPasElement; const AName: String): TPasElement;
- var
- Member: TPasElement;
- OverloadedProc: TPasOverloadedProc;
- begin
- Result:=AParent;
- If (not (po_nooverloadedprocs in Options)) and (AParent is TPasClassType) then
- begin
- OverloadedProc:=CheckOverLoadList(TPasClassType(AParent).Members,AName,Member);
- If (OverloadedProc<>Nil) then
- Result:=OverloadedProc;
- end;
- end;
- procedure TPasParser.ParseMain(var Module: TPasModule);
- begin
- Module:=nil;
- NextToken;
- SaveComments;
- case CurToken of
- tkUnit:
- ParseUnit(Module);
- tkProgram:
- ParseProgram(Module);
- tkLibrary:
- ParseLibrary(Module);
- else
- ungettoken;
- ParseProgram(Module,True);
- // ParseExcTokenError('unit');
- end;
- end;
- // Starts after the "unit" token
- procedure TPasParser.ParseUnit(var Module: TPasModule);
- var
- AUnitName: String;
- begin
- Module := nil;
- AUnitName := ExpectIdentifier;
- NextToken;
- while CurToken = tkDot do
- begin
- ExpectIdentifier;
- AUnitName := AUnitName + '.' + CurTokenString;
- NextToken;
- end;
- UngetToken;
- Module := TPasModule(CreateElement(TPasModule, AUnitName,
- Engine.Package));
- FCurModule:=Module;
- try
- if Assigned(Engine.Package) then
- begin
- Module.PackageName := Engine.Package.Name;
- Engine.Package.Modules.Add(Module);
- end;
- CheckHint(Module,True);
- // ExpectToken(tkSemicolon);
- ExpectToken(tkInterface);
- If LogEvent(pleInterface) then
- DoLog(mtInfo,nLogStartInterface,SLogStartInterface);
- ParseInterface;
- Engine.FinishScope(stModule,Module);
- finally
- FCurModule:=nil;
- end;
- end;
- // Starts after the "program" token
- procedure TPasParser.ParseProgram(var Module: TPasModule; SkipHeader : Boolean = False);
- Var
- PP : TPasProgram;
- Section : TProgramSection;
- N : String;
- begin
- if SkipHeader then
- N:=ChangeFileExt(Scanner.CurFilename,'')
- else
- N:=ExpectIdentifier;
- Module := nil;
- PP:=TPasProgram(CreateElement(TPasProgram, N, Engine.Package));
- Module :=PP;
- FCurModule:=Module;
- try
- if Assigned(Engine.Package) then
- begin
- Module.PackageName := Engine.Package.Name;
- Engine.Package.Modules.Add(Module);
- end;
- if not SkipHeader then
- begin
- NextToken;
- If (CurToken=tkBraceOpen) then
- begin
- PP.InputFile:=ExpectIdentifier;
- NextToken;
- if Not (CurToken in [tkBraceClose,tkComma]) then
- ParseExc(nParserExpectedCommaRBracket,SParserExpectedCommaRBracket);
- If (CurToken=tkComma) then
- PP.OutPutFile:=ExpectIdentifier;
- ExpectToken(tkBraceClose);
- NextToken;
- end;
- if (CurToken<>tkSemicolon) then
- ParseExcTokenError(';');
- end;
- Section := TProgramSection(CreateElement(TProgramSection, '', CurModule));
- PP.ProgramSection := Section;
- ParseOptionalUsesList(Section);
- ParseDeclarations(Section);
- Engine.FinishScope(stModule,Module);
- finally
- FCurModule:=nil;
- end;
- end;
- procedure TPasParser.ParseLibrary(var Module: TPasModule);
- Var
- PP : TPasLibrary;
- Section : TLibrarySection;
- begin
- Module := nil;
- PP:=TPasLibrary(CreateElement(TPasLibrary, ExpectIdentifier, Engine.Package));
- Module :=PP;
- FCurModule:=Module;
- try
- if Assigned(Engine.Package) then
- begin
- Module.PackageName := Engine.Package.Name;
- Engine.Package.Modules.Add(Module);
- end;
- NextToken;
- if (CurToken<>tkSemicolon) then
- ParseExcTokenError(';');
- Section := TLibrarySection(CreateElement(TLibrarySection, '', CurModule));
- PP.LibrarySection := Section;
- ParseOptionalUsesList(Section);
- ParseDeclarations(Section);
- Engine.FinishScope(stModule,Module);
- finally
- FCurModule:=nil;
- end;
- end;
- procedure TPasParser.ParseOptionalUsesList(ASection: TPasSection);
- // checks if next token is Uses keyword and read uses list
- begin
- NextToken;
- if CurToken=tkuses then
- ParseUsesList(ASection)
- else begin
- CheckImplicitUsedUnits(ASection);
- Engine.FinishScope(stUsesList,ASection);
- UngetToken;
- end;
- end;
- // Starts after the "interface" token
- procedure TPasParser.ParseInterface;
- var
- Section: TInterfaceSection;
- begin
- Section := TInterfaceSection(CreateElement(TInterfaceSection, '', CurModule));
- CurModule.InterfaceSection := Section;
- ParseOptionalUsesList(Section);
- ParseDeclarations(Section); // this also parses the Implementation section
- end;
- // Starts after the "implementation" token
- procedure TPasParser.ParseImplementation;
- var
- Section: TImplementationSection;
- begin
- Section := TImplementationSection(CreateElement(TImplementationSection, '', CurModule));
- CurModule.ImplementationSection := Section;
- ParseOptionalUsesList(Section);
- ParseDeclarations(Section);
- end;
- procedure TPasParser.ParseInitialization;
- var
- Section: TInitializationSection;
- SubBlock: TPasImplElement;
- begin
- Section := TInitializationSection(CreateElement(TInitializationSection, '', CurModule));
- CurModule.InitializationSection := Section;
- repeat
- NextToken;
- if (CurToken=tkend) then
- begin
- ExpectToken(tkDot);
- exit;
- end
- else if (CurToken=tkfinalization) then
- begin
- ParseFinalization;
- exit;
- end
- else if CurToken<>tkSemiColon then
- begin
- UngetToken;
- ParseStatement(Section,SubBlock);
- if SubBlock=nil then
- ExpectToken(tkend);
- end;
- until false;
- end;
- procedure TPasParser.ParseFinalization;
- var
- Section: TFinalizationSection;
- SubBlock: TPasImplElement;
- begin
- Section := TFinalizationSection(CreateElement(TFinalizationSection, '', CurModule));
- CurModule.FinalizationSection := Section;
- repeat
- NextToken;
- if (CurToken=tkend) then
- begin
- ExpectToken(tkDot);
- exit;
- end
- else if CurToken<>tkSemiColon then
- begin
- UngetToken;
- ParseStatement(Section,SubBlock);
- if SubBlock=nil then
- ExpectToken(tkend);
- end;
- until false;
- UngetToken;
- end;
- function TPasParser.GetProcTypeFromToken(tk: TToken; IsClass: Boolean
- ): TProcType;
- begin
- Case tk of
- tkProcedure :
- if IsClass then
- Result:=ptClassProcedure
- else
- Result:=ptProcedure;
- tkFunction:
- if IsClass then
- Result:=ptClassFunction
- else
- Result:=ptFunction;
- tkConstructor:
- if IsClass then
- Result:=ptClassConstructor
- else
- Result:=ptConstructor;
- tkDestructor:
- if IsClass then
- Result:=ptClassDestructor
- else
- Result:=ptDestructor;
- tkOperator:
- if IsClass then
- Result:=ptClassOperator
- else
- Result:=ptOperator;
- else
- ParseExc(nParserNotAProcToken,SParserNotAProcToken);
- end;
- end;
- procedure TPasParser.ParseDeclarations(Declarations: TPasDeclarations);
- var
- CurBlock: TDeclType;
- procedure SetBlock(NewBlock: TDeclType);
- begin
- if CurBlock=NewBlock then exit;
- if CurBlock=declType then
- Engine.FinishScope(stTypeSection,Declarations);
- CurBlock:=NewBlock;
- Scanner.SetForceCaret(NewBlock=declType);
- end;
- var
- ConstEl: TPasConst;
- ResStrEl: TPasResString;
- TypeEl: TPasType;
- ClassEl: TPasClassType;
- ArrEl : TPasArrayType;
- List: TFPList;
- i,j: Integer;
- VarEl: TPasVariable;
- ExpEl: TPasExportSymbol;
- PropEl : TPasProperty;
- TypeName: String;
- PT : TProcType;
- NamePos: TPasSourcePos;
- ok: Boolean;
- Proc: TPasProcedure;
- begin
- CurBlock := declNone;
- while True do
- begin
- NextToken;
- // writeln('TPasParser.ParseSection Token=',CurTokenString,' ',CurToken, ' ',scanner.CurFilename);
- case CurToken of
- tkend:
- begin
- If (CurModule is TPasProgram) and (CurModule.InitializationSection=Nil) then
- ParseExcTokenError('begin');
- ExpectToken(tkDot);
- break;
- end;
- tkimplementation:
- if (Declarations is TInterfaceSection) then
- begin
- If Not Engine.InterfaceOnly then
- begin
- If LogEvent(pleImplementation) then
- DoLog(mtInfo,nLogStartImplementation,SLogStartImplementation);
- SetBlock(declNone);
- ParseImplementation;
- end;
- break;
- end;
- tkinitialization:
- if (Declarations is TInterfaceSection)
- or ((Declarations is TImplementationSection) and not (Declarations is TProgramSection)) then
- begin
- SetBlock(declNone);
- ParseInitialization;
- break;
- end;
- tkfinalization:
- if (Declarations is TInterfaceSection)
- or ((Declarations is TImplementationSection) and not (Declarations is TProgramSection)) then
- begin
- SetBlock(declNone);
- ParseFinalization;
- break;
- end;
- tkUses:
- if Declarations.ClassType=TInterfaceSection then
- ParseExcTokenError(TokenInfos[tkimplementation])
- else if Declarations is TPasSection then
- ParseExcTokenError(TokenInfos[tkend])
- else
- ParseExcSyntaxError;
- tkConst:
- SetBlock(declConst);
- tkexports:
- SetBlock(declExports);
- tkResourcestring:
- SetBlock(declResourcestring);
- tkType:
- SetBlock(declType);
- tkVar:
- SetBlock(declVar);
- tkThreadVar:
- SetBlock(declThreadVar);
- tkProperty:
- SetBlock(declProperty);
- tkProcedure, tkFunction, tkConstructor, tkDestructor,tkOperator:
- begin
- SetBlock(declNone);
- SaveComments;
- pt:=GetProcTypeFromToken(CurToken);
- AddProcOrFunction(Declarations, ParseProcedureOrFunctionDecl(Declarations, pt));
- end;
- tkClass:
- begin
- SetBlock(declNone);
- SaveComments;
- NextToken;
- If CurToken in [tkprocedure,tkFunction,tkConstructor, tkDestructor] then
- begin
- pt:=GetProcTypeFromToken(CurToken,True);
- AddProcOrFunction(Declarations,ParseProcedureOrFunctionDecl(Declarations, pt));
- end
- else
- ExpectToken(tkprocedure);
- end;
- tkIdentifier:
- begin
- SaveComments;
- case CurBlock of
- declConst:
- begin
- ConstEl := ParseConstDecl(Declarations);
- Declarations.Declarations.Add(ConstEl);
- Declarations.Consts.Add(ConstEl);
- end;
- declResourcestring:
- begin
- ResStrEl := ParseResourcestringDecl(Declarations);
- Declarations.Declarations.Add(ResStrEl);
- Declarations.ResStrings.Add(ResStrEl);
- end;
- declType:
- begin
- TypeEl := ParseTypeDecl(Declarations);
- // Scanner.SetForceCaret(OldForceCaret); // It may have been switched off
- if Assigned(TypeEl) then // !!!
- begin
- Declarations.Declarations.Add(TypeEl);
- if (TypeEl.ClassType = TPasClassType)
- and (not (po_keepclassforward in Options)) then
- begin
- // Remove previous forward declarations, if necessary
- for i := 0 to Declarations.Classes.Count - 1 do
- begin
- ClassEl := TPasClassType(Declarations.Classes[i]);
- if CompareText(ClassEl.Name, TypeEl.Name) = 0 then
- begin
- Declarations.Classes.Delete(i);
- for j := 0 to Declarations.Declarations.Count - 1 do
- if CompareText(TypeEl.Name,
- TPasElement(Declarations.Declarations[j]).Name) = 0 then
- begin
- Declarations.Declarations.Delete(j);
- break;
- end;
- ClassEl.Release;
- break;
- end;
- end;
- // Add the new class to the class list
- Declarations.Classes.Add(TypeEl)
- end else
- Declarations.Types.Add(TypeEl);
- end;
- end;
- declExports:
- begin
- List := TFPList.Create;
- try
- ok:=false;
- try
- ParseExportDecl(Declarations, List);
- ok:=true;
- finally
- if not ok then
- for i := 0 to List.Count - 1 do
- TPasExportSymbol(List[i]).Release;
- end;
- for i := 0 to List.Count - 1 do
- begin
- ExpEl := TPasExportSymbol(List[i]);
- Declarations.Declarations.Add(ExpEl);
- Declarations.ExportSymbols.Add(ExpEl);
- end;
- finally
- List.Free;
- end;
- end;
- declVar, declThreadVar:
- begin
- List := TFPList.Create;
- try
- ParseVarDecl(Declarations, List);
- for i := 0 to List.Count - 1 do
- begin
- VarEl := TPasVariable(List[i]);
- Engine.FinishScope(stDeclaration,VarEl);
- Declarations.Declarations.Add(VarEl);
- Declarations.Variables.Add(VarEl);
- end;
- CheckToken(tkSemicolon);
- finally
- List.Free;
- end;
- end;
- declProperty:
- begin
- PropEl:=ParseProperty(Declarations,CurtokenString,visDefault,false);
- Declarations.Declarations.Add(PropEl);
- Declarations.Properties.Add(PropEl);
- end;
- else
- ParseExcSyntaxError;
- end;
- end;
- tkGeneric:
- begin
- if CurBlock <> declType then
- ParseExcSyntaxError;
- TypeName := ExpectIdentifier;
- NamePos:=Scanner.CurSourcePos;
- List:=TFPList.Create;
- try
- ReadGenericArguments(List,Nil);
- ExpectToken(tkEqual);
- NextToken;
- Case CurToken of
- tkObject,
- tkClass :
- begin
- ClassEl := TPasClassType(CreateElement(TPasClassType,
- TypeName, Declarations, NamePos));
- ClassEl.SetGenericTemplates(List);
- NextToken;
- DoParseClassType(ClassEl);
- Declarations.Declarations.Add(ClassEl);
- Declarations.Classes.Add(ClassEl);
- CheckHint(classel,True);
- end;
- tkArray:
- begin
- if List.Count<>1 then
- ParseExc(nParserGenericArray1Element,sParserGenericArray1Element);
- ArrEl:=TPasArrayType(ParseArrayType(Declarations,NamePos,TypeName,pmNone));
- CheckHint(ArrEl,True);
- ArrEl.ElType.Release;
- ArrEl.elType:=TPasGenericTemplateType(List[0]);
- Declarations.Declarations.Add(ArrEl);
- Declarations.Types.Add(ArrEl);
- end;
- else
- ParseExc(nParserGenericClassOrArray,SParserGenericClassOrArray);
- end;
- finally
- List.Free;
- end;
- end;
- tkbegin:
- begin
- if Declarations is TProcedureBody then
- begin
- Proc:=Declarations.Parent as TPasProcedure;
- if pmAssembler in Proc.Modifiers then
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,['asm']);
- SetBlock(declNone);
- ParseProcBeginBlock(TProcedureBody(Declarations));
- break;
- end
- else if (Declarations is TInterfaceSection)
- or (Declarations is TImplementationSection) then
- begin
- SetBlock(declNone);
- ParseInitialization;
- break;
- end
- else
- ParseExcSyntaxError;
- end;
- tkasm:
- begin
- if Declarations is TProcedureBody then
- begin
- Proc:=Declarations.Parent as TPasProcedure;
- if not (pmAssembler in Proc.Modifiers) then
- ParseExc(nParserExpectTokenError,SParserExpectTokenError,['begin']);
- SetBlock(declNone);
- ParseProcAsmBlock(TProcedureBody(Declarations));
- break;
- end
- else
- ParseExcSyntaxError;
- end;
- tklabel:
- begin
- SetBlock(declNone);
- if not (Declarations is TInterfaceSection) then
- ParseLabels(Declarations);
- end;
- else
- ParseExcSyntaxError;
- end;
- end;
- SetBlock(declNone);
- end;
- function TPasParser.CheckUseUnit(ASection: TPasSection; AUnitName: string
- ): TPasElement;
- procedure CheckDuplicateInUsesList(AUnitName : string; UsesList: TFPList);
- var
- i: Integer;
- begin
- if UsesList=nil then exit;
- for i:=0 to UsesList.Count-1 do
- if CompareText(AUnitName,TPasModule(UsesList[i]).Name)=0 then
- ParseExc(nParserDuplicateIdentifier,SParserDuplicateIdentifier,[AUnitName]);
- end;
- begin
- if CompareText(AUnitName,CurModule.Name)=0 then
- begin
- // System is implicit, except when parsing system unit.
- if CompareText(AUnitName,'System')=0 then
- exit;
- ParseExc(nParserDuplicateIdentifier,SParserDuplicateIdentifier,[AUnitName]);
- end;
- CheckDuplicateInUsesList(AUnitName,ASection.UsesList);
- if ASection.ClassType=TImplementationSection then
- CheckDuplicateInUsesList(AUnitName,CurModule.InterfaceSection.UsesList);
- result := Engine.FindModule(AUnitName); // should we resolve module here when "IN" filename is not known yet?
- if Assigned(result) then
- result.AddRef
- else
- Result := TPasUnresolvedUnitRef(CreateElement(TPasUnresolvedUnitRef,
- AUnitName, ASection));
- ASection.UsesList.Add(Result);
- end;
- procedure TPasParser.CheckImplicitUsedUnits(ASection: TPasSection);
- var
- i: Integer;
- begin
- If not (ASection.ClassType=TImplementationSection) Then // interface,program,library,package
- begin
- // load implicit units, like 'System'
- for i:=0 to ImplicitUses.Count-1 do
- CheckUseUnit(ASection,ImplicitUses[i]);
- end;
- end;
- // Starts after the "uses" token
- procedure TPasParser.ParseUsesList(ASection: TPasSection);
- var
- AUnitName: String;
- Element: TPasElement;
- begin
- CheckImplicitUsedUnits(ASection);
- Repeat
- AUnitName := ExpectIdentifier;
- NextToken;
- while CurToken = tkDot do
- begin
- ExpectIdentifier;
- AUnitName := AUnitName + '.' + CurTokenString;
- NextToken;
- end;
- Element := CheckUseUnit(ASection,AUnitName);
- if (CurToken=tkin) then
- begin
- ExpectToken(tkString);
- if (Element is TPasModule) and (TPasmodule(Element).filename='') then
- TPasModule(Element).FileName:=curtokenstring
- else if (Element is TPasUnresolvedUnitRef) then
- TPasUnresolvedUnitRef(Element).FileName:=curtokenstring;
- NextToken;
- end;
- if Not (CurToken in [tkComma,tkSemicolon]) then
- ParseExc(nParserExpectedCommaSemicolon,SParserExpectedCommaSemicolon);
- Until (CurToken=tkSemicolon);
- Engine.FinishScope(stUsesList,ASection);
- end;
- // Starts after the variable name
- function TPasParser.ParseConstDecl(Parent: TPasElement): TPasConst;
- var
- OldForceCaret,ok: Boolean;
- begin
- SaveComments;
- Result := TPasConst(CreateElement(TPasConst, CurTokenString, Parent));
- if Parent is TPasClassType then
- Include(Result.VarModifiers,vmClass);
- ok:=false;
- try
- NextToken;
- if CurToken = tkColon then
- begin
- OldForceCaret:=Scanner.SetForceCaret(True);
- try
- Result.VarType := ParseType(Result,Scanner.CurSourcePos);
- finally
- Scanner.SetForceCaret(OldForceCaret);
- end;
- { if Result.VarType is TPasRangeType then
- Ungettoken; // Range type stops on token after last range token}
- end
- else
- UngetToken;
- ExpectToken(tkEqual);
- NextToken;
- Result.Expr:=DoParseConstValueExpression(Result);
- UngetToken;
- CheckHint(Result,True);
- ok:=true;
- finally
- if not ok then
- ReleaseAndNil(TPasElement(Result));
- end;
- Engine.FinishScope(stConstDef,Result);
- end;
- // Starts after the variable name
- function TPasParser.ParseResourcestringDecl(Parent: TPasElement): TPasResString;
- var
- ok: Boolean;
- begin
- SaveComments;
- Result := TPasResString(CreateElement(TPasResString, CurTokenString, Parent));
- ok:=false;
- try
- ExpectToken(tkEqual);
- NextToken; // skip tkEqual
- Result.Expr:=DoParseConstValueExpression(Result);
- UngetToken;
- CheckHint(Result,True);
- ok:=true;
- finally
- if not ok then
- ReleaseAndNil(TPasElement(Result));
- end;
- end;
- procedure TPasParser.ReadGenericArguments(List : TFPList;Parent : TPasElement);
- Var
- N : String;
- begin
- ExpectToken(tkLessThan);
- repeat
- N:=ExpectIdentifier;
- List.Add(CreateElement(TPasGenericTemplateType,N,Parent));
- NextToken;
- if not (CurToken in [tkComma, tkGreaterThan]) then
- ParseExc(nParserExpectToken2Error,SParserExpectToken2Error,
- [TokenInfos[tkComma], TokenInfos[tkGreaterThan]]);
- until CurToken = tkGreaterThan;
- end;
- // Starts after the type name
- function TPasParser.ParseRangeType(AParent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String; Full: Boolean
- ): TPasRangeType;
- Var
- PE : TPasExpr;
- ok: Boolean;
- begin
- Result := TPasRangeType(CreateElement(TPasRangeType, TypeName, AParent, NamePos));
- ok:=false;
- try
- if Full then
- begin
- If not (CurToken=tkEqual) then
- ParseExcTokenError(TokenInfos[tkEqual]);
- end;
- NextToken;
- PE:=DoParseExpression(Result,Nil,False);
- if not ((PE is TBinaryExpr) and (TBinaryExpr(PE).Kind=pekRange)) then
- begin
- PE.Release;
- ParseExc(nRangeExpressionExpected,SRangeExpressionExpected);
- end;
- Result.RangeExpr:=PE as TBinaryExpr;
- UngetToken;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- Engine.FinishScope(stTypeDef,Result);
- end;
- // Starts after Exports, on first identifier.
- procedure TPasParser.ParseExportDecl(Parent: TPasElement; List: TFPList);
- Var
- E : TPasExportSymbol;
- begin
- Repeat
- if List.Count<>0 then
- ExpectIdentifier;
- E:=TPasExportSymbol(CreateElement(TPasExportSymbol,CurtokenString,Parent));
- List.Add(E);
- NextToken;
- if CurTokenIsIdentifier('INDEX') then
- begin
- NextToken;
- E.Exportindex:=DoParseExpression(E,Nil)
- end
- else if CurTokenIsIdentifier('NAME') then
- begin
- NextToken;
- E.ExportName:=DoParseExpression(E,Nil)
- end;
- if not (CurToken in [tkComma,tkSemicolon]) then
- ParseExc(nParserExpectedCommaSemicolon,SParserExpectedCommaSemicolon);
- until (CurToken=tkSemicolon);
- end;
- function TPasParser.ParseSpecializeType(Parent: TPasElement;
- const TypeName: String): TPasClassType;
- begin
- NextToken;
- Result:=ParseSimpleType(Parent,Scanner.CurSourcePos,TypeName) as TPasClassType;
- end;
- function TPasParser.ParseProcedureType(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: String; const PT: TProcType
- ): TPasProcedureType;
- var
- ok: Boolean;
- begin
- if PT in [ptFunction,ptClassFunction] then
- Result := CreateFunctionType(TypeName, 'Result', Parent, False, NamePos)
- else
- Result := TPasProcedureType(CreateElement(TPasProcedureType, TypeName, Parent, NamePos));
- ok:=false;
- try
- ParseProcedureOrFunctionHeader(Result, TPasProcedureType(Result), PT, True);
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType;
- var
- TypeName: String;
- NamePos: TPasSourcePos;
- OldForceCaret : Boolean;
- List : TFPList;
- begin
- TypeName := CurTokenString;
- NamePos:=Scanner.CurSourcePos;
- List:=Nil;
- OldForceCaret:=Scanner.SetForceCaret(True);
- try
- NextToken;
- if (CurToken=tkLessThan) and (msDelphi in CurrentModeswitches) then
- List:=TFPList.Create;
- UnGetToken; // ReadGenericArguments starts at <
- if Assigned(List) then
- ReadGenericArguments(List,Parent);
- ExpectToken(tkEqual);
- Result:=ParseType(Parent,NamePos,TypeName,True,List);
- finally
- Scanner.SetForceCaret(OldForceCaret);
- List.Free;
- end;
- end;
- function TPasParser.GetVariableValueAndLocation(Parent: TPasElement; out
- Value: TPasExpr; out Location: String): Boolean;
- begin
- Value:=Nil;
- NextToken;
- Result:=CurToken=tkEqual;
- if Result then
- begin
- NextToken;
- Value := DoParseConstValueExpression(Parent);
- // NextToken;
- end;
- if (CurToken=tkAbsolute) then
- begin
- Result:=True;
- ExpectIdentifier;
- Location:=CurTokenText;
- NextToken;
- if CurToken=tkDot then
- begin
- ExpectIdentifier;
- Location:=Location+'.'+CurTokenText;
- end
- else
- UnGetToken;
- end
- else
- UngetToken;
- end;
- function TPasParser.GetVariableModifiers(Parent: TPasElement; out
- VarMods: TVariableModifiers; out LibName, ExportName: TPasExpr;
- ExternalClass: Boolean): string;
- Var
- S : String;
- ExtMod: TVariableModifier;
- begin
- Result := '';
- LibName := nil;
- ExportName := nil;
- VarMods := [];
- NextToken;
- If CurTokenIsIdentifier('cvar') and not ExternalClass then
- begin
- Result:=';cvar';
- Include(VarMods,vmcvar);
- ExpectToken(tkSemicolon);
- NextToken;
- end;
- s:=LowerCase(CurTokenText);
- if s='external' then
- ExtMod:=vmExternal
- else if (s='public') and not externalclass then
- ExtMod:=vmPublic
- else if (s='export') and not externalclass then
- ExtMod:=vmExport
- else
- begin
- UngetToken;
- exit;
- end;
- Include(varMods,ExtMod);
- Result:=Result+';'+CurTokenText;
- NextToken;
- if not (CurToken in [tkString,tkIdentifier]) then
- begin
- if (CurToken=tkSemicolon) and (ExtMod in [vmExternal,vmPublic]) then
- exit;
- ParseExcSyntaxError;
- end;
- // export name exportname;
- // public;
- // public name exportname;
- // external;
- // external libname;
- // external libname name exportname;
- // external name exportname;
- if (ExtMod=vmExternal) and (CurToken in [tkString,tkIdentifier])
- and Not (CurTokenIsIdentifier('name')) and not ExternalClass then
- begin
- Result := Result + ' ' + CurTokenText;
- LibName:=DoParseExpression(Parent);
- end;
- if not CurTokenIsIdentifier('name') then
- ParseExcSyntaxError;
- NextToken;
- if not (CurToken in [tkChar,tkString,tkIdentifier]) then
- ParseExcTokenError(TokenInfos[tkString]);
- Result := Result + ' ' + CurTokenText;
- ExportName:=DoParseExpression(Parent);
- end;
- // Full means that a full variable declaration is being parsed.
- procedure TPasParser.ParseVarList(Parent: TPasElement; VarList: TFPList;
- AVisibility: TPasMemberVisibility; Full : Boolean);
- // on Exception the VarList is restored, no need to Release the new elements
- var
- i, OldListCount: Integer;
- Value , aLibName, aExpName: TPasExpr;
- VarType: TPasType;
- VarEl: TPasVariable;
- H : TPasMemberHints;
- VarMods: TVariableModifiers;
- D,Mods,Loc: string;
- OldForceCaret,ok,ExternalClass: Boolean;
- begin
- Value:=Nil;
- aLibName:=nil;
- aExpName:=nil;
- OldListCount:=VarList.Count;
- ok:=false;
- try
- D:=SaveComments; // This means we support only one comment per 'list'.
- VarEl:=nil;
- Repeat
- // create the TPasVariable here, so that SourceLineNumber is correct
- VarEl:=TPasVariable(CreateElement(TPasVariable,CurTokenString,Parent,AVisibility));
- VarList.Add(VarEl);
- NextToken;
- if Not (CurToken in [tkComma,tkColon]) then
- ParseExc(nParserExpectedCommaColon,SParserExpectedCommaColon);
- if CurToken=tkComma then
- ExpectIdentifier;
- Until (CurToken=tkColon);
- OldForceCaret:=Scanner.SetForceCaret(True);
- try
- VarType := ParseComplexType(VarEl);
- finally
- Scanner.SetForceCaret(OldForceCaret);
- end;
- // read type
- for i := OldListCount to VarList.Count - 1 do
- begin
- VarEl:=TPasVariable(VarList[i]);
- // Writeln(VarEl.Name, AVisibility);
- VarEl.VarType := VarType;
- //VarType.Parent := VarEl; // this is wrong for references
- if (i>=OldListCount) then
- VarType.AddRef;
- end;
- H:=CheckHint(Nil,False);
- If Full then
- GetVariableValueAndLocation(Parent,Value,Loc);
- if (Value<>nil) and (VarList.Count>OldListCount+1) then
- ParseExc(nParserOnlyOneVariableCanBeInitialized,SParserOnlyOneVariableCanBeInitialized);
- TPasVariable(VarList[OldListCount]).Expr:=Value;
- Value:=nil;
- // Note: external members are allowed for non external classes too
- ExternalClass:=(msExternalClass in CurrentModeSwitches)
- and (Parent is TPasClassType);
- H:=H+CheckHint(Nil,False);
- if Full or Externalclass then
- begin
- NextToken;
- If Curtoken<>tkSemicolon then
- UnGetToken;
- Mods:=GetVariableModifiers(Parent,VarMods,aLibName,aExpName,ExternalClass);
- if (mods='') and (CurToken<>tkSemicolon) then
- NextToken;
- end
- else
- begin
- NextToken;
- VarMods:=[];
- Mods:='';
- end;
- SaveComments(D);
- // connect
- for i := OldListCount to VarList.Count - 1 do
- begin
- VarEl:=TPasVariable(VarList[i]);
- // Writeln(VarEl.Name, AVisibility);
- // Procedure declaration eats the hints.
- if Assigned(VarType) and (VarType is TPasProcedureType) then
- VarEl.Hints:=VarType.Hints
- else
- VarEl.Hints:=H;
- VarEl.Modifiers:=Mods;
- VarEl.VarModifiers:=VarMods;
- VarEl.AbsoluteLocation:=Loc;
- if aLibName<>nil then
- begin
- VarEl.LibraryName:=aLibName;
- aLibName.AddRef;
- end;
- if aExpName<>nil then
- begin
- VarEl.ExportName:=aExpName;
- aExpName.AddRef;
- end;
- end;
- ok:=true;
- finally
- if aLibName<>nil then aLibName.Release;
- if aExpName<>nil then aExpName.Release;
- if not ok then
- begin
- if Value<>nil then Value.Release;
- for i:=OldListCount to VarList.Count-1 do
- TPasElement(VarList[i]).Release;
- VarList.Count:=OldListCount;
- end;
- end;
- end;
- procedure TPasParser.SetOptions(AValue: TPOptions);
- begin
- if FOptions=AValue then Exit;
- FOptions:=AValue;
- If Assigned(FScanner) then
- FScanner.Options:=AValue;
- end;
- function TPasParser.SaveComments: String;
- begin
- if Engine.NeedComments then
- FSavedComments:=CurComments.Text; // Expensive, so don't do unless needed.
- Result:=FSavedComments;
- end;
- function TPasParser.SaveComments(const AValue: String): String;
- begin
- FSavedComments:=AValue;
- Result:=FSavedComments;
- end;
- function TPasParser.LogEvent(E: TPParserLogEvent): Boolean;
- begin
- Result:=E in FLogEvents;
- end;
- procedure TPasParser.SetLastMsg(MsgType: TMessageType; MsgNumber: integer;
- const Fmt: String; Args: array of const);
- begin
- FLastMsgType := MsgType;
- FLastMsgNumber := MsgNumber;
- FLastMsgPattern := Fmt;
- FLastMsg := SafeFormat(Fmt,Args);
- CreateMsgArgs(FLastMsgArgs,Args);
- end;
- procedure TPasParser.DoLog(MsgType: TMessageType; MsgNumber: integer;
- const Msg: String; SkipSourceInfo: Boolean);
- begin
- DoLog(MsgType,MsgNumber,Msg,[],SkipSourceInfo);
- end;
- procedure TPasParser.DoLog(MsgType: TMessageType; MsgNumber: integer;
- const Fmt: String; Args: array of const; SkipSourceInfo: Boolean);
- begin
- SetLastMsg(MsgType,MsgNumber,Fmt,Args);
- If Assigned(FOnLog) then
- if SkipSourceInfo or not assigned(scanner) then
- FOnLog(Self,FLastMsg)
- else
- FOnLog(Self,Format('%s(%d) : %s',[Scanner.CurFilename,Scanner.CurRow,FLastMsg]));
- end;
- procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; List: TFPList;
- AVisibility: TPasMemberVisibility = VisDefault; ClosingBrace: Boolean = False);
- Var
- tt : TTokens;
- begin
- ParseVarList(Parent,List,AVisibility,False);
- tt:=[tkEnd,tkSemicolon];
- if ClosingBrace then
- include(tt,tkBraceClose);
- if not (CurToken in tt) then
- ParseExc(nParserExpectedSemiColonEnd,SParserExpectedSemiColonEnd);
- end;
- // Starts after the variable name
- procedure TPasParser.ParseVarDecl(Parent: TPasElement; List: TFPList);
- begin
- ParseVarList(Parent,List,visDefault,True);
- end;
- // Starts after the opening bracket token
- procedure TPasParser.ParseArgList(Parent: TPasElement; Args: TFPList; EndToken: TToken);
- var
- IsUntyped, ok, LastHadDefaultValue: Boolean;
- Name : String;
- Value : TPasExpr;
- i, OldArgCount: Integer;
- Arg: TPasArgument;
- Access: TArgumentAccess;
- ArgType: TPasType;
- begin
- LastHadDefaultValue := false;
- while True do
- begin
- OldArgCount:=Args.Count;
- Access := argDefault;
- IsUntyped := False;
- ArgType := nil;
- while True do
- begin
- NextToken;
- if CurToken = tkConst then
- begin
- Access := argConst;
- Name := ExpectIdentifier;
- end else if CurToken = tkConstRef then
- begin
- Access := argConstref;
- Name := ExpectIdentifier;
- end else if CurToken = tkVar then
- begin
- Access := ArgVar;
- Name := ExpectIdentifier;
- end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OUT') then
- begin
- Access := ArgOut;
- Name := ExpectIdentifier;
- end else if CurToken = tkIdentifier then
- Name := CurTokenString
- else
- ParseExc(nParserExpectedConstVarID,SParserExpectedConstVarID);
- Arg := TPasArgument(CreateElement(TPasArgument, Name, Parent));
- Arg.Access := Access;
- Args.Add(Arg);
- NextToken;
- if CurToken = tkColon then
- break
- else if ((CurToken = tkSemicolon) or (CurToken = tkBraceClose)) and
- (Access <> argDefault) then
- begin
- // found an untyped const or var argument
- UngetToken;
- IsUntyped := True;
- break
- end
- else if CurToken <> tkComma then
- ParseExc(nParserExpectedCommaColon,SParserExpectedCommaColon);
- end;
- Value:=Nil;
- if not IsUntyped then
- begin
- Arg := TPasArgument(Args[0]);
- ArgType := ParseType(Arg,Scanner.CurSourcePos);
- ok:=false;
- try
- NextToken;
- if CurToken = tkEqual then
- begin
- if (Args.Count>OldArgCount+1) then
- begin
- ArgType.Release;
- ArgType:=nil;
- ParseExc(nParserOnlyOneArgumentCanHaveDefault,SParserOnlyOneArgumentCanHaveDefault);
- end;
- if Parent is TPasProperty then
- ParseExc(nParserPropertyArgumentsCanNotHaveDefaultValues,
- SParserPropertyArgumentsCanNotHaveDefaultValues);
- NextToken;
- Value := DoParseExpression(Parent,Nil);
- // After this, we're on ), which must be unget.
- LastHadDefaultValue:=true;
- end
- else if LastHadDefaultValue then
- ParseExc(nParserDefaultParameterRequiredFor,
- SParserDefaultParameterRequiredFor,[TPasArgument(Args[OldArgCount]).Name]);
- UngetToken;
- ok:=true;
- finally
- if (not ok) and (ArgType<>nil) then
- ArgType.Release;
- end;
- end;
- for i := OldArgCount to Args.Count - 1 do
- begin
- Arg := TPasArgument(Args[i]);
- Arg.ArgType := ArgType;
- if Assigned(ArgType) then
- begin
- if (i > OldArgCount) then
- ArgType.AddRef;
- end;
- Arg.ValueExpr := Value;
- Value:=Nil; // Only the first gets a value. OK, since Var A,B : Integer = 1 is not allowed.
- end;
- for i := OldArgCount to Args.Count - 1 do
- Engine.FinishScope(stDeclaration,TPasArgument(Args[i]));
- NextToken;
- if (CurToken = tkIdentifier) and (LowerCase(CurTokenString) = 'location') then
- begin
- NextToken; // remove 'location'
- NextToken; // remove register
- end;
- if CurToken = EndToken then
- break;
- end;
- end;
- function TPasParser.CheckProcedureArgs(Parent: TPasElement; Args: TFPList;
- Mandatory: Boolean): boolean;
- begin
- NextToken;
- case CurToken of
- tkBraceOpen:
- begin
- Result:=true;
- NextToken;
- if (CurToken<>tkBraceClose) then
- begin
- UngetToken;
- ParseArgList(Parent, Args, tkBraceClose);
- end;
- end;
- tkSemicolon,tkColon,tkof,tkis,tkIdentifier:
- begin
- Result:=false;
- if Mandatory then
- ParseExc(nParserExpectedLBracketColon,SParserExpectedLBracketColon)
- else
- UngetToken;
- end
- else
- ParseExcTokenError(';');
- end;
- end;
- procedure TPasParser.HandleProcedureModifier(Parent: TPasElement; pm: TProcedureModifier);
- Var
- Tok : String;
- P : TPasProcedure;
- E : TPasExpr;
- procedure AddModifier;
- begin
- if pm in P.Modifiers then
- ParseExcSyntaxError;
- P.AddModifier(pm);
- end;
- begin
- P:=TPasProcedure(Parent);
- if pm<>pmPublic then
- AddModifier;
- Case pm of
- pmExternal:
- begin
- NextToken;
- if CurToken in [tkString,tkIdentifier] then
- begin
- // external libname
- // external libname name XYZ
- // external name XYZ
- Tok:=UpperCase(CurTokenString);
- if Not ((CurToken=tkIdentifier) and (Tok='NAME')) then
- begin
- E:=DoParseExpression(Parent);
- if Assigned(P) then
- P.LibraryExpr:=E;
- end;
- if CurToken=tkSemicolon then
- UnGetToken
- else
- begin
- Tok:=UpperCase(CurTokenString);
- if ((CurToken=tkIdentifier) and (Tok='NAME')) then
- begin
- NextToken;
- if not (CurToken in [tkChar,tkString,tkIdentifier]) then
- ParseExcTokenError(TokenInfos[tkString]);
- E:=DoParseExpression(Parent);
- if Assigned(P) then
- P.LibrarySymbolName:=E;
- end;
- end;
- end
- else
- UngetToken;
- end;
- pmPublic:
- begin
- NextToken;
- If not CurTokenIsIdentifier('name') then
- begin
- if P.Parent is TPasClassType then
- begin
- // public section starts
- UngetToken;
- UngetToken;
- exit;
- end;
- AddModifier;
- CheckToken(tkSemicolon);
- exit;
- end
- else
- begin
- AddModifier;
- NextToken; // Should be export name string.
- if not (CurToken in [tkString,tkIdentifier]) then
- ParseExcTokenError(TokenInfos[tkString]);
- E:=DoParseExpression(Parent);
- if Parent is TPasProcedure then
- TPasProcedure(Parent).PublicName:=E;
- if (CurToken <> tkSemicolon) then
- ParseExcTokenError(TokenInfos[tkSemicolon]);
- end;
- end;
- pmForward:
- begin
- if (Parent.Parent is TInterfaceSection) then
- begin
- ParseExc(nParserForwardNotInterface,SParserForwardNotInterface);
- UngetToken;
- end;
- end;
- pmMessage:
- begin
- Repeat
- NextToken;
- If CurToken<>tkSemicolon then
- begin
- if Parent is TPasProcedure then
- TPasProcedure(Parent).MessageName:=CurtokenString;
- If (CurToken=tkString) and (Parent is TPasProcedure) then
- TPasProcedure(Parent).Messagetype:=pmtString;
- end;
- until CurToken = tkSemicolon;
- UngetToken;
- end;
- pmDispID:
- begin
- TPasProcedure(Parent).DispIDExpr:=DoParseExpression(Parent,Nil);
- if CurToken = tkSemicolon then
- UngetToken;
- end;
- end; // Case
- end;
- procedure TPasParser.HandleProcedureTypeModifier(ProcType: TPasProcedureType;
- ptm: TProcTypeModifier);
- begin
- if ptm in ProcType.Modifiers then
- ParseExcSyntaxError;
- Include(ProcType.Modifiers,ptm);
- end;
- // Next token is expected to be a "(", ";" or for a function ":". The caller
- // will get the token after the final ";" as next token.
- procedure TPasParser.ParseProcedureOrFunctionHeader(Parent: TPasElement;
- Element: TPasProcedureType; ProcType: TProcType; OfObjectPossible: Boolean);
- Function FindInSection(AName : String;ASection : TPasSection) : Boolean;
- Var
- I : integer;
- Cn,FN : String;
- CT : TPasClassType;
- begin
- // ToDo: add an event for the resolver to use a faster lookup
- I:=ASection.Functions.Count-1;
- While (I>=0) and (CompareText(TPasElement(ASection.Functions[I]).Name,AName)<>0) do
- Dec(I);
- Result:=I<>-1;
- I:=Pos('.',AName);
- if (Not Result) and (I<>0) then
- begin
- CN:=Copy(AName,1,I-1);
- FN:=Aname;
- Delete(FN,1,I);
- I:=Asection.Classes.Count-1;
- While Not Result and (I>=0) do
- begin
- CT:=TPasClassType(ASection.Classes[i]);
- if CompareText(CT.Name,CN)=0 then
- Result:=CT.FindMember(TPasFunction, FN)<>Nil;
- Dec(I);
- end;
- end;
- end;
- procedure ConsumeSemi;
- begin
- NextToken;
- if (CurToken <> tkSemicolon) and IsCurTokenHint then
- UngetToken;
- end;
- function DoCheckHint : Boolean;
- var
- ahint : TPasMemberHint;
- begin
- Result:= IsCurTokenHint(ahint);
- if Result then // deprecated,platform,experimental,library, unimplemented etc
- begin
- Element.Hints:=Element.Hints+[ahint];
- if aHint=hDeprecated then
- begin
- NextToken;
- if (CurToken<>tkString) then
- UngetToken
- else
- Element.HintMessage:=CurTokenString;
- end;
- end;
- end;
- Var
- Tok : String;
- CC : TCallingConvention;
- PM : TProcedureModifier;
- Done: Boolean;
- ResultEl: TPasResultElement;
- OK,IsProc : Boolean;
- PTM: TProcTypeModifier;
- ModCount: Integer;
- LastToken: TToken;
- begin
- // Element must be non-nil. Removed all checks for not-nil.
- // If it is nil, the following fails anyway.
- CheckProcedureArgs(Element,Element.Args,ProcType in [ptOperator,ptClassOperator]);
- IsProc:=Parent is TPasProcedure;
- case ProcType of
- ptFunction,ptClassFunction:
- begin
- NextToken;
- if CurToken = tkColon then
- begin
- ResultEl:=TPasFunctionType(Element).ResultEl;
- ResultEl.ResultType := ParseType(ResultEl,Scanner.CurSourcePos);
- end
- // In Delphi mode, the implementation in the implementation section can be without result as it was declared
- // We actually check if the function exists in the interface section.
- else if (msDelphi in CurrentModeswitches) and
- (Assigned(CurModule.ImplementationSection) or
- (CurModule is TPasProgram)) then
- begin
- if Assigned(CurModule.InterfaceSection) then
- OK:=FindInSection(Parent.Name,CurModule.InterfaceSection)
- else if (CurModule is TPasProgram) and Assigned(TPasProgram(CurModule).ProgramSection) then
- OK:=FindInSection(Parent.Name,TPasProgram(CurModule).ProgramSection);
- if Not OK then
- CheckToken(tkColon)
- else
- begin
- CheckToken(tkSemiColon);
- UngetToken;
- end;
- end
- else
- begin
- // Raise error
- CheckToken(tkColon);
- end;
- end;
- ptOperator,ptClassOperator:
- begin
- NextToken;
- ResultEl:=TPasFunctionType(Element).ResultEl;
- if (CurToken=tkIdentifier) then
- begin
- ResultEl.Name := CurTokenName;
- ExpectToken(tkColon);
- end
- else
- if (CurToken=tkColon) then
- ResultEl.Name := 'Result'
- else
- ParseExc(nParserExpectedColonID,SParserExpectedColonID);
- ResultEl.ResultType := ParseType(ResultEl,Scanner.CurSourcePos)
- end;
- end;
- if OfObjectPossible then
- begin
- NextToken;
- if (CurToken = tkOf) then
- begin
- ExpectToken(tkObject);
- Element.IsOfObject := True;
- end
- else if (CurToken = tkIs) then
- begin
- expectToken(tkIdentifier);
- if (lowerCase(CurTokenString)<>'nested') then
- ParseExc(nParserExpectedNested,SParserExpectedNested);
- Element.IsNested:=True;
- end
- else
- UnGetToken;
- end;
- ModCount:=0;
- Repeat
- inc(ModCount);
- LastToken:=CurToken;
- NextToken;
- if (ModCount=1) and (CurToken = tkEqual) then
- begin
- // for example: const p: procedure = nil;
- UngetToken;
- exit;
- end;
- If CurToken=tkSemicolon then
- begin
- if LastToken=tkSemicolon then
- ParseExcSyntaxError;
- end
- else if TokenIsCallingConvention(CurTokenString,cc) then
- begin
- Element.CallingConvention:=Cc;
- if cc = ccSysCall then
- begin
- // remove LibBase
- NextToken;
- if CurToken=tkSemiColon then
- UngetToken
- else
- // remove legacy or basesysv on MorphOS syscalls
- begin
- if CurTokenIsIdentifier('legacy') or CurTokenIsIdentifier('BaseSysV') then
- NextToken;
- NextToken; // remove offset
- end;
- end;
- ExpectToken(tkSemicolon);
- end
- else if IsProc and TokenIsProcedureModifier(Parent,CurTokenString,PM) then
- HandleProcedureModifier(Parent,PM)
- else if TokenIsProcedureTypeModifier(Parent,CurTokenString,PTM) then
- HandleProcedureTypeModifier(Element,PTM)
- else if (CurToken=tklibrary) then // library is a token and a directive.
- begin
- Tok:=UpperCase(CurTokenString);
- NextToken;
- If (tok<>'NAME') then
- Element.Hints:=Element.Hints+[hLibrary]
- else
- begin
- NextToken; // Should be export name string.
- ExpectToken(tkSemicolon);
- end;
- end
- else if DoCheckHint then
- ConsumeSemi
- else if (CurToken=tkIdentifier) and (CompareText(CurTokenText,'alias')=0) then
- begin
- ExpectToken(tkColon);
- ExpectToken(tkString);
- if (Parent is TPasProcedure) then
- (Parent as TPasProcedure).AliasName:=CurTokenText;
- ExpectToken(tkSemicolon);
- end
- else if (CurToken = tkSquaredBraceOpen) then
- begin
- repeat
- NextToken
- until CurToken = tkSquaredBraceClose;
- ExpectToken(tkSemicolon);
- end
- else
- CheckToken(tkSemicolon);
- Done:=(CurToken=tkSemiColon);
- if Done then
- begin
- NextToken;
- Done:=Not ((Curtoken=tkSquaredBraceOpen) or
- TokenIsProcedureModifier(Parent,CurtokenString,PM) or
- TokenIsProcedureTypeModifier(Parent,CurtokenString,PTM) or
- IsCurTokenHint() or
- TokenIsCallingConvention(CurTokenString,cc) or
- (CurToken=tkIdentifier) and (CompareText(CurTokenText,'alias')=0));
- // DumpCurToken('Done '+IntToStr(Ord(Done)));
- UngetToken;
- end;
- // Writeln('Done: ',TokenInfos[Curtoken],' ',CurtokenString);
- Until Done;
- if DoCheckHint then // deprecated,platform,experimental,library, unimplemented etc
- ConsumeSemi;
- if (ProcType in [ptOperator,ptClassOperator]) and (Parent is TPasOperator) then
- TPasOperator(Parent).CorrectName;
- Engine.FinishScope(stProcedureHeader,Element);
- if (Parent is TPasProcedure)
- and (not TPasProcedure(Parent).IsForward)
- and (not TPasProcedure(Parent).IsExternal)
- and ((Parent.Parent is TImplementationSection)
- or (Parent.Parent is TProcedureBody))
- then
- ParseProcedureBody(Parent);
- if Parent is TPasProcedure then
- Engine.FinishScope(stProcedure,Parent);
- end;
- // starts after the semicolon
- procedure TPasParser.ParseProcedureBody(Parent: TPasElement);
- var
- Body: TProcedureBody;
- begin
- Body := TProcedureBody(CreateElement(TProcedureBody, '', Parent));
- TPasProcedure(Parent).Body:=Body;
- ParseDeclarations(Body);
- end;
- function TPasParser.ParseProperty(Parent: TPasElement; const AName: String;
- AVisibility: TPasMemberVisibility; IsClassField: boolean): TPasProperty;
- function GetAccessorName(aParent: TPasElement; out Expr: TPasExpr): String;
- var
- Params: TParamsExpr;
- Param: TPasExpr;
- begin
- ExpectIdentifier;
- Result := CurTokenString;
- Expr := CreatePrimitiveExpr(aParent,pekIdent,CurTokenString);
- // read .subident.subident...
- repeat
- NextToken;
- if CurToken <> tkDot then break;
- ExpectIdentifier;
- Result := Result + '.' + CurTokenString;
- AddToBinaryExprChain(Expr,CreatePrimitiveExpr(aParent,pekIdent,CurTokenString),eopSubIdent);
- until false;
- // read optional array index
- if CurToken <> tkSquaredBraceOpen then
- UnGetToken
- else
- begin
- Result := Result + '[';
- Params:=TParamsExpr(CreateElement(TParamsExpr,'',aParent));
- Params.Kind:=pekArrayParams;
- AddParamsToBinaryExprChain(Expr,Params);
- NextToken;
- case CurToken of
- tkChar: Param:=CreatePrimitiveExpr(aParent,pekString, CurTokenText);
- tkNumber: Param:=CreatePrimitiveExpr(aParent,pekNumber, CurTokenString);
- tkIdentifier: Param:=CreatePrimitiveExpr(aParent,pekIdent, CurTokenText);
- tkfalse, tktrue: Param:=CreateBoolConstExpr(aParent,pekBoolConst, CurToken=tktrue);
- else
- ParseExcExpectedIdentifier;
- end;
- Params.AddParam(Param);
- Result := Result + CurTokenString;
- ExpectToken(tkSquaredBraceClose);
- Result := Result + ']';
- end;
- repeat
- NextToken;
- if CurToken <> tkDot then
- begin
- UngetToken;
- break;
- end;
- ExpectIdentifier;
- Result := Result + '.' + CurTokenString;
- AddToBinaryExprChain(Expr,CreatePrimitiveExpr(aParent,pekIdent,CurTokenString),eopSubIdent);
- until false;
- end;
- var
- isArray , ok: Boolean;
- h : TPasMemberHint;
- begin
- Result:=TPasProperty(CreateElement(TPasProperty,AName,Parent,AVisibility));
- if IsClassField then
- Include(Result.VarModifiers,vmClass);
- ok:=false;
- try
- NextToken;
- isArray:=CurToken=tkSquaredBraceOpen;
- if isArray then
- begin
- ParseArgList(Result, Result.Args, tkSquaredBraceClose);
- NextToken;
- end;
- if CurToken = tkColon then
- begin
- Result.VarType := ParseType(Result,Scanner.CurSourcePos);
- NextToken;
- end;
- if CurTokenIsIdentifier('INDEX') then
- begin
- NextToken;
- Result.IndexExpr := DoParseExpression(Result);
- end;
- if CurTokenIsIdentifier('READ') then
- begin
- Result.ReadAccessorName := GetAccessorName(Result,Result.ReadAccessor);
- NextToken;
- end;
- if CurTokenIsIdentifier('WRITE') then
- begin
- Result.WriteAccessorName := GetAccessorName(Result,Result.WriteAccessor);
- NextToken;
- end;
- if CurTokenIsIdentifier('READONLY') then
- begin
- Result.DispIDReadOnly:=True;
- NextToken;
- end;
- if CurTokenIsIdentifier('DISPID') then
- begin
- NextToken;
- Result.DispIDExpr := DoParseExpression(Result,Nil);
- NextToken;
- end;
- if CurTokenIsIdentifier('IMPLEMENTS') then
- begin
- Result.ImplementsName := GetAccessorName(Result,Result.ImplementsFunc);
- NextToken;
- end;
- if CurTokenIsIdentifier('STORED') then
- begin
- NextToken;
- if CurToken = tkTrue then
- Result.StoredAccessorName := 'True'
- else if CurToken = tkFalse then
- Result.StoredAccessorName := 'False'
- else if CurToken = tkIdentifier then
- begin
- UngetToken;
- Result.StoredAccessorName := GetAccessorName(Result,Result.StoredAccessor);
- end
- else
- ParseExcSyntaxError;
- NextToken;
- end;
- if CurTokenIsIdentifier('DEFAULT') then
- begin
- if isArray then
- ParseExc(nParserArrayPropertiesCannotHaveDefaultValue,SParserArrayPropertiesCannotHaveDefaultValue);
- NextToken;
- Result.DefaultExpr := DoParseExpression(Result);
- // NextToken;
- end
- else if CurtokenIsIdentifier('NODEFAULT') then
- begin
- Result.IsNodefault:=true;
- if Result.DefaultExpr<>nil then
- ParseExcSyntaxError;
- NextToken;
- end;
- // Here the property ends. There can still be a 'default'
- if CurToken = tkSemicolon then
- NextToken;
- if CurTokenIsIdentifier('DEFAULT') then
- begin
- if (Result.VarType<>Nil) and (not isArray) then
- ParseExc(nParserDefaultPropertyMustBeArray,SParserDefaultPropertyMustBeArray);
- NextToken;
- if CurToken = tkSemicolon then
- begin
- Result.IsDefault := True;
- NextToken;
- end
- end;
- // Handle hints
- while IsCurTokenHint(h) do
- begin
- Result.Hints:=Result.Hints+[h];
- NextToken;
- if CurToken=tkSemicolon then
- NextToken;
- end;
- UngetToken;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- Engine.FinishScope(stDeclaration,Result);
- end;
- // Starts after the "begin" token
- procedure TPasParser.ParseProcBeginBlock(Parent: TProcedureBody);
- var
- BeginBlock: TPasImplBeginBlock;
- SubBlock: TPasImplElement;
- begin
- BeginBlock := TPasImplBeginBlock(CreateElement(TPasImplBeginBlock, '', Parent));
- Parent.Body := BeginBlock;
- repeat
- NextToken;
- // writeln('TPasParser.ParseProcBeginBlock ',curtokenstring);
- if CurToken=tkend then
- break
- else if CurToken<>tkSemiColon then
- begin
- UngetToken;
- ParseStatement(BeginBlock,SubBlock);
- if SubBlock=nil then
- ExpectToken(tkend);
- end;
- until false;
- ExpectToken(tkSemicolon);
- // writeln('TPasParser.ParseProcBeginBlock ended ',curtokenstring);
- end;
- procedure TPasParser.ParseProcAsmBlock(Parent: TProcedureBody);
- var
- AsmBlock: TPasImplAsmStatement;
- begin
- AsmBlock:=TPasImplAsmStatement(CreateElement(TPasImplAsmStatement,'',Parent));
- Parent.Body:=AsmBlock;
- ParseAsmBlock(AsmBlock);
- ExpectToken(tkSemicolon);
- end;
- procedure TPasParser.ParseAsmBlock(AsmBlock: TPasImplAsmStatement);
- begin
- if po_asmwhole in Options then
- begin
- FTokenBufferIndex:=1;
- FTokenBufferSize:=1;
- FCommentsBuffer[0].Clear;
- repeat
- Scanner.ReadNonPascalTillEndToken(true);
- case Scanner.CurToken of
- tkLineEnding:
- AsmBlock.Tokens.Add(Scanner.CurTokenString);
- tkend:
- begin
- FTokenBuffer[0] := tkend;
- FTokenStringBuffer[0] := Scanner.CurTokenString;
- break;
- end
- else
- begin
- // missing end
- FTokenBuffer[0] := tkEOF;
- FTokenStringBuffer[0] := '';
- end;
- end;
- until false;
- FCurToken := FTokenBuffer[0];
- FCurTokenString := FTokenStringBuffer[0];
- FCurComments:=FCommentsBuffer[0];
- CheckToken(tkend);
- end
- else
- begin
- NextToken;
- While CurToken<>tkEnd do
- begin
- // ToDo: allow @@end
- AsmBlock.Tokens.Add(CurTokenText);
- NextToken;
- end;
- end;
- // NextToken; // Eat end.
- // Do not consume end. Current token will normally be end;
- end;
- // Next token is start of (compound) statement
- // After parsing CurToken is on last token of statement
- procedure TPasParser.ParseStatement(Parent: TPasImplBlock;
- out NewImplElement: TPasImplElement);
- var
- CurBlock: TPasImplBlock;
- {$IFDEF VerbosePasParser}
- function i: string;
- var
- c: TPasElement;
- begin
- Result:='ParseImplCompoundStatement ';
- c:=CurBlock;
- while c<>nil do begin
- Result:=Result+' ';
- c:=c.Parent;
- end;
- end;
- {$ENDIF}
- function CloseBlock: boolean; // true if parent reached
- begin
- if CurBlock.ClassType=TPasImplExceptOn then
- Engine.FinishScope(stExceptOnStatement,CurBlock);
- CurBlock:=CurBlock.Parent as TPasImplBlock;
- Result:=CurBlock=Parent;
- end;
- function CloseStatement(CloseIfs: boolean): boolean; // true if parent reached
- begin
- if CurBlock=Parent then exit(true);
- while CurBlock.CloseOnSemicolon
- or (CloseIfs and (CurBlock is TPasImplIfElse)) do
- if CloseBlock then exit(true);
- Result:=false;
- end;
- procedure CreateBlock(NewBlock: TPasImplBlock);
- begin
- CurBlock.AddElement(NewBlock);
- CurBlock:=NewBlock;
- if NewImplElement=nil then NewImplElement:=CurBlock;
- end;
- var
- SubBlock: TPasImplElement;
- CmdElem: TPasImplElement;
- left, right: TPasExpr;
- El : TPasImplElement;
- ak : TAssignKind;
- lt : TLoopType;
- ok: Boolean;
- SrcPos: TPasSourcePos;
- Name: String;
- TypeEl: TPasType;
- begin
- NewImplElement:=nil;
- CurBlock := Parent;
- while True do
- begin
- NextToken;
- // WriteLn({$IFDEF VerbosePasParser}i,{$ENDIF}' Token=',CurTokenText);
- case CurToken of
- tkasm:
- begin
- El:=TPasImplElement(CreateElement(TPasImplAsmStatement,'',CurBlock));
- ParseAsmBlock(TPasImplAsmStatement(El));
- CurBlock.AddElement(El);
- if NewImplElement=nil then NewImplElement:=CurBlock;
- if CloseStatement(true) then
- break;
- end;
- tkbegin:
- begin
- El:=TPasImplElement(CreateElement(TPasImplBeginBlock,'',CurBlock));
- CreateBlock(TPasImplBeginBlock(El));
- end;
- tkrepeat:
- begin
- El:=TPasImplRepeatUntil(CreateElement(TPasImplRepeatUntil,'',CurBlock));
- CreateBlock(TPasImplRepeatUntil(El));
- end;
- tkIf:
- begin
- NextToken;
- Left:=DoParseExpression(CurBlock);
- UngetToken;
- El:=TPasImplIfElse(CreateElement(TPasImplIfElse,'',CurBlock));
- TPasImplIfElse(El).ConditionExpr:=Left;
- Left.Parent:=El;
- //WriteLn(i,'IF Condition="',Condition,'" Token=',CurTokenText);
- CreateBlock(TPasImplIfElse(El));
- ExpectToken(tkthen);
- end;
- tkelse:
- if (CurBlock is TPasImplIfElse) then
- begin
- if TPasImplIfElse(CurBlock).IfBranch=nil then
- begin
- El:=TPasImplCommand(CreateElement(TPasImplCommand,'', CurBlock));
- CurBlock.AddElement(El);
- end;
- if TPasImplIfElse(CurBlock).ElseBranch<>nil then
- begin
- // this and the following 3 may solve TPasImplIfElse.AddElement BUG
- // ifs without begin end
- // if .. then
- // if .. then
- // else
- // else
- CloseBlock;
- CloseStatement(false);
- end;
- // Case ... else without semicolon in front.
- end else if (CurBlock is TPasImplCaseStatement) then
- begin
- UngetToken;
- CloseStatement(False);
- exit;
- end else if (CurBlock is TPasImplWhileDo) then
- begin
- CloseBlock;
- UngetToken;
- end else if (CurBlock is TPasImplForLoop) then
- begin
- //if .. then for .. do smt else ..
- CloseBlock;
- UngetToken;
- end else if (CurBlock is TPasImplWithDo) then
- begin
- //if .. then with .. do smt else ..
- CloseBlock;
- UngetToken;
- end else if (CurBlock is TPasImplRaise) then
- begin
- //if .. then Raise Exception else ..
- CloseBlock;
- UngetToken;
- end else if (CurBlock is TPasImplTryExcept) then
- begin
- CloseBlock;
- El:=TPasImplTryExceptElse(CreateElement(TPasImplTryExceptElse,'',CurBlock));
- TPasImplTry(CurBlock).ElseBranch:=TPasImplTryExceptElse(El);
- CurBlock:=TPasImplTryExceptElse(El);
- end else
- ParseExcSyntaxError;
- tkwhile:
- begin
- // while Condition do
- NextToken;
- left:=DoParseExpression(CurBlock);
- UngetToken;
- //WriteLn(i,'WHILE Condition="',Condition,'" Token=',CurTokenText);
- El:=TPasImplWhileDo(CreateElement(TPasImplWhileDo,'',CurBlock));
- TPasImplWhileDo(El).ConditionExpr:=left;
- CreateBlock(TPasImplWhileDo(El));
- ExpectToken(tkdo);
- end;
- tkgoto:
- begin
- NextToken;
- curblock.AddCommand('goto '+curtokenstring);
- // expecttoken(tkSemiColon);
- end;
- tkfor:
- begin
- // for VarName := StartValue to EndValue do
- // for VarName in Expression do
- El:=TPasImplForLoop(CreateElement(TPasImplForLoop,'',CurBlock));
- ok:=false;
- Try
- ExpectIdentifier;
- Left:=CreatePrimitiveExpr(El,pekIdent,CurTokenString);
- TPasImplForLoop(El).VariableName:=Left;
- repeat
- NextToken;
- case CurToken of
- tkAssign:
- begin
- lt:=ltNormal;
- break;
- end;
- tkin:
- begin
- lt:=ltIn;
- break;
- end;
- tkDot:
- begin
- ExpectIdentifier;
- AddToBinaryExprChain(Left,
- CreatePrimitiveExpr(El,pekIdent,CurTokenString), eopSubIdent);
- TPasImplForLoop(El).VariableName:=Left;
- end;
- else
- ParseExc(nParserExpectedAssignIn,SParserExpectedAssignIn);
- end;
- until false;
- NextToken;
- TPasImplForLoop(El).StartExpr:=DoParseExpression(El);
- if (Lt=ltNormal) then
- begin
- if Not (CurToken in [tkTo,tkDownTo]) then
- ParseExcTokenError(TokenInfos[tkTo]);
- if CurToken=tkdownto then
- Lt:=ltDown;
- NextToken;
- TPasImplForLoop(El).EndExpr:=DoParseExpression(El);
- end;
- TPasImplForLoop(El).LoopType:=lt;
- if (CurToken<>tkDo) then
- ParseExcTokenError(TokenInfos[tkDo]);
- ok:=true;
- finally
- if not ok then
- El.Release;
- end;
- CreateBlock(TPasImplForLoop(El));
- //WriteLn(i,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);
- end;
- tkwith:
- begin
- // with Expr do
- // with Expr, Expr do
- SrcPos:=Scanner.CurSourcePos;
- NextToken;
- Left:=DoParseExpression(CurBlock);
- //writeln(i,'WITH Expr="',Expr,'" Token=',CurTokenText);
- El:=TPasImplWithDo(CreateElement(TPasImplWithDo,'',CurBlock,SrcPos));
- TPasImplWithDo(El).AddExpression(Left);
- Left.Parent:=El;
- CreateBlock(TPasImplWithDo(El));
- repeat
- if CurToken=tkdo then break;
- if CurToken<>tkComma then
- ParseExcTokenError(TokenInfos[tkdo]);
- NextToken;
- Left:=DoParseExpression(CurBlock);
- //writeln(i,'WITH ...,Expr="',Expr,'" Token=',CurTokenText);
- TPasImplWithDo(CurBlock).AddExpression(Left);
- until false;
- end;
- tkcase:
- begin
- NextToken;
- Left:=DoParseExpression(CurBlock);
- UngetToken;
- //writeln(i,'CASE OF Expr="',Expr,'" Token=',CurTokenText);
- ExpectToken(tkof);
- El:=TPasImplCaseOf(CreateElement(TPasImplCaseOf,'',CurBlock));
- TPasImplCaseOf(El).CaseExpr:=Left;
- Left.Parent:=El;
- CreateBlock(TPasImplCaseOf(El));
- repeat
- NextToken;
- //writeln(i,'CASE OF Token=',CurTokenText);
- case CurToken of
- tkend:
- begin
- if CurBlock.Elements.Count=0 then
- ParseExc(nParserExpectCase,SParserExpectCase);
- break; // end without else
- end;
- tkelse:
- begin
- // create case-else block
- El:=TPasImplCaseElse(CreateElement(TPasImplCaseElse,'',CurBlock));
- TPasImplCaseOf(CurBlock).ElseBranch:=TPasImplCaseElse(El);
- CreateBlock(TPasImplCaseElse(El));
- break;
- end
- else
- // read case values
- if (curToken=tkIdentifier) and (LowerCase(CurtokenString)='otherwise') then
- begin
- // create case-else block
- El:=TPasImplCaseElse(CreateElement(TPasImplCaseElse,'',CurBlock));
- TPasImplCaseOf(CurBlock).ElseBranch:=TPasImplCaseElse(El);
- CreateBlock(TPasImplCaseElse(El));
- break;
- end
- else
- repeat
- Left:=DoParseExpression(CurBlock);
- //writeln(i,'CASE value="',Expr,'" Token=',CurTokenText);
- if CurBlock is TPasImplCaseStatement then
- TPasImplCaseStatement(CurBlock).Expressions.Add(Left)
- else
- begin
- El:=TPasImplCaseStatement(CreateElement(TPasImplCaseStatement,'',CurBlock));
- TPasImplCaseStatement(El).AddExpression(Left);
- CurBlock.AddElement(El);
- CurBlock:=TPasImplCaseStatement(El);
- end;
- //writeln(i,'CASE after value Token=',CurTokenText);
- if (CurToken=tkComma) then
- NextToken
- else if (CurToken<>tkColon) then
- ParseExcTokenError(TokenInfos[tkComma]);
- until Curtoken=tkColon;
- // read statement
- ParseStatement(CurBlock,SubBlock);
- CloseBlock;
- if CurToken<>tkSemicolon then
- begin
- NextToken;
- if not (CurToken in [tkSemicolon,tkelse,tkend]) then
- ParseExcTokenError(TokenInfos[tkSemicolon]);
- if CurToken<>tkSemicolon then
- UngetToken;
- end;
- end;
- until false;
- if CurToken=tkend then
- begin
- if CloseBlock then break;
- if CloseStatement(false) then break;
- end;
- end;
- tktry:
- begin
- El:=TPasImplTry(CreateElement(TPasImplTry,'',CurBlock));
- CreateBlock(TPasImplTry(El));
- end;
- tkfinally:
- begin
- if CloseStatement(true) then
- begin
- UngetToken;
- break;
- end;
- if CurBlock is TPasImplTry then
- begin
- El:=TPasImplTryFinally(CreateElement(TPasImplTryFinally,'',CurBlock));
- TPasImplTry(CurBlock).FinallyExcept:=TPasImplTryFinally(El);
- CurBlock:=TPasImplTryFinally(El);
- end else
- ParseExcSyntaxError;
- end;
- tkexcept:
- begin
- if CloseStatement(true) then
- begin
- UngetToken;
- break;
- end;
- if CurBlock is TPasImplTry then
- begin
- //writeln(i,'EXCEPT');
- El:=TPasImplTryExcept(CreateElement(TPasImplTryExcept,'',CurBlock));
- TPasImplTry(CurBlock).FinallyExcept:=TPasImplTryExcept(El);
- CurBlock:=TPasImplTryExcept(El);
- end else
- ParseExcSyntaxError;
- end;
- tkon:
- begin
- // in try except:
- // on E: Exception do
- // on Exception do
- if CurBlock is TPasImplTryExcept then
- begin
- ExpectIdentifier;
- El:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock));
- SrcPos:=Scanner.CurSourcePos;
- Name:=CurTokenString;
- NextToken;
- //writeln('ON t=',Name,' Token=',CurTokenText);
- if CurToken=tkColon then
- begin
- // the first expression was the variable name
- NextToken;
- TypeEl:=ParseSimpleType(El,SrcPos,'');
- TPasImplExceptOn(El).TypeEl:=TypeEl;
- TPasImplExceptOn(El).VarEl:=TPasVariable(CreateElement(TPasVariable,
- Name,El,SrcPos));
- TPasImplExceptOn(El).VarEl.VarType:=TypeEl;
- TypeEl.AddRef;
- end
- else
- begin
- UngetToken;
- TPasImplExceptOn(El).TypeEl:=ParseSimpleType(El,SrcPos,'');
- end;
- Engine.FinishScope(stExceptOnExpr,El);
- CurBlock.AddElement(El);
- CurBlock:=TPasImplExceptOn(El);
- ExpectToken(tkDo);
- end else
- ParseExcSyntaxError;
- end;
- tkraise:
- begin
- El:=TPasImplRaise(CreateElement(TPasImplRaise,'',CurBlock));
- CreateBlock(TPasImplRaise(El));
- NextToken;
- If Curtoken in [tkElse,tkEnd,tkSemicolon] then
- UnGetToken
- else
- begin
- TPasImplRaise(El).ExceptObject:=DoParseExpression(El);
- if (CurToken=tkIdentifier) and (Uppercase(CurtokenString)='AT') then
- begin
- NextToken;
- TPasImplRaise(El).ExceptAddr:=DoParseExpression(El);
- end;
- if Curtoken in [tkSemicolon,tkEnd] then
- UngetToken
- end;
- end;
- tkend:
- begin
- if CloseStatement(true) then
- begin
- UngetToken;
- break;
- end;
- if CurBlock is TPasImplBeginBlock then
- begin
- if CloseBlock then break; // close end
- if CloseStatement(false) then break;
- end else if CurBlock is TPasImplCaseElse then
- begin
- if CloseBlock then break; // close else
- if CloseBlock then break; // close caseof
- if CloseStatement(false) then break;
- end else if CurBlock is TPasImplTryHandler then
- begin
- if CloseBlock then break; // close finally/except
- if CloseBlock then break; // close try
- if CloseStatement(false) then break;
- end else
- ParseExcSyntaxError;
- end;
- tkSemiColon:
- if CloseStatement(true) then break;
- tkuntil:
- begin
- if CloseStatement(true) then
- begin
- UngetToken;
- break;
- end;
- if CurBlock is TPasImplRepeatUntil then
- begin
- NextToken;
- Left:=DoParseExpression(CurBlock);
- UngetToken;
- TPasImplRepeatUntil(CurBlock).ConditionExpr:=Left;
- //WriteLn(i,'UNTIL Condition="',Condition,'" Token=',CurTokenString);
- if CloseBlock then break;
- end else
- ParseExcSyntaxError;
- end;
- tkEOF:
- CheckToken(tkend);
- tkBraceOpen,tkIdentifier,tkNumber,tkSquaredBraceOpen,tkMinus,tkPlus,tkinherited:
- begin
- left:=DoParseExpression(CurBlock);
- case CurToken of
- tkAssign,
- tkAssignPlus,
- tkAssignMinus,
- tkAssignMul,
- tkAssignDivision:
- begin
- // assign statement
- Ak:=TokenToAssignKind(CurToken);
- NextToken;
- right:=DoParseExpression(CurBlock); // this may solve TPasImplWhileDo.AddElement BUG
- El:=TPasImplAssign(CreateElement(TPasImplAssign,'',CurBlock));
- left.Parent:=El;
- right.Parent:=El;
- TPasImplAssign(El).left:=Left;
- TPasImplAssign(El).right:=Right;
- TPasImplAssign(El).Kind:=ak;
- CurBlock.AddElement(El);
- CmdElem:=TPasImplAssign(El);
- UngetToken;
- end;
- tkColon:
- begin
- if not (left is TPrimitiveExpr) then
- ParseExcTokenError(TokenInfos[tkSemicolon]);
- // label mark. todo: check mark identifier in the list of labels
- El:=TPasImplLabelMark(CreateElement(TPasImplLabelMark,'', CurBlock));
- TPasImplLabelMark(El).LabelId:=TPrimitiveExpr(left).Value;
- CurBlock.AddElement(El);
- CmdElem:=TPasImplLabelMark(El);
- left.Free;
- end;
- else
- // simple statement (function call)
- El:=TPasImplSimple(CreateElement(TPasImplSimple,'',CurBlock));
- TPasImplSimple(El).expr:=Left;
- CurBlock.AddElement(El);
- CmdElem:=TPasImplSimple(El);
- UngetToken;
- end;
- if not (CmdElem is TPasImplLabelMark) then
- if NewImplElement=nil then NewImplElement:=CmdElem;
- end;
- else
- ParseExcSyntaxError;
- end;
- end;
- end;
- procedure TPasParser.ParseLabels(AParent: TPasElement);
- var
- Labels: TPasLabels;
- begin
- Labels:=TPasLabels(CreateElement(TPasLabels, '', AParent));
- repeat
- Labels.Labels.Add(ExpectIdentifier);
- NextToken;
- if not (CurToken in [tkSemicolon, tkComma]) then
- ParseExcTokenError(TokenInfos[tkSemicolon]);
- until CurToken=tkSemicolon;
- end;
- // Starts after the "procedure" or "function" token
- function TPasParser.GetProcedureClass(ProcType: TProcType): TPTreeElement;
- begin
- Case ProcType of
- ptFunction : Result:=TPasFunction;
- ptClassFunction : Result:=TPasClassFunction;
- ptClassProcedure : Result:=TPasClassProcedure;
- ptClassConstructor : Result:=TPasClassConstructor;
- ptClassDestructor : Result:=TPasClassDestructor;
- ptProcedure : Result:=TPasProcedure;
- ptConstructor : Result:=TPasConstructor;
- ptDestructor : Result:=TPasDestructor;
- ptOperator : Result:=TPasOperator;
- ptClassOperator : Result:=TPasClassOperator;
- else
- ParseExc(nParserUnknownProcedureType,SParserUnknownProcedureType,[Ord(ProcType)]);
- end;
- end;
- function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement; ProcType: TProcType;AVisibility : TPasMemberVisibility = VisDefault): TPasProcedure;
- function ExpectProcName: string;
- Var
- L : TFPList;
- I : Integer;
- begin
- Result:=ExpectIdentifier;
- //writeln('ExpectProcName ',Parent.Classname);
- if Parent is TImplementationSection then
- begin
- NextToken;
- While CurToken in [tkDot,tkLessThan] do
- begin
- if CurToken=tkDot then
- Result:=Result+'.'+ExpectIdentifier
- else
- begin // <> can be ignored, we read the list but discard its content
- UnGetToken;
- L:=TFPList.Create;
- Try
- ReadGenericArguments(L,Parent);
- finally
- For I:=0 to L.Count-1 do
- TPasElement(L[i]).Release;
- L.Free;
- end;
- end;
- NextToken;
- end;
- UngetToken;
- end;
- end;
- var
- Name: String;
- PC : TPTreeElement;
- Ot : TOperatorType;
- IsTokenBased , ok: Boolean;
- begin
- If (Not (ProcType in [ptOperator,ptClassOperator])) then
- Name:=ExpectProcName
- else
- begin
- NextToken;
- IsTokenBased:=Curtoken<>tkIdentifier;
- if IsTokenBased then
- OT:=TPasOperator.TokenToOperatorType(CurTokenText)
- else
- OT:=TPasOperator.NameToOperatorType(CurTokenString);
- if (ot=otUnknown) then
- ParseExc(nErrUnknownOperatorType,SErrUnknownOperatorType,[CurTokenString]);
- Name:=OperatorNames[Ot];
- end;
- PC:=GetProcedureClass(ProcType);
- Parent:=CheckIfOverLoaded(Parent,Name);
- Result:=TPasProcedure(CreateElement(PC,Name,Parent,AVisibility));
- ok:=false;
- try
- if Not (ProcType in [ptFunction, ptClassFunction, ptOperator, ptClassOperator]) then
- Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '', Result))
- else
- begin
- Result.ProcType := CreateFunctionType('', 'Result', Result, True, Scanner.CurSourcePos);
- if (ProcType in [ptOperator, ptClassOperator]) then
- begin
- TPasOperator(Result).TokenBased:=IsTokenBased;
- TPasOperator(Result).OperatorType:=OT;
- TPasOperator(Result).CorrectName;
- end;
- end;
- ParseProcedureOrFunctionHeader(Result, Result.ProcType, ProcType, False);
- Result.Hints:=Result.ProcType.Hints;
- Result.HintMessage:=Result.ProcType.HintMessage;
- // + is detected as 'positive', but is in fact Add if there are 2 arguments.
- if (ProcType in [ptOperator, ptClassOperator]) then
- With TPasOperator(Result) do
- begin
- if (OperatorType in [otPositive, otNegative]) then
- begin
- if (ProcType.Args.Count>1) then
- begin
- Case OperatorType of
- otPositive : OperatorType:=otPlus;
- otNegative : OperatorType:=otMinus;
- end;
- Name:=OperatorNames[OperatorType];
- TPasOperator(Result).CorrectName;
- end;
- end;
- end;
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- // Current token is the first token after tkOf
- procedure TPasParser.ParseRecordVariantParts(ARec: TPasRecordType;
- AEndToken: TToken);
- Var
- M : TPasRecordType;
- V : TPasVariant;
- Done : Boolean;
- begin
- Repeat
- V:=TPasVariant(CreateElement(TPasVariant, '', ARec));
- ARec.Variants.Add(V);
- Repeat
- NextToken;
- V.Values.Add(DoParseExpression(ARec));
- if Not (CurToken in [tkComma,tkColon]) then
- ParseExc(nParserExpectedCommaColon,SParserExpectedCommaColon);
- Until (curToken=tkColon);
- ExpectToken(tkBraceOpen);
- NextToken;
- M:=TPasRecordType(CreateElement(TPasRecordType,'',V));
- V.Members:=M;
- ParseRecordFieldList(M,tkBraceClose,False);
- // Current token is closing ), so we eat that
- NextToken;
- // If there is a semicolon, we eat that too.
- if CurToken=tkSemicolon then
- NextToken;
- // ParseExpression starts with a nexttoken.
- // So we need to determine the next token, and if it is an ending token, unget.
- Done:=CurToken=AEndToken;
- If not Done then
- Ungettoken;
- Until Done;
- end;
- procedure TPasParser.DumpCurToken(const Msg: String; IndentAction: TIndentAction
- );
- begin
- if IndentAction=iaUndent then
- FDumpIndent:=copy(FDumpIndent,1,Length(FDumpIndent)-2);
- Writeln(FDumpIndent,Msg,' : ',TokenInfos[CurToken],' "',CurTokenString,'", Position: ',Scanner.CurFilename,'(',Scanner.CurRow,',',SCanner.CurColumn,') : ',Scanner.CurLine);
- if IndentAction=iaIndent then
- FDumpIndent:=FDumpIndent+' ';
- Flush(output);
- end;
- function TPasParser.GetCurrentModeSwitches: TModeSwitches;
- begin
- if Assigned(FScanner) then
- Result:=FScanner.CurrentModeSwitches
- else
- Result:=[msNone];
- end;
- procedure TPasParser.SetCurrentModeSwitches(AValue: TModeSwitches);
- begin
- if Assigned(FScanner) then
- FScanner.CurrentModeSwitches:=AValue;
- end;
- // Starts on first token after Record or (. Ends on AEndToken
- procedure TPasParser.ParseRecordFieldList(ARec: TPasRecordType;
- AEndToken: TToken; AllowMethods: Boolean);
- Var
- VariantName : String;
- v : TPasmemberVisibility;
- Proc: TPasProcedure;
- ProcType: TProcType;
- Prop : TPasProperty;
- Cons : TPasConst;
- isClass : Boolean;
- NamePos: TPasSourcePos;
- OldCount, i: Integer;
- begin
- v:=visDefault;
- isClass:=False;
- while CurToken<>AEndToken do
- begin
- SaveComments;
- Case CurToken of
- tkConst:
- begin
- if Not AllowMethods then
- ParseExc(nErrRecordConstantsNotAllowed,SErrRecordConstantsNotAllowed);
- ExpectToken(tkIdentifier);
- Cons:=ParseConstDecl(ARec);
- Cons.Visibility:=v;
- ARec.members.Add(Cons);
- end;
- tkClass:
- begin
- if Not AllowMethods then
- ParseExc(nErrRecordMethodsNotAllowed,SErrRecordMethodsNotAllowed);
- if isClass then
- ParseExc(nParserTypeSyntaxError,SParserTypeSyntaxError);
- isClass:=True;
- end;
- tkProperty:
- begin
- if Not AllowMethods then
- ParseExc(nErrRecordPropertiesNotAllowed,SErrRecordPropertiesNotAllowed);
- ExpectToken(tkIdentifier);
- Prop:=ParseProperty(ARec,CurtokenString,v,isClass);
- Arec.Members.Add(Prop);
- end;
- tkOperator,
- tkProcedure,
- tkConstructor,
- tkFunction :
- begin
- if Not AllowMethods then
- ParseExc(nErrRecordMethodsNotAllowed,SErrRecordMethodsNotAllowed);
- ProcType:=GetProcTypeFromToken(CurToken,isClass);
- Proc:=ParseProcedureOrFunctionDecl(ARec,ProcType,v);
- if Proc.Parent is TPasOverloadedProc then
- TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
- else
- ARec.Members.Add(Proc);
- end;
- tkGeneric, // Counts as field name
- tkIdentifier :
- begin
- if CheckVisibility(CurtokenString,v) then
- begin
- If not (msAdvancedRecords in Scanner.CurrentModeSwitches) then
- ParseExc(nErrRecordVisibilityNotAllowed,SErrRecordVisibilityNotAllowed);
- if not (v in [visPrivate,visPublic,visStrictPrivate]) then
- ParseExc(nParserInvalidRecordVisibility,SParserInvalidRecordVisibility);
- NextToken;
- Continue;
- end;
- OldCount:=ARec.Members.Count;
- ParseInlineVarDecl(ARec, ARec.Members, v, AEndToken=tkBraceClose);
- for i:=OldCount to ARec.Members.Count-1 do
- Engine.FinishScope(stDeclaration,TPasVariable(ARec.Members[i]));
- end;
- tkCase :
- begin
- ARec.Variants:=TFPList.Create;
- NextToken;
- VariantName:=CurTokenString;
- NamePos:=Scanner.CurSourcePos;
- NextToken;
- If CurToken=tkColon then
- begin
- ARec.VariantEl:=TPasVariable(CreateElement(TPasVariable,VariantName,ARec,NamePos));
- TPasVariable(ARec.VariantEl).VarType:=ParseType(ARec,Scanner.CurSourcePos);
- end
- else
- begin
- UnGetToken;
- UnGetToken;
- ARec.VariantEl:=ParseType(ARec,Scanner.CurSourcePos);
- end;
- ExpectToken(tkOf);
- ParseRecordVariantParts(ARec,AEndToken);
- end;
- else
- ParseExc(nParserTypeSyntaxError,SParserTypeSyntaxError);
- end;
- If CurToken<>tkClass then
- isClass:=False;
- if CurToken<>AEndToken then
- NextToken;
- end;
- end;
- // Starts after the "record" token
- function TPasParser.ParseRecordDecl(Parent: TPasElement;
- const NamePos: TPasSourcePos; const TypeName: string;
- const Packmode: TPackMode): TPasRecordType;
- var
- ok: Boolean;
- begin
- Result := TPasRecordType(CreateElement(TPasRecordType, TypeName, Parent, NamePos));
- ok:=false;
- try
- Result.PackMode:=PackMode;
- NextToken;
- ParseRecordFieldList(Result,tkEnd,true);
- Engine.FinishScope(stTypeDef,Result);
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- Function IsVisibility(S : String; var AVisibility :TPasMemberVisibility) : Boolean;
- Const
- VNames : array[TPasMemberVisibility] of string =
- ('', 'private', 'protected', 'public', 'published', 'automated', '', '');
- Var
- V : TPasMemberVisibility;
- begin
- Result:=False;
- S:=lowerCase(S);
- For V :=Low(TPasMemberVisibility) to High(TPasMemberVisibility) do
- begin
- Result:=(VNames[V]<>'') and (S=VNames[V]);
- if Result then
- begin
- AVisibility := v;
- Exit;
- end;
- end;
- end;
- function TPasParser.CheckVisibility(S: String;
- var AVisibility: TPasMemberVisibility): Boolean;
- Var
- B : Boolean;
- begin
- s := LowerCase(CurTokenString);
- B:=(S='strict');
- if B then
- begin
- NextToken;
- s:=LowerCase(CurTokenString);
- end;
- Result:=isVisibility(S,AVisibility);
- if Result then
- begin
- if B then
- case AVisibility of
- visPrivate : AVisibility:=visStrictPrivate;
- visProtected : AVisibility:=visStrictProtected;
- else
- ParseExc(nParserStrangeVisibility,SParserStrangeVisibility,[S]);
- end
- end
- else if B then
- ParseExc(nParserExpectVisibility,SParserExpectVisibility);
- end;
- procedure TPasParser.ProcessMethod(AType: TPasClassType; IsClass : Boolean; AVisibility : TPasMemberVisibility);
- var
- Proc: TPasProcedure;
- ProcType: TProcType;
- begin
- ProcType:=GetProcTypeFromToken(CurToken,isClass);
- Proc:=ParseProcedureOrFunctionDecl(AType,ProcType,AVisibility);
- if Proc.Parent is TPasOverloadedProc then
- TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
- else
- AType.Members.Add(Proc);
- end;
- procedure TPasParser.ParseClassFields(AType: TPasClassType;
- const AVisibility: TPasMemberVisibility; IsClassField: Boolean);
- Var
- VarList: TFPList;
- Element: TPasElement;
- I : Integer;
- isStatic : Boolean;
- VarEl: TPasVariable;
- begin
- VarList := TFPList.Create;
- try
- ParseInlineVarDecl(AType, VarList, AVisibility, False);
- if CurToken=tkSemicolon then
- begin
- NextToken;
- isStatic:=CurTokenIsIdentifier('static');
- if isStatic then
- ExpectToken(tkSemicolon)
- else
- UngetToken;
- end;
- for i := 0 to VarList.Count - 1 do
- begin
- Element := TPasElement(VarList[i]);
- Element.Visibility := AVisibility;
- if (Element is TPasVariable) then
- begin
- VarEl:=TPasVariable(Element);
- if IsClassField then
- Include(VarEl.VarModifiers,vmClass);
- if isStatic then
- Include(VarEl.VarModifiers,vmStatic);
- Engine.FinishScope(stDeclaration,VarEl);
- end;
- AType.Members.Add(Element);
- end;
- finally
- VarList.Free;
- end;
- end;
- procedure TPasParser.ParseClassLocalTypes(AType: TPasClassType; AVisibility : TPasMemberVisibility);
- Var
- T : TPasType;
- Done : Boolean;
- begin
- // Writeln('Parsing local types');
- Repeat
- T:=ParseTypeDecl(AType);
- T.Visibility:=AVisibility;
- AType.Members.Add(t);
- // Writeln(CurtokenString,' ',TokenInfos[Curtoken]);
- NextToken;
- Done:=(Curtoken<>tkIdentifier) or CheckVisibility(CurtokenString,AVisibility);
- if Done then
- UngetToken;
- Until Done;
- end;
- procedure TPasParser.ParseClassLocalConsts(AType: TPasClassType; AVisibility : TPasMemberVisibility);
- Var
- C : TPasConst;
- Done : Boolean;
- begin
- // Writeln('Parsing local consts');
- Repeat
- C:=ParseConstDecl(AType);
- C.Visibility:=AVisibility;
- AType.Members.Add(C);
- // Writeln(CurtokenString,' ',TokenInfos[Curtoken]);
- NextToken;
- Done:=(Curtoken<>tkIdentifier) or CheckVisibility(CurtokenString,AVisibility);
- if Done then
- UngetToken;
- Until Done;
- end;
- procedure TPasParser.ParseClassMembers(AType: TPasClassType);
- Var
- CurVisibility : TPasMemberVisibility;
- begin
- CurVisibility := visDefault;
- while (CurToken<>tkEnd) do
- begin
- case CurToken of
- tkType:
- begin
- ExpectToken(tkIdentifier);
- SaveComments;
- ParseClassLocalTypes(AType,CurVisibility);
- end;
- tkConst:
- begin
- ExpectToken(tkIdentifier);
- SaveComments;
- ParseClassLocalConsts(AType,CurVisibility);
- end;
- tkVar,
- tkIdentifier:
- begin
- if (AType.ObjKind in [okInterface,okDispInterface]) then
- ParseExc(nParserNoFieldsAllowed,SParserNoFieldsAllowed);
- if CurToken=tkVar then
- ExpectToken(tkIdentifier);
- SaveComments;
- if Not CheckVisibility(CurtokenString,CurVisibility) then
- ParseClassFields(AType,CurVisibility,false);
- end;
- tkProcedure,tkFunction,tkConstructor,tkDestructor:
- begin
- SaveComments;
- if (Curtoken in [tkConstructor,tkDestructor]) and (AType.ObjKind in [okInterface,okDispInterface,okRecordHelper]) then
- ParseExc(nParserNoConstructorAllowed,SParserNoConstructorAllowed);
- ProcessMethod(AType,False,CurVisibility);
- end;
- tkclass:
- begin
- SaveComments;
- NextToken;
- if CurToken in [tkConstructor,tkDestructor,tkProcedure,tkFunction] then
- ProcessMethod(AType,True,CurVisibility)
- else if CurToken = tkVar then
- begin
- ExpectToken(tkIdentifier);
- ParseClassFields(AType,CurVisibility,true);
- end
- else if CurToken=tkProperty then
- begin
- ExpectToken(tkIdentifier);
- AType.Members.Add(ParseProperty(AType,CurtokenString,CurVisibility,true));
- end
- else
- ParseExc(nParserTypeSyntaxError,SParserTypeSyntaxError)
- end;
- tkProperty:
- begin
- SaveComments;
- ExpectIdentifier;
- AType.Members.Add(ParseProperty(AType,CurtokenString,CurVisibility,false));
- end
- else
- CheckToken(tkIdentifier);
- end;
- NextToken;
- end;
- end;
- procedure TPasParser.DoParseClassType(AType: TPasClassType);
- var
- Element : TPasElement;
- s: String;
- CT : TPasClassType;
- begin
- ct:=Nil;
- // nettism/new delphi features
- if (CurToken=tkIdentifier) and (Atype.ObjKind in [okClass,okGeneric]) then
- begin
- s := LowerCase(CurTokenString);
- if (s = 'sealed') or (s = 'abstract') then
- begin
- AType.Modifiers.Add(s);
- NextToken;
- end;
- end;
- // Parse ancestor list
- AType.IsForward:=(CurToken=tkSemiColon);
- if (CurToken=tkBraceOpen) then
- begin
- AType.AncestorType := ParseType(AType,Scanner.CurSourcePos);
- NextToken;
- if curToken=tkLessthan then
- CT := TPasClassType(CreateElement(TPasClassType, AType.AncestorType.Name, AType.Parent, Scanner.CurSourcePos));
- UnGetToken ;
- if Assigned(CT) then
- try
- CT.ObjKind := okSpecialize;
- CT.AncestorType := TPasUnresolvedTypeRef.Create(AType.AncestorType.Name,AType.Parent);
- CT.IsShortDefinition:=True;
- ReadGenericArguments(CT.GenericTemplateTypes,CT);
- AType.AncestorType.Release;
- AType.AncestorType:=CT;
- CT:=Nil;
- Finally
- FreeAndNil(CT);
- end;
- while True do
- begin
- NextToken;
- if CurToken = tkBraceClose then
- break ;
- UngetToken;
- ExpectToken(tkComma);
- Element:=ParseType(AType,Scanner.CurSourcePos,'',False); // search interface.
- if assigned(element) then
- AType.Interfaces.add(element);
- end;
- NextToken;
- AType.IsShortDefinition:=(CurToken=tkSemicolon);
- end;
- if (AType.ObjKind in [okClassHelper,okRecordHelper]) then
- begin
- if (CurToken<>tkFor) then
- ParseExcTokenError(TokenInfos[tkFor]);
- AType.HelperForType:=ParseType(AType,Scanner.CurSourcePos);
- NextToken;
- end;
- Engine.FinishScope(stAncestors,AType);
- if (AType.IsShortDefinition or AType.IsForward) then
- UngetToken
- else
- begin
- if (AType.ObjKind in [okInterface,okDispInterface]) and (CurToken = tkSquaredBraceOpen) then
- begin
- NextToken;
- AType.GUIDExpr:=DoParseExpression(AType);
- if (CurToken<>tkSquaredBraceClose) then
- ParseExcTokenError(TokenInfos[tkSquaredBraceClose]);
- NextToken;
- end;
- ParseClassMembers(AType);
- end;
- end;
- function TPasParser.ParseClassDecl(Parent: TPasElement;
- const NamePos: TPasSourcePos; const AClassName: String;
- AObjKind: TPasObjKind; PackMode: TPackMode; GenericArgs: TFPList): TPasType;
- Var
- ok: Boolean;
- FT : TPasType;
- AExternalNameSpace,AExternalName : String;
- PCT:TPasClassType;
- begin
- NextToken;
- FT:=Nil;
- if (AObjKind = okClass) and (CurToken = tkOf) then
- begin
- Result := TPasClassOfType(CreateElement(TPasClassOfType, AClassName,
- Parent, NamePos));
- ExpectIdentifier;
- UngetToken; // Only names are allowed as following type
- TPasClassOfType(Result).DestType := ParseType(Result,Scanner.CurSourcePos);
- Engine.FinishScope(stTypeDef,Result);
- exit;
- end;
- if ((AobjKind in [okClass,OKInterface]) and (msExternalClass in CurrentModeswitches) and CurTokenIsIdentifier('external')) then
- begin
- NextToken;
- if CurToken<>tkString then
- UnGetToken
- else
- AExternalNameSpace:=CurTokenString;
- ExpectIdentifier;
- If Not CurTokenIsIdentifier('Name') then
- ParseExc(nParserExpectedExternalClassName,SParserExpectedExternalClassName);
- NextToken;
- if not (CurToken in [tkChar,tkString]) then
- CheckToken(tkString);
- AExternalName:=CurTokenString;
- NextToken;
- end
- else
- begin
- AExternalNameSpace:='';
- AExternalName:='';
- end;
- if (CurTokenIsIdentifier('Helper')) then
- begin
- if Not (AObjKind in [okClass,okTypeHelper,okRecordHelper]) then
- ParseExc(nParserHelperNotAllowed,SParserHelperNotAllowed,[ObjKindNames[AObjKind]]);
- Case AObjKind of
- okClass:
- AObjKind:=okClassHelper;
- okTypeHelper:
- begin
- ExpectToken(tkFor);
- FT:=ParseType(Parent,Scanner.CurSourcePos,'',False);
- end
- end;
- NextToken;
- end;
- PCT := TPasClassType(CreateElement(TPasClassType, AClassName,
- Parent, NamePos));
- Result:=PCT;
- PCT.HelperForType:=FT;
- PCT.IsExternal:=(AExternalName<>'');
- if AExternalName<>'' then
- PCT.ExternalName:=AnsiDequotedStr(AExternalName,'''');
- if AExternalNameSpace<>'' then
- PCT.ExternalNameSpace:=AnsiDequotedStr(AExternalNameSpace,'''');
- ok:=false;
- try
- PCT.ObjKind := AObjKind;
- PCT.PackMode:=PackMode;
- if Assigned(GenericArgs) then
- PCT.SetGenericTemplates(GenericArgs);
- DoParseClassType(PCT);
- Engine.FinishScope(stTypeDef,Result);
- ok:=true;
- finally
- if not ok then
- Result.Release;
- end;
- end;
- function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement): TPasElement;
- begin
- Result := Engine.CreateElement(AClass, AName, AParent, visDefault, Scanner.CurSourcePos);
- end;
- function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; const ASrcPos: TPasSourcePos): TPasElement;
- begin
- Result := Engine.CreateElement(AClass, AName, AParent, visDefault, ASrcPos);
- end;
- function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
- begin
- Result := Engine.CreateElement(AClass, AName, AParent, AVisibility,
- Scanner.CurSourcePos);
- end;
- function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASrcPos: TPasSourcePos): TPasElement;
- begin
- Result := Engine.CreateElement(AClass, AName, AParent, AVisibility, ASrcPos);
- end;
- function TPasParser.CreatePrimitiveExpr(AParent: TPasElement;
- AKind: TPasExprKind; const AValue: String): TPrimitiveExpr;
- begin
- Result:=TPrimitiveExpr(CreateElement(TPrimitiveExpr,'',AParent));
- Result.Kind:=AKind;
- Result.Value:=AValue;
- end;
- function TPasParser.CreateBoolConstExpr(AParent: TPasElement;
- AKind: TPasExprKind; const ABoolValue: Boolean): TBoolConstExpr;
- begin
- Result:=TBoolConstExpr(CreateElement(TBoolConstExpr,'',AParent));
- Result.Kind:=AKind;
- Result.Value:=ABoolValue;
- end;
- function TPasParser.CreateBinaryExpr(AParent: TPasElement; xleft,
- xright: TPasExpr; AOpCode: TExprOpCode): TBinaryExpr;
- begin
- Result:=TBinaryExpr(CreateElement(TBinaryExpr,'',AParent));
- Result.OpCode:=AOpCode;
- Result.Kind:=pekBinary;
- if xleft<>nil then
- begin
- Result.left:=xleft;
- xleft.Parent:=Result;
- end;
- if xright<>nil then
- begin
- Result.right:=xright;
- xright.Parent:=Result;
- end;
- end;
- procedure TPasParser.AddToBinaryExprChain(var ChainFirst: TPasExpr;
- Element: TPasExpr; AOpCode: TExprOpCode);
- begin
- if Element=nil then
- exit
- else if ChainFirst=nil then
- begin
- // empty chain => simply add element, no need to create TBinaryExpr
- ChainFirst:=Element;
- end
- else
- begin
- // create new binary, old becomes left, Element right
- ChainFirst:=CreateBinaryExpr(ChainFirst.Parent,ChainFirst,Element,AOpCode);
- end;
- end;
- procedure TPasParser.AddParamsToBinaryExprChain(var ChainFirst: TPasExpr;
- Params: TParamsExpr);
- // append Params to chain, using the last(right) element as Params.Value
- var
- Bin: TBinaryExpr;
- begin
- if Params.Value<>nil then
- ParseExcSyntaxError;
- if ChainFirst=nil then
- ParseExcSyntaxError;
- if ChainFirst is TBinaryExpr then
- begin
- Bin:=TBinaryExpr(ChainFirst);
- if Bin.left=nil then
- ParseExcSyntaxError;
- if Bin.right=nil then
- ParseExcSyntaxError;
- Params.Value:=Bin.right;
- Params.Value.Parent:=Params;
- Bin.right:=Params;
- Params.Parent:=Bin;
- end
- else
- begin
- Params.Value:=ChainFirst;
- Params.Parent:=ChainFirst.Parent;
- ChainFirst.Parent:=Params;
- ChainFirst:=Params;
- end;
- end;
- {$IFDEF VerbosePasParser}
- procedure TPasParser.WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr
- );
- var
- i: Integer;
- begin
- if First=nil then
- begin
- write(Prefix,'First=nil');
- if Last=nil then
- writeln('=Last')
- else
- begin
- writeln(', ERROR Last=',Last.ClassName);
- ParseExcSyntaxError;
- end;
- end
- else if Last=nil then
- begin
- writeln(Prefix,'ERROR Last=nil First=',First.ClassName);
- ParseExcSyntaxError;
- end
- else if First is TBinaryExpr then
- begin
- i:=0;
- while First is TBinaryExpr do
- begin
- writeln(Prefix,Space(i*2),'bin.left=',TBinaryExpr(First).left.ClassName);
- if First=Last then break;
- First:=TBinaryExpr(First).right;
- inc(i);
- end;
- if First<>Last then
- begin
- writeln(Prefix,Space(i*2),'ERROR Last is not last in chain');
- ParseExcSyntaxError;
- end;
- if not (Last is TBinaryExpr) then
- begin
- writeln(Prefix,Space(i*2),'ERROR Last is not TBinaryExpr: ',Last.ClassName);
- ParseExcSyntaxError;
- end;
- if TBinaryExpr(Last).right=nil then
- begin
- writeln(Prefix,Space(i*2),'ERROR Last.right=nil');
- ParseExcSyntaxError;
- end;
- writeln(Prefix,Space(i*2),'last.right=',TBinaryExpr(Last).right.ClassName);
- end
- else if First=Last then
- writeln(Prefix,'First=Last=',First.ClassName)
- else
- begin
- write(Prefix,'ERROR First=',First.ClassName);
- if Last<>nil then
- writeln(' Last=',Last.ClassName)
- else
- writeln(' Last=nil');
- end;
- end;
- {$ENDIF}
- function TPasParser.CreateUnaryExpr(AParent: TPasElement; AOperand: TPasExpr;
- AOpCode: TExprOpCode): TUnaryExpr;
- begin
- Result:=TUnaryExpr(CreateElement(TUnaryExpr,'',AParent));
- Result.Kind:=pekUnary;
- Result.Operand:=AOperand;
- Result.Operand.Parent:=Result;
- Result.OpCode:=AOpCode;
- end;
- function TPasParser.CreateArrayValues(AParent: TPasElement): TArrayValues;
- begin
- Result:=TArrayValues(CreateElement(TArrayValues,'',AParent));
- Result.Kind:=pekListOfExp;
- end;
- function TPasParser.CreateFunctionType(const AName, AResultName: String;
- AParent: TPasElement; UseParentAsResultParent: Boolean;
- const NamePos: TPasSourcePos): TPasFunctionType;
- begin
- Result:=Engine.CreateFunctionType(AName,AResultName,
- AParent,UseParentAsResultParent,
- NamePos);
- end;
- function TPasParser.CreateInheritedExpr(AParent: TPasElement): TInheritedExpr;
- begin
- Result:=TInheritedExpr(CreateElement(TInheritedExpr,'',AParent));
- Result.Kind:=pekInherited;
- end;
- function TPasParser.CreateSelfExpr(AParent: TPasElement): TSelfExpr;
- begin
- Result:=TSelfExpr(CreateElement(TSelfExpr,'Self',AParent));
- Result.Kind:=pekSelf;
- end;
- function TPasParser.CreateNilExpr(AParent: TPasElement): TNilExpr;
- begin
- Result:=TNilExpr(CreateElement(TNilExpr,'nil',AParent));
- Result.Kind:=pekNil;
- end;
- function TPasParser.CreateRecordValues(AParent: TPasElement): TRecordValues;
- begin
- Result:=TRecordValues(CreateElement(TRecordValues,'',AParent));
- Result.Kind:=pekListOfExp;
- end;
- end.
|