This chapter is intended to be a QuickStart guide for programmers who are familiar with Borland Pascal, version 7 for DOS protected mode. Other versions don't differ too much but this one was the very last DOS version Borland has published.
GNU Pascal (GPC) is compatible to version 7 of Borland Pascal (BP) to a large extent and comes with portable replacements of the Borland standard units.
However, BP is a 16-bit compiler while GPC is a 32/64-bit compiler which, unlike other free compilers, does not intend to emulate BP in all respects. 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 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.
On the DOS (DJGPP) and Linux platforms, you can use the 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 suffix `.pas': 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.
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).
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
with DOS and 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 them all 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):
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 --verbose -Q $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
According to the ISO 7185 and ISO 10206 standards, GNU Pascal
can recognize comments opened with (*
and closed with
}
. With Borland Pascal, both types of comments can be
nested, so you will probably have sources where passages
containing comments are "commented out". GPC's default
behavior is to allow nested comments, so you don't need to worry
about this. However you can switch it off either by a
command-line option, or by a compiler directive:
--no-nested-comments {$N-} (*$N-*)
The $N directive also exists in BP but has another meaning. The same holds for most of GPC's other compiler directives (also corresponding to command-line options in most cases):
--short-circuit $B+ $B- like in Borland Pascal: $B- means short-circuit Boolean operators; $B+ complete evaluation --c-numbers $C+ $C- enable/disable C-style octal 0177 and hexadecial 0xFF numbers --char-escapes $E+ $E- enable/disable C-style character escape sequences in strings --io-checking $I+ $I- like in Borland Pascal: enable/disable I/O checking --nested-comments $N+ $N- enable/disable nested comments (see above) --pedantic $P+ $P- give/don't give portability warnings $W+ $W- enable/disable warnings $X+ $X- mostly like in Borland Pascal: enable/disable extended syntax (ignore function return values, operator definitions, "PChars", pointer arithmetics, ...) --borland-pascal disable or warn about GPC features not supported by Borland Pascal; do not warn about "dangerous" BP features {$I FileName } like in Borland Pascal: include filename.pas or filename.p (make it lowercase) {$include "filename.pas"} include (case-sensitive) {$include <filename.pas>} the same, but don't search in the current directory {$M Hello!} write message "Hello!" to error device during compilation {$define FOO} like in Borland Pascal: {$D FOO} define FOO (for conditional compilation) Unlike BP, GPC treats FOO case-sensitively @cindex foo -D FOO the same in command line {$D loop while true do} define "loop" to be "while true do" as a macro like in C. The name of the macro is case-sensitive. {$undef FOO} like in Borland Pascal: undefine FOO {$ifdef FOO} conditional compilation ... (like in Borland Pascal). {$else} GPC predefines the symbol ... __GPC__ (with two leading {$endif} and trailing underscores).
You also can use C-style preprocessor directives, e.g. `#include.', but this is deprecated, e.g. because of possible conflicts with Borland Pascal style `#42' character constants.
As in Borland Pascal, {$...}
and (*$...*)
are equivalent.
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 (* to begin *);
and there also exists
to end do begin ... end (* to 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.'. In section GNU Pascal extensions and section About Pascal and Extended Pascal languages, you can find information about Extended Pascal Modules, an alternative to units.
At the moment, there are no qualified identifiers, so take care about name clashes between different 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
precompiled Interface which resides in a .gpi
file.
(See section GPI files--GNU Pascal Interfaces for GPI file internals.)
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 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 all units compiled, 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 units in one
and the same 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 Test; 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, it
recognizes that the argument of 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 "Bugs" chapter; see section Known bugs and inconveniences; how to report bugs.
Sometimes it is nice to have a look at the assembler output of
the compiler. 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.
GNU Pascal has an inline assembler, but it is quite different from Borland's one: It supports a large variety of processors and works together with GPC's optimization.
A tutorial for use of the GPC inline assembler is available from the same place where you got GPC itself in a subdirectory `contrib', file `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.)
Objects in the Borland Pascal 7.0 notation are implemented into GNU Pascal with the following differences:
MyObj = object x: Integer; Procedure Foo; virtual; y: Real; Function Bar: Char; end (* MyObj *);
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 (parantheses); GNU Pascal
accepts [brackets], too, however.
For more about Strings and Schema types see section GNU Pascal extensions and section About Pascal and Extended Pascal languages.
GPC supports Borland Pascal's String-handling functions and some more (see section GNU Pascal extensions):
Borland Pascal GNU Pascal Length Length Pos Pos, Index (1) Str Str, WriteStr (1) (2) Val Val, ReadStr (2) Copy Copy, SubStr, MyStr [ 2 .. 7 ] (3) MyStr [ 0 ]:= #7; SetLength - Trim =, <>, <, <=, >, >= =, <>, <, <=, >, >= (4) EQ, NE, LT, LE, GT, GE Insert Insert Delete Delete
(1) The order of parameters of the Extended Pascal routines (`Index', `WriteStr') is different from the Borland Pascal routines.
(2) `ReadStr' and `WriteStr' allow an arbitrary number of arguments, and the arguments are not limited to numbers. `WriteStr' also allows comfortable formatting like `Writeln' does, e.g. `WriteStr (Dest, Foo : 20, Bar, 1/3 : 10 : 2)'.
(3) `SubStr' reports a runtime error if the requested substring does not fit in the given string, `Copy' does not.
(4) By default, the string operators behave like in BP. However, if you use the option `--no-exact-compare-strings', they ignore differences of trailing blanks, so e.g. `'foo'' and `'foo '' are considered equal. The corresponding functions (`EQ', ...) always do exact comparisons.
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 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 ...
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.
Procedure Foo; Var x: static Real; begin (* Foo *) (* x keeps its value between two calls to this Procedure *) end (* Foo *);
The bitwise operators `shl', `shr', `and', `or', `xor' work in GNU Pascal like in Borland Pascal. As an extension, you can use them as "procedures", for example
and ( x, $0000FFFF );
as an alternative to
x:= x and $0000FFFF;
GPC accepts the Borland-specific notation `$ABCD' for hexadecimal numbers, but you also can use Extended Pascal notation:
2#11111111 for a binary, 8#177 for an octal, 16#FF for a hexadecimal number,
and so on up to a basis of 36.
`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:
a:= Succ ( a, 5 );
`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.
The `Mem' and `Port' arrays don't exist in GNU Pascal. As a replacement for `Port', you can use the routines provided in the `Ports' unit.
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 Strings), but rather
use a `for' loop to assign the empty string to each string.
This is even 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:
Type Point = record x, y: Real; end (* Point *); Operator + ( a, b: Point ) c: Point; begin (* Point + Point *) c.x:= a.x + b.x; c.y:= a.y + b.y; end (* Point + Point *);
The Pascal-SC operators `+>', `+<', etc. for exact numerical calculations are not implemented, but you can define them. If you write a module which really implements these operators, please send it to us, so we can include it into the next distribution.
(And if you know more about modules in Pascal-SC than just their existence, please contact us as well! We could probably easily implement them if we knew how they look like. Something quite close to Pascal-SC modules already is implemented as "GNU specific modules".)
Borland Pascal GNU Pascal bits(1) signed ShortInt ByteInt 8 yes Integer ShortInt 16 yes LongInt Integer 32 yes Comp LongInt, Comp 64 yes Byte Byte 8 no Word ShortWord 16 no - Word 32 no - LongWord 64 no(1) The size of the GNU Pascal types may depend on the platform. The sizes above currently apply to most platforms, including the x86. If you care for types with exactly the same size as in Borland Pascal, take a look at the `System' unit and read its comments. You can get the size of a type with `SizeOf' in bytes (like in Borland Pascal) and with `BitSizeOf' in bits, and you can declare types with a specific size, e.g.
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. }
Borland Pascal GNU Pascal Single Single, ShortReal Real - Double Double, Real Extended Extended, LongReal Comp Comp, LongInt
Type myRec = record f, o, oo: Boolean; Bar: Integer; end (* myRec *);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; see
section Options for Code Generation Conventions. 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
concern, or when reading/storing them from/to binary files where the
exact layout matters.
Type FuncPtr = ^Function ( Real ): Real;GNU Pascal also supports Standard Pascal's procedural parameters--see below. Furthermore, GNU Pascal allows you to call local procedures through procedural pointers/variables/parameters without reverting to any dirty tricks (like assembler, which is necessary in Borland Pascal).
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 GNU Pascal extensions.
p:= GetMem ( 1024 );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; ... );but 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 a "cleaner" mechanism to pass arrays of variable size.
Procedure DrawGraph ( Function f ( x: Real ): Real );
Program Foo ( Input, Output );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
as an alternative to else
(according to Extended Pascal):
case x of 1: writeln ( 'one' ); 2: writeln ( 'two' ); otherwise writeln ( 'many' ); end (* case *);
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:
Inline Function Max ( x, y: Integer ): Integer; begin (* Max *) if x > y then Max:= x else Max:= y; end (* Max *);(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 above), GNU Pascal automatically "inlines" short procedures and functions.
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 MS-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 the 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.