📄 uconditionalparser.pas
字号:
begin
if FConditionalCompiling.Count = 0 then
Exception(etPreCompiler, '"$ELSE" without "$IFxxx" found!');
ValidCmds := FConditionalCompiling.Last;
if not (cccelse in ValidCmds) then
Exception(etPreCompiler, '"$ELSE" after another "$ELSE" found!');
//$ELSE and $ELSEIF not allowed anymore
ValidCmds := ValidCmds - [cccelse, cccelseif];
FConditionalCompiling.Pop;
FConditionalCompiling.Add(ValidCmds);
Skip(Command); //now just skip "body" in ELSE-part
FConditionalCompiling.Pop;
end
else
//end of conditional compiling command found?
if Cmd = 'endif' then
begin
if FConditionalCompiling.Count = 0 then
Exception(etPreCompiler, '"$ENDIF" without "$IFxxx" found!');
if not (cccendif in FConditionalCompiling.Last) then
Exception(etPreCompiler,
'"$ENDIF" (instead of "$IFEND") after "$IF" found!');
FConditionalCompiling.Pop; //just remove the command
end
else
//new conditional compiling command found?
if (Cmd = 'ifdef') or (Cmd = 'ifndef') or (Cmd = 'ifopt') then
begin //conditional compiling
if FirstParam = '' then
Exception(etPreCompiler, 'Parameter for "$IFxxx" missing!');
if (Cmd[3] = 'o') then //$IFOPT found?
begin
if (Length(FirstParam) <> 2) or
not (FirstParam[1] in ['A'..'Z', 'a'..'z']) or
not (FirstParam[2] in ['+', '-']) then
Exception(etPreCompiler,
'Character and "+" or "-" after $IFOPT expected, failed!');
//delete text if compiler switch differs from the +/-
SkipBody := TheDefines.Options[UpCase(FirstParam[1])] <>
(FirstParam[2] = '+');
end
else //delete text if symbol not defined xor $define
SkipBody := (TheDefines.Defines.IndexOf(FirstParam) <> -1) <>
(Cmd[3] = 'd');
//add conditional compiling command
FConditionalCompiling.Add([cccelse, cccelseif, cccifend, cccendif]);
if SkipBody then //"body" should be skipped?
begin
repeat
CmdFound := Skip(Command); //get next conditional command
until (CmdFound <> cccelseif) or //until part not to skip found
GetConditionalCompilingDecision(Command);
if CmdFound <> cccelseif then //not just another part?
begin
FConditionalCompiling.Pop; //remove conditional command
if CmdFound = cccelse then //if only $ELSE
//add it again without $ELSE
FConditionalCompiling.Add([cccifend, cccendif])
else
Assert((CmdFound = cccendif) or (CmdFound = cccifend));
end;
end;
end
else
//end of conditional compiling command found?
if Cmd = 'ifend' then
begin
if FConditionalCompiling.Count = 0 then
Exception(etPreCompiler, '"$IFEND" without "$IF" found!');
if not (cccifend in FConditionalCompiling.Last) then
Exception(etPreCompiler,
'"$IFEND" (instead of "$ENDIF") after "$IFxxx" found!');
FConditionalCompiling.Pop; //just remove the command
end
else
//new conditional compiling command found?
if (Cmd = 'if') or (Cmd = 'elseif') then
begin
if FirstParam = '' then
ExceptionFmt(etPreCompiler,
'Parameter for "$%s" missing!', [UpperCase(Cmd)]);
if Cmd[1] <> 'i' then //$ELSEIF ?
begin
if FConditionalCompiling.Count = 0 then
Exception(etPreCompiler, '"$ELSEIF" without "$IF" found!');
if not (cccelse in FConditionalCompiling.Last) then
Exception(etPreCompiler,
'"$ELSEIF" without "$IF" or after "$ELSE" found!');
end
else //$IF => add conditional compiling command
FConditionalCompiling.Add([cccelse, cccelseif, cccifend, cccendif]);
//is expression not true?
if not GetConditionalCompilingDecision(Command) then
begin
repeat
CmdFound := Skip(Command); //skip "body"
until (CmdFound <> cccelseif) or //until end or true part reached
GetConditionalCompilingDecision(Command);
if CmdFound <> cccelseif then //not just another part
begin
FConditionalCompiling.Pop; //remove conditional command
if CmdFound = cccelse then //if it is $ELSE
//add again without $ELSE
FConditionalCompiling.Add([cccifend, cccendif])
else
Assert((CmdFound = cccifend) or (CmdFound = cccendif));
end;
end;
end
else
//inclusion of another file found?
if (Cmd = 'include') or (Cmd = 'i') then
Result := HandleInclude(FirstParam) //include it
else
//compiler message found?
if Cmd = 'message' then //just generate a message
WarningMessage(etPreCompiler, 'Compiler-$Message: ' + Command);
(* {$MESSAGE 'Boo!'} -> HINT
{$Message Hint 'Feed the cat.'} -> HINT
{$messaGe Warn 'Looks like rain.'} -> WARNING
{$Message Error 'not implemented'} -> ERROR
{$Message Fatal 'dead'} -> FATAL *)
{
I = INCLUDE
L = LINK
M = MINSTACKSIZE/MAXSTACKSIZE
R = RESOURCE
$C PRELOAD = ?????????
}
{cpp:
HPPEMIT
NOINCLUDE
EXTERNALSYM
}
end; //if Command <> ''
end;
{Handles the inclusion of a file.
~param FileName the name of the file to include
~result if a file was included }
function TConditionalParser.HandleInclude(FileName: String): Boolean;
var Parser :TConditionalParser; //original file
FilePath :String; //absolut path of file
i :Integer; //counter through search paths
begin
Assert(not Assigned(FIncludedFile));
//'.pas' (or '.PAS' ???) may be automatically appended
if ExtractFileExt(FileName) = '' then
FileName := FileName + '.PAS'; //'.pas' ???? correct ????
{ $INCLUDE search paths:
1. current (file) path (original file, not included?)
2. project path
3. project search paths
4. delphi search paths }
Parser := GetMainParser; //search original parser
if IsAbsolutePath(FileName) then //path to included file is absolute?
FilePath := FileName //just use it
else
begin
//search in path of original file
FilePath := GetAbsolutePathRelative(
ExtractFilePath(Parser.ThisFile.FilePath), FileName);
{
if Assigned(Parser.ProjectFile) and not FileExists(FilePath) then
FilePath := GetAbsolutePathRelative(ExtractFilePath(Parser.ProjectFile.
FilePath),
FileName);
}
//if not found so far and search paths available
if not FileExists(FilePath) and
(Parser.ThisFile.Defines.SearchPath.Count > 0) then
begin
i := 0; //try with all search-paths ...
repeat //get file in the path
FilePath := ExtractShortPathName(ExpandFileName(
GetAbsolutePathRelative(
ExtractFilePath(Parser.ThisFile.Defines.SearchPath[i]),
FileName)));
Inc(i);
//until every path tried or file found
until (i = Parser.ThisFile.Defines.SearchPath.Count) or
FileExists(FilePath);
end;
//if not found search in path of current file (Delphi 4 does not do this)
if (Parser <> Self) and not FileExists(FilePath) then
FilePath := GetAbsolutePathRelative(ExtractFilePath(FThisFile.FilePath),
FileName);
end;
Result := FileExists(FilePath); //file found?
if not Result then
WarningMessageFmt(etPreCompiler,
'File "%s" to $INCLUDE not found!', [FileName])
else
begin
FilePath := ExtractShortPathName(FilePath);
Parser := Self; //check if already including
while Assigned(Parser) and (Parser.ThisFile.FilePath <> FilePath) do
Parser := Parser.IncludedByFile;
if Assigned(Parser) then //already including this file?
WarningMessageFmt(etPreCompiler,
'Recursive inclusion of file "%s", ignored!', [FilePath])
else
begin
Parser := GetMainParser; //search original parser again
//check if file was already parsed as a file by its own
if Assigned(Parser.ThisFile.FileList.GetFileAbsolute(FilePath)) then
WarningMessage(etPreCompiler,
'Included file was already read as a normal file, this is probably an error!: ' +
FilePath);
try
//read INCLUDEd file and create parser for the included file
FIncludedFile := TConditionalParser.Create(
Parser.ThisFile.FileList.IncludeFile(FilePath,
FileName));
FIncludedFile.ThisFile.Parser := nil; //don't need reference on parser
FIncludedFile.IncludedByFile := Self;
FIncludedFile.PascalDialect := PascalDialect;
if FIncludedFile.ThisFile.InternalFileName = '' then
FIncludedFile.ThisFile.InternalFileName := '$I ' +
ExtractFileName(FileName);
//create a copy of the defines - use same compiler defines
FIncludedFile.FDefinesIncluded := TDefines.Create;
if Assigned(FDefinesIncluded) then
FIncludedFile.FDefinesIncluded.CopyOptions(FDefinesIncluded)
else
FIncludedFile.FDefinesIncluded.CopyOptions(FThisFile.Defines);
// FIncludedFile.ThisFile.SetCompilerDefines(FThisFile.Defines, True);
//pre-parse it
FIncludedFile.SetContentToParse(FIncludedFile.ThisFile.Lines);
//increment statistics values of main file by values of included file
with GetMainParser.ThisFile.Statistic do
begin
IncrementBy(psfLines,
FIncludedFile.ThisFile.Statistic.Numbers[psfLines]);
IncrementBy(psfCharacters,
FIncludedFile.ThisFile.Statistic.Numbers[psfCharacters]);
IncrementBy(psfEmptyLines,
FIncludedFile.ThisFile.Statistic.Numbers[psfEmptyLines]);
IncrementBy(psfLinesWithComments,
FIncludedFile.ThisFile.Statistic.Numbers[
psfLinesWithComments]);
IncrementBy(psfLinesWithTokens,
FIncludedFile.ThisFile.Statistic.Numbers[
psfLinesWithTokens]);
end;
except
if ExceptObject is EParseException then
with EParseException(ExceptObject) do
begin
Message := Format('In $INCLUDEd file %s %d:%d (%s):' + LineDelimiter,
[FileName, ErrorPosition.Row, ErrorPosition.Column,
FilePath]) + Message;
TheFile := Self.FThisFile; //set data of this file
//position of the $INCLUDE
ErrorPosition := AbsoluteLastTokenStartPos;
end;
raise;
end;
end; //else assigned(Parser) //recursive inclusion
end; //else not Result
Parser := GetMainParser; //get main parser (again)
if Parser = Self then //this is the main parser?
FThisFile.Statistic.Increment(pfsIncludedFiles); //increment statistic
Parser.ThisFile.Statistic.Increment(pfsAllIncludedFiles); //ditto
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -