123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860 |
- {
- This file is part of the Free Component Library
- Pascal source lexical scanner
- Copyright (c) 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.
- **********************************************************************}
- {$mode objfpc}
- {$h+}
- unit PScanner;
- interface
- uses SysUtils, Classes;
- resourcestring
- SErrInvalidCharacter = 'Invalid character ''%s''';
- SErrOpenString = 'string exceeds end of line';
- SErrIncludeFileNotFound = 'Could not find include file ''%s''';
- SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
- SErrInvalidPPElse = '$ELSE without matching $IFxxx';
- SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
- SLogOpeningFile = 'Opening source file "%s".';
- SLogLineNumber = 'Reading line %d.';
- SLogIFDefAccepted = 'IFDEF %s found, accepting.';
- SLogIFDefRejected = 'IFDEF %s found, rejecting.';
- SLogIFNDefAccepted = 'IFNDEF %s found, accepting.';
- SLogIFNDefRejected = 'IFNDEF %s found, rejecting.';
- SLogIFOPTIgnored = 'IFOPT %s found, ignoring (rejected).';
- SLogIFIgnored = 'IF %s found, ignoring (rejected).';
- type
- TToken = (
- tkEOF,
- tkWhitespace,
- tkComment,
- tkIdentifier,
- tkString,
- tkNumber,
- tkChar,
- // Simple (one-character) tokens
- tkBraceOpen, // '('
- tkBraceClose, // ')'
- tkMul, // '*'
- tkPlus, // '+'
- tkComma, // ','
- tkMinus, // '-'
- tkDot, // '.'
- tkDivision, // '/'
- tkColon, // ':'
- tkSemicolon, // ';'
- tkLessThan, // '<'
- tkEqual, // '='
- tkGreaterThan, // '>'
- tkAt, // '@'
- tkSquaredBraceOpen, // '['
- tkSquaredBraceClose, // ']'
- tkCaret, // '^'
- tkBackslash, // '\'
- // Two-character tokens
- tkDotDot, // '..'
- tkAssign, // ':='
- tkNotEqual, // '<>'
- tkLessEqualThan, // '<='
- tkGreaterEqualThan, // '>='
- tkPower, // '**'
- tkSymmetricalDifference, // '><'
- tkAssignPlus, // +=
- tkAssignMinus, // -=
- tkAssignMul, // *=
- tkAssignDivision, // /=
- // Reserved words
- tkabsolute,
- tkand,
- tkarray,
- tkas,
- tkasm,
- tkbegin,
- tkbitpacked,
- tkcase,
- tkclass,
- tkconst,
- tkconstref,
- tkconstructor,
- tkdestructor,
- tkdiv,
- tkdo,
- tkdownto,
- tkelse,
- tkend,
- tkexcept,
- tkexports,
- tkfalse,
- tkfile,
- tkfinalization,
- tkfinally,
- tkfor,
- tkfunction,
- tkgeneric,
- tkgoto,
- tkHelper,
- tkif,
- tkimplementation,
- tkin,
- tkinherited,
- tkinitialization,
- tkinline,
- tkinterface,
- tkis,
- tklabel,
- tklibrary,
- tkmod,
- tknil,
- tknot,
- tkobject,
- tkof,
- tkon,
- tkoperator,
- tkor,
- tkpacked,
- tkprocedure,
- tkprogram,
- tkproperty,
- tkraise,
- tkrecord,
- tkrepeat,
- tkResourceString,
- tkself,
- tkset,
- tkshl,
- tkshr,
- tkspecialize,
- // tkstring,
- tkthen,
- tkthreadvar,
- tkto,
- tktrue,
- tktry,
- tktype,
- tkunit,
- tkuntil,
- tkuses,
- tkvar,
- tkwhile,
- tkwith,
- tkxor,
- tkLineEnding,
- tkTab
- );
- TTokens = set of TToken;
- { TMacroDef }
- TMacroDef = Class(TObject)
- Private
- FName: String;
- FValue: String;
- Public
- Constructor Create(Const AName,AValue : String);
- Property Name : String Read FName;
- Property Value : String Read FValue Write FValue;
- end;
- { TLineReader }
- TLineReader = class
- Private
- FFilename: string;
- public
- constructor Create(const AFilename: string); virtual;
- function IsEOF: Boolean; virtual; abstract;
- function ReadLine: string; virtual; abstract;
- property Filename: string read FFilename;
- end;
- { TFileLineReader }
- TFileLineReader = class(TLineReader)
- private
- FTextFile: Text;
- FileOpened: Boolean;
- FBuffer : Array[0..4096-1] of byte;
- public
- constructor Create(const AFilename: string); override;
- destructor Destroy; override;
- function IsEOF: Boolean; override;
- function ReadLine: string; override;
- end;
- { TStreamLineReader }
- TStreamLineReader = class(TLineReader)
- private
- FContent: AnsiString;
- FPos : Integer;
- public
- Procedure InitFromStream(AStream : TStream);
- function IsEOF: Boolean; override;
- function ReadLine: string; override;
- end;
- { TFileStreamLineReader }
- TFileStreamLineReader = class(TStreamLineReader)
- Public
- constructor Create(const AFilename: string); override;
- end;
- { TStringStreamLineReader }
- TStringStreamLineReader = class(TStreamLineReader)
- Public
- constructor Create( const AFilename: string; Const ASource: String);
- end;
- { TMacroReader }
- TMacroReader = Class(TStringStreamLineReader)
- private
- FCurCol: Integer;
- FCurRow: Integer;
- Public
- Property CurCol : Integer Read FCurCol Write FCurCol;
- Property CurRow : Integer Read FCurRow Write FCurRow;
- end;
- { TBaseFileResolver }
- TBaseFileResolver = class
- private
- FBaseDirectory: string;
- FIncludePaths: TStringList;
- FStrictFileCase : Boolean;
- Protected
- procedure SetBaseDirectory(AValue: string); virtual;
- procedure SetStrictFileCase(AValue: Boolean); virtual;
- Function FindIncludeFileName(const AName: string): String;
- Property IncludePaths: TStringList Read FIncludePaths;
- public
- constructor Create; virtual;
- destructor Destroy; override;
- procedure AddIncludePath(const APath: string); virtual;
- function FindSourceFile(const AName: string): TLineReader; virtual; abstract;
- function FindIncludeFile(const AName: string): TLineReader; virtual; abstract;
- Property StrictFileCase : Boolean Read FStrictFileCase Write SetStrictFileCase;
- property BaseDirectory: string read FBaseDirectory write SetBaseDirectory;
- end;
- { TFileResolver }
- TFileResolver = class(TBaseFileResolver)
- private
- FUseStreams: Boolean;
- Protected
- Function CreateFileReader(Const AFileName : String) : TLineReader; virtual;
- Public
- function FindSourceFile(const AName: string): TLineReader; override;
- function FindIncludeFile(const AName: string): TLineReader; override;
- Property UseStreams : Boolean Read FUseStreams Write FUseStreams;
- end;
- { TStreamResolver }
- TStreamResolver = class(TBaseFileResolver)
- Private
- FOwnsStreams: Boolean;
- FStreams : TStringList;
- function FindStream(const AName: string; ScanIncludes: Boolean): TStream;
- function FindStreamReader(const AName: string; ScanIncludes: Boolean): TLineReader;
- procedure SetOwnsStreams(AValue: Boolean);
- Public
- constructor Create; override;
- destructor Destroy; override;
- Procedure Clear;
- Procedure AddStream(Const AName : String; AStream : TStream);
- function FindSourceFile(const AName: string): TLineReader; override;
- function FindIncludeFile(const AName: string): TLineReader; override;
- Property OwnsStreams : Boolean Read FOwnsStreams write SetOwnsStreams;
- end;
- EScannerError = class(Exception);
- EFileNotFoundError = class(Exception);
- TPascalScannerPPSkipMode = (ppSkipNone, ppSkipIfBranch, ppSkipElseBranch, ppSkipAll);
- TPOption = (po_delphi,po_cassignments);
- TPOptions = set of TPOption;
- { TPascalScanner }
- TPScannerLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
- TPScannerLogEvent = (sleFile,sleLineNumber,sleConditionals);
- TPScannerLogEvents = Set of TPScannerLogEvent;
- TPascalScanner = class
- private
- FFileResolver: TBaseFileResolver;
- FCurSourceFile: TLineReader;
- FCurFilename: string;
- FCurRow: Integer;
- FCurToken: TToken;
- FCurTokenString: string;
- FCurLine: string;
- FMacros,
- FDefines: TStrings;
- FOptions: TPOptions;
- FLogEvents: TPScannerLogEvents;
- FOnLog: TPScannerLogHandler;
- FSkipComments: Boolean;
- FSkipWhiteSpace: Boolean;
- TokenStr: PChar;
- FIncludeStack: TFPList;
- // Preprocessor $IFxxx skipping data
- PPSkipMode: TPascalScannerPPSkipMode;
- PPIsSkipping: Boolean;
- PPSkipStackIndex: Integer;
- PPSkipModeStack: array[0..255] of TPascalScannerPPSkipMode;
- PPIsSkippingStack: array[0..255] of Boolean;
- function GetCurColumn: Integer;
- procedure SetOptions(AValue: TPOptions);
- protected
- Procedure DoLog(Const Msg : String; SkipSourceInfo : Boolean = False);overload;
- Procedure DoLog(Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
- procedure Error(const Msg: string);overload;
- procedure Error(const Msg: string; Args: array of Const);overload;
- procedure HandleDefine(Param: String); virtual;
- procedure HandleIncludeFile(Param: String); virtual;
- procedure HandleUnDefine(Param: String);virtual;
- function HandleMacro(AIndex: integer): TToken;virtual;
- procedure PushStackItem; virtual;
- function DoFetchTextToken: TToken;
- function DoFetchToken: TToken;
- procedure ClearFiles;
- Procedure ClearMacros;
- Procedure SetCurTokenString(AValue : string);
- function LogEvent(E : TPScannerLogEvent) : Boolean; inline;
- public
- constructor Create(AFileResolver: TBaseFileResolver);
- destructor Destroy; override;
- procedure OpenFile(const AFilename: string);
- function FetchToken: TToken;
- Procedure AddDefine(S : String);
- Procedure RemoveDefine(S : String);
- property FileResolver: TBaseFileResolver read FFileResolver;
- property CurSourceFile: TLineReader read FCurSourceFile;
- property CurFilename: string read FCurFilename;
- Property SkipWhiteSpace : Boolean Read FSkipWhiteSpace Write FSkipWhiteSpace;
- Property SkipComments : Boolean Read FSkipComments Write FSkipComments;
- property CurLine: string read FCurLine;
- property CurRow: Integer read FCurRow;
- property CurColumn: Integer read GetCurColumn;
- property CurToken: TToken read FCurToken;
- property CurTokenString: string read FCurTokenString;
- property Defines: TStrings read FDefines;
- property Macros: TStrings read FMacros;
- Property Options : TPOptions Read FOptions Write SetOptions;
- Property LogEvents : TPScannerLogEvents Read FLogEvents Write FLogEvents;
- Property OnLog : TPScannerLogHandler Read FOnLog Write FOnLog;
- end;
- const
- TokenInfos: array[TToken] of string = (
- 'EOF',
- 'Whitespace',
- 'Comment',
- 'Identifier',
- 'string',
- 'Number',
- 'Character',
- '(',
- ')',
- '*',
- '+',
- ',',
- '-',
- '.',
- '/',
- ':',
- ';',
- '<',
- '=',
- '>',
- '@',
- '[',
- ']',
- '^',
- '\',
- '..',
- ':=',
- '<>',
- '<=',
- '>=',
- '**',
- '><',
- '+=',
- '-=',
- '*=',
- '/=',
- // Reserved words
- 'absolute',
- 'and',
- 'array',
- 'as',
- 'asm',
- 'begin',
- 'bitpacked',
- 'case',
- 'class',
- 'const',
- 'constref',
- 'constructor',
- 'destructor',
- 'div',
- 'do',
- 'downto',
- 'else',
- 'end',
- 'except',
- 'exports',
- 'false',
- 'file',
- 'finalization',
- 'finally',
- 'for',
- 'function',
- 'generic',
- 'goto',
- 'helper',
- 'if',
- 'implementation',
- 'in',
- 'inherited',
- 'initialization',
- 'inline',
- 'interface',
- 'is',
- 'label',
- 'library',
- 'mod',
- 'nil',
- 'not',
- 'object',
- 'of',
- 'on',
- 'operator',
- 'or',
- 'packed',
- 'procedure',
- 'program',
- 'property',
- 'raise',
- 'record',
- 'repeat',
- 'resourcestring',
- 'self',
- 'set',
- 'shl',
- 'shr',
- 'specialize',
- // 'string',
- 'then',
- 'threadvar',
- 'to',
- 'true',
- 'try',
- 'type',
- 'unit',
- 'until',
- 'uses',
- 'var',
- 'while',
- 'with',
- 'xor',
- 'LineEnding',
- 'Tab'
- );
- function FilenameIsAbsolute(const TheFilename: string):boolean;
- function FilenameIsWinAbsolute(const TheFilename: string): boolean;
- function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
- function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
- implementation
- Var
- SortedTokens : array of TToken;
- LowerCaseTokens : Array[ttoken] of String;
- Procedure SortTokenInfo;
- Var
- tk: tToken;
- I,J,K, l: integer;
- begin
- for tk:=Low(TToken) to High(ttoken) do
- LowerCaseTokens[tk]:=LowerCase(TokenInfos[tk]);
- SetLength(SortedTokens,Ord(tkXor)-Ord(tkAbsolute)+1);
- I:=0;
- for tk := tkAbsolute to tkXOR do
- begin
- SortedTokens[i]:=tk;
- Inc(i);
- end;
- l:=Length(SortedTokens)-1;
- k:=l shr 1;
- while (k>0) do
- begin
- for i:=0 to l-k do
- begin
- j:=i;
- while (J>=0) and (LowerCaseTokens[SortedTokens[J]]>LowerCaseTokens[SortedTokens[J+K]]) do
- begin
- tk:=SortedTokens[J];
- SortedTokens[J]:=SortedTokens[J+K];
- SortedTokens[J+K]:=tk;
- if (J>K) then
- Dec(J,K)
- else
- J := 0
- end;
- end;
- K:=K shr 1;
- end;
- end;
- function IndexOfToken(Const AToken : string) : Integer;
- var
- B,T,M : Integer;
- N : String;
- begin
- B:=0;
- T:=Length(SortedTokens)-1;
- while (B<=T) do
- begin
- M:=(B+T) div 2;
- N:=LowerCaseTokens[SortedTokens[M]];
- if (AToken<N) then
- T:=M-1
- else if (AToken=N) then
- Exit(M)
- else
- B:=M+1;
- end;
- Result:=-1;
- end;
- function IsNamedToken(Const AToken : String; Out T : TToken) : Boolean;
- Var
- I : Integer;
- begin
- if (Length(SortedTokens)=0) then
- SortTokenInfo;
- I:=IndexOfToken(LowerCase(AToken));
- Result:=I<>-1;
- If Result then
- T:=SortedTokens[I];
- end;
- type
- TIncludeStackItem = class
- SourceFile: TLineReader;
- Filename: string;
- Token: TToken;
- TokenString: string;
- Line: string;
- Row: Integer;
- TokenStr: PChar;
- end;
- function FilenameIsAbsolute(const TheFilename: string):boolean;
- begin
- {$IFDEF WINDOWS}
- // windows
- Result:=FilenameIsWinAbsolute(TheFilename);
- {$ELSE}
- // unix
- Result:=FilenameIsUnixAbsolute(TheFilename);
- {$ENDIF}
- end;
- function FilenameIsWinAbsolute(const TheFilename: string): boolean;
- begin
- Result:=((length(TheFilename)>=2) and (TheFilename[1] in ['A'..'Z','a'..'z'])
- and (TheFilename[2]=':'))
- or ((length(TheFilename)>=2)
- and (TheFilename[1]='\') and (TheFilename[2]='\'));
- end;
- function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
- begin
- Result:=(TheFilename<>'') and (TheFilename[1]='/');
- end;
- { TMacroDef }
- constructor TMacroDef.Create(const AName, AValue: String);
- begin
- FName:=AName;
- FValue:=AValue;
- end;
- { TStreamResolver }
- procedure TStreamResolver.SetOwnsStreams(AValue: Boolean);
- begin
- if FOwnsStreams=AValue then Exit;
- FOwnsStreams:=AValue;
- end;
- constructor TStreamResolver.Create;
- begin
- Inherited;
- FStreams:=TStringList.Create;
- FStreams.Sorted:=True;
- FStreams.Duplicates:=dupError;
- end;
- destructor TStreamResolver.Destroy;
- begin
- Clear;
- FreeAndNil(FStreams);
- inherited Destroy;
- end;
- procedure TStreamResolver.Clear;
- Var
- I : integer;
- begin
- if OwnsStreams then
- begin
- For I:=0 to FStreams.Count-1 do
- Fstreams.Objects[i].Free;
- end;
- FStreams.Clear;
- end;
- procedure TStreamResolver.AddStream(const AName: String; AStream: TStream);
- begin
- FStreams.AddObject(AName,AStream);
- end;
- function TStreamResolver.FindStream(const AName: string; ScanIncludes : Boolean) : TStream;
- Var
- I,J : Integer;
- FN : String;
- begin
- Result:=Nil;
- I:=FStreams.IndexOf(AName);
- If (I=-1) and ScanIncludes then
- begin
- J:=0;
- While (I=-1) and (J<IncludePaths.Count-1) do
- begin
- FN:=IncludeTrailingPathDelimiter(IncludePaths[i])+AName;
- I:=FStreams.INdexOf(FN);
- Inc(J);
- end;
- end;
- If (I<>-1) then
- Result:=FStreams.Objects[i] as TStream;
- end;
- function TStreamResolver.FindStreamReader(const AName: string; ScanIncludes : Boolean) : TLineReader;
- Var
- S : TStream;
- SL : TStreamLineReader;
- begin
- Result:=Nil;
- S:=FindStream(AName,ScanIncludes);
- If (S<>Nil) then
- begin
- SL:=TStreamLineReader.Create(AName);
- try
- SL.InitFromStream(S);
- Result:=SL;
- except
- FreeAndNil(SL);
- Raise;
- end;
- end;
- end;
- function TStreamResolver.FindSourceFile(const AName: string): TLineReader;
- begin
- Result:=FindStreamReader(AName,False);
- end;
- function TStreamResolver.FindIncludeFile(const AName: string): TLineReader;
- begin
- Result:=FindStreamReader(AName,True);
- end;
- { TStringStreamLineReader }
- constructor TStringStreamLineReader.Create(const AFilename: string; const ASource: String);
- Var
- S : TStringStream;
- begin
- inherited Create(AFilename);
- S:=TStringStream.Create(ASource);
- try
- InitFromStream(S);
- finally
- S.Free;
- end;
- end;
- { TFileStreamLineReader }
- constructor TFileStreamLineReader.Create(const AFilename: string);
- Var
- S : TFileStream;
- begin
- inherited Create(AFilename);
- S:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
- try
- InitFromStream(S);
- finally
- S.Free;
- end;
- end;
- { TStreamLineReader }
- Procedure TStreamLineReader.InitFromStream(AStream : TStream);
- begin
- SetLength(FContent,AStream.Size);
- AStream.Read(FContent[1],AStream.Size);
- FPos:=0;
- end;
- function TStreamLineReader.IsEOF: Boolean;
- begin
- Result:=FPos>=Length(FContent);
- end;
- function TStreamLineReader.ReadLine: string;
- Var
- LPos : Integer;
- EOL : Boolean;
- begin
- If isEOF then
- exit;
- LPos:=FPos+1;
- Repeat
- Inc(FPos);
- EOL:=(FContent[FPos] in [#10,#13]);
- until isEOF or EOL;
- If EOL then
- Result:=Copy(FContent,LPos,FPos-LPos)
- else
- Result:=Copy(FContent,LPos,FPos-LPos+1);
- If (not isEOF) and (FContent[FPos]=#13) and (FContent[FPos+1]=#10) then
- inc(FPos);
- end;
- { TLineReader }
- constructor TLineReader.Create(const AFilename: string);
- begin
- FFileName:=AFileName;
- end;
- { ---------------------------------------------------------------------
- TFileLineReader
- ---------------------------------------------------------------------}
- constructor TFileLineReader.Create(const AFilename: string);
- begin
- inherited Create(AFileName);
- Assign(FTextFile, AFilename);
- Reset(FTextFile);
- SetTextBuf(FTextFile,FBuffer,SizeOf(FBuffer));
- FileOpened := true;
- end;
- destructor TFileLineReader.Destroy;
- begin
- if FileOpened then
- Close(FTextFile);
- inherited Destroy;
- end;
- function TFileLineReader.IsEOF: Boolean;
- begin
- Result := EOF(FTextFile);
- end;
- function TFileLineReader.ReadLine: string;
- begin
- ReadLn(FTextFile, Result);
- end;
- { ---------------------------------------------------------------------
- TBaseFileResolver
- ---------------------------------------------------------------------}
- procedure TBaseFileResolver.SetBaseDirectory(AValue: string);
- begin
- if FBaseDirectory=AValue then Exit;
- FBaseDirectory:=AValue;
- end;
- procedure TBaseFileResolver.SetStrictFileCase(AValue: Boolean);
- begin
- if FStrictFileCase=AValue then Exit;
- FStrictFileCase:=AValue;
- end;
- function TBaseFileResolver.FindIncludeFileName(const AName: string): String;
- function SearchLowUpCase(FN: string): string;
- var
- Dir: String;
- begin
- If FileExists(FN) then
- Result:=FN
- else if StrictFileCase then
- Result:=''
- else
- begin
- Dir:=ExtractFilePath(FN);
- FN:=ExtractFileName(FN);
- Result:=Dir+LowerCase(FN);
- If FileExists(Result) then exit;
- Result:=Dir+uppercase(Fn);
- If FileExists(Result) then exit;
- Result:='';
- end;
- end;
- var
- i: Integer;
- FN : string;
- begin
- Result := '';
- // convert pathdelims to system
- FN:=SetDirSeparators(AName);
- If FilenameIsAbsolute(FN) then
- begin
- // Maybe this should also do a SearchLowUpCase ?
- if FileExists(FN) then
- Result := FN;
- end
- else
- begin
- // file name is relative
- // search in include path
- I:=0;
- While (Result='') and (I<FIncludePaths.Count) do
- begin
- Result:=SearchLowUpCase(FIncludePaths[i]+AName);
- Inc(I);
- end;
- // search in BaseDirectory
- if (Result='') and (BaseDirectory<>'') then
- Result:=SearchLowUpCase(BaseDirectory+AName);
- end;
- end;
- constructor TBaseFileResolver.Create;
- begin
- inherited Create;
- FIncludePaths := TStringList.Create;
- end;
- destructor TBaseFileResolver.Destroy;
- begin
- FIncludePaths.Free;
- inherited Destroy;
- end;
- procedure TBaseFileResolver.AddIncludePath(const APath: string);
- begin
- if (APath='') then
- FIncludePaths.Add('./')
- else
- FIncludePaths.Add(IncludeTrailingPathDelimiter(ExpandFileName(APath)));
- end;
- { ---------------------------------------------------------------------
- TFileResolver
- ---------------------------------------------------------------------}
- function TFileResolver.CreateFileReader(const AFileName: String): TLineReader;
- begin
- If UseStreams then
- Result:=TFileStreamLineReader.Create(AFileName)
- else
- Result:=TFileLineReader.Create(AFileName);
- end;
- function TFileResolver.FindSourceFile(const AName: string): TLineReader;
- begin
- if not FileExists(AName) then
- Raise EFileNotFoundError.create(Aname)
- else
- try
- Result := CreateFileReader(AName)
- except
- Result := nil;
- end;
- end;
- function TFileResolver.FindIncludeFile(const AName: string): TLineReader;
- Var
- FN : String;
- begin
- Result:=Nil;
- FN:=FindIncludeFileName(ANAme);
- If (FN<>'') then
- try
- Result := TFileLineReader.Create(FN);
- except
- Result:=Nil;
- end;
- end;
- { ---------------------------------------------------------------------
- TPascalScanner
- ---------------------------------------------------------------------}
- constructor TPascalScanner.Create(AFileResolver: TBaseFileResolver);
- Function CS : TStringList;
- begin
- Result:=TStringList.Create;
- Result.Sorted:=True;
- Result.Duplicates:=dupError;
- end;
- begin
- inherited Create;
- FFileResolver := AFileResolver;
- FIncludeStack := TFPList.Create;
- FDefines := CS;
- FMacros:=CS;
- end;
- destructor TPascalScanner.Destroy;
- begin
- ClearMacros;
- FreeAndNil(FMacros);
- FreeAndNil(FDefines);
- ClearFiles;
- FIncludeStack.Free;
- inherited Destroy;
- end;
- procedure TPascalScanner.ClearFiles;
- begin
- // Dont' free the first element, because it is CurSourceFile
- while FIncludeStack.Count > 1 do
- begin
- TFileResolver(FIncludeStack[1]).Free;
- FIncludeStack.Delete(1);
- end;
- FIncludeStack.Clear;
- FreeAndNil(FCurSourceFile);
- end;
- procedure TPascalScanner.ClearMacros;
- Var
- I : Integer;
- begin
- For I:=0 to FMacros.Count-1 do
- FMacros.Objects[i].Free;
- FMacros.Clear;
- end;
- procedure TPascalScanner.SetCurTokenString(AValue: string);
- begin
- FCurtokenString:=AValue;
- end;
- procedure TPascalScanner.OpenFile(const AFilename: string);
- begin
- Clearfiles;
- FCurSourceFile := FileResolver.FindSourceFile(AFilename);
- if LogEvent(sleFile) then
- DoLog(SLogOpeningFile,[AFileName],True);
- FCurFilename := AFilename;
- FileResolver.BaseDirectory := IncludeTrailingPathDelimiter(ExtractFilePath(AFilename));
- end;
- function TPascalScanner.FetchToken: TToken;
- var
- IncludeStackItem: TIncludeStackItem;
- begin
- while true do
- begin
- Result := DoFetchToken;
- Case FCurToken of
- tkEOF:
- begin
- if FIncludeStack.Count > 0 then
- begin
- CurSourceFile.Free;
- IncludeStackItem :=
- TIncludeStackItem(FIncludeStack[FIncludeStack.Count - 1]);
- FIncludeStack.Delete(FIncludeStack.Count - 1);
- FCurSourceFile := IncludeStackItem.SourceFile;
- FCurFilename := IncludeStackItem.Filename;
- FCurToken := IncludeStackItem.Token;
- FCurTokenString := IncludeStackItem.TokenString;
- FCurLine := IncludeStackItem.Line;
- FCurRow := IncludeStackItem.Row;
- TokenStr := IncludeStackItem.TokenStr;
- IncludeStackItem.Free;
- Result := FCurToken;
- end
- else
- break
- end;
- tkWhiteSpace,
- tkLineEnding:
- if not (FSkipWhiteSpace or PPIsSkipping) then
- Break;
- tkComment:
- if not (FSkipComments or PPIsSkipping) then
- Break;
- else
- if not PPIsSkipping then
- break;
- end; // Case
- end;
- // Writeln(Result, '(',CurTokenString,')');
- end;
- procedure TPascalScanner.Error(const Msg: string);
- begin
- raise EScannerError.Create(Msg);
- end;
- procedure TPascalScanner.Error(const Msg: string; Args: array of Const);
- begin
- raise EScannerError.CreateFmt(Msg, Args);
- end;
- function TPascalScanner.DoFetchTextToken:TToken;
- var
- OldLength : Integer;
- TokenStart : PChar;
- SectionLength : Integer;
- begin
- Result:=tkEOF;
- OldLength:=0;
- FCurTokenString := '';
- while TokenStr[0] in ['#', ''''] do
- begin
- case TokenStr[0] of
- '#':
- begin
- TokenStart := TokenStr;
- Inc(TokenStr);
- if TokenStr[0] = '$' then
- begin
- Inc(TokenStr);
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'f']);
- end else
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0'..'9']);
- if Result=tkEOF then Result := tkChar else Result:=tkString;
- end;
- '''':
- begin
- TokenStart := TokenStr;
- Inc(TokenStr);
- while true do
- begin
- if TokenStr[0] = '''' then
- if TokenStr[1] = '''' then
- Inc(TokenStr)
- else
- break;
- if TokenStr[0] = #0 then
- Error(SErrOpenString);
- Inc(TokenStr);
- end;
- Inc(TokenStr);
- Result := tkString;
- end;
- else
- Break;
- end;
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- Inc(OldLength, SectionLength);
- end;
- end;
- Procedure TPascalScanner.PushStackItem;
- Var
- SI: TIncludeStackItem;
- begin
- SI := TIncludeStackItem.Create;
- SI.SourceFile := CurSourceFile;
- SI.Filename := CurFilename;
- SI.Token := CurToken;
- SI.TokenString := CurTokenString;
- SI.Line := CurLine;
- SI.Row := CurRow;
- SI.TokenStr := TokenStr;
- FIncludeStack.Add(SI);
- TokenStr:=Nil;
- FCurRow := 0;
- end;
- Procedure TPascalScanner.HandleIncludeFile(Param : String);
- begin
- PushStackItem;
- if Length(Param)>1 then
- begin
- if (Param[1]=#39) and (Param[length(Param)]=#39) then
- param:=copy(param,2,length(param)-2);
- end;
- FCurSourceFile := FileResolver.FindIncludeFile(Param);
- if not Assigned(FCurSourceFile) then
- Error(SErrIncludeFileNotFound, [Param]);
- FCurFilename := Param;
- if FCurSourceFile is TFileLineReader then
- FCurFilename := TFileLineReader(FCurSourceFile).Filename; // nicer error messages
- If LogEvent(sleFile) then
- DoLog(SLogOpeningFile,[FCurFileName],True);
- end;
- function TPascalScanner.HandleMacro(AIndex : integer) : TToken;
- Var
- M : TMacroDef;
- ML : TMacroReader;
- begin
- PushStackItem;
- M:=FMacros.Objects[AIndex] as TMacroDef;
- ML:=TMacroReader.Create(FCurFileName,M.Value);
- ML.CurRow:=FCurRow;
- ML.CurCol:=CurColumn;
- FCurSourceFile:=ML;
- Result:=DofetchToken;
- // Writeln(Result,Curtoken);
- end;
- Procedure TPascalScanner.HandleDefine(Param : String);
- Var
- Index : Integer;
- MN,MV : String;
- begin
- Param := UpperCase(Param);
- Index:=Pos(':=',Param);
- If (Index=0) then
- AddDefine(Param)
- else
- begin
- MV:=Trim(Param);
- MN:=Trim(Copy(MV,1,Index-1));
- Delete(MV,1,Index+1);
- Index:=FMacros.IndexOf(MN);
- If (Index=-1) then
- FMacros.AddObject(MN,TMacroDef.Create(MN,MV))
- else
- TMacroDef(FMacros.Objects[index]).Value:=MV;
- end;
- end;
- Procedure TPascalScanner.HandleUnDefine(Param : String);
- Var
- Index : integer;
- begin
- Param := UpperCase(Param);
- Index:=FDefines.IndexOf(Param);
- If (Index>=0) then
- RemoveDefine(Param)
- else
- begin
- Index := FMacros.IndexOf(Param);
- If (Index>=0) then
- begin
- FMacros.Objects[Index].FRee;
- FMacros.Delete(Index);
- end;
- end;
- end;
- function TPascalScanner.DoFetchToken: TToken;
- function FetchLine: Boolean;
- begin
- if CurSourceFile.IsEOF then
- begin
- FCurLine := '';
- TokenStr := nil;
- Result := false;
- end else
- begin
- FCurLine := CurSourceFile.ReadLine;
- TokenStr := PChar(CurLine);
- Result := true;
- Inc(FCurRow);
- if LogEvent(sleLineNumber) and ((FCurRow Mod 100) = 0) then
- DoLog(SLogLineNumber,[FCurRow],True);
- end;
- end;
- var
- TokenStart, CurPos: PChar;
- i: TToken;
- OldLength, SectionLength, NestingLevel, Index: Integer;
- Directive, Param : string;
- begin
- if TokenStr = nil then
- if not FetchLine then
- begin
- Result := tkEOF;
- FCurToken := Result;
- exit;
- end;
- FCurTokenString := '';
- case TokenStr[0] of
- #0: // Empty line
- begin
- FetchLine;
- Result := tkLineEnding;
- end;
- ' ':
- begin
- Result := tkWhitespace;
- repeat
- Inc(TokenStr);
- if TokenStr[0] = #0 then
- if not FetchLine then
- begin
- FCurToken := Result;
- exit;
- end;
- until not (TokenStr[0] in [' ']);
- end;
- #9:
- begin
- Result := tkTab;
- repeat
- Inc(TokenStr);
- if TokenStr[0] = #0 then
- if not FetchLine then
- begin
- FCurToken := Result;
- exit;
- end;
- until not (TokenStr[0] in [#9]);
- end;
- '#', '''':
- Result:=DoFetchTextToken;
- '&':
- begin
- TokenStart := TokenStr;
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0'..'7']);
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- Result := tkNumber;
- end;
- '$':
- begin
- TokenStart := TokenStr;
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0'..'9', 'A'..'F', 'a'..'f']);
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- Result := tkNumber;
- end;
- '%':
- begin
- TokenStart := TokenStr;
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0','1']);
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- Result := tkNumber;
- end;
- '(':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '*' then
- begin
- // Old-style multi-line comment
- Inc(TokenStr);
- while (TokenStr[0] <> '*') or (TokenStr[1] <> ')') do
- begin
- if TokenStr[0] = #0 then
- begin
- if not FetchLine then
- begin
- Result := tkEOF;
- FCurToken := Result;
- exit;
- end;
- end else
- Inc(TokenStr);
- end;
- Inc(TokenStr, 2);
- Result := tkComment;
- end else
- Result := tkBraceOpen;
- end;
- ')':
- begin
- Inc(TokenStr);
- Result := tkBraceClose;
- end;
- '*':
- begin
- Result:=tkMul;
- Inc(TokenStr);
- if TokenStr[0] = '*' then
- begin
- Inc(TokenStr);
- Result := tkPower;
- end
- else if (po_cassignments in options) then
- begin
- if TokenStr[0]='=' then
- begin
- Inc(TokenStr);
- Result:=tkAssignMul;
- end;
- end
- end;
- '+':
- begin
- Result:=tkPlus;
- Inc(TokenStr);
- if (po_cassignments in options) then
- begin
- if TokenStr[0]='=' then
- begin
- Inc(TokenStr);
- Result:=tkAssignPlus;
- end;
- end
- end;
- ',':
- begin
- Inc(TokenStr);
- Result := tkComma;
- end;
- '-':
- begin
- Result := tkMinus;
- Inc(TokenStr);
- if (po_cassignments in options) then
- begin
- if TokenStr[0]='=' then
- begin
- Inc(TokenStr);
- Result:=tkAssignMinus;
- end;
- end
- end;
- '.':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '.' then
- begin
- Inc(TokenStr);
- Result := tkDotDot;
- end else
- Result := tkDot;
- end;
- '/':
- begin
- Result := tkDivision;
- Inc(TokenStr);
- if (TokenStr[0] = '/') then // Single-line comment
- begin
- Inc(TokenStr);
- TokenStart := TokenStr;
- FCurTokenString := '';
- while TokenStr[0] <> #0 do
- Inc(TokenStr);
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- Result := tkComment;
- end
- else if (po_cassignments in options) then
- begin
- if TokenStr[0]='=' then
- begin
- Inc(TokenStr);
- Result:=tkAssignDivision;
- end;
- end
- end;
- '0'..'9':
- begin
- TokenStart := TokenStr;
- while true do
- begin
- Inc(TokenStr);
- case TokenStr[0] of
- '.':
- begin
- if TokenStr[1] in ['0'..'9', 'e', 'E'] then
- begin
- Inc(TokenStr);
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0'..'9', 'e', 'E']);
- end;
- break;
- end;
- '0'..'9': ;
- 'e', 'E':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '-' then
- Inc(TokenStr);
- while TokenStr[0] in ['0'..'9'] do
- Inc(TokenStr);
- break;
- end;
- else
- break;
- end;
- end;
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- Result := tkNumber;
- end;
- ':':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '=' then
- begin
- Inc(TokenStr);
- Result := tkAssign;
- end else
- Result := tkColon;
- end;
- ';':
- begin
- Inc(TokenStr);
- Result := tkSemicolon;
- end;
- '<':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '>' then
- begin
- Inc(TokenStr);
- Result := tkNotEqual;
- end else if TokenStr[0] = '=' then
- begin
- Inc(TokenStr);
- Result := tkLessEqualThan;
- end else
- Result := tkLessThan;
- end;
- '=':
- begin
- Inc(TokenStr);
- Result := tkEqual;
- end;
- '>':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '=' then
- begin
- Inc(TokenStr);
- Result := tkGreaterEqualThan;
- end else if TokenStr[0] = '<' then
- begin
- Inc(TokenStr);
- Result := tkSymmetricalDifference;
- end else
- Result := tkGreaterThan;
- end;
- '@':
- begin
- Inc(TokenStr);
- Result := tkAt;
- end;
- '[':
- begin
- Inc(TokenStr);
- Result := tkSquaredBraceOpen;
- end;
- ']':
- begin
- Inc(TokenStr);
- Result := tkSquaredBraceClose;
- end;
- '^':
- begin
- Inc(TokenStr);
- Result := tkCaret;
- end;
- '\':
- begin
- Inc(TokenStr);
- Result := tkBackslash;
- end;
- '{': // Multi-line comment
- begin
- Inc(TokenStr);
- TokenStart := TokenStr;
- FCurTokenString := '';
- OldLength := 0;
- NestingLevel := 0;
- while (TokenStr[0] <> '}') or (NestingLevel > 0) do
- begin
- if TokenStr[0] = #0 then
- begin
- SectionLength := TokenStr - TokenStart + 1;
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 1 then
- Move(TokenStart^, FCurTokenString[OldLength + 1],
- SectionLength - 1);
- Inc(OldLength, SectionLength);
- FCurTokenString[OldLength] := #10;
- if not FetchLine then
- begin
- Result := tkEOF;
- FCurToken := Result;
- exit;
- end;
- TokenStart := TokenStr;
- end else
- begin
- if not(po_delphi in Options) and (TokenStr[0] = '{') then
- Inc(NestingLevel)
- else if TokenStr[0] = '}' then
- Dec(NestingLevel);
- Inc(TokenStr);
- end;
- end;
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, OldLength + SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
- Inc(TokenStr);
- Result := tkComment;
- //WriteLn('Kommentar: "', CurTokenString, '"');
- if (Length(CurTokenString) > 0) and (CurTokenString[1] = '$') then
- begin
- TokenStart := @CurTokenString[2];
- CurPos := TokenStart;
- while (CurPos[0] <> ' ') and (CurPos[0] <> #0) do
- Inc(CurPos);
- SectionLength := CurPos - TokenStart;
- SetLength(Directive, SectionLength);
- if SectionLength > 0 then
- begin
- Move(TokenStart^, Directive[1], SectionLength);
- Directive := UpperCase(Directive);
- if CurPos[0] <> #0 then
- begin
- TokenStart := CurPos + 1;
- CurPos := TokenStart;
- while CurPos[0] <> #0 do
- Inc(CurPos);
- SectionLength := CurPos - TokenStart;
- SetLength(Param, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, Param[1], SectionLength);
- end else
- Param := '';
- if Not PPIsSkipping then
- begin
- if (Directive = 'I') or (Directive = 'INCLUDE') then
- begin
- if ((Param='') or (Param[1]<>'%')) then
- HandleIncludeFile(param)
- else if Param[1]='%' then
- begin
- fcurtokenstring:='{$i '+param+'}';
- fcurtoken:=tkstring;
- result:=fcurtoken;
- exit;
- end
- end
- else if (Directive = 'DEFINE') then
- HandleDefine(Param)
- else if (Directive = 'UNDEF') then
- HandleUnDefine(Param)
- end;
- if (Directive = 'IFDEF') then
- begin
- if PPSkipStackIndex = High(PPSkipModeStack) then
- Error(SErrIfXXXNestingLimitReached);
- PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
- PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
- Inc(PPSkipStackIndex);
- if PPIsSkipping then
- begin
- PPSkipMode := ppSkipAll;
- PPIsSkipping := true;
- end else
- begin
- Param := UpperCase(Param);
- Index := Defines.IndexOf(Param);
- if Index < 0 then
- Index := Macros.IndexOf(Param);
- if Index < 0 then
- begin
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end else
- PPSkipMode := ppSkipElseBranch;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(SLogIFDefAccepted,[Param])
- else
- DoLog(SLogIFDefRejected,[Param])
- end;
- end else if Directive = 'IFNDEF' then
- begin
- if PPSkipStackIndex = High(PPSkipModeStack) then
- Error(SErrIfXXXNestingLimitReached);
- PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
- PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
- Inc(PPSkipStackIndex);
- if PPIsSkipping then
- begin
- PPSkipMode := ppSkipAll;
- PPIsSkipping := true;
- end else
- begin
- Param := UpperCase(Param);
- Index := Defines.IndexOf(Param);
- if Index >= 0 then
- begin
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end else
- PPSkipMode := ppSkipElseBranch;
- If LogEvent(sleConditionals) then
- if PPSkipMode=ppSkipElseBranch then
- DoLog(SLogIFNDefAccepted,[Param])
- else
- DoLog(SLogIFNDefRejected,[Param])
- end;
- end else if Directive = 'IFOPT' then
- begin
- if PPSkipStackIndex = High(PPSkipModeStack) then
- Error(SErrIfXXXNestingLimitReached);
- PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
- PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
- Inc(PPSkipStackIndex);
- if PPIsSkipping then
- begin
- PPSkipMode := ppSkipAll;
- PPIsSkipping := true;
- end else
- begin
- { !!!: Currently, options are not supported, so they are just
- assumed as not being set. }
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- end;
- If LogEvent(sleConditionals) then
- DoLog(SLogIFOPTIgnored,[Uppercase(Param)])
- end else if Directive = 'IF' then
- begin
- if PPSkipStackIndex = High(PPSkipModeStack) then
- Error(SErrIfXXXNestingLimitReached);
- PPSkipModeStack[PPSkipStackIndex] := PPSkipMode;
- PPIsSkippingStack[PPSkipStackIndex] := PPIsSkipping;
- Inc(PPSkipStackIndex);
- if PPIsSkipping then
- begin
- PPSkipMode := ppSkipAll;
- PPIsSkipping := true;
- end else
- begin
- { !!!: Currently, expressions are not supported, so they are
- just assumed as evaluating to false. }
- PPSkipMode := ppSkipIfBranch;
- PPIsSkipping := true;
- If LogEvent(sleConditionals) then
- DoLog(SLogIFIgnored,[Uppercase(Param)])
- end;
- end else if Directive = 'ELSE' then
- begin
- if PPSkipStackIndex = 0 then
- Error(SErrInvalidPPElse);
- if PPSkipMode = ppSkipIfBranch then
- PPIsSkipping := false
- else if PPSkipMode = ppSkipElseBranch then
- PPIsSkipping := true;
- end else if ((Directive = 'ENDIF') or (Directive='IFEND')) then
- begin
- if PPSkipStackIndex = 0 then
- Error(SErrInvalidPPEndif);
- Dec(PPSkipStackIndex);
- PPSkipMode := PPSkipModeStack[PPSkipStackIndex];
- PPIsSkipping := PPIsSkippingStack[PPSkipStackIndex];
- end;
- end else
- Directive := '';
- end;
- end;
- 'A'..'Z', 'a'..'z', '_':
- begin
- TokenStart := TokenStr;
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
- SectionLength := TokenStr - TokenStart;
- SetLength(FCurTokenString, SectionLength);
- if SectionLength > 0 then
- Move(TokenStart^, FCurTokenString[1], SectionLength);
- for i := tkAbsolute to tkXOR do
- if CompareText(CurTokenString, TokenInfos[i]) = 0 then
- begin
- Result := i;
- FCurToken := Result;
- exit;
- end;
- Index:=FMacros.IndexOf(CurtokenString);
- if (Index=-1) then
- Result := tkIdentifier
- else
- Result:=HandleMacro(index);
- end;
- else
- if PPIsSkipping then
- Inc(TokenStr)
- else
- Error(SErrInvalidCharacter, [TokenStr[0]]);
- end;
- FCurToken := Result;
- end;
- function TPascalScanner.LogEvent(E: TPScannerLogEvent): Boolean;
- begin
- Result:=E in FLogEvents;
- end;
- function TPascalScanner.GetCurColumn: Integer;
- begin
- If (TokenStr<>Nil) then
- Result := TokenStr - PChar(CurLine)
- else
- Result:=0;
- end;
- procedure TPascalScanner.DoLog(const Msg: String;SkipSourceInfo : Boolean = False);
- begin
- If Assigned(FOnLog) then
- if SkipSourceInfo then
- FOnLog(Self,Msg)
- else
- FOnLog(Self,Format('%s(%d) : %s',[FCurFileName,FCurRow,Msg]));
- end;
- procedure TPascalScanner.DoLog(const Fmt: String; Args: array of const;SkipSourceInfo : Boolean = False);
- begin
- DoLog(Format(Fmt,Args),SkipSourceInfo);
- end;
- procedure TPascalScanner.SetOptions(AValue: TPOptions);
- begin
- if FOptions=AValue then Exit;
- FOptions:=AValue;
- end;
- Procedure TPascalScanner.AddDefine(S : String);
- begin
- If FDefines.IndexOf(S)=-1 then
- FDefines.Add(S);
- end;
- Procedure TPascalScanner.RemoveDefine(S : String);
- Var
- I : Integer;
- begin
- I:=FDefines.IndexOf(S);
- if (I<>-1) then
- FDefines.Delete(I);
- end;
- end.
|