Free Pascal Manual
Free Pascal Manual
User's guide. Programmer's guide. Reference guide for the system unit, and supported Pascal constructs. Standard units reference manual.
Free Pascal : Users' manual Contents Introduction About this document About the compiler Getting more information. Installing the compiler Before Installation : Requirements Installing the compiler. Testing the compiler Compiler usage Compiling a program Compiling a unit Creating an executable for GO32V1 and PMODE/DJ targets Reducing the size of your program Compiling problems General problems Problems you may encounter under DOS Compiler configuration Using the command-line options Using the configuration file Porting Turbo Pascal Code Things that will not work Things which are extra Turbo Pascal compatibility mode Utilities and units that come with Free Pascal Supplied programs Supplied units Debugging your Programs Compiling your program with debugger support Using gdb to debug your program Caveats when debugging with gdb Support for gprof, the gnu profiler CGI programming in Free Pascal Getting your data Producing output I'm under Windows, what now ? Alphabetical listing of command-line options Alphabetical list of reserved words Compiler error messages Compiler errors Run time errors Assembler reader errors. The Floating Point Coprocessor emulator A sample gdb.ini file
Page 2
INTRODUCTION
About this document About the compiler Getting more information.
Page 3
Page 4
Software requirements
UNDER DOS
The DOS distribution contains all the files you need to run the compiler and compile pascal programs.
UNDER LINUX
Under LINUX you need to have the following programs installed : 1. gnu as, the gnu assembler. 2. gnu ld, the gnu linker. 3. Optionally (but highly recommended) : gnu make. For easy recompiling of the compiler and Run-Time Library, this is needed. Other than that, Free Pascal should run on almost any I386 LINUX system.
Page 5
This file is located in the directory where you installed Free Pascal. The installation program doesn't modify the AUTOEXEC.BAT, since many people (including the authors of Free Pascal) don't like this. You can choose to insert a call to this batch file in your AUTOEXEC.BAT file, like this : CALL C:\PP\SET_PP.BAT (This is assuming that you installed Free Pascal in the default location.) In order to run Free Pascal from any directory on your system, you must extend your path variable to contain the C:\PP\BIN directory. You can choose to do this in your AUTOEXEC.BAT file, but you can also insert a statement in the SET_PP.BAT file. Whatever the location you choose, It should look something like this : SET PATH=%PATH%;C:\PP\BIN (Again, assuming that you installed in the default location). If you want to use the graphic drivers you must modify the environment variable GO32. Instructions for doing this can be found in the documentation of the Graph unit, at the InitGraph procedure.
Page 6
If you run the installation script as the root user, you can just accept all installation defaults. If you don't run as root, you must take care to supply the installation program with directory names where you have write permission, as it will attempt to create the directories you specify. In principle, you can install it wherever you want, though. At the end of installation, the installation program will generate a configuration file for the Free Pascal compiler which reflects the settings that you chose. It will install this file in the /etc directory, (if you are not installing as root, this will fail), and in the directory where you installed the libraries. If you want the Free Pascal compiler to use this configuration file, it must be present in /etc, or you can set the environment variable PPC_CONFIG_PATH. Under csh, you can do this by adding a setenv PPC_CONFIG_PATH /usr/lib/ppc/0.99.1 line to your .login file in your home directory. (see also the next section)
FINALLY
Also distributed in Free Pascal is a README file. It contains the latest instructions for installing Free Pascal, and should always be read first.
Page 7
COMPILER USAGE
Here we describe the essentials to compile a program and a unit. We also describe how to make a standalone executable of the compiled program under DOS. For more advanced uses of the compiler, see the section on configuring the compiler, and the Programmer's guideThe examples in this section suppose that you have a ppc386.cfg which is set up correctly, and which contains at least the path setting for the RTL units. In principle this file is generated by the installation program. You may have to check that it is in the correct place (see section 5.2 for more information on this). Compiling a program Compiling a unit Creating an executable for GO32V1 and PMODE/DJ targets Reducing the size of your program
COMPILING A PROGRAM
Compiling a program is very simple. Assuming that you have a program source in the file prog.pp, you can compile this with the following command: ppc386 [options] prog.pp The square brackets [] indicate that what is between them is optional. If your program file has the .pp or .pas extension, you can omit this on the command line, e.g. in the previous example you could have typed: ppc386 [options] prog If all went well, the compiler will produce an executable, or, for version 1 of the DOS extender, a file which can be converted to an executable. Under LINUX and version 2 of the DOS extender, the file you obtained is the executable. You can execute it straight away, you don't need to do anything else. Under DOS, additional processing is required. See the section on creating an executable. You will notice that there is also anothe file in your directory, with extensions .o. This contains, the object file for your program. If you compiled a program, you can delete the object file (.o), but not if you compiled a unit. Then the object file contains the code of the unit, and will be linked in any program that uses the unit you compiled, so you shouldn't remove it.
COMPILING A UNIT
Compiling a unit is not essentially different from compiling a program. The difference is mainly that the linker isn't called in this case. To compile a unit in the file foo.pp, just type : ppc386 foo Recall the remark about file extensions in the previous section. When all went well, you will be left with 2 (two) unit files: 1. foo.ppu This is the file describing the unit you just compiled. 2. foo.o This file contains the actual code of the unit. This file will eventually end up in the executables. Both files are needed if you plan to use the unit for some programs. So don't delete them. If you want to distribute the unit, you must provide both the .ppu and .o file. One is useless without the other.
Page 8
GO32V1
When compiling under DOS, GO32V2 is the default target. However, if you use go32V1 (using the -TDOS switch), the compilation process leaves you with a file which you cannot execute right away. There are 2 things you can do when compiling has finished. The first thing is to use the DOS extender from D.J. Delorie to execute your program : go32 prog This is fine for testing, but if you want to use a program regularly, it would be easier if you could just type the program name, i.e. prog This can be accomplished by making a DOS executable of your compiled program. There two ways to create a DOS executable (under DOS only): 1. if the GO32.EXE is already installed on the computers where the program should run, you must only copy a program called STUB.EXE at the begin of the AOUT file. This is accomplished with the AOUT2EXE.EXE program. which comes with the compiler: AOUT2EXE PROG and you get a DOS executable which loads the GO32.EXE automatically. the GO32.EXE executable must be in current directory or be in a directory in the PATH variable. 2. The second way to create a DOS executable is to put GO32.EXE at the beginning of the AOUT file. To do this, at the command prompt, type : COPY /B GO32.EXE+PROG PROG.EXE (assuming Free Pascal created a file called PROG, of course.) This becomes then a stand-alone executable for DOS, which doesn't need the GO32.EXE on the machine where it should run.
PMODE/DJ
You can also use the PMODE/DJ extender to run your Free Pascal applications. To make an executable which works with the PMODE extender, you can simply create an GO32V2 executable (the default), and then convert it to a PMODE executable with the following two extra commands: 1. First, strip the GO32V2 header of the executable: EXE2COFF PROG.EXE (we suppose that PROG.EXE is the program generated by the compilation process. 2. Secondly, add the PMODE stub: COPY /B PMODSTUB.EXE+PROG PROG.EXE If the PMODSTUB.EXE file isn't in your local directory, you need to supply the whole path to it. That's it. No additional steps are needed to create a PMODE extender executable. Be aware, though, that the PMODE extender doesn't support virtual memory, so if you're short on memory, you may run unto trouble. Also, officially there is not support for the PMODE/DJ extender. It just happens that the compiler and some of the programs it generates, run under this extender too.
Page 9
COMPILING PROBLEMS
General problems Problems you may encounter under DOS
GENERAL PROBLEMS
IO-error -2 at ... : Under LINUX you can get this message at compiler startup. It means typically that the compiler doesn't find the error definitions file. You can correct this mistake with the -Fr option under LINUX. (See 5.1) Error : File not found : xxx This typically happens when your unit path isn't set correctly. Remember that the compiler looks for units only in the current directory, and in the directory where the compiler itself is. If you want it to look somewhere else too, you must explicitly tell it to do so using the -Up option (See 5.1).
Page 10
COMPILER CONFIGURATION
The output of the compiler can be controlled in many ways. This can be done essentially in two distinct ways: Using command-line options. Using the configuration file: ppc386.cfg. The compiler first reads the configuration file. Only then the command line options are checked. This creates the possibility to set some basic options in the configuration file, and at the same time you can still set some specific options when compiling some unit or program. First we list the command line options, and then we explain how to specify the command line options in the configuration file. When reading this, keep in mind that the options are case sensitive. While this is customary for LINUX, it isn't under DOS. Using the command-line options Using the configuration file
General options
-h if you specify this option, the compiler outputs a list of all options, and exits after that. -? idem as -h. -i This option tells the compiler to print the copyright information. -l This option tells the compiler to print the Free Pascal logo on standard output. It also gives you the Free Pascal version number. -Lx Set the language the compiler uses for its messages. x can be one of the following: D : Use German. E : Use English. -n Tells the compiler not to read the configuration file.
Page 11
p : Tells the compiler to print the names of procedures and functions as it is processing them. c : Tells the compiler to warn you when it processes a conditional. m : Tells the compiler to write which macros are defined. d : Tells the compiler to write other debugging info. a : Tells the compiler to write all possible info. (this is the same as spcifying all options) 0 : Tells the compiler to write no messages. This is useful when you want to override the default setting in the configuration file.
Page 12
-Cn Omit the linking stage. -Co Generate Integer overflow checking code. -Cr Generate Range checking code. -Csxxx Set stack size to xxx. (OS/2 only). CS Statically link your program/unit. -Ct generate stack checking code. -dxxx Define the symbol name xxx. This can be used to conditionally compile parts of your code. -E Same as -Cn. -g Generate debugging information for debugging with gdb. -gp Generate profiler code for gprof. -On optimize the compiler's output; n can have one of the following values : a simple optimizations g optimize for size G optimize for time x optimize maximum z uncertain optimizations 2 optimize for Pentium II (tm) 3 optimize for i386 4 optimize for i486 5 optimize for Pentium (tm) 6 optimizations for PentiumPro (tm) The exact effect of these effects can be found in the appendices of the Programmer's guide. -oxxx Tells the compiler to use xxx as the name of the output file (executable). Only with programs. -pg Tells the compiler to issue code for profiling support. -s Tells the compiler not to call the assembler and linker. Instead, the compiler writes a script, PPAS.BAT under DOS, or ppas.sh under LINUX, which can then be executed to produce an executable. -Txxx Specifies the target operating system. xxx can be one of the following: DOS : DOS and the DJ DELORIE extender. OS2 : OS/2 (2.x) (this is still under development). LINUX : LINUX.
Page 13
WIN32 : Windows 32 bit (this is still under development). GO32V2 : DOS and version 2 of the DJ DELORIE extender. -Uld make dynamic library from unit. -Uls make static library from unit. -uxxx Undefine symbol xxx. -Xx executable options. This tells the compiler what kind of LINUX executable should be generated. the parameter x can be one of the following: c : (LINUX only) Link with the C library. You should only use this when you start to port Free Pascal to another operating system. s : (DOS only) Strip the symbols from the executable.
Page 14
Page 15
Page 16
function a : longint; begin a:=12; while a>4 do begin {...} end; end; The example above would work with TP, but the compiler would assume that the a>4 is a recursive call. To do a recursive call in this you must append () behind the function name: function a : longint; begin a:=12; { this is the recursive call } if a()>4 then begin {...} end; end; There is partial support of Delphi constructs. (see the Programmer's guide for more information on this). The exit call accepts a return value for functions. function a : longint; begin a:=12; if a>4 then begin exit(a*67); {function result upon exit is a*67 } end; end; Free Pascal supports function overloading. That is, you can define many functions with the same name, but with different arguments. For example: procedure DoSomething (a : longint); begin {...} end; procedure DoSomething (a : real); begin {...} end; You can then call procedure DoSomething with an argument of type Longint or Real. This feature has the consequence that a previously declared function must always be defined with the header completely the same: procedure x (v : longint); forward; {...} procedure x;{ This will overload the previously declared x} begin {...} end; This construction will generate a compiler error, because the compiler didn't find a definition
4. 5.
6.
Page 17
of procedure x (v : longint);. Instead you should define your procedure x as: procedure x (v : longint); { This correctly defines the previously declared x} begin {...} end;
Page 18
SUPPLIED PROGRAMS
dumppu is a program which shows the contents of a Free Pascal unit. It comes in source form, and must be compiled before you can use it. Once compiled, you can just issue the following command dumppu foo.ppu to display the contents of the foo.ppu unit. Also distributed with Free Pascal comes a series of demonstration programs. These programs have no other purpose than demonstrating the capabilities of Free Pascal. They are located in the demo directory of the sources. All example programs of the documentation are available. Check out the directories that end on ex in the documentation sources. There you will find all example sources. ppumove is a program to make shared or static libraries from units. It should be distributed in binary form along with the compiler.
SUPPLIED UNITS
Here we list the units that come with the Free Pascal distribution. Since there is a difference in the supplied units per operating system, we list them separately per system. They are documented in the Unit reference.
Under DOS
strings This unit provides basic string handling routines for the pchar type, comparable to similar routines in standard C libraries. objects This unit provides basic routines for handling objects. dos This unit provides basic routines for accessing the operating system DOS. It provides almost the same functionality as the Turbo Pascal unit. printer This unit provides all you need for rudimentary access to the printer. getopts This unit gives you the gnu getopts command-line arguments handling mechanism. It also supports long options. crt This unit provides basic screen handling routines. It provides the same functionality as the Turbo Pascal CRT unit. graph This unit provides basic graphics handling, with routines to draw lines on the screen, display texts etc. It provides the same functions as the Turbo Pascal unit. go32
Page 19
This unit provides access to possibilities of the GO32 DOS extender. emu387 This unit provides support for the coprocessor emulator. mmx This unit provides support for mmx extensions in your code.
Under Linux
strings This unit provides basic string handling routines for the PChar type, comparable to similar routines in standard C libraries. objects This unit provides basic routines for handling objects. crt This unit provides basic screen handling routines. It provides the same functionality Turbo Pascal CRT unit. It works on any terminal which supports the vt100 escape sequences. dos This unit provides an emulation of the same unit under DOS. It is intended primarily for easy porting of Pascal programs from DOS to LINUX. For good performance, however, it is recommended to use the linux unit. linux This unit provides access to the LINUX operating system. It provides most file and I/O handling routines that you may need. It implements most of the standard C library constructs that you will find on a Unix system. If you do a lot of disk/file operations, the use of this unit is recommended over the one you use under Dos. printer This unit provides an interface to the standard Unix printing mechanism. getopts This unit gives you the gnu getopts command-line arguments handling mechanism. It also supports long options. mmx This unit provides support for mmx extensions in your code. sockets This unit gives you access to sockets and TCP/IP programming.
Page 20
Page 21
If your program runs without problems, gdb will inform you of this, and return the exit code of your program. If the exit code was zero, then the message 'Program exited normally'. If something went wrong (a segmentation fault or so), gdb will stop the execution of your program, and inform you of this with an appropriate message. You can then use the other gdb commands to see what happened. Alternatively, you can instruct gdb to stop at a certain point in your program, with the break command. Here is a short list of gdb commands, which you are likely to need when debugging your program: quit Exits the debugger. kill Stops a running program. help Gives help on all gdb commands. file Loads a new program into the debugger. directory Add a new directory to the search path for source files. Remark: My copy of gdb needs '.' to be added explicitly to the search path, otherwise it doesn't find the sources. list Lists the program sources per 10 lines. As an option you can specify a line number or function name. break Sets a breakpoint at a specified line or function awatch Sets a watch-point for an expression. A watch-point stops execution of your program whenever the value of an expression is either read or written. for more information, see the gdb users' guide, or use the 'help' function in gdb. The appendix F contains a sample init file for gdb, which produces good results when debugging Free Pascal programs.
Page 22
5.
6. 7.
Print out a Pascal string end If you insert it in your gdb.ini file, you can look at a string with this function. There is a sample gdb.ini in appendix F. Objects are difficult to handle, mainly because gdb is oriented towards C and C++. The workaround implemented in Free Pascal is that object methods are represented as functions, with an extra parameter this (all lowercase !) The name of this function is a concatenation of the object type and the function name, separated by two underscore characters. For example, the method TPoint.Draw would be converted to TPOINT__DRAW, and could be stopped at with break TPOINT__DRAW Global overloaded functions confuse gdb because they have the same name. Thus you cannot set a breakpoint at an overloaded function, unless you know it's line number, in which case you can set a breakpoint at the starting linenumber of the function.
Page 23
Page 24
var data : array[1..max_data] of datarec; i,nrdata : longint; c : char; literal,aname : boolean; begin writeln ('Content-type: text/html'); writeln; if getenv('REQUEST_METHOD')<>'POST' then begin writeln ('This script should be referenced with a METHOD of POST'); write ('If you don''t understand this, see this '); write ('< A HREF="http://www.ncsa.uiuc.edu/SDG/Softare/Mosaic'); writeln ('/Docs/fill-out-forms/overview.htm">forms overview</A>.'); halt(1); end; if getenv('CONTENT_TYPE')<>'application/x-www-form-urlencoded' then begin writeln ('This script can only be used to decode form results'); halt(1) end; nrdata:=1; aname:=true; while not eof(input) do begin literal:=false; read(c); if c='\' then begin literal:=true; read(c); end; if literal or ((c<>'=') and (c<>'&')) then with data[nrdata] do if aname then name:=name+c else value:=value+c else begin if c='&' then begin inc (nrdata); aname:=true; end else aname:=false; end end; writeln ('<H1>Form Results :</H1>'); writeln ('You submitted the following name/value pairs :'); writeln ('<UL>'); for i:=1 to nrdata do writeln ('<LI> ',data[i].name,' = ',data[i].value); writeln ('</UL>'); end.
Page 25
While this program isn't shorter than the C program provided as an example at NCSA, it doesn't need any other units. everythig is done using standard Pascal procedures. Note that this program has a limitation: the length of names and values is limited to 255 characters. This is due to the fact that strings in Pascal have a maximal length of 255. It is of course easy to redefine the datarec record in such a way that longer values are allowed. In case you have to read the contents of a TEXTAREA form element, this may be needed.
Page 26
if aname then name:=name+p^ else value:=value+p^ else begin if p^='&' then begin inc (nrdata); aname:=true; end else aname:=false; end; inc(longint(p)); end; Writeln ('<H1>Form Results :</H1>'); Writeln ('You submitted the following name/value pairs :'); Writeln ('<UL>'); for i:=1 to nrdata do writeln ('<LI> ',data[i].name,' = ',data[i].value); Writeln ('</UL>'); end. Although it may not be written in the most elegant way, this program does the same thing as the previous one. It also suffers from the same drawback, namely the limited length of the value field of the datarec. This drawback can be remedied by redefining datarec as follows: type datarec = record; name,value : pchar; end; and assigning at run time enough space to keep the contents of the value field. This can be done with a getmem (data[nrdata].value,needed_number_of_bytes); call. After that you can do a strlcopy (data[nrdata].value,p,needed_number_of_bytes); to copy the data into place. You may have noticed the following unorthodox call : inc(longint(p)); Free Pascal doesn't give you pointer arithmetic as in C. However, longints and pointers have the same length (namely 4 bytes). Doing a type-cast to a longint allows you to do arithmetic on the pointer. Note however, that this is a non-portable call. This may work on the I386 processor, but not on a ALPHA processor (where a pointer is 8 bytes long). This will be remedied in future releases of Free Pascal.
PRODUCING OUTPUT
The previous section concentrated mostly on getting input from the web server. To send the reply to the server, you don't need to do anything special.You just print your data on standard output, and the Webserver will intercept this, and send your output to the WWW-client waiting for it. You can print anything you want, the only thing you must take care of is that you supply a Contentstype line, followed by an empty line, as follows: Writeln ('Content-type: text/html'); Writeln; { ...start output of the form... } And that's all there is to it !
Page 27
Windows then you also should be able to do CGI programming, but the above instructions will not work. If some kind soul is willing to write a section on CGI programming under Windows, I'd be willing to include it here.
Page 28
Target operating system -TDOS DOS extender by DJ Delorie -TOS2 OS/2 2.x -TLINUX Linux -TWin32 Windows 32 Bit -TGO32V2 version 2 of DJ Delorie DOS extender -u<x> undefines the symbol <x> -U unit options -Uls make static library from unit -Uld make dynamic library from unit -Un don't check the unit name -Up<x> same as -Fu<x> -Us compile a system unit -v<x> Be verbose. <x> is a combination of the following letters : e : Show errors (default) d : Show debug info w : Show warnings u : Show used files n : Show notes t : Show tried files h : Show hints m : Show defined macros i : Show general info p : Show compiled procedures l : Show linenumbers c : Show conditionals a : Show everything 0 : Show nothing (except errors) -X executable options -Xc link with the c library -Xs strip all symbols from executable Processor specific options: -A output format -Aatt AT&T assembler -Ao coff file using GNU AS -Aobj OMF file using NASM -Anasm coff file using NASM -Amasm assembler for the Microsoft/Borland/Watcom assembler -R assembler reading style -Ratt read AT&T style assembler -Rintel read Intel style assembler -Rdirect copy assembler text directly to assembler file -O optimizations -Oa simple optimizations -Og optimize for size -OG optimize for time -Ox optimize maximum -Oz uncertain optimizes (see docs) -O2 optimize for Pentium II (tm) -O3 optimize for i386 -O4 optimize for i486 -O5 optimize for Pentium (tm) -O6 optimizations for PentiumPro (tm) -? -h shows this help shows this help without waiting
-T<x>
Page 29
COMPILER ERRORS
The following is a list of general compiler errors. unexpected end of file this typically happens in on of the following cases : The source file ends befor then final end. statement. This happens mostly when the begin and end statements aren't balanced; An include file ends in the middle of a statement. A comment wasn't closed. duplicate identifier: The identifier was already declared in the current scope. syntax error: An error against the Turbo Pascal language was encountered. This happens typically when an illegal character is found in the sources file. Parser - syntax error An error against the Turbo Pascal language was encountered. This happens typically when an illegal character is found in the sources file. out of memory The compiler doesn't have enough memory to compile your program. There are several remedies for this: If you're using the build option of the compiler, try compiling the different units manually. If you're compiling a huge program, split it up in units, and compile these separately. If the previous two don't work, recompile the compiler with a bigger heap (you can use the -Ch option for this, See 5.1) unknown identifier The identifier encountered hasn't been declared, or is used outside the scope where it's defined. illegal character An illegal character was encountered in the input file. source too long The compiler cannot cope with source files longer than (???) procedure type INLINE not supported You tried to compile a program with C++ style inlining, and forgot to specify the -Si option (See 5.1). The compiler doesn't support C++ styled inlining by default. procedure type NEAR ignored This is a warning. NEAR is a construct for 8 or 16 bit programs. Since the compile generates 32 bit programs, it ignores this directive. procedure type FAR ignored This is a warning. FAR is a construct for 8 or 16 bit programs. Since the compile generates 32 bit programs, it ignores this directive. INTERRUPT ignored Interrupt procedures aren't possible on operating systems, other than DOS, it isn't allowed to take over an interrupt at the user level. (versions older than 0.9.2 didn't have INTERRUPT support. private methods shouldn't be VIRTUAL You declared a method in the private part of a object (class) as virtual. This is not allowed. Private methods cannot be overridden anyway.
Page 30
constructor can't be private or protected Constructors must be in the 'public' part of an object (class) declaration. destructor can't be private or protected Destructors must be in the 'public' part of an object (class) declaration. identifier not found local class definitions are not allowed Classes must be defined globally. anonym class definitions are not allowed type identifier expected The identifier is not a type, or you forgot to supply a type identifier. identifier already as type identifier declared You are trying to redefine a type. type identifier not defined The compiler encountered an unknown type. type mismatch This can happen in many cases: The variable you're assigning to is of a different type than the expression in the assignment. You are calling a function or procedure with parameters that are incompatible with the parameters in the function or procedure definition. statement expected illegal integer constant You made an exression which isn't an integer, and the compiler expects the result to be an integer. illegal expression expression too complicated - FPU stack overflow Your expression is too long for the compiler. You should try dividing the construct over multiple assignments. CONTINUE not allowed You're trying to use continue outside a loop construction. BREAK not allowed You're trying to use break outside a loop construction. illegal qualifier One of the following is appending : You're trying to access a field of a variable that is not a record. You're indexing a variable that is not an array. You're dereferencing a variable that is not a pointer. illegal counter variable The type of a for loop must be ordinal. ordinal value expected The expression must be of ordinal type (i.e. maximum a Longint) high range limit < low range limit You are declaring a subrange, and the lower limit is higher than the high limit of the range. illegal unit name The name of the unit doesn't match the file name. unknown format of unit file The unit the compiler is trying to read is corrupted, or generated with a newer version of the compiler. Reading PPU-File The unit the compiler is trying to read is corrupted, or generated with a newer version of the compiler. Invalid PPU-File entry The unit the compiler is trying to read is corrupted, or generated with a newer version of the compiler. circular unit use Two units are using each other in the interface part. This is only allowed in the implementation part. too many units
Page 31
Free Pascal has a limit of 1024 units in a program. You can change this behavior by changing the maxunits constant in the files.pas file of the compiler, and recompiling the compiler. illegal char constant The compiler expects a character constant, but finds something else. overloaded identifier isn't a function identifier The compiler encountered a symbol with the same name a s an overloaded function, but it isn't a function it can overload. overloaded functions have the same parameter list You're declaring overloaded functions, but with the same parameter list. Overloaded function must have at least 1 different parameter in their declaration. illegal parameter list You are calling a function with parameters that are of a different type than the declared parameters of the function. can't determine which overloaded function to call You're calling overloaded functions with a parameter that doesn't correspond to any of the declared function parameter lists. e.g. when you have declared a function with parameters word and longint, and then you call it with a parameter which is of type integer. forward declaration not solved: This can happen in two cases: This happens when you declare a function (in the interface part, or with a forward directive, but do not implement it. You reference a type which isn't declared in the current type block. input file not found Free Pascal cannot find the program or unit source file, or the included file isn't found. function header doesn't match the forward declaration You declared the function in the interface part, or with the forward directive, but define it with a different parameter list. unknown field identifier The field doesn't exist in the record definition. parameter list size exceeds 65535 bytes The I386 processor limits the parameter list to 65535 bytes (the RET instruction causes this) function nesting > 31 You can nest function definitions only 31 times. illegal compiler switch You included a compiler switch (i.e. {$... }) which the compiler doesn't know. can't open include file You want to include (i.e {$i file}) which the compiler doesn't find. Check if the filename is correct. record or class type expected The variable or expression isn't of the type record or class. only values can be jumped over in enumeration types Free Pascal allows enumeration constructions as in C. Given the following declaration two declarations: type a = (A_A,A_B,A_E=:6,A_UAS:=200); type a = (A_A,A_B,A_E=:6,A_UAS:=4); The second declaration would produce an error. A_UAS needs to have a value higher than A_E, i.e. at least 7. pointer type expected The variable or expression isn't of the type pointer. unit is compiled for another operating system The unit was compiled with a different target than the target for which you're compiling now. (see the option -T See 5.1). typed constants of classes are not allowed You cannot declare a constant of type class or object. duplicate case label
Page 32
You are specifying the same label 2 times in a case statement. range check error while evaluating constants The constants are out of their allowed range. illegal type conversion When doing a type-cast, you must take care that the sizes of the variable and the destination type are the same. class type expected The variable of expression isn't of the type class. functions variables of overloaded functions are not allowed You are trying to assign an overloaded function to a procedural variable. This isn't allowed. can't create assembler file The assembler output file cannot be opened. This can have many causes, but 'disk full' is a reasonable guess. string length must be a value from 1 to 255 The length of a string in Pascal is limited to 255 characters. You are trying to declare a string with length greater than 255. class identifier expected The variable isn't of type class. method identifier expected This identifier is not a method. function header doesn't match any method of this class You are defining a function as a class method, but no such function was declared in the class. use extended syntax of DISPOSE and NEW to generate instances of classes If you have a pointer a to a class type, then the statement new(a) will not initialize the class (i.e. the constructor isn't called), although space will be allocated. you should issue the new(a,init) statement. This will allocate space, and call the constructor of the class. file types must be var parameters You cannot specify files as value parameters, i.e. they must always be declared var parameters. string exceeds line You forgot probably to include the closing ' in a string, so it occupies multiple lines. illegal version of the unit: This unit was compiled with an earlier version of Free Pascal. illegal floating point constant destructors can't have parameters You are declaring a destructor with a parameter list. Destructor methods cannot have parameters. FAIL can be used in constructors only You are using the FAIl instruction outside a constructor method. records fields can be aligned to 1,2 or 4 bytes only You are specifying the {$PACKRECORDS n} with an illegal value for n. Only 1,2 or 4 are valid in this case. too many $ENDIFs or $ELSEs Your {$IFDEF ..} and {$ENDIF} statements aren't balanced. $ENDIF expected Your {$IFDEF ..} and {$ENDIF} statements aren't balanced. illegal call by reference parameters can't generate DEF file OS/2 only. The DEF file cannot be generated. all overloaded methods must be virtual if one is virtual: If you declare overloaded methods in a class, then they should either all be virtual, or none. You cannot mix them. overloaded methods which are virtual must have the same return type: If you declare virtual overloaded methods in a class definition, they must have the same return type. all overloaded virtual methods must support exceptions if one support exceptions: If you declare overloaded virtual methods in a class, then they should either all support exceptions, or none. You cannot mix them.
Page 33
EXPORT declared functions can't be called You are trying to call a procedure you declared as export. Due to the different calling scheme of Free Pascal and C, you cannot call such a function from within your Pascal program. EXPORT declared functions can't be nested You cannot declare a function or procedure within a function or procedure that was declared as an export procedure. methods can't be EXPORTed You cannot declare a procedure that is a method for an object as exported. That is, you methods cannot be called from a C program. SELF is only allowed in methods You are trying to use the self parameter outside an object's method. Only methods get passed the self parameters. call by var parameters have to match exactly When calling a function declared with var parameters, the variables in the function call must be of exactly the same type. There is no automatic type conversion. class identifier expected The variable isn't of type class. class isn't a super class of the current class When calling inherited methods, you are trying to call a method of a strange class. You can only call an inherited method of a parent class. methods can be only in other methods called direct with type identifier of the class A construction like sometype.somemethod is only allowed in a method. illegal type: pointer to class expected You specified an illegal type. possible illegal call of constructor or destructor (doesn't match to this context) class should have one destructor only You can declare only one destructor for a class. expression must be constructor call When using the extended syntax of new, you must specify the constructor method of the class you are trying to create. The procedure you specified is not a constructor. identifier idents no member When using the extended syntax of new, you must specify the constructor method of the class you are trying to create. The procedure you specified does not exist. expression must be destructor call When using the extended syntax of dispose, you must specify the destructor method of the class you are trying to dispose of. The procedure you specified is not a destructor. type conflict between set elements There is at least one set element which is of the wrong type, i.e. not of the set type. illegal expression in set constructor type conflict between set elements You are specifying elements of a different type for a set. illegal use of ':' expression type must be class or record type The expression isn't of type class or record. the operator / isn't defined for integer, the result will be real, use DIV instead When using the '/' operator in Free Pascal the result will be of type real, when used with integers. can't write PPU file There is a problem when writing to the unit file. illegal order of record elements When declaring a constant record, you specified the fields in the wrong order. the name of constructors must be INIT You are declaring a constructor with a name which isn't init, and the -Ss switch is in effect. See the -Ss switch (See 5.1). the name of constructors must be DONE You are declaring a constructor with a name which isn't done, and the -Ss switch is in effect. See
Page 34
the -Ss switch (See 5.1). set element type mismatch The type of the element doesn't equal the set type. illegal label declaration label not found A goto label was encountered, but the label isn't declared. GOTO and LABEL are not supported (use command line switch -Sg) You must compile a program which has labels and goto statements with the -Sg switch. By default, label and goto aren't supported. set expected The variable or expression isn't of type set. identifier isn't a label The identifier specified after the goto isn't of type label. label already defined You're attempting to define a label two times. (i.e. you put the same label on two different places.) label isn't defined: A label was declared, but not defined. constructors and destructors must be methods You're declaring a procedure as destructor or constructor, when the procedure isn't a class method. error when assembling An error occurred when assembling. This can have many causes. identifier not used: This is a warning. The identifier was declared (locally or globally) but wasn't used (locally or globally). functions with void return value can't return any value In Free Pascal, you can specify a return value for a function when using the exit statement. This error occurs when you try to do this with a procedure. Procedures cannot return a value. Hmmm..., this code can't be much efficient You construction seems dubious to the compiler. unreachable code You specified a loop which will never be executed. Example: while false do begin {.. code ...} end; This overloaded function can't be local (must be exported) You are defining a overloaded function in the implementation part of a unit, but there is no corresponding declaration in the interface part of the unit. It's not possible to overload this operator You are trying to overload an operator which cannot be overloaded. Abstract methods can't be called direct Free Pascal understands the abstract keyword. the mix of CLASSES and OBJECTS are not allowed You cannot use object and class intertwined. macro buffer overflow while reading or expanding a macro Your macro or it's result was too long for the compiler. keyword redefined as macro has no effect You cannot redefine keywords with macros. extension of macros exceeds a deep of 16, perhaps there is a recursive macro definition (crashes the compiler) When expanding a macro macros have been nested to a level of 16. ENDIF without IF(N)DEF Your code contains more {$ENDIF} than {$IF(N)DEF} statements. user defined: A user defined warning occurred. see also the Programmer's guide\
Page 35
linker: Duplicate symbol: Two global symbols in the code have the same name. linker: Error while reading object file The linker couldn't read the object file (the assembled file). linker: object file not found The linker didn't find the object file (the assembled file). linker: illegal magic number in file: The linker cannot determine the type of a file it wants to link in. The type of a link file is specified using a magic number, which is some pre-defined constant, unique for each system. The extended syntax of new or dispose isn't allowed for a class You cannot generate an instance of a class with the extended syntax of new. The constructor must be used for that. For the same reason, you cannot call Dispose to de-allocate an instance of a class, the destructor must be used for that. To generate an instance of a class or an object with an abstract method isn't allowed You are trying to generate an instance of a class which has an abstract method that wasn't overridden. Only virtual methods can be abstract You are declaring a method as abstract, when it isn't declared to be virtual. Abstract methods shouldn't have any definition (with function body) Abstract methods can only be declared, you cannot implement them. They should be overridden by a descendant class. can't call the assembler An error occurred when calling the assembler. can't call o2obj An error occurred when calling the o to obj conversion program. asm syntax error There is an error in the assembly language. register name expected There is an error in the assembly language. The assembler expected a register and got something else. asm size mismatch There is an error in the assembly language. The sizes of operands and registers don't match. no instr match, There is an error in the assembly language. An unknown instruction was encountered. can't compile unit: When trying to do a build, the compiler cannot compile one of the units. Re-raise isn't possible there You are trying to raise an exception where it isn't allowed. You can only raise exceptions in an except block. Syntax error while parsing a conditional compiling expression Evaluating a conditional compiling expression Keyword redefined as macro has no effect compiler switches aren't allowed in (* ... *) styled comments No DLL File specified Illegal open parameter Illegal floating point constant string types doesn't match, because of $V+ mode Only class methods can be referred with class references Only class methods can be accessed in class methods Constant and CASE types do not match The symbol can't be exported from a library A virtual method must be overridden using the OVERRIDE directive: There is no method in an ancestor class to be overridden: No member is provided to access property Illegal symbol for property access
Page 36
Cannot write a protected field of an object range check error in set constructor or duplicate set element Pointer to class expected Operator is not overloaded Variable or type indentifier expected Assembler incompatible with function return value Procedure overloading is switched off Comparative operator must return a boolean value Use of unsupported feature! absolute can only be associated to ONE variable absolute can only be associated a var or const succ or pred on enums with assignments not possible Array properties aren't allowed at this point No property found to override Only one default property is allowed, found inherited default property in class The default property must be an array property Internal Error in SymTableStack() Error in type defenition Only static variables can be used in static methods or outside methods Invalid call to tvarsym.mangledname() illegal type declaration of set elements Forward class definition not resolved identifier idents no member The use of a far pointer isn't allowed there procedure call with stackframe ESP/SP Abstract methods can't be called directly Internal Error in getfloatreg(), allocation failure Unknown float type SecondVecn() base defined twice Extended cg68k not supported 32-bit unsigned not supported in MC68000 mode inline() Stack limit excedeed in local routine Internal Error in second
Page 37
The number given to the Getdir function specifies a non-existent disk. 16 Cannot remove current directory You get this if you try to remove the current diirectory. 17 Cannot rename across drives You cannot rename a file such that it would end up on another disk or partition. 100 Disk read error DOS only. An error occurred when reading from disk. Typically when you try to read past the end of a file. 101 Disk write error DOS only. Reported when the disk is full, and you're trying to write to it. 102 File not assigned This is reported by Reset, Rewrite, Append, Rename and Erase, if you call them with an unassigne function as a parameter. 103 File not open Reported by the following functions : Close , Read, Write, Seek, EOf, FilePos, FileSize, Flush, BlockRead, and BlockWrite if the file isn't open. 104 File not open for input Reported by Read, BlockRead, Eof, Eoln, SeekEof or SeekEoln if the file isn't opened with Reset. 105 File not open for output Reported by write if a text file isn't opened with Rewrite. 106 Invalid numeric format Reported when a non-numerice value is read from a text file, when a numeric value was expected. 150 Disk is write-protected (Critical error, DOS only.) 151 Bad drive request struct length (Critical error, DOS only.) 152 Drive not ready (Critical error, DOS only.) 154 CRC error in data (Critical error, DOS only.) 156 Disk seek error (Critical error, DOS only.) 157 Unknown media type (Critical error, DOS only.) 158 Sector Not Found (Critical error, DOS only.) 159 Printer out of paper (Critical error, DOS only.) 160 Device write fault (Critical error, DOS only.) 161 Device read fault (Critical error, DOS only.) 162 Hardware failure (Critical error, DOS only.) 200 Division by zero You are dividing a number by zero. 201 Range check error If you compiled your program with range checking on, then you can get this error in the following cases: An array was accessed with an index outside its declared range. You're trying to assign a value to a variable outside its range (for instance a enumerated type). 202 Stack overflow error The stack has grown beyond itss maximum size. This error can easily occur if you have recursive functions. 203 Heap overflow error The heap has grown beyond its boundaries, ad you are rying to get more memory. Please note that
Page 38
Free Pascal provides a growing heap, i.e. the heap will try to allocate more memory if needed. However, if the heap has reached the maximum size allowed by the operating system or hardware, then you will get this error. 204 Invalid pointer operation This you will get if you call dispose or Freemem with an invalid pointer (notably, Nil) 205 Floating point overflow You are trying to use or produce too large real numbers. 206 Floating point underflow You are trying to use or produce too small real numbers. 207 Invalid floating point operation Can occur if you try to calculate the square root or logarithm of a negative number. 210 Object not initialized When compiled with range checking on, a program will report this error if you call a virtal method without having initialized the VMT. 211 Call to abstract method Your program tried to execute an abstract virtual method. Abstract methods should be overridden, and the overriding method should be called. 212 Stream registration error This occurs when an invalid type is registered in the objects unit. 213 Collection index out of range You are trying to access a collection item with an invalid index. (objects unit) 214 Collection overflow error The collection has reached its maximal size, and you are trying to add another element. (objects unit) 216 General Protection fault You are trying to access memory outside your appointed memory.
Page 39
This occurs when trying to use a non-valid prefix instruction Asm syntax error - Trying to add more than one prefix This occurs when you try to add more than one prefix instruction Asm syntax error - Opcode not found You have tried to use an unsupported or unknown opcode Constant value out of bounds This error is reported when the constant parser determines that the value you are using is out of bounds, either with the opcode or with the constant declaration used. Non-label pattern contains @ This only applied to the m68k and Intel styled assembler, this is reported when you try to use a nonlabel identifier with a '@' prefix. Internal error in Findtype() Internal Error in ConcatOpcode() Internal Errror converting binary Internal Errror converting hexadecimal Internal Errror converting octal Internal Error in BuildScaling() Internal Error in BuildConstant() internal error in BuildReference() internal error in HandleExtend() Internal error in ConcatLabeledInstr() These errors should never occur, if they do then you have found a new bug in the assembler parsers. Please contact one of the developers. Opcode not in table, operands not checked This warning only occurs when compiling the system unit, or related files. No checking is performed on the operands of the opcodes. @CODE and @DATA not supported This Turbo Pascal construct is not supported. SEG and OFFSET not supported This Turbo Pascal construct is not supported. Modulo not supported Modulo constant operation is not supported. Floating point binary representation ignored Floating point hexadecimal representation ignored Floating point octal representation ignored These warnings occur when a floating point constant are declared in a base other then decimal. No conversion can be done on these formats. You should use a decimal representation instead. Identifier supposed external This warning occurs when a symbol is not found in the symolb table, it is therefore considered external. Functions with void return value can't return any value in asm code Only routines with a return value can have a return value set. Error in binary constant Error in octal constant Error in hexadecimal constant Error in integer constant These errors are reported when you tried using an invalid constant expression, or that the value is out of range. Invalid labeled opcode Asm syntax error - error in reference Invalid Opcode Invalid combination of opcode and operands Invalid size in reference Invalid middle sized operand Invalid three operand opcode Assembler syntax error
Page 40
Invalid operand type You tried using an invalid combination of opcode and operands, check the syntax and if you are sure it is correct, please contact one of the developers. Unknown identifier The identifier you are trying to access does not exist, or is not within the current scope. Trying to define an index register more than once Trying to define a segment register twice Trying to define a base register twice You are trying to define an index/segment register more then once. Invalid field specifier The record or object field you are trying to access does not exist, or is incorrect. Invalid scaling factor Invalid scaling value Scaling value only allowed with index Allowed scaling values are 1,2,4 or 8. Cannot use SELF outside a method You are trying to access the SELF identifier for objects outside a method. Invalid combination of prefix and opcode This opcode cannot be prefixed by this instruction Invalid combination of override and opcode This opcode cannot be overriden by this combination Too many operands on line At most three operand instructions exist on the m68k, and i386, you are probably trying to use an invalid syntax for this opcode. Duplicate local symbol You are trying to redefine a local symbol, such as a local label. Unknown label identifer Undefined local symbol local symbol not found inside asm statement This label does not seem to have been defined in the current scope Assemble node syntax error Not a directive or local symbol The assembler statement is invalid, or you are not using a recognized directive.
Page 41
Intel style (eg: rep ds stosb) segment overrides are not support by the assembler parser. Expressions of the form [sreg:reg...] are currently not supported To access a memory operand in a different segment, you should use the sreg:[reg...] snytax instead of [sreg:reg...] Size suffix and destination register do not match In intel AT&T syntax, you are using a register size which does not concord with the operand size specified. Invalid assembler syntax. No ref with brackets Trying to use a negative index register Local symbols not allowed as references Invalid operand in bracket expression Invalid symbol name: Invalid Reference syntax Invalid string as opcode operand: Null label references are not allowed Using a defined name as a local label Invalid constant symbol Invalid constant expression / at beginning of line not allowed NOR not supported Invalid floating point register name Invalid floating point constant: Asm syntax error - Should start with bracket Asm syntax error - register: Asm syntax error - in opcode operand Invalid String expression Constant expression out of bounds Invalid or missing opcode Invalid real constant expression Parenthesis are not allowed Invalid Reference Cannot use __SELF outside a method Cannot use __OLDEBP outside a nested procedure Invalid segment override expression Strings not allowed as constants Switching sections is not allowed in an assembler block Invalid global definition Line separator expected Invalid local common definition Invalid global common definition assembler code not returned to text invalid opcode size Invalid character: < Invalid character: > Unsupported opcode Invalid suffix for intel assembler Extended not supported in this mode Comp not supported in this mode Invalid Operand: Override operator not supported
Page 42
Invalid Register list in movem/fmovem The register list is invalid, normally a range of registers should be separated by - and individual registers should be separated by a slash. Invalid Register list for opcode 68020+ mode required to assemble
Page 43
Page 44
define pst set $pos=&$arg0 set $strlen = {byte}$pos print {char}&$arg0.st@($strlen+1) end document pst Print out a pascal string end
Page 45
Page 46
Page 47
Contents
Compiler directives Local directives $F : Far or near functions $I : Input/Output checking $I : Include file $L : Link object file $I386_XXX : Specify assembler format $MMX : MMX support $OUTPUT_FORMAT : Specify the output format $V : Var-string checking Global directives $A : Align Data $B : Complete boolean evaluation $D : Debugging symbols $E : Emulation of coprocessor $G : Generate 80286 code $L : Local symbol information $N : Numeric processing $O : Overlay code generation $Q : Overflow checking $R : Range checking $S : Stack checking $X : Extended syntax Using conditionals, Messages and macros Conditionals Messages Macros Using assembly language Intel syntax AT&T Syntax Calling mechanism Telling the compiler what registers have changed Linking issues Declaring an external function or procedure Explicitly linking an object file in your program Linking your program to a library Making a shared library Adapting your code Compiling libraries Moving units into a library Unit searching strategy Objects Constructor and Destructor calls Memory storage of objects The Virtual Method Table Generated code Units Programs MMX support
Page 48
Memory issues
What is it about ? Saturation support Restrictions of MMX support Supported MMX operations Optimizing MMX support The 32-bit model. The stack The heap grows Using Blocks Using the split heap Accessing DOS memory under the Go32 extender
Anatomy of a unit file List of compiler source files Compiler limits Optimizing techniques used in the compiler.
Page 49
LOCAL DIRECTIVES
Local directives have no command-line counterpart. They influence the compiler's behaviour from the moment they're encountered until the moment another switch annihilates their behaviour, or the end of the unit or program is reached. $F
This directive is recognized for compatibility with Turbo Pascal. Under the 32-bit programming model, the concept of near and far calls have no meaning, hence the directive is ignored. A warning is printed to the screen, telling you so. As an example, : the following piece of code : {$F+} Procedure TestProc; begin Writeln ('Hello From TestProc'); end; begin testProc end. Generates the following compiler output: malpertuus: >pp -vw testf Compiler: ppc386 Units are searched in: /home/michael;/usr/bin/;/usr/lib/ppc/0.9.1/linuxunits Target OS: Linux Compiling testf.pp testf.pp(1) Warning: illegal compiler switch 7739 kB free Calling assembler... Assembled... Calling linker... 12 lines compiled, 1.00000000000000E+0000 You can see that the verbosity level was set to display warnings. If you declare a function as Far (this has the same effect as setting it between {$F+}...{$F-}
Page 50
directives), the compiler also generates a warning : testf.pp(3) Warning: FAR ignored The same story is true for procedures declared as Near. The warning displayed in that case is: testf.pp(3) Warning: NEAR ignored $I
: Input/Output checking
The {$I-} directive tells the compiler not to generate input/output checking code in your program. If you compile using the -Ci compiler switch, the Free Pascal compiler inserts input/output checking code after every input/output call in your program. If an error occurred during input or output, then a run-time error will be generated. Use this switch if you wish to avoid this behavior. If you still want to check if something went wrong, you can use the IOResult function to see if everything went without problems. Conversely, {$I+} will turn error-checking back on, until another directive is encountered which turns it off again. The most common use for this switch is to check if the opening of a file went without problems, as in the following piece of code: ... assign (f,'file.txt'); {$I-} rewrite (f); {$I+} if IOResult<>0 then begin Writeln ('Error opening file : "file.txt"'); exit end; ... $I
: Include file
The {$I filename} directive tells the compiler to read further statements from the file filename. The statements read there will be inserted as if they occurred in the current file. The compiler will append the .pp extension to the file if you don't specify an extension yourself. Do not put the filename between quotes, as they will be regarded as part of the file's name. You can nest included files, but not infinitely deep. The number of files is restricted to the number of file descriptors available to the Free Pascal compiler. Contrary to Turbo Pascal, include files can cross blocks. I.e. you can start a block in one file (with a Begin keyword) and end it in another (with a End keyword). The smallest entity in an include file must be a token, i.e. an identifier, keyword or operator. $L
The {$L filename} directive tells the compiler that the file filename should be linked to your program. You can only use this directive in a program. If you do use it in a unit, the compiler will not complain, but simply ignores the directive. The compiler will not look for the file in the unit path. The name will be passed to the linker exactly as you've typed it. Since the files name is passed directly to the linker, this means that on LINUX systems, the name is case sensitive, and must be typed exactly as it appears on your system. Remark : Take care that the object file you're linking is in a format the linker understands. Which format this is, depends on the platform you're on. Typing ld on th command line gives a list of formats ld knows about. You can pass other files and options to the linker using the -k command-line option. You can specify more than one of these options, and they will be passed to the linker, in the order that you specified them
Page 51
on the command line, just before the names of the object files that must be linked. $I386_XXX
This switch informs the compiler what kind of assembler it can expect in an asm block. The XXX should be replaced by one of the following: att Indicates that asm blocks contain AT&T syntax assembler. intel Indicates that asm blocks contain Intel syntax assembler. direct Tells the compiler that asm blocks should be copied directly to the assembler file. These switches are local, and retain their value to the end of the unit that is compiled, unless they are replaced by another directive of the same type. The command-line switch that corresponds to this switch is -R. $MMX
: MMX support
As of version 0.9.8, Free Pascal supports optimization for the MMX Intel processor (see also 7). This optimizes certain code parts for the MMX Intel processor, thus greatly improving speed. The speed is noticed mostly when moving large amounts of data. Things that change are Data with a size that is a multiple of 8 bytes is moved using the movq assembler instruction, which moves 8 bytes at a time When MMX support is on, you aren't allowed to do floating point arithmetic. You are allowed to move floating point data, but no arithmetic can be done. If you wish to do floating point math anyway, you must first switch of MMX support and clear the FPU using the emms function of the cpu unit. The following example will make this more clear: Program MMXDemo; uses cpu; var d1 : double; a : array[0..10000] of double; i : longint;
begin d1:=1.0; {$mmx+} { floating point data is used, but we do _no_ arithmetic } for i:=0 to 10000 do a[i]:=d2; { this is done with 64 bit moves } {$mmx-} emms; { clear fpu } { now we can do floating point arithmetic } .... end. See, however, the chapter on MMX (7) for more information on this topic. $OUTPUT_FORMAT
{$OUTPUT_FORMAT format} has the same functionality as the -A command-line option : It tells the compiler what kind of object file must be generated. You can specify this switch only befor the Program or Unit clause in your source file. The different kinds of formats are shown in table (1.1).
Page 52
Table 1.1: Formats generated by the compiler Switch value att o obj wasm $V
Generated format AT&T assembler file. Unix object file. OMF file. assembler for the Watcom assembler.
: Var-string checking
When in the + state, the compiler checks that strings passed as parameters are of the same, identical, string type as the declared parameters of the procedure.
Page 53
COMPILER DIRECTIVES
Free Pascal supports compiler directives in your source file. They are not the same as Turbo Pascal directives, although some are supported for compatibility. There is a distinction between local and global directives; local directives take effect from the moment they are encountered, global directives have an effect on all of the compiled code. Local directives Global directives
GLOBAL DIRECTIVES
Global directives affect the whole of the compilation process. That is why they also have a command line counterpart. The command-line counterpart is given for each of the directives. $A
: Align Data
This switch is recognized for Turbo Pascal Compatibility, but is not yet implemented. The alignment of data will be different in any case, since Free Pascal is a 32-bit compiler. $B
This switch is understood by the Free Pascal compiler, but is ignored. The compiler always uses shortcut evaluation, i.e. the evaluation of a boolean expression is stopped once the result of the total exression is known with certainty. So, in the following example, the function Bofu, which has a boolean result, will never get called. If False and Bofu then ... $D
: Debugging symbols
When this switch is on, the compiler inserts GNU debugging information in the executable. The effect of this switch is the same as the command-line switch -g. By default, insertion of debugging information is off. $E
: Emulation of coprocessor
This directive controls the emulation of the coprocessor. On the i386 processor, it is supported for compatibility with Turbo Pascal. The compiler itself doesn't do the emulation of the coprocessor. Under DOS, the DOS extender does this, and under LINUX, the kernel takes care of the coprocessor support. If you use the Motorola 680x0 version, then the switch is recognized, as there is no extender to emulate the coprocessor, so the compiler must do that by itself. There is no command-line counterpart for this directive. $G
This option is recognised for Turbo Pascal cmpatibility, but is ignored, because the compiler needs at least a 386 or higher class processor.
Page 54
$L
This switch (not to be confused with the {$L file} file linking directive) is recognised for Turbo Pascal compatibility, but is ignored. generation of symbol information is controlled by the $D switch. $N
: Numeric processing
This switch is recognised for Turbo Pascal compatibility, but is otherwise ignored, since the compiler always uses the coprocessor for floating point mathematics. $O
This switch is recognised for Turbo Pascal compatibility, but is otherwise ignored, since the compiler requires a 386 or higher computer, with at least 4 Mb. of ram. $Q
: Overflow checking
The {$Q+} directive turns on integer overflow checking. This means that the compiler inserts code to check for overflow when doing computations with an integer. When an overflow occurs, the run-time library will print a message Overflow at xxx, and exit the program with exit code 1. Using the {$Q-} switch switches off the overflow checking code generation. The generation of overflow checking code can also be controlled using the -Co command line compiler option (see Users' guide\). $R
: Range checking
By default, the computer doesn't generate code to check the ranges of array indices, enumeration types, subrange types, etc. Specifying the {$R+} switch tells the computer to generate code to check these indices. If, at run-time, an index or enumeration type is specified that is out of the declared range of the compiler, then a run-time error is generated, and the program exits with exit code 1. The {$R-} switch tells the compiler not to generate range checking code. This may result in faulty program behaviour, but no run-time errors will be generated. Remark: this has not been implemented completely yet. $S
: Stack checking
The {$S+} directive tells the compiler to generate stack checking code. This generates code to check if a stack overflow occurred, i.e. to see whether the stack has grown beyond its maximally allowed size. If the stack grows beyond the maximum size, then a run-time error is generated, and the program will exit with exit code 1. Specifying {$S-} will turn generation of stack-checking code off. There is no command-line switch which is equivalent to this directive. Remark: In principle, the stack is almost unlimited, i.e. limited to the total free amount of memory on the computer. $X
: Extended syntax
Extended syntax allows you to drop the result of a function. This means that you can use a function call as if it were a procedure. Standard this feature is on. You can switch it off using the {$X-} directive. The following, for instance, will not compile : function Func (var Arg : sometype) : longint;
Page 55
{ declaration of Func }
{$X-} Func (A); The reason this construct is supported is that you may wish to call a function for certain side-effects it has, but you don't need the function result. In this case you don't need to assign the function result, saving you an extra variable. The command-line compiler switch -Sa1 has the same effect as the {$X+} directive.
Page 56
CONDITIONALS
The rules for using conditional symbols are the same as under Turbo Pascal. Defining a symbol goes as follows: {$Define Symbol } From this point on in your code, the compiler know the symbol Symbol Symbols are, like the Pascal language, case insensitive. You can also define a symbol on the command line. the -dSymbol option defines the symbol Symbol. You can specify as many symbols on the command line as you want. Undefining an existing symbol is done in a similar way: {$Undef Symbol } If the symbol didn't exist yet, this doesn't do anything. If the symbol existed previously, the symbol will be erased, and will not be recognized any more in the code following the {$Undef ...} statement. You can also undefine symbols from the command line with the -u command-line switch.. To compile code conditionally, depending on whether a symbol is defined or not, you can enclose the code in a {$ifdef Symbol} .. {$endif} pair. For instance the following code will never be compiled : {$Undef MySymbol} {$ifdef Mysymbol} DoSomething; ... {$endif} Similarly, you can enclose your code in a {$Ifndef Symbol} .. {$endif} pair. Then the code between the pair will only be compiled when the used symbol doesn't exist. For example, in the following example, the call to the DoSomething will always be compiled: {$Undef MySymbol} {$ifndef Mysymbol} DoSomething; ... {$endif} You can combine the two alternatives in one structure, namely as follows {$ifdef Mysymbol} DoSomething; {$else} DoSomethingElse {$endif} In this example, if MySymbol exists, then the call to DoSomething will be compiled. If it doesn't exist, the call to DoSomethingElse is compiled. The Free Pascal compiler defines some symbols before starting to compile your program or unit. You can use these symbols to differentiate between different versions of the compiler, and between different compilers. In table (2.1), a list of pre-defined symbols is given. In that table, you should change v with the version number of the compiler you're using, r with the release number and p with the patch-number of the compiler. 'OS' needs to be changed by the type of operating system. Currently this can be one of DOS,
Page 57
GO32V2, LINUX, OS2 or WIN32. This symbol is undefined if you specify a target that is different from the platform you're compiling on. the -TSomeOS option on the command line will define the SomeOS symbol, and will undefined the existing platform symbol. Table 2.1: Symbols defined by the compiler. Free VERv VERv_r VERv_r_p OS As an example : Version 0.9.1 of the compiler, running on a Linux system, defines the following symbols before reading the command line arguments: FPC, VER0, VER0_9, VER0_9_1 and LINUX. Specifying -TOS2 on the command-line will undefine the LINUX symbol, and will define the OS2 symbol. Remark: Symbols, even when they're defined in the interface part of a unit, are not available outside that unit. Free Pascal supports the {$IFOPT } directive for Turbo Pascal compatibility, but doesn't act on it. It always rejects the condition, so code between {$IFOPT } and {$Endif} is never compiled. Except for the Turbo Pascal constructs, from version 0.9.8 and higher, the Free Pascal compiler also supports a stronger conditional compile mechanism: The {$If } construct. The prototype of this construct is as follows : {$If expr} CompileTheseLines; {$else} BetterCompileTheseLines; {$endif} In this directive expr is a Pascal expression which is evaluated using strings, unless both parts of a comparision can be evaluated as numbers, in which case they are evaluated using numbers. If the complemete expression evaluates to '0', then it is considered false and rejected. Otherwise it is considered true and accepted. This may have unsexpected consequences : {$If 0} Will evaluate to False and be rejected, while {$If 00} Will evaluate to True. You can use any Pascal operator to construct your expression : =, <>, >, <, >=, <=, AND, NOT, OR and you can use round brackets to change the precedence of the operators. The following example shows you many of the possibilities: {$ifdef fpc} var y : longint; {$else fpc} var z : longint; {$endif fpc} var x : longint;
begin {$if (fpc_version=0) and (fpc_release>6) and (fpc_patch>4)} {$info At least this is version 0.9.5} {$else}
Page 58
{$fatalerror Problem with version check} {$endif} {$define x:=1234} {$if x=1234} {$info x=1234} {$else} {$fatalerror x should be 1234} {$endif} {$if 12asdf and 12asdf} {$info $if 12asdf and 12asdf is ok} {$else} {$fatalerror $if 12asdf and 12asdf rejected} {$endif} {$if 0 or 1} {$info $if 0 or 1 is ok} {$else} {$fatalerror $if 0 or 1 rejected} {$endif} {$if 0} {$fatalerror $if 0 accepted} {$else} {$info $if 0 is ok} {$endif} {$if 12=12} {$info $if 12=12 is ok} {$else} {$fatalerror $if 12=12 rejected} {$endif} {$if 12<>312} {$info $if 12<>312 is ok} {$else} {$fatalerror $if 12<>312 rejected} {$endif} {$if 12<=312} {$info $if 12<=312 is ok} {$else} {$fatalerror $if 12<=312 rejected} {$endif} {$if 12<312} {$info $if 12<312 is ok} {$else} {$fatalerror $if 12<312 rejected} {$endif} {$if a12=a12} {$info $if a12=a12 is ok} {$else}
Page 59
{$fatalerror $if a12=a12 rejected} {$endif} {$if a12<=z312} {$info $if a12<=z312 is ok} {$else} {$fatalerror $if a12<=z312 rejected} {$endif} {$if a12<z312} {$info $if a12<z312 is ok} {$else} {$fatalerror $if a12<z312 rejected} {$endif} {$if not(0)} {$info $if not(0) is OK} {$else} {$fatalerror $if not(0) rejected} {$endif} {$info *************************************************} {$info * Now have to follow at least 2 error messages: *} {$info *************************************************} {$if not(0} {$endif} {$if not(<} {$endif} end. As you can see from the example, this construct isn't useful when used with normal symbols, but it is if you use macros, which are explained in section (2.3), they can be very useful. When trying this example, you must switch on macro support, with the -Sm command-line switch.
MESSAGES
Free Pascal lets you define normal, warning and error messages in your code. Messages can be used to display useful information, such as copyright notices, a list of symbols that your code reacts on etc. Warnings can be used if you think some part of your code is still buggy, or if you think that a certain combination of symbols isn't useful. In general anything which may cause problems when compiling. Error messages can be useful if you need a certain symbol to be defined to warn that a certain variable isn't defined or so, or when the compiler version isn't suitable for your code. The compiler treats these messages as if they were generated by the compiler. This means that if you haven't turned on warning messages, the warning will not e displayed. Errors are always displayed, and the compiler stops as if an error had occurred. For messages, the syntax is as follows : {$Message Message text } Or {$Info Message text } For notes: {$Note Message text }
Page 60
For warnings: {$Warning Warning Message text } For errors : {$Error Error Message text } Lastly, for fatal errors : {$FatalError Error Message text } or {$Stop Error Message text } The difference between $Error and $FatalError or $Stop messages is that when the compiler encounters an error, it still continues to compile. With a fatal error, the compiler stops. Remark : You cannot use the '}' character in your message, since this will be treated as the closing brace of the message. As an example, the following piece of code will generate an error when the symbol RequiredVar isn't defined: {$ifndef RequiredVar} {$Error Requiredvar isn't defined !} {$endif} But the compiler will continue to compile. It will not, however, generate a unit file or a program (since an error occurred).
MACROS
Macros are very much like symbols in their syntax, the difference is that macros have a value whereas a symbol simply is defined or is not defined. If you want macro support, you need to specify the -Sm command-line switch, otherwise your macro will be regarded as a symbol. Defining a macro in your program is done in the same way as defining a symbol; in a {$define } preprocessor statement: {$define ident:=expr} If the compiler encounters ident in the rest of the source file, it will be replaced immediately by expr. This replacement works recursive, meaning that when the compiler expanded one of your macros, it will look at the resulting expression again to see if another replacement can be made. You need to be careful with this, because an infinite loop can occur in this manner. Here are two examples which illustrate the use of macros: {$define sum:=a:=a+b;} ... sum { will be expanded to 'a:=a+b;' remark the absence of the semicolon} ... {$define b:=100} sum { Will be expanded recursively to a:=a+100; } ... The previous example could go wrong : {$define sum:=a:=a+b;} ... sum { will be expanded to 'a:=a+b;' remark the absence of the semicolon} ... {$define b=sum} { DON'T do this !!!} sum { Will be infinitely recursively expanded... } ... On my system, the last example results in a heap error, causing the compiler to exit with a run-time error 203. Remark: Macros defined in the interface part of a unit are not available outside that unit ! They can just be used as a notational convenience, or in conditional compiles. By default, from version 0.9.8 of the compiler on, the compiler predefines three macros, containing the
Page 61
version number, the release number and the patch number. They are listed in table (2.2). Table 2.2: Predefined macros Symbol Contains FPC_VERSION The version number of the compiler. FPC_RELEASE The release number of the compiler. FPC_PATCH The patch number of the compiler. Remark: Don't forget that macros support isn't on by default. You need to compile with the -Sm command-line switch.
Page 62
INTEL SYNTAX
As of version 0.9.7, Free Pascal supports Intel syntax in it's asm blocks. The Intel syntax in your asm block is converted to AT&T syntax by the compiler, after which it is inserted in the compiled source. The supported assembler constructs are a subset of the normal assembly syntax. In what follows we specify what constructs are not supported in Free Pascal, but which exist in Turbo Pascal: The TBYTE qualifier is not supported. The & identifier override is not supported. The HIGH operator is not supported. The LOW operator is not supported. The OFFSET and SEG operators are not supported. use LEA and the various Lxx instructions instead. Expressions with constant strings are not allowed. Access to record fields via parenthesis is not allowed Typecasts with normal pascal types are not allowed, only recognized assembler typecasts are allowed. Example: mov al, byte ptr MyWord -- allowed, mov al, byte(MyWord) -- allowed, mov al, shortint(MyWord) -- not allowed. Pascal type typecasts on constants are not allowed. Example: const s= 10; const t = 32767; in Turbo Pascal: mov al, byte(s) -- useless typecast. mov al, byte(t) -- syntax error! In this parser, either of those cases will give out a syntax error. Constant references expressions with constants only are not allowed (in all cases they do not work in protected mode, under linux i386). Examples: mov al,byte ptr ['c'] -- not allowed. mov al,byte ptr [100h] -- not allowed. (This is due to the limitation of Turbo Assembler). Brackets within brackets are not allowed Expressions with segment overrides fully in brackets are presently not supported, but they can easily be implemented in BuildReference if requested. Example: mov al,[ds:bx] -- not allowed use instead: mov al,ds:[bx] Possible allowed indexing are as follows:
Page 63
Sreg:[REG+REG*SCALING+/-disp] SReg:[REG+/-disp] SReg:[REG] SReg:[REG+REG+/-disp] SReg:[REG+REG*SCALING] Where Sreg is optional and specifies the segment override. Notes: 1. The order of terms is important contrary to Turbo Pascal. 2. The Scaling value must be a value, and not an identifier to a symbol. Examples: const myscale = 1; ... mov al,byte ptr [esi+ebx*myscale] -- not allowed. use: mov al, byte ptr [esi+ebx*1] Possible variable identifier syntax is as follows: (Id = Variable or typed constant identifier.) 1. ID 2. [ID] 3. [ID+expr] 4. ID[expr] Possible fields are as follow: 1. ID.subfield.subfield ... 2. [ref].ID.subfield.subfield ... 3. [ref].typename.subfield ... Local Labels: Contrary to Turbo Pascal, local labels, must at least contain one character after the local symbol indicator. Example: @: -- not allowed use instead, for example: @1: -- allowed Contrary to Turbo Pascal local references cannot be used as references, only as displacements. example: lds si,@mylabel -- not allowed Contrary to Turbo Pascal, SEGCS, SEGDS, SEGES and SEGSS segment overrides are presently not supported. (This is a planned addition though). Contrary to Turbo Pascal where memory sizes specifiers can be practically anywhere, the Free Pascal Intel inline assembler requires memory size specifiers to be outside the brackets. example: mov al,[byte ptr myvar] -- not allowed. use: mov al,byte ptr [myvar] -- allowed. Base and Index registers must be 32-bit registers. (limitation of the GNU Assembler). XLAT is equivalent to XLATB. Only Single and Double FPU opcodes are supported. Floating point opcodes are currently not supported (except those which involve only floating point registers). The Intel inline assembler supports the following macros : @Result represents the function result return value. Self represents the object method pointer in methods.
Page 64
AT&T SYNTAX
Free Pascal uses the gnu as assembler to generate its object files. Since the gnu assembler uses AT&T assembly syntax, the code you write should use the same syntax. The differences between AT&T and Intel syntax as used in Turbo Pascal are summarized in the following: The opcode names include the size of the operand. In general, one can say that the AT&T opcode name is the Intel opcode name, suffixed with a 'l', 'w' or 'b' for, respectively, longint (32 bit), word (16 bit) and byte (8 bit) memory or register references. As an example, the Intel construct 'mov al bl is equivalent to the AT&T style 'movb %bl,%al' instruction. AT&T immediate operands are designated with '$', while Intel syntax doesn't use a prefix for immediate operands. Thus the Intel construct 'mov ax, 2' becomes 'movb $2, %al' in AT&T syntax. AT&T register names are preceded by a '%' sign. They are undelimited in Intel syntax. AT&T indicates absolute jump/call operands with '*', Intel syntax doesn't delimit these addresses. The order of the source and destination operands are switched. AT&T syntax uses 'Source, Dest', while Intel syntax features 'Dest, Source'. Thus the Intel construct 'add eax, 4' transforms to 'addl $4, %eax' in the AT&T dialect. Immediate long jumps are prefixed with the 'l' prefix. Thus the Intel 'call/jmp section:offset' is transformed to 'lcall/ljmp $section,$offset'. Similarly the far return is 'lret', instead of the Intel 'ret far'. Memory references are specified differently in AT&T and Intel assembly. The Intel indirect memory reference Section:[Base + Index*Scale + Offs] is written in AT&T syntax as : Section:Offs(Base,Index,Scale) Where Base and Index are optional 32-bit base and index registers, and Scale is used to multiply Index. It can take the values 1,2,4 and 8. The Section is used to specify an optional section register for the memory operand. More information about the AT&T syntax can be found in the as manual, although the following differences with normal AT&T assembly must be taken into account : Only the following directives are presently supported: .byte .word .long .ascii .asciz .globl The following directives are recognized but are not supported: .align .lcomm Eventually they will be supported. Directives are case sensitive, other identifiers are not case sensitive. Contrary to GAS local labels/symbols must start with .L The nor operator '!' is not supported. String expressions in operands are not supported. Constant expressions which represent memory references are not allowed even though constant immediate value expressions are supported. examples: const myid = 10; ... movl $myid,%eax -- allowed movl myid(%esi),%eax -- not allowed. When the .globl directive is found, the symbol following it is made public and is
Page 65
immediately emitted. Therefore label names with this name will be ignored. Only Single and Double FPU opcodes are supported. The AT&T inline assembler supports the following macros : __RESULT represents the function result return value. __SELF represents the object method pointer in methods. __OLDEBP represents the old base pointer in recusrive routines.
CALLING MECHANISM
Procedures and Functions are called with their parameters on the stack. Contrary to Turbo Pascal, all parameters are pushed on the stack, and they are pushed right to left, instead of left to right for Turbo Pascal. This is especially important if you have some assembly subroutines in Turbo Pascal which you would like to translate to Free Pascal. Function results are returned in the first register, if they fit in the register. For more information on this, see section (8.2) The registers are not saved when calling a function or procedure. If you want to call a procedure or function from assembly language, you must save any registers you wish to preserve. The first thing a procedure does is saving the base pointer, and setting the base (%ebp) pointer equal to the stack pointer (%esp). References to the pushed parameters and local variables are constructed using the base pointer. In practice this amounts to the following assembly code as the procedure or function header : pushl %ebp movl %esp,%ebp When the procedure or function exits, it clears the stack by means of the RET xx call, where xx is the total size of the pushed parameters on the stack. Thus, in case parameters with a total size of xx have been passed to a function, the generated exit sequence looks as follows: leave ret $xx When you want your code to be called by a C library or used in a C program, you will run into trouble because of this calling mechanism. In C, the calling procedure is expected to clear the stack, not the called procedure. To avoid this problem, Free Pascal supports the export modifier. Procedures that are defined using the export modifier, use a C-compatible calling mechanism. This means that they can be called from a C program or library, or that you can use them as a callback function. This also means that you cannot call this procedure or function from your own program, since your program uses the Pascal calling convention. However, in the exported function, you can of course call other Pascal routines. Technically, the C calling mechanism is implemented by generating the following exit sequence at the end of your function or procedure: leave {Copies EBP to ESP, pops EBP from the stack.} ret Comparing this exit sequence with the previous one makes it clear why you cannot call this procedure from within Pascal: The arguments still are on the stack when the procedure exits. As of version 0.9.8, the Free Pascal compiler supports also the cdecl and stdcall modifiers, as found in Delphi. The cdecl modifier does the same as the export modifier, and stdcall does nothing, since Free Pascal pushes the paramaters from right to left by default. All this is summarized in table (3.1). The first column lists the modifier you specify for a procedure declaration. The second one lists the order the paramaters are pushed on the stack. The third column specifies who is responsible for cleaning the stack: the caller or the called function. Finally, the last column specifies if registers are used to pass parameters to the function. Table 3.1: Calling mechanisms in Free Pascal
Page 66
Modifier Pushing order Stack cleaned by (none) Right-to-left Function cdecl Right-to-left Caller export Right-to-left Caller stdcall Right-to-left Function More about this can be found in chapter (4) on linking.
Parameters in registers No No No No
Page 67
LINKING ISSUES
When you only use Pascal code, and Pascal units, then you will not see much of the part that the linker plays in creating your executable. The linker is only called when you compile a program. When compiling units, the linker isn't invoked. However, there are times that you want to C libraries, or to external object files that are generated using a C compiler (or even another pascal compiler). The Free Pascal compiler can generate calls to a C function, and can generate functions that can be called from C (exported functions). However, these exported functions cannot be called from inside Pascal anymore. More on these calling conventions can be found in section (3.3). In general, there are 2 things you must do to use a function that resides in an external library or object file: 1. You must make a pascal declaration of the function or procedure you want to use. 2. You must tell the compiler where the function resides, i.e. in what object file or what library, so the compiler can link the necessary code in. The following sections attempt to explain how to do this. Declaring an external function or procedure Explicitly linking an object file in your program Linking your program to a library Making a shared library
4.
Page 68
using their index: Procedure ProcName (Args : TPRocArgs); external 'Name' Index SomeIndex; This tells the compiler that the procedure ProcName resides in a dynamic link library, with index SomeIndex. Remark: Note that this is ONLY available under and OS/2. In earlier versions of the Free Pascal compiler, the following construct was also possible : Procedure ProcName (Args : TPRocArgs); [ C ]; This method is equivalent to the following statement: Procedure ProcName (Args : TPRocArgs); cdecl; external; However, the [ C ] directive is no longer supoerted as of version 0.99.5 of Free Pascal, therefore you should use the external directive, with the cdecl directive, if needed.
Page 69
{$L fib.o} begin For I:=1 to 40 do writeln ('Fib(',i,') : ',Fibonacci (i)); end. With just two commands, this can be made into a program : as -o fib.o fib.s pp fibo.pp This example supposes that you have your assembler routine in fib.s, and your Pascal program in fibo.pp.
Page 70
is described first.
Compiling libraries
Once you have your (adapted) code, with exported and other functions, you can compile your unit, and tell the compiler to make it into a library. The compiler will simply compile your unit, and perform the necessary steps to transform it into a static or shared (dynamical) library. You can do this as follows, for a dynamical library: ppc386 -Uld myunit On LINUX this will leave you with a file libmyunit.so. On and OS/2, this will leave you with myunit.dll. If you want a static library, you can do ppc386 -Uls myunit This will leave you with libmyunit.a and a file myunit.ppl. The myunit.ppl is the unit file needed by the Free Pascal compiler. The extension .ppl means that the file describes a unit that resides in a library. The resulting files are then libraries. To make static libraries, you need the ranlib or ar program on your system. It is standard on any LINUX system, and is provided with the GCC compiler under DOS. BEWARE: This command doesn't include anything but the current unit in thelibrary. Other units are left out, so if you use code from other units, you must dpley them together with your library.
Page 71
Page 72
OBJECTS
In this short chapter we give some technical things about objects. For instructions on how to use and declare objects, see Reference guide. Constructor and Destructor calls Memory storage of objects The Virtual Method Table
Page 73
GENERATED CODE
The Free Pascal compiler relies on the assembler to make object files. It generates just the assembly language file. In the following two sections, we discuss what is generated when you compile a unit or a program. Units Programs
UNITS
When you compile a unit, the Free Pascal compiler generates 2 files : 1. A unit description file (with extension .ppu). 2. An assembly language file (with extension .s). The assembly language file contains the actual source code for the statements in your unit, and the necessary memory allocations for any variables you use in your unit. This file is converted by the assembler to an object file (with extension .o) which can then be linked to other units and your program, to form an executable. By default (compiler version 0.9.4 and up), the assembly file is removed after it has been compiled. Only in the case of the -s command-line option, the assembly file must be left on disk, so the assembler can be called later. The unit file contains all the information the compiler needs to use the unit: 1. Other used units, both in interface and implementation. 2. Types and variables from the interface section of the unit. 3. Function declarations from the interface section of the unit. 4. Some debugging information, when compiled with debugging. 5. A date and time stamp. Macros, symbols and compiler directives are not saved to the unit description file. Aliases for functions are also not written to this file, which is logical, since they cannot appear in the interface section of a unit. The detailed contents and structure of this file are described in the first appendix. You can examine a unit description file using the dumpppu program, which shows the contents of the file. If you want to distribute a unit without source code, you must provide both the unit description file and the object file. You can also provide a C header file to go with the object file. In that case, your unit can be used by someone who wishes to write his programs in C. However, you must make this header file yourself since the Free Pascal compiler doesn't make one for you.
PROGRAMS
When you compile a program, the compiler produces again 2 files : 1. An assembly language file containing the statements of your program, and memory allocations for all used variables. 2. A linker response file. This file contains a list of object files the linker must link together. The link response file is, by default, removed from the disk. Only when you specify the -s command-line option or when linking fails, then the ile is left on the disk. It is named link.res. The assembly language file is converted to an object file by the assembler, and then linked together with the rest of the units and a program header, to form your final program. The program header file is a small assembly program which provides the entry point for the program. This is where the execution of your program starts, so it depends on the operating system, because operating systems pass parameters to executables in wildly different ways. It's name is prt0.o, and the source file resides in prt0.s or some variant of this name. It usually resided where the system unit source for your system resides. It's main function is to save the environment and command-line arguments, set up the stack. Then it calls the main program.
Page 74
MMX SUPPORT
What is it about ? Saturation support Restrictions of MMX support Supported MMX operations Optimizing MMX support
WHAT IS IT ABOUT ?
Free Pascal supports the new MMX (Multi-Media extensions) instructions of Intel processors. The idea of MMX is to process multiple data with one instruction, for example the processor can add simultaneously 4 words. To implement this efficiently, the Pascal language needs to be extended. So Free Pascal allows to add for example two array[0..3] of word, if MMX support is switched on. The operation is done by the MMX unit and allows people without assembler knowledge to take advantage of the MMX extensions. Here is an example: uses MMX; { include some predefined data types } const { tmmxword = array[0..3] of word;, declared by unit MMX } w1 : tmmxword = (111,123,432,4356); w2 : tmmxword = (4213,63456,756,4); var w3 : tmmxword; l : longint;
begin if is_mmx_cpu then { is_mmx_cpu is exported from unit mmx } begin {$mmx+} { turn mmx on } w3:=w1+w2; {$mmx-} end else begin for i:=0 to 3 do w3[i]:=w1[i]+w2[i]; end; end.
SATURATION SUPPORT
One important point of MMX is the support of saturated operations. If a operation would cause an overflow, the value stays at the highest or lowest possible value for the data type: If you use byte values you get normally 250+12=6. This is very annoying when doing color manipulations or changing audio samples, when you have to do a word add and check if the value is greater than 255. The solution is saturation: 250+12 gives 255. Saturated operations are supported by the MMX unit. If you want to use them,
Page 75
you have simple turn the switch saturation on: $saturation+ Here is an example: Program SaturationDemo; { example for saturation, scales data (for example audio) with 1.5 with rounding to negative infinity } var audio1 : tmmxword; const helpdata1 : tmmxword = ($c000,$c000,$c000,$c000); helpdata2 : tmmxword = ($8000,$8000,$8000,$8000); begin { audio1 contains four 16 bit audio samples } {$mmx+} { convert it to $8000 is defined as zero, multiply data with 0.75 } audio1:=tmmxfixed16(audio1+helpdata2)*tmmxfixed(helpdata1); {$saturation+} { avoid overflows (all values>$7fff becomes $ffff) } audio1:=(audio1+helpdata2)-helpdata2; {$saturation-} { now mupltily with 2 and change to integer } audio1:=(audio1 shl 1)-helpdata2; {$mmx-} end.
Page 76
Use MMX only in low level routines because the compiler saves all used MMX registers when calling a subroutine. The NOT-operator isn't supported natively by MMX, so the compiler has to generate a workaround and this operation is inefficient. Simple assignements of floating point numbers don't access floating point registers, so you need no call to the EMMS procedure. Only when doing arithmetic, you need to call the EMMS procedure.
Page 77
MEMORY ISSUES
The 32-bit model. The stack Accessing DOS memory under the Go32 extender
THE STACK
The stack is used to pass parameters to procedures or functions, to store local variables, and, in some cases, to return function results. When a function or procedure is called, then the following is done by the compiler : 1. If there are any parameters to be passed to the procedure, they are pushed from right to left on the stack. 2. If a function is called that returns a variable of type String, Set, Record, Object or Array, then an address to store the function result in, is pushed on the stack. 3. If the called procedure or function is an object method, then the pointer to self is pushed on
Page 78
the stack. If the procedure or function is nested in another function or procedure, then the frame pointer of the parent procedure is pushed on the stack. 5. The return address is pushed on the stack (by the Call instruction). The resulting stack frame upon entering looks as in table (8.1). 4. Table 8.1: Stack frame when calling a procedure Offset What is stored Optional ? +x parameters Yes +12 function result Yes +8 self Yes +4 Frame pointer of parent procedure Yes +0 Return address No The stack is cleared with the ret I386 instruction, meaning that the size of all pushed parameters is limited to 64K. The stack size is unlimited for all supported platforms. On the GO32V2 platform, the minimum guaranteed stack is 128Kb, but this can be set with the -Ctxxx compiler switch. The heap is used to store all dynamic variables, and to store class instances. The interface to the heap is the same as in Turbo Pascal, although the effects are maybe not the same. On top of that, the Free Pascal runtime library has some extra possibilities, not available in Turbo Pascal. These extra possibilities are explained in the next subsections.
Using Blocks
If you need to allocate a lot of small block for a small period, then you may want to recompile the run-time library with the USEBLOCKS symbol defined. If it is recompiled, then the heap management is done in a different way. The run-time library keeps a linked list of allocated blocks with size up to 256 bytes. By default, it keeps 32 of these lists. When a piece of memory in a block is deallocated, the heap manager doesn't really deallocate the occupied memory. The block is simply put in the linked list corresponding to its size. When you then again request a block of memory, the manager checks in the list if there is a non-allocated block which fits the size you need (rounded to 8 bytes). If so, the block is used to allocate the memory you requested. This method of allocating works faster if the heap is very fragmented, and you allocate a lot of small memory chunks. Since it is invisible to the program, this provides an easy way of improving the performance of the heap manager.
Page 79
entering this particular part of your program, and release the occupied memory in one call with the Release call. For most purposes, this works very good. But sometimes, you may need to allocate something on the heap that you don't want deallocated when you release the allocated memory. That is where the split heap comes in. When you split the heap, the heap manager keeps 2 heaps: the base heap (the normal heap), and the temporary heap. After the call to split the heap, memory is allocated from the temporary heap. When you're finished using all this memory, you unsplit the heap. This clears all the memory on the split heap with one call. After that, memory will be allocated from the base heap again. So far, nothing special, nothing that can't be done with calls to mark and release. Suppose now that you have split the heap, and that you've come to a point where you need to allocate memory that is to stay allocated after you unsplit the heap again. At this point, mark and release are of no use. But when using the split heap, you can tell the heap manager to -temporarily- use the base heap again to allocate memory. When you've allocated the needed memory, you can tell the heap manager that it should start using the temporary heap again. When you're finished using the temporary heap, you release it, and the memory you allocated on the base heap will still be allocated. To use the split-heap, you must recompile the run-time library with the TempHeap symbol defined. This means that the following functions are available : procedure Split_Heap; procedure Switch_To_Base_Heap; procedure Switch_To_Temp_Heap; procedure Switch_Heap; procedure ReleaseTempHeap; procedure GetempMem(var p : pointer;size : longint); split_heap is used to split the heap. It cannot be called two times in a row, without a call to releasetempheap. Releasetempheap completely releases the memory used by the temporary heap. Switching temporarily back to the base heap can be done using the switch_to_base_heap call, and returning to the temporary heap is done using the switch_to_temp_heap call. Switching from one to the other without knowing on which one your are right now, can be done using the switch_heap call, which will split the heap first if needed. A call to GetTempMem will allocate a memory block on the temporary heap, whatever the current heap is. The current heap after this call will be the temporary heap. Typically, what will appear in your code is the following sequence : Split_Heap ... { Memory allocation } ... { !! non-volatile memory needed !!} Switch_To_Base_Heap; getmem (P,size); Switch_To_Temp_Heap; ... {Memory allocation} ... ReleaseTempHeap; {All allocated memory is now freed, except for the memory pointed to by 'P' } ...
Page 80
protected mode equivalents of segments. In Free Pascal, a pointer is an offset into the DS selector, which points to the Data of your program. To access the (real mode) DOS memory, somehow you need a selector that points to the DOS memory. The GO32 unit provides you with such a selector: The DosMemSelector variable, as it is conveniently called. You can also allocate memory in DOS's memory space, using the global_dos_alloc function of the GO32 unit. This function will allocate memory in a place where DOS sees it. As an example, here is a function that returns memory in real mode DOS and returns a selector:offset pair for it. procedure dosalloc(var selector : word; var segment : word; size : longint); var result : longint; begin result := global_dos_alloc(size); selector := word(result); segment := word(result shr 16);
end; (you need to free this memory using the global_dos_free function.) You can access any place in memory using a selector. You can get a selector using the allocate_ldt_descriptor function, and then let this selector point to the physical memory you want using the set_segment_base_address function, and set its length using set_segment_limit function. You can manipulate the memory pointed to by the selector using the functions of the GO32 unit. For instance with the seg_fillchar function. After using the selector, you must free it again using the free_ldt_selector function. More information on all this can be found in the Unit reference the chapter on the GO32 unit.
Page 81
17..20 Marks start of unit file. After the header, in the second part, first the list of all source files for the unit is written. Each name is written as a direct copy of the string in memory, i.e. a length bytes, and then all characters of the string. This list includes any file that was included in the unit source with the {$i file} directive. The list is terminated with a $ff byte marker. After this, the list of units in the uses clause is written, together with their checksums. The file is written as a string, the checksum as a longint (i.e. four bytes). Again this list is terminated with a $ff byte marker. After that, in the third part, the definitions of all types, variables, constants, procedures and functions are written to the unit file. They are written in the following manner: First a byte is written, which determines the kind of definition that follows. then follows, as a series of bytes, a type-dependent description of the definition. The exact byte order for each type can be found in table (A.2)
Start byte 3 2
Size 4 9
Array type
16
Procedure
21 9 15
? 1 variable
Class
18
variable
16 19 20
1(+4) 4 5
Stored fields Reference to the type pointer points to. Table A.2: Description of definition fields 1 byte to indicate base type. 4-byte start range 4-byte end range 4-byte reference to element type. 4-byte reference to range type. 4-byte start range (longint) 4-byte end range (longint) 4-byte reference to the return type definition. 2 byte Word containing modifiers. 2 byte Word containing number of parameters. 5 bytes per parameter. 1 byte : used registers. String containing the mangled name. 8 bytes. 4-byte reference to the return type definition. 2 byte Word containing modifiers. 2 byte Word containing number of parameters. 5 bytes per parameter. 1 byte containing the length of the string. Longint indicating record length list of fields, to be read as unit in itself. $ff end marker. Longint indicating data length String with mangled name of class. 4 byte reference to ancestor class. list of fields, to be read as unit in itself. $ff end marker. 1 byte for type of file. 4-byte reference to type of typed file. Biggest element. 4-byte reference to set element type. 1 byte flag.
Page 82
This list of definitions is again terminated with a $ff byte marker. After that, a list of symbols is given, together with a reference to a definition. This represents the names of the declarations, and the definition they refer to. A reference consists of 2 words : the first word indicates the unit number (as it appears in the uses clause), and the second word is the number of the definition in that unit. A nil reference is stored as $ffffffff. After this follows again a $ff byte terminated list of filenames: The names of the units in the uses clause of the implementation section.
Page 83
globals.pas This unit defines some help routines that are used throughout the entire compiler, and it does some initializations. hcodegen.pas This unit contains processor-independent helper routines for the code generator. options.pas This unit processes the processor-independent command-line options. scanner.pas This unit contains the scanner routines. Here the input file is read and split in tokens. parser.pas, pass_1.pas These units contain the actual Pascal parser. pp.pas This is the main program. It does some initializations and sets the ball rolling. symtable.pas This unit contains the code that keeps the symbol tables for the parser. It also contains the code to read a unit file. systems.pas This unit defines the different operating systems: names, specifications of file systems, places where to look for things etc. sysutils.pas This unit keeps routines for exception handling. tree.pas The main structure for the code generator is a tree of operators and operands, and this unit defines the tree structure. types.pas This unit contains some helper routines for handling of different Pascal types. verbose.pas This unit provides the verbosity support. All messages from the compiler are put on screen with this unit.
COMPILER LIMITS
Although many of the restrictions imposed by the MS-DOS system are removed by use of an extender, or use of another operating system, there still are some limitations to the compiler: 1. String constants are limited to 128 characters. All other characters are simply dropped from the definition. 2. The length of generated unit files is limited to 65K for the real-mode compiler, and to 1Mb for the 32-bit compiler. This limit can be changed by changing the bytearray1 type in cobjects.pas 3. Procedure or Function definitions can be nested to a level of 32. 4. Maximally 255 units can be used in a program when using the real-mode compiler. When using the 32-bit compiler, the limit is set to 1024. You can change this by redefining the maxunits constant in the files.pas compiler source file. 5. Procedures or functions accept parameters with a total size up to $ffff bytes. This limit is due to the RET instruction of the I386 processor. If the calls were made using the C convention this limit would disappear.
Page 84
2.
3. 4. 5.
(%ebp), %eax on PentiumPro and PII systems will be changed into xorl %eax,%eax; movb (%ebp),%al for lesser systems. Cyrix 6x86 processor owners should optimize with -O4 instead of -O5, because -O5 leads to larger code, and thus to smaller speed, according to the Cyrix developers FAQ. When optimizing for speed (-OG) or size (-Og), a choice is made between using shorter instructions (for size) such as enter $4, or longer instructions subl $4,%esp for speed. When smaller size is requested, things aren't aligned on 4-byte boundaries. When speed is requested, things are aligned on 4-byte boundaries as much as possible. Simple optimization (-Oa) makes sure the peephole optimizer is used, as well as the reloading optimizer. Maximum optimization (-Ox) avoids creation of stack frames if they aren't required, and unnecessary loading of registers is avoided as much as possible. (buggy at the moment (version 0.99.0). Uncertain optimizations (-Oz): With this switch, the reloading optimizer (enabled with -Oa) can be forced into making uncertain optimizations. You can enable uncertain optimizations only in certain cases, otherwise you will produce a bug; the following technical description tells you when to use them: If uncertain optimizations are enabled, the reloading optimizer assumes that If something is written to a local/global register or a procedure/function parameter, this value doesn't overwrite the value to which a pointer points. If something is written to memory pointed to by a pointer variable, this value doesn't overwrite the value of a local/global variable or a procedure/function parameter. The practical upshot of this is that you cannot use the uncertain optimizations if you access any local or global variables through pointers. In theory, this includes Var parameters, but it is all right if you don't both read the variable once through its Var reference and then read it using it's name. The following example will produce bad code when you switch on uncertain optimizations: Var temp: Longint; Procedure Foo(Var Bar: Longint); Begin If (Bar = temp) Then Begin Inc(Bar); If (Bar <> temp) then Writeln('bug!') End End; Begin Foo(Temp); End. The reason it produces bad code is because you access the global variable Temp both through its name Temp and through a pointer, in this case using the Bar variable parameter, which is nothing but a pointer to Temp in the above code. On the other hand, you can use the uncertain optimizations if you access global/local variables or parameters through pointers, and only access them through this pointer. For example: Type TMyRec = Record a, b: Longint; End; PMyRec = ^TMyRec;
Page 85
TMyRecArray = Array [1..100000] of TMyRec; PMyRecArray = ^TMyRecArray; Var MyRecArrayPtr: PMyRecArray; MyRecPtr: PMyRec; Counter: Longint; Begin New(MyRecArrayPtr); For Counter := 1 to 100000 Do Begin MyRecPtr := @MyRecArrayPtr^[Counter]; MyRecPtr^.a := Counter; MyRecPtr^.b := Counter div 2; End; End. Will produce correct code, because the global variable MyRecArrayPtr is not accessed directly, but through a pointer (MyRecPtr in this case). In conclusion, one could say that you can use uncertain optimizations only when you know what you're doing.
Page 86
Reference guide for the system unit, and supported Pascal constructs.
Page 87
Page 88
Contents
List of Tables Supported Pascal language constructs Data types Integer types Real types Character types Char Strings PChar Booleans Arrays Pointers Procedural types Records Set types Enumeration types Constants Ordinary constants Typed constants Objects The Turbo Pascal approach The Delphi approach Statements controlling program flow. Assignments The Case statement The For..to/downto..do statement The Goto statement The If..then..else statement The Repeat..until statement The While..do statement The With statement Compound statements Using functions and procedures Function overloading Const parameters Open array parameters Using assembler in your code Modifiers Public cdecl external Export StdCall Alias [RegisterList] Unsupported Turbo Pascal modifiers Reference : The system unit Types, Constants and Variables Types
Page 89
Constants Variables Functions and Procedures Abs Addr Append Arctan Assign Blockread Blockwrite Chdir Chr Close Concat Copy Cos CSeg Dec Delete Dispose DSeg Eof Eoln Erase Exit Exp Filepos Filesize Fillchar Fillword Flush Frac Freemem Getdir Getmem Halt Hi Inc Insert Int IOresult Length Ln Lo Lowercase Mark Maxavail Memavail Mkdir Move New
Page 90
Index
Odd Ofs Ord Paramcount Paramstr Pi Pos Ptr Random Randomize Read Readln Release Rename Reset Rewrite Rmdir Round Runerror Seek SeekEof SeekEoln Seg SetTextBuf Sin SizeOf Sptr Sqr Sqrt SSeg Str Swap Trunc Truncate Upcase Val Write Writeln
Page 91
List of Tables
Predefined integer types Supported Real types PChar pointer arithmetic Set Manipulation operators Allowed C constructs in Free Pascal Unsupported modifiers
Page 92
Page 93
DATA TYPES
Free Pascal supports the same data types as Turbo Pascal, with some extensions from Delphi. Integer types Real types Character types Booleans Arrays Pointers Procedural types Records Set types Enumeration types
Integer types
The integer types predefined in Free Pascal are listed in table (1.1). Table 1.1: Predefined integer types Type Range Size in bytes Byte 0 .. 255 1 Shortint -127 .. 127 1 Integer -32768 .. 32767 2 Word 0 .. 65535 2 Longint -2147483648 .. 2147483648 4 Cardinal 0..4294967296 4 Free Pascal does automatic type conversion in expressions where different kinds of integer types are used. Free Pascal supports hexadecimal format the same way as Turbo Pascal does. To specify a constant value in hexadecimal format, prepend it with a dollar sign ($). Thus, the hexadecimal $FF equals 255 decimal. In addition to the support for hexadecimal notation, Free Pascal also supports binary notation. You can specify a binary number by preceding it with a percent sign (%). Thus, 255 can be specified in binary notation as %11111111.
Real types
Free Pascal uses the math coprocessor (or an emulation) for al its floating-point calculations. The native type for the coprocessor is Double. Other than that, all Turbo Pascal real types are supported. They're listed in table (1.2). Table 1.2: Supported Real types Type Range Significant digits Size Real 2.9E-39 .. 1.7E38 11-12 6 Single 1.5E-45 .. 3.4E38 7-8 4 Double 5.0E-324 .. 1.7E308 15-16 8 Extended 1.9E-4951 .. 1.1E4932 19-20 10 Until version 0.9.1 of the compiler, all the real types are mapped to type Double, meaning that they all have size 8. From version 0.9.3, the Extended and single types are defined with the same suze as in Turbo Pascal. The SizeOf function is your friend here.
Page 94
Character types
CHAR
Free Pascal supports the type Char. A Char is exactly 1 byte in size, and contains one character. You can specify a character constant by enclosing the character in single quotes, as follows : 'a' or 'A' are both character constants. You can also specify a character by their ASCII value, by preceding the ASCII value with the number symbol (#). For example specifying #65 would be the same as 'A'. Also, the caret character (^) can be used in combination with a letter to specify a character with ASCII value less than 27. Thus ^G equals #7 (G is the seventh letter in the alphabet.) If you want to represent the single quote character, type it two times successively, thus '''' represents the single quote character.
STRINGS
Free Pascal supports the String type as it is defined in Turbo Pascal. To declare a variable as a string, use the following declaration: Var S : String[Size]; This will declare S as a variable of type String, with maximum length Size. Size can be any value from 1 to 255. Free Pascal reserves Size+1 bytes for the string S, and in the zeroeth element of the string (S[0]) it will store the length of the variable. If you don't specify the size of the string, 255 is taken as a default. To specify a constant string, you enclose the string in single-quotes, just as a Char type, only now you can have more than one character. Given that S is of type String, the following are valid assignments: S:='This is a string.'; S:='One'+', Two'+', Three'; S:='This isn''t difficult !'; S:='This is a weird character : '#145' !'; As you can see, the single quote character is represented by 2 single-quote characters next to each other. Strange characters can be specified by their ASCII value. The example shows also that you can add two strings. The resulting string is just the concatenation of the first with the second string, without spaces in between them. Strings can not be substracted, however.
PCHAR
Free Pascal supports the Delphi implementation of the PChar type. PChar is defined as a pointer to a Char type, but allows additional operations. The PChar type can be understood best as the Pascal equivalent of a C-style null-terminated string, i.e. a variable of type PChar is a pointer that points to an array of type Char, which is ended by a nullcharacter (#0). Free Pascal supports initializing of PChar typed constants, or a direct assignment. For example, the following pieces of code are equivalent: program one; var p : pchar; begin P:='This is a null-terminated string.'; writeln (P); end. Results in the same as program two; const P : PChar = 'This is a null-terminated string.'
Page 95
begin Writeln (P); end. These examples also show that it is possible to write the contents of the string to a file of type Text. The strings_ unit contains procedures and functions that manipulate the PChar type as you can do it in C. Since it is equivalent to a pointer to a type Char variable, it is also possible to do the following: Program three; Var S : String[30]; P : Pchar; begin S:='This is a null-terminated string.'#0; P:=@S[1]; writeln (P); end. This will have the same result as the previous two examples. You cannot add null-terminated strings as you can do with normal Pascal strings. If you want to concatenate two PChar strings, you will need to use the strings unit. However, it is possible to do some pointer arithmetic. You can use the operators + and - to do operations on PChar pointers. In table (1.3), P and Q are of type PChar, and I is of type Longint. Table 1.3: PChar pointer arithmetic Operation P + I I + P P - I P - Q
Result Adds I to the address pointed to by P. Adds I to the address pointed to by P. Substracts I from the address pointed to by P. Returns, as an integer, the distance between 2 addresses (or the number of characters between P and Q)
Booleans
Free Pascal supports the Boolean type, with its two pre-defined possible values True and False. These are the only two values that can be assigned to a Boolean type. Of course, any expression that resolves to a boolean value, can also be assigned to a boolean type. Assuming B to be of type Boolean, the following are valid assignments: B:=True; B:=False; B:=1<>2; { Results in B:=True } Boolean expressions are also used in conditions. Remark: In Free Pascal, boolean expressions are always evaluated in such a way that when the result is known, the rest of the expression will no longer be evaluated (Called short-cut evaluation). In the following example, the function Func will never be called, which may have strange side-effects. ... B:=False; A := B and Func; Here Func is a function which returns a Boolean type.
Arrays
Free Pascal supports arrays as in Turbo Pascal, except that packed arrays are not supported. Multi-dimensional arrays are also supported.
Page 96
Pointers
Free Pascal supports the use of pointers. A variable of the type Pointer contains an address in memory, where the data of another variable may be stored. Pointers can be typed, which means that they point to a particular kind of data. The type of this data is known at compile time. Consider the following example: Program pointers; type Buffer = String[255]; BufPtr = ^Buffer; Var B : Buffer; BP : BufPtr; PP : Pointer; etc.. In this example, BP is a pointer to a Buffer type; while B is a variable of type Buffer. B takes 256 bytes memory, and BP only takes 4 bytes of memory (enough to keep an adress in memory). Remark: Free Pascal treats pointers much the same way as C does. This means that you can treat a pointer to some type as being an array of this type. The pointer then points to the zeroeth element of this array. Thus the following pointer declaration Var p : ^Longint; Can be considered equivalent to the following array declaration: Var p : array[0..Infinity] of Longint; The reference P^ is then the same as p[0]. The following program illustrates this maybe more clear: program PointerArray; var i : longint; p : ^longint; pp : array[0..100] of longint; begin for i:=0 to 100 do pp[i]:=i; { Fill array } p:=@pp[0]; { Let p point to pp } for i:=0 to 100 do if p[i]<>pp[i] then writeln ('Ohoh, problem !') end. Free Pascal doesn't support pointer arithmetic as C does, however.
Procedural types
Free Pascal has support for procedural types, although it differs from the Turbo Pascal implementation of them. The type declaration remains the same. The two following examples are valid type declarations: Type TOneArg = Procedure (Var X : integer); TNoArg = Function : Real; var proc : TOneArg; func : TNoArg; Given these declarations, the following assignments are valid: Procedure printit (Var X : Integer); begin writeln (x);
Page 97
end; ... P:=@printit; Func:=@Pi; From this example, the difference with Turbo Pascal is clear: In Turbo Pascal it isn't necessary to use the address operator (@) when assigning a procedural type variable, whereas in Free Pascal it is required.
Records
Free Pascal supports records. The prototype type definition of a record is: Type RecType = Record Element1 : type1; Element2,Element3 : type2; ... Elementn ; Typen; end; Variant records are also supported: Type RecType = Record Element1 : type1; Case [PivotElmt:] Type Identifier of Value1 : (VarElt1, Varelt2 : Vartype1); Value2 : (VarElt3, Varelt4 : Vartype2); end; The variant part must be last in the record. The optional PivotElmt can be used to see which variant is active at a certain time. Remark: If you want to read a typed file with records, produced by a Turbo Pascal program, then chances are that you will not succeed in reading that file correctly. The reason for this is that by default, elements of a record are aligned at 2-byte boundaries, for performance reasons. This default behaviour can be changed with the {$PackRecords n} switch. Possible values for n are 1, 2 and 4. This switch tells the compiler to align elements of a record on 1,2 or 4 byte boundaries. Take a look at the following program: Program PackRecordsDemo; type {$PackRecords 2} Trec1 = Record A : byte; B : Word; end; {$PACKRECORDS 1} Trec2 = Record A : Byte; B : Word; end; begin Writeln ('Size Trec1 : ',SizeOf(Trec1)); Writeln ('Size Trec2 : ',SizeOf(Trec2)); end. The output of this program will be : Size Trec1 : 4
Page 98
Size Trec2 : 3 And this is as expected. In Trec1, each of the elements A and B takes 2 bytes of memory, and in Trec1, A takes only 1 byte of memory. As from version 0.9.3 (a developers' version), Free Pascal supports also the 'packed record', this is a record where all the elements are byte-aligned. Thus the two following declarations are equivalent: {$PACKRECORDS 1} Trec2 = Record A : Byte; B : Word; end; {$PACKRECORDS 2} and Trec2 = Packed Record A : Byte; B : Word; end; Note the {$PACKRECORDS 2} after the first declaration !
Set types
Free Pascal supports the set types as in Turbo Pascal. The prototype of a set declaration is: SetType = Set of TargetType; Each of the elements of SetType must be of type TargetType. TargetType can be any ordinal type with a range between 0 and 255. A set can contain maximally 255 elements. The following is a valid set declaration: Type Days = (Mon, Tue, Wed, Thu, Fri, Sqt, Sun); Var WeekDays : Set of days; Given this set declaration, the follwing assignment is legal: WeekDays := [ Mon, Tue, Wed, Thu, Fri]; The operators for manipulations of sets are listed in table (1.4). Table 1.4: Set Manipulation operators Operation Operator Union + Difference Intersection * You can compare two sets with the <> and = operators, but not (yet) with the < and > operators. From compiler version 0.9.5, the compiler stores small sets (less than 32 elements) in a longint, if the type range allows it. This allows for faster processing and decreases program size.
Enumeration types
Enumeration types are supported in Free Pascal. On top of the Turbo Pascal implementation, Free Pascal allows the following C-style extension of the enumeration type. Type EnumType = (one, two, three, forty := 40); As a result, the ordinal number of forty is 40, and not 4, as it would be when the '= 40' wasn't present. When specifying such an enumeration type, it is important to keep in mind that you should keep initialized set elements in ascending order. The following will produce a compiler error: Type EnumType = (one, two, three, forty := 40, thirty:=30);
Page 99
It is necessary to keep forty and Thirty in the correct order. Remark : You cannot use the Pred and Succ functions on this kind of enumeration types. If you try to do that, you'll get a compiler error.
Page 100
CONSTANTS
Just as in Turbo Pascal, Free Pascal supports both normal and typed constants. Ordinary constants Typed constants
Ordinary constants
Ordinary constants declarations are no different from the TP implementation. You can only declare constants of the following types: Ordinal types, Real types, Char, and String. The following are all valid constant declarations: Const e = 2.7182818; { Real type constant. } a = 2; { Integer type constant. } c = '4'; { Character type constant. } s = 'This is a constant string'; {String type constant.} Assigning a value to a constant is not permitted. Thus, given the previous declaration, the following will result in a compiler error: s:='some other string';
Typed constants
Typed constants serve to provide a program with initialized variables. Contrary to ordinary constants, they may be assigned to at run-time. The difference with normal variables is that their value is initialised when the program starts, whereas normal variables must be initialised explicitly. The prototype of a typed constant declaration is: Const SomeConst : SomeType = SomeValue; After that, the constant SomeConst will be of type SomeType, and have initial value SomeValue. Given the declaration: Const S : String = 'This is a typed constant string'; The following is a valid assignment: S:='Result : '+Func; Where Func is a function that returns a String. Typed constants also allow you to initialize arrays and records. For arrays, the initial elements must be specified, surrounded by round brackets, and separated by commas. The number of elements must be exactly the same as number of elements in the declaration of the type. As an example: Const tt : array [1..3] of string[20] = ('ikke','gij', 'hij'); ti : array [1..3] of longint = (1,2,3); For constant records, you should specify each element of the record, in the form Field : Value, separated by commas, and surrounded by round brackets. As an example: Type Point = record X,Y : Real end; Const Origin : Point = (X:0.0 , Y:0.0); The order of the fields in a constant record needs to be the same as in the type declaration, otherwise you'll get a compile-time error.
Page 101
Page 102
OBJECTS
Free Pascal supports object oriented programming. In fact, part of the compiler is written using objects. Here we present some technical questions regarding object oriented programming in Free Pascal. Free Pascal supports 2 programming models for object-oriented programming. You can choose to program object oriented using the Turbo Pascal approach, or you can prefer the Delphi approach. The Turbo Pascal approach The Delphi approach
Page 103
TObj = object; Constructor init; ... end; Pobj = ^TObj; Var PP : Pobj; Then the following 3 calls are equivalent : pp:=new (Pobj,Init); and new(pp,init); and also new (pp); pp^.init; In the last case, the compiler will issue a warning that you should use the extended syntax of new and dispose to generate instances of an object. You can ignore this warning, but it's better programming practice to use the extended syntax to create instances of an object. Similarly, the Dispose procedure accepts the name of a destructor. The destructor will then be called, before removing the object from the heap. In view of the compiler warning remark, the now following Delphi approach may be considered a more natural way of object-oriented programming.
Page 104
you declare a variable of some class, the compiler just allocates a pointer, not the entire object. The constructor of a class returns a pointer to an initialized instance of the object. So, to initialize an instance of some class, you do the following : ClassVar:=ClassType.ConstructorName; Remark : Free Pascal doesn't support the concept of properties yet.
Page 105
Assignments
In addition to the standard Pascal assignment operator (:=), Free Pascal supports some c-style constructions. All available constructs are listed in table (1.5). Table 1.5: Allowed C constructs in Free Pascal Assignm Result ent Adds b to a, and stores the result in a. a += b Substracts b from a, and stores the result in a. a -= b Multiplies a with b, and stores the result in a. a *= b Divides a through b, and stores the result in a. a /= b For these connstructs to work, you should specify the -Sc command-line switch. Remark: These constructions are just for typing convenience, they don't generate different code. Free Pascal also supports typed assignments. This means that an assignment statement has a definite type, and hence can be assigned to another variable. The type of the assignment a:=b is the type of a (or, in this case, of b), and this can be assigned to another variable : c:=a:=b;. To summarize: the construct a:=b:=c; results in both a and b being assign the value of c, which may be an expression. For this construct to be allowed, it is necessary to specify the -Sa4 switch on the command line.
Page 106
Case i of 3 : DoSomething; 1..5 : DoSomethingElse; end; The compiler will generate a Duplicate case label error when compiling this, because the 3 also appears (implicitly) in the range 1..5 Remark: In versions earlier than 0.9.7, there was an incompatibility here with Turbo Pascal. Where in Turbo Pascal you could do the following: case Pivot of ... Else begin Statement1 Statement2 end; You needed to do the following in Free Pascal : case Pivot of ... Else begin Statement1 Statement2 end; end; So there's an extra end keyword at the end. But from version 0.9.7 this has been fixed.
Page 107
Page 108
Compound statements
Compound statements are a group of statements, separated by semicolons, that are surrounded by the keywords Begin and End. The Last statement doesn't need to be followed by a semicolon, although it is allowed.
Page 109
Function overloading
Function overloading simply means that you can define the same function more than once, but each time with a different set of arguments. When the compiler encounters a unction call, it will look at the function parameters to decide which od the defined function This can be useful if you want to define the same function for different types. For example, if the RTL, the Dec procedure is is defined as: ... Dec(Var I : longint;decrement : longint); Dec(Var I : longint); Dec(Var I : Byte;decrement : longint); Dec(Var I : Byte); ... When the compiler encounters a call to the dec function, it wil first search which function it should use. It therefore checks the parameters in your function call, and looks if there is a function definition which maches the specified parameter list. If the compiler finds such a function, a call is inserted to that function. If no such function is found, a compiler error is generated. Const parameters In addition to var parameters and normal parameters (call by value, call by reference), Free Pascal also supports Const parameters. You can specify a Const parameter as follows: Function Name (Const S: Type_Of_S) : ResultType A constant argument is passed by refenence (i.e. the function or procedure receives a pointer to the passed , but you are not allowed to assign to it, this will result in a compiler error. The main use for this is reducing the stack size, hence improving performance.
Page 110
Page 111
MODIFIERS
Free Pascal doesn't support all Turbo Pascal modifiers, but does support a number of additional modifiers. They are used mainly for assembler and reference to C object files. Public cdecl external Export StdCall Alias [RegisterList] Unsupported Turbo Pascal modifiers
Public
The Public keyword is used to declare a function globally in a unit. This is useful if you don't want a function to be accessible from the unit file, but you do want the function to be accessible from the object file. as an example: Unit someunit; interface Function First : Real; Implementation Function First : Real; begin First:=0; end; Function Second : Real; [Public]; begin Second:=1; end; end. If another program or unit uses this unit, it will not be able to use the function Second, since it isn't declared in the interface part. However, it will be possible to access the function Second at the assemblylanguage level, by using it's mangled name (Programmer's guide\).
cdecl
The cdecl modifier can be used to declare a function that uses a C type calling convention. This must be used if you wish to acces functions in an object file generated by a C compiler. It allows you to use the function in your code, and at linking time, you must link the object file containing the C implementation of the function or procedure. As an example: program CmodDemo;
Page 112
{$LINKLIB c} Const P : Pchar = 'This is fun !'; Function strlen (P : Pchar) : Longint; cdecl; external; begin Writeln ('Length of (',p,') : ',strlen(p)) end. When compiling this, and linking to the C-library, you will be able to call the strlen function throughout your program. The external directive tells the compiler that the function resides in an external object filebrary (see 1.7). Remark The parameters in our declaration of the C function should match exactly the ones in the declaration in C. Since C is case sensitive, this means also that the name of the function must be exactly the same.
external
The external modifier can be used to declare a function that resides in an external object file. It allows you to use the function in your code, and at linking time, you must link the object file containing the implementation of the function or procedure. As an example: program CmodDemo; {$Linklib c} Const P : Pchar = 'This is fun !'; Function strlen (P : Pchar) : Longint; cdecl; external; begin Writeln ('Length of (',p,') : ',strlen(p)) end. Remark The parameters in our declaration of the external function should match exactly the ones in the declaration in the object file. Since C is case sensitive, this means also that the name of the function must be exactly the same. The external modifier has also an extended syntax: 1. external 'lname'; Tells the compiler that the function resides in library 'lname'. The compiler will the automatically link this library to your program. 2. external 'lname' name Fname; Tells the compiler that the function resides in library 'lname', but with name 'Fname'. The compiler will the automatically link this library to your program, and use the correct name for the function. 3. and OS/2 only: external 'lname' Index Ind; Tells the compiler that the function resides in library 'lname', but with indexname Ind. The compiler will the automatically link this library to your program, and use the correct index for the function.
Page 113
Export
Sometimes you must provide a callback function for a C library, or you want your routines to be callable from a C program. Since Free Pascal and C use different calling schemes for functions and procedures, the compiler must be told to generate code that can be called from a C routine. This is where the Export modifier comes in. Contrary to the other modifiers, it must be specified separately, as follows: function DoSquare (X : longint) : longint; export; begin ... end; The square brackets around the modifier are not allowed in this case. Remark: You cannot call an exported function from within Free Pascal programs. If you try to do so, the compiler will complain when compiling your source code. If you do want to call an exported procedure from pascal, you must use a dummy function: Procedure RealDoSomething; begin ... end; Procedure DoSomething; export; begin RealDoSomething; end; In this example, from your Free Pascal code, you can call the RealDoSomething procedure. If someone wants to link to your code from a C program, he can call the DoSomething procedure. Both calls will have the same effect. Remark: as of version 0.9.8, Free Pascal supports the Delphi cdecl modifier. This modifier works in the same way as the export modifier. More information about these modifiers can be found in the Programmer's guide in the section on the calling mechanism and the chapter on linking.
StdCall
As of version 0.9.8, Free Pascal supports the Delphi stdcall modifier. This modifier does actually nothing, since the Free Pascal compiler by default pushes parameters from right to left on the stack, which is what the modifier does under Delphi (which pushes parameters on the stack from left to right). More information about this modifier can be found in the Programmer's guide in the section on the calling mechanism and the chapter on linking.
Alias
The Alias modifier allows you to specify a different name for a procedure or function. This is mostly useful for referring to this procedure from assembly language constructs. As an example, consider the following program: Program Aliases; Procedure Printit; [Alias : 'DOIT']; begin Writeln ('In Printit (alias : "DOIT")'); end;
Page 114
begin asm call DOIT end; end. Remark: the specified alias is inserted straight into the assembly code, thus it is case sensitive. The Alias modifier, combined with the Public modifier, make a powerful tool for making externally accessible object files.
[RegisterList]
This modifier list is used to indicate the registers that are modified by an assembler block in your code. The compiler stores certain results in the registers. If you modify theregisters in an assembly block, the compiler should, sometimes, be told about it. The prototype syntax of the Registerlist modifier is: asm statements end; ['register1','register2',...,'registern']; Where 'register' is one of 'EAX',EBX',ECX','EDX' etc.
Page 115
Page 116
Length Ln Lo Lowercase Mark Maxavail Memavail Mkdir Move New Odd Ofs Ord Paramcount Paramstr Pi Pos Ptr Random Randomize Read Readln Release Rename Reset Rewrite Rmdir Round Runerror Seek SeekEof SeekEoln Seg SetTextBuf Sin SizeOf Sptr Sqr Sqrt SSeg Str Swap Trunc Truncate Upcase Val Write Writeln
Page 117
Types
The following integer types are defined in the System unit: shortint = -128..127; longint = $80000000..$7fffffff; integer = -32768..32767; byte = 0..255; word = 0..65535; The following Real types are declared: double = real; {$ifdef VER0_6} extended = real; single = real; {$endif VER0_6} And the following pointer types: pchar = ^char; ppchar = ^pchar;
Constants
The following constants for file-handling are defined in the system unit: Const fmclosed = $D7B0; fminput = $D7B1; fmoutput = $D7B2; fminout = $D7B3; fmappend = $D7B4; filemode : byte = 2; Further, the following general-purpose constants are also defined: const test8086 : byte = 2; { always i386 or newer } test8087 : byte = 3; { Always 387 or higher. emulated if needed. } erroraddr : pointer = nil; errorcode : word = 0; { max level in dumping on error } max_frame_dump : word = 20;
Variables
The following variables are defined and initialized in the system unit: var output,input,stderr : text; exitproc : pointer;
Page 118
exitcode : word; stackbottom : longint; loweststack : longint; The variables ExitProc, exitcode are used in the Free Pascal exit scheme. It works similarly to the on in Turbo Pascal: When a program halts (be it through the call of the Halt function or Exit or through a run-time error), the exit mechanism checks the value of ExitProc. If this one is non-Nil, it is set to Nil, and the procedure is called. If the exit procedure exits, the value of ExitProc is checked again. If it is non-Nil then the above steps are repeated. So if you want to install your exit procedure, you should save the old value of ExitProc (may be nonNil, since other units could have set it before you did). In your exit procedure you then restore the value of ExitProc, such that if it was non-Nil the exit-procedure can be called. The ErrorAddr and ExitCode can be used to check for error-conditions. If ErrorAddr is non-Nil, a run-time error has occurred. If so, ExitCode contains the error code. If ErrorAddr is Nil, then ExitCode contains the argument to Halt or 0 if the program terminated normally. ExitCode is always passed to the operating system as the exit-code of your process. Under GO32, the following constants are also defined : const seg0040 = $0040; segA000 = $A000; segB000 = $B000; segB800 = $B800; These constants allow easy access to the bios/screen segment via mem/absolute.
Page 119
Page 120
Odd Ofs Ord Paramcount Paramstr Pi Pos Ptr Random Randomize Read Readln Release Rename Reset Rewrite Rmdir Round Runerror Seek SeekEof SeekEoln Seg SetTextBuf Sin SizeOf Sptr Sqr Sqrt SSeg Str Swap Trunc Truncate Upcase Val Write Writeln
Abs
DECLARATION:
Function Abs (X : Every numerical type) : Every numerical type;
DESCRIPTION:
Abs returns the absolute value of a variable. The result of the function has the same type as its argument, which can be any numerical type.
ERRORS:
None.
Page 121
SEE ALSO:
Round Example Program Example1; { Program to demonstrate the Abs function. } Var r : real; i : integer; begin r:=abs(-1.0); i:=abs(-21); end. { r:=1.0 } { i:=21 }
Addr
DECLARATION:
Function Addr (X : Any type) : Pointer;
DESCRIPTION:
Addr returns a pointer to its argument, which can be any type, or a function or procedure name. The returned pointer isn't typed. The same result can be obtained by the @ operator, which can return a typed pointer (Programmer's guide\).
ERRORS:
None
SEE ALSO:
SizeOf Example Program Example2; { Program to demonstrate the Addr function. } Const Zero : integer = 0; Var p : pointer; i : Integer; begin p:=Addr(p); p:=Addr(I); p:=Addr(Zero); end. { P points to itself } { P points to I } { P points to 'Zero' }
Append
Page 122 Free Pascal Manual
DECLARATION:
Procedure Append (Var F : Text) ;
DESCRIPTION:
Append opens an existing file in append mode. Any data written to F will be appended to the file. If the file didn't exist, it will be created, contrary to the Turbo Pascal implementation of Append, where a file needed to exist in order to be opened by append. Only text files can be opened in append mode.
ERRORS:
If the file can't be created, a run-time error will be generated.
SEE ALSO:
Rewrite,Append, Reset Example Program Example3; { Program to demonstrate the Append function. } Var f : text; begin Assign (f,'test.txt'); Rewrite (f); { file is opened for write, and emptied } Writeln (F,'This is the first line of text.txt'); close (f); Append(f); { file is opened for write, but NOT emptied. any text written to it is appended.} Writeln (f,'This is the second line of text.txt'); close (f); end.
Arctan
DECLARATION:
Function Arctan (X : Real) : Real;
DESCRIPTION:
Arctan returns the Arctangent of X, which can be any real type. The resulting angle is in radial units.
ERRORS:
None
SEE ALSO:
Sin, Cos Example Program Example4; { Program to demonstrate the ArcTan function. } Var R : Real;
Page 123
{ R:=0 } { R:=0.25 }
Assign
DECLARATION: DESCRIPTION:
Assign assigns a name to F, which can be any file type. This call doesn't open the file, it just assigns a name to a file variable, and marks the file as closed. Procedure Assign (Var F; Name : String) ;
ERRORS:
None.
SEE ALSO:
Reset, Rewrite, Append Example Program Example5; { Program to demonstrate the Assign function. } Var F : text; begin Assign (F,''); Rewrite (f); { The following can be put in any file by redirecting it from the command line.} Writeln (f,'This goes to standard output !'); Close (f); Assign (F,'Test.txt'); rewrite (f); writeln (f,'This doesn''t go to standard output !'); close (f); end.
Blockread
DECLARATION: DESCRIPTION:
Blockread reads count or less records from file F. The result is placed in Buffer, which must contain enough room for Count records. The function cannot read partial records. If Result is specified, it contains the number of records actually read. If Result isn't specified, and less than Count records were read, a run-time error is generated. This behavior can be controlled by the {$i} switch. Procedure Blockread (Var F : File; Var Buffer; Var Count : Longint [; var Result : Longint]) ;
Page 124
ERRORS:
If Result isn't specified, then a run-time error is generated if less than count records were read.
SEE ALSO:
Blockwrite,Reset, Assign Example Program Example6; { Program to demonstrate the BlockRead and BlockWrite functions. } Var Fin, fout : File; NumRead,NumWritten : Word; Buf : Array[1..2048] of byte; Total : Longint; begin Assign (Fin, Paramstr(1)); Assign (Fout,Paramstr(2)); Reset (Fin,1); Rewrite (Fout,1); Total:=0; Repeat BlockRead (Fin,buf,Sizeof(buf),NumRead); BlockWrite (Fout,Buf,NumRead,NumWritten); inc(Total,NumWritten); Until (NumRead=0) or (NumWritten<>NumRead); Write ('Copied ',Total,' bytes from file ',paramstr(1)); Writeln (' to file ',paramstr(2)); end.
Blockwrite
DECLARATION:
Procedure Blockwrite (Var F : File; Var Buffer; Var Count : Longint) ;
DESCRIPTION:
Blockread writes count records from buffer to the file F. If the records couldn't be written to disk, a run-time error is generated. This behavior can be controlled by the {$i} switch.
ERRORS:
A run-time error is generated if, for some reason, the records couldn't be written to disk.
SEE ALSO:
Blockread,Reset, Assign For the example, see Blockread.
Chdir
DECLARATION:
Procedure Chdir (const S : string) ;
Page 125
DESCRIPTION:
Chdir changes the working directory of the process to S.
ERRORS:
If the directory S doesn't exist, a run-time error is generated.
SEE ALSO:
Mkdir, Rmdir Example Program Example7; { Program to demonstrate the ChDir function. } begin {$I-} ChDir (ParamStr(1)); if IOresult<>0 then Writeln ('Cannot change to directory : ',paramstr (1)); end.
Chr
DECLARATION:
Function Chr (X : byte) : Char;
DESCRIPTION:
Chr returns the character which has ASCII value X.
ERRORS:
None.
SEE ALSO:
Ord,Str Example Program Example8; { Program to demonstrate the Chr function. } begin Write (chr(10),chr(13)); { The same effect as Writeln; } end.
Close
DECLARATION: DESCRIPTION:
Close flushes the buffer of the file F and closes F. After a call to Close, data can no longer be read from or written to F. To reopen a file closed with Close, it isn't necessary to assign the file again. A call to Reset or Rewrite is Procedure Close (Var F : Anyfiletype) ;
Page 126
sufficient.
ERRORS:
None.
SEE ALSO:
Assign, Reset, Rewrite Example Program Example9; { Program to demonstrate the Close function. } Var F : text; begin Assign (f,'Test.txt'); ReWrite (F); Writeln (F,'Some text written to Test.txt'); close (f); { Flushes contents of buffer to disk, closes the file. Omitting this may cause data NOT to be written to disk.} end.
Concat
DECLARATION: DESCRIPTION:
Concat concatenates the strings S1,S2 etc. to one long string. The resulting string is truncated at a length of 255 bytes. The same operation can be performed with the + operation. Function Concat (S1,S2 [,S3, ... ,Sn]) : String;
ERRORS:
None.
SEE ALSO:
Copy, Delete, Insert, Pos, Length Example Program Example10; { Program to demonstrate the Concat function. } Var S : String; begin S:=Concat('This can be done',' Easier ','with the + operator !'); end.
Page 127
Copy
DECLARATION:
Function Copy (Const S : String;Index : Integer;Count : Byte) : String;
DESCRIPTION:
Copy returns a string which is a copy if the Count characters in S, starting at position Index. If Count is larger than the length of the string S, the result is truncated. If Index is larger than the length of the string S, then an empty string is returned.
ERRORS:
None.
SEE ALSO:
Delete, Insert, Pos Example Program Example11; { Program to demonstrate the Copy function. } Var S,T : String; begin T:='1234567'; S:=Copy (T,1,2); S:=Copy (T,4,2); S:=Copy (T,4,8); end.
Cos
DECLARATION: DESCRIPTION:
Cos returns the cosine of X, where X is an angle, in radians. Function Cos (X : real) : Real;
ERRORS:
None.
SEE ALSO:
Arctan, Sin Example Program Example12; { Program to demonstrate the Cos function. } Var R : Real; begin R:=Cos(Pi); R:=Cos(Pi/2); R:=Cos(0); { R:=-1 } { R:=0 } { R:=1 }
Page 128
end.
CSeg
DECLARATION:
Function CSeg : Word;
DESCRIPTION:
CSeg returns the Code segment register. In Free Pascal, it returns always a zero, since Free Pascal is a 32 bit compiler.
ERRORS:
None.
SEE ALSO:
DSeg, Seg, Ofs, Ptr Example Program Example13; { Program to demonstrate the CSeg function. } var W : word; begin W:=CSeg; {W:=0, provided for comppatibility, FPC is 32 bit.} end.
Dec
DECLARATION:
Procedure Dec (Var X : Any ordinal type[; Decrement : Longint]) ;
DESCRIPTION:
Dec decreases the value of X with Decrement. If Decrement isn't specified, then 1 is taken as a default.
ERRORS:
A range check can occur, or an underflow error, if you try to decrease X below its minimum value.
SEE ALSO:
Inc Example Program Example14; { Program to demonstrate the Dec function. } Var I L W B : : : : Integer; Longint; Word; Byte;
Page 129
Si : ShortInt; begin I:=1; L:=2; W:=3; B:=4; Si:=5; Dec (i); Dec (L,2); Dec (W,2); Dec (B,-2); Dec (Si,0); end.
{ { { { {
} } } } }
Delete
DECLARATION: DESCRIPTION:
Delete removes Count characters from string S, starting at position Index. All remaining characters are shifted Count positions to the left, and the length of the string is adjusted. Procedure Delete (var S : string;Index : Integer;Count : Integer) ;
ERRORS:
None.
SEE ALSO:
Copy,Pos,Insert Example Program Example15; { Program to demonstrate the Delete function. } Var S : String; begin S:='This is not easy !'; Delete (S,9,4); { S:='This is easy !' } end.
Dispose
DECLARATION: DESCRIPTION:
Dispose releases the memory allocated with a call to New. The pointer P must be typed. The released memory is returned to the heap. Procedure Dispose (P : pointer) ;
ERRORS:
An error will occur if the pointer doesn't point to a location in the heap.
Page 130
SEE ALSO:
New, Getmem, Freemem Example Program Example16; { Program to demonstrate the Dispose and New functions. } Type SS = String[20]; AnObj = Object I : integer; Constructor Init; Destructor Done; end; Var P : ^SS; T : ^AnObj; Constructor Anobj.Init; begin Writeln ('Initializing an instance of AnObj !'); end; Destructor AnObj.Done; begin Writeln ('Destroying an instance of AnObj !'); end; begin New (P); P^:='Hello, World !'; Dispose (P); { P is undefined from here on !} New(T,Init); T^.i:=0; Dispose (T,Done); end.
DSeg
DECLARATION:
Function DSeg : Word;
DESCRIPTION:
DSeg returns the data segment register. In Free Pascal, it returns always a zero, since Free Pascal is a 32 bit compiler.
ERRORS:
None.
Page 131
SEE ALSO:
CSeg, Seg, Ofs, Ptr Example Program Example17; { Program to demonstrate the DSeg function. } Var W : Word; begin W:=DSeg; {W:=0, This function is provided for compatibility, FPC is a 32 bit comiler.} end.
Eof
DECLARATION: DESCRIPTION:
Eof returns True if the file-pointer has reached the end of the file, or if the file is empty. In all other cases Eof returns False. If no file F is specified, standard input is assumed. Function Eof [(F : Any file type)] : Boolean;
ERRORS:
None.
SEE ALSO:
Eoln, Assign, Reset, Rewrite Example Program Example18; { Program to demonstrate the Eof function. } Var T1,T2 : text; C : Char; begin { Set file to read from. Empty means from standard input.} assign (t1,paramstr(1)); reset (t1); { Set file to write to. Empty means to standard output. } assign (t2,paramstr(2)); rewrite (t2); While not eof(t1) do begin read (t1,C); write (t2,C); end; Close (t1); Close (t2);
Page 132
end.
Eoln
DECLARATION:
Function Eoln [(F : Text)] : Boolean;
DESCRIPTION:
Eof returns True if the file pointer has reached the end of a line, which is demarcated by a line-feed character (ASCII value 10), or if the end of the file is reached. In all other cases Eof returns False. If no file F is specified, standard input is assumed. It can only be used on files of type Text.
ERRORS:
None.
SEE ALSO:
Eof, Assign, Reset, Rewrite Example Program Example19; { Program to demonstrate the Eoln function. } begin { This program waits for keyboard input. } { It will print True when an empty line is put in, and false when you type a non-empty line. It will only stop when you press enter.} Writeln (eoln); end.
Erase
DECLARATION: DESCRIPTION:
Erase removes an unopened file from disk. The file should be assigned with Assign, but not opened with Reset or Rewrite Procedure Erase (Var F : Any file type) ;
ERRORS:
A run-time error will be generated if the specified file doesn't exist.
SEE ALSO:
Assign Example Program Example20; { Program to demonstrate the Erase function. } Var F : Text;
Page 133
begin { Create a file with a line of text in it} Assign (F,'test.txt'); Rewrite (F); Writeln (F,'Try and find this when I''m finished !'); close (f); { Now remove the file } Erase (f); end.
Exit
DECLARATION:
Procedure Exit ([Var X : return type )] ;
DESCRIPTION:
Exit exits the current subroutine, and returns control to the calling routine. If invoked in the main program routine, exit stops the program. The optional argument X allows to specify a return value, in the case Exit is invoked in a function. The function result will then be equal to X.
ERRORS:
None.
SEE ALSO:
Halt Example Program Example21; { Program to demonstrate the Exit function. } Procedure DoAnExit (Yes : Boolean); { This procedure demonstrates the normal Exit } begin Writeln ('Hello from DoAnExit !'); If Yes then begin Writeln ('Bailing out early.'); exit; end; Writeln ('Continuing to the end.'); end; Function Positive (Which : Integer) : Boolean; { This function demonstrates the extra FPC feature of Exit : You can specify a return value for the function } begin if Which>0 then exit (True) else
Page 134
exit (False); end; begin { This call will go to the end } DoAnExit (False); { This call will bail out early } DoAnExit (True); if Positive (-1) then Writeln ('The compiler is nuts, -1 is not positive.') else Writeln ('The compiler is not so bad, -1 seems to be negative.'); end.
Exp
DECLARATION: DESCRIPTION:
Exp returns the exponent of X, i.e. the number e to the power X. Function Exp (Var X : real) : Real;
ERRORS:
None.
SEE ALSO:
Ln Example Program Example22; { Program to demonstrate the Exp function. } begin Writeln (Exp(1):8:2); { Should print 2.72 } end.
Filepos
DECLARATION: DESCRIPTION:
Filepos returns the current record position of the file-pointer in file F. It cannot be invoked with a file of type Text. Function Filepos (Var F : Any file type) : Longint;
ERRORS:
None.
SEE ALSO:
Filesize Example Program Example23;
Page 135
{ Program to demonstrate the FilePos function. } Var F : File of Longint; L,FP : longint; begin { Fill a file with data : Each position contains the position ! } Assign (F,'test.dat'); Rewrite (F); For L:=0 to 100 do begin FP:=FilePos(F); Write (F,FP); end; Close (F); Reset (F); { If ll goes well, nothing is displayed here. } While not (Eof(F)) do begin FP:=FilePos (F); Read (F,L); if L<>FP then Writeln ('Something is wrong here ! : Got ',l,' on pos ',FP); end; Close (F); Erase (f); end.
Filesize
DECLARATION:
Function Filesize (Var F : Any file type) : Longint;
DESCRIPTION:
Filepos returns the total number of records in file F. It cannot be invoked with a file of type Text. (under LINUX, this also means that it cannot be invoked on pipes.) If F is empty, 0 is returned.
ERRORS:
None.
SEE ALSO:
Filepos Example Program Example24; { Program to demonstrate the FileSize function. } Var F : File Of byte; L : File Of Longint;
Page 136
begin Assign (F,paramstr(1)); Reset (F); Writeln ('File size in bytes : ',FileSize(F)); Close (F); Assign (L,paramstr (1)); Reset (L); Writeln ('File size in Longints : ',FileSize(L)); Close (f); end.
Fillchar
DECLARATION:
Procedure Fillchar (Var X;Count : Longint;Value : char or byte); ;
DESCRIPTION:
Fillchar fills the memory starting at X with Count bytes or characters with value equal to Value.
ERRORS:
No checking on the size of X is done.
SEE ALSO:
Fillword, Move Example Program Example25; { Program to demonstrate the FillChar function. } Var S : String[10]; I : Byte; begin For i:=10 downto 0 do begin { Fill S with i spaces } FillChar (S,SizeOf(S),' '); { Set Length } S[0]:=chr(i); Writeln (s,'*'); end; end.
Fillword
DECLARATION: DESCRIPTION:
Fillword fills the memory starting at X with Count words with value equal to Value. Procedure Fillword (Var X;Count : Longint;Value : Word); ;
Page 137
ERRORS:
No checking on the size of X is done.
SEE ALSO:
Fillword, Move Example Program Example76; { Program to demonstrate the FillWord function. } Var W : Array[1..100] of Word; begin { Quick initialization of array W } FillWord(W,100,0); end.
Flush
DECLARATION: DESCRIPTION:
Flush empties the internal buffer of file F and writes the contents to disk. The file is not closed as a result of this call. Procedure Flush (Var F : Text) ;
ERRORS:
If the disk is full, a run-time error will be generated.
SEE ALSO:
Close Example Program Example26; { Program to demonstrate the Flush function. } Var F : Text; begin { Assign F to standard output } Assign (F,''); Rewrite (F); Writeln (F,'This line is written first, but appears later !'); { At this point the text is in the internal pascal buffer, and not yet written to standard output } Writeln ('This line appears first, but is written later !'); { A writeln to 'output' always causes a flush - so this text is written to screen } Flush (f); { At this point, the text written to F is written to screen. } Write (F,'Finishing '); Close (f); { Closing a file always causes a flush first } Writeln ('off.');
Page 138
end.
Frac
DECLARATION: DESCRIPTION:
Frac returns the non-integer part of X. Function Frac (X : real) : Real;
ERRORS:
None.
SEE ALSO:
Round, Int Example Program Example27; { Program to demonstrate the Frac function. } Var R : Real; begin Writeln (Frac (123.456):0:3); { Prints O.456 } Writeln (Frac (-123.456):0:3); { Prints -O.456 } end.
Freemem
DECLARATION: DESCRIPTION:
Freemem releases the memory occupied by the pointer P, of size Count, and returns it to the heap. P should point to the memory allocated to a dynamical variable. Procedure Freemem (Var P : pointer; Count : longint) ;
ERRORS:
An error will occur when P doesn't point to the heap.
SEE ALSO:
Getmem, New, Dispose Example Program Example28; { Program to demonstrate the FreeMem and GetMem functions. } Var P : Pointer; MM : Longint; begin { Get memory for P }
Page 139
MM:=MemAvail; Writeln ('Memory available GetMem (P,80); MM:=MM-Memavail; Write ('Memory available Writeln (' or ',MM,' bytes { fill it with spaces } FillChar (P^,80,' '); { Free the memory again } FreeMem (P,80); Writeln ('Memory available end.
before GetMem : ',MemAvail); after GetMem : ',MemAvail); less than before the call.');
Getdir
DECLARATION: DESCRIPTION:
Getdir returns in dir the current directory on the drive drivenr, where drivenr is 1 for the first floppy drive, 3 for the first hard disk etc. A value of 0 returns the directory on the current disk. On LINUX, drivenr is ignored, as there is only one directory tree. Procedure Getdir (drivenr : byte;var dir : string) ;
ERRORS:
An error is returned under DOS, if the drive requested isn't ready.
SEE ALSO:
Chdir Example Program Example29; { Program to demonstrate the GetDir function. } Var S : String; begin GetDir (0,S); Writeln ('Current directory is : ',S); end.
Getmem
DECLARATION: DESCRIPTION:
Getmem reserves Size bytes memory on the heap, and returns a pointer to this memory in p. If no more memory is available, nil is returned. Procedure Getmem (var p : pointer;size : longint) ;
ERRORS:
None.
Page 140
SEE ALSO:
Freemem, Dispose, New For an example, see Freemem.
Halt
DECLARATION: DESCRIPTION:
Halt stops program execution and returns control to the calling program. The optional argument Errnum specifies an exit value. If omitted, zero is returned. Procedure Halt [(Errnum : byte] ;
ERRORS:
None.
SEE ALSO:
Exit Example Program Example30; { Program to demonstrate the Halt function. } begin Writeln ('Before Halt.'); Halt (1); { Stop with exit code 1 } Writeln ('After Halt doesn''t get executed.'); end.
Hi
DECLARATION: DESCRIPTION:
Hi returns the high byte or word from X, depending on the size of X. If the size of X is 4, then the high word is returned. If the size is 2 then the high byte is retuned. hi cannot be invoked on types of size 1, such as byte or char. Function Hi (X : Ordinal type) : Word or byte;
ERRORS:
None
SEE ALSO:
Lo Example Program Example31; { Program to demonstrate the Hi function. } var L : Longint; W : Word;
Page 141
begin L:=1 Shl 16; W:=1 Shl 8; Writeln (Hi(L)); Writeln (Hi(W)); end.
{ { { {
Inc
DECLARATION: DESCRIPTION:
Inc increases the value of X with Increment. If Increment isn't specified, then 1 is taken as a default. Procedure Inc (Var X : Any ordinal type[; Increment : Longint]) ;
ERRORS:
A range check can occur, or an overflow error, if you try to increase X over its maximum value.
SEE ALSO:
Dec Example Program Example32; { Program to demonstrate the Inc function. } Const C : Cardinal L : Longint I : Integer W : Word B : Byte SI : ShortInt CH : Char begin Inc Inc Inc Inc Inc Inc Inc end. (C); (L,5); (I,-3); (W,3); (B,100); (SI,-3); (CH,1); { { { { { { { = = = = = = = 1; 1; 1; 1; 1; 1; 'A'; C:=2 L:=6 I:=-2 W:=4 B:=101 Si:=-2 ch:='B' } } } } } } }
Insert
DECLARATION:
Procedure Insert (Var Source : String;var S : String;Index : integer) ;
Page 142
DESCRIPTION:
Insert inserts string S in string Source, at position Index, shifting all characters after Index to the right. The resulting string is truncated at 255 characters, if needed.
ERRORS:
None.
SEE ALSO:
Delete, Copy, Pos Example Program Example33; { Program to demonstrate the Insert function. } Var S : String; begin S:='Free Pascal is difficult to use !'; Insert ('NOT ',S,pos('difficult',S)); writeln (s); end.
Int
DECLARATION: DESCRIPTION:
Int returns the integer part of any real X, as a real. Function Int (X : real) : Real;
ERRORS:
None.
SEE ALSO:
Frac, Round Example Program Example34; { Program to demonstrate the Int function. } begin Writeln (Int(123.456):0:1); { Prints 123.0 } Writeln (Int(-123.456):0:1); { Prints -123.0 } end.
IOresult
DECLARATION:
Function IOresult : Word;
Page 143
DESCRIPTION:
IOresult contains the result of any input/output call, when the {$i-} compiler directive is active, and IO checking is disabled. When the flag is read, it is reset to zero. If IOresult is zero, the operation completed successfully. If non-zero, an error occurred. The following errors can occur: DOS errors : 2 File not found. 3 Path not found. 4 Too many open files. 5 Access denied. 6 Invalid file handle. 12 Invalid file-access mode. 15 Invalid disk number. 16 Cannot remove current directory. 17 Cannot rename across volumes. I/O errors : 100 Error when reading from disk. 101 Error when writing to disk. 102 File not assigned. 103 File not open. 104 File not opened for input. 105 File not opened for output. 106 Invalid number. Fatal errors : 150 Disk is write protected. 151 Unknown device. 152 Drive not ready. 153 Unknown command. 154 CRC check failed. 155 Invalid drive specified.. 156 Seek error on disk. 157
Page 144
Invalid media type. 158 Sector not found. 159 Printer out of paper. 160 Error when writing to device. 161 Error when reading from device. 162 Hardware failure.
ERRORS:
None.
SEE ALSO:
All I/O functions. Example Program Example35; { Program to demonstrate the IOResult function. } Var F : text; begin Assign (f,paramstr(1)); {$i-} Reset (f); {$i+} If IOresult<>0 then writeln ('File ',paramstr(1),' doesn''t exist') else writeln ('File ',paramstr(1),' exists'); end.
Length
DECLARATION: DESCRIPTION:
Length returns the length of the string S, which is limited to 255. If the strings S is empty, 0 is returned. Note: The length of the string S is stored in S[0]. Function Length (S : String) : Byte;
ERRORS:
None.
SEE ALSO:
Pos Example Program Example36; { Program to demonstrate the Length function. } Var S : String; I : Integer;
Page 145
begin S:=''; for i:=1 to 10 do begin S:=S+'*'; Writeln (Length(S):2,' : ',s); end; end.
Ln
DECLARATION:
Function Ln (X : real) : Real;
DESCRIPTION:
Ln returns the natural logarithm of the real parameter X. X must be positive.
ERRORS:
An run-time error will occur when X is negative.
SEE ALSO:
Exp Example Program Example37; { Program to demonstrate the Ln function. } begin Writeln (Ln(1)); { Prints 0 } Writeln (Ln(Exp(1))); { Prints 1 } end.
Lo
DECLARATION:
Function Lo (O : Word or Longint) : Byte or Word;
DESCRIPTION:
Lo returns the low byte of its argument if this is of type Integer or Word. It returns the low word of its argument if this is of type Longint or Cardinal.
ERRORS:
None.
SEE ALSO:
Ord, Chr Example Program Example38;
Page 146
{ Program to demonstrate the Lo function. } Var L : Longint; W : Word; begin L:=(1 Shl 16) + (1 Shl 4); Writeln (Lo(L)); W:=(1 Shl 8) + (1 Shl 4); Writeln (Lo(W)); end. { { { { $10010 Prints $110 Prints } 16 } } 16 }
Lowercase
DECLARATION:
Function Lowercase (C : Char or String) : Char or String;
DESCRIPTION:
Lowercase returns the lowercase version of its argument C. If its argument is a string, then the complete string is converted to lowercase. The type of the returned value is the same as the type of the argument.
ERRORS:
None.
SEE ALSO:
Upcase Example Program Example73; { Program to demonstrate the Lowercase function. } Var I : Longint; begin For i:=ord('A') to ord('Z') do write (lowercase(chr(i))); Writeln; Writeln (Lowercase('ABCDEFGHIJKLMNOPQRSTUVWXYZ')); end.
Mark
DECLARATION:
Procedure Mark (Var P : Pointer) ;
DESCRIPTION:
Mark copies the current heap-pointer to P.
ERRORS:
None.
SEE ALSO:
Getmem, Freemem, New, Dispose, Maxavail
Page 147
Example Program Example39; { Program to demonstrate the Mark and Release functions. } Var P,PP,PPP,MM : Pointer; begin Getmem (P,100); Mark (MM); Writeln ('Getmem 100 : Memory (marked)'); GetMem (PP,1000); Writeln ('Getmem 1000 : Memory GetMem (PPP,100000); Writeln ('Getmem 10000 : Memory Release (MM); Writeln ('Released : Memory { At this point, PP and PPP are end.
Maxavail
DECLARATION:
Function Maxavail : Longint;
DESCRIPTION:
Maxavail returns the size, in bytes, of the biggest free memory block in the heap. Remark: The heap grows dynamically if more memory is needed than is available.
ERRORS:
None.
SEE ALSO:
Release, Memavail,Freemem, Getmem Example Program Example40; { Program to demonstrate the MaxAvail function. } Var P : Pointer; I : longint; begin { This will allocate memory until there is no more memory} I:=0; While MaxAvail>=1000 do begin Inc (I); GetMem (P,1000); end; { Default 4MB heap is allocated, so 4000 blocks should be allocated.
Page 148
When compiled with the -Ch10000 switch, the program will be able to allocate 10 block } Writeln ('Allocated ',i,' blocks of 1000 bytes'); end.
Memavail
DECLARATION: DESCRIPTION:
Memavail returns the size, in bytes, of the free heap memory. Remark: The heap grows dynamically if more memory is needed than is available. Function Memavail : Longint;
ERRORS:
None.
SEE ALSO:
Maxavail,Freemem, Getmem Example Program Example41; { Program to demonstrate the MemAvail function. } Var P, PP : Pointer; begin GetMem (P,100); GetMem (PP,10000); FreeMem (P,100); { Due to the heap fragmentation introduced By the previous calls, the maximum amount of memory isn't equal to the maximum block size available. } Writeln ('Total heap available (Bytes) : ',MemAvail); Writeln ('Largest block available (Bytes) : ',MaxAvail); end.
Mkdir
DECLARATION:
Procedure Mkdir (const S : string) ;
DESCRIPTION:
Chdir creates a new directory S.
ERRORS:
If a parent-directory of directory S doesn't exist, a run-time error is generated.
SEE ALSO:
Chdir, Rmdir For an example, see Rmdir.
Page 149
Move
DECLARATION:
Procedure Move (var Source,Dest;Count : longint) ;
DESCRIPTION:
Move moves Count bytes from Source to Dest.
ERRORS:
If either Dest or Source is outside the accessible memory for the process, then a run-time error will be generated. With older versions of the compiler, a segmentation-fault will occur.
SEE ALSO:
Fillword, Fillchar Example Program Example42; { Program to demonstrate the Move function. } Var S1,S2 : String [30]; begin S1:='Hello World !'; S2:='Bye, bye !'; Move (S1,S2,Sizeof(S1)); Writeln (S2); end.
New
DECLARATION: DESCRIPTION:
New allocates a new instance of the type pointed to by P, and puts the address in P. If P is an object, then it is possible to specify the name of the constructor with which the instance will be created. Procedure New (Var P : Pointer[, Constructor]) ;
ERRORS:
If not enough memory is available, Nil will be returned.
SEE ALSO:
Dispose, Freemem, Getmem, Memavail, Maxavail For an example, see Dispose.
Odd
DECLARATION:
Page 150
Function Odd (X : longint) : Boolean;
DESCRIPTION:
Odd returns True if X is odd, or False otherwise.
ERRORS:
None.
SEE ALSO:
Abs, Ord Example Program Example43; { Program to demonstrate the Odd function. } begin If Odd(1) Then Writeln ('Everything OK with 1 !'); If Not Odd(2) Then Writeln ('Everything OK with 2 !'); end.
Ofs
DECLARATION:
Function Ofs Var X : Longint;
DESCRIPTION:
Ofs returns the offset of the address of a variable. This function is only supported for compatibility. In Free Pascal, it returns always the complete address of the variable, since Free Pascal is a 32 bit compiler.
ERRORS:
None.
SEE ALSO:
DSeg, CSeg, Seg, Ptr Example Program Example44; { Program to demonstrate the Ofs function. } Var W : Pointer; begin W:=Ofs(W); { W contains its own offset. } end.
Ord
DECLARATION:
Function Ord (X : Ordinal type) : Byte;
Page 151
DESCRIPTION:
Ord returns the Ordinal value of a ordinal-type variable X.
ERRORS:
None.
SEE ALSO:
Chr Example Program Example45; { Program to demonstrate the Ord function. } Type TEnum = (Zero, One, Two, Three, Four); Var X : Longint; Y : TEnum; begin X:=125; Writeln (Ord(X)); Y:= One; Writeln (Ord(y)); end.
Paramcount
DECLARATION: DESCRIPTION:
Paramcount returns the number of command-line arguments. If no arguments were given to the running program, 0 is returned. Function Paramcount : Longint;
ERRORS:
None.
SEE ALSO:
Paramstr Example Program Example46; { Program to demonstrate the ParamCount and ParamStr functions. } Var I : Longint; begin Writeln (paramstr(0),' : Got ',ParamCount,' command-line parameters: '); For i:=1 to ParamCount do Writeln (ParamStr (i)); end.
Page 152
Paramstr
DECLARATION: DESCRIPTION:
Paramstr returns the L-th command-line argument. L must be between 0 and Paramcount, these values included. The zeroth argument is the name with which the program was started. Function Paramstr (L : Longint) : String;
ERRORS:
Under Linux, command-line arguments may be longer than 255 characters. In that case, the string is truncated. If you want to access the complete string, you must use the argv pointer to access the real values of the command-line parameters.
SEE ALSO:
Paramcount For an example, see Paramcount.
Pi
DECLARATION:
Function Pi : Real;
DESCRIPTION:
Pi returns the value of Pi (3.1415926535897932385).
ERRORS:
None.
SEE ALSO:
Cos, Sin Example Program Example47; { Program to demonstrate the Pi function. } begin Writeln (Pi); Writeln (Sin(Pi)); end. {3.1415926}
Pos
DECLARATION:
Function Pos (Const Substr : String;Const S : String) : Byte;
DESCRIPTION:
Pos returns the index of Substr in S, if S contains Substr. In case Substr isn't found, 0 is returned. The search is case-sensitive.
Page 153
ERRORS:
None
SEE ALSO:
Length, Copy, Delete, Insert Example Program Example48; { Program to demonstrate the Pos function. } Var S : String; begin S:='The first space in this sentence is at position : '; Writeln (S,pos(' ',S)); S:='The last letter of the alphabet doesn''t appear in this sentence '; If (Pos ('Z',S)=0) and (Pos('z',S)=0) then Writeln (S); end.
Ptr
DECLARATION:
Function Ptr (Sel,Off : Longint) : Pointer;
DESCRIPTION:
Ptr returns a pointer, pointing to the address specified by segmentSel and offset Off. Remark 1: In the 32-bit flat-memory model supported by Free Pascal, this function is obsolete.
ERRORS:
Remark 2:
SEE ALSO:
The returned address is simply the offset. If you recompile the RTL with -dDoMapping defined, then the compiler returns the following : ptr:=pointer($e0000000+sel shl 4+off) under DOS, or ptr:=pointer(sel shl 4+off) on other OSes. None. Addr Example Program Example59; { Program to demonstrate the Ptr function. } Var P : ^String; S : String; begin S:='Hello, World !'; P:=Ptr(Seg(S),Longint(Ofs(S))); {P now points to S !} Writeln (P^); end.
Page 154
Random
DECLARATION:
Function Random [(L : longint)] : Longint or Real;
DESCRIPTION:
Random returns a random number larger or equal to 0 and strictly less than L. If the argument L is omitted, a real number between 0 and 1 is returned. (0 included, 1 excluded)
ERRORS:
None.
SEE ALSO:
Randomize Example Program Example49; { Program to demonstrate the Random and Randomize functions. } Var I,Count,guess : Longint; R : Real; begin Randomize; { This way we generate a new sequence every time the program is run} Count:=0; For i:=1 to 1000 do If Random>0.5 then inc(Count); Writeln ('Generated ',Count,' numbers > 0.5'); Writeln ('out of 1000 generated numbers.'); count:=0; For i:=1 to 5 do begin write ('Guess a number between 1 and 5 : '); readln(Guess); If Guess=Random(5)+1 then inc(count); end; Writeln ('You guessed ',Count,' out of 5 correct.'); end.
Randomize
DECLARATION: DESCRIPTION:
Randomize initializes the random number generator of Free Pascal, by giving a value to Randseed, calculated with the system clock. Procedure Randomize ;
ERRORS:
None.
SEE ALSO:
Random
Page 155
Read
DECLARATION: DESCRIPTION:
Read reads one or more values from a file F, and stores the result in V1, V2, etc.; If no file F is specified, then standard input is read. If F is of type Text, then the variables V1, V2 etc. must be of type Char, Integer, Real or String. If F is a typed file, then each of the variables must be of the type specified in the declaration of F. Untyped files are not allowed as an argument. Procedure Read ([Var F : Any file type], V1 [, V2, ... , Vn]) ;
ERRORS:
If no data is available, a run-time error is generated. This behavior can be controlled with the {$i} compiler switch.
SEE ALSO:
Readln, Blockread, Write, Blockwrite Example Program Example50; { Program to demonstrate the Read(Ln) function. } Var S : String; C : Char; F : File of char; begin Assign (F,'ex50.pp'); Reset (F); C:='A'; Writeln ('The characters before the first space in ex50.pp are : '); While not Eof(f) and (C<>' ') do Begin Read (F,C); Write (C); end; Writeln; Close (F); Writeln ('Type some words. An empty line ends the program.'); repeat Readln (S); until S=''; end.
Readln
Page 156 Free Pascal Manual
DECLARATION:
Procedure Readln [Var F : Text], V1 [, V2, ... , Vn]) ;
DESCRIPTION:
Read reads one or more values from a file F, and stores the result in V1, V2, etc. After that it goes to the next line in the file (defined by the LineFeed (#10) character). If no file F is specified, then standard input is read. The variables V1, V2 etc. must be of type Char, Integer, Real, String or PChar.
ERRORS:
If no data is available, a run-time error is generated. This behavior can be controlled with the {$i} compiler switch.
SEE ALSO:
Read, Blockread, Write, Blockwrite For an example, see Read.
Release
DECLARATION: DESCRIPTION:
Release sets the top of the Heap to the location pointed to by P. All memory at a location higher than P is marked empty. Procedure Release (Var P : pointer) ;
ERRORS:
A run-time error will be generated if P points to memory outside the heap.
SEE ALSO:
Mark, Memavail, Maxavail, Getmem, Freemem New, Dispose For an example, see Mark.
Rename
DECLARATION:
Procedure Rename (Var F : Any Filetype; Const S : String) ;
DESCRIPTION:
Rename changes the name of the assigned file F to S. F must be assigned, but not opened.
ERRORS:
A run-time error will be generated if F isn't assigned, or doesn't exist.
SEE ALSO:
Erase Example Program Example77; { Program to demonstrate the Rename function. } Var F : Text;
Page 157
Reset
DECLARATION: DESCRIPTION:
Reset opens a file F for reading. F can be any file type. If F is an untyped or typed file, then it is opened for reading and writing. If F is an untyped file, the record size can be specified in the optional parameter L. Default a value of 128 is used. Procedure Reset (Var F : Any File Type[; L : longint]) ;
ERRORS:
If the file cannot be opened for reading, then a run-time error is generated. This behavior can be changed by the {$i} compiler switch.
SEE ALSO:
Rewrite, Assign, Close Example Program Example51; { Program to demonstrate the Reset function. } Function FileExists (Name : String) : boolean; Var F : File; begin {$i-} Assign (F,Name); Reset (F); {$I+} FileExists:=(IoResult=0) and (Name<>''); Close (f); end; begin If FileExists (Paramstr(1)) then Writeln ('File found') else Writeln ('File NOT found'); end.
Rewrite
DECLARATION:
Procedure Rewrite (Var F : Any File Type[; L : longint]) ;
Page 158
DESCRIPTION:
Rewrite opens a file F for writing. F can be any file type. If F is an untyped or typed file, then it is opened for reading and writing. If F is an untyped file, the record size can be specified in the optional parameter L. Default a value of 128 is used. if Rewrite finds a file with the same name as F, this file is truncated to length 0. If it doesn't find such a file, a new file is created.
ERRORS:
If the file cannot be opened for writing, then a run-time error is generated. This behavior can be changed by the {$i} compiler switch.
SEE ALSO:
Reset, Assign, Close Example Program Example52; { Program to demonstrate the Rewrite function. } Var F : File; I : longint; begin Assign (F,'Test.dat'); { Create the file. Recordsize is 4 } Rewrite (F,Sizeof(I)); For I:=1 to 10 do BlockWrite (F,I,1); close (f); { F contains now a binary representation of 10 longints going from 1 to 10 } end.
Rmdir
DECLARATION: DESCRIPTION:
Rmdir removes the directory S. Procedure Rmdir (const S : string) ;
ERRORS:
If S doesn't exist, or isn't empty, a run-time error is generated.
SEE ALSO:
Chdir, Rmdir Example Program Example53; { Program to demonstrate the MkDir and RmDir functions. } Const D : String[8] = 'TEST.DIR'; Var S : String;
Page 159
begin Writeln ('Making directory ',D); Mkdir (D); Writeln ('Changing directory to ',D); ChDir (D); GetDir (0,S); Writeln ('Current Directory is : ',S); WRiteln ('Going back'); ChDir ('..'); Writeln ('Removing directory ',D); RmDir (D); end.
Round
DECLARATION: DESCRIPTION:
Round rounds X to the closest integer, which may be bigger or smaller than X. Function Round (X : real) : Longint;
ERRORS:
None.
SEE ALSO:
Frac, Int, Trunc Example Program Example54; { Program to demonstrate the Round function. } begin Writeln Writeln Writeln Writeln end. (Round(123.456)); (Round(-123.456)); (Round(12.3456)); (Round(-12.3456)); { { { { Prints Prints Prints Prints 124 -124 12 -12 } } } }
Runerror
DECLARATION: DESCRIPTION:
Runerror stops the execution of the program, and generates a run-time error ErrorCode. Procedure Runerror (ErrorCode : Word) ;
ERRORS:
None.
SEE ALSO:
Exit, Halt Example
Page 160
Program Example55; { Program to demonstrate the RunError function. } begin { The program will stop end emit a run-error 106 } RunError (106); end.
Seek
DECLARATION: DESCRIPTION:
Seek sets the file-pointer for file F to record Nr. Count. The first record in a file has Count=0. F can be any file type, except Text. If F is an untyped file, with no specified record size, 128 is assumed. Procedure Seek (Var F; Count : Longint) ;
ERRORS:
A run-time error is generated if Count points to a position outside the file, or the file isn't opened.
SEE ALSO:
Eof, SeekEof, SeekEoln Example Program Example56; { Program to demonstrate the Seek function. } Var F : File; I,j : longint; begin { Create a file and fill it with data } Assign (F,'test.dat'); Rewrite(F); { Create file } Close(f); FileMode:=2; ReSet (F,Sizeof(i)); { Opened read/write } For I:=0 to 10 do BlockWrite (F,I,1); { Go Back to the begining of the file } Seek(F,0); For I:=0 to 10 do begin BlockRead (F,J,1); If J<>I then Writeln ('Error: expected ' ,i,', got ',j); end; Close (f); end.
Page 161
SeekEof
DECLARATION:
Function SeekEof [(Var F : text)] : Boolean;
DESCRIPTION:
SeekEof returns True is the file-pointer is at the end of the file. It ignores all whitespace. Calling this function has the effect that the file-position is advanced until the first non-whitespace character or the end-of-file marker is reached. If the end-of-file marker is reached, True is returned. Otherwise, False is returned. If the parameter F is omitted, standard Input is assumed.
ERRORS:
A run-time error is generated if the file F isn't opened.
SEE ALSO:
Eof, SeekEoln, Seek Example Program Example57; { Program to demonstrate the SeekEof function. } Var C : Char; begin { this will print all characters from standard input except Whitespace characters. } While Not SeekEof do begin Read (C); Write (C); end; end.
SeekEoln
DECLARATION:
Function SeekEoln [(Var F : text)] : Boolean;
DESCRIPTION:
SeekEoln returns True is the file-pointer is at the end of the current line. It ignores all whitespace. Calling this function has the effect that the file-position is advanced until the first non-whitespace character or the end-of-line marker is reached. If the end-of-line marker is reached, True is returned. Otherwise, False is returned. The end-of-line marker is defined as #10, the LineFeed character. If the parameter F is omitted, standard Input is assumed.
ERRORS:
A run-time error is generated if the file F isn't opened.
SEE ALSO:
Eof, SeekEof, Seek Example
Page 162
Program Example58; { Program to demonstrate the SeekEoln function. } Var C : Char; begin { This will read the first line of standard output and print all characters except whitespace. } While not SeekEoln do Begin Read (c); Write (c); end; end.
Seg
DECLARATION:
Function Seg Var X : Longint;
DESCRIPTION:
Seg returns the segment of the address of a variable. This function is only supported for compatibility. In Free Pascal, it returns always 0, since Free Pascal is a 32 bit compiler, segments have no meaning.
ERRORS:
None.
SEE ALSO:
DSeg, CSeg, Ofs, Ptr Example Program Example60; { Program to demonstrate the Seg function. } Var W : Word; begin W:=Seg(W); end. { W contains its own Segment}
SetTextBuf
DECLARATION: DESCRIPTION:
SetTextBuf assigns an I/O buffer to a text file. The new buffer is located at Buf and is Size bytes long. If Size is omitted, then SizeOf(Buf) is assumed. The standard buffer of any text file is 128 bytes long. For heavy I/0 operations this may prove too slow. The SetTextBuf procedure allows you to set a bigger buffer for your application, thus reducing the Procedure SetTextBuf (Var f : Text; Var Buf[; Size : Word]) ;
Page 163
number of system calls, and thus reducing the load on the system resources. The maximum size of the newly assigned buffer is 65355 bytes. Remark 1: Never assign a new buffer to an opened file. You can assign a new buffer immediately after a call to Rewrite, Reset or Append, but not after you read from/wrote to the file. This may cause loss of data. If you still want to assign a new buffer after read/write operations have been performed, flush the file first. This will ensure that the current buffer is emptied. Remark 2: Take care that the buffer you assign is always valid. If you assign a local variable as a buffer, then after your program exits the local program block, the buffer will no longer be valid, and stack problems may occur.
ERRORS:
No checking on Size is done.
SEE ALSO:
Assign, Reset, Rewrite, Append Example Program Example61; { Program to demonstrate the SetTextBuf function. } Var Fin,Fout : Text; Ch : Char; Bufin,Bufout : Array[1..10000] of byte; begin Assign (Fin,paramstr(1)); Reset (Fin); Assign (Fout,paramstr(2)); Rewrite (Fout); { This is harmless before IO has begun } { Try this program again on a big file, after commenting out the following 2 lines and recompiling it. } SetTextBuf (Fin,Bufin); SetTextBuf (Fout,Bufout); While not eof(Fin) do begin Read (Fin,ch); write (Fout,ch); end; Close (Fin); Close (Fout); end.
Sin
DECLARATION: DESCRIPTION:
Sin returns the sine of its argument X, where X is an angle in radians. Function Sin (X : real) : Real;
Page 164
ERRORS:
None.
SEE ALSO:
Cos, Pi, Exp Example Program Example62; { Program to demonstrate the Sin function. } begin Writeln (Sin(Pi):0:1); { Prints 0.0 } Writeln (Sin(Pi/2):0:1); { Prints 1.0 } end.
SizeOf
DECLARATION: DESCRIPTION:
SizeOf Returns the size, in bytes, of any variable or type-identifier. Remark: this isn't really a RTL function. Its result is calculated at compile-time, and hard-coded in your executable. Function SizeOf (X : Any Type) : Longint;
ERRORS:
None.
SEE ALSO:
Addr Example Program Example63; { Program to demonstrate the SizeOf function. } Var I : Longint; S : String [10]; begin Writeln (SizeOf(I)); Writeln (SizeOf(S)); end. { Prints 4 } { Prints 11 }
Sptr
DECLARATION: DESCRIPTION:
Sptr returns the current stack pointer. Function Sptr : Pointer;
Page 165
ERRORS:
None.
SEE ALSO:
Example Program Example64; { Program to demonstrate the SPtr function. } Var P :Longint; begin P:=Sptr; { P Contains now the current stack position. } end.
Sqr
DECLARATION: DESCRIPTION:
Sqr returns the square of its argument X. Function Sqr (X : Real) : Real;
ERRORS:
None.
SEE ALSO:
Sqrt, Ln, Exp Example Program Example65; { Program to demonstrate the Sqr function. } Var i : Integer; begin For i:=1 to 10 do writeln (Sqr(i):3); end.
Sqrt
DECLARATION:
Function Sqrt (X : Real) : Real;
DESCRIPTION:
Sqrt returns the square root of its argument X, which must be positive.
ERRORS:
If X is negative, then a run-time error is generated.
Page 166
SEE ALSO:
Sqr, Ln, Exp Example Program Example66; { Program to demonstrate the Sqrt function. } begin Writeln (Sqrt(4):0:3); { Prints 2.000 } Writeln (Sqrt(2):0:3); { Prints 1.414 } end.
SSeg
DECLARATION:
Function SSeg : Longint;
DESCRIPTION:
SSeg returns the Stack Segment. This function is only supported for compatibolity reasons, as Sptr returns the correct contents of the stackpointer.
ERRORS:
None.
SEE ALSO:
Sptr Example Program Example67; { Program to demonstrate the SSeg function. } Var W : Longint; begin W:=SSeg; end.
Str
DECLARATION:
Procedure Str (Var X[:NumPlaces[:Decimals]]; Var S : String) ;
DESCRIPTION:
Str returns a string which represents the value of X. X can be any numerical type. The optional NumPLaces and Decimals specifiers control the formatting of the string.
ERRORS:
None.
SEE ALSO:
Val Example
Page 167
Program Example68; { Program to demonstrate the Str function. } Var S : String; Function IntToStr (I : Longint) : String; Var S : String; begin Str (I,S); IntToStr:=S; end; begin S:='*'+IntToStr(-233)+'*'; Writeln (S); end.
Swap
DECLARATION: DESCRIPTION:
Swap swaps the high and low order bytes of X if X is of type Word or Integer, or swaps the high and low order words of X if X is of type Longint or Cardinal. The return type is the type of X Function Swap (X) : Type of X;
ERRORS:
None.
SEE ALSO:
Lo, Hi Example Program Example69; { Program to demonstrate the Swap function. } Var W : Word; L : Longint; begin W:=$1234; W:=Swap(W); if W<>$3412 then writeln ('Error when swapping word !'); L:=$12345678; L:=Swap(L); if L<>$56781234 then writeln ('Error when swapping Longint !'); end.
Page 168
Trunc
DECLARATION:
Function Trunc (X : real) : Longint;
DESCRIPTION:
Trunc returns the integer part of X, which is always smaller than (or equal to) X.
ERRORS:
None.
SEE ALSO:
Frac, Int, Trunc Example Program Example54; { Program to demonstrate the Trunc function. } begin Writeln Writeln Writeln Writeln end. (Trunc(123.456)); (Trunc(-123.456)); (Trunc(12.3456)); (Trunc(-12.3456)); { { { { Prints Prints Prints Prints 123 -123 12 -12 } } } }
Truncate
DECLARATION: DESCRIPTION:
Truncate truncates the (opened) file F at the current file position. Procedure Truncate (Var F : file) ;
ERRORS:
Errors are reported by IOresult.
SEE ALSO:
Append, Filepos, Seek Example Program Example71; { Program to demonstrate the Truncate function. } Var F : File of longint; I,L : Longint; begin Assign (F,'test.dat'); Rewrite (F); For I:=1 to 10 Do Write (F,I); Writeln ('Filesize before Truncate : ',FileSize(F)); Close (f); Reset (F); Repeat
Page 169
Read (F,I); Until i=5; Truncate (F); Writeln ('Filesize after Truncate Close (f); end.
: ',Filesize(F));
Upcase
DECLARATION:
Function Upcase (C : Char or string) : Char or String;
DESCRIPTION:
Upcase returns the uppercase version of its argument C. If its argument is a string, then the complete string is converted to uppercase. The type of the returned value is the same as the type of the argument.
ERRORS:
None.
SEE ALSO:
Lowercase Example Program Example72; { Program to demonstrate the Upcase function. } Var I : Longint; begin For i:=ord('a') to ord('z') do write (upcase(chr(i))); Writeln; { This doesn't work in TP, but it does in Free Pascal } Writeln (Upcase('abcdefghijklmnopqrstuvwxyz')); end.
Val
DECLARATION: DESCRIPTION:
Val converts the value represented in the string S to a numerical value, and stores this value in the variable V, which can be of type Longint, real and Byte. If the conversion isn't succesfull, then the parameter Code contains the index of the character in S which prevented the conversion. The string S isn't allow to contain spaces. Procedure Val (const S : string;var V;var Code : word) ;
ERRORS:
If the conversion doesn't succeed, the value of Code indicates the position where the conversion went wrong.
Page 170
SEE ALSO:
Str Example Program Example74; { Program to demonstrate the Val function. } Var I, Code : Integer; begin Val (ParamStr (1),I,Code); If Code<>0 then Writeln ('Error at position ',code,' : ',Paramstr(1)[Code]) else Writeln ('Value : ',I); end.
Write
DECLARATION:
Procedure Write ([Var F : Any filetype;] V1 [; V2; ... , Vn)] ;
DESCRIPTION:
Write writes the contents of the variables V1, V2 etc. to the file F. F can be a typed file, or a Text file. If F is a typed file, then the variables V1, V2 etc. must be of the same type as the type in the declaration of F. Untyped files are not allowed. If the parameter F is omitted, standard output is assumed. If F is of type Text, then the necessary conversions are done such that the output of the variables is in human-readable format. This conversion is done for all numerical types. Strings are printed exactly as they are in memory, as well as PChar types. The format of the numerical conversions can be influenced through the following modifiers: OutputVariable : NumChars [: Decimals ] This will print the value of OutputVariable with a minimum of NumChars characters, from which Decimals are reserved for the decimals. If the number cannot be represented with NumChars characters, NumChars will be increased, until the representation fits. If the representation requires less than NumChars characters then the output is filled up with spaces, to the left of the generated string, thus resulting in a right-aligned representation. If no formatting is specified, then the number is written using its natural length, with a space in front of it if it's positive, and a minus sign if it's negative. Real numbers are, by default, written in scientific notation.
ERRORS:
If an error occurs, a run-time error is generated. This behavior can be controlled with the {$i} switch.
SEE ALSO:
Writeln, Read, Readln, Blockwrite
Writeln
DECLARATION:
Procedure Writeln [([Var F : Text;] [V1 [; V2; ... , Vn)]] ;
Page 171
DESCRIPTION:
Writeln does the same as Write for text files, and emits a Carriage Return - LineFeed character pair after that. If the parameter F is omitted, standard output is assumed. If no variables are specified, a Carriage Return - LineFeed character pair is emitted, resulting in a new line in the file F. Remark: Under LINUX, the Carriage Return character is omitted, as customary in Unix environments.
ERRORS:
If an error occurs, a run-time error is generated. This behavior can be controlled with the {$i} switch.
SEE ALSO:
Write, Read, Readln, Blockwrite Example Program Example75; { Program to demonstrate the Write(ln) function. } Var F : File of Longint; L : Longint; begin Write ('This is on the first line ! '); { No CR/LF pair! } Writeln ('And this too...'); Writeln ('But this is already on the second line...'); Assign (f,'test.dat'); Rewrite (f); For L:=1 to 10 do write (F,L); { No writeln allowed here ! } Close (f); end.
Page 172