📄 uconditionalparser.pas
字号:
Finish := False; //assume not finished
if Result = 'if' then //"$IF" found?
SkipIf //skip this commands
else //older conditional commands found?
if (Result = 'ifdef') or (Result = 'ifndef') or (Result = 'ifopt') then
SkipIfDef //skip this command
else
Finish := True; //else finish and return command
until Finish; //as long as not finished
if not Assigned(FIncludedByFile) then //this is the main parser?
FThisFile.Statistic.Increment(pfsCompilerDirectivesNotIncluded);
GetMainParser.ThisFile.Statistic.Increment(pfsCompilerDirectives);
end;
{Skips everything after an $IFDEF, $IFNDEF or $IFOPT up to and including the
$ENDIF. }
procedure SkipIfDef;
var ElseFound :Boolean; //"$ELSE" already found
Command :String; //a compiler command
DummyParams :String; //parameters of the command
begin
ElseFound := False; //no else found so far
repeat
Command := GetNextSkipCommand(DummyParams); //get next command
if Command = 'else' then //"$ELSE" found?
begin
if ElseFound then //has already been found?
Exception(etPreCompiler, '"$ELSE" found after another "$ELSE"!');
ElseFound := True; //has been found!
end
else //invalid command?
if (Command = 'ifend') or (Command = 'elseif') then
ExceptionFmt(etPreCompiler,
'"$%s" found after "$IFDEF", "$IFNDEF" or "$IFOPT"!',
[UpperCase(Command)]);
until Command = 'endif'; //until the "$ENDIF" found
end;
{Skips everything after an $IF up to and including the $IFEND. }
procedure SkipIf;
var ElseFound :Boolean; //"$ELSE" already found
Command :String; //a compiler command
DummyParams :String; //parameters of the command
begin
ElseFound := False; //no else found so far
repeat
Command := GetNextSkipCommand(DummyParams); //get next command
if Command = 'elseif' then //"$ELSEIF" found?
begin
if ElseFound then //still allowed?
Exception(etPreCompiler, '"$ELSEIF" found after "$ELSE"!');
end
else
if Command = 'else' then //"$ELSE" found?
begin
if ElseFound then //not yet found?
Exception(etPreCompiler, '"$ELSE" found after another "$ELSE"!');
ElseFound := True; //now found
end
else
if Command = 'endif' then //"$ENDIF" not valid here???
Exception(etPreCompiler,
'"$ENDIF" (instead of "$IFEND") found after "$IF"!');
until Command = 'ifend'; //until the "$IFEND" found
end;
{Skips everything up to and including the next $ELSE, $ELSEIF, $ENDIF or
$IFEND. Checks if it is valid with the stack.
~param Params the parameters of the conditional compiling command
~result the conditional compiling command found }
function Skip(var Params: String): TConditionalCompilingCommand;
var Command :String; //the command
begin
repeat
Command := GetNextSkipCommand(Params); //get next command
if Command = 'endif' then //get kind of command
Result := cccendif
else
if Command = 'else' then
Result := cccelse
else
if Command = 'ifend' then
Result := cccifend
else
if Command = 'elseif' then
Result := cccelseif
else
Result := cccif; //dummy: end not reached
until Result <> cccif; //end reached?
if not (Result in FConditionalCompiling.Last) then //command here valid?
ExceptionFmt(etPreCompiler,
'"$%s" found, but not allowed here!', [UpperCase(Command)]);
end;
var TheDefines :TDefines; //the defines of the current file
{Parses a compiler command/the first line of a compiler comment. Only the
compiler switches are extracted and parsed.
~param Line the first line of a compiler comment after the $ }
procedure ParseOption(var Line: String);
var Option :String; //the option (the first identifier)
C :Char; //the compiler switch - character
//index in the list of long names of the compiler switch
Index :Integer;
begin
repeat //until C = #0 or Line = ''
Option := ''; //extract first option (identifier)
while (Line <> '') and (Line[1] in IdentifierChars) do
begin
Option := Option + Line[1];
Delete(Line, 1, 1);
end;
if Option <> '' then //no identifier/text found?
begin
if Length(Option) = 1 then //only one single char?
begin
C := Option[1]; //use this as compiler switch
if C in ['a'..'z'] then //and use the upper case letter
Dec(C, Ord('a') - Ord('A'));
end
else //search it as a long name for a compiler switch
if IsWordIn(Option, LongCompilerOptions, Index) then
C := ShortCompilerOptions[Index] //and use the compiler switch
else
C := #0; //if not found abort
case C of
#0: Line := Option + Line; //abort and reset Line
'A': if (Length(Option) > 1) and //alignment of types
(Option[1] in ['a', 'A']) and (Option[2] in ['0'..'9']) then
TheDefines.Option['A'] := Option[2] <> '1'
else
if (Line <> '') then
if Length(Option) = 1 then
begin
if (Length(Line) = 1) and (Line[1] in ['+', '-']) then
TheDefines.Option['A'] := Line[1] = '+';
end
else
if (UpperCase(Line) = ' ON') or (UpperCase(Line) = ' OFF') or
(Line = ' 1') or (Line = ' 2') or
(Line = ' 4') or (Line = ' 8') then
TheDefines.Option['A'] := (Line[3] = 'N') or
(Line[2] in ['2', '4', '8']);
'Y': if UpperCase(Option) = 'YD' then //gathering of references
TheDefines.Option['Y'] := True //"$YD" means also "$Y+"
else
if (Line <> '') then
if Length(Option) = 1 then
begin
if ((Length(Line) = 1) or (Line[2] = ',')) and
(Line[1] in ['+', '-']) then
begin
TheDefines.Option['Y'] := Line[1] = '+';
Delete(Line, 1, 1);
end;
end
else
if (UpperCase(Line) = ' ON') or (UpperCase(Line) = ' OFF') then
TheDefines.Option['Y'] := Line[3] = 'N';
'Z': if (Length(Option) > 1) and //size of enumeration types
(Option[1] in ['z', 'Z']) and (Option[2] in ['0'..'9']) then
//minimal enumerations?
TheDefines.Option['Z'] := Option[2] <> '1'
else
if (Line <> '') then
if Length(Option) = 1 then
begin
if ((Length(Line) = 1) or (Line[2] = ',')) and
(Line[1] in ['+', '-']) then
begin
TheDefines.Option['Z'] := Line[1] = '+';
Delete(Line, 1, 1);
end;
if (Length(Line) = 1) and (Line[1] in ['+', '-']) then
TheDefines.Option['Z'] := Line[1] = '+';
end
else
if (UpperCase(Line) = ' ON') or (UpperCase(Line) = ' OFF') or
(Line = ' 1') or (Line = ' 2') or (Line = ' 4') then
TheDefines.Option['Z'] := (Line[3] = 'N') or
(Line[2] in ['2', '4']);
else
if (C in ['A'..'Z']) and (Line <> '') and
(((Length(Option) = 1) and //short option?
((Length(Line) = 1) or (Line[2] = ',')) and
(Line[1] in ['+', '-'])) or
((Length(Option) > 1) and //long option?
(UpperCase(Line) = ' ON') or (UpperCase(Line) = ' OFF'))
) then
begin
if ((Length(Line) = 1) or (Line[2] = ',')) and //short option?
(Line[1] in ['+', '-']) then
begin //set compiler switch by +/-
TheDefines.Option[C] := Line[1] = '+';
Delete(Line, 1, 1);
end
else //set compiler switch by ON/OFF
if (UpperCase(Line) = ' ON') or (UpperCase(Line) = ' OFF') then
TheDefines.Option[C] := Line[3] = 'N';
end
else
begin
C := #0; //abort and
Line := Option + Line; //reset Line
end;
end;
if (Line <> '') and (Line[1] <> ',') then //no further options?
C := #0; //abort
end
else
C := #0; //no identifier => abort
until (C = #0) or (Line = ''); //abort or no other option left
end;
var Cmd :String; //the first command (identifier)
FirstParam :String; //the first parameter of the command
i :Integer; //general indices
//currently allowed conditional compiling commands
ValidCmds :TConditionalCompilingCommands;
//if the "body" of a conditional compiling command should be skipped
SkipBody :Boolean;
//the found conditional compiling command
CmdFound :TConditionalCompilingCommand;
begin
if not Assigned(FIncludedByFile) then //this is the main parser?
FThisFile.Statistic.Increment(pfsCompilerDirectivesNotIncluded);
GetMainParser.ThisFile.Statistic.Increment(pfsCompilerDirectives);
Result := False; //assume no file newly included
if Command <> '' then //command given?
begin
TheDefines := FDefinesIncluded; //get defines of the current file
if not Assigned(TheDefines) then
TheDefines := FThisFile.Defines;
ParseOption(Command); //try parsing the options
i := Pos(' ', Command); //extract command and first parameter
if i = 0 then //no parameters?
begin
Cmd := Command; //use whole line as command
Command := '';
end
else
begin
Cmd := Copy(Command, 1, i - 1); //extract command
Delete(Command, 1, i);
Command := Trim(Command);
FirstParam := Command;
if Command <> '' then //further parameters?
if Command[1] = '''' then //is a string (starting with "'")?
begin
Delete(FirstParam, 1, 1); //get string without "'"
i := Pos('''', FirstParam);
if i = 0 then
WarningMessage(etPreCompiler,
'Option to compiler-directive starting with "''" but no "''" following!')
else
Delete(FirstParam, i, High(Length(FirstParam)));
end
else
begin
i := Pos(' ', FirstParam); //search the first space
if i <> 0 then //delete it and anything following
Delete(FirstParam, i, High(Length(FirstParam)));
end;
end;
Cmd := LowerCase(Cmd);
//handle the command:
//simple compiler symbols to define or undefine?
if (Cmd = 'define') or (Cmd = 'undef') then
begin
if Command = '' then
Exception(etPreCompiler, 'Parameter for $define/$undef missing!');
//search compiler symbol
i := TheDefines.Defines.IndexOf(FirstParam);
if Cmd[1] = 'd' then //should be defined?
begin
if i < 0 then //if not already defined
TheDefines.Defines.Append(FirstParam); //define it
end
else
if i >= 0 then //if it is defined
TheDefines.Defines.Delete(i); //undefine it
end
else
//ELSE-part of conditional compiling command found?
if Cmd = 'else' then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -