Porting Turbo Pascal to Free Pascal
This document contains some information about differences between Free Pascal and Turbo Pascal 7.0 (and to some extent Delphi). This list is not complete.
More documentation can be found in the WIKI , more Wiki, and the documentation.
Assembler
- The default assembler uses another syntax, but you can turn on the Intel styled assembler reader (which is what Turbo Pascal uses) using the -Rintel command line option or by adding {$asmmode intel} in your source.
- The 32 bit memory model requires a complete recoding of your assembler blocks in case you come from TP.
Run time library
- The swap(), lo() and hi() intrinsics are overloaded for all integer types, rather than that they always assume a 16 bit operand. So for a 32 bit type, swap will swap the lower and upper 16 bits, and similarly lo() resp. hi() will also return the lower resp. upper 16 bits rather than 8 bits
- To use the PORT array, add the Ports unit to you uses clause (only available under Dos/Go32v2 and Linux)
- You can access the realmode memory using MEM[seg:ofs], as well as MemW and MemL (only available under Dos/Go32v2)
- Ofs() returns a ptrint instead of a word
- The OVERLAY unit isn't available
- Turbo Vision support is provided by Free Vision; a clone because the original Turbo Vision is still not freely available (copyright not released by Borland)
Preprocessor/Syntax
- If you use the -So command line switch (or add {$mode TP}in your source), the compiler use its Turbo Pascal compatibility mode, which will disable several of FPC's advanced features (such as procedure overloading) to enable better compatibility with Turbo Pascal.
- Nested comments are allowed, but give a Warning when found (disabled in TP mode)
Syntax
- FAR and NEAR are ignored
- To get the address of a procedure to assign it to a procedure variable you must use the @-operator (in TP and Delphi mode, procedure variables work like in TP)
procedure p; begin end; var proc : procedure; begin proc:=@p; end;
Semantics
- Records are by default aligned to the size of a cpu word; use 'packed record' or {$PACKRECORDS 1} to get TP7 compatible records. A word of warning: use packed only if you absolutely need to, as non-alignment of fields may not work on non-Intel processors (and will slow down data access in all cases).
type r1=record a : byte; b : word; end; r2=packed record a : byte; b : word; end; begin writeln(sizeof(r1)); { outputs 4 } writeln(sizeof(r2)); { outputs 3 } end.
function a : longint; begin a:=12; while a>4 do begin {...} end; end;
function a : longint; begin a:=12; { v---- this is a recursive call } if a()>4 then begin {...} end; end;
function a : longint; begin a:=12; if a>4 then exit(a*67); end;
procedure x(v : longint);forward; procedure x; { this overloads the procedure x !!!!} begin { ... } end; { write instead: } procedure x(v : longint); begin { ... } end;
Others
- The command line parameters are different
- Not all compiler switches are fully implemented
- The units are not binary compatible
- The Overflow check also affects inc() and dec().
- The Range check not only checks array index for legal values, but also values to be in the possible range of variables. Thus if you need {$Q-} somewhere, you may need to add {$R-}.
- The search order for unit-directories and include-directories is reversed, it starts with the last directory. If you have two units with the same name, FreePascal may use a different one than TurboPascal does.
- The round function does not round up at 0.5, but to the nearest even number (although SetRoundMode can be used to control the behaviour somewhat)
- the dos unit Findfirst() call must always be followed by a Findclose to release some resource.