Porting to GNU Pascal from traditional Macintosh Pascal
compilers.
GNU Pascal has a rich set of features,
that you will soon appreciate. Still, if you are porting from MPW Pascal, THINK
Pascal or MetroWerks CodeWarrior Pascal, some source code changes
will be necessary.
1. Size
of built-in integer types
In GPC on Mac OS X
INTEGER is 4 bytes long
LONGINT is 8 bytes long
One solution is to redefine them
in GPC
Type
Int16 = Integer
attribute ( size = 16);
Int32 = Integer
attribute ( size = 32);
Integer = Int16;
Longint = Int32;
A better solution is to replace Integer by Int16 and Longint by Int32, wherever binary
compatibility requires it.
2. Size of an unsigned
byte
Traditionally, Macintosh Pascal compilers set the size of an unsigned byte
or char to two bytes, except in packed records and packed arrays.
GPC breaks with this rather absurd tradition; the size
of an unsigned byte or char is one byte.
3. Size of a set
A set in GPC is internally a multiple of
4 bytes long.
4. Alignment directives
Replace $align mac68k by $maximum-field-alignment=16
and $align powerpc by $maximum-field-alignment=32.
Note that $align mac68K rounds the total size of composite data types
up to a multiple of 2 bytes, $maximum-field-alignment=16
doesn't.
For PowerPC code, GPC accepts
-malign-powerpc and -malign-natural, but only
as command-line options. For Intel code, -malign-double and -mno-align-double
can be passed.
5. Conditional
compiler directives
GPC supports Macintosh Pascal conditional
compiler directives: $ifc, $elsec,
$endc, $definec, $macro, $elifc,
$undefc, $errorc and $undefc. It doesn't have
the $setc directive.
Note that, unlike in MetroWerks Pascal,
macros do not extend unit boundaries !
If you maintain a common source code
base, you can test for GNU Pascal like this:
{$ifc defined __GPC__}
{$definec gpc True}
{$elsec}
{$definec gpc False}
{$endc}
Replace {$ifc undefined xxx} by {$ifc not defined xxx} or by {$ifndef
xxx}.
6. Other compiler
options
GPC features an impressive
number of compiler options, but they are, for the most part,
different from what you are used to. See the docs included
with the compiler (gpc.pdf and gpc.options.rtf).
Instead of $push and $pop, GPC has
$local and $endlocal, but currently they only work for
on/off switches and for the $maximum-field-alignment
directive, e.g.
{$local maximum-field-alignment=16}
Type ... {$endlocal}
7. Universal parameters
Unfortunately, the UNIV qualifier
is missing in GNU Pascal. However, GNU Pascal has a universal
pointer type Pointer. Be aware that in traditional Macintosh
Pascal Pointer is a function. For a common source code base
you can write something like this:
Type
{$ifc
defined __GPC__}
UnivPtr = Pointer;
UnivHandle = ^Pointer;
{$elsec}
UnivPtr = Ptr;
UnivHandle = Handle;
{$endc}
Furthermore, GNU Pascal has completely
untyped parameters, as in Borland Pascal.
8. UCSD-Pascal
strings
In GNU Pascal, you can define:
Type
Str255 = string[ 255] ....
... but internally GNU Pascal strings don't
match UCSD-Pascal strings, as used in UCSD Pascal and later
in Borland Pascal and in traditional Macintosh Pascal. In Macintosh
documentation, UCSD-Pascal strings are misnamed "Pascal strings".
UCSD-Pascal strings are on the to-do
list for the GPC compiler but as of today they are missing.
The Mac OS X Interfaces for GNU Pascal
show a way around this. Please study the source code of the GPCStrings/GPCStringsAll
unit and the Strxxx type definitions in the MacTypes unit.
When using the Strxxx type defintions in the MacTypes unit, be aware that
GPC always copies the whole pseudo-string record, not just assigned characters.
Therefore:
• use (fast) string const parameters rather than (slow) string value
parameters
• particularly, use const parameters when interfacing with C "pascal"
string parameters (as value parameters will crash)
• do not to write something like this (as it will obviously crash)
PStr := T_StrPtr( NewPtr( Str.sLength + 1));
if PStr <> nil then PStr^:= Str; {crash}
9. Object Pascal
GNU Pascal
implements several different objects models:
--gnu-objects (the GNU Pascal default
object model)
--ooe-objects (the Object Oriented Extensions
to Pascal draft object model)
--mac-objects (the object model of MPW
Pascal, Think Pascal and CodeWarrior Pascal (but pointer-based))
--borland-objects (the object models
of Turbo Pascal and Delphi)
To work with the object model
of traditional Macintosh Pascal compilers, pass
--mac-objects (which is the default in --mac-pascal mode). You can also
specify {$mac-objects} in source code (and use other object models in separate
parts of the source code).
The member function can be defined with a macro (in an include file)
{$definec member(a,b) ((a) is b)}
10. Mod-operator
The ISO Pascal standard requires that
(a) the result of i mod j is non-negative and (b) j
is positive. Unlike most other Pascal compilers, GNU Pascal follows that standard,
except for the language dialects --borland-pascal and --mac-pascal.
11. Trunc and
Round
In ISO Pascal Trunc is a predefined function
that returns an integer value. It is an error if the result value
of Trunc doesn't exist in the Integer type. The fp.pas unit
of Apple’s PInterfaces declares a trunc function that returns
a value of type Double_t.
To solve this ambivalence, the trunc function
in fp.pas has been renamed to truncd.
Same for the Round function.
12. External
symbols
For intricate reasons, in GNU Pascal
external routines must be declared external 'libname' name
'routinename'. The libname is optional and
currently ignored by the compiler.
procedure SysBeep; external name 'SysBeep';
Examples of declarations of external
variables and constants:
Var
qd: QDGlobals; external
name 'qd';
pi: double_t;
attribute (const); external name 'pi';
Internal Pascal routines that need a special name for external linking
can use attribute( name = xxx), e.g.
procedure PluginEntryPoint; attribute( name = 'PluginEntryPoint');
13. Line feeds
GPC expects UNIX Line Feeds in source
files instead of Macintosh Carriage Returns.
14. Filenames
• Don't use uppercase extensions .P and .PAS in filenames for Pascal
sources.
• Don't give C source files and Pascal source files the same basename
(e.g. stuff.p in the same project as stuff.c)
15. Case statements
CodeWarrior Pascal erroneously accepts a missing semicolon at the end
of the statements that form a case statement. In GPC, the semicolon is
obligatory.
case item of
1: proc1 {missing semicolon}
2: if found then proc2 {missing semicolon}
else proc3 {bug}
end;
The example shows how dangerous the bug in CodeWarrior Pascal is, when else is used in case-statements instead
of otherwise.
16.
Bxx routines
GPC doesn't have the Bxxx routines. They can be replaced by macros (in
an include file):
BAnd(i,j)=((i) and (j))
BOr(i,j)=((i) or (j))
BXOr(i,j)=((i) xor (j))
Bsr(i,n)=((i) shr (n))
Bsl(i,n)=((i) shl (n))
BTST(i,n)=((((i) shr (n)) and 1)=1)
BSet(i,n)=i:=(i) or (1 shl (n))
BClr(i,n)=i:=(i) and not (1 shl (n))
Before using them, please note that they don't behave exactly
as in CodeWarrior, MPW and THINK Pascal. The
following is not correctly handled by the macros
(taken from notes written by Gale Paeper):
• Zero filling less than 32-bit sized parameters to 32-bit size.
• 680x0 ISO mod shift field wrap arounds (680x0
shift fields have ISO Pascal mod 32 behavior and not MacPascal's mod remainder
32 behavior. Also, unlike GPC's bitwise operators, the 680x0
field value is mod 32'ed before shifting is performed).
• 680x0 zero left
filling for shr operations (GPC sign fills instead of zero fills).
• Bug/feature in the MPW Pascal compiler (and duplicated for blind backward
compatibility in CW/MW Pascal) where signed constants less than 32-bit size
(e.g., $FF) are sign filled instead of zero filled to 32-bit size by the
compiler. THINK Pascal implements the correct zero filled behavior for constants.
Furthermore, it may be necessary to disable range-checking locally when
using these macros (also see note 24, below).
{$local R-}
j:=Bsl( i,2)
{$endlocal}
17.
Ord4
GPC doesn't have Ord4. When converting a pointer to it’s address value,
use PtrCard (unsigned) or PtrInt (signed). Otherwise, use
Ord or a value type-cast.
18. Using a function result as actual var parameter.
CodeWarrior Pascal erroneously accepts a function result as actual parameter
where the formal parameter requires a var parameter. This bug is not reproduced
in GPC. Use const parameters where appropriate.
19. Hexadecimal constants
In GPC, hexadecimal
constants are always unsigned (unless the ‘minus’ token is used, of course).
In CodeWarrior Pascal,
some hexadecimal constants are signed, others are unsigned. This can lead
to very subtle application bugs !
Const {positive unless marked negative}
k1= $F;
k2= $FF;
k3= $FFF;
k4= $FFFF; {negative in CW
Pascal}
k5= $FFFFF;
k6= $FFFFFF;
k7= $FFFFFFF;
k8= $FFFFFFFF; {negative
in CW Pascal}
h1= $0F;
h2= $0FF;
h3= $0FFF;
h4= $0FFFF;
h5= $0FFFFF;
h6= $0FFFFFF;
h7= $0FFFFFFF;
h8= $0FFFFFFFF; {negative
in CW Pascal}
20. The @ address operator
In GPC, the @
operator is typed or untyped, dependent on the compiler switches --typed-address
or {$T+} and --no-typed-address or {$T-}. The compiler directives can be
used locally, e.g.
{$local T-} myCPB.ioNamePtr := @FSSpecRec.name; {$endlocal}
21. Operator precedence
GPC applies strict
operator precedence rules. In --mac-pascal and --borland-pascal modes only,
there is an exception for the unary – and + operators (as in CodeWarrior
Pascal)
i:= i + –1
i:= i + +1
are allowed in --mac-pascal
and --borland-pascal modes only. The correct syntax in other modes
is
i:= i + (–1)
i:= i + (+1)
or simply
i:= i –1
i:= i +1
22. Qualified identifiers
GPC implements
qualified identifiers, but the consequence is that a procedure and a unit
can not have the same name. Doing so will result in an error for the procedure
call "statement used as expression".
23. Recursive type definitions
In recursive
type definitions, GPC expects that the pointer type is declared first
Type
NodePtr = ^Node;
Node = record pLeft, pRight: NodePtr end;
24. Range checking
GPC implements
range-checking much stricter than traditional Macintosh Pascal compilers.
For example, a typecast from an unsigned to a signed integer (or vice-versa)
may cause a range-check error and the same is true for implicit type conversions
! So, it may be necessary to disable range-checking locally, e.g.
GetDateTime (a);
{$local R-}{range check
error on implicit SInt32/UInt32 conversion}
SetQDGlobalsRandomSeed(a);
{$endlocal}
This list doesn't claim to
be complete (and in fact isn't).
(back to the
GNU Pascal for Mac OS X page)