12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198 |
- {
- 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);
- procedure ParseFileType(Element: TPasFileType);
- 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;
- tkFile:
- begin
- Result := TPasFileType(CreateElement(TPasFileType, '', Parent));
- 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;
- procedure TPasParser.ParseFileType(Element: TPasFileType);
- begin
- NextToken;
- If CurToken=tkOf then
- Element.ElType := ParseType(nil);
- 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;
- tkFile:
- begin
- Result := TPasFileType(CreateElement(TPasFileType, TypeName, Parent));
- Try
- ParseFileType(TPasFileType(Result));
- ExpectToken(tkSemicolon);
- Except
- Result.free;
- Raise;
- end;
- 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
- ExpectIdentifier;
- S:=CurTokenText;
- NextToken;
- if CurToken=tkDot then
- begin
- ExpectIdentifier;
- S:=S+'.'+CurTokenText;
- end
- else
- UnGetToken;
- For I:=0 to List.Count-1 do
- TPasVariable(List[i]).AbsoluteLocation:=S;
- 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='PASCAL') then
- begin
- { El['calling-conv'] := 'pascal';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='STDCALL') then
- begin
- { El['calling-conv'] := 'stdcall';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='OLDFPCCALL') then
- begin
- { El['calling-conv'] := 'oldfpccall';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='EXTDECL') then
- begin
- { El['calling-conv'] := 'extdecl';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='REGISTER') then
- begin
- { El['calling-conv'] := 'register';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='COMPILERPROC') then
- begin
- { El['calling-conv'] := 'compilerproc';}
- ExpectToken(tkSemicolon);
- end
- else if (Tok='VARARGS') then
- begin
- { 'varargs': needs CDECL & EXTERNAL }
- 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 (tok='ASSEMBLER') then
- begin
- ExpectToken(tkSemicolon);
- end
- else if (tok = 'EXTERNAL') then
- repeat
- NextToken;
- until CurToken = tkSemicolon
- else if (tok = 'PUBLIC') then
- begin
- NextToken;
- { Should be token Name,
- if not we're in a class and the public section starts }
- If (Uppercase(CurTokenString)<>'NAME') then
- begin
- UngetToken;
- UngetToken;
- Break;
- end
- else
- begin
- NextToken; // Should be export name string.
- ExpectToken(tkSemicolon);
- end;
- end
- 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;
-
- if CurToken = tkSquaredBraceOpen then begin
- Result := Result + '[';
- NextToken;
- if CurToken in [tkIdentifier, tkNumber] then begin
- Result := Result + CurTokenString;
- end;
- ExpectToken(tkSquaredBraceClose);
- Result := Result + ']';
- end else
- UngetToken;
-
- // writeln(Result);
- end;
- begin
- NextToken;
- // if array prop then parse [ arg1:type1;... ]
- if CurToken = tkSquaredBraceOpen then begin
- // !!!: Parse array properties correctly
- ParseArgList(Element, TPasProperty(Element).Args, tkSquaredBraceClose);
- NextToken;
- end;
- if CurToken = tkColon then begin
- // if ":prop_data_type" if supplied then read it
- // read property type
- TPasProperty(Element).VarType := ParseType(Element);
- NextToken;
- end;
- if CurToken <> tkSemicolon then begin
- // if indexed prop then read the index value
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'INDEX') then
- // read 'index' access modifier
- TPasProperty(Element).IndexValue := ParseExpression
- else
- // not indexed prop will be recheck for another token
- UngetToken;
- NextToken;
- end;
-
- // if the accessors list is not finished
- if CurToken <> tkSemicolon then begin
- // read 'read' access modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'READ') then
- TPasProperty(Element).ReadAccessorName := GetAccessorName
- else
- // not read accessor will be recheck for another token
- UngetToken;
-
- NextToken;
- end;
-
- // if the accessors list is not finished
- if CurToken <> tkSemicolon then begin
- // read 'write' access modifier
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'WRITE') then
- TPasProperty(Element).WriteAccessorName := GetAccessorName
- else
- // not write accessor will be recheck for another token
- UngetToken;
-
- NextToken;
- end;
-
- // if the specifiers list is not finished
- 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
- // not stored accessor will be recheck for another token
- UngetToken;
- NextToken;
- end;
-
- // if the specifiers list is not finished
- if CurToken <> tkSemicolon then begin
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then
- // read 'default' value modifier -> ParseExpression(DEFAULT <value>)
- TPasProperty(Element).DefaultValue := ParseExpression
- else
- // not "default <value>" prop will be recheck for another token
- UngetToken;
-
- NextToken;
- end;
-
- // if the specifiers list is not finished
- if CurToken <> tkSemicolon then begin
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'NODEFAULT') then begin
- // read 'nodefault' modifier
- TPasProperty(Element).IsNodefault:=true;
- end;
- // stop recheck for specifiers - start from next token
- NextToken;
- end;
- // after NODEFAULT may be a ";"
- if CurToken = tkSemicolon then begin
- // read semicolon
- NextToken;
- end;
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEFAULT') then begin
- // what is after DEFAULT token at the end
- NextToken;
- if CurToken = tkSemicolon then begin
- // ";" then DEFAULT=prop
- TPasProperty(Element).IsDefault := True;
- UngetToken;
- end else begin
- // "!;" then a step back to get phrase "DEFAULT <value>"
- UngetToken;
- // DefaultValue -> ParseExpression(DEFAULT <value>) and stay on the <value>
- TPasProperty(Element).DefaultValue := ParseExpression;
- end;
- //!! there may be DEPRECATED token
- NextToken;
-
- end;
- // after DEFAULT may be a ";"
- if CurToken = tkSemicolon then begin
- // read semicolon
- NextToken;
- end;
-
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEPRECATED') then begin
- // nothing to do on DEPRECATED - just to accept
- // NextToken;
- end else
- UngetToken;;
-
- //!! else
- // not DEFAULT prop accessor will be recheck for another token
- //!! UngetToken;
- {
- if CurToken = tkSemicolon then begin
- // read semicolon
- NextToken;
- end;
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'DEPRECATED') then begin
- // nothing to do - just to process
- NextToken;
- end;
- if CurToken = tkSemicolon then begin
- // read semicolon
- NextToken;
- end;
- }
-
- 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 = 'REINTRODUCE' then
- Proc.IsReintroduced := True
- else if s = 'OVERLOAD' then
- Proc.IsOverload := True
- else if s = 'STATIC' then
- Proc.IsStatic := 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 = 'PASCAL' then
- { El['calling-conv'] := 'cdecl';}
- else if s = 'STDCALL' then
- { El['calling-conv'] := 'stdcall';}
- else if s = 'OLDFPCCALL' then
- { El['calling-conv'] := 'oldfpccall';}
- else if s = 'EXTDECL' then
- { El['calling-conv'] := 'extdecl';}
- else if s = 'DEPRECATED' then
- { El['calling-conv'] := 'deprecated';}
- 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.
|