| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567 |
- {
- $Id$
- This file is part of the Free Component Library
- Pascal source parser
- Copyright (c) 2000-2003 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;
- 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';
- 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): TPasElement;
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
- virtual; abstract;
- function CreateFunctionType(const AName: String; AParent: TPasElement;
- UseParentAsResultParent: Boolean): 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: String): TPasModule;
- implementation
- uses Classes, PScanner;
- type
- TDeclType = (declNone, declConst, declResourcestring, declType, declVar);
- 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;
- function GetCurColumn: Integer;
- procedure ParseExc(const Msg: String);
- public
- constructor Create(AFileResolver: TFileResolver; AEngine: TPasTreeContainer;
- const AFilename: String);
- destructor Destroy; override;
- function CurTokenName: String;
- function CurTokenText: String;
- procedure NextToken;
- procedure UngetToken;
- procedure ExpectToken(tk: TToken);
- function ExpectIdentifier: String;
- 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;
- AVisibility : TPasMemberVisibility);
- procedure ParseInlineVarDecl(Parent: TPasElement; VarList: TList);
- procedure ParseVarDecl(Parent: TPasElement; List: TList);
- procedure ParseArgList(Parent: TPasElement; Args: TList; EndToken: TToken);
- procedure ParseProcedureOrFunctionHeader(Parent: TPasElement;
- Element: TPasProcedureType; IsFunction, OfObjectPossible: Boolean);
- function ParseProcedureOrFunctionDecl(Parent: TPasElement;
- IsFunction: Boolean): TPasProcedure;
- procedure ParseRecordDecl(Parent: TPasRecordType);
- function ParseClassDecl(Parent: TPasElement; const AClassName: String;
- AObjKind: TPasObjKind): TPasType;
- 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): TPasElement;
- begin
- Result := CreateElement(AClass, AName, AParent, visDefault);
- end;
- function TPasTreeContainer.CreateFunctionType(const AName: String;
- AParent: TPasElement; UseParentAsResultParent: Boolean): TPasFunctionType;
- var
- ResultParent: TPasElement;
- begin
- Result := TPasFunctionType(CreateElement(TPasFunctionType, AName, AParent));
- if UseParentAsResultParent then
- ResultParent := AParent
- else
- ResultParent := Result;
- TPasFunctionType(Result).ResultEl :=
- TPasResultElement(CreateElement(TPasResultElement, 'Result', ResultParent));
- 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(AFileResolver: TFileResolver;
- AEngine: TPasTreeContainer; const AFilename: String);
- begin
- inherited Create;
- FFileResolver := AFileResolver;
- FEngine := AEngine;
- FScanner := TPascalScanner.Create(FileResolver, AFilename);
- end;
- destructor TPasParser.Destroy;
- begin
- Scanner.Free;
- inherited Destroy;
- 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
- repeat
- FCurToken := Scanner.FetchToken;
- //WriteLn('Token: ', TokenInfos[CurToken], ' ', Scanner.CurTokenString);
- until not (FCurToken in [tkWhitespace, tkComment]);
- 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;
- var
- TypeToken: TToken;
- Name, s: String;
- EnumValue: TPasEnumValue;
- Ref: TPasElement;
- begin
- Result := nil; // !!!: Remove in the future
- NextToken;
- case CurToken of
- tkIdentifier:
- begin
- TypeToken := CurToken;
- Name := CurTokenString;
- NextToken;
- if CurToken = tkDot then
- begin
- ExpectIdentifier;
- 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(Engine.CreateElement(TPasTypeRef, Name, nil));
- TPasTypeRef(Result).RefType := Ref as TPasType;}
- Result := Ref as TPasType;
- Result.AddRef;
- end else
- Result := TPasUnresolvedTypeRef(Engine.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(
- Engine.CreateElement(TPasPointerType, '', Parent));
- TPasPointerType(Result).DestType := ParseType(nil);
- end;
- tkArray:
- begin
- Result := TPasArrayType(Engine.CreateElement(TPasArrayType, '', Parent));
- ParseArrayType(TPasArrayType(Result));
- end;
- tkBraceOpen:
- begin
- Result := TPasEnumType(Engine.CreateElement(TPasEnumType, '', Parent));
- while True do
- begin
- NextToken;
- EnumValue := TPasEnumValue(Engine.CreateElement(TPasEnumValue,
- CurTokenString, Result));
- TPasEnumType(Result).Values.Add(EnumValue);
- NextToken;
- if CurToken = tkBraceClose then
- break
- else if CurToken <> tkComma then
- ParseExc(SParserExpectedCommaRBracket);
- end;
- end;
- tkRecord:
- begin
- Result := TPasRecordType(
- Engine.CreateElement(TPasRecordType, '', Parent));
- ParseRecordDecl(TPasRecordType(Result));
- UngetToken;
- end;
-
- else
- ParseExc(SParserTypeSyntaxError);
- end;
- end;
- function TPasParser.ParseComplexType: TPasType;
- begin
- NextToken;
- case CurToken of
- tkProcedure:
- begin
- Result := TPasProcedureType(
- Engine.CreateElement(TPasProcedureType, '', nil));
- ParseProcedureOrFunctionHeader(Result,
- TPasProcedureType(Result), False, True);
- UngetToken; // Unget semicolon
- end;
- tkFunction:
- begin
- Result := Engine.CreateFunctionType('', nil, False);
- ParseProcedureOrFunctionHeader(Result,
- TPasFunctionType(Result), True, 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;
- 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: Integer;
- VarEl: TPasVariable;
- begin
- Module := nil;
- Module := TPasModule(Engine.
- 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(Engine.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;
- tkProcedure:
- begin
- AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, False));
- CurBlock := declNone;
- end;
- tkFunction:
- begin
- AddProcOrFunction(Section, ParseProcedureOrFunctionDecl(Section, True));
- CurBlock := declNone;
- end;
- tkOperator:
- begin
- // !!!: Not supported yet
- i := 0;
- repeat
- NextToken;
- if CurToken = tkBraceOpen then
- Inc(i)
- else if CurToken = tkBraceClose then
- Dec(i);
- until (CurToken = tkSemicolon) and (i = 0);
- 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 i := 0 to Section.Declarations.Count - 1 do
- if CompareText(TypeEl.Name,
- TPasElement(Section.Declarations[i]).Name) = 0 then
- begin
- Section.Declarations.Delete(i);
- 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:
- begin
- List := TList.Create;
- try
- ParseVarDecl(Section, List);
- 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(Engine.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(Engine.CreateElement(TPasConst, CurTokenString, Parent));
- NextToken;
- if CurToken = tkColon then
- Result.VarType := ParseType(nil)
- else
- UngetToken;
- ExpectToken(tkEqual);
- Result.Value := ParseExpression;
- ExpectToken(tkSemicolon);
- end;
- // Starts after the variable name
- function TPasParser.ParseResourcestringDecl(Parent: TPasElement): TPasResString;
- begin
- Result := TPasResString(
- Engine.CreateElement(TPasResString, CurTokenString, Parent));
- ExpectToken(tkEqual);
- ExpectToken(tkString);
- Result.Value := CurTokenString;
- ExpectToken(tkSemicolon);
- end;
- // Starts after the type name
- function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType;
- var
- TypeName: String;
- procedure ParseRange;
- begin
- Result := TPasRangeType(Engine.CreateElement(TPasRangeType, TypeName, Parent));
- TPasRangeType(Result).RangeStart := ParseExpression;
- ExpectToken(tkDotDot);
- TPasRangeType(Result).RangeEnd := ParseExpression;
- ExpectToken(tkSemicolon);
- end;
- var
- EnumValue: TPasEnumValue;
- begin
- TypeName := CurTokenString;
- ExpectToken(tkEqual);
- NextToken;
- case CurToken of
- tkRecord:
- begin
- Result := TPasRecordType(
- Engine.CreateElement(TPasRecordType, TypeName, Parent));
- ParseRecordDecl(TPasRecordType(Result));
- end;
- tkPacked:
- begin
- Result := TPasRecordType(
- Engine.CreateElement(TPasRecordType, TypeName, Parent));
- TPasRecordType(Result).IsPacked := True;
- ExpectToken(tkRecord);
- ParseRecordDecl(TPasRecordType(Result));
- end;
- tkObject:
- Result := ParseClassDecl(Parent, TypeName, okObject);
- tkClass:
- Result := ParseClassDecl(Parent, TypeName, okClass);
- tkInterface:
- Result := ParseClassDecl(Parent, TypeName, okInterface);
- tkCaret:
- begin
- Result := TPasPointerType(
- Engine.CreateElement(TPasPointerType, TypeName, Parent));
- TPasPointerType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- end;
- tkIdentifier:
- begin
- NextToken;
- if CurToken = tkSemicolon then
- begin
- UngetToken;
- UngetToken;
- Result := TPasAliasType(
- Engine.CreateElement(TPasAliasType, TypeName, Parent));
- TPasAliasType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- end else
- begin
- UngetToken;
- UngetToken;
- ParseRange;
- end;
- end;
- { _STRING, _FILE:
- begin
- Result := TPasAliasType(
- Engine.CreateElement(TPasAliasType, TypeName, Parent));
- UngetToken;
- TPasAliasType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- end;}
- tkArray:
- begin
- Result := TPasArrayType(
- Engine.CreateElement(TPasArrayType, TypeName, Parent));
- ParseArrayType(TPasArrayType(Result));
- ExpectToken(tkSemicolon);
- end;
- tkSet:
- begin
- Result := TPasSetType(
- Engine.CreateElement(TPasSetType, TypeName, Parent));
- ExpectToken(tkOf);
- TPasSetType(Result).EnumType := ParseType(Result);
- ExpectToken(tkSemicolon);
- end;
- tkBraceOpen:
- begin
- Result := TPasEnumType(
- Engine.CreateElement(TPasEnumType, TypeName, Parent));
- while True do
- begin
- NextToken;
- EnumValue := TPasEnumValue(
- Engine.CreateElement(TPasEnumValue, CurTokenString, Result));
- TPasEnumType(Result).Values.Add(EnumValue);
- NextToken;
- if CurToken = tkBraceClose then
- break
- else if CurToken <> tkComma then
- ParseExc(SParserExpectedCommaRBracket);
- end;
- ExpectToken(tkSemicolon);
- end;
- tkProcedure:
- begin
- Result := TPasProcedureType(
- Engine.CreateElement(TPasProcedureType, TypeName, Parent));
- ParseProcedureOrFunctionHeader(Result,
- TPasProcedureType(Result), False, True);
- end;
- tkFunction:
- begin
- Result := Engine.CreateFunctionType(TypeName, Parent, False);
- ParseProcedureOrFunctionHeader(Result,
- TPasFunctionType(Result), True, True);
- end;
- tkType:
- begin
- Result := TPasTypeAliasType(
- Engine.CreateElement(TPasTypeAliasType, TypeName, Parent));
- TPasTypeAliasType(Result).DestType := ParseType(nil);
- ExpectToken(tkSemicolon);
- 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);
- end;
- procedure TPasParser.ParseInlineVarDecl(Parent: TPasElement; VarList: TList;
- AVisibility : TPasMemberVisibility);
- 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 := ParseType(nil);
- for i := 0 to VarNames.Count - 1 do
- begin
- VarEl := TPasVariable(
- Engine.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) 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;
- U,M: string;
- begin
- while True do
- begin
- List.Add(Engine.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) 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(
- Engine.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; IsFunction, OfObjectPossible: Boolean);
- begin
- NextToken;
- if IsFunction then
- begin
- if CurToken = tkBraceOpen then
- begin
- ParseArgList(Parent, Element.Args, tkBraceClose);
- ExpectToken(tkColon);
- end else if CurToken <> tkColon then
- ParseExc(SParserExpectedLBracketColon);
- if Assigned(Element) then // !!!
- TPasFunctionType(Element).ResultEl.ResultType := ParseType(Parent)
- else
- ParseType(nil);
- end else
- begin
- if CurToken = tkBraceOpen then
- begin
- ParseArgList(Element, Element.Args, tkBraceClose);
- end else if (CurToken = tkSemicolon) or (OfObjectPossible and (CurToken = tkOf)) then
- UngetToken
- else
- ParseExc(SParserExpectedLBracketSemicolon);
- end;
- NextToken;
- if OfObjectPossible and (CurToken = tkOf) then
- begin
- ExpectToken(tkObject);
- Element.IsOfObject := True;
- end else
- UngetToken;
- ExpectToken(tkSemicolon);
- while True do
- begin
- NextToken;
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'CDECL') then
- begin
- { El['calling-conv'] := 'cdecl';}
- ExpectToken(tkSemicolon);
- end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'STDCALL') then
- begin
- { El['calling-conv'] := 'stdcall';}
- ExpectToken(tkSemicolon);
- end else if (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'EXTERNAL') then
- begin
- repeat
- NextToken
- until CurToken = tkSemicolon;
- end else if Parent.InheritsFrom(TPasProcedure) and
- (CurToken = tkIdentifier) and (UpperCase(CurTokenString) = 'OVERLOAD') then
- begin
- TPasProcedure(Parent).IsOverload := True;
- ExpectToken(tkSemicolon);
- end else
- begin
- UngetToken;
- break;
- end;
- end;
- end;
- // Starts after the "procedure" or "function" token
- function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
- IsFunction: Boolean): TPasProcedure;
- var
- Name: String;
- begin
- Name := ExpectIdentifier;
- if IsFunction then
- begin
- Result := TPasFunction(Engine.CreateElement(TPasFunction, Name, Parent));
- Result.ProcType := Engine.CreateFunctionType('', Result, True);
- end else
- begin
- Result := TPasProcedure(Engine.CreateElement(TPasProcedure, Name, Parent));
- Result.ProcType := TPasProcedureType(
- Engine.CreateElement(TPasProcedureType, '', Result));
- end;
- ParseProcedureOrFunctionHeader(Result, Result.ProcType, IsFunction, False);
- end;
- // Starts after the "record" token
- procedure TPasParser.ParseRecordDecl(Parent: TPasRecordType);
- Var
- CCount : Integer;
- begin
- while True do
- begin
- if CurToken = tkEnd then
- break;
- NextToken;
- if CurToken = tkEnd then
- break
- else if CurToken = tkCase then
- begin
- CCount:=0;
- Repeat
- NextToken;
- If CurToken=tkBraceOpen then
- inc(CCount)
- else If CurToken=tkBraceClose then
- Dec(CCount)
- until (CCount=0) and (CurToken=tkEnd);
- Break;
- end
- else
- ParseInlineVarDecl(Parent, Parent.Members);
- end;
- ExpectToken(tkSemicolon);
- 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;
- begin
- ExpectIdentifier;
- Owner := CheckIfOverloaded(TPasClassType(Result), CurTokenString);
- if HasReturnValue then
- begin
- Proc := TPasFunction(
- Engine.CreateElement(TPasFunction, CurTokenString, Owner, CurVisibility));
- Proc.ProcType := Engine.CreateFunctionType( '', Proc, True);
- end else
- begin
- // !!!: The following is more than ugly
- if MethodTypeName = 'constructor' then
- Proc := TPasConstructor(
- Engine.CreateElement(TPasConstructor, CurTokenString, Owner, CurVisibility))
- else if MethodTypeName = 'destructor' then
- Proc := TPasDestructor(
- Engine.CreateElement(TPasDestructor, CurTokenString, Owner, CurVisibility))
- else
- Proc := TPasProcedure(
- Engine.CreateElement(TPasProcedure, CurTokenString, Owner, CurVisibility));
- Proc.ProcType := TPasProcedureType(
- Engine.CreateElement(TPasProcedureType, '', Proc, CurVisibility));
- end;
- if Owner.ClassType = TPasOverloadedProc then
- TPasOverloadedProc(Owner).Overloads.Add(Proc)
- else
- TPasClassType(Result).Members.Add(Proc);
- ParseProcedureOrFunctionHeader(Proc, Proc.ProcType, HasReturnValue, 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;
- 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;
- var
- s: String;
- i: Integer;
- VarList: TList;
- Element: TPasElement;
- begin
- NextToken;
- if (AObjKind = okClass) and (CurToken = tkOf) then
- begin
- Result := TPasClassOfType(
- Engine.CreateElement(TPasClassOfType, AClassName, Parent));
- 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));
- TPasClassType(Result).ObjKind := AObjKind;
- 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);
- 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 := Engine.CreateElement(TPasProperty,
- CurTokenString, Result, CurVisibility);
- TPasClassType(Result).Members.Add(Element);
- NextToken;
- // !!!: Parse array properties correctly
- if CurToken = tkSquaredBraceOpen then
- begin
- ParseArgList(Element, TPasProperty(Element).Args, tkSquaredBraceClose);
- NextToken;
- end;
- if CurToken = tkColon then
- begin
- TPasProperty(Element).VarType := ParseType(Element);
- NextToken;
- if CurToken <> tkSemicolon then
- begin
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'READ') then
- TPasProperty(Element).ReadAccessorName := GetAccessorName
- else
- UngetToken;
- NextToken;
- if CurToken <> tkSemicolon then
- begin
- if (CurToken = tkIdentifier) and (UpperCase(CurTokenText) = 'WRITE') then
- TPasProperty(Element).WriteAccessorName := GetAccessorName
- else
- UngetToken;
- NextToken;
- if CurToken <> tkSemicolon then
- begin
- 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;
- end;
- end;
- end;
- end;
- NextToken;
- 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;
- end;
- NextToken;
- end;
- // Eat semicolon after class...end
- ExpectToken(tkSemicolon);
- end;
- end;
- function ParseSource(AEngine: TPasTreeContainer;
- const FPCCommandLine: String): TPasModule;
- var
- FileResolver: TFileResolver;
- Parser: TPasParser;
- Start, CurPos: PChar;
- Filename: String;
- 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
- if s[2] = 'F' then
- if s[3] = 'i' then
- FileResolver.AddIncludePath(Copy(s, 4, Length(s)));
- end else
- if Filename <> '' then
- raise Exception.Create(SErrMultipleSourceFiles)
- else
- Filename := s;
- end;
- begin
- FileResolver := TFileResolver.Create;
- try
- Filename := '';
- 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;
- if Filename = '' then
- raise Exception.Create(SErrNoSourceGiven);
- Parser := TPasParser.Create(FileResolver, AEngine, Filename);
- Parser.ParseMain(Result);
- Parser.Free;
- finally
- FileResolver.Free;
- end;
- end;
- end.
- {
- $Log$
- Revision 1.1 2003-03-13 21:47:42 sg
- * First version as part of FCL
- }
|