codetools: skipped code is now converted to special comments

git-svn-id: trunk@38521 -
This commit is contained in:
mattias 2012-09-05 10:47:44 +00:00
parent a3eea5f52e
commit 20382c7ed0
10 changed files with 325 additions and 404 deletions

View File

@ -262,7 +262,7 @@ begin
Result:=false;
ProcHead:='';
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
[btSetIgnoreErrorPos,btLoadDirtySource,btCursorPosOutAllowed]);
[btSetIgnoreErrorPos,btCursorPosOutAllowed]);
ANode:=FindDeepestNodeAtPos(CleanCursorPos,True);
while (ANode<>nil) and (ANode.Desc<>ctnProcedure) do
ANode:=ANode.Parent;

View File

@ -38,7 +38,6 @@ interface
{ $DEFINE ShowIgnoreError}
{ $DEFINE VerboseUpdateNeeded}
{$DEFINE ShowDirtySrc}
uses
{$IFDEF MEM_CHECK}
@ -74,41 +73,6 @@ type
end;
{ TDirtySource - class to store a dirty source }
TDirtySource = class
public
CursorPos: TCodeXYPosition;
Src: string;
GapSrc: string;
Code: TCodeBuffer;
Valid: boolean;
CurPos: TAtomPosition;
StartPos: integer;
GapStart: integer;
GapEnd: integer;
LockCount: integer;
Owner: TCustomCodeTool;
procedure BeginUpdate;
procedure EndUpdate;
procedure SetGap(const NewCursorPos: TCodeXYPosition;
NewDirtyStartPos, NewDirtyGapStart, NewDirtyGapEnd: integer);
constructor Create(TheOwner: TCustomCodeTool);
procedure Clear;
procedure SetCursorToIdentStartEndAtPosition;
function GetCursorSrcPos: PChar;
function IsPCharInSrc(p: PChar): boolean;
procedure MoveCursorToPos(APos: integer);
procedure MoveCursorToPos(APos: PChar);
function CalcMemSize: PtrUInt;
end;
THybridCursorType = (
hcClean,
hcDirty
);
// types for user aborts
TOnParserProgress = function(Tool: TCustomCodeTool): boolean of object;
TCodeTreeChangeEvent = procedure(Tool: TCustomCodeTool;
@ -169,8 +133,6 @@ type
procedure RaiseLastError;
procedure DoProgress; inline;
procedure NotifyAboutProgress;
// dirty/dead source
procedure LoadDirtySource(const CursorPos: TCodeXYPosition);
procedure FetchScannerSource(Range: TLinkScannerRange); virtual;
function InternalAtomIsIdentifier: boolean; inline;
public
@ -190,9 +152,6 @@ type
JumpCentered: boolean;
CursorBeyondEOL: boolean;
DirtySrc: TDirtySource;
HybridCursorType: THybridCursorType;
ErrorPosition: TCodeXYPosition;
ErrorNicePosition: TCodeXYPosition;// if NiceErrorPosition is set, then it is in front of ErrorPosition
@ -243,7 +202,6 @@ type
procedure BeginParsingAndGetCleanPosOLD(
OnlyInterfaceNeeded: boolean; CursorPos: TCodeXYPosition;
out CleanCursorPos: integer);
function IsDirtySrcValid: boolean;
function StringIsKeyWord(const Word: string): boolean;
@ -255,9 +213,7 @@ type
procedure MoveCursorToNearestAtom(ACleanPos: integer);
procedure MoveCursorToLastNodeAtom(ANode: TCodeTreeNode);
function IsPCharInSrc(ACleanPos: PChar): boolean;
procedure MoveHybridCursorToPos(DirtyPos: PChar);
function GetHybridCursorStart: integer;
// read atoms
procedure ReadNextAtom;
procedure UndoReadNextAtom;
@ -417,7 +373,6 @@ begin
FreeAndNil(LastAtoms);
FreeAndNil(Tree);
FreeAndNil(KeyWordFuncList);
FreeAndNil(DirtySrc);
inherited Destroy;
end;
@ -540,40 +495,6 @@ begin
end;
end;
procedure TCustomCodeTool.LoadDirtySource(const CursorPos: TCodeXYPosition);
// - create the DirtySrc object
// - load the unparsed source at CursorPos
// - find the gap bounds
var
NewDirtyStartPos: integer;
NewDirtyGapStart: integer;
NewDirtyGapEnd: integer;
CursorInLink: Boolean;
BestLinkIndex: Integer;
BestLink: TSourceLink;
begin
DebugLn('TCustomCodeTool.LoadDirtySource X=',dbgs(CursorPos.X),' Y=',dbgs(CursorPos.Y),
' ',ExtractFilename(CursorPos.Code.Filename));
if DirtySrc=nil then DirtySrc:=TDirtySource.Create(Self);
CursorPos.Code.LineColToPosition(CursorPos.Y,CursorPos.X,NewDirtyStartPos);
if NewDirtyStartPos<1 then
RaiseCatchableException('NewDirtyStartPos<1');
CursorInLink:=false;
BestLinkIndex:=Scanner.LinkIndexNearCursorPos(NewDirtyStartPos,
CursorPos.Code,CursorInLink);
if BestLinkIndex<0 then
RaiseCatchableException('BestLinkIndex<0');
if CursorInLink then
RaiseCatchableException('CursorInLink');
BestLink:=Scanner.Links[BestLinkIndex];
NewDirtyGapStart:=BestLink.SrcPos+Scanner.LinkSize(BestLinkIndex);
if BestLinkIndex<Scanner.LinkCount then
NewDirtyGapEnd:=Scanner.Links[BestLinkIndex+1].SrcPos
else
NewDirtyGapEnd:=CursorPos.Code.SourceLength;
DirtySrc.SetGap(CursorPos,NewDirtyStartPos,NewDirtyGapStart,NewDirtyGapEnd);
end;
procedure TCustomCodeTool.FetchScannerSource(Range: TLinkScannerRange);
begin
// update scanned code
@ -590,8 +511,6 @@ begin
DebugLn(['TCustomCodeTool.BeginParsing ',MainFilename]);
{$ENDIF}
FRangeValidTill:=lsrInit;
DirtySrc.Free;
DirtySrc:=nil;
end;
// delete nodes
@ -2101,11 +2020,6 @@ begin
BeginParsingAndGetCleanPos(Range,CursorPos,CleanCursorPos);
end;
function TCustomCodeTool.IsDirtySrcValid: boolean;
begin
Result:=(DirtySrc<>nil) and (DirtySrc.Code<>nil);
end;
function TCustomCodeTool.IgnoreErrorAfterPositionIsInFrontOfLastErrMessage: boolean;
var
IgnoreErrorAfterCleanPos: integer;
@ -2351,7 +2265,6 @@ begin
LastAtoms.Clear;
NextPos.StartPos:=-1;
CurNode:=nil;
HybridCursorType:=hcClean;
end;
procedure TCustomCodeTool.MoveCursorToCleanPos(ACleanPos: PChar);
@ -2423,23 +2336,6 @@ begin
Result:=true;
end;
procedure TCustomCodeTool.MoveHybridCursorToPos(DirtyPos: PChar);
begin
if IsDirtySrcValid and (not IsPCharInSrc(DirtyPos)) then begin
DirtySrc.MoveCursorToPos(DirtyPos);
HybridCursorType:=hcDirty;
end else
MoveCursorToCleanPos(DirtyPos);
end;
function TCustomCodeTool.GetHybridCursorStart: integer;
begin
if HybridCursorType=hcDirty then
Result:=DirtySrc.CurPos.StartPos
else
Result:=CurPos.StartPos;
end;
procedure TCustomCodeTool.CreateChildNode;
var NewNode: TCodeTreeNode;
begin
@ -2618,9 +2514,6 @@ begin
if LastAtoms<>nil then
Stats.Add('TCustomCodeTool.LastAtoms',
LastAtoms.CalcMemSize);
if DirtySrc<>nil then
Stats.Add('TCustomCodeTool.DirtySrc',
DirtySrc.CalcMemSize);
end;
procedure TCustomCodeTool.CheckNodeTool(Node: TCodeTreeNode);
@ -2850,6 +2743,17 @@ end;
procedure TCustomCodeTool.GetCleanPosInfo(CodePosInFront, CleanPos: integer;
ResolveComments: boolean; out SameArea: TAtomPosition);
{ Use this function to safely find out if a position is in a comment,
a string constant, an atom or is in space
CodePosInFront: a position in code, where parsing starts
If -1 it uses FindDeepestNodeAtPos
CleanPos: target position
ResolveComments: if CleanPos is in a comment, parse again in the comment (not recursive)
SameArea: area around CleanPos, either an atom, comment, directive or space
if CleanPos<CodePosInFront then CleanAtomPosition
if CleanPos>SrcLen then CurPos.StartPos>SrcLen
}
var
ANode: TCodeTreeNode;
begin
@ -2858,6 +2762,8 @@ begin
ANode:=FindDeepestNodeAtPos(CleanPos,True);
CodePosInFront:=ANode.StartPos;
end;
if CodePosInFront>CleanPos then
exit;
MoveCursorToCleanPos(CodePosInFront);
repeat
ReadNextAtom;
@ -2893,6 +2799,7 @@ begin
ReadTillCommentEnd;
SameArea.EndPos:=CurPos.StartPos;
if (SameArea.StartPos=SameArea.EndPos) then
// inconsistency: some non space and non comment between two tokens
RaiseException('TCustomCodeTool.GetCleanPosInfo Internal Error A');
if CleanPos<SameArea.EndPos then begin
// cursor is in comment
@ -2900,11 +2807,19 @@ begin
// take comment as normal code and search again
CodePosInFront:=SameArea.StartPos;
case Src[CodePosInFront] of
'{': inc(CodePosInFront);
'{':
begin
inc(CodePosInFront);
if (CodePosInFront<=SrcLen) and (Src[CodePosInFront+1]=#3) then
inc(CodePosInFront);
end;
'(','/': inc(CodePosInFront,2);
else
RaiseException('TCustomCodeTool.GetCleanPosInfo Internal Error B '+dbgstr(Src[CodePosInFront])+' at '+CleanPosToStr(CodePosInFront,true));
end;
if CodePosInFront>CleanPos then
// CleanPos at start of comment => return comment
exit;
GetCleanPosInfo(CodePosInFront,CleanPos,true,SameArea);
end;
exit;
@ -3209,134 +3124,6 @@ begin
Filename:=AFilename;
end;
{ TDirtySource }
procedure TDirtySource.BeginUpdate;
begin
inc(LockCount);
end;
procedure TDirtySource.EndUpdate;
begin
if LockCount<=0 then
RaiseCatchableException('TDirtySource.EndUpdate');
dec(LockCount);
end;
procedure TDirtySource.SetGap(const NewCursorPos: TCodeXYPosition;
NewDirtyStartPos, NewDirtyGapStart, NewDirtyGapEnd: integer);
begin
// check for conflicts
if (LockCount>0) then begin
if (Code<>nil) and (Code<>NewCursorPos.Code) then
RaiseCatchableException('TDirtySource.SetGap Code change');
if (GapStart>0) then
if (NewDirtyStartPos<>StartPos)
or (NewDirtyGapStart<>GapStart)
or (NewDirtyGapEnd<>GapEnd) then
RaiseCatchableException('TDirtySource.SetGap Gap change');
end;
if (NewDirtyGapStart>NewDirtyStartPos)
or (NewDirtyStartPos>NewDirtyGapEnd) then
RaiseCatchableException('TDirtySource.SetGap Gap Bounds');
// set values
CursorPos:=NewCursorPos;
Code:=CursorPos.Code;
StartPos:=NewDirtyStartPos;
GapStart:=NewDirtyGapStart;
GapEnd:=NewDirtyGapEnd;
CurPos.StartPos:=StartPos;
CurPos.EndPos:=StartPos;
CurPos.Flag:=cafNone;
// get source
if Code<>nil then
Src:=Code.Source
else
Src:='';
if (GapStart>0) then begin
GapSrc:=copy(Src,GapStart,GapEnd-GapStart);
{$IFDEF ShowDirtySrc}
DebugLn('TDirtySource.SetGap Owner=',ExtractFilename(Owner.MainFilename),
' Code=',ExtractFilename(Code.Filename),
' Gap('+dbgs(GapStart)+','+dbgs(StartPos)+','+dbgs(GapEnd)+')',
'"',StringToPascalConst(copy(GapSrc,1,20)),'"..',
'"',StringToPascalConst(copy(GapSrc,length(GapSrc)-19,20)),'"'
);
{$ENDIF}
end else begin
GapSrc:='';
end;
end;
constructor TDirtySource.Create(TheOwner: TCustomCodeTool);
begin
Owner:=TheOwner;
end;
procedure TDirtySource.Clear;
begin
SetGap(CodeXYPosition(0,0,nil),0,0,0);
end;
procedure TDirtySource.SetCursorToIdentStartEndAtPosition;
begin
GetIdentStartEndAtPosition(GapSrc,CurPos.StartPos,
CurPos.StartPos,CurPos.EndPos);
end;
function TDirtySource.GetCursorSrcPos: PChar;
begin
Result:=@Src[CurPos.StartPos];
end;
function TDirtySource.IsPCharInSrc(p: PChar): boolean;
var NewPos: integer;
begin
Result:=false;
if Src='' then exit;
NewPos:=PtrInt(PtrUInt(p))-PtrInt(PtrUInt(@Src[1]))+1;
if (NewPos<1) or (NewPos>length(Src)) then exit;
Result:=true;
end;
procedure TDirtySource.MoveCursorToPos(APos: integer);
begin
CurPos.StartPos:=APos;
CurPos.EndPos:=APos;
CurPos.Flag:=cafNone;
end;
procedure TDirtySource.MoveCursorToPos(APos: PChar);
procedure RaiseSrcEmpty;
begin
RaiseCatchableException('[TDirtySource.MoveCursorToPos - PChar] Src empty');
end;
procedure RaiseNotInSrc;
begin
RaiseCatchableException('[TDirtySource.MoveCursorToPos - PChar] Pos not in Src');
end;
var NewPos: integer;
begin
if Src='' then
RaiseSrcEmpty;
NewPos:=PtrInt(PtrUInt(APos))-PtrInt(PtrUInt(@Src[1]))+1;
if (NewPos<1) or (NewPos>length(Src)) then
RaiseNotInSrc;
MoveCursorToPos(NewPos);
end;
function TDirtySource.CalcMemSize: PtrUInt;
begin
Result:=PtrUInt(InstanceSize)
+MemSizeString(Src)
+MemSizeString(GapSrc);
end;
{ TCodeTreeNodeParseError }
constructor TCodeTreeNodeParseError.Create(ANode: TCodeTreeNode);

View File

@ -29,7 +29,7 @@
<PackageName Value="CodeTools"/>
</Item1>
</RequiredPackages>
<Units Count="4">
<Units Count="5">
<Unit0>
<Filename Value="finddeclaration.lpr"/>
<IsPartOfProject Value="True"/>
@ -49,6 +49,11 @@
<Filename Value="../../../../../amat/test/test.inc"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="scanexamples/commentsidentifiers.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="commentsidentifiers"/>
</Unit4>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -48,6 +48,7 @@ begin
writeln('Usage:');
writeln(' ',ParamStr(0));
writeln(' ',ParamStr(0),' <filename> <X> <Y>');
Halt(1);
end;
// setup the Options

View File

@ -43,7 +43,7 @@ uses
MemCheck,
{$ENDIF}
Classes, SysUtils, LazUTF8, LazDbgLog, LazFileCache, LazFileUtils,
lazutf8classes, AVL_Tree, CodeToolsStrConsts;
lazutf8classes, LazLogger, AVL_Tree, CodeToolsStrConsts;
type
TFPCStreamSeekType = int64;
@ -289,6 +289,9 @@ function dbgMemRange(P: PByte; Count: integer; Width: integer = 0): string; over
function DbgS(const i1,i2,i3,i4: integer): string; overload;
function DbgStr(const StringWithSpecialChars: string): string; overload;
function DbgStr(const StringWithSpecialChars: string; StartPos, Len: PtrInt): string; overload;
function DbgText(const StringWithSpecialChars: string;
KeepLines: boolean = true // true = add LineEnding for each line break
): string; overload;
function MemSizeString(const s: string): PtrUInt; inline;
function MemSizeFPList(const List: TFPList): PtrUInt; inline;
@ -2061,15 +2064,15 @@ var
s: String;
begin
Result:=StringWithSpecialChars;
i:=1;
while (i<=length(Result)) do begin
i:=length(Result);
while (i>0) do begin
case Result[i] of
' '..#126: inc(i);
' '..#126: ;
else
s:='#'+IntToStr(ord(Result[i]));
Result:=copy(Result,1,i-1)+s+copy(Result,i+1,length(Result)-i);
inc(i,length(s));
ReplaceSubstring(Result,i,1,s);
end;
dec(i);
end;
end;
@ -2079,6 +2082,38 @@ begin
Result:=dbgstr(copy(StringWithSpecialChars,StartPos,Len));
end;
function DbgText(const StringWithSpecialChars: string; KeepLines: boolean
): string;
var
i: Integer;
s: String;
LastChar: Char;
c: Char;
begin
Result:=StringWithSpecialChars;
i:=1;
LastChar:=#0;
while (i<=length(Result)) do begin
c:=Result[i];
case c of
' '..#126: inc(i);
else
s:='#'+IntToStr(ord(c));
if (c in [#10,#13]) then begin
if ((LastChar in [#10,#13])
or (i=length(Result)) or (not (Result[i+1] in [#10,#13])))
then begin
s+=LineEnding;
c:=#0; // line break was handled
end;
end;
ReplaceSubstring(Result,i,1,s);
inc(i,length(s));
end;
LastChar:=c;
end;
end;
function MemSizeString(const s: string): PtrUInt;
begin
Result:=LazDbgLog.MemSizeString(s);

View File

@ -1236,7 +1236,6 @@ begin
{$IFDEF CTDEBUG}
DebugLn('TFindDeclarationTool.FindDeclarationOfIdentifier A CursorPos=X',dbgs(CursorPos.X),',Y',dbgs(CursorPos.Y));
{$ENDIF}
if DirtySrc<>nil then DirtySrc.Clear;
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
[btSetIgnoreErrorPos]);
{$IFDEF CTDEBUG}
@ -1410,12 +1409,13 @@ begin
{$IFDEF CTDEBUG}
DebugLn('TFindDeclarationTool.FindDeclaration A CursorPos=X',dbgs(CursorPos.X),',Y',dbgs(CursorPos.Y));
{$ENDIF}
if DirtySrc<>nil then DirtySrc.Clear;
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
[btSetIgnoreErrorPos,btLoadDirtySource,btCursorPosOutAllowed]);
[btSetIgnoreErrorPos,btCursorPosOutAllowed]);
{$IFDEF CTDEBUG}
DebugLn('TFindDeclarationTool.FindDeclaration C CleanCursorPos=',dbgs(CleanCursorPos));
{$ENDIF}
//debugln(['TFindDeclarationTool.FindDeclaration ',dbgtext(copy(Src,CleanCursorPos-30,30)),'|',dbgtext(copy(Src,CleanCursorPos,30))]);
// find CodeTreeNode at cursor
if (Tree.Root<>nil) and (Tree.Root.StartPos<=CleanCursorPos) then begin
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(CleanCursorPos,true);
@ -1444,8 +1444,7 @@ begin
CleanPosInFront:=1;
CursorNode:=nil;
end;
if (not IsDirtySrcValid)
and IsIncludeDirectiveAtPos(CleanCursorPos,CleanPosInFront,NewPos.Code)
if IsIncludeDirectiveAtPos(CleanCursorPos,CleanPosInFront,NewPos.Code)
then begin
// include directive
//DebugLn(['TFindDeclarationTool.FindDeclaration IsIncludeDirectiveAtPos']);
@ -1464,8 +1463,7 @@ begin
{$IFDEF CTDEBUG}
DebugLn('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsString(CursorNode.Desc),' HasChildren=',dbgs(CursorNode.FirstChild<>nil));
{$ENDIF}
if (not IsDirtySrcValid)
and (CursorNode.Desc in [ctnUsesSection,ctnUseUnit]) then begin
if (CursorNode.Desc in [ctnUsesSection,ctnUseUnit]) then begin
// in uses section
//DebugLn(['TFindDeclarationTool.FindDeclaration IsUsesSection']);
Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos,
@ -1485,19 +1483,13 @@ begin
CheckIfCursorInPropertyNode;
// set cursor on identifier
MoveCursorToCleanPos(CleanCursorPos);
if IsDirtySrcValid then begin
DirtySrc.SetCursorToIdentStartEndAtPosition;
CursorAtIdentifier:=DirtySrc.CurPos.StartPos<DirtySrc.CurPos.EndPos;
IdentifierStart:=DirtySrc.GetCursorSrcPos;
end else begin
GetIdentStartEndAtPosition(Src,CleanCursorPos,
CurPos.StartPos,CurPos.EndPos);
CursorAtIdentifier:=CurPos.StartPos<CurPos.EndPos;
if CursorAtIdentifier then
IdentifierStart:=@Src[CurPos.StartPos]
else
IdentifierStart:=PChar(Src);
end;
GetIdentStartEndAtPosition(Src,CleanCursorPos,
CurPos.StartPos,CurPos.EndPos);
CursorAtIdentifier:=CurPos.StartPos<CurPos.EndPos;
if CursorAtIdentifier then
IdentifierStart:=@Src[CurPos.StartPos]
else
IdentifierStart:=PChar(Src);
if CursorAtIdentifier then begin
// find declaration of identifier
Params:=TFindDeclarationParams.Create;
@ -1510,7 +1502,6 @@ begin
if fsfSkipClassForward in SearchSmartFlags then
Include(Params.Flags,fdfSkipClassForward);
if not DirectSearch then begin
// ToDo: DirtySrc
Result:=FindDeclarationOfIdentAtParam(Params);
end else begin
Include(Params.Flags,fdfIgnoreCurContextNode);
@ -5163,9 +5154,8 @@ begin
ActivateGlobalWriteLock;
try
// build code tree
if DirtySrc<>nil then DirtySrc.Clear;
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
[btSetIgnoreErrorPos,btLoadDirtySource,btCursorPosOutAllowed]);
[btSetIgnoreErrorPos,btCursorPosOutAllowed]);
// find CodeTreeNode at cursor
if (Tree.Root<>nil) and (Tree.Root.StartPos<=CleanCursorPos) then
CursorNode := BuildSubTreeAndFindDeepestNodeAtPos(CleanCursorPos, True)
@ -5182,16 +5172,10 @@ begin
end;
// set cursor on identifier
MoveCursorToCleanPos(CleanCursorPos);
if IsDirtySrcValid then begin
DirtySrc.SetCursorToIdentStartEndAtPosition;
if DirtySrc.CurPos.StartPos >= DirtySrc.CurPos.EndPos then Exit;
Identifier := DirtySrc.GetCursorSrcPos;
end else begin
GetIdentStartEndAtPosition(Src,CleanCursorPos,
CurPos.StartPos,CurPos.EndPos);
if CurPos.StartPos >= CurPos.EndPos then Exit;
Identifier := @Src[CurPos.StartPos];
end;
GetIdentStartEndAtPosition(Src,CleanCursorPos,
CurPos.StartPos,CurPos.EndPos);
if CurPos.StartPos >= CurPos.EndPos then Exit;
Identifier := @Src[CurPos.StartPos];
// find declaration of identifier
Params := TFindDeclarationParams.Create;
try

View File

@ -2347,8 +2347,7 @@ begin
ReadPriorAtom;
CurrentIdentifierList.StartAtomInFront:=CurPos;
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags)
and (not IsDirtySrcValid) then
begin
then begin
// check if LValue
if (CurPos.Flag in [cafSemicolon,cafEnd,cafColon])
or UpAtomIs('BEGIN')
@ -2370,7 +2369,7 @@ begin
end;
end;
// context behind
if (IdentEndPos<SrcLen) and (not IsDirtySrcValid) then begin
if (IdentEndPos<SrcLen) then begin
MoveCursorToCleanPos(IdentEndPos);
InFrontOfDirective:=(CurPos.StartPos<SrcLen) and (Src[CurPos.StartPos]='{')
and (Src[CurPos.StartPos+1]='$');

View File

@ -26,9 +26,6 @@
resulting source is called the cleaned source. A link points from a position
of the cleaned source to its position in the real source.
The link list makes it possible to change scanned code in the source files.
ToDo:
- macros
}
unit LinkScanner;
@ -44,7 +41,6 @@ unit LinkScanner;
{$I codetools.inc}
{ $DEFINE ShowIgnoreErrorAfter}
{ $DEFINE EnableIncludeSkippedCode}
// debugging
{ $DEFINE ShowUpdateCleanedSrc}
@ -95,7 +91,10 @@ type
{ TSourceLink is used to map between the codefiles and the cleaned source }
TSourceLinkKind = (
slkCode,
slkMissingIncludeFile
slkMissingIncludeFile,
slkSkipStart, // start of skipped code due to IFDEFs {#3
slkSkipEnd, // end of skipped code due to IFDEFs #3}
slkCompilerString // e.g. {$I %FPCVERSION%}
);
TSourceLinkKinds = set of TSourceLinkKind;
PSourceLink = ^TSourceLink;
@ -349,15 +348,15 @@ type
function ReturnFromIncludeFileAndIsEnd: boolean;
function ReadIdentifier: string;
function ReadUpperIdentifier: string;
procedure SkipSpace; {$IFDEF UseInline}inline;{$ENDIF}
procedure SkipCurlyComment;
procedure SkipLineComment;
procedure SkipRoundComment;
procedure ReadSpace; {$IFDEF UseInline}inline;{$ENDIF}
procedure ReadCurlyComment;
procedure ReadLineComment;
procedure ReadRoundComment;
procedure CommentEndNotFound;
procedure EndComment; {$IFDEF UseInline}inline;{$ENDIF}
procedure IncCommentLevel; {$IFDEF UseInline}inline;{$ENDIF}
procedure DecCommentLevel; {$IFDEF UseInline}inline;{$ENDIF}
procedure HandleDirectives;
procedure HandleDirective;
procedure UpdateCleanedSource(NewCopiedSrcPos: integer);
function ReturnFromIncludeFile: boolean;
function ParseKeyWord(StartPos, WordLen: integer; LastTokenType: TLSTokenType
@ -387,7 +386,9 @@ type
procedure SetCompilerMode(const AValue: TCompilerMode);
procedure SkipTillEndifElse(SkippingUntil: TLSSkippingDirective);
function InternalIfDirective: boolean;
procedure EndSkipping;
procedure AddSkipComment(IsStart: boolean);
function IfdefDirective: boolean;
function IfCDirective: boolean;
function IfndefDirective: boolean;
@ -425,6 +426,7 @@ type
function MissingIncludeFilesNeedsUpdate: boolean;
procedure ClearMissingIncludeFiles;
// code macros
procedure AddMacroValue(MacroName: PChar;
ValueStart, ValueEnd: integer);
procedure ClearMacros;
@ -623,6 +625,7 @@ function IndexOfCodeInUniqueList(ACode: Pointer;
UniqueSortedCodeList: TFPList): integer;
function dbgs(r: TLinkScannerRange): string; overload;
function dbgs(const ModeSwitches: TCompilerModeSwitches): string; overload;
function dbgs(k: TSourceLinkKind): string; overload;
implementation
@ -689,6 +692,17 @@ begin
Result:='['+Result+']';
end;
function dbgs(k: TSourceLinkKind): string;
begin
case k of
slkCode: Result:='Code';
slkMissingIncludeFile: Result:='MissingInc';
slkSkipStart: Result:='SkipStart';
slkSkipEnd: Result:='SkipEnd';
else Result:='?';
end;
end;
procedure AddCodeToUniqueList(ACode: Pointer; UniqueSortedCodeList: TFPList);
var l,m,r: integer;
begin
@ -751,7 +765,14 @@ var
NewCapacity: Integer;
Link: PSourceLink;
begin
if FLinkCount=FLinkCapacity then begin
if (LinkCount>0) and (FLinks[FLinkCount-1].CleanedPos=CleanedLen+1) then begin
// last link is empty => remove
{$IFDEF ShowUpdateCleanedSrc}
Link:=@FLinks[FLinkCount-1];
debugln(['TLinkScanner.AddLink removing empty link: ',dbgs(Link^.Kind)]);
{$ENDIF}
dec(FLinkCount);
end else if FLinkCount=FLinkCapacity then begin
NewCapacity:=FLinkCapacity*2;
if NewCapacity<16 then NewCapacity:=16;
ReAllocMem(FLinks,NewCapacity*SizeOf(TSourceLink));
@ -878,8 +899,6 @@ function TLinkScanner.FindFirstSiblingLink(LinkIndex: integer): integer;
if LinkIndex is in an include file, the result will be the first link of
the include file. If the include file is included multiple times, it is
treated as if they are different files.
ToDo: if include file includes itself, directly or indirectly
}
var
LastIndex: integer;
@ -1043,7 +1062,7 @@ begin
end;
end;
procedure TLinkScanner.HandleDirectives;
procedure TLinkScanner.HandleDirective;
var DirStart, DirLen: integer;
begin
SrcPos:=CommentInnerStartPos+1;
@ -1052,7 +1071,7 @@ begin
inc(SrcPos);
DirLen:=SrcPos-DirStart;
if DirLen>255 then DirLen:=255;
FDirectiveName:=UpperCaseStr(copy(Src,DirStart,DirLen));
FDirectiveName:=copy(Src,DirStart,DirLen);
DoDirective(DirStart,DirLen);
SrcPos:=CommentEndPos;
end;
@ -1108,20 +1127,20 @@ begin
'{' :
begin
SrcPos:=p-PChar(Src)+1;
SkipCurlyComment;
ReadCurlyComment;
p:=@Src[SrcPos];
end;
'/':
if p[1]='/' then begin
SrcPos:=p-PChar(Src)+1;
SkipLineComment;
ReadLineComment;
p:=@Src[SrcPos];
end else
break;
'(':
if p[1]='*' then begin
SrcPos:=p-PChar(Src)+1;
SkipRoundComment;
ReadRoundComment;
p:=@Src[SrcPos];
end else
break;
@ -1397,13 +1416,12 @@ begin
LastTokenType:=TokenType;
end;
finally
if FSkippingDirectives=lssdNone then begin
{$IFDEF ShowUpdateCleanedSrc}
DebugLn('TLinkScanner.Scan UpdatePos=',DbgS(SrcPos-1));
{$ENDIF}
if SrcPos>CopiedSrcPos then
UpdateCleanedSource(SrcPos-1);
end else begin
{$IFDEF ShowUpdateCleanedSrc}
DebugLn('TLinkScanner.Scan UpdatePos=',DbgS(SrcPos-1));
{$ENDIF}
if (SrcPos>CopiedSrcPos) then
UpdateCleanedSource(SrcPos-1);
if FSkippingDirectives<>lssdNone then begin
{$IFDEF ShowUpdateCleanedSrc}
DebugLn(['TLinkScanner.Scan missing $ENDIF']);
{$ENDIF}
@ -1431,7 +1449,7 @@ begin
FLinks[Index]:=Value;
end;
procedure TLinkScanner.SkipCurlyComment;
procedure TLinkScanner.ReadCurlyComment;
// a normal pascal {} comment
var
p: PChar;
@ -1469,11 +1487,12 @@ begin
CommentInnerEndPos:=SrcPos-1;
if (CommentLevel>0) then CommentEndNotFound;
// handle compiler switches
if Src[CommentInnerStartPos]='$' then HandleDirectives;
if Src[CommentInnerStartPos]='$' then
HandleDirective;
EndComment;
end;
procedure TLinkScanner.SkipLineComment;
procedure TLinkScanner.ReadLineComment;
// a // newline comment
var
p: PChar;
@ -1494,7 +1513,7 @@ begin
EndComment;
end;
procedure TLinkScanner.SkipRoundComment;
procedure TLinkScanner.ReadRoundComment;
// a delphi comment (* *)
var
p: PChar;
@ -1539,7 +1558,8 @@ begin
CommentInnerEndPos:=SrcPos-2;
if (CommentLevel>0) then CommentEndNotFound;
// handle compiler switches
if Src[CommentInnerStartPos]='$' then HandleDirectives;
if Src[CommentInnerStartPos]='$' then
HandleDirective;
EndComment;
end;
@ -2352,7 +2372,6 @@ begin
else if InitialValues.IsDefined('WIN32') then
FHiddenUsedUnits:='SYSWIN32';
end;
// ToDo: heaptrc
if InitialValues.IsDefined(MacroUseLineInfo) then
FHiddenUsedUnits:=FHiddenUsedUnits+',lineinfo'
else if InitialValues.IsDefined(MacroUselnfodwrf) then
@ -2433,20 +2452,24 @@ end;
function TLinkScanner.ShortSwitchDirective: boolean;
// example: {$H+} or {$H+, R- comment}
var
c: Char;
begin
FDirectiveName:=CompilerSwitchesNames[FDirectiveName[1]];
c:=UpChars[FDirectiveName[1]];
FDirectiveName:=CompilerSwitchesNames[c];
if FDirectiveName<>'' then begin
if (SrcPos<=SrcLen) and (Src[SrcPos] in ['-','+']) then begin
if Src[SrcPos]='-' then
Values.Variables[FDirectiveName]:='0'
else
Values.Variables[FDirectiveName]:='1';
inc(SrcPos);
Result:=ReadNextSwitchDirective;
end else begin
if FDirectiveName<>CompilerSwitchesNames['I'] then
Result:=LongSwitchDirective
if c='I' then
Result:=IncludeDirective
else
Result:=IncludeDirective;
Result:=LongSwitchDirective;
end;
end else
Result:=true;
@ -2468,17 +2491,17 @@ begin
case UpChars[p^] of
'A':
case UpChars[p[1]] of
'L': if CompareIdentifiers(p,'ALIGN')=0 then Result:=true;
'S': if CompareIdentifiers(p,'ASSERTIONS')=0 then Result:=true;
'L': if CompareIdentifiers(p,'ALIGN')=0 then Result:=LongSwitchDirective;
'S': if CompareIdentifiers(p,'ASSERTIONS')=0 then Result:=LongSwitchDirective;
end;
'B':
if CompareIdentifiers(p,'BOOLEVAL')=0 then Result:=true;
if CompareIdentifiers(p,'BOOLEVAL')=0 then Result:=LongSwitchDirective;
'D':
case UpChars[p[1]] of
'E':
case UpChars[p[2]] of
'F': if CompareIdentifiers(p,'DEFINE')=0 then Result:=DefineDirective;
'B': if CompareIdentifiers(p,'DEBUGINFO')=0 then Result:=true;
'B': if CompareIdentifiers(p,'DEBUGINFO')=0 then Result:=LongSwitchDirective;
end;
end;
'E':
@ -2498,7 +2521,7 @@ begin
if CompareIdentifiers(p,'ENDC')=0 then Result:=EndCDirective
else if CompareIdentifiers(p,'ENDIF')=0 then Result:=EndIfDirective;
'X':
if CompareIdentifiers(p,'EXTENDEDSYNTAX')=0 then Result:=true;
if CompareIdentifiers(p,'EXTENDEDSYNTAX')=0 then Result:=LongSwitchDirective;
end;
'I':
case UpChars[p[1]] of
@ -2514,36 +2537,36 @@ begin
'N':
if CompareIdentifiers(p,'INCLUDE')=0 then Result:=IncludeDirective
else if CompareIdentifiers(p,'INCLUDEPATH')=0 then Result:=IncludePathDirective;
'O': if CompareIdentifiers(p,'IOCHECKS')=0 then Result:=true;
'O': if CompareIdentifiers(p,'IOCHECKS')=0 then Result:=LongSwitchDirective;
end;
'L':
if CompareIdentifiers(p,'LOCALSYMBOLS')=0 then Result:=true
else if CompareIdentifiers(p,'LONGSTRINGS')=0 then Result:=true;
if CompareIdentifiers(p,'LOCALSYMBOLS')=0 then Result:=LongSwitchDirective
else if CompareIdentifiers(p,'LONGSTRINGS')=0 then Result:=LongSwitchDirective;
'M':
if CompareIdentifiers(p,'MODE')=0 then Result:=ModeDirective
else if CompareIdentifiers(p,'MODESWITCH')=0 then Result:=ModeSwitchDirective
else if CompareIdentifiers(p,'MACRO')=0 then Result:=MacroDirective;
'O':
if CompareIdentifiers(p,'OPENSTRINGS')=0 then Result:=true
else if CompareIdentifiers(p,'OVERFLOWCHECKS')=0 then Result:=true;
if CompareIdentifiers(p,'OPENSTRINGS')=0 then Result:=LongSwitchDirective
else if CompareIdentifiers(p,'OVERFLOWCHECKS')=0 then Result:=LongSwitchDirective;
'R':
if CompareIdentifiers(p,'RANGECHECKS')=0 then Result:=true
else if CompareIdentifiers(p,'REFERENCEINFO')=0 then Result:=true;
if CompareIdentifiers(p,'RANGECHECKS')=0 then Result:=LongSwitchDirective
else if CompareIdentifiers(p,'REFERENCEINFO')=0 then Result:=LongSwitchDirective;
'S':
if CompareIdentifiers(p,'SETC')=0 then Result:=SetCDirective
else if CompareIdentifiers(p,'STACKFRAMES')=0 then Result:=true;
else if CompareIdentifiers(p,'STACKFRAMES')=0 then Result:=LongSwitchDirective;
'T':
if CompareIdentifiers(p,'THREADING')=0 then Result:=ThreadingDirective
else if CompareIdentifiers(p,'TYPEADDRESS')=0 then Result:=true
else if CompareIdentifiers(p,'TYPEINFO')=0 then Result:=true;
else if CompareIdentifiers(p,'TYPEADDRESS')=0 then Result:=LongSwitchDirective
else if CompareIdentifiers(p,'TYPEINFO')=0 then Result:=LongSwitchDirective;
'U':
if CompareIdentifiers(p,'UNDEF')=0 then Result:=UndefDirective;
'V':
if CompareIdentifiers(p,'VARSTRINGCHECKS')=0 then Result:=true;
if CompareIdentifiers(p,'VARSTRINGCHECKS')=0 then Result:=LongSwitchDirective;
end;
end;
end else begin
// skipping code, but still have to read if directives
// skipping code => read only IF directives
case UpChars[p^] of
'E':
case UpChars[p[1]] of
@ -2582,7 +2605,7 @@ function TLinkScanner.LongSwitchDirective: boolean;
// example: {$ASSERTIONS ON comment}
var ValStart: integer;
begin
SkipSpace;
ReadSpace;
ValStart:=SrcPos;
while (SrcPos<=SrcLen) and IsWordChar[Src[SrcPos]] do
inc(SrcPos);
@ -2594,9 +2617,9 @@ begin
and (FDirectiveName='ASSERTIONS') then
Values.Variables[FDirectiveName]:='PRELOAD'
else if (FDirectiveName='LOCALSYMBOLS') then
// ignore link object directive
// ignore "localsymbols <something>"
else if (FDirectiveName='RANGECHECKS') then
// ignore link object directive
// ignore "rangechecks <something>"
else if (FDirectiveName='ALIGN') then
// set record align size
else begin
@ -2610,7 +2633,7 @@ function TLinkScanner.MacroDirective: boolean;
var
ValStart: LongInt;
begin
SkipSpace;
ReadSpace;
ValStart:=SrcPos;
while (SrcPos<=SrcLen) and (IsWordChar[Src[SrcPos]]) do
inc(SrcPos);
@ -2630,7 +2653,7 @@ var ValStart: integer;
AMode: TCompilerMode;
ModeValid: boolean;
begin
SkipSpace;
ReadSpace;
ValStart:=SrcPos;
while (SrcPos<=SrcLen) and (IsWordChar[Src[SrcPos]]) do
inc(SrcPos);
@ -2669,7 +2692,7 @@ var
ModeSwitch: TCompilerModeSwitch;
s: TCompilerModeSwitches;
begin
SkipSpace;
ReadSpace;
ValStart:=SrcPos;
while (SrcPos<=SrcLen) and (IsIdentChar[Src[SrcPos]]) do
inc(SrcPos);
@ -2696,7 +2719,7 @@ function TLinkScanner.ThreadingDirective: boolean;
var
ValStart: integer;
begin
SkipSpace;
ReadSpace;
ValStart:=SrcPos;
while (SrcPos<=SrcLen) and (IsWordChar[Src[SrcPos]]) do
inc(SrcPos);
@ -2713,7 +2736,7 @@ end;
function TLinkScanner.ReadNextSwitchDirective: boolean;
var DirStart, DirLen: integer;
begin
SkipSpace;
ReadSpace;
if (SrcPos<=SrcLen) and (Src[SrcPos]=',') then begin
inc(SrcPos);
DirStart:=SrcPos;
@ -2721,7 +2744,7 @@ begin
inc(SrcPos);
DirLen:=SrcPos-DirStart;
if DirLen>255 then DirLen:=255;
FDirectiveName:=UpperCaseStr(copy(Src,DirStart,DirLen));
FDirectiveName:=copy(Src,DirStart,DirLen);
Result:=DoDirective(DirStart,DirLen);
end else
Result:=true;
@ -2733,7 +2756,7 @@ var VariableName: string;
begin
inc(IfLevel);
if FSkippingDirectives<>lssdNone then exit(true);
SkipSpace;
ReadSpace;
VariableName:=ReadUpperIdentifier;
if (VariableName<>'') and (not Values.IsDefined(VariableName)) then
SkipTillEndifElse(lssdTillElse);
@ -2749,7 +2772,7 @@ begin
Result:=InternalIfDirective;
end;
procedure TLinkScanner.SkipSpace;
procedure TLinkScanner.ReadSpace;
begin
while (SrcPos<=SrcLen) and (IsSpaceChar[Src[SrcPos]]) do inc(SrcPos);
end;
@ -2791,7 +2814,7 @@ var VariableName: string;
begin
inc(IfLevel);
if FSkippingDirectives<>lssdNone then exit(true);
SkipSpace;
ReadSpace;
VariableName:=ReadUpperIdentifier;
if (VariableName<>'') and (Values.IsDefined(VariableName)) then
SkipTillEndifElse(lssdTillElse);
@ -2810,8 +2833,11 @@ begin
if IfLevel<=0 then
RaiseAWithoutB;
dec(IfLevel);
if IfLevel<FSkipIfLevel then begin
FSkippingDirectives:=lssdNone;
if (IfLevel<FSkipIfLevel) and (FSkippingDirectives<>lssdNone) then begin
{$IFDEF ShowUpdateCleanedSrc}
debugln(['TLinkScanner.EndifDirective end skip']);
{$ENDIF}
EndSkipping;
end;
Result:=true;
end;
@ -2829,8 +2855,11 @@ begin
if IfLevel<=0 then
RaiseAWithoutB;
dec(IfLevel);
if IfLevel<FSkipIfLevel then begin
FSkippingDirectives:=lssdNone;
if (IfLevel<FSkipIfLevel) and (FSkippingDirectives<>lssdNone) then begin
{$IFDEF ShowUpdateCleanedSrc}
debugln(['TLinkScanner.EndCDirective end skip']);
{$ENDIF}
EndSkipping;
end;
Result:=true;
end;
@ -2847,8 +2876,11 @@ begin
if IfLevel<=0 then
RaiseAWithoutB;
dec(IfLevel);
if IfLevel<FSkipIfLevel then begin
FSkippingDirectives:=lssdNone;
if (IfLevel<FSkipIfLevel) and (FSkippingDirectives<>lssdNone) then begin
{$IFDEF ShowUpdateCleanedSrc}
debugln(['TLinkScanner.IfEndDirective end skip']);
{$ENDIF}
EndSkipping;
end;
Result:=true;
end;
@ -2866,12 +2898,15 @@ begin
RaiseAWithoutB;
case FSkippingDirectives of
lssdNone:
// last block was executed, skip all other
SkipTillEndifElse(lssdTillEndIf);
lssdTillElse:
if IfLevel=FSkipIfLevel then
FSkippingDirectives:=lssdNone;
// else: continue skip;
lssdTillEndIf: ; // continue skip
if IfLevel=FSkipIfLevel then begin
{$IFDEF ShowUpdateCleanedSrc}
debugln(['TLinkScanner.ElseDirective skipped front, using ELSE part']);
{$ENDIF}
EndSkipping;
end;
end;
Result:=true;
end;
@ -2890,12 +2925,15 @@ begin
RaiseAWithoutB;
case FSkippingDirectives of
lssdNone:
// last block was executed, skip all other
SkipTillEndifElse(lssdTillEndIf);
lssdTillElse:
if IfLevel=FSkipIfLevel then
FSkippingDirectives:=lssdNone;
// else: continue skip;
lssdTillEndIf: ; // continue skip
if IfLevel=FSkipIfLevel then begin
{$IFDEF ShowUpdateCleanedSrc}
debugln(['TLinkScanner.ElseCDirective skipped front, using ELSEC part']);
{$ENDIF}
EndSkipping;
end;
end;
Result:=true;
end;
@ -2911,13 +2949,15 @@ function TLinkScanner.ElseIfDirective: boolean;
begin
if IfLevel=0 then
RaiseAWithoutB;
if (FSkippingDirectives=lssdTillElse) and (IfLevel=FSkipIfLevel) then begin
Result:=InternalIfDirective;
end else begin
if (FSkippingDirectives=lssdNone) then
SkipTillEndifElse(lssdTillEndIf);
Result:=true;
case FSkippingDirectives of
lssdNone:
// last block was executed, skip all other
SkipTillEndifElse(lssdTillEndIf);
lssdTillElse:
if IfLevel=FSkipIfLevel then
exit(InternalIfDirective);
end;
Result:=true;
end;
function TLinkScanner.ElIfCDirective: boolean;
@ -2932,13 +2972,15 @@ begin
//DebugLn(['TLinkScanner.ElIfCDirective FSkippingDirectives=',ord(FSkippingDirectives),' IfLevel=',IfLevel]);
if IfLevel=0 then
RaiseAWithoutB;
if (FSkippingDirectives=lssdTillElse) and (IfLevel=FSkipIfLevel) then begin
Result:=InternalIfDirective;
end else begin
if (FSkippingDirectives=lssdNone) then
SkipTillEndifElse(lssdTillEndIf);
Result:=true;
case FSkippingDirectives of
lssdNone:
// last block was executed, skip all other
SkipTillEndifElse(lssdTillEndIf);
lssdTillElse:
if IfLevel=FSkipIfLevel then
exit(InternalIfDirective);
end;
Result:=true;
end;
function TLinkScanner.DefineDirective: boolean;
@ -2946,17 +2988,17 @@ function TLinkScanner.DefineDirective: boolean;
var VariableName, NewValue: string;
NamePos: LongInt;
begin
SkipSpace;
ReadSpace;
NamePos:=SrcPos;
VariableName:=ReadUpperIdentifier;
if (VariableName<>'') then begin
SkipSpace;
ReadSpace;
if FMacrosOn and (SrcPos<SrcLen)
and (Src[SrcPos]=':') and (Src[SrcPos+1]='=')
then begin
// makro => store the value
inc(SrcPos,2);
SkipSpace;
ReadSpace;
NewValue:=copy(Src,SrcPos,CommentInnerEndPos-SrcPos);
if CompareIdentifiers(PChar(NewValue),'false')=0 then
NewValue:='0'
@ -2976,7 +3018,7 @@ function TLinkScanner.UndefDirective: boolean;
// {$undefine name}
var VariableName: string;
begin
SkipSpace;
ReadSpace;
VariableName:=ReadUpperIdentifier;
if (VariableName<>'') then
Values.Undefine(VariableName);
@ -2987,15 +3029,15 @@ function TLinkScanner.SetCDirective: boolean;
// {$setc name} or {$setc name:=value}
var VariableName, NewValue: string;
begin
SkipSpace;
ReadSpace;
VariableName:=ReadUpperIdentifier;
if (VariableName<>'') then begin
SkipSpace;
ReadSpace;
if FMacrosOn and (SrcPos<SrcLen)
and (Src[SrcPos]=':') and (Src[SrcPos+1]='=')
then begin
inc(SrcPos,2);
SkipSpace;
ReadSpace;
NewValue:=copy(Src,SrcPos,CommentInnerEndPos-SrcPos);
if CompareIdentifiers(PChar(NewValue),'false')=0 then
NewValue:='0'
@ -3016,7 +3058,23 @@ var IncFilename: string;
DynamicExtension: Boolean;
begin
inc(SrcPos);
if (Src[SrcPos]<>'%') then begin
if (Src[SrcPos]='%') then begin
// ToDo: insert string constant: %date%, %fpcversion%
UpdateCleanedSource(CommentStartPos-1);
// insert ''
if 2>length(FCleanedSrc)-CleanedLen then begin
// expand cleaned source string by at least 1024
SetLength(FCleanedSrc,length(FCleanedSrc)+1024);
end;
AddLink(1,nil,slkCompilerString);
inc(CleanedLen);
FCleanedSrc[CleanedLen]:='''';
inc(CleanedLen);
FCleanedSrc[CleanedLen]:='''';
// continue after directive
CopiedSrcPos:=CommentEndPos-1;
AddLink(CommentEndPos,Code);
end else begin
IncFilename:=Trim(copy(Src,SrcPos,CommentInnerEndPos-SrcPos));
if (IncFilename<>'') and (IncFilename[1]='''')
and (IncFilename[length(IncFilename)]='''') then
@ -3481,10 +3539,35 @@ begin
//DebugLn(['TLinkScanner.AddMacroSource END Token=',copy(Src,TokenStart,SrcPos-TokenStart)]);
end;
procedure TLinkScanner.AddSkipComment(IsStart: boolean);
begin
//DebugLn(['TLinkScanner.AddSkipComment InFront="',dbgstr(CleanedSrc,CleanedLen-12,13),'" isstart=',IsStart]);
// insert {#3 or #3}
if 2>length(FCleanedSrc)-CleanedLen then begin
// expand cleaned source string by at least 1024
SetLength(FCleanedSrc,length(FCleanedSrc)+1024);
end;
if IsStart then begin
AddLink(1,nil,slkSkipStart);
inc(CleanedLen);
FCleanedSrc[CleanedLen]:='{';
inc(CleanedLen);
FCleanedSrc[CleanedLen]:=#3;
end else begin
AddLink(1,nil,slkSkipEnd);
inc(CleanedLen);
FCleanedSrc[CleanedLen]:=#3;
inc(CleanedLen);
FCleanedSrc[CleanedLen]:='}';
end;
// SrcPos was not touched and still stands at the same position
//DebugLn(['TLinkScanner.AddSkipComment END']);
end;
function TLinkScanner.ReturnFromIncludeFile: boolean;
var OldPos: TSourceLink;
begin
if FSkippingDirectives=lssdNone then begin
if (SrcPos-1>CopiedSrcPos) then begin
{$IFDEF ShowUpdateCleanedSrc}
DebugLn('TLinkScanner.ReturnFromIncludeFile A UpdatePos=',DbgS(SrcPos-1));
{$ENDIF}
@ -3547,7 +3630,7 @@ end;
function TLinkScanner.DoSourceTypeToken: boolean;
// program, unit, library, package
// unit unit1;
// unit unit1 platform;
// unit a.b.unit1 platform;
// unit unit1 unimplemented;
begin
if ScannedRange<>lsrInit then exit(false);
@ -3653,10 +3736,11 @@ begin
SrcPos:=CommentEndPos;
{$IFDEF ShowUpdateCleanedSrc}
DebugLn('TLinkScanner.SkipTillEndifElse A UpdatePos=',DbgS(SrcPos-1),' Src=',DbgStr(copy(Src,SrcPos-15,15))+'|'+DbgStr(copy(Src,SrcPos,15)));
DebugLn('TLinkScanner.SkipTillEndifElse A UpdatePos=',DbgS(SrcPos-1),' Src=',DbgStr(Src,SrcPos-15,15)+'|'+DbgStr(Src,SrcPos,15));
{$ENDIF}
UpdateCleanedSource(SrcPos-1);
AddSkipComment(true);
// parse till $else, $elseif or $endif
FSkipIfLevel:=IfLevel;
if (SrcPos<=SrcLen) then begin
@ -3666,14 +3750,14 @@ begin
'{':
begin
SrcPos:=p-PChar(Src)+1;
SkipCurlyComment;
ReadCurlyComment;
if (FSkippingDirectives=lssdNone) or (SrcPos>SrcLen) then break;
p:=@Src[SrcPos];
end;
'/':
if p[1]='/' then begin
SrcPos:=p-PChar(Src)+1;
SkipLineComment;
ReadLineComment;
if (FSkippingDirectives=lssdNone) or (SrcPos>SrcLen) then break;
p:=@Src[SrcPos];
end else
@ -3681,7 +3765,7 @@ begin
'(':
if p[1]='*' then begin
SrcPos:=p-PChar(Src)+1;
SkipRoundComment;
ReadRoundComment;
if (FSkippingDirectives=lssdNone) or (SrcPos>SrcLen) then break;
p:=@Src[SrcPos];
end else
@ -3696,10 +3780,11 @@ begin
end;
#0:
begin
// FPC allows that corresponding IFDEF and ENDIF are in different files
SrcPos:=p-PChar(Src)+1;
if (SrcPos>SrcLen) then begin
if not ReturnFromIncludeFile then begin
CommentStartPos:=0;
CopiedSrcPos:=SrcLen+1;
break;
end;
p:=@Src[SrcPos];
@ -3711,10 +3796,6 @@ begin
end;
end;
SrcPos:=p-PChar(Src)+1;
end;
if CommentStartPos>0 then begin
CopiedSrcPos:=CommentStartPos-1;
AddLink(CommentStartPos,Code);
end else begin
CopiedSrcPos:=SrcLen+1;
end;
@ -3740,24 +3821,60 @@ begin
end;
function TLinkScanner.InternalIfDirective: boolean;
// {$if expression} or {$ifc expression} or indirectly called by {$elifc expression}
// {$if expression} or {$ifc expression}
// or indirectly called by {$elifc expression} or {$elseif expression}
procedure RaiseMissingExpr;
begin
RaiseException('missing expression');
end;
var
ExprResult: Boolean;
begin
//DebugLn(['TLinkScanner.InternalIfDirective FSkippingDirectives=',ord(FSkippingDirectives),' IfLevel=',IfLevel]);
inc(SrcPos);
if SrcPos>SrcLen then
RaiseMissingExpr;
ExprResult:=Values.EvalBoolean(@Src[SrcPos],CommentInnerEndPos-SrcPos);
Result:=true;
//DebugLn(['TLinkScanner.InternalIfDirective ExprResult=',ExprResult]);
if Values.ErrorPosition>=0 then begin
inc(SrcPos,Values.ErrorPosition);
RaiseException(Values.ErrorMsg)
end else if ExprResult then
FSkippingDirectives:=lssdNone
else
end else if ExprResult then begin
// expression evaluates to true => stop skipping and parse block
if FSkippingDirectives<>lssdNone then begin
{$IFDEF ShowUpdateCleanedSrc}
debugln(['TLinkScanner.InternalIfDirective skipped front, using ELIFC part']);
{$ENDIF}
EndSkipping;
end;
end else
// expression evaluates to false => skip this block
SkipTillEndifElse(lssdTillElse);
end;
procedure TLinkScanner.EndSkipping;
procedure ErrorNotSkipping;
begin
debugln(['ErrorNotSkipping internal error, please report this bug']);
CTDumpStack;
end;
begin
if FSkippingDirectives=lssdNone then begin
ErrorNotSkipping;
exit;
end;
FSkippingDirectives:=lssdNone;
UpdateCleanedSource(CommentStartPos-1);
AddSkipComment(false);
AddLink(CommentStartPos,Code);
FSkipIfLevel:=-1;
end;
function TLinkScanner.CursorToCleanPos(ACursorPos: integer; ACode: pointer;
out ACleanPos: integer): integer;
// 0=valid CleanPos

View File

@ -106,7 +106,6 @@ type
TBuildTreeFlag = (
btSetIgnoreErrorPos,
btKeepIgnoreErrorPos,
btLoadDirtySource,
btCursorPosOutAllowed
);
TBuildTreeFlags = set of TBuildTreeFlag;
@ -4877,8 +4876,6 @@ var
Node: TCodeTreeNode;
DeleteNode: TCodeTreeNode;
begin
DirtySrc.Free;
DirtySrc:=nil;
// update scanned code
if FLastScannerChangeStep=Scanner.ChangeStep then begin
if LastErrorValid then
@ -5134,10 +5131,6 @@ begin
CaretType:=CaretToCleanPos(CursorPos, CleanCursorPos);
if (CaretType=0) or (CaretType=-1) then begin
BuildSubTree(CleanCursorPos);
if (CaretType=-1) and (btLoadDirtySource in BuildTreeFlags) then begin
// cursor position lies in dead code (skipped code between IFDEF/ENDIF)
LoadDirtySource(CursorPos);
end;
exit;
end
else if (CaretType=-2) or (not (btCursorPosOutAllowed in BuildTreeFlags)) then

View File

@ -816,7 +816,7 @@ begin
dec(BaseDirLen);
if BaseDirLen=0 then exit;
//WriteLn('CreateRelativePath START ',copy(CmpBaseDirectory,1,BaseDirLen),' ',copy(CmpFilename,1,FileNameLength));
//DebugLn(['CreateRelativePath START ',copy(CmpBaseDirectory,1,BaseDirLen),' ',copy(CmpFilename,1,FileNameLength)]);
// count shared directories
p:=1;