Conditional expressions and related command-line options (--define, --conditionals)
1. Introduction
Pascal allows for directives in the source code. These look similar to comments and they contain commands for the compiler to do something special, like conditionaly ignore (or not ignore) a piece of following Pascal code.
An example:
type
TProcess = class
public
property CommandLine: TStrings read GetCommandLine;
procedure Run;
{$ifdef MSWINDOWS}
property Handle: TWindowHandle read GetHandle;
{$endif}
{$ifdef UNIX}
property StdIn: TUnixHandle read GetStdIn write SetStdIn;
property StdOut: TUnixHandle read GetStdOut write SetStdOut;
property StdErr: TUnixHandle read GetStdErr write SetStdErr;
{$endif}
end;
Just like a compiler, PasDoc understands various directives when it parses Pascal code:
-
$ifdef,$if,$ifopt(and friends:$else,$endif,$ifend) - to conditionally use or ignore a piece of code. -
$define,$undef- to define or undefine a symbol that can be used in$if defined(SYMBOL)/$ifdefexpressions. -
$include(short form$I) to include another file.
In contrast to a Pascal compiler, PasDoc starts with an empty list of conditional directives. For example, we don’t automatically define MSWINDOWS, even when you run PasDoc on Windows. The reason for this is that you usually want to generate one documentation that makes sense for all operating systems, all compiler versions and so on. It’s up to you to decide which symbols should be defined to achieve this.
You can tell PasDoc to have some symbol defined using the --define and --conditionals
CommandLine options described below.
2. --define command-line option
--define SYMBOL (short form is -D SYMBOL) adds SYMBOL to the list of defined symbols. In effect, in Pascal code, {$ifdef SYMBOL} and (equivalent) {$if defined(SYMBOL)} will be considered true.
You can specify multiple symbols separated by a comma:
pasdoc --define DEBUG,FPC,MSWINDOWS myunit.pas
This defines three conditionals: DEBUG, FPC and MSWINDOWS.
You can also just use --define SYMBOL multiple times, like this:
pasdoc --define DEBUG --define FPC --define MSWINDOWS myunit.pas
3. --define command-line option with := to define a symbol with a value
You can use the assignment operator to define a symbol with a value, like this:
pasdoc --define FPC_FULLVERSION:=30202 --define LCL_FULLVERSION:=2020401 myunit.pas
This makes the given symbol behave like a macro, that expands to the given value, both during normal Pascal code parsing and during conditional expression evaluation in $if / $elseif.
This is useful to:
-
Define values for useful symbols used in conditional expressions, like:
-
Special FPC
FPC_FULLVERSIONsymbol (available only in conditional expressions in FPC, though in PasDoc it will be also expanded during normal Pascal code parsing) -
LCL_FULLVERSIONdefined in LazarusLCLVersionunit -
CompilerVersion constant from Delphi.
-
-
Or to define FPC macros values at command-line.
4. --conditionals command-line option
--conditionals SYMBOLS-FILE option (short form
-d SYMBOLS-FILE) adds the symbols specified in a file
SYMBOLS-FILE to the list of conditional symbols defined. The file must contain one
symbol per line, without any comments.
Examples:
pasdoc --conditionals c:\sources\myconditionals.txt pasdoc --conditionals /home/me/pascal/myconditionals.txt
where the myconditionals.txt file may contain, for example:
DEBUG FPC MSWINDOWS
5. Define symbols to make the code valid for PasDoc
When you use conditional directives in your code, make sure that the combination of symbols you define for PasDoc results in code that can be parsed by PasDoc. For example, if you have something like this:
const NewLine =
{$ifdef MSWINDOWS} #13#10 {$endif}
{$ifdef UNIX} #10 {$endif};
By default PasDoc defines neither MSWINDOWS nor UNIX, so it will consider them both undefined. Thus PasDoc will "see" (and fail to parse) a code like this:
const NewLine = ;
You have to make sure that the combination of symbols used by PasDoc makes sense, i.e. results in code that can be parsed. Sometimes the right solution is to introduce a special variant, used only when parsing with PasDoc:
const NewLine =
{$ifdef PASDOC}
'The value of this constant depends on the operating system'
{$else}
{$ifdef MSWINDOWS} #13#10 {$endif}
{$ifdef UNIX} #10 {$endif}
{$endif};
Make sure to execute PasDoc with command-line option -define PASDOC to make it work.
6. Support for $if expressions
The $if directive allows to evaluate an expression, like
{$if defined(MSWINDOWS) and not defined(FPC)}
const CompilerInfo = 'Delphi on Windows';
{$endif}
Most of $if features supported by compilers (like FPC or Delphi) are supported. This includes:
-
Functions
defined(SYMBOL),undefined(SYMBOL),option(R+) -
Constants
false,true -
Composing the expression using
and,or,not,xoroperations -
Comparing (Booleans and Integers) using
= -
Addition, multiplication operatoers.
Some expressions remain not supported, ultimately because PasDoc is not a compiler (so we don’t have the knowledge about the units you used, like RTL; and we don’t decide what are OS / CPU parameters). We don’t support:
-
declared(…) -
SizeOf(…)
The solution is to use a special symbol, like PASDOC, to make sure that the expression is valid for PasDoc. For example:
const
{ Integer of the same size as Pointer.
@deprecated Use NativeUInt (Delphi) or PtrUInt (FPC). }
MyPointerInt =
{$if defined(PASDOC)}
UIntSystemDependent
{$elseif SizeOf(Pointer) = 8}
UInt64
{$else}
UInt32
{$endif};