This chapter is intended to be a QuickStart guide for programmers who are familiar with Borland Pascal.
Throughout the manual, we talk of "Borland Pascal" or "BP" for short, to refer to Borland Pascal version 7 for Dos protected mode. Other versions of Borland Pascal and Turbo Pascall don't differ too much, but this one was the very last Dos version Borland has published, so in most if not all cases, you can safely substitute the version you're familiar with.
"Borland Pascal" and "Turbo Pascal" are registered trademarks of Inprise Corp./Borland Inc.
GNU Pascal (GPC) is compatible to version 7 of Borland Pascal (BP) to a large extent and comes with portable replacements of the BP standard units.
However, BP is a 16-bit compiler while GPC is a 32/64-bit compiler, so the size of the `Integer' type, for instance, is 16 bits in BP, but at least 32 bits in GPC. If a BP program has been designed with portability in mind from the ground up, it may work with GPC without any change. Programs which rely on byte order, on the internals or sizes of data types or which use unportable things like interrupts and assembler code, will need to be changed. The following section lists the possible problems with solutions.
The GPC Run Time System (RTS) is fairly complete, and you can use all libraries written for GNU C from GNU Pascal, so there is much less need to use unportable constructs than there was in BP. (For example, BP's Turbo Vision library uses assembler to call a local procedure through a pointer. With GPC you can do this in Pascal just as with global procedures.) Please do not throw away the advantage of full portability by sticking to those workarounds.
We have successfully ported real-world projects (with several 10000s of lines) from BP to GPC, so this is possible for you, too.
This sections lists the remaining incompatibilities of GPC to BP, and the problems you might encounter when porting BP programs from 16-bit Dos to other platforms, and gives solutions for them.
By incompatibilites we mean problems that can arise when trying to compile a valid BP program with GPC. Of course, there are many features in GPC that BP doesn't know, but we call them extensions unless they can break valid BP programs, so they are not mentioned here. The subsequent sections of the `Borland Pascal' chapter mention a number of useful extensions that you might want to know about but which will not break your BP code.
Some of the differences can be "overcome" by command-line switches. As a summary:
--borland-pascal -w --uses=System -D__BP_TYPE_SIZES__ --pack-struct -D__BP_RANDOM__ -D__BP_UNPORTABLE_ROUTINES__ -D__BP_PARAMSTR_0__
But please read the following notes, and don't use these switches indiscriminately when not necessary. There are reasons why they are not GPC's defaults.
GPC's internal string format (Extended Pascal string schema) is different from BP's. BP compatible short strings will be implemented in GPC soon, but in the meantime, you'll have to live with the difference. In general, GPC's format has many advantages (no length limit of 255 characters, constant and reference parameters always know about their capacity, etc.), but you will see differences if you:
GPC does not yet support qualified identifiers. They will be implemented soon. In the meantime, just don't use them, sorry. (In general, using the same global identifier in different units can easily be confusing, so it's not bad practice to avoid this, anyway.)
GPC's inline assembler is not compatible to BP's. It uses
AT&T syntax, supports a large variety of processors and works
together with GPC's optimizer. So, either convert your inline
assembly to AT&T syntax, or (usually better) to Pascal, or put it
into an external file which you can assemble with your favourite
(32 bit) assembler. A tutorial for using the GPC inline assembler is
available at
ftp://agnes.dida.physik.uni-essen.de/gnu-pascal/contrib/gpcasm.zip
Since many things you usually do with assembler in BP are provided by GPC's Run Time System (RTS), you will not need the inline assembler as often as in BP. (See section Portability hints.)
The same applies to BP's `inline' directive for hand-written machine code. GPC's `inline' directive works for Pascal routines (see section Miscellaneous), so you'll have to convert any hand-written machine code to Pascal (and thereby make it more readable, portable and easier to maintain while still getting the performance of inline code).
GPC supports `Move' and `FillChar', and they're fully BP compatible. However, some data structures have different internal formats which may become relevant when using these procedures. E.g., using `Move' on file variables does not work in GPC (there are reasons why assigning file variables with `:=' is not allowed in Pascal, and circumventing this restriction with `Move' is not a good idea). For other examples, see section String type, section Real type, and section Endianness assumptions.
GPC does not support BP's 6-byte `Real' type. It supports `Single', `Double' and `Extended' which, at least on the x86 and some other processors, are compatible to BP.
For BP's 6-byte `Real' type, GPC's `System' unit provides an emulation, called `BPReal', as well as conversion routines to GPC's `Real' type (which is the same as `Double'), called `RealToBPReal' and `BPRealToReal'. You'll probably only need them when reading or writing binary files containing values of the BP 6-byte real type. There are no operators (e.g., `+') available for `BPReal', but since GPC supports operator overloading, you could define them yourself (e.g., convert to `Real', do the operation, and convert back). Needless to say that this is very inefficient and should not be done for any serious computations. Better convert your data after reading them from the file and before writing them back, or simply convert your data files once (the other types are more efficient even with BP on any non-prehistoric processor, anyway).
A somewhat BP compatible Graph unit exists but is distributed separately due to its license. It is known to work under DJGPP and Linux/x86, under development under Mingw, and should work under any Unix system with X11 (but only tested on a few systems).
The OOP stuff (Turbo Vision etc.) is not yet completed, but work on several projects is underway. If you want information about the current status or access to development source, please contact the GPC mailing list.
The routines `Keep', `GetIntVec' and `SetIntVec' in the `Dos' unit do not even make sense on DJGPP (32 bit Dos extender). If your program uses these, it is either a low-level Dos utility for which porting to a 32 bit environment might cause bigger problems (because the internal issues of DPMI become relevant which are usually hidden by DJGPP), or it installs interrupt handlers which will have to be thought about more carefully because of things like locking memory, knowing about and handling the differences between real and protected mode interrupts, etc. For these kinds of things, we refer you to the DJGPP FAQ (see section `DJGPP FAQ' in the DJGPP FAQ).
The internal structure of file variables (`FileRec' and `TextRec' in BP's `Dos' unit and `TFileRec' and `TTextRec' in BP's `WinDos' unit) is different in GPC. However, as far as Text File Device Drivers (TFDDs) are concerned, GPC offers a more powerful mechanism. Please see the RTS reference (see section Pascal declarations for GPC's Run Time System), under `AssignTFDD'.
Those few routines in the `System' unit that deal with segmented pointers (e.g., `Ptr') are emulated in such a way that such ugly BP constructs like
PInteger (Ptr (Seg (a), Ofs (a) + 6 * SizeOf (Integer)))^ = 42
work in GPC, but they do not provide access to absolute memory addresses. Neither do `absolute' variables (which take a simple address in the program's address space in GPC, rather than a segmented address), and the `Mem' and `Port' arrays don't exist in GPC.
As a replacement for `Port' on x86 processors, you can use the routines provided in the `Ports' unit, section BP compatibility (partly): `Port', `PortW' arrays. If you want to access absolute memory addresses in the first megabyte under DJGPP, you can't do this with normal pointers because DJGPP programs run in a protected memory environment, unless you use a dirty trick called near pointer hack. Please see the DJGPP FAQ (see section `DJGPP FAQ' in the DJGPP FAQ) for this and for other ways.
For similar reasons, the variable `PrefixSeg' in the `System' unit is not supported. Apart from TSRs, its only meaningful use in BP might be the setting of environment variables. GPC provides the `SetEnv' and `UnSetEnv' procedures for this purpose which you can use instead of any BP equivalents based on `PrefixSeg'. (However note that they will modify the program's own and its childs' environment, not its parent's environment. This is a property -- most people call it a feature -- of the environments, including DJGPP, that GPC compiled programs run in.)
GPC also runs on big-endian systems (see section Endianness). This is, of course, a feature of GPC, but might affect your programs when running on a big-endian system if they make assumptions about endianness, e.g., by using type casts (or `absolute' declarations or variant records misused as type casts) in certain ways. Please see the demo program `absdemo.pas' for an example and how to solve it.
Endianness is also relevant (the more common case) when exchanging data between different machines, e.g. via binary files or over a network. Since the latter is not easily possible in BP, and the techniques to solve the problems are mostly the same as for files, we concentrate on files here.
First, you have to choose the endianness to use for the file. Most known data formats have a specified endianness (usually that of the processor on which the format was originally created). If you define your own binary data format, you're free to choose the endianness to use.
Then, when reading or writing values larger than one byte from/to the file, you have to convert them. GPC's Run Time System supports this by some routines. E.g., you can read an array from a little-endian file with the procedure `BlockReadLittleEndian', or write one to a big-endian file with `BlockWriteBigEndian'. Note: The endianness in the procedure names refers to the file, not the system -- the routines know about the endianness of the system they run on, but you have to tell them the endianness of the file to use. This means you do not have to (and must not) use an `ifdef' to use the version matching the system's endianness.
When reading or writing records or other more complicated structures, either read/write them field by field using `BlockReadBigEndian' etc., or read/write them with the regular `BlockRead' and `BlockWrite' procedures and convert each field after reading or before writing using procedures like `ConvertFromBigEndian' or `ConvertToLittleEndian' (but remember, when writing, to undo the conversion afterwards, if you want to keep using the data -- this is not necessary with `BlockWriteLittleEndian' etc.).
Especially for strings, there are ready-made procedures like `ReadStringBigEndian' or `WriteStringLittleEndian' which will read/write the length as a 64 bit value (much space for really long strings :-) in the given endianness, followed by the characters (which have no endianness problem).
All these routines are described in detail in the RTS reference (see section Pascal declarations for GPC's Run Time System), under `endianness'. The demo program `endiandemo.pas' contains an example on how to use these routines.
GPC warns about some BP constructs which are especially "dirty", like misusing typed constants as initialized variables. GPC also supports some features that may conflict with BP code, like macros. The command line option `--borland-pascal' disables both, so you might want to use it for a first attempt to compile your BP code under GPC. However, we suggest you try compiling without this switch and fixing any resulting problems as soon as you've become acquainted with GPC.
Even in `--borland-pascal' mode, GPC may warn about some dangerous things. To disable all warnings, you can use the `-w' option (note: lower-case `w'!). This is not recommended at all, but you may consider it more BP compatible...
A few exotic BP routines and declarations (e.g., `Swap' and `HeapError') are contained in a `System' unit, section BP compatibility: System, which GPC (unlike BP) does not automatically use in each program. To use it, you can add a `uses System;' clause to your program. If you don't want to change your code, the command line option `--uses=System' will do the same.
Since GPC runs on 32 and 64 bit platforms, integer types have larger sizes than in BP. However, if you use the `System' unit (see section - -uses=System - Swap; HeapError; etc.) and define the symbol `__BP_TYPE_SIZES__' (by giving `-D__BP_TYPE_SIZES__' on the command line), it will redeclare the types to the sizes used by BP. This is less efficient and more limiting, but might be necessary if your program relies on the exact type sizes.
GPC by default aligns fields of records and arrays suitably for higher performance, while BP doesn't. If you don't want the alignment (e.g., because the program relies on the internal format of your structures), either declare the relevant structures as `packed' (which BP also accepts, but ignores), or give the `--pack-struct' option.
GPC uses a more elaborate pseudo random number generator than BP does. Using the `Random' and `Randomize' functions works the same way, but there is no `RandSeed' variable (but a `SeedRandom' procedure). However, if you use the `System' unit (see section - -uses=System - Swap; HeapError; etc.) and define the symbol `__BP_RANDOM__' (by giving `-D__BP_RANDOM__' on the command line), it will provide a 100% BP compatible pseudo random number generator, including the `RandSeed' variable, which will produce exactly the same sequence of pseudo random numbers that BP's pseudo random number generator does. Even the `Randomize' function will then behave exactly like in BP.
A few more routines in the `Dos' and `WinDos' units besides the ones mentioned under section Keep; GetIntVec; SetIntVec, like `Intr' or `DosVersion', are meaningless on non-Dos systems. By default, the `Dos' unit does not provide these routines (it only provides those that are meaningful on all systems, which are most of its routines, including the most commonly used ones). If you need the unportable ones, you get them by using the `System' unit (see section - -uses=System - Swap; HeapError; etc.) and defining the symbol `__BP_UNPORTABLE_ROUTINES__' (by giving `-D__BP_UNPORTABLE_ROUTINES__' on the command line). If you use `Intr' or `MsDos', your program will only compile under DJGPP then. Other routines, e.g. `DosVersion' are emulated quite roughly on other systems. Please see the notes in the `Dos' unit (see section BP compatibility: Dos) for details.
In BP (or under Dos), `ParamStr (0)' always contains the full path of the current executable. Under GPC, by default it contains what was passed by the caller as the 0th argument -- which is often the name of the executable, but that's merely a convention, and it usually does not include the path.
If you use the `System' unit (see section - -uses=System - Swap; HeapError; etc.) and define the symbol `__BP_PARAMSTR_0__' (by giving `-D__BP_PARAMSTR_0__' on the command line), it will change the value of `ParamStr (0)' to that of `ExecutablePath', overwriting the value actually passed by the caller, to imitate BP's/Dos's behaviour. However note: On most systems, `ExecutablePath' is not guaranteed to return the full path, so defining this symbol doesn't change anything. In general, you cannot expect to find the full executable path, so better don't even try it, or your program will (at best) run on some systems. For most cases where BP programs access their own executable, there are cleaner alternatives available.
On the Dos (DJGPP) and Linux platforms, you can use RHIDE for GNU Pascal; check the subdirectories of your DJGPP distribution.
Unfortunately, there is no IDE which would run on all platforms. We are working on it, but this will take some time. Please be patient -- or offer your help!
Without an IDE, the GNU Pascal Compiler, GPC, is called about like the command-line version of the Borland Pascal Compiler, BPC. Edit your source file(s) with your favorite ASCII editor, then call GNU Pascal with a command line like
C:\GNU-PAS> gpc hello.pas -o hello.exe
on your Dos or OS/2 box or
myhost:/home/joe/gnu-pascal> gpc hello.pas -o hello
on your Unix (or Unix-compatible) system.
Don't omit the `.pas' suffix: GPC is a common interface for a Pascal compiler, a C, ObjC and C++ compiler, an assembler, a linker, and perhaps an Ada and a FORTRAN compiler. From the extension of your source file GPC figures out which compiler to run. GPC recognizes Pascal sources by the extension `.pas', `.p', `.pp' or `.dpr'.
The -o is a command line option which tells GPC how the
executable has to be named. If not given, the executable will be
called `a.out' (Unix) or `a.exe' (Dos). However, you can
use the `--executable-file-name' to tell GPC to always call the
executable like the source (with the extension removed under Unix
and changed to `.exe' under Dos).
Note that GPC is case-sensitive concerning file names and options, so it will not work if you type
C:\GNU-PAS> GPC HELLO.PAS -O HELLO.EXE
GPC is a very quiet compiler and doesn't print anything on the screen unless you request it or there is an error. If you want to see what is going on, invoke GPC with additional options:
-Q "don't be quiet" (or: Quassel-Modus in German)
(with capital `Q'!) means that GPC prints out the names of procedures and functions it processes, and
--verbose
or abbreviated
-v
means that GPC informs you about the stages of compilation, i.e. preprocessing, compiling, assembling, and linking.
One example (this time for OS/2):
[C:\GNU-Pascal] gpc --verbose -Q hello.pas
Throughout this chapter, we will tell you about a lot of command-line switches. They are all invoked this way.
After compilation, there will be an executable hello file in
the current directory. (hello.exe on Dos or OS/2.) Just run
it and enjoy. If you're new to Unix, please note that the current
directory is not on the PATH in most installations, so you might
have to run your program as `./hello'. This also helps to avoid
name conflicts with other programs. Such conflicts are especially
common with the program name `test' which happens to be a
standard utility under Unix that does not print any output. If you
call your program `test.pas', compile it, and then invoke
`test', you will usually not run your program, but the utility
which leads to mysterious problems. So, invoke your program as
`./test' or, better yet, avoid the name `test' for your
programs.
If there are compilation errors, GNU Pascal will not stop
compilation after the first one -- as Borland Pascal does -- but try
to catch all errors in one compilation. If you get more error
messages than your screen can hold, you can catch them in a file
(e.g. gpc.out) or pipe them to a program like `more'
in the following way:
gpc hello.pas 2> gpc.out
This works with OS/2 and any bash-like shell under Unix; for Dos you
must get a replacement for command.com which supports this
kind of redirection, or use the `redir' utility (see also the
DJGPP FAQ, section `DJGPP FAQ' in the DJGPP FAQ.):
C:\GNU-PAS> redir -eo gpc hello.pas -o hello.exe | more
You can also use Borland's IDE for GNU Pascal on the Dos platform: Install the GNU Pascal Compiler in the Tools menu (via Options/Tools).
Name: GNU Pascal Path: gpc Arguments: $SAVE ALL --executable-file-name $NAME($EDNAME).pas HotKey: Shift+F9
Note once more that GPC is case-sensitive, so it is important to
specify .pas instead of the .PAS Borland Pascal would
append otherwise!
You can include more command-line arguments to GNU Pascal (e.g. `--automake'; see below) as you will learn more about them.
Since Borland Pascal will try to recompile your program if you use
its Run menu function, you will need another tool to run your
program:
Name: Run Program Path: command.com Arguments: /c $NAME($EDNAME) HotKey: Shift+F10
GPC supports comments surrounded by `{ }' and `(* *)',
just like BP does. According to the ISO 7185 and ISO 10206
standards, Pascal allows comments opened with (* and closed
with }. Borland Pascal does not support such mixed
comments, so you might have sources where passages containing
comments are "commented out" using the other kind of comment
delimiters. GPC's default behaviour is (like BP) not to allow mixed
comments, so you don't need to worry about this. However, if you
happen to like mixed comments, you can turn them on either by a
command-line option, or by a compiler directive:
--mixed-comments {$mixed-comments} (*$mixed-comments*)
GPC supports nested comments (e.g., `{ foo { bar } baz }'), but they are disabled by default (compatible to BP which doesn't know nested comments at all). You can enable them with the option `--nested-comments' (or the equivalent compiler directive)
GPC also supports Delphi style comments starting with `//' and extending until the end of the line. This comment style is activated by default unless one of the `--standard-pascal', `--extended-pascal', `--object-pascal' or `--borland-pascal' dialect options is given. You can turn them on or off with the `--[no-]delphi-comments' option.
All of BP's one-letter compiler directives are supported by GPC, though some of them are ignored because they are not necessary under GPC. Besides, GPC supports a lot more directives. For an overview, see section Compiler Directives And The Preprocessor.
You can use units in the same way as in Borland Pascal. However, there are some additional features.
Concerning the syntax of a unit, you can, if you want, use Extended Pascal syntax to specify a unit initializer, i.e., instead of writing
begin ... end.
at the end of the unit, you can get the same result with
to begin do
begin
...
end;
and there also exists
to end do
begin
...
end;
which specifies a finalization routine. You can use this instead of Borland Pascal's exit procedures, but for compatibility, the included `System' unit also provides the `ExitProc' variable. The `to begin do' and/or `to end do' parts must be followed by the final `end.'. See section The Source Structure of ISO-10206 Extended Pascal Modules, for information about Extended Pascal modules, an alternative to units.
When GPC compiles a unit, it produces two files: an .o object
file (compatible with other GNU compilers such as GNU C) plus a
.gpi file which describes the interface.
If you are interested in the internal format of GPI file, see section GPI files -- GNU Pascal Interfaces.
If you want to compile a program that uses units, you must "make" the project. (This is the command-line switch `-M' or the IDE keystroke `F9' in BP.) For this purpose, GPC provides the command-line switch `--automake':
gpc --automake hello.pas
If you want to force everything to be rebuilt rather than only recompile changed files (`-B' or "build" in BP), use `--autobuild' instead of `--automake':
gpc --autobuild hello.pas
For more information about the AutoMake mechanism, see section GPC's AutoMake Mechanism -- How it Works.
If you do not want to use the AutoMake mechanism for whatever reason, you can also compile every unit manually and then link everything together.
GPC does not automatically recognize that something is a unit and cannot be linked; you have to tell this by a command line switch:
-c only compile, don't link.
(If you omit this switch when compiling a unit, you only get a linker error message `undefined reference to `main''. Nothing serious.)
For example, to compile two units, use:
gpc -c myunit1.pas myunit2.pas
When you have compiled all units, you can compile a program that uses them without using `--automake':
gpc hello.pas
However, using `--automake' is recommended, since it will recompile units that were modified.
You could also specify the program and the units in one command line:
gpc hello.pas myunit1.pas myunit2.pas
One of the purposes of writing units is to compile them separately.
However, GNU Pascal allows you to have one or more units in the same
source file (producing only one .o file but separate
.gpi files). You even can have a program and one or more
units in one source file; in this case, no .o file is
produced at all.
GNU Pascal is a 32/64 bit compiler with excellent optimization algorithms (which are identically the same as those of GNU C). There are six optimization levels, specified by the command line options `-O', `-O2', ..., `-O6'.
One example:
program OptimizationDemo; procedure Foo; var A, B : Integer; begin A := 3; B := 4; WriteLn (A + B) end; begin Foo end.
When GNU Pascal compiles this program with optimization
(`-O3'), it recognizes that the argument to `WriteLn' is the
constant 7 -- and optimizes away the variables A and
B. If the variables were global, they would not be optimized
away because they might be accessed from other places, but the
constant 7 would still be optimized.
For more about optimization, see the GNU C documentation.
The command line option `-g' specifies generation of debugging information for GDB, the GNU debugger. GDB comes with its own documentation. Currently, GDB does not understand Pascal syntax, so you should be familiar with C expressions if you want to use it.
See also "Notes for debugging" in the "Programming" chapter; see section Notes for Debugging.
Sometimes it is nice to have a look at the assembler output of the
compiler. You can do this in a debugger or disassembler (which is
the only way to do it in BP), but you can also tell GPC to produce
assembler code directly: When you specify the -S command line
option, GPC produces an .s file instead of an .o file.
The .s file contains assembler source for your program. More
about this in the next section.
Objects in the Borland Pascal 7.0 notation are implemented into GNU Pascal with the following differences:
type
MyObj = object
x: Integer;
procedure Foo; virtual;
y: Real;
function Bar: Char;
end;
Strings are "Schema types" in GNU Pascal which is something more
advanced than Borland-style strings. For variables, you cannot
specify just String as a type like in Borland Pascal; for
parameters and pointer types you can. There is no 255 characters
length limit. According to Extended Pascal, the maximum string
length must be in (parentheses); GNU Pascal accepts [brackets], too,
however, like BP.
For more about strings and schema types see section EP's Schema Types including `String'.
GPC supports Borland Pascal's string handling functions and some more (see section String Operations):
GNU Pascal supports Borland Pascal's "typed constants" but also Extended Pascal's initialized variables:
var x : Integer value 7;
or
var x : Integer = 7;
When a typed constant is misused as an initialized variable, a warning is given unless you specify `--borland-pascal'.
When you want a local variable to preserve its value, define it as `static' instead of using a typed constant. Typed constants also become static automatically for Borland Pascal compatibility, but it's better not to rely on this "feature" in new programs. Initialized variables do not become static automatically.
program StaticDemo;
procedure Foo;
{ x keeps its value between two calls to this procedure }
var
x : static Integer = 0;
begin
WriteLn (x);
Inc (x)
end;
begin
Foo;
Foo;
Foo;
end.
For records and arrays, GPC supports both BP style and Extended
Pascal style initializers. When you initialize a record, you may
omit the field names. When you initialize an array, you may provide
indices with a :. However, this additional information is
ignored completely, so perhaps it's best for the moment to only
provide the values ...
program BPInitVarDemo;
(*$W no-field-name-problem*) (* avoid a warning by GPC *)
const
A : Integer = 7;
B : array [1 .. 3] of Char = ('F', 'o', 'o');
C : array [1 .. 3] of Char = 'Bar';
Foo : record
x, y : Integer;
end = (x : 3; y : 4);
begin
end.
The bitwise operators `shl', `shr', `and', `or', `xor' and `not' work in GNU Pascal like in Borland Pascal. As an extension, you can use them as procedures, for example
program AndProcedureDemo; var x : Integer; begin and (x, $0000ffff); end.
as an alternative to
program AndOperatorDemo; var x : Integer; begin x := x and $0000ffff; end.
GPC accepts the BP style notation `$abcd' for hexadecimal numbers, but you also can use Extended Pascal notation:
program EPBaseDemo; const Binary = 2#11111111; Octal = 8#177; Hex = 16#ff; begin end.
and so on up to a basis of 36. Of course, you can mix the notations as you like, e.g.:
program BPEPBaseDemo; begin WriteLn ($cafe = 2#1100101011111110) end.
`Inc' and `Dec' are implemented like in Borland Pascal. `Pred' and `Succ' are generalized according to Extended Pascal and can have a second (optional) parameter:
procedure SuccDemo;
var a : Integer = 42;
begin
a := Succ (a, 5);
WriteLn (a) { 47 }
end.
BP style `absolute' variables work in the context of overloading other variables as well as in the context of specifying an absolute address, but the latter is highly unportable and not very useful even in Dos protected mode.
program BPAbsoluteDemo;
type
TString = String (80);
TTypeChoice = (t_Integer, t_Char, t_String);
(* WARNING: BAD STYLE! *)
procedure ReadVar (var x : Void; TypeChoice : TTypeChoice);
var
xInt : Integer absolute x;
xChar : Char absolute x;
xStr : TString absolute x;
begin
case TypeChoice of
t_Integer : ReadLn (xInt);
t_Char : ReadLn (xChar);
t_String : ReadLn (xStr);
end
end;
var
i : Integer;
c : Char;
s : TString;
begin
ReadVar (i, t_Integer);
ReadVar (c, t_Char);
ReadVar (s, t_String);
WriteLn (i, ' ', c, ' ', s)
end.
GNU Pascal knows Borland Pascal's procedures FillChar and
Move. However, their use can be dangerous because it often
makes implicit unportable assumptions about type sizes, endianness,
internal structures or similar things. Therefore, avoid them
whenever possible. E.g., if you want to clear an array of strings,
don't `FillChar' the whole array with zeros (this would
overwrite the Schema discriminants, see section BP compatibility: Strings), but rather
use a `for' loop to assign the empty string to each string. In
fact, this is also more efficient than `FillChar', since it
only has to set the length field of each string to zero.
GNU Pascal allows the user to define operators according to the Pascal-SC syntax:
program PXSCOperatorDemo;
type
Point = record
x, y : Real;
end;
operator + (a, b : Point) c : Point;
begin
c.x := a.x + b.x;
c.y := a.y + b.y;
end;
var
a, b, c : Point = (42, 0.5);
begin
c := a + b
end.
The Pascal-SC operators `+>', `+<', etc. for exact numerical calculations are not implemented, but you can define them.
program IntegerSizeDemo;
type
MyInt = Integer (42); { 42 bits, signed }
MyWord = Word (2); { 2 bits, unsigned, i.e., 0 .. 3 }
MyCard = Cardinal (2); { the same }
HalfInt = Integer (BitSizeOf (Integer) div 2);
{ A signed integer type which is half as big as the normal
`Integer' type, regardless of how big `Integer' is
on any platform the program is compiled on. }
begin
end.
System unit.
type
MyRec = record
f, o, oo : Boolean;
Bar : Integer
end;
has 8 bytes, not 7. Use the --pack-struct option or declare
the record as `packed' to force GPC to pack it to 7 bytes.
However, note that this produces somewhat less efficient code on the
x86 and far less efficient code on certain other processors. Packing
records and arrays is mostly useful only when using large structures
where memory usage is a real concern, or when reading or writing
them from/to binary files where the exact layout matters.
In addition to BP's procedural types, GNU Pascal has pointers to procedures:
type FuncPtr = ^function (Real) : Real;
The differences between procedure pointers and procedural types are only syntactical:
One can use both kinds in the same program, of course, though it is recommended to stick to one kind throughout to avoid maximum confusion.
GNU Pascal also supports Standard Pascal's procedural parameters (see section Special Parameters).
Furthermore, GNU Pascal allows you to call even local procedures through procedural pointers, variables or parameters without reverting to any dirty tricks (like assembler, which is necessary in BP).
The differences between the various kinds of procedural types, pointers and parameters are demonstrated in the demo program `procvardemo.pas'. An example for calling local routines through procedural parameters can be found in the demo program `iteratordemo.pas'.
Besides the operators found in Borland Pascal, GNU Pascal supports the following operators:
pow and ** which do not
exist in Borland Pascal. You can use x pow y for integer and
x ** y for real or complex exponents. The basis may be
integer, real or complex in both cases.
@, but also
& as an address operator.
set1 >< set2. For more about this, see section Set Operations.
program GetMemFunctionDemo; var p : Pointer; begin p := GetMem (1024) end.The second parameter to `FreeMem' is ignored by GNU Pascal and may be omitted. Memory blocks are always freed with the same size they were allocated with. Remark: Extended Pascal Schema types provide a cleaner approach to most of the applications of `GetMem' and `FreeMem'.
procedure Foo (var x);like in Borland Pascal. In GNU Pascal, you can also use
procedure Foo (var x : Void);
procedure Foo (a : Integer; ...);However, GPC does not (yet) provide a portable mechanism to access the additional arguments.
procedure Foo (a : array of Integer);are implemented. However, Standard Pascal `conformant array parameters' are usually a cleaner mechanism to pass arrays of variable size.
procedure DrawGraph (function f (x : Real) : Real);
program Foo (Input, Output); begin end.In GNU Pascal, headline parameters are optional. If the headline is omitted entirely, a warning is given unless you have specified `--borland-pascal' in the command line.
otherwise (according to Extended Pascal) as an
alternative to else:
program CaseOtherwiseDemo;
var x : Integer;
begin
ReadLn (x);
case x of
1 : WriteLn ('one');
2 : WriteLn ('two');
otherwise
WriteLn ('many')
end
end.
Note: In the absence of a `case' or `otherwise' branch,
missing cases labels cause an error in Extended Pascal (which goes
unnoticed in Borland Pascal). GPC does not give this error, but a
warning if the `-Wswitch' option is given, however only for
enumeration types.
Card function for sets which counts
their elements. Unlike Borland Pascal, GNU Pascal does not limit
sets to the range 0 .. 255.
function Max (x, y : Integer) : Integer; inline ($58 / $59 / $3b / $c1 / $7f / $01 / $91);GNU Pascal:
program InlineDemo;
inline function Max (x, y : Integer) : Integer;
begin
if x > y then
Max := x
else
Max := y
end;
begin
WriteLn (Max (42, 17), ' ', Max (-4, -2))
end.
(Actually, a more general `Max' function is already built-in.)
This feature is not so important as it might seem because in
optimization level 3 or higher (see section The most commonly used options to GPC), GNU Pascal
automatically inlines short procedures and functions.
Pascal is a well-known programming language and hardly needs to be described here. Note, however, that there is a large difference between the language used by the BP compiler and the Pascal Standards.
Extended Pascal is a standardized language based on the original Standard Pascal, but with significant extensions. Unfortunately, Borland Pascal does not conform to any of the Pascal standards. Writing a program that both complies to Extended Pascal (or even Standard Pascal) and compiles with BP is almost impossible for any non-trivial task.
On the other hand, BP has some nice features that make it very powerful in the environments in which it runs. However, some of those features are of little use on non-Dos systems and would not be good candidates for standardization.
There are also several BP features which are semantically similar to features in Standard Pascal or Extended Pascal, but syntactically different.
Therefore, in order to be useful to users coming from either side, GPC supports both the standards and the BP dialect as good as possible. By default, GPC allows features from any dialect it knows. By giving a dialect option such as `--borland-pascal' or `--extended-pascal', you can tell GPC to disable the features not found in that dialect, and to adjust its warning behaviour to the dialect.
The different sets of reserved words are a little problem, but GPC solves it by making the words in question only "conditionally reserved" which works transparently without problems in most cases. Still, giving a dialect option will disable all keywords not part of this dialect.
Apart from this, there are surprisingly few real conflicts between the dialects. Therefore, you can usually compile your BP code without the `--borland-pascal' option and make use of all of GPC's features. You might be surprised, though, when GPC accepts things you didn't know were allowed. :-)
Finally, if you want to make use of some of GPC's extensions (compared to BP) and still keep the code compileable with BP without using `ifdef's all over the place, we suggest you look at the unit `gpc-bp.pas', shipped with GPC, which contains BP versions of some of GPC's features. Please read the comments at the beginning of the unit to find out more about it.
GPC offers you the possibility to make your code fully portable to each of the many platforms supported by GPC. It would be a pity not to make use of this.
This section lists some known pitfalls that often hinder otherwise well-written programs to take full advantage of GPC. If you have never used any compiler but Borland Pascal and similar compilers, some of the advices might look strange to you. But this is just the same level of strangeness that your old programs will have for you once you have understood the principles of cross-platform portability. Remember that many tricks you have always been applying almost automatically in Borland Pascal were necessary to overcome certain limitations of the Dos platform and to compensate for the compiler's missing optimization. Programming with an optimizing compiler like GPC for platforms without a 64 kB limit is a completely new experience -- and perhaps it is among the reasons why you are now working with GPC in the first place?
Okay -- but why should I bother and make my program portable? I know that all who want to use my program are running WXYZ-OS anyway.
Yes, but that's the result of a self-fulfilling prophecy. It depends on you whether it will always remain like this or not. Consider a program ABC written for a single platform, WXYZ-OS. Naturally, only WXYZ-OS-users get interested in ABC. The author gets feedback only from WXYZ-OS users and does not see any reason to make the program cross-platform. Then people realize that if they want to run ABC they must move to WXYZ-OS. The author concludes that people only want WXYZ-OS programs, and so on.
To break out, just create a portable version of your program now. Then all OSes have equal chances to show their abilities when running your program, and your customers can choose their OS. Then, maybe, they decide to use your program just for the reason that they can be sure that it will run on all present and future platforms and not only on a specific one -- who knows?
My program is a tool specifically designed to make the best of the STUV feature of WXYZ-OS. There is no point in making it portable.
How much do you know about non-WXYZ-OSes? Just ask an expert how the STUV feature is named elsewhere. Be sure, if it is of value, it exists almost everywhere.
I am using a lot of low-level stuff in my programs, so they cannot be portable.
You do not use those low-level routines directly in your high-level routines, do you? There should always be a layer "in-between" that encapsulates the low-level routines and present an API to your program that exactly reflects the needs of your application. This "API in between" is the point where you can exchange the low-level routines by portable calls to GPC's Run Time System.
If you do not have such a layer in-between, then the API of the low-level routines you call are your first approximation for such a layer. If you have ever thought "it would be great if that API function had that additional parameter", then your own extended version of that API function that has that parameter can become part of your "API in between". But then don't stop here: Certainly the API of the OS is not ideal for your program's needs. Just create more routines that encapsulate all OS-specific stuff ...
When the low-level stuff in question consists of interrupts, assembler and similar things, then the first thing you need is a portable replacement of the functionality. Fortunately, GPC covers many things already in Pascal that require assembler in Borland Pascal:
Go to the first, previous, next, last section, table of contents.