📄 uconditionalparser.pas
字号:
if not Assigned(TheDefines) then
TheDefines := FThisFile.Defines;
Parser := TTokenParser.Create; //parser for the expression
try
Parser.PascalDialect := PascalDialect;
Position := AbsoluteLastTokenStartPos; //parser the expression
Parser.ParseString(Expression, Position.Row, Position.Column);
NextToken := '';
ParseExpression(NextToken, pAll, Value); //evaluate the expression
finally
Parser.Free;
end;
if NextToken <> '' then
ExceptionFmt(etPreCompiler,
'Unexpected token in condition after "$IF" or "$ELSEIF": "%s"!',
[NextToken]);
if Value.kind = vkNone then
ExceptionFmt(etPreCompiler,
'Invalid condition after "$IF" or "$ELSEIF": "%s"!',
[Expression]);
//return the boolean value of the expression (if possible)
Result := ((Value.kind = vkBoolean) and (Value.bool)) or
((Value.kind = vkNumber) and (Value.num <> 0));
end;
{Checks if the Extended Syntax is enabled at the moment.
~result if the Extended Syntax is enabled currently }
function TConditionalParser.IsExtendedSyntaxEnabled: Boolean;
begin
if Assigned(FIncludedFile) then //includes a file?
//use setting of the included file
Result := FIncludedFile.IsExtendedSyntaxEnabled
else
if Assigned(FDefinesIncluded) then //is included?
Result := FDefinesIncluded.Options['X'] //use state of the parser
else
Result := inherited IsExtendedSyntaxEnabled; //return setting of file
end;
{Returns the next token (after the current position).
~param Token returns the found token or '' if no token could be found
~result if a token could be found }
function TConditionalParser.DoGetToken(var Token: String): Boolean;
{Gets the next token in this file (not in an included one). }
procedure GetNextToken;
var FromIncluded :Boolean; //whether token was read from included file
begin
FromIncluded := False;
Result := DoDoGetToken(Token); //get the token
while Result and (Token <> '') and //it is a comment for the compiler?
((Token[1] = '{') or
((Length(Token) >= 2) and (Token[1] = '(') and (Token[2] = '*'))) do
begin
if Token[1] = '{' then //delete comment braces
Token := Copy(Token, 3, Length(Token) - 3)
else
Token := Copy(Token, 4, Length(Token) - 5);
FromIncluded := HandleCompilerOption(Token); //handle the compiler option
if FromIncluded then //new included file?
Result := DoGetToken(Token) //get token in included file
else
Result := DoDoGetToken(Token); //get the next token
end;
if Result and not FromIncluded and not Assigned(FIncludedByFile) then
begin
FThisFile.Statistic.Increment(pfsTokens);
FThisFile.Statistic.Increment(pfsTokensNotIncluded);
end;
end;
var TokenPosition :TTokenPosition; //effective position of the token
begin
if Assigned(FIncludedFile) then //currently reading an included file?
begin
try
Result := FIncludedFile.GetToken(Token); //get token in $INCLUDEd file
if Result and not Assigned(FIncludedByFile) then
FThisFile.Statistic.Increment(pfsTokens);
except
if ExceptObject is EParseException then //in case of an exception
with EParseException(ExceptObject) do //change file data to this
begin
Message := Format('In $INCLUDEd file %s %d:%d:' + LineDelimiter,
[ExtractFileName(FIncludedFile.ThisFile.FilePath),
ErrorPosition.Row, ErrorPosition.Column]) + Message;
TheFile := Self.FThisFile;
ErrorPosition := AbsoluteLastTokenStartPos; //position of the $INCLUDE
end;
raise;
end;
if Result then //a token was read from the included file?
begin
//read its effective position and set it
TokenPosition := FIncludedFile.GetLastTokenPositions;
SetEffectivePositionOfLastToken(TokenPosition.FEffectiveFile,
TokenPosition.FEffectivePosition);
end
else //token not found/end of file
begin
//change the changed compiler options also in the including file
if Assigned(FDefinesIncluded) then //is in turn included?
begin //change local defines
FDefinesIncluded.Options := FIncludedFile.FDefinesIncluded.Options;
FDefinesIncluded.Defines.Assign(FIncludedFile.FDefinesIncluded.Defines);
end
else
begin //change defines of files
FThisFile.Defines.Options := FIncludedFile.FDefinesIncluded.Options;
FThisFile.Defines.Defines.Assign(FIncludedFile.FDefinesIncluded.
Defines);
end;
try
FIncludedFile.Free; //free included file
finally
FIncludedFile := nil; //no file included currently
end;
GetNextToken; //get the next token
end;
end //if assigned(FIncludedFile)
else
GetNextToken; //just get the next token
end;
{Initializes an Parser-Exception-Object before it gets raised. Adds position in
the including file to the exception object.
~param ExcpObj the exception object to be initialized
~result ExcpObj after the initialization }
function TConditionalParser.InitExceptionObject(ExcpObj: Exception): Exception;
var Included :TConditionalParser; //counter through included files
// LastPos :TPosition; //position in included file
begin
Result := inherited InitExceptionObject(ExcpObj);
{
Included := FIncludedFile;
while Assigned(Included) do //while another file included
begin
LastPos := Included.AbsoluteLastTokenStartPos; //get current position in it
//and add it
Result.Message := Format('In $INCLUDEd file %s %d:%d:' + LineDelimiter +
'...',
[ExtractFileName(Included.ThisFile.FilePath),
LastPos.Row, LastPos.Column]) +
Result.Message;
Included := Included.CurrentlyIncludedFile; //get file included by this one
end;
Included := FIncludedByFile;
while Assigned(Included) do //while included by another file
begin
LastPos := Included.AbsoluteLastTokenStartPos; //get current position in it
//and add it
Result.Message := Format('$INCLUDEd by file %s %d:%d:' + LineDelimiter +
'...',
[ExtractFileName(Included.ThisFile.FilePath),
LastPos.Row, LastPos.Column]) +
Result.Message;
Included := Included.IncludedByFile; //get the file including this one
end;
}
if Result is EParseException then //extended information?
begin
Included := Self;
//get included file currently reading tokens from
while Assigned(Included.FIncludedFile) do
Included := Included.FIncludedFile;
//set file and position of the error
EParseException(Result).EffectiveFile := Included.ThisFile;
EParseException(Result).EffectiveErrorPosition :=
Included.AbsoluteLastTokenStartPos;
if Assigned(FIncludedByFile) then //included by other files?
begin
Included := GetMainParser; //get the original including file
//set file and position of the original, first including file
EParseException(Result).TheFile := Included.ThisFile;
EParseException(Result).ErrorPosition :=
Included.AbsoluteLastTokenStartPos;
end;
end;
end;
{Handles a compiler option (if it understands it).
~param Command the compiler command in the comment
~result if a file was included }
function TConditionalParser.HandleCompilerOption(Command: String): Boolean;
//Gets the next compiler command, skipping everything until it is found.
function GetNextSkipCommand(var Params: String): String; forward;
{Skips everything after an $IFDEF, $IFNDEF or $IFOPT up to and including the
$ENDIF. }
procedure SkipIfDef; forward;
{Skips everything after an $IF up to and including the $IFEND. }
procedure SkipIf; forward;
{Skips everything up to and including the next $ELSE, $ELSEIF, $ENDIF or
$IFEND. Checks if it is valid with the stack. }
function Skip(var Params: String): TConditionalCompilingCommand; forward;
//Parses a compiler command/the first line of a compiler comment.
procedure ParseOption(var Line: String); forward;
{Gets the next compiler command, skipping everything until it is found. Nested
command blocks are recognized and skipped completely.
~param Params out: the parameters of the command
~result the next compiler command }
function GetNextSkipCommand(var Params: String): String;
var IsDirective :Boolean; //if new token is a compiler directive
i :Integer; //end of the command in the comment
Finish :Boolean; //if the command has been found
begin
Result := '';
repeat //as long as not finished
repeat //as long as no compiler command found
if not DoDoGetToken(Result) then //get a token
Exception(etPreCompiler,
'Unexpected end while searching for "$ENDIF"/"$IFEND"!');
Assert(Result <> '');
IsDirective := (Result[1] = '{') or //is a compiler command?
((Length(Result) >= 2) and
(Result[1] = '(') and (Result[2] = '*'));
if not IsDirective then //not a compiler command
begin //update the statistic
if not assigned(FIncludedByFile) then //this is the main parser?
FThisFile.Statistic.Increment(pfsSkippedTokensNotIncluded);
GetMainParser.ThisFile.Statistic.Increment(pfsSkippedTokens);
end;
until IsDirective; //until token is a compiler command
//delete comment-signs and "$"
if Result[1] = '{' then
Result := Copy(Result, 3, Length(Result) - 3)
else
Result := Copy(Result, 4, Length(Result) - 5);
i := Pos(' ', Result); //extract command
if i <> 0 then
begin
Params := Copy(Result, i + 1, High(Length(Result)));
Result := Copy(Result, 1, i - 1)
end
else
Params := '';
Result := LowerCase(Result);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -