1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044 |
- {
- 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.
- **********************************************************************}
- unit PParser;
- interface
- uses SysUtils, PasTree, PScanner;
- resourcestring
- SErrNoSourceGiven = 'No source file specified';
- SErrMultipleSourceFiles = 'Please specify only one source file';
- SParserError = 'Error';
- SParserErrorAtToken = '%s at token "%s"';
- SParserUngetTokenError = 'Internal error: Cannot unget more tokens, history buffer is full';
- SParserExpectTokenError = 'Expected "%s"';
- SParserExpectedCommaRBracket = 'Expected "," or ")"';
- SParserExpectedCommaSemicolon = 'Expected "," or ";"';
- SParserExpectedCommaColon = 'Expected "," or ":"';
- SParserExpectedLBracketColon = 'Expected "(" or ":"';
- SParserExpectedLBracketSemicolon = 'Expected "(" or ";"';
- SParserExpectedColonSemicolon = 'Expected ":" or ";"';
- SParserExpectedSemiColonEnd = 'Expected ";" or "End"';
- SParserExpectedConstVarID = 'Expected "const", "var" or identifier';
- SParserExpectedColonID = 'Expected ":" or identifier';
- SParserSyntaxError = 'Syntax error';
- SParserTypeSyntaxError = 'Syntax error in type';
- SParserArrayTypeSyntaxError = 'Syntax error in array type';
- SParserInterfaceTokenError = 'Invalid token in interface section of unit';
- SParserInvalidTypeDef = 'Invalid type definition';
- type
- TPasTreeContainer = class
- protected
- FPackage: TPasPackage;
- public
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; const ASourceFilename: String;
- ASourceLinenumber: Integer): TPasElement;
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
- virtual; abstract;
- function CreateFunctionType(const AName, AResultName: String; AParent: TPasElement;
- UseParentAsResultParent: Boolean; const ASourceFilename: String;
- ASourceLinenumber: Integer): TPasFunctionType;
- function FindElement(const AName: String): TPasElement; virtual; abstract;
- function FindModule(const AName: String): TPasModule; virtual;
- property Package: TPasPackage read FPackage;
- 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;
- function ParseSource(AEngine: TPasTreeContainer;
- const FPCCommandLine, OSTarget, CPUTarget: String): TPasModule;
- implementation
- uses Classes;
- type
- TDeclType = (declNone, declConst, declResourcestring, declType, declVar, declThreadvar);
- TProcType = (ptProcedure, ptFunction, ptOperator);
- TPasParser = class
- private
- FFileResolver: TFileResolver;
- FScanner: TPascalScanner;
- FEngine: TPasTreeContainer;
- FCurToken: TToken;
- FCurTokenString: String;
- // UngetToken support:
- FTokenBuffer: array[0..1] of TToken;
- FTokenStringBuffer: array[0..1] of String;
- FTokenBufferIndex, FTokenBufferSize: Integer;
- procedure ParseExc(const Msg: String);
- protected
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement): TPasElement;
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
- public
- Options : set of TPOptions;
- constructor Create(AScanner: TPascalScanner; AFileResolver: TFileResolver;
- AEngine: TPasTreeContainer);
- function CurTokenName: String;
- function CurTokenText: String;
- procedure NextToken;
- procedure UngetToken;
- procedure ExpectToken(tk: TToken);
- function ExpectIdentifier: String;
- function ParseType(Parent: TPasElement; Prefix : String): TPasType;
- function ParseType(Parent: TPasElement): TPasType;
- function ParseComplexType: TPasType;
- procedure ParseArrayType(Element: TPasArrayType);
- function ParseExpression: String;
- procedure AddProcOrFunction(ASection: TPasSection; AProc: TPasProcedure);
- function CheckIfOverloaded(AOwner: TPasClassType;
- const AName: String): TPasElement;
- procedure ParseMain(var Module: TPasModule);
- procedure ParseUnit(var Module: TPasModule);
- procedure ParseUsesList(ASection: TPasSection);
- function ParseConstDecl(Parent: TPasElement): TPasConst;
- function ParseResourcestringDecl(Parent: TPasElement): TPasResString;
- function ParseTypeDecl(Parent: TPasElement): TPasType;
- procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList);
- procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
- AVisibility : TPasMemberVisibility; ClosingBrace: Boolean);
- procedure ParseVarDecl(Parent: TPasElement; List: TList);
- procedure ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
- procedure ParseProcedureOrFunctionHeader(Parent: TPasElement;
- Element: TPasProcedureType; ProcType: TProcType; OfObjectPossible: Boolean);
- function ParseProcedureOrFunctionDecl(Parent: TPasElement;
- ProcType: TProcType): TPasProcedure;
- procedure ParseRecordDecl(Parent: TPasRecordType; IsNested: Boolean); // !!!: Optimize this. We have 3x the same wrapper code around it.
- function ParseClassDecl(Parent: TPasElement; const AClassName: String;
- AObjKind: TPasObjKind): TPasType;
- procedure ParseProperty(Element:TPasElement);
- property FileResolver: TFileResolver read FFileResolver;
- property Scanner: TPascalScanner read FScanner;
- property Engine: TPasTreeContainer read FEngine;
- property CurToken: TToken read FCurToken;
- property CurTokenString: String read FCurTokenString;
- 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.CreateFunctionType(const AName, AResultName: String;
- AParent: TPasElement; UseParentAsResultParent: Boolean;
- const ASourceFilename: String; ASourceLinenumber: Integer): TPasFunctionType;
- var
- ResultParent: TPasElement;
- begin
- Result := TPasFunctionType(CreateElement(TPasFunctionType, AName, AParent,
- ASourceFilename, ASourceLinenumber));
- if UseParentAsResultParent then
- ResultParent := AParent
- else
- ResultParent := Result;
- TPasFunctionType(Result).ResultEl :=
- TPasResultElement(CreateElement(TPasResultElement, AResultName, ResultParent,
- ASourceFilename, ASourceLinenumber));
- end;
- function TPasTreeContainer.FindModule(const AName: String): TPasModule;
- begin
- Result := nil;
- end;
- constructor EParserError.Create(const AReason, AFilename: String;
- ARow, AColumn: Integer);
- begin
- inherited Create(AReason);
- FFilename := AFilename;
- FRow := ARow;
- FColumn := AColumn;
- end;
- procedure TPasParser.ParseExc(const Msg: String);
- begin
- raise EParserError.Create(Format(SParserErrorAtToken, [Msg, CurTokenName]),
- Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
- end;
- constructor TPasParser.Create(AScanner: TPascalScanner;
- AFileResolver: TFileResolver; AEngine: TPasTreeContainer);
- begin
- inherited Create;
- FScanner := AScanner;
- FFileResolver := AFileResolver;
- FEngine := AEngine;
- end;
- function TPasParser.CurTokenName: String;
- begin
- if CurToken = tkIdentifier then
- Result := 'Identifier ' + Scanner.CurTokenString
- else
- Result := TokenInfos[CurToken];
- end;
- function TPasParser.CurTokenText: String;
- begin
- case CurToken of
- tkIdentifier, tkString, tkNumber, tkChar:
- Result := Scanner.CurTokenString;
- else
- Result := TokenInfos[CurToken];
- end;
- end;
- procedure TPasParser.NextToken;
- begin
- if FTokenBufferIndex < FTokenBufferSize then
- begin
- // Get token from buffer
- FCurToken := FTokenBuffer[FTokenBufferIndex];
- FCurTokenString := FTokenStringBuffer[FTokenBufferIndex];
- Inc(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];
- Dec(FTokenBufferSize);
- Dec(FTokenBufferIndex);
- end;
- // Fetch new token
- try
- repeat
- FCurToken := Scanner.FetchToken;
- until not (FCurToken in [tkWhitespace, tkComment]);
- except
- on e: EScannerError do
- raise EParserError.Create(e.Message,
- Scanner.CurFilename, Scanner.CurRow, Scanner.CurColumn);
- end;
- FCurTokenString := Scanner.CurTokenString;
- FTokenBuffer[FTokenBufferSize] := FCurToken;
- FTokenStringBuffer[FTokenBufferSize] := FCurTokenString;
- Inc(FTokenBufferSize);
- Inc(FTokenBufferIndex);
- end;
- end;
- procedure TPasParser.UngetToken;
- begin
- if FTokenBufferIndex = 0 then
- ParseExc(SParserUngetTokenError)
- else
- Dec(FTokenBufferIndex);
- end;
- procedure TPasParser.ExpectToken(tk: TToken);
- begin
- NextToken;
- if CurToken <> tk then
- ParseExc(Format(SParserExpectTokenError, [TokenInfos[tk]]));
- end;
- function TPasParser.ExpectIdentifier: String;
- begin
- ExpectToken(tkIdentifier);
- Result := CurTokenString;
- end;
- function TPasParser.ParseType(Parent: TPasElement): TPasType;
- begin
- Result:=ParseType(Parent,'');
- end;
- function TPasParser.ParseType(Parent: TPasElement; Prefix : String): TPasType;
- procedure ParseRange;
- begin
- Result := TPasRangeType(CreateElement(TPasRangeType, '', Parent));
- try
- TPasRangeType(Result).RangeStart := ParseExpression;
- ExpectToken(tkDotDot);
- TPasRangeType(Result).RangeEnd := ParseExpression;
- except
- Result.Free;
- raise;
- end;
- end;
- var
- Name, s: String;
- EnumValue: TPasEnumValue;
- Ref: TPasElement;
- HadPackedModifier : Boolean; // 12/04/04 - Dave - Added
- begin
- Result := nil; // !!!: Remove in the future
- HadPackedModifier := False; { Assume not present }
- NextToken;
- if CurToken = tkPacked then { If PACKED modifier }
- begin { Handle PACKED modifier for all situations }
- NextToken; { Move to next token for rest of parse }
- if CurToken in [tkArray, tkRecord, tkObject, tkClass] then { If allowed }
- HadPackedModifier := True { rememeber for later }
- else { otherwise, syntax error }
- ParseExc(Format(SParserExpectTokenError,['ARRAY, RECORD, OBJECT or CLASS']))
- end;
- case CurToken of
- tkIdentifier:
- begin
- Name := CurTokenString;
- If (Prefix<>'') then
- Name:=Prefix+'.'+Name;
- NextToken;
- if CurToken = tkDot then
- begin
- ExpectIdentifier;
- Name := Name+'.'+CurTokenString;
- end else
- UngetToken;
- Ref := nil;
- s := UpperCase(Name);
- if s = 'BYTE' then Name := 'Byte'
- else if s = 'BOOLEAN' then Name := 'Boolean'
- else if s = 'CHAR' then Name := 'Char'
- else if s = 'INTEGER' then Name := 'Integer'
- else if s = 'INT64' then Name := 'Int64'
- else if s = 'LONGINT' then Name := 'LongInt'
- else if s = 'LONGWORD' then Name := 'LongWord'
- else if s = 'SHORTINT' then Name := 'ShortInt'
- else if s = 'SMALLINT' then Name := 'SmallInt'
- else if s = 'STRING' then Name := 'String'
- else if s = 'WORD' then Name := 'Word'
- else
- Ref := Engine.FindElement(Name);
- if Assigned(Ref) then
- begin
- {Result := TPasTypeRef(CreateElement(TPasTypeRef, Name, nil));
- TPasTypeRef(Result).RefType := Ref as TPasType;}
- Result := Ref as TPasType;
- Result.AddRef;
- end else
- Result := TPasUnresolvedTypeRef(CreateElement(TPasUnresolvedTypeRef, Name, nil));
- // !!!: Doesn't make sense for resolved types
- if Name = 'String' then
- begin
- NextToken;
- if CurToken = tkSquaredBraceOpen then
- begin
- // !!!: Parse the string length value and store it
- repeat
- NextToken;
- until CurToken = tkSquaredBraceClose;
- end else
- UngetToken;
- end;
- end;
- tkCaret:
- begin
- Result := TPasPointerType(CreateElement(TPasPointerType, '', Parent));
- TPasPointerType(Result).DestType := ParseType(nil);
- end;
- tkArray:
- begin
- Result := TPasArrayType(CreateElement(TPasArrayType, '', Parent));
- TPasArrayType(Result).IsPacked := HadPackedModifier;
- ParseArrayType(TPasArrayType(Result));
- end;
- tkBraceOpen:
- begin
- Result := TPasEnumType(CreateElement(TPasEnumType, '', Parent));
- while True do
- begin
- NextToken;
- EnumValue := TPasEnumValue(CreateElement(TPasEnumValue,
- CurTokenString, Result));
- TPasEnumType(Result).Values.Add(EnumValue);
- NextToken;
- if CurToken = tkBraceClose then
- break
- else if CurToken in [tkEqual,tkAssign] then
- begin
- EnumValue.AssignedValue:=ParseExpression;
- NextToken;
- if CurToken = tkBraceClose then
- Break
- else if not (CurToken=tkComma) then
- ParseExc(SParserExpectedCommaRBracket);
- end
- else if not (CurToken=tkComma) then
- ParseExc(SParserExpectedCommaRBracket)
- end;
- end;
- tkSet:
- begin
- Result := TPasSetType(CreateElement(TPasSetType, '', Parent));
- try
- ExpectToken(tkOf);
- TPasSetType(Result).EnumType := ParseType(Result);
- except
- Result.Free;
- raise;
- end;
- end;
- tkRecord:
- begin
- Result := TPasRecordType(CreateElement(TPasRecordType, '', Parent));
- TPasRecordType(Result).IsPacked := HadPackedModifier;
- try
- ParseRecordDecl(TPasRecordType(Result), False);
- except
- Result.Free;
- raise;
- end;
- end;
- tkProcedure:
- begin
- Result := TPasProcedureType(
- CreateElement(TPasProcedureType, '', Parent));
- try
- ParseProcedureOrFunctionHeader(Result,
- TPasProcedureType(Result), ptProcedure, True);
- except
- Result.Free;
- raise;
- end;
- end;
- tkFunction:
- begin
- Result := Engine.CreateFunctionType('', 'Result', Parent, False,
- Scanner.CurFilename, Scanner.CurRow);
- try
- ParseProcedureOrFunctionHeader(Result,
- TPasFunctionType(Result), ptFunction, True);
- except
- Result.Free;
- raise;
- end;
- end;
- else
- begin
- UngetToken;
- ParseRange;
- end;
- // ParseExc(SParserTypeSyntaxError);
- end;
- end;
- function TPasParser.ParseComplexType: TPasType;
- begin
- NextToken;
- case CurToken of
- tkProcedure:
- begin
- Result := TPasProcedureType(CreateElement(TPasProcedureType, '', nil));
- ParseProcedureOrFunctionHeader(Result,
- TPasProcedureType(Result), ptProcedure, True);
- UngetToken; // Unget semicolon
- end;
- tkFunction:
- begin
- Result := Engine.CreateFunctionType('', 'Result', nil, False,
- Scanner.CurFilename, Scanner.CurRow);
- ParseProcedureOrFunctionHeader(Result,
- TPasFunctionType(Result), ptFunction, True);
- UngetToken; // Unget semicolon
- end;
- else
- begin
- UngetToken;
- Result := ParseType(nil);
- exit;
- end;
- end;
- end;
- procedure TPasParser.ParseArrayType(Element: TPasArrayType);
- Var
- S : String;
- begin
- NextToken;
- S:='';
- case CurToken of
- tkSquaredBraceOpen:
- begin
- repeat
- NextToken;
- if CurToken<>tkSquaredBraceClose then
- S:=S+CurTokenText;
- until CurToken = tkSquaredBraceClose;
- Element.IndexRange:=S;
- ExpectToken(tkOf);
- Element.ElType := ParseType(nil);
- end;
- tkOf:
- begin
- NextToken;
- if CurToken = tkConst then
- // ArrayEl.AppendChild(Doc.CreateElement('const'))
- else
- begin
- UngetToken;
- Element.ElType := ParseType(nil);
- end
- end
- else
- ParseExc(SParserArrayTypeSyntaxError);
- end;
- end;
- function TPasParser.ParseExpression: String;
- var
- BracketLevel: Integer;
- MayAppendSpace, AppendSpace, NextAppendSpace: Boolean;
- begin
- SetLength(Result, 0);
- BracketLevel := 0;
- MayAppendSpace := False;
- AppendSpace := False;
- while True do
- begin
- NextToken;
- { !!!: Does not detect when normal brackets and square brackets are mixed
- in a wrong way. }
- if CurToken in [tkBraceOpen, tkSquaredBraceOpen] then
- Inc(BracketLevel)
- else if CurToken in [tkBraceClose, tkSquaredBraceClose] then
- begin
- if BracketLevel = 0 then
- break;
- Dec(BracketLevel);
- end else if (CurToken in [tkComma, tkSemicolon, tkColon, tkSquaredBraceClose,
- tkDotDot]) and (BracketLevel = 0) then
- break;
- if MayAppendSpace then
- begin
- NextAppendSpace := False;
- case CurToken of
- tkBraceOpen, tkBraceClose, tkDivision, tkEqual, tkCaret, tkAnd, tkAs,
- tkDiv, tkIn, tkIs, tkMinus, tkMod, tkMul, tkNot, tkOf, tkOn,
- tkOr, tkPlus, tkSHL, tkSHR, tkXOR:
- { tkPlus.._ASSIGNMENT, _UNEQUAL, tkPlusASN.._XORASN, _AS, _AT, _IN, _IS,
- tkOf, _ON, _OR, _AND, _DIV, _MOD, _NOT, _SHL, _SHR, _XOR:}
- begin
- AppendSpace := True;
- NextAppendSpace := True;
- end;
- end;
- if AppendSpace then
- Result := Result + ' ';
- AppendSpace := NextAppendSpace;
- end else
- MayAppendSpace := True;
- if CurToken=tkString then
- begin
- If (Length(CurTokenText)>0) and (CurTokenText[1]=#0) then
- Writeln('First char is null : "',CurTokenText,'"');
- Result := Result + ''''+StringReplace(CurTokenText,'''','''''',[rfReplaceAll])+''''
- end
- else
- Result := Result + CurTokenText;
- end;
- UngetToken;
- end;
- procedure TPasParser.AddProcOrFunction(ASection: TPasSection;
- AProc: TPasProcedure);
- var
- i: Integer;
- Member: TPasElement;
- OverloadedProc: TPasOverloadedProc;
- begin
- for i := 0 to ASection.Functions.Count - 1 do
- begin
- Member := TPasElement(ASection.Functions[i]);
- if CompareText(Member.Name, AProc.Name) = 0 then
- begin
- if Member.ClassType = TPasOverloadedProc then
- TPasOverloadedProc(Member).Overloads.Add(AProc)
- else
- begin
- OverloadedProc := TPasOverloadedProc.Create(AProc.Name, ASection);
- OverloadedProc.Overloads.Add(Member);
- OverloadedProc.Overloads.Add(AProc);
- ASection.Functions[i] := OverloadedProc;
- ASection.Declarations[ASection.Declarations.IndexOf(Member)] :=
- OverloadedProc;
- end;
- exit;
- end;
- end;
- // Not overloaded, so just add the proc/function to the lists
- ASection.Declarations.Add(AProc);
- ASection.Functions.Add(AProc);
- end;
- // Returns the parent for an element which is to be created
- function TPasParser.CheckIfOverloaded(AOwner: TPasClassType;
- const AName: String): TPasElement;
- var
- i: Integer;
- Member: TPasElement;
- begin
- for i := 0 to AOwner.Members.Count - 1 do
- begin
- Member := TPasElement(AOwner.Members[i]);
- if CompareText(Member.Name, AName) = 0 then
- begin
- if Member.ClassType = TPasOverloadedProc then
- Result := Member
- else
- begin
- Result := TPasOverloadedProc.Create(AName, AOwner);
- Result.Visibility := Member.Visibility;
- TPasOverloadedProc(Result).Overloads.Add(Member);
- AOwner.Members[i] := Result;
- end;
- exit;
- end;
- end;
- Result := AOwner;
- end;
- procedure TPasParser.ParseMain(var Module: TPasModule);
- begin
- NextToken;
- case CurToken of
- tkUnit: ParseUnit(Module);
- else
- ParseExc(Format(SParserExpectTokenError, ['unit']));
- end;
- end;
- // Starts after the "unit" token
- procedure TPasParser.ParseUnit(var Module: TPasModule);
- var
- CurBlock: TDeclType;
- Section: TPasSection;
- ConstEl: TPasConst;
- ResStrEl: TPasResString;
- TypeEl: TPasType;
- ClassEl: TPasClassType;
- List: TList;
- i,j: Integer;
- VarEl: TPasVariable;
- begin
- Module := nil;
- Module := TPasModule(CreateElement(TPasModule, ExpectIdentifier,
- Engine.Package));
- if Assigned(Engine.Package) then
- begin
- Module.PackageName := Engine.Package.Name;
- Engine.Package.Modules.Add(Module);
- end;
- ExpectToken(tkSemicolon);
- ExpectToken(tkInterface);
- Section := TPasSection(CreateElement(TPasSection, '', Module));
- Module.InterfaceSection := Section;
- CurBlock := declNone;
- while True do
- begin
- NextToken;
- if CurToken = tkImplementation then
- break;
- case CurToken of
- tkUses:
- ParseUsesList(Section);
- tkConst:
- CurBlock := declConst;
- tkResourcestring:
- CurBlock := declResourcestring;
- tkType:
- CurBlock := declType;
- tkVar:
- CurBlock := declVar;
- tkThreadVar:
- CurBlock := declThreadVar;
- tkProcedure:
- begin
- AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, ptProcedure));
- CurBlock := declNone;
- end;
- tkFunction:
- begin
- AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, ptFunction));
- CurBlock := declNone;
- end;
- tkProperty:
- begin
- ExpectIdentifier;
- ParseProperty(CreateElement(TPasProperty, CurTokenString, Section));
- end;
- tkOperator:
- begin
- AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, ptOperator));
- CurBlock := declNone;
- end;
- tkIdentifier:
- begin
- case CurBlock of
- declConst:
- begin
- ConstEl := ParseConstDecl(Section);
- Section.Declarations.Add(ConstEl);
- Section.Consts.Add(ConstEl);
- end;
- declResourcestring:
- begin
- ResStrEl := ParseResourcestringDecl(Section);
- Section.Declarations.Add(ResStrEl);
- Section.ResStrings.Add(ResStrEl);
- end;
- declType:
- begin
- TypeEl := ParseTypeDecl(Section);
- if Assigned(TypeEl) then // !!!
- begin
- Section.Declarations.Add(TypeEl);
- if TypeEl.ClassType = TPasClassType then
- begin
- // Remove previous forward declarations, if necessary
- for i := 0 to Section.Classes.Count - 1 do
- begin
- ClassEl := TPasClassType(Section.Classes[i]);
- if CompareText(ClassEl.Name, TypeEl.Name) = 0 then
- begin
- Section.Classes.Delete(i);
- for j := 0 to Section.Declarations.Count - 1 do
- if CompareText(TypeEl.Name,
- TPasElement(Section.Declarations[j]).Name) = 0 then
- begin
- Section.Declarations.Delete(j);
- break;
- end;
- ClassEl.Release;
- break;
- end;
- end;
- // Add the new class to the class list
- Section.Classes.Add(TypeEl)
- end else
- Section.Types.Add(TypeEl);
- end;
- end;
- declVar, declThreadVar:
- begin
- List := TList.Create;
- try
- try
- ParseVarDecl(Section, List);
- except
- for i := 0 to List.Count - 1 do
- TPasVariable(List[i]).Release;
- raise;
- end;
- for i := 0 to List.Count - 1 do
- begin
- VarEl := TPasVariable(List[i]);
- Section.Declarations.Add(VarEl);
- Section.Variables.Add(VarEl);
- end;
- finally
- List.Free;
- end;
- end;
- else
- ParseExc(SParserSyntaxError);
- end;
- end;
- else
- ParseExc(SParserInterfaceTokenError);
- end;
- end;
- end;
- // Starts after the "uses" token
- procedure TPasParser.ParseUsesList(ASection: TPasSection);
- var
- UnitName: String;
- Element: TPasElement;
- begin
- while True do
- begin
- UnitName := ExpectIdentifier;
- Element := Engine.FindModule(UnitName);
- if Assigned(Element) then
- Element.AddRef
- else
- Element := TPasType(CreateElement(TPasUnresolvedTypeRef, UnitName,
- ASection));
- ASection.UsesList.Add(Element);
- NextToken;
- if CurToken = tkSemicolon then
- break
- else if CurToken <> tkComma then
- ParseExc(SParserExpectedCommaSemicolon);
- end;
- end;
- // Starts after the variable name
- function TPasParser.ParseConstDecl(Parent: TPasElement): TPasConst;
- begin
- Result := TPasConst(CreateElement(TPasConst, CurTokenString, Parent));
- try
- NextToken;
- if CurToken = tkColon then
- Result.VarType := ParseType(nil)
- else
- UngetToken;
- ExpectToken(tkEqual);
- Result.Value := ParseExpression;
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- // Starts after the variable name
- function TPasParser.ParseResourcestringDecl(Parent: TPasElement): TPasResString;
- begin
- Result := TPasResString(CreateElement(TPasResString, CurTokenString, Parent));
- try
- ExpectToken(tkEqual);
- Result.Value := ParseExpression;
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- // Starts after the type name
- function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType;
- var
- TypeName: String;
- procedure ParseRange;
- begin
- Result := TPasRangeType(CreateElement(TPasRangeType, TypeName, Parent));
- try
- TPasRangeType(Result).RangeStart := ParseExpression;
- ExpectToken(tkDotDot);
- TPasRangeType(Result).RangeEnd := ParseExpression;
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- var
- EnumValue: TPasEnumValue;
- Prefix : String;
- HadPackedModifier : Boolean; // 12/04/04 - Dave - Added
- begin
- TypeName := CurTokenString;
- ExpectToken(tkEqual);
- NextToken;
- HadPackedModifier := False; { Assume not present }
- if CurToken = tkPacked then { If PACKED modifier }
- begin { Handle PACKED modifier for all situations }
- NextToken; { Move to next token for rest of parse }
- if CurToken in [tkArray, tkRecord, tkObject, tkClass] then { If allowed }
- HadPackedModifier := True { rememeber for later }
- else { otherwise, syntax error }
- ParseExc(Format(SParserExpectTokenError,['ARRAY, RECORD, OBJECT or CLASS']))
- end;
- case CurToken of
- tkRecord:
- begin
- Result := TPasRecordType(CreateElement(TPasRecordType, TypeName,
- Parent));
- try
- ParseRecordDecl(TPasRecordType(Result), False);
- ExpectToken(tkSemicolon);
- TPasRecordType(Result).IsPacked := HadPackedModifier;
- except
- Result.Free;
- raise;
- end;
- end;
- tkObject:
- begin
- Result := ParseClassDecl(Parent, TypeName, okObject);
- TPasClassType(Result).IsPacked := HadPackedModifier;
- end;
- tkClass:
- begin
- Result := ParseClassDecl(Parent, TypeName, okClass);
- { could be TPasClassOfType }
- if result is TPasClassType then
- TPasClassType(Result).IsPacked := HadPackedModifier;
- end;
- tkInterface:
- Result := ParseClassDecl(Parent, TypeName, okInterface);
- tkCaret:
- begin
- Result := TPasPointerType(CreateElement(TPasPointerType, TypeName,
- Parent));
- try
- TPasPointerType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- tkIdentifier:
- begin
- Prefix:=CurTokenString;
- NextToken;
- if CurToken = tkDot then
- begin
- ExpectIdentifier;
- NextToken;
- end
- else
- Prefix:='';
- if CurToken = tkSemicolon then
- begin
- UngetToken;
- UngetToken;
- Result := TPasAliasType(CreateElement(TPasAliasType, TypeName,
- Parent));
- try
- TPasAliasType(Result).DestType := ParseType(nil,Prefix);
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end else if CurToken = tkSquaredBraceOpen then
- begin
- // !!!: Check for string type and store string length somewhere
- Result := TPasAliasType(CreateElement(TPasAliasType, TypeName,
- Parent));
- try
- TPasAliasType(Result).DestType :=
- TPasUnresolvedTypeRef.Create(CurTokenString, Parent);
- ParseExpression;
- ExpectToken(tkSquaredBraceClose);
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end else
- begin
- UngetToken;
- UngetToken;
- ParseRange;
- end;
- end;
- { _STRING, _FILE:
- begin
- Result := TPasAliasType(CreateElement(TPasAliasType, TypeName, Parent));
- UngetToken;
- TPasAliasType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- end;}
- tkArray:
- begin
- Result := TPasArrayType(CreateElement(TPasArrayType, TypeName, Parent));
- try
- ParseArrayType(TPasArrayType(Result));
- TPasArrayType(Result).IsPacked := HadPackedModifier;
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- tkSet:
- begin
- Result := TPasSetType(CreateElement(TPasSetType, TypeName, Parent));
- try
- ExpectToken(tkOf);
- TPasSetType(Result).EnumType := ParseType(Result);
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- tkBraceOpen:
- begin
- Result := TPasEnumType(CreateElement(TPasEnumType, TypeName, Parent));
- try
- while True do
- begin
- NextToken;
- EnumValue := TPasEnumValue(CreateElement(TPasEnumValue,
- CurTokenString, Result));
- TPasEnumType(Result).Values.Add(EnumValue);
- NextToken;
- if CurToken = tkBraceClose then
- break
- else if CurToken in [tkEqual,tkAssign] then
- begin
- EnumValue.AssignedValue:=ParseExpression;
- NextToken;
- if CurToken = tkBraceClose then
- Break
- else if not (CurToken=tkComma) then
- ParseExc(SParserExpectedCommaRBracket);
- end
- else if not (CurToken=tkComma) then
- ParseExc(SParserExpectedCommaRBracket)
- end;
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- tkProcedure:
- begin
- Result := TPasProcedureType(CreateElement(TPasProcedureType, TypeName,
- Parent));
- try
- ParseProcedureOrFunctionHeader(Result,
- TPasProcedureType(Result), ptProcedure, True);
- except
- Result.Free;
- raise;
- end;
- end;
- tkFunction:
- begin
- Result := Engine.CreateFunctionType(TypeName, 'Result', Parent, False,
- Scanner.CurFilename, Scanner.CurRow);
- try
- ParseProcedureOrFunctionHeader(Result,
- TPasFunctionType(Result), ptFunction, True);
- except
- Result.Free;
- raise;
- end;
- end;
- tkType:
- begin
- Result := TPasTypeAliasType(CreateElement(TPasTypeAliasType, TypeName,
- Parent));
- try
- TPasTypeAliasType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- except
- Result.Free;
- raise;
- end;
- end;
- else
- begin
- UngetToken;
- ParseRange;
- end;
- end;
- end;
- // Starts after the variable name
- procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList);
- begin
- ParseInlineVarDecl(Parent, VarList, visDefault, False);
- end;
- procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
- AVisibility: TPasMemberVisibility; ClosingBrace: Boolean);
- var
- VarNames: TStringList;
- i: Integer;
- VarType: TPasType;
- VarEl: TPasVariable;
- begin
- VarNames := TStringList.Create;
- try
- while True do
- begin
- VarNames.Add(CurTokenString);
- NextToken;
- if CurToken = tkColon then
- break
- else if CurToken <> tkComma then
- ParseExc(SParserExpectedCommaColon);
- ExpectIdentifier;
- end;
- VarType := ParseComplexType;
- for i := 0 to VarNames.Count - 1 do
- begin
- VarEl := TPasVariable(CreateElement(TPasVariable, VarNames[i], Parent,
- AVisibility));
- VarEl.VarType := VarType;
- if i > 0 then
- VarType.AddRef;
- VarList.Add(VarEl);
- end;
- NextToken;
- // Records may be terminated with end, no semicolon
- if (CurToken <> tkEnd) and (CurToken <> tkSemicolon) and not
- (ClosingBrace and (CurToken = tkBraceClose)) then
- ParseExc(SParserExpectedSemiColonEnd);
- finally
- VarNames.Free;
- end;
- end;
- // Starts after the variable name
- procedure TPasParser.ParseVarDecl(Parent: TPasElement; List: TList);
- var
- i: Integer;
- VarType: TPasType;
- Value, S: String;
- M: string;
- begin
- while True do
- begin
- List.Add(CreateElement(TPasVariable, CurTokenString, Parent));
- NextToken;
- if CurToken = tkColon then
- break
- else if CurToken <> tkComma then
- ParseExc(SParserExpectedCommaColon);
- ExpectIdentifier;
- end;
- VarType := ParseComplexType;
- for i := 0 to List.Count - 1 do
- begin
- TPasVariable(List[i]).VarType := VarType;
- if i > 0 then
- VarType.AddRef;
- end;
- NextToken;
- If CurToken=tkEqual then
- begin
- Value := ParseExpression;
- for i := 0 to List.Count - 1 do
- TPasVariable(List[i]).Value := Value;
- end
- else
- UngetToken;
- NextToken;
- if CurToken = tkAbsolute then
- begin
- // !!!: Store this information
- ExpectIdentifier;
- end else
- UngetToken;
- ExpectToken(tkSemicolon);
- M := '';
- while True do
- begin
- NextToken;
- if CurToken = tkIdentifier then
- begin
- s := UpperCase(CurTokenText);
- if s = 'CVAR' then
- begin
- M := M + '; cvar';
- ExpectToken(tkSemicolon);
- end
- else if (s = 'EXTERNAL') or (s = 'PUBLIC') or (s = 'EXPORT') then
- begin
- M := M + ';' + CurTokenText;
- if s = 'EXTERNAL' then
- begin
- NextToken;
- if ((CurToken = tkString) or (CurToken = tkIdentifier)) and (UpperCase(CurTokenText)<> 'NAME') then
- begin
- // !!!: Is this really correct for tkString?
- M := M + ' ' + CurTokenText;
- NextToken;
- end;
- end
- else
- NextToken;
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'NAME') then
- begin
- M := M + ' name ';
- NextToken;
- if (CurToken = tkString) or (CurToken = tkIdentifier) then
- // !!!: Is this really correct for tkString?
- M := M + CurTokenText
- else
- ParseExc(SParserSyntaxError);
- ExpectToken(tkSemicolon);
- end
- else if CurToken <> tkSemicolon then
- ParseExc(SParserSyntaxError);
- end else
- begin
- UngetToken;
- break;
- end
- end else
- begin
- UngetToken;
- break;
- end;
- end; // while
- if M <> '' then
- for i := 0 to List.Count - 1 do
- TPasVariable(List[i]).Modifiers := M;
- end;
- // Starts after the opening bracket token
- procedure TPasParser.ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
- var
- ArgNames: TStringList;
- IsUntyped: Boolean;
- Name, Value: String;
- i: Integer;
- Arg: TPasArgument;
- Access: TArgumentAccess;
- ArgType: TPasType;
- begin
- while True do
- begin
- ArgNames := TStringList.Create;
- Access := argDefault;
- IsUntyped := False;
- ArgType := nil;
- while True do
- begin
- NextToken;
- if CurToken = tkConst then
- begin
- Access := argConst;
- 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(SParserExpectedConstVarID);
- ArgNames.Add(Name);
- 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(SParserExpectedCommaColon);
- end;
- SetLength(Value, 0);
- if not IsUntyped then
- begin
- ArgType := ParseType(nil);
- NextToken;
- if CurToken = tkEqual then
- begin
- Value := ParseExpression;
- end else
- UngetToken;
- end;
- for i := 0 to ArgNames.Count - 1 do
- begin
- Arg := TPasArgument(CreateElement(TPasArgument, ArgNames[i], Parent));
- Arg.Access := Access;
- Arg.ArgType := ArgType;
- if (i > 0) and Assigned(ArgType) then
- ArgType.AddRef;
- Arg.Value := Value;
- Args.Add(Arg);
- end;
- ArgNames.Free;
- NextToken;
- if CurToken = EndToken then
- break;
- end;
- 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);
-
- Var
- Tok : String;
-
- begin
- NextToken;
- case ProcType of
- ptFunction:
- begin
- if CurToken = tkBraceOpen then
- begin
- NextToken;
- if (CurToken = tkBraceClose) then
- else
- begin
- UngetToken;
- ParseArgList(Parent, Element.Args, tkBraceClose);
- end;
- ExpectToken(tkColon);
- end else if CurToken <> tkColon then
- ParseExc(SParserExpectedLBracketColon);
- if Assigned(Element) then // !!!
- TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
- else
- ParseType(nil);
- end;
- ptProcedure:
- begin
- if CurToken = tkBraceOpen then
- begin
- NextToken;
- if (CurToken = tkBraceClose) then
- else
- begin
- UngetToken;
- ParseArgList(Element, Element.Args, tkBraceClose);
- end
- end else if (CurToken = tkSemicolon) or (OfObjectPossible and (CurToken = tkOf)) then
- UngetToken
- else
- ParseExc(SParserExpectedLBracketSemicolon);
- end;
- ptOperator:
- begin
- ParseArgList(Element, Element.Args, tkBraceClose);
- NextToken;
- if (CurToken=tkIdentifier) then begin
- TPasFunctionType(Element).ResultEl.Name := CurTokenName;
- ExpectToken(tkColon);
- end
- else if (CurToken=tkColon) then
- TPasFunctionType(Element).ResultEl.Name := 'Result'
- else
- ParseExc(SParserExpectedColonID);
- if Assigned(Element) then // !!!
- TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
- else
- ParseType(nil);
- end;
- end;
- NextToken;
- if OfObjectPossible and (CurToken = tkOf) then
- begin
- ExpectToken(tkObject);
- Element.IsOfObject := True;
- end else
- UngetToken;
- NextToken;
- if CurToken = tkEqual then
- begin
- // for example: const p: procedure = nil;
- UngetToken;
- exit;
- end else
- UngetToken;
- ExpectToken(tkSemicolon);
- while True do
- begin
- NextToken;
- if (CurToken = tkIdentifier) then
- begin
- Tok:=UpperCase(CurTokenString);
- If (Tok='CDECL') then
- begin
- { El['calling-conv'] := 'cdecl';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='STDCALL') then
- begin
- { El['calling-conv'] := 'stdcall';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='COMPILERPROC') then
- begin
- { El['calling-conv'] := 'compilerproc';}
- ExpectToken(tkSemicolon);
- end
- else if (tok='DEPRECATED') then
- begin
- { El['calling-conv'] := 'deprecated';}
- ExpectToken(tkSemicolon);
- end
- else if (tok='OVERLOAD') then
- begin
- TPasProcedure(Parent).IsOverload := True;
- ExpectToken(tkSemicolon);
- end
- else if (tok='INLINE') then
- begin
- ExpectToken(tkSemicolon);
- end
- else if (UpperCase(CurTokenString) = 'EXTERNAL') then
- repeat
- NextToken;
- until CurToken = tkSemicolon
- else
- begin
- UnGetToken;
- Break;
- end
- end
- else if (CurToken = tkInline) then
- begin
- { TPasProcedure(Parent).IsInline := True;}
- ExpectToken(tkSemicolon);
- end
- else if (CurToken = tkSquaredBraceOpen) then
- begin
- repeat
- NextToken
- until CurToken = tkSquaredBraceClose;
- ExpectToken(tkSemicolon);
- end
- else
- begin
- UngetToken;
- break;
- end;
- end;
- end;
- procedure TPasParser.ParseProperty(Element:TPasElement);
- function GetAccessorName: String;
- begin
- ExpectIdentifier;
- Result := CurTokenString;
- while True do
- begin
- NextToken;
- if CurToken = tkDot then
- begin
- ExpectIdentifier;
- Result := Result + '.' + CurTokenString;
- end else
- break;
- end;
- UngetToken;
- end;
- begin
- NextToken;
- // !!!: Parse array properties correctly
- if CurToken = tkSquaredBraceOpen then
- begin
- ParseArgList(Element, TPasProperty(Element).Args, tkSquaredBraceClose);
- NextToken;
- end;
- if CurToken = tkColon then
- begin
- // read property type
- TPasProperty(Element).VarType := ParseType(Element);
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- // read 'index' access modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'INDEX') then
- TPasProperty(Element).IndexValue := ParseExpression
- else
- UngetToken;
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- // read 'read' access modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'READ') then
- TPasProperty(Element).ReadAccessorName := GetAccessorName
- else
- UngetToken;
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- // read 'write' access modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'WRITE') then
- TPasProperty(Element).WriteAccessorName := GetAccessorName
- else
- UngetToken;
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- // read 'stored' access modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'STORED') then
- begin
- NextToken;
- if CurToken = tkTrue then
- TPasProperty(Element).StoredAccessorName := 'True'
- else if CurToken = tkFalse then
- TPasProperty(Element).StoredAccessorName := 'False'
- else if CurToken = tkIdentifier then
- TPasProperty(Element).StoredAccessorName := CurTokenString
- else
- ParseExc(SParserSyntaxError);
- end else
- UngetToken;
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- // read 'default' value modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then
- TPasProperty(Element).DefaultValue := ParseExpression
- else
- UngetToken;
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- // read 'nodefault' modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'NODEFAULT') then
- begin
- TPasProperty(Element).IsNodefault:=true;
- end;
- NextToken;
- end;
- if CurToken = tkSemicolon then
- begin
- // read semicolon
- NextToken;
- end;
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then
- begin
- NextToken;
- if CurToken = tkSemicolon then
- begin
- TPasProperty(Element).IsDefault := True;
- UngetToken;
- end else
- begin
- UngetToken;
- TPasProperty(Element).DefaultValue := ParseExpression;
- end;
- end else
- UngetToken;
- end;
- // Starts after the "procedure" or "function" token
- function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
- ProcType: TProcType): TPasProcedure;
- var
- Name: String;
- i: Integer;
- begin
- case ProcType of
- ptFunction:
- begin
- Name := ExpectIdentifier;
- Result := TPasFunction(CreateElement(TPasFunction, Name, Parent));
- Result.ProcType := Engine.CreateFunctionType('', 'Result', Result, True,
- Scanner.CurFilename, Scanner.CurRow);
- end;
- ptProcedure:
- begin
- Name := ExpectIdentifier;
- Result := TPasProcedure(CreateElement(TPasProcedure, Name, Parent));
- Result.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
- Result));
- end;
- ptOperator:
- begin
- NextToken;
- Name := 'operator ' + TokenInfos[CurToken];
- Result := TPasOperator(CreateElement(TPasOperator, Name, Parent));
- Result.ProcType := Engine.CreateFunctionType('', '__INVALID__', Result,
- True, Scanner.CurFilename, Scanner.CurRow);
- end;
- end;
- ParseProcedureOrFunctionHeader(Result, Result.ProcType, ProcType, False);
- if ProcType = ptOperator then
- begin
- Result.Name := Result.Name + '(';
- for i := 0 to Result.ProcType.Args.Count - 1 do
- begin
- if i > 0 then
- Result.Name := Result.Name + ', ';
- Result.Name := Result.Name +
- TPasArgument(Result.ProcType.Args[i]).ArgType.Name;
- end;
- Result.Name := Result.Name + '): ' +
- TPasFunctionType(Result.ProcType).ResultEl.ResultType.Name;
- end;
- end;
- // Starts after the "record" token
- procedure TPasParser.ParseRecordDecl(Parent: TPasRecordType; IsNested: Boolean);
- var
- VariantName: String;
- Variant: TPasVariant;
- begin
- while True do
- begin
- if IsNested then
- begin
- if CurToken = tkBraceClose then
- break;
- NextToken;
- if CurToken = tkBraceClose then
- break;
- end else
- begin
- if CurToken = tkEnd then
- break;
- NextToken;
- if CurToken = tkEnd then
- break;
- end;
- if CurToken = tkCase then
- begin
- ExpectToken(tkIdentifier);
- VariantName := CurTokenString;
- NextToken;
- if CurToken = tkColon then
- Parent.VariantName := VariantName
- else
- begin
- UngetToken;
- UngetToken;
- end;
- Parent.VariantType := ParseType(Parent);
- Parent.Variants := TList.Create;
- ExpectToken(tkOf);
- while True do
- begin
- Variant := TPasVariant(CreateElement(TPasVariant, '', Parent));
- Parent.Variants.Add(Variant);
- Variant.Values := TStringList.Create;
- while True do
- begin
- Variant.Values.Add(ParseExpression);
- NextToken;
- if CurToken = tkColon then
- break
- else if CurToken <> tkComma then
- ParseExc(SParserExpectedCommaColon);
- end;
- ExpectToken(tkBraceOpen);
- Variant.Members := TPasRecordType(CreateElement(TPasRecordType, '',
- Variant));
- try
- ParseRecordDecl(Variant.Members, True);
- except
- Variant.Members.Free;
- raise;
- end;
- NextToken;
- if CurToken = tkSemicolon then
- NextToken;
- if (CurToken = tkEnd) or (CurToken = tkBraceClose) then
- break
- else
- UngetToken;
- end
- end else
- ParseInlineVarDecl(Parent, Parent.Members, visDefault, IsNested);
- end;
- end;
- // Starts after the "class" token
- function TPasParser.ParseClassDecl(Parent: TPasElement;
- const AClassName: String; AObjKind: TPasObjKind): TPasType;
- var
- CurVisibility: TPasMemberVisibility;
- procedure ProcessMethod(const MethodTypeName: String; HasReturnValue: Boolean);
- var
- Owner: TPasElement;
- Proc: TPasProcedure;
- s: String;
- pt: TProcType;
- begin
- ExpectIdentifier;
- Owner := CheckIfOverloaded(TPasClassType(Result), CurTokenString);
- if HasReturnValue then
- begin
- Proc := TPasFunction(CreateElement(TPasFunction, CurTokenString, Owner,
- CurVisibility));
- Proc.ProcType := Engine.CreateFunctionType('', 'Result', Proc, True,
- Scanner.CurFilename, Scanner.CurRow);
- end else
- begin
- // !!!: The following is more than ugly
- if MethodTypeName = 'constructor' then
- Proc := TPasConstructor(CreateElement(TPasConstructor, CurTokenString,
- Owner, CurVisibility))
- else if MethodTypeName = 'destructor' then
- Proc := TPasDestructor(CreateElement(TPasDestructor, CurTokenString,
- Owner, CurVisibility))
- else
- Proc := TPasProcedure(CreateElement(TPasProcedure, CurTokenString,
- Owner, CurVisibility));
- Proc.ProcType := TPasProcedureType(CreateElement(TPasProcedureType, '',
- Proc, CurVisibility));
- end;
- if Owner.ClassType = TPasOverloadedProc then
- TPasOverloadedProc(Owner).Overloads.Add(Proc)
- else
- TPasClassType(Result).Members.Add(Proc);
- if HasReturnValue then
- pt := ptFunction
- else
- pt := ptProcedure;
- ParseProcedureOrFunctionHeader(Proc, Proc.ProcType, pt, False);
- while True do
- begin
- NextToken;
- if CurToken = tkIdentifier then
- begin
- s := UpperCase(CurTokenString);
- if s = 'VIRTUAL' then
- Proc.IsVirtual := True
- else if s = 'DYNAMIC' then
- Proc.IsDynamic := True
- else if s = 'ABSTRACT' then
- Proc.IsAbstract := True
- else if s = 'OVERRIDE' then
- Proc.IsOverride := True
- else if s = 'OVERLOAD' then
- Proc.IsOverload := True
- else if s = 'MESSAGE' then
- begin
- Proc.IsMessage := True;
- repeat
- NextToken;
- until CurToken = tkSemicolon;
- UngetToken;
- end else if s = 'CDECL' then
- { El['calling-conv'] := 'cdecl';}
- else if s = 'STDCALL' then
- { El['calling-conv'] := 'stdcall';}
- else
- begin
- UngetToken;
- break;
- end;
- ExpectToken(tkSemicolon);
- end else
- begin
- UngetToken;
- break;
- end;
- end;
- end;
- var
- s, SourceFilename: String;
- i, SourceLinenumber: Integer;
- VarList: TList;
- Element: TPasElement;
- begin
- // Save current parsing position to get it correct in all cases
- SourceFilename := Scanner.CurFilename;
- SourceLinenumber := Scanner.CurRow;
- NextToken;
- if (AObjKind = okClass) and (CurToken = tkOf) then
- begin
- Result := TPasClassOfType(Engine.CreateElement(TPasClassOfType, AClassName,
- Parent, SourceFilename, SourceLinenumber));
- ExpectIdentifier;
- UngetToken; // Only names are allowed as following type
- TPasClassOfType(Result).DestType := ParseType(Result);
- ExpectToken(tkSemicolon);
- exit;
- end;
- Result := TPasClassType(Engine.CreateElement(TPasClassType, AClassName,
- Parent, SourceFilename, SourceLinenumber));
- try
- TPasClassType(Result).ObjKind := AObjKind;
- // Parse ancestor list
- if CurToken = tkBraceOpen then
- begin
- TPasClassType(Result).AncestorType := ParseType(nil);
- while True do
- begin
- NextToken;
- if CurToken = tkBraceClose then
- break;
- UngetToken;
- ExpectToken(tkComma);
- ExpectIdentifier;
- // !!!: Store interface name
- end;
- NextToken;
- end;
- if CurToken <> tkSemicolon then
- begin
- CurVisibility := visDefault;
- while CurToken <> tkEnd do
- begin
- case CurToken of
- tkIdentifier:
- begin
- s := LowerCase(CurTokenString);
- if s = 'private' then
- CurVisibility := visPrivate
- else if s = 'protected' then
- CurVisibility := visProtected
- else if s = 'public' then
- CurVisibility := visPublic
- else if s = 'published' then
- CurVisibility := visPublished
- else if s = 'automated' then
- CurVisibility := visAutomated
- else
- begin
- VarList := TList.Create;
- try
- ParseInlineVarDecl(Result, VarList, CurVisibility, False);
- for i := 0 to VarList.Count - 1 do
- begin
- Element := TPasElement(VarList[i]);
- Element.Visibility := CurVisibility;
- TPasClassType(Result).Members.Add(Element);
- end;
- finally
- VarList.Free;
- end;
- end;
- end;
- tkProcedure:
- ProcessMethod('procedure', False);
- tkFunction:
- ProcessMethod('function', True);
- tkConstructor:
- ProcessMethod('constructor', False);
- tkDestructor:
- ProcessMethod('destructor', False);
- tkProperty:
- begin
- ExpectIdentifier;
- Element := CreateElement(TPasProperty, CurTokenString, Result, CurVisibility);
- TPasClassType(Result).Members.Add(Element);
- ParseProperty(Element);
- end;
- end; // end case
- NextToken;
- end;
- // Eat semicolon after class...end
- ExpectToken(tkSemicolon);
- end;
- except
- Result.Free;
- raise;
- end;
- end;
- function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement): TPasElement;
- begin
- Result := Engine.CreateElement(AClass, AName, AParent,
- Scanner.CurFilename, Scanner.CurRow);
- end;
- function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
- begin
- Result := Engine.CreateElement(AClass, AName, AParent, AVisibility,
- Scanner.CurFilename, Scanner.CurRow);
- end;
- function ParseSource(AEngine: TPasTreeContainer;
- const FPCCommandLine, OSTarget, CPUTarget: String): 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] = '-' then
- begin
- case s[2] of
- 'd':
- Scanner.Defines.Append(UpperCase(Copy(s, 3, Length(s))));
- 'F':
- if s[3] = 'i' then
- FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
- 'S':
- if s[3]='d' then
- begin
- include(Scanner.Options,po_delphi);
- include(Parser.Options,po_delphi);
- 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;
- Scanner := TPascalScanner.Create(FileResolver);
- Scanner.Defines.Append('FPK');
- Scanner.Defines.Append('FPC');
- s := UpperCase(OSTarget);
- Scanner.Defines.Append(s);
- if s = 'LINUX' then
- Scanner.Defines.Append('UNIX')
- else if s = 'FREEBSD' then
- begin
- Scanner.Defines.Append('BSD');
- Scanner.Defines.Append('UNIX');
- end else if s = 'NETBSD' then
- begin
- Scanner.Defines.Append('BSD');
- Scanner.Defines.Append('UNIX');
- end else if s = 'SUNOS' then
- begin
- Scanner.Defines.Append('SOLARIS');
- Scanner.Defines.Append('UNIX');
- end else if s = 'GO32V2' then
- Scanner.Defines.Append('DPMI')
- else if s = 'BEOS' then
- Scanner.Defines.Append('UNIX')
- else if s = 'QNX' then
- Scanner.Defines.Append('UNIX');
- Parser := TPasParser.Create(Scanner, FileResolver, AEngine);
- Filename := '';
- 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);
- Scanner.OpenFile(Filename);
- Parser.ParseMain(Result);
- finally
- Parser.Free;
- Scanner.Free;
- FileResolver.Free;
- end;
- end;
- end.
|