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

GPC on Mac OS X

INTEGER is 4 bytes long
LONGINT is 8 bytes long

One solution is to redefine them in GPC

    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

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

$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}
{$definec gpc False}

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:

  {$ifc defined __GPC__}
    UnivPtr = Pointer;
    UnivHandle = ^Pointer;
    UnivPtr = Ptr;
    UnivHandle = Handle;

Furthermore, GNU Pascal has completely untyped parameters, as in Borland Pascal.

8.    UCSD-Pascal strings

In GNU Pascal, you can define:

  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:

    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}

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)

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

    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}

This list doesn't claim to be complete (and in fact isn't).

(back to the GNU Pascal for Mac OS X page)