Turbo Pascal Version 7.0 Language Guide 1992 PDF
Turbo Pascal Version 7.0 Language Guide 1992 PDF
LANGUAGE GUIDE
• LANGUAGE DEFINITION
• STANDARD UNITS
• MEMORY MANAGEMENT
• ASSEMBLY LANGUAGE
B 0 R L 'A N D
Turbo Pasca/®
Version 7.0
Language Guide
iii
Character pointers and character Part 3 Inside Turbo Pascal
arrays ........................... 171
Character pointer indexing . . . . . . . .. 171 Chapter 19 Memory issues 209
Null-terminated strings and standard The Turbo Pascal memory map ....... 209
procedures ....................... 173 The heap manager .................. 211
An example using string-handling Disposal methods . . . . . . . . . . . . . . . .. 212
functions ........................ 173 The free list ...................... 215
The HeapError variable . . . . . . . . . . .. 217
Chapter 17 Using the Borland Internal data formats ................ 218
Graphics Interface 175 Integer types ..................... 218
Drivers ............................ 175 Char types ....................... 218
IBM 8514 support .......... , ...... 176 Boolean types .................... 218
Coordinate system ................ 177 Enumerated types. . . . . . . . . . . . . . . .. 219
Current pointer . . . . . . . . . . . . . . . . . . . .. 178 Floating-point types. . . . . . . . . . . . . .. 219
Text ............................... 178 The Real type . . . . . . . . . . . . . ... . . .. 219
Figures and styles. . . . . . . . . . . . . . . . . .. 179 The Single type ..... . . . . . . . . . . .. 220
Viewports and bit images .......... 179 The Double type ................ 220
Paging and colors .... . . . . . . . . . . . . . .. 180 The Extended type .............. 220
Error handling ...................... 180 The Comp type ................. 221
Getting started ..................... 181 Pointer types ..................... 221
Heap management routines ........ 183 String types ...................... 221
Graph procedures and functions ...... 185 Set types ......................... 221
Graph unit constants, types, and Array types ...................... 222
variables. . . . . . . . . . . . . . . . . . . . . . . . . .. 188 Record types ..................... 222
Constants .. . . . . . . . . . . . . . . . . . . . . .. 188 Object types . . . . . . . . . . . . . . . . . . . . .. 222
Types ........................... 189 Virtual method tables ........... 223
Variables ........................ 189 Dynamic method tables . . . . . . . . .. 225
File types ........................ 228
Chapter 18 Using overlays 191
Procedural types .................. 230
The overlay manager ................ 192 Direct memory access ............... 230
Overlay buffer management. . . . . . .. 193 Direct port access ................... 231
Overlay procedures and functions ..... 195
Variables and constants .............. 196 Chapter 20 Control issues 233
Result codes . . . . . . . . . . . . . . . . . . . . .. 196 Calling conventions ................. 233
Designing overlaid programs . . . . . . . .. 197 Variable parameters . . . . . . . . . . . . . .. 234
Overlay code generation ........... 197 , Value parameters ................. 234
The far call requirement ........... 197 Open parameters ................,. 235
Initializing the overlay manager .... 198 Function results .................. 235
Initialization sections .............. 201 NEAR and FAR calls .............. 236
What not to overlay ............... 202 Nested procedures and functions ... 236
Debugging overlays .. . . . . . . . . . . . .. 202 Method calling conventions ........ 237
External routines in overlays ....... 203 Virtual method calls . . . . . . . . . . . . . .. 238
Installing an overlay-read function .... 204 Dynamic method calls . . . . . . . . . . . .. 239
Overlays in .EXE files . . . . . . . . . . . . . . .. 205 Constructors and destructors ....... 240
iv
Entry and exit code ................ 240 Instruction opcodes ............... 257
Register-saving conventions . . . . . . .. 241 RET instruction sizing ........... 258
Exit procedures . . . . . . . . . . . . . . . . . . . .. 241 Automatic jump sizing .......... 258
Interrupt handling .................. 243 Assembler directives .............. 259
Writing interrupt procedures ....... 243 Operands ........................ 261
Expressions ........................ 262
Chapter 21 Optimizing your code 245
Differences between Pascal and
Constantfolding .................... 245 Assembler expressions. . . . . . . . . . . .. 262
Constant merging . . . . . . . . . . . . . . . . . .. 246 Expression elements . . . . . . . . . . . . . .. 263
Short-circuit evaluation . . . . . . . . . . . . .. 246 Constants . . . . . . . . . . . . . . . . . . . . .. 263
Constant parameters ................ 246 Numeric constants ............ 263
Redundant pointer-load elimination ... 247 String constants . . . . . . . . . . . . . .. 264
Constant set inlining ................ 247 Registers ....................... 265
Small sets . . . . . . . . . . . . . . . . . . . . . . . . .. 248 Symbols ....................... 265
Order of evaluation ................. 248 Expression classes . . . . . . . . . . . . . . . .. 269
Range checking . . . . . . . . . . . . . . . . . . . .. 249 Expression types . . . . . . . . . . . . . . . . .. 270
Shift instead of multiply or divide ..... 249 Expression operators .............. 272
Automatic word alignment . . . . . . . . . .. 249 Assembler procedures and functions .. 274
Eliminating dead code ............... 250
Smart linking . . . . . . . . . . . . . . . . . . . . . .. 250 Chapter 23 Linking assembler code 279
Turbo Assembler and Turbo Pascal . . .. 280
Part 4 Using Turbo Pascal with
Examples of assembly language
assembly language routines ........................... 281
Chapter 22 The built-in assembler 255 Assembly language methods ......... 283
The asm statement .................. 256 Inline machine code . . . . . . . . . . . . . . . .. 284
Register use ...................... 256 Inline statements .................. 284
Assembler statement syntax .......... 256 Inline directives .................. 285
Labels ........................... 257 Index 287
v
T A B L E s
·2.1: Turbo Pascal reserved words ........ 16 15.3: Dos unit disk status functions ..... 161
2.2: Turbo Pascal directives ............. 17 15.4: Dos unit file-handling procedures
4.1: Predefined integer types ............ 25 and functions ................... 161
4.2: Real data types .................... 28 15.5: Dos unit environment-handling
6.1: Precedence of operators ............ 65 functions ....................... 161
6.2: Binary arithmetic operations ........ 68 15.6: Dos unit process-handling
6.3: Unary arithmetic operations ........ 69 procedures ..................... 161
6.4: Logical operations ................. 70 15.7: Dos unit miscellaneous procedures
6.5: Boolean operations .. ·.............. 70 and functions ................... 162
6.6: String operation ................... 71 15.8: Dos unit constants ............... 162
6.7: Permitted PChar constructs ......... 72 15.9: Dos unit types .................. 163
6.8: Set operations ..................... 72 15.10: WinDos date and time
6.9: Relational operations .............. 73 procedures ................... ~163
12.1: Flow-control procedures .......... 130 15.11: WinDos unit interrupt support
12.2: Transfer functions ............... 130 procedures .................... 164
12.3: Arithmetic functions ............. 130 15.12: WinDos unit disk status functions .164
12.4: Ordinal procedures and functions .131 15.13: File-handling procedures and
12.5: String procedures and functions ... 131 functions ...................... 164
12.6: Dynamic-allocation procedures and 15.14: WinDos unit directory-handling
functions ....................... 132 procedures and functions ........ 165
12.7: Pointer and address functions ..... 132 15.15: WinDos unit environment-handling
12.8: Miscellaneous procedures and functions ...................... 165
functions ....................... 133 15.16: WinDos unit miscellaneous
12.9: Predeclared variables in the System procedures and functions ........ 165
unit ............................ 133 15.17: WinDos constants .............. 166
13.1: Input and output procedures and 15.18: WinDos unit types .............. 166
functions ....................... 135 16.1: Strings unit functions ............ 168
13.2: Control characters .............. 143 17.1: BGI drivers ..................... 176
13.3: Line input editing keys ........... 143 17.2: Graph unit procedures and
13.4: Crt unit procedures and functions .144 functions ....................... 185
13.5: Crt unit constants ............... 145 17.3: Graph unit constant groups ....... 188
13.6: Crt unit variables ................ 145 17.4: Graph unit types ................ 189
14.1: Test8087 variable values .......... 157 18.1: Overlay unit procedures and
15.1: Dos unit date and time procedures .160 functions ....................... 196
15.2: Dos unit interrupt support 18.2: Overlay unit variables ........... 196
procedures ..................... 160 22.1: Built-in assembler reserved words .261
vi
22.2: String examples and their values .. 265 22.6: Summary of built-in asssembler
22.3: CPU registers ................... 265 expression operators ............. 272
22.4: Values, classes, and types of 22.7: Definitions of built-in assembler
symbols ........................ 267 expression operators ............. 273
22.5: Predefined type symbols ......... 272
vii
F G u R E s
1.1: Procedure or function diagram ....... 6 19.4: Creating a "hole" in the heap ..... 214
1.2: Simple Pascal program diagram ...... 7 19.5: Enlarging the free block .......... 214
1.3: Statement diagram ................ 10 19.6: Releasing the free block .......... 215
1.4: An expanded Pascal program ....... 12 19.7: Layouts of instances of TLocation,
17.1: Screen with xy-coordinates ........ 177 TPoint, and TCircle .............. 223
18.1: Loading and disposing of overlays .194 19.8: TPoint and TCircle's VMT layouts .225
19.1: Turbo Pascal memory map ........ 210 19.9: TBase's VMT and DMT layouts .... 227
19.2: Disposal method using Mark and 19.10: TDerived's VMT and DMT
Release ......................... 212 layouts ........................ 228
19.3: Heap layout with Release(P)
executed ....................... 213
viii
N T R o D u c T o N
Read the Introduction in the This manual is about the Turbo Pascal language. It
User's Guide for an overview
of the entire Turbo Pascal • Presents the formal definition of the Turbo Pascal language
documentation set and how
to use the Turbo Pascal • Introduces the run-time library and tells you how to use the
manuals most effectively. units that make it up
• Describes what goes on inside Turbo Pascal in regards to
memory, data formats, calling conventions, input and output,
and automatic optimizations
• Explains how to use Turbo Pascal with assembly language
You'll find this manual most useful if you are an experienced
Pascal programmer.
Read the User's Guide if
• You want to know how to install Turbo Pascal
• You've used Turbo Pascal before and you want to know what is
new in this release
• You're not familiar with Borland's integrated development
environment (the IDE)
• You want to know how to use the integrated debugger
• You want to refresh your knowledge about pointers
• You are new to object-oriented programming
Read the Programmer's Reference to look up reference material on
• The run-time library
• Compiler directives
• Error messages
• The command-line compiler
• The editor
Introduction
What's in this manual
This book is split into four parts: language grammar, the run-time
library, advanced programming issues, and using assembly
language with Turbo Pascal.
Part I, "The Turbo Pascal language," defines the Turbo Pascal
language. First you're introduced to the overall structure of a
Turbo Pascal program; then you examine each element of a
program in detail.
Part II, "The run-time library," contains information about using
all the standard units: the System, Dos, WinDos, Strings, Crt,
Overlay, and Graph units.
Part III, "Inside Turbo Pascal," presents technical information for
advanced users about
• How Turbo Pascal uses memory
• How Turbo Pascal implements program control
• Using the 80x87
• Optimizing your code
Part IV, "Using Turbo Pascal with assembly language," explains
how to use the built-in assembler and how to link your Turbo
Pascal programs with code written in Turbo Assembler.
2 Language Guide
p A R T
3
4 Language Guide
c H A p T E R
Figure 1.1
Procedure or function Procedure or function
diagram
Procedure or function heading
!.L09iC
end;
If you find your program does the same thing many times, you
might want to put the logic into a procedure or function. You
write the code in a procedure or function once and your program
can use it as often as necessary.
Here is an example of a function. This GetNumber function gets a
number from the user:
6 Language Guide
function GetNumber: Reali
var
Response: Reali
begin
Write('Enter a number: ') i
Readln(Response)i
GetNumber := Responsei
endi
A procedure or function must appear before the main code
section in the main program block. The main code section can
then use the procedure or function.
begin
The main logic of the program is found between the last begin
and end.
procedure PrintReport;
begin
A := GetNumber;
Calculate (A) ;
PrintReport;
end.
The primary logic in this program is very simple to understand.
All the details are hidden within the bodies of the procedures and
functions. Using procedures and functions encourages you to
think about your program in a logical, modular way.
Statements
The code section between begin and end contains statements that
describe the actions the program can take and is called the
statement part. These are examples of statements:
A := B + C; {Assign a value}
Calculate {Length, Height); {Activate a procedure}
if X < 2 then {Conditional statement}
Answer := X * Y;
begin {Compound statement}
X := 3;
Y := 4;
Z : = 5;
end;
8 Language Guide
while not EOF(InFile) do {Repetitive statement}
begin
Readln(InFile, Line);
Process(Line);
end;
Simple statements can either assign a value, activate a procedure
or function, or transfer the running of the program to another
statement in the code. The first two examples shown in the
examples are simple statements.
Structured statements can be compound statements that contain
multiple statements, conditional and repetitive statements that
control the flow of logic within a program, and with statements
that simplify access to data in a record.
You might compare a Pascal statement to a sentence in a human
language such as English, Danish, or Greek. Simple Pascal
statements and simple human sentences hold one complete
thought. Structured Pascal statements and complex sentences
contain more complicated logic.
Expressions
Just as a sentence is made up of phrases, so is a Pascal statement
made up of expressions. The phrases of a sentence are made up of
words, and the expressions of a statement are composed of ele-
ments called factors and operators. Expressions usually compare
things or perform arithmetic, logical, or Boolean operations.
Just as phrases in a human language can be made up of smaller
phrases, so can expressions in Pascal be made up of simpler
expressions. You can read about all the combinations of factors
and operators in Chapter 6 that make up expressions. They can be
quite complex. For now, it might help to see some examples of
expressions:
x+Y
Done <> Error
I <= Length
-x
Figure 1.3
Statements (1 or more)
Statement diagram
Expressions (1 or more)
Tokens (1 or more)
10 Language Guide
program Example;
const
A = 12; {Constant A never changes in value}
B: Integer = 23; {Typed constant B gets an initial value}
var
X, Y: Integer; {Variables X and Yare type Integer}
J: Real; {Variable J is type Real}
begin
X := 7; {Variable X is assigned a value}
Y := 8; {Variable Y is assigned a value}
X := Y + Y; {The value of variable X changes}
B := 57; {Typed constant B gets a new value}
J := 0.075; {Variable J gets a floating-point value}
end.
In this simple and not very useful program, X is assigned the
value 7 originally; two statements later it is assigned a new value,
Y + Y. The value of a variable can vary.
A is a constant. The program gives it a value of 12 and this value
can't change-its value remains constant throughout the
program.
B is a typed constant. It's given a value when it's declared, but it's
also given a type of Integer. You can think of a typed constant as a
variable with an initial value. The program can later change the
initial value of B to some other value.
The part of this program that declares the constants and variables
is called the declaration part.
If you'll look back at the code example on page 7, you'll see that
the function GetNumber has a declaration part that declares a
variable. Procedures and functions can contain a declaration part
just as a program or unit can.
Declarations
begin
Statements (1 or more)
end.
The program heading, the optional uses clause (we'll talk about
this in the next section), and the main program block make up a
Pascal program. Within the main program block can exist the
smaller blocks of procedures and functions. Although the
diagram doesn't show this, procedures and functions can be
nested within other procedures and functions. In other words,
blocks can contain other blocks.
Combined with other tokens and blank spaces, tokens make up
expressions which make up statements.
12 Language Guide
In turn, statements combined with declaration parts make up
blocks, either the main program block or a block in a procedure or
function.
Units
A Turbo Pa,scal program can use blocks of code in separate
modules called units. You can think of a unit as a mini-program
your application can use. Like a program, it has a heading, called
a unit heading, and a main block that contains a code section
delineated by begin and end.
Any Turbo Pascal main program block can include a line that
enables the program to use one or more units. For example, if you
are writing a program called Colors and you want to change the
color of the text as it appears on your screen, you can specify that
your program use the standard Crt unit that is part of the Turbo
Pascal run-time library:
program Colors;
uses Crt;
begin
end.
The uses Crt line tells Turbo Pascal to include the Crt unit in the
executable program. The Crt unit contains all the necessary code
to change the color of the text in your program, among other
things. Simply by including uses Crt, your program can use all
the procedures and functions in the Crt unit. If you put all the
code required to create the functionality of the Crt unit within
your program, it would be a lot more work, and it would
sidetrack you from the main purpose of your program.
Turbo Pascal's run-time library includes several units you'll find
useful. For example, use the Dos unit and your program has
access to several operating system and file-handling routines.
You can also write your own units. Use them to divide large
programs into logically related modules. Code you place in a unit
can be used by any program. You only have to write the code
once, then you can use it many times.
14 Language Guide
c H A p T E R
Tokens
Tokens are the smallest meaningful units of text in a Pascal
program. They are categorized as special symbols, identifiers,
labels, numbers, and string constants.
Separators can't be part of A Pascal program is made up of tokens and separators. A
tokens except in string
constants.
separator is either a blank or a comment. Two adjacent tokens
must be separated by one or more separators if each token is a
reserved word, an identifier, a label, or a number.
Special symbols
Turbo Pascal uses the following subsets of the ASCII character set:
• Letters-the English alphabet, A through Z and a through z
• Digits-the Arabic numerals a through 9
• Hex digits-the Arabic numerals a through 9, the letters A
through F, and the letters a through f
• Blanks-the space character (ASCII 32) and all ASCII control
characters (ASCII a through 31), including the end-of-line or
return character (ASCII 13)
These are the syntax diagrams for letter, digit, and hex digit:
Chapter 2, Tokens 15
digit - - - - - . - - - - - ,
¢ ... ~
hex digit
4digiti
A··· F
$ cp ...
meanings.
The following single characters are special symbols:
+ _ */=< > [] ., () : ; 'A @ { } $#
These character pairs are also special symbols:
<= >= := .. (* *) (. .)
A left bracket ([) is equivalent to the character pair of left
parenthesis and a period-(., and a right bracket (]) is equivalent
to the character pair of a period and a right parenthesis-.).
Likewise, a left brace ({) is equivalent to the character pair of left
parenthesis and an asterisk-(*, and a right brace 0) is equivalent
to the character pair of an asterisk and a right parenthesis-*).
Table 2.1
Turbo Pascal reserved words and file not then
array for object to
asm function of type
begin goto or unit
case if packed until
const implementation procedure uses
constructor in program var
destructor inherited record while
div inline repeat with
do interface set xor
downto label shl
else mod shr
end nil string
16 Language Guide
The following are Turbo Pascal's standard (built-in) directives.
Directives are used only in contexts where user-defined identifiers
can't occur. Unlike reserved words, you can redefine standard
directives, but we advise that you don't.
Table 2,2
Turbo Pascal directives absolute far near virtual
assembler forward private
external interrupt public
Identifiers
Identifiers denote constants, types, variables, procedures,
functions, units, programs, and fields in records.
An identifier can be of any length, but only the first 63 characters
are significant. An identifier must begin with a letter or an under-
score character U and can't contain spaces. Letters, digits, and
underscore characters (ASCII $5F) are allowed after the first char-
acter. Like reserved words, identifiers are not case sensitive.
Units are described in When several instances of the same identifier exist, you may need
Chapter 5 of the User's Guide to qualify the identifier by another identifier to select a specific
and Chapter 10 of this book.
instance. For example, to qualify the identifier ldent by the unit
identifier UnitName, write UnitName.Ident. The combined
identifier is called a qualified identifier.
identifier
underscore -G-
qualified ~d
t'f'
identifier ~
Chapter 2, Tokens 17
Here are some examples of identifiers and qualified identifiers:
Writeln
Exit
Rea12String
System. MemAvail
Strings.StrLen
WinCrt.ReadText
In this manual, standard and user-defined identifiers are italicized
when they are referred to in text.
Numbers
Ordinary decimal notation is used for numbers that are constants
of type Integer and Real. A hexadecimal integer constant uses a
dollar sign ($) as a prefix. Engineering notation (E or e, followed
by an exponent) is read as "times ten to the power of" in real
types. For example, 7E-2 means 7 x 10-2; 12.25e+6 or 12.25e6 both
mean 12.25 x 10+6 . Syntax diagrams for writing numbers follow:
hex digit sequence -rl. hex digit tT--
digit sequence~
unsigned integer
Signw
unsigned real
digit sequence digit sequence 11--;:::========:::;-,+
scale factor
18 Language Guide
Numbers with decimals or exponents denote real-type constants.
Other decimal numbers denote integer-type constants; they must
be within the range -2,147,483,648 to 2,147,483,647.
Hexadecimal numbers denote integer-type constants; they must
be within the range $00000000 to $FFFFFFFF. The resulting value's
sign is implied by the hexadecimal notation.
Labels
A label is a digit sequence in the range 0 to 9999. Leading zeros
are not significant. Labels are used with goto statements.
label
Character strings
A character string is a sequence of zero or more characters from
the extended ASCII character set, written on one line in the
program and enclosed by apostrophes. A character string with
nothing between the apostrophes is a null string. Two sequential
apostrophes within a character string denote a single character, an
apostrophe. For example,
'TURBO' { TURBO }
'You"ll see' { You'll see}
{ , }
{ null string }
{ a space }
As an extension to Standard Pascal, Turbo Pascal lets you embed
control characters in character strings. The # character followed by
an unsigned integer constant in the range 0 to 255 denotes a
character of the corresponding ASCII value. There must be no
separators between the # character and the integer constant.
Likewise, if several control characters are part of a character
string, there must be no separators between them. For example,
Chapter 2, Tokens 19
#13#10
'Line l'#13'Line2'
#7#7'Wake up!'#7#7
10--
quoted string - ( )
q string character P
string character
Comments
The following constructs are comments and are ignored by the
compiler:
{ Any text not containing right brace }
(* Any text not containing star/right parenthesis *)
The compiler directives are A comment that contains a dollar sign ($) immediately after the
explained in Chapter 2 of the opening { or (* is a compiler directive. A mnemonic of the compiler
Programmer's Reference.
command follows the $ character.
Program lines
Turbo Pascal program lines have a maximum length of 126
characters.
20 Language Guide
c H A p T E R
Constants
A constant declaration declares a constant within the block
containing the declaration. A constant is an identifier that holds a
value that can't change. A constant identifier can't be included in
its own declaration.
constant declaration rl identifier ~ constant ~0-r
Wherever Standard Pascal As an extension to Standard Pascal, Turbo Pascal allows the use of
allows only a simple con-
stant, Turbo Pascal allows a
constant expressions. A constant expression is an expression that
constant expression. can be evaluated by the compiler without actually executing the
program. Examples of constant expressions follow:
100
'A'
256 - 1
(2.5 + 1) (2.5 - 1)
'Turbo' + ' , + 'Pascal'
Chr (32)
Ord ( , Z') - Ord ( , A') + 1
Chapter 3, Constants 21
• References to variables and typed constants (except in constant
address expressions as described on page 59)
• Function calls (except those noted in the following text)
• The address operator (@) (except in constant address
expressions as described on page 59)
For expression syntax, see Except for these restrictions, constant expressions follow the same
Chapter 6, "Expressions."
syntactical rules as ordinary expressions.
The following standard functions are allowed in constant
expressions:
22 Language Guide
c H A p T E R
Types
When you declare a variable, you must state its type. A variable's
type circumscribes the set of values it can have and the operations
that can be performed on it. A type declaration specifies the
identifier that denotes a type.
type declaration -I identifier ~~
When an identifier occurs on the left side of a type declaration, it's
declared as a type identifier for the block in which the type
declaration occurs. A type identifier's scope doesn't include itself
except for pointer types.
type
type identifier
There are five major type classes. They are described in the
following sections. .
Simple types
Simple types define ordered sets of values.
Chapter 4, Types 23
simple type
Ordinal types
Ordinal types are a subset of simple types. All simple types other
than real types are ordinal types, which are set off by six
characteristics:
• All possible values of a given ordinal type are an ordered set,
and each possible value is associated with an ordinality, which is
an integral value. Except for integer-type values, the first value
of every ordinal type has ordinality 0, the next has ordinality I,
and so on for each value in that ordinal type. The ordinality of
an integer-type value is the value itself. In any ordinal type,
each value other than the first has a predecessor, and each value
other than the last has a successor based on the ordering of the
type.
• The standard function Ord can be applied to any ordinal-type
value to return the ordinality of the value.
• The standard function Pred can be applied to any ordinal-type
value to return the predecessor of the value. If applied to the
first value in the ordinal type and if range-checking is enabled
{$R+}, Pred produces a run-time error.
• The standard function Suee can be applied to any ordinal-type
value to return the successor of the value. If applied to the last
value in the ordinal type and if range checking is enabled {$R+},
Suee produces a run-time error.
• The standard function Low can be applied to an ordinal-type
and to a variable reference of an ordinal type. The result is the
lowest value in the range of the given ordinal type.
• The standard function High can be applied to an ordinal-type
and to a variable reference of an ordinal type. The result is the
highest value in the range of the given ordinal type.
The syntax of an ordinal type follows:
24 Language Guide
ordinal type 1 subrange type
enumerated type
ordinal type identifier
Integer types There are five predefined integer types: Shortint, Integer, Longint,
Byte, and Word. Each type denotes a specific subset of the whole
numbers, according to the following table:
Table 4.1
Predefined integer types Type Range Format
Chapter 4, Types 25
Boolean types There are four predefined Boolean types: Boolean, ByteBool,
WordBool, and LongBool. Boolean values are denoted by the
predefined constant identifiers False and True. Because Booleans
are enumerated types, these relationships hold:
• False < True
• Ord(False) = a
• Ord(True) = 1
.Succ(False) = True
• Pred(True) = False
Boolean and ByteBool variables occupy one byte, a WordBool
variable occupies two bytes (one word), and a LongBool variable
occupies four bytes (two words). Boolean is the preferred type and
uses the least memory; ByteBool, WordBool, and LongBool exist
primarily to provide compatibility with other languages and the
Windows environment.
A Boolean variable can assume the ordinal values a and 1 only, but
variables of type ByteBool, WordBool, and LongBool can assume
other ordinal values. An expression of type ByteBool, WordBool, or
LongBool is considered False when its ordinal value is zero, and
True when its ordinal value is nonzero. Whenever a ByteBool,
WordBool, or LongBool value is used in a context where a Boolean
value is expected, the compiler will automatically generate code
that converts any nonzero value to the value True.
Char type Char's set of values are characters, ordered according to the
extended's ASCII character set. The function call Ord(Ch), where
Ch is a Char value, returns Ch's ordinality.
A string constant of length 1 can denote a constant character
value. Any character value can be generated with the standard
function Chr.
identifier list ~
26 Language Guide
When an identifier occurs within the identifier list of an
enumerated type, it's declared as a constant for the block the
enumerated type is declared in. This constant's type is the
enumerated type being declared.
An enumerated constant's ordinality is determined by its position
in the identifier list it's declared in. The enumerated type it's
declared in becomes the constant's type. The first enumerated
constant in a list has an ordinality of zero.
Here's an example of an enumerated type:
type
Suit = (Club, Diamond, Heart, Spade);
Given these declarations, Diamond is a constant of type Suit.
When the Ord function is applied to an enumerated type's value,
Ord returns an integer that shows where the value falls with
respect to the other values of the enumerated type. Given the
preceding declarations, Ord(Club) returns zero, Ord(Diamond)
returns I, and so on.
Subrange types A sub range type is a range of values from an ordinal type called
the host type. The definition of a subrange type specifies the
smallest and the largest value in the subrange; its syntax follows:
subrange type -I constant ~o-I constant ~
Both constants must be of the same ordinal type. Sub range types
of the form A .. B require that A is less than or equal to B.
These are examples of subrange types:
o.. 99
-128 .. 127
Club .. Heart
A variable of a sub range type has all the properties of variables of
the host type, but its run-time value must be in the specified
interval.
One syntactic ambiguity ar~ses from allowing constant expres-
sions where Standard Pascal only allows simple constants.
Consider the following declarations:
Chapter 4, Types 27
const
X = 50;
Y = 10;
type
Color = (Red, Green, Blue);
Scale = (X - Y) * 2 .. (X + Y) * 2;
Real types
A real type has a set of values that is a subset of real numbers,
which can be represented in floating-point notation with a fixed
number of digits. A value's floating-point notation normally
comprises three values-M, B, and E-such that M x BE = N,
where B is always 2, and both M and E are integral values within
the real type's range. These M and E values further prescribe the
real type's range and precision.
There are five kinds of real types: Real, Single, Double, Extended,
and Camp. The real types differ in the range and precision of
values they hold as shown in the following table:
Table 4.2
Real data types Significant Size in
Type Range digits bytes
The Comp type holds only Real 2.9 X 10-39 .. 1.7 X 1038 11-12 6
integral values within Single 1.5 X 10-45 .. 3.4 X 1038 7-8 4
_2'3+ 7 to 2'3- 7, which is Double 5.0 X 10-324 .. 1.7 X 10308 15-16 8
approximately-9.2x 70 78 to Extended 3.4 X 10-4932 .. 1.1 X 104932 19-20 10
9.2x 70 78 • Camp _2 63 +1 .. 263-1 19-20 8
28 Language Guide
Software floating point In the {$N-} state, which is selected by default, the generated code
performs all real-type calculations in software by calling run-time
library routines. For reasons of speed and code size, only opera-
tions on variables of type Real are allowed in this state. Any
attempt to compile statements that operate on the Single, Double,
Extended, and Camp types generates an error.
80x8? floating point In the {$N+} state, the generated code performs all real-type
calculations using 80x87 instructions and can use all five real
types.
For more details on 80x87 Turbo Pascal includes a run-time library that will automatically
floating-point code emulate an 80x87 in software if one isn't present. The $E compiler
generation and software
emulation, refer to directive is used to determine whether or not the 80x87 emulator
Chapter 74, "Using the should be included in a program.
80x87."
String types
Operators for the string types A string-type value is a sequence of characters with a dynamic
are described in the sections
"String operator" and
length attribute (depending on the actual character count during
"Relational operators" in program execution) and a constant size attribute from Ito 255. A
Chapter 6. string type declared without a size attribute is given the default
size attribute 255. The length attribute's current value is returned
String-type standard
procedures and functions
by the standard function Length.
are described in "String
string type -c3I--T---:::;:::---;::::==========:::;--;::::-r-
procedures and functions"
on page 737.
l-CD--I unsigned integer ~
The ordering between any two string values is set by the ordering
relationship of the character values in corresponding positions. In
two strings of unequal length, each character in the longer string
without a corresponding character in the shorter string takes on a
higher or greater-than value; for example, 'xs' is greater than 'x'.
Null strings can be equal only to other null strings, and they hold
the least string values.
Characters in a string can be accessed as components of an array.
See the section" Arrays, strings, and indexes" on page 55.
The Low and High standard functions can be applied to a string-
type identifier and to a variable reference of a string type. In this
case, Low returns zero, and High returns the size attribute
(maximum length) of the given string.
Chapter 4, Types 29
Read about open string A variable parameter declared using the OpenString identifier, or
parameters on page 111. using the string keyword in the {$P+} state, is an open string
parameter. Open string parameters allow string variables of
varying sizes to be passed to the same procedure or function.
Structured types
The maximum permitted size A structured type, characterized by its structuring method and by
of any structured type in
Turbo Pascal is 65,520 bytes.
its component type(s), holds more than one value. If a component
type is struCtured, the resulting structured type has more than
one level of structuring. A structured type can have unlimited
levels of structuring.
structured type -or---=~---'r--or--~
~=======::::.--,
Array types
Arrays have a fixed number of components of one type-the
component type. In the following syntax diagram, the component
type follows the word of.
30 Language Guide
therefore, the number of elements is the product of the number of
values in each index type.
The following is an example of an array type:
array[1 .. 100] of Real
If an array type's component type is also an array, you can treat
the result as an array of arrays or as a single multidimensional
array. For example
array [Boolean] of array[l .. 10] of array[Size] of Real
is interpreted the same way by the compiler as
array [Boolean, 1 .. 10,Size] of Real
You can also express
packed array[l .. 10] of packed array[1 .. 8] of Boolean
as
packed array[l .. 10,1 .. 8] of Boolean
See "Arrays, strings, and You access an array's components by supplying the array's
indexes" on page 55.
identifier with one or more indexes in brackets.
When applied to an array-type identifier or a variable reference of
an array type, the Low and High standard functions return the low
and high bounds of the index type of the array.
An array type of the form
packed array[M .. N] of Char
See "Identical and where M is less than N is called a packed string type (the word
compatible types" on
packed can be omitted because it has no effect in Turbo Pascal). A
page 46.
packed string type has certain properties not shared by other
array types, as explained below.
An array type of the form
array[O .. X] of Char
where X is a positive nonzero integer is called a zero-based
character array. Zero-based character arrays are used to store null-
terminated strings, and when the extended syntax is enabled (using
a {$X+} compiler directive), a zero-based character array is
compatible with a PChar value. For a complete discussion of this
topic, read Chapter 16, "Using null~terminated strings,"
beginning on page 167.
Chapter 4, Types 31
Read about open array A parameter declared using the array of T syntax is an open array
parameters on page 773. parameter. Open array parameters allow arrays of varying sizes to
be passed to the same procedure or function.
Record types
A record type comprises a set number of components, or fields,
that can be of different types. The record-type declaration speci-
fies the type of each field and the identifier that names the field.
record type ~-1--;:======:::;1~'~
Lj field list ~
L'I
field list
-f::-"ix-ed-:--p-art-'
L:G)OOT=l variant part po c::o==t I
The fixed part of a record type sets out the list of fixed fields,
giving an identifier and a type for each. Each field contains
information that is always retrieved in the same way.
The following is an example of a record type:
type
TDateRec = record
Year: Integer;
Month: 1. .12;
Day: 1..31;
end;
The variant part shown in the syntax diagram of a record-type
declaration distributes memory space for more than one list of
fields, so the information can be accessed in more ways than one.
Each list of fields is a variant. The variants overlay the same space
in memory, and all fields of all variants can be accessed at all
times.
32 Language Guide
variant~
~Idlist!
",---------," I CD-
You can see from the diagram that each variant is identified by at
least one constant. All constants must be distinct and of an ordinal
type compatible with the tag field type. Variant and fixed fields
are accessed the same way.
An optional identifier, the tag field identifier, can be placed in the
variant part. If a tag field identifier is present, it becomes the iden-
tifier of an additional fixed field-the tag field-of the record. The
program can use the tag field's value to show which variant is
active at a given time. Without a tag field, the program selects a
variant by another criterion.
Some record types with variants follow:
type
TPerson = record
FirstName, LastNarne: string[40];
BirthDate: TDate;
case Citizen: Boolean of
True: (BirthPlace: string[40]);
False: (Country: string[201;
EntryPort: string[20];
EntryDate: TDate;
ExitDate: TDate);
end;
TPolygon = record
X, Y: Real;
case Kind: Figure of
TRectangle: (Height, Width: Real);
TTriangle: (Sidel, Side2, Angle: Real);
TCircle: (Radius: Real);
end;
Object types
An object type"is a structure consisting of a fixed number of com-
ponents. Each component is either a field, which contains data of a
particular type, or a method, which performs an operation on the
object. Similar to a variable declaration, the declaration of a field
specifies the field's data type and an identifier that names the
field. Similar to a procedure or function declaration, the decla-
ration of a method specifies a procedure, function, constructor, or
destructor heading.
Chapter 4, Types 33
An object type can inherit components from another object type. If
T2 inherits from Tl, then T2 is a descendant of Tl, and Tl is an
ancestor of T2.
Inheritance is transitive; that is, if T3 inherits from T2, and T2
inherits from Tl, then T3 also inherits from Tl. The domain of an
object type consists of itself and all its descendants.
object type
integer constant
function heading
constructor heading
destructor heading
34 Language Guide
procedure Grow(DX, DY: Integer);
procedure Intersect (var R: TRectangle);
procedure Union(var R: TRectangle);
function Contains(D: TPoint): Boolean;
end;
PString = AString;
PField ATField;
TField object
private
x, Y, Len: Integer;
Name: String;
public
constructor Copy(var F: TField);
constructor Init(FX, FY, FLen: Integer; FName: String);
destructor Done; virtual;
procedure Display; virtual;
procedure Edit; virtual;
function GetStr: String; virtual;
function PutStr(S: String): Boolean; virtual;
private
procedure DisplayStr(X, Y: Integer; S: String);
end;
PStrField ATStrField;
TStrField object (TField)
private
Value: PString;
public
constructor Init(FX, FY, FLen: Integer; FName: String);
destructor Done; virtual;
function GetStr: String; virtual;
function PutStr(S: String): Boolean; virtual;
function Get: String;
procedure Put(S: String);
end;
PNumField ATNumField;
TNumField object (TField)
private
Value, Min, Max: Longint;
public
constructor Init(FX, FY, FLen: Integer; FName: String;
FMin, FMax: Longint);
function GetStr: String; virtual;
function PutStr(S: String): Boolean; virtual;
function Get: Longint;
35
procedure Put(N: Longint);
end;
PZipField = ATZipField;
TZipField = object (TNurnField)
public
function GetStr: String; virtual;
function PutStr(S: String): Boolean; virtual;
end;
Contrary to other types, an object type can be declared only in a
type declaration part in the outermost scope of a program or unit.
Therefore, an object type can't be declared in a variable decla-
ration part or within a procedure, function, or method block.
The component type of a file type can't be an object type, or any
structured type with an object-type component.
Components and The scope of a component identifier extends over the domain of
scope its object type. Also, the scope of a component identifier extends
over procedure, function, constructor, and destructor blocks that
implement methods of the object type and its descendants. For
this reason, the spelling of a component identifier must be unique
within an object type and all its descendants and all its methods.
Component identifiers declared in the component list that
immediately follows the object-type heading and component
identifiers declared in public component sections have no special
restrictions on their scope. In contrast, the scope of component
identifiers declared in private component sections is restricted to
the module (program or unit) that contains the object-type
declaration. In other words, private component identifiers act like
normal public component identifiers within the module that
contains the object-type declaration, but outside the module, any
private component identifiers are unknown and inaccessible. By
placing related object types in the same module, these object types
can gain access to each other's private components without
making the private components known to other modules.
Within an object-type declaration, a method heading can specify
parameters of the object type being declared, even though the
declaration isn't yet complete. In the previous example on page
34, the Copy, Intersect, and Union methods of the TRee tangle type
illustrate this.
36 Language Guide
Methods The declaration of a method within an object type corresponds to
a forward declaration of that method. This means that somewhere
Methods can be called only after the object-type declaration, and within the same scope as the
through an object instance object-type declaration, the method must be implemented by a
variable.
defining declaration.
Read more about methods When unique identification of a method is required, a qualified-
on page 103.
method identifier is used. It consists of an object-type identifier,
followed by a period (.), followed by a method identifier. Like any
other identifier, a qualified-method identifier can be prefixed with
a unit identifier and a period, if required.
qualified method identifier
Y object type identifier K)--/ method identifier ~
Virtual methods By default, methods are static. With the exception of constructor
methods, they can be made virtual by including a virtual directive
in the method declaration. The compiler resolves calls to static
methods at compile time. Calls to virtual methods are resolved at
run time; this isknown as late binding.
If an object type declares or inherits any virtual methods, then
variables of that type must be initialized through a constructor call
before any call to a virtual method. Therefore, any object type that
declares or inherits any virtual methods must also declare or
inherit at least one constructor method.
An object type can override (redefine) any of the methods it
inherits from its ancestors. If a method declaration in a descen-
dant specifies the same method identifier as a method declaration
in an ancestor, then the declaration in the descendant overrides
the declaration in the ancestor. The scope of an override method
extends over the domain of the descendant in which it's intro-
duced, or until the method identifier is again overridden.
An override of a static method is free to change the method
heading any way it pleases. In contrast, an override of a virtual
method must match exactly the order, types, and names of the
parameters, and the type of the function result, if any. The
override must again include a virtual directive.
Chapter 4, Types 37
Dynamic methods Turbo Pascal supports an additional class of late-bound methods
called dynamic methods. Dynamic methods differ from virtual
methods only in the way dynamic method calls are d!spatched at
run time. For all other purposes, a dynamic method can be
considered equivalent to a virtual method.
The declaration of a dynamic method is like that of a virtual
method except that a dynamic method declaration must include a
dynamic method index right after the virtual keyword. The dynamic
method index must be an integer constant in the range 1..65535
and it must be unique among the dynamic method indexes of any
other dynamic methods contained in the object type or its
ancestors. For example,
procedure FileOpen(var Msg: TMessage); virtual 100;
An override of a dynamic method must match the order, types,
and names of the parameters and the type of the function result of
the ancestral method exactly. The override must also include a
virtual directive followed by the same dynamic method index as
was specified in the ancestor object type.
38 Language Guide
S. Put ( 'Frank' ) ;
S.Display;
S.Done;
end;
If S.Init had not been called, then the call to S.Display causes this
example to fail.
Assignment to an instance of an object type doesn't initialize the
instance.
An object is initialized by compiler-generated code that executes
between the time that the constructor call takes place and when
execution actually reaches the first statement of the constructor's
code block.
If an object instance isn't initialized and range checking is 'on
{$R+}, the first call to a virtual method of the object instance
results in a run-time error. If range checking is off {$R-}, calling a
virtual method of an uninitialized object instance results in
undefined behavior.
The rule of required initialization also applies to instances that are
components of structured types. For example,
var
Comment: array[l .. 5] of TStrField;
I: Integer;
begin
for I := 1 to 5 do Comment [I] .Init(l, I + 10, 40, 'Comment');
Dispose(SP, Done);
end;
Chapter 4, Types 39
A pointer to an object type is assignment-compatible with a
pointer to any ancestor object type. Therefore, during execution of
a program, a pointer to an object type might point to an instance
of that type or to an instance of any descendant type.
For example, a pointer of type PZipField can be assigned to
pointers of type PZipField, PNumField, and PField, and during
execution of a program, a pointer of type PField might be either nil
or point to an instance of TField, TStrField, TNumField, or
TZipField, or any other instance of a descendant of TField.
Pointer assignment-compatibility rules also apply to object-type
variable parameters. For example, the TField.Copy method might
be passed an instance of TField, TStrField, TNumField, TZipField, or
any other instance of a descendant of TField.
40 Language Guide
activation becomes the instance referenced by the with statement.
Likewise, within a method, the variable-reference part of a
method designator can be omitted. In that case, the implicit Self
parameter of the method activation becomes the Self of the
method containing the call.
Chapter 4, Types 41
As these examples demonstrate, a qualified-method activation
allows an override method to "reuse" the code of the method it
overrides.
Set types
A set type's range of values is the power set of a particular ordinal
type (the base type). The power set is the set of all possible subsets
of values of the base type including the empty set. Therefore, each
possible value of a set type is a subset of the possible values of the
base type.
A variable of a set type can hold from none to all the values of the
set.
set type -@--@--l ordinal type ~
Set-type operators are The base type must not have more than 256 possible values, and
described in the section "Set
operators" in Chapter 6. "Set
the ordinal values of the upper and lower bounds of the base type
constructors" in the same must be within the range 0 to 255.
chapter shows how to
construct set values. Every set type can hold the value [ ], which is called the empty set.
File types
A file type consists of a linear sequence of components of the
component type, which can be of any type except a file type, any
structured type with a file-type component, or an object type. The
number of components isn't set by the file-type declaration.
file type
If the word of and the component type are omitted, the type
denotes an untyped file. Untyped files are low-level I/O
(input/output) channels primarily used for direct access to any
disk file regardless of its internal format.
The standard file type Text signifies a file containing characters
organized into lines. Text files use special I/O procedures, which
are discussed in Chapter 13, "Input and output."
42 Language Guide
Pointer types
A pointer type defines a set of values that point to dynamic
variables of a specified type called the base type. A pointer-type
variable contains the memory address of a dynamic variable.
-0--l base type ~
pointer type
Type Pointer
The predefined type Pointer denotes an untyped pointer; that is, a
pointer that doesn't point to any specific type. Variables of type
See Chapter 5$ section Pointer can't be dereferenced; writing the pointer symbol" after
entitled "Pointers and
such a variable is an error. Generic pointers, however, can be
dynamic variables" on page
56 for the syntax of typecast to allow dereferencing. Like the value denoted by the
referencing the dynamic word nil, values of type Pointer are compatible with all other
variable pointed to by a pointer types.
pointer variable.
Type PChar
Turbo Pascal has a predefined type, Pehar, to represent a pointer
to a null-terminated string. The System unit declares pehar as
type PChar = AChar;
Turbo Pascal supports a set of extended syntax rules to facilitate
handling of null-terminated strings using the pehar type. For a
complete discussion of this topic, see Chapter 16, "Using null-
terminated strings."
Chapter 4, Types 43
Procedural types
Standard Pascal regards procedures and functions as program
parts that can be executed through procedure or function calls.
Turbo Pascal has a much broader view of procedures and
functions: It allows procedures and functions to be treated as
entities that can be assigned to variables and passed as parame-
ters. Such actions are made possible through procedural types.
A procedural-type declaration specifies the parameters and, for a
function, the result type.
procedural type
Procedural values
A variable of a procedural type can be assigned a procedural value.
Procedural values can be one of these:
44 Language Guide
• The value nil
• A variable reference of a procedural type
• A procedure or function identifier
In the context of procedural values, a procedure or function
declaration can be viewed as a special kind of constant
declaration, the value of the constant being the procedure or
function. For example, given the following declarations:
var
P: SwapProc;
F: MathFunc;
procedure Swap(var A, B: Integer); far;
var
Temp: Integer;
begin
Temp := A;
A := B;
B := Temp;
end;
function Tan (Angle: Real); far;
begin
Tan := Sin(Angle) / Cos (Angle) ;
end;
Using a procedural variable that has been assigned the value nil in
a procedure statement or a function call results in an error. nil is
intended to indicate that a procedural variable is unassigned, and
whenever there is a possibility that a procedural variable is nil,
procedure statements or function calls involving that procedural
variable should be guarded by a test:
if @P <> nil then P(I, J);
See "Procedural types in Notice the use of the @ operator to indicate that P is being ex-
expressions" on page 44.
amined rather than being called.
Chapter 4, Types 45
Type
compatibility To be considered compatible, procedural types must have the
same number of parameters, and parameters in corresponding
positions must be of identical types. Finally, the result types of
functions must be identical. Parameter names have no
significance when determining procedural-type compatibility.
The value nil is compatible with any procedural type.
To be used as procedural values, procedures and functions must
be declared with a far directive or compiled in the {$F+} state.
Also, standard procedures and functions, nested procedures and
functions, methods, inline procedures and functions, and interrupt
procedures can't be used as procedural values.
Standard procedures and functions are the ones declared by the
System unit, such as WriteLn, ReadLn, Chr, and Ord. To use a
standard procedure or function as a procedural value, write a
"shell" around it. For example, the following function FSin is
assignment-compatible with the MathFunc type declared above.
function FSin(X: Real): Real; far;
begin
FSin : = Sin (X) ;
end;
A procedure or function is nested when it's declared within
another procedure or function. Such nested procedures and
functions can't be used as procedural values.
Type identity
Type identity is required only between actual and formal variable
parameters in procedure and function calls.
46 Language Guide
Two types-say, Tl and T2-are identical if one of the following
is true: Tl and T2 are the same type identifier; Tl is declared to be
equivalent to a type identical to T2.
The second condition connotes that Tl doesn't have to be de-
clared directly to be equivalent to T2. The type declarations
Tl = Integer;
T2 = Tl;
T3 = Integer;
T4 = T2;
result in Tl, T2, T3, T4, and Integer as identical types. The type
declarations
T5 = set of Integer;
T6 = set of Integer;
don't make T5 and T6 identical because set of Integer isn't a type
identifier. Two variables declared in the same declaration, for
example,
Vl, V2: set of Integer;
are of identical types-unless the declarations are separate. The
declarations
Vl: set of Integer;
V2: set of Integer;
V3: Integer;
V4: Integer;
mean V3 and V 4 are of identical type, but not Vl and V2.
Type
compatibility Compatibility between two types is sometimes required, such as
in expressions or in relational operations. Type compatibility is
important, however, as a precondition of assignment
compatibility.
Type compatibility exists when at least one of the following
conditions is true:
• Both types are the same.
• Both types are real types.
• Both types are integer types.
• One type is a subrange of the other.
• Both types are subranges of the same host type.
Chapter 4, Types 47
• Both. types are set types with compatible base types.
• Both types are packed string types with an identical number of
components.
• One type is a string type and the other is either a string type,
packed string type, or Char type.
• One type is Pointer and the other is any pointer type.
• One type is PChar and the other is a zero-based character array
of the form array[O .. X] of Char. (This applies only when
extended syntax is enabled with the {$X+} directive.)
• Both types are pointers to identical types. (This applies only
when type-checked pointers are enabled with the {$T +}
directive.)
• Both types are procedural types with identical result types, an
identical number of parameters, and a one-to-one identity
between parameter types.
Assignment
compatibility Assignment compatibility is necessary when a value is assigned to
something, such as in an assignment statement or in passing
value parameters.
A value of type T2 is assignment-compatible with a type T1 (that
is, T1 := T2 is allowed) if any of the following are True:
• T1 and T2 are identical types and neither is a file type or a
structured type that contains a file-type component at any level
of structuring.
• T1 and T2 are compatible ordinal types, and the values of type
T2 falls within the range of possible values of T 1.
• T1 and T2 are real types, and the value of type T2 falls within the
range of possible values of T l'
• T1 is a real type, and T2 is an integer type.
• T 1 and T 2 are string types.
• T1 is a string type, and T2 is a Char type.
• T1 is a string type, and T2 is a packed string type.
• T1 and T2 are compatible, packed string types.
• T1 and T2 are compatible set types, and all the members of the
value of type T 2 fall within the range of possible values of T l'
• T1 and T2 are compatible pointer types.
48 Language Guide
• T1 is a PChar and T2 is a string constant. (This applies only
when extended syntax is enabled {$X+}.)
• T1 is a PChar and T2 is a zero-based character array of the form
array[O .. X] of Char. (This applies only when extended syntax is
enabled {$X+}.)
• T1 and T2 are compatible procedural types.
• T1 is a procedural type, and T2 is a procedure or function with
an identical result type, an identical number of parameters, and
a one-to-one identity between parameter types.
• T2 is assignment-compatible with an object type T1 if T2 is an
object type in the domain of T l'
• A pointer type P2, pointing to an object type T2, is assignment-
compatible with a pointer type P 1, pointing to an object type T 11
if T2 is' in the domain of T l'
A compile-time error occurs when assignment compatibility is
necessary and none of the items in the preceding list are true.
Chapter 4, Types 49
TMeasureData = record
When: TDatei
Count: TTestIndexi
Data: PTestListi
endi
TMeasureList = array[1 .. 50] of TMeasureDatai
TName = string[80]i
TSex = (Male, Female)i
PPersonData = ATPersonDatai
TPersonData = record
Name, FirstName: TNamei
Age: Integeri
Married: Booleani
TFather, TChild, TSibling: PPersonDatai
case S: TSex of
Male: (Bearded: Boolean);
Female: (Pregnant: Boolean)i
endi
TPersonBuf = array[O . . SizeOf(TPersonData)-l] of Byte;
TPeople = file of TPersonDatai
In the example, Range, Number, and Integer are identical types.
TTestIndex is compatible and assignment-compatible with, but not
identical to, the types Number, Range, and Integer. Notice the use
of constant expressions in the declarations of TCharVal and
TPersonBuf
50 Language Guide
c H A p T E R
absolute clause
The data
segment The maximum size of the data segment is 65,520 bytes. When a
program is linked (this happens automatically at the end of the
compilation of a program), the global variables of all units used
by the program, as well as the program's own global variables, are
placed in the data segment.
For information on dynamic If you need more than 65,520 bytes of global data, you should
variables, see "Pointers and allocate the larger structures as dynamic variables.
dynamic variables" on
page 56.
The stack
segment The size of the stack segment is set through a $M compiler
directive-it can be anywhere from 1,024 to 65,520 bytes. The
default stack-segment size is 16,384 bytes.
Each time a procedure or function is activated (called), it allocates
a set of local variables on the stack. On exit, the local variables are
.disposed of. At any time during the execution of a program, the
total size of the local variables allocated by the active procedures
and functions can't exceed the size of the stack segment.
The $S compiler directive is used to include stack-overflow
checks in the code. In the default {$S+} state, code is generated to
check for stack overflow at the beginning of each procedure and
function. In the {$S-} state, no such checks are performed.
A stack overflow can cause a system crash, so don't turn off stack
checks unless you're absolutely sure that an overflow will never
occur.
52 Language Guide
Absolute
variables Variables can be declared to reside at specific memory addresses,
and are then called absolute variables. The declaration of such
variables must include an absolute clause following the type:
Variable
references A variable reference signifies one of the following:
ill A variable
• A component of a structured- or string-type variable
• A dynamic variable pointed to by a pointer-type variable
Qualifiers
A variable reference can contain zero or more qualifiers that
modify the meaning of the variable reference.
qualifier
54 Language Guide
Arrays, strings, and A specific component of an array variable is denoted by a variable
indexes reference that refers to the array variable, followed by an index
that specifies the component.
A specific character within a string variable is denoted by a
variable reference that refers to the string variable, followed by an
index that specifies the character position.
index ~ expression
....------t01+1
f--r-CD--
------I
is the same as
Matrix[I, J]
Object component The format of an object component designator is the same as that
designators of a record field designator; that is, it consists of an instance (a
variable reference), followed by a period and a component identi-
fier. A component designator that designates a method is called a
method designator. A with statement can be applied to an instance
of an object type. In that case, the instance and the period can be
omitted in referencing components of the object type.
The instance and the period can also be omitted within any
method block, and when they are, the effect is the same as if Self
and a period were written before the component reference.
Pointers and dynamic The value of a pointer variable is either nil or the address of a
variables dynamic variable.
The dynamic variable pointed to by a pointer variable is refer-
enced by writing the pointer symbol (/\) after the pointer variable.
You create dynamic variables and their pointer values with the
procedures New and GetMem. You can use the @ (address-of)
operator and the function Ptr to create pointer values that are
treated as pointers to dynamic variables.
nil doesn't point to any variable. The results are undefined if you
access a dynamic variable when the pointer's value is nil or
undefined. These are examples of references to dynamic variables:
Pi"
Pl".Sibling"
Results[l] .Data"
56 Language Guide
Variable
typecasts A variable reference of one type can be changed into a variable
reference of another type through a variable typecast.
variable typecast
type identifier variable reference
Typed constants
Typed constants can be compared to initialized variables-
variables whose values are defined on entry to their block. Unlike
an untyped constant, the declaration of a typed constant specifies
both the type and the value of the constant.
typed constant declaration
L-I identifier ~ typed constant ~
58 Language Guide
typed constant -~-+I
::======---------.
procedural constant
Simple-type
constants Declaring a typed constant as a simple type specifies the value of
the constant:
const
Maximum: Integer = 9999;
Factor: Real = -0.1;
Breakchar: Char = #3;
As mentioned earlier, the value of a typed constant can be
specified using a constant-address expression, that is, an
expression that takes the address, offset, or segment of a global
variable, a typed constant, a procedure, or a function. For
example,
var
Buffer: array[O .. 1023] of Byte;
const
BufferOfs: Word = Ofs(Buffer);
BufferSeg: Word = Seg(Buffer);
String-type
constants The declaration of a typed constant of a string type specifies the
maximum length of the string and its initial value:
const
Heading: string[7] = 'Section';
NewLine: string[2] = #13#10;
TrueStr: string[5] = 'Yes';
FalseStr: string[5] = 'No';
Structured-type
constants The declaration of a structured-type constant specifies the value
of each of the structure's components. Turbo Pascal supports the
declaration of array, record, object, and set-type constants. File-
type constants and constants of array, record, and object types
that contain file-type components aren't allowed.
60 Language Guide
This example defines the array constant StatStr, which can be
used to convert values of type TStatus into their corresponding
string representations. These are the components of StatStr:
StatStr[Active] = 'Active'
StatStr[Passive] = 'Passive'
StatStr[Waiting] = 'Waiting'
The component type of an array constant can be any type except a
file type. Packed string-type constants (character arrays) can be
specified both as single characters and as strings. The definition
const
Digits: array[0 .. 9] of Char = ('0', '1', '2', '3', '4', '5',
'6', '7', , 8', '9');
Object-type constants The declaration of an object-type constant uses the same syntax as
the declaration of a record-type constant. No value is, or can be,
specified for method components. Referring to the earlier object-
type declarations starting on page 34, these are examples of
object-type constants:
62 Language Guide
const
ZeroPoint: TPoint = (X: Oi Y: O)i
ScreenRect: TRect = (A: (X: Oi Y: 0) i B: (X: 80i Y: 25));
CountField: TNumField = (X: 5; Y: 20i Len: 4; Name: nili
Value: 0; Min: -999; Max: 999)i
Constants of an object type that contains virtual methods need not
be initialized through a constructor call-this initialization is
handled automatically by the compiler.
Pointer-type
constants The declaration of a pointer-type constant uses a constant-address
expression to specify the pointer value. Some examples follow:
type
TDirection = (Left, Right, Up, Down);
TStringptr = AString;
PNode = ATNode;
TNode = record
Next: PNode;
Symbol: TStringPtr;
Value: TDirection;
end;
const
Sl: string[4] , DOWW i
S2: string[2] 'UP'i
S3: string [5] 'RIGHT'i
S4: string [4] 'LEFT'i
N1: TNode = (Next: nili Symbol: @Sli Value: Down) i
N2: TNode = (Next: @Nl; Symbol: @S2; Value: Up) ;
N3: TNode = (Next: @N2i Symbol: @S3i Value: Right) ;
N4: TNode = (Next: @N3; Symbol: @S4; Value: Left) ;
DirectionTable: PNode = @N4;
Procedural-type
constants A procedural-type constant must specify the identifier of a proce-
dure or function that is assignment-compatible with the type of
the constant, or it must specify the value nil.
procedural constant
Here's an example:
type
TErrorProc = procedure (ErrorCode: Integer);
procedure DefaultError(ErrorCode: Integer); far;
begin
WriteLn('Error " ErrorCode, , .');
end;
const
ErrorHandler: TErrorProc = DefaultError;
64 Language Guide
c H A p T E R
Expressions
Expressions are made up of operators and operands. Most Pascal
operators are binary; they take two operands. The rest are unary
and take only one operand. Binary operators use the usual
algebraic form (for example, A + B). -A unary operator always
precedes its operand (for example, -B).
In more complex expressions, rules of precedence clarify the order
in which operations are performed.
Table 6.1
Precedence of operators Operators Precedence Categories
@,not first (high) unary operators
*, /, diY, mod, and, second multiplying operators
shl, shr
+,., or, xor third adding operators
=, <>, <, >, <=, >=, in fourth (low) relational operators
Chapter 6, Expressions 65
Operations with equal precedence are normally performed from
left to right, although the compiler may rearrange the operands to
generate optimum code.
Expression syntax
The precedence rules follow from the syntax of expressions,
which are built from factors, terms, and simple expressions.
A factor's syntax follows:
factor variable reference
unsigned constant f-----------t
66 Language Guide
These are some examples of factors:
x { Variable reference
@X Pointer to a variable
15 Unsigned constant
(X + Y + Z) { SUbexpression
Sin(X / 2) { Function call
exi t [ 0
I I 9 A
•• I I I I I •• I Z1
I Set constructor
not Done Negation of a Boolean
Char(Digit + 48) { Value typecast
x* Y
Z / (1 - Z)
Y shl 2
(X <= Y) and (Y < Z)
Simple expressions apply adding operators and signs to terms:
simple expression
Chapter 6, Expressions 67
expression
simple expression Jr--:::::::::-----;:::======:;-r-
~---,.~-.j simple expression
Operators
Operators are classified as arithmetic operators, logical operators,
string operators, character-pointer operators, set operators,
relational operators, and the @ operator.
Arithmetic
operators The following tables show the types of operands and results for
binary and unary arithmetic operations.
Table 6.2
Binary arithmetic operations Operator Operation Operand types Result type
The + operator is a/so used as + addition integer type integer type
a string or set operator, and real type real type
the +, -, and * operators are
a/so used as set operators. subtraction integer type integer type
real type real type
* multiplication integer type integer type
real type real type
division integer type real type
real type real type
div integer division integer type integer type
mod remainder integer type integer type
68 Language Guide
Table 6.1
Unary arithmetic operations Operator Operation Operand types Result type
Logical operators
The types of operands and results for logical operations are
shown in Table 6.4.
Chapter 6, Expressions 69
Table 6.4
Logical operations Operator Operation Operand types Result type
The not operator is a unary not bitwise negation integer type Boolean
operator. and bitwise and integer type Boolean
or bitwise or integer type Boolean
xor bitwise xor integer type Boolean
shl shift left integer type Boolean
shr shift right integer type Boolean
Boolean
operators The types of operands and results for Boolean operations are
shown in Table 6.5.
Table 6.5
Boolean operations Operator Operation Operand types Result type
The not operator is a unary not negation Boolean type Boolean
operator. and logical and Boolean type Boolean
or logical or Boolean type Boolean
xor logical xor Boolean type Boolean
70 Language Guide
minimum code size. Short-circuit evaluation also makes possible
the evaluation of constructs that would not otherwise be legal. For
example,
while (I <= Length(S)) and (S[I] <> ' ') do
Inc (I);
while (P <> nil) and (pA.Value <> 5) do
p := PA.Next;
In both cases, the second test is not evaluated if the first test is
False.
The evaluation model is controlled through the $B compiler
directive. The default state is {$B-}, and in this state, the compiler
generates short-circuit evaluation code. In the {$B+} state, the
compiler generates complete evaluation.
Because Standard Pascal doesn't specify which model should be
used for Boolean expression evaluation, programs dependent on
either model are not truly portable. You may decide, however,
that sacrificing portability is worth the gain in execution speed
and simplicity provided by the short-circuit model.
String operator
The types of operands and results for string operation are shown
in Table 6.6.
Table 6.6
String operation Operator Operation Operand types Result type
+ concatenation string type, string type
Char type, or
packed string type
Character-
pointer operators The extended syntax (enabled using a {$X+} compiler directive)
supports a number of character-pointer operations. The plus (+)
and minus (-) operators can be used to increment and decrement
Chapter 6, Expressions 71
the offset part of a pointer value, and the minus operator can be
used to calculate the distance (difference) between the offset parts
of two character pointers. Assuming that P and Q are values of
type PChar and I is a value of type Word, these constructs are
allowed:
Table 6.7
Permitted PChar constructs Operation Result
P +I Add I to the offset part of P
I +P Add I to the offset part of P
P- I Subtract I from the offset part of P
P- Q Subtract offset part of Q from offset part of P
Set operators
The types of operands for set operations are shown in Table 6.8.
Table 6.8
Set operations Operator Operation Operand types
72 Language Guide
Relational
operators The types of operands and results for relational operations are
shown in Table 6.9.
Table 6.9
Relational operations Operator type Operation Operand types Result type
= equal compatible simple, Boolean
pointer, set, string,
or packed string types
<> not equal compatible simple, Boolean
pointer, set, string,
or packed string types
< less than compatible simple, Boolean
string, packed
string types, or
PChar
> greater than compatible simple, Boolean
string, packed
string types, or
PChar
<= less than compatible simple, Boolean
or equal to string, packed
string types, or
PChar
>= greater than compatible simple, Boolean
or equal to string, or packed
string types, or
PChar
<= subset of compatible set types Boolean
>= superset of compatible set types Boolean
in member of left operand, any Boolean
ordinal type T;
right operand, set
whose base is
compatible with T
Comparing simple When the operands =, <>, <, >, >=, or <= are of simple types, they
types must be compatible types; however, if one operand is of a real
type, the other can be of an integer type.
Chapter 6, Expressions 73
Comparing strings The relational operators =, <>, <, >, >=, and <= compare strings
according to the ordering of the extended ASCII character set.
Any two string values can be compared because all string values
are compatible.
A character-type value is compatible with a string-type value.
When the two are compared, the character-type value is treated as
a string-type value with length 1. When a packed string-type
value with N components is compared with a string-type value,
it's treated as a string-type value with length N.
Comparing packed The relational operators =, <>, <, >, >=, and <= can also be used to
strings compare two packed string-type values if both have the same
number of components. If the number of components is N, then
the operation corresponds to comparing two strings, each of
lengthN.
Comparing pointers =
The operators and <> can be used on compatible pointer-type
operands. Two pointers are equal only if they point to the same
object.
Comparing character The extended syntax (enabled using a {$X+} compiler directive)
pointers allows the >, <, >=, and <= operators to be applied to PChar
values. Note, however, that these relational tests assume that the
two pointers being compared point within the same character array,
and for that reason, the operators only compare the offset parts of
the two pointer values. If the two character pointers point into
different character arrays, the result is undefined.
Comparing sets If A and B are set operands, their comparisons produce these
results:
• A = B is True only if A and B contain exactly the same members;
otherwise, A <> B.
• A <= B is True only if every member of A is also a member of B.
• A >= B is True only if every member of B is also a member of A.
74 Language Guide
Testing set membership The in operator returns True when the value of the ordinal-type
operand is a member of the set-type operand; otherwise, it returns
False.
The @ operator
The @ operator is used in an address factor to compute the
address of a variable, procedure, function, or method.
address factor :--r----+I variable reference
procedure identifier
function identifier
Chapter 6, Expressions 75
Function calls
See "Method activations" on A function call activates a function specified by a function
page 40, "Qualified-method identifier, a method designator, a qualified-method designator, or
activations" on page 41, and·
"Procedural types" on a procedural-type variable reference. The function call must have
page 44. a list of actual parameters if the corresponding function
declaration contains a list of formal parameters. Each parameter
takes the place of the corresponding formal parameter according
to parameter rules explained in Chapter 9, "Procedures and
functions," on page 107.
function call
function identifier
actual parameter list
method designator
variable reference
Set constructors
A set constructor denotes a set-type value, and is formed by
writing expressions within brackets ([D. Each expression denotes
a value of the set.
76 Language Guide
-(Df--"lr---;:==========::;---,---'CD--
set constructor
T!
member group ~
L..----<Ol+I---
.....
Value typecasts
The type of an expression can be changed to another type through
a value typecast.
value typecast -I type identifier r--cIH expression KD-
The expression type and the specified type must both be either
ordinal types or pointer types. For ordinal types, the resulting
value is obtained by converting the expression. The conversion
may involve truncation or extension of the original value if the
size of the specified type is different from that of the expression.
In cases where the value is extended, the sign of the value is
always preserved; that is, the value is sign-extended.
See "Variable typecasts" on The syntax of a value typecast is almost identical to that of a
page 57.
variable typecast. Value typecasts operate on values, however, not
on variables, and therefore they can't particIpate in variable
references; that is, a value typecast can't be followed by qualifiers.
In particular, value typecasts can't appear on the left side of an
assignment statement.
Chapter 6, Expressions 77
These are some examples of value typecasts:
Integer (' A')
Char (48)
Boolean(O)
Color(2)
Longint(@Buffer)
BytePtr(Ptr($40 , $49))
78 Language Guide
know if it should compare the procedural value in F to the
procedural value of Readlnt to determine if F currently points to
Readlnt, or if it should call F and Readlnt and then compare the
returned values.
if F = ReadInt then
WriteLn('Equal') ;
Standard Pascal syntax, however, specifies that the occurrence of
a function identifier in an expression denotes a call to that
function, so the effect of the preceding statement is to call F and
Readlnt, and then compare the returned values. To compare the
procedural value in F to the procedural value of Readlnt, the
following construct must be used:
if @F = @ReadInt then
Writeln('Equal');
end;
var
SornePtr: Pointer;
begin
SornePtr := @SorneProc;
end.
To get the memory address of a procedural variable rather than
the address stored in it, use a double address (@@) operator. For
example, where @P means convert P into an untyped pointer
variable, @@P means return the physical address of the variable P.
Chapter 6, Expressions 79
80 Language Guide
c H A p T E R
Statements
Statements describe algorithmic actions that can be executed.
Labels can prefix statements, and these labels can be referenced
by goto statements.
statement Ir-;:::::==::;--::::~TT---;:============:;--r-
simple statement
Simple statements
A simple statement is a statement that doesn't contain any other
statements.
simple statement assignment statement
Chapter 7, Statements 81
Assignment
statements Assignment statements replace the current value of a variable
with a new value specified by an expression. They can be used to
set the return value of the function also.
assignment statement
variable reference
function identifier
See the section "Type The expression must be assignment-compatible with the type of
compatibility" on page 47.
the variable or the type of the function result.
These are examples of assignment statements:
X := Y + Zi
Done := (I >= 1) and (I < 100)i
Hue1 := [Blue, SuCC(C)li
I := Sqr(J) - I * Ki
Procedure
statements A procedure statement activates a procedure specified by a
procedure identifier, a method designator, a qualified method
designator, or a procedural-type variable reference. If the
See Chapter 9, "Procedures corresponding procedure declaration contains a list of formal
and functions. "
parameters, then the procedure statement must have a matching
list of actual parameters (parameters listed in definitions are
formal parameters; in the calling statement, they are actual
82 Language Guide
parameters). The actual parameters are passed to the formal
parameters as part of the call.
procedure statement
procedure identifier r------:nr-;:::============::::;-f-
actual parameter list
method designator
variable reference
Goto statements
A goto statement transfers program execution to the statement
marked by the specified label. The syntax diagram of a goto
statement follows:
goto statement ~
Structured statements
Structured statements are constructs composed of other
statements that are to be executed in sequentially (compound and
with statements), conditionally (conditional statements), or
repeatedly (repetitive statements).
Chapter 7, Statements 83
structured statement -~-+l compound statement
Compound
statements The compound statement specifies that its component statements
are to be executed in the same sequence as they are written. The
component statements are treated as one statement, crucial in
contexts where the Pascal syntax only allows one statement. begin
and end bracket the statements, which are separated by
semicolons.
compound statement
Conditional
statements A conditional statement selects for execution a single one (or
none) of its component statements.
conditional statement
84 Language Guide
If the expression produces False and the else part is present, the
statement following else is executed; if the else part isn't present,
execution continues at the next statement following the if
statement.
The syntactic ambiguity arising from the construct
if e1 then if e2 then 81 else 82;
is resolved by interpreting the construct as follows:
Note: No semicolon is if e1 then
allowed preceding an else begin
clause.
if e2 then
81
else
82
end;
Usually, an else is associated with the closest if not already
associated with an else.
Two examples of if statements follow:
if x < 1. 5 then
Z := X + Y
else
Z := 1.5;
if P1 <> nil then
P1 := P1 A .Father;
Case statements The case statement consists of an expression (the selector) and a
list of statements, each prefixed with one or more constants
(called case constants) or with the word else. The selector must be
of a byte-sized or word-sized ordinal type, so string types and the
integer type Longint are invalid selector types. All case constants
must be unique and of an ordinal type compatible with the
selector type.
case statement
Chapter 7, Statements 85
else part -®--I statement ~
The case statement executes the statement prefixed by a case
constant equal to the value of the selector or a case range contain-
ing the value of the selector. If no such case constant of the case
range exists and an else part is present, the statement following
else is executed. If there is no else part, execution continues with
the next statement following the if statement.
These are examples of case statements:
case Operator of
Plus: X := X + Y;
Minus: X := X - Y;
Times: X := X * Y;
end;
case I of
0, 2, 4, 6, 8: Writeln('Even digit');
1, 3, 5, 7, 9: Writeln('Odd digit');
10 .. 100: Writeln('Between 10 and 100');
else
Writeln('Negative or greater than 100');
end;
Repetitive
statements Repetitive statements specify certain statements to be executed
repeatedly.
repetitive statement
for statement
86 Language Guide
Repeat statements A repeat statement contains an expression that controls the
repeated execution of astatement sequence within that repeat
statement.
repeat statement
~expressionf---
Chapter 7, statements 87
while I > 0 do
begin
if Odd (I) then Z := Z * X;
I := I div 2;
X := Sqr(X);
end;
while not 'Eof(1nFile) do
begin
Readln(1nFile, Line);
Process (Line) ;
end;
-I variable identifier ~
control variable
88 Language Guide
If the contained statement alters the value of the control variable,
your results will probably not be what you expect. After a for
statement is executed, the value of the control variable value is
undefined, unless execution of the for statement was interrupted
by a goto from the for statement.
With these restrictions in mind, the for statement
for V := ExprI to Expr2 do Body;
is equivalent to
begin
TempI := ExprI;
Temp2 := Expr2;
if TempI <= Temp2 then
begin
V := TempI;
Body;
while V <> Temp2 do
begin
V : = Succ (V) ;
Body;
end;
end;
end;
and the for statement
for V := ExprI downto Expr2 do Body;
is equivalent to
begin
TempI := ExprI;
Temp2 := Expr2;
if TempI >= Temp2 then
begin
V := TempI;
Body;
while V <> Temp2 do
begin
V := Pred(V);
Body;
end;
end;
end;
Chapter 7, Statements 89
where Templ and Temp2 are auxiliary variables of the host type of
the variable V and don't occur elsewhere in the program.
These are examples of for statements:
for I := 2 to 63 do
if Data[I] > Max then
Max := Data[I]
for I := 1 to 10 do
for J := 1 to 10 do
begin
X := 0;
for K := 1 to 10 do
X := X + Mat1[I, K] * Mat2[K, J];
Ma t [I, J] : = X;
end;
for C := Red to Blue do Check(C);
With statements
The with statement is shorthand for referencing the fields of a
record, and the fields and methods of an object. Within a with
statement, the fields of one or more specific record variables can
be referenced using their field identifiers only. The syntax of a
with statement follows:
90 Language Guide
here is an example of a with statement:
with OrderDate do
if Month = 12 then
begin
Month := 1;
Year := Year + 1
end
else
Month := Month + 1;
This is equivalent to
if OrderDate.Month = 12 then
begin
OrderDate.Month := 1;
OrderDate.Year := TDate.Year + 1
end
else
OrderDate.Month := TDate.Month + 1;
Within a with statement, each variable reference is first checked to
see if it can be interpreted as a field of the record. If so, it's always
interpreted as such, even if a variable with the same name is also
accessible. Suppose the following declarations have been made:
type
TPoint = record
X, Y: Integer;
end;
var
X: TPoint;
Y: Integer;
Chapter 7, Statements 91
The statement
with Vl, V2, ... Vn do S;
is equivalent to
with Vl do
with V2 do
with Vn do
S;
92 Language Guide
c H A p T E R
Blocks
The overall syntax of any block follows this format:
block - l declaration part ~I statement part ~
declaration part
H label declaration part I
The type declaration part includes all type declarations local to the
block.
type declaration part -~ type declaration I--r
The variable declaration part is composed of variable declarations
local to the block.
variable declaration part -@>-rl variable declaration l-r
The procedure and function declaration part is made up of procedure
and function declarations local to the block.
procedure/function declaration part
L...-r---r--+I procedure declaration
function declaration
constructor declaration
destructor declaration
94 Language Guide
Rules of scope
The presence of an identifier or label in a declaration defines the
identifier or label. Each time the identifier or label occurs again, it
must be within the scope of this declaration.
Block scope
The scope of an identifier or label declared in a label, constant,
type, variable, procedure, or function declaration stretches from
the point of declaration to the end of the current block, and
includes all blocks enclosed by the current block.
An identifier or label declared in an outer block can be redeclared
in an inner block enclosed by the outer block. Before the point of
declaration in the inner block, and after the end of the inner block,
the identifier or label represents the entity declared in the outer
block.
program Outer; { Start of outer scope }
type
I = Integer; { define I as type Integer }
var
T: I; { define T as an Integer variable }
procedure Inner; Start of inner scope }
type
T = I; redefine T as type Integer
var
I: T; { redefine I as an Integer variable
begin
I : = 1;
end; { End of inner scope }
begin
T : = 1;
end. { End of outer scope }
Record scope
The scope of a field identifier declared in a record-type definition
extends from the point of declaration to the end of the record-type
definition. Also, the scope of field identifiers includes field desig-
See "Record types" on nators and with statements that operate on variable references of
page 32.
the given record type.
Unit scope
The scope of identifiers declared in the interface section of a unit
follow the rules of block scope, and extends over all clients of the
unit. In other words, programs or units containing uses clauses
have access to the identifiers belonging to the interface parts of
the units in those uses clauses.
Each unit in a uses clause imposes a new scope that encloses the
remaining units used and the program or unit containing the
uses clause. The first unit in a uses clause represents the
outermost scope, and the last unit represents the innermost scope.
This implies that if two or more units declare the same identifier,
an unqualified reference to the identifier selects the instance
declared by the last unit in the uses clause. But by writing a
qualified identifier (a unit identifier, followed by a period,
followed by the identifier), every instance of the identifier can be
selected.
The identifiers of Turbo Pascal's predefined constants, types,
variables, procedures, and functions act as if they were declared
in a block enclosing all used units and the entire program. In fact,
these standard objects are defined in a unit called System, which is
used by any program or unit before the units named in the uses
clause. This means that any unit or program can redeclare the
standard identifiers, but a specific reference can still be made
through a qualified identifier, for example, System.Integer or
System. Writeln.
96 Language Guide
c H A p T E R
Procedure declarations
A procedure declaration associates an identifier with a block as a
procedure; that procedure can then be activated by a procedure
statement.
procedure declaration
Y procedure heading f--O-l subroutine block ~
procedure heading
The syntax for a formal The procedure heading names the procedure's identifier and
parameter list is shown in the
specifies the formal parameters (if any).
section "Parameters" on
page 107. A procedure is activated by a procedure statement, which states
the procedure's identifier and actual parameters, if any. The
statements to be executed on activation are noted in the statement
part of the procedure's block. If the procedure's identifier is used
in a procedure statement within the procedure's block, the
procedure is executed recursively (it calls itself while executing).
Here's an example of a procedure declaration:
procedure NumString(N: Integer; var S: string);
var
V: Integer;
begin
V := Abs (N);
S ..-- " ,.
repeat
S := Chr(N mod 10 + Ord('O')) + S;
N := N div 10;
until N = 0;
if N < 0 then
S .- '-' + S;
end;
98 Language Guide
they can be called from other modules. Procedures and functions
declared in a program or in the implementation part of a unit use
the near call model-they can only be called from within that
program or unit.
For some purposes, a procedure or function may be required to
use the far call model. For example, if a procedure or function is
to be assigned to a procedural variable, it has to use the far call
model. The $F compiler directive can be used to override the
compiler's automatic call model selection. Procedures and
functions compiled in the {$F+} state always use the far call
model; in the {$F-} state, the compiler automatically selects the
correct model. The default state is {$F-}.
To force a specific call model, a procedure or function declaration
can optionally specify a near or far directive before the block-if
such a directive is present, it overrides the setting of the $F
compiler directive as well as the compiler's automatic call model
selection.
Interrupt
declarations Optionally, a procedure declaration can specify an interrupt
directive before the block; the procedure is then considered an
interrupt procedure. For now, note that interrupt procedures can't
be called from procedure statements, and that every interrupt
procedure must specify a parameter list like the following:
See "Writing interrupt procedure MyInt(Flags, es, IP, AX, BX, ex, DX, SI, DI, DS, ES,
procedures" on page 243. BP: Word);
interrupt;
Forward
declarations A procedure or function declaration that specifies the directive
forward instead of a block is a forward declaration. Somewhere
after this declaration, the procedure must be defined by a defining
declaration. The defining declaration can omit the formal
parameter list and the function result, or it can optionally repeat
it. In the latter case, the defining declaration's heading must match
exactly the order, types, and names of parameters, and the type of
the function result, if any.
Walter(4, 5);
end;
procedure Walter;
begin
end;
A procedure's or function's defining declaration can be an external
or assembler declaration; however, it can't be a near, far,
interrupt, or inline declaration or another forward declaration.
External
declarations External declarations let you interface with separately compiled
procedures and functions written in assembly language. The
For further details on linking
with assembly language, see external code must be linked with the Pascal program or unit
Chapter 23. through {$L filename} directives.
Examples of external procedure declarations follow:
procedure MoveWord(var Source, Dest; Count: Word); external;
procedure MoveLong(var Source, Dest; Count: Word); external;
procedure FillWord(var Dest; Data: Integer; Count: Word); external;
procedure FillLong(var Dest; Data: Longint; Count: Word); external;
{$L BLOCK.OBJ}
Inline
declarations The inline directive enables you to write machine code instruc-
tions in place of a block of Pascal code.
inline directive -l inline statement ~
See the syntax of an inline When a normal procedure or function is called, the compiler
statement on page 284.
generates code that pushes the procedure's or function's
parameters onto the stack and then generates a CALL instruction
to call the procedure or function. When you call an inline
procedure or function, the compiler generates code from the inline
directive instead of the CALL. Therefore, an inline procedure or
function is expanded every time you refer to it, just like a macro
in assembly language.
Here's a short example of two inline procedures:
procedure Disablelnterruptsi inline($FA)i { eLI }
procedure Enablelnterruptsi inline($FB)i { STI }
Function declarations
A function declaration defines a block that computes and returns
a value.
function declaration
L-I function heading ~I subroutine block 1-0-
function heading
.----,
The function heading specifies the identifier for the function, the
formal parameters (if any), and the function result type.
A function is activated by the evaluation of a function call. The
function call gives the function's identifier and actual parameters,
if any, required by the function. A function call appears as an
operand in an expression. When the expression is evaluated, the
function is executed, and the value of the operand becomes the
value returned by the function.
The statement part of the function's block specifies the statements
to be executed upon activation of the function. The block should
contain at least one assignment statement that assigns a value to
the function identifier. The result of the function is the last value
assigned. If no such assignment statement exists or if it isn't
executed, the value returned by the function is undefined.
If the function's identifier is used in a function call within the
function's block, the function is executed recursively.
Following are examples of function declarations:
function Max(A: Vector; N: Integer): Extended;
var
. X: Extended;
I: Integer;
begin
X := A[l];
for I := 2 to N do
if X < A[I] then X := A[I];
Max := X;
end;
function Power(X: Extended; Y: Integer): Extended;
var
Z: Extended;
I: Integer;
begin
Z := 1.0; I := Y;
while I > 0 do
begin
if Odd (I) then Z := Z * X;
I := I div 2;
X := Sqr(X);
end;
Method declarations
See page 37 for more about The declaration of a method within an object type corresponds to
declaring methods in a forward declaration of that method. Therefore, somewhere after
objects.
the object-type declaration and within the same scope as the
object-type declaration, the method must be implemented by a
defining declaration.
For procedure and function methods, the defining declaration
takes the form of a normal procedure or function, but the proce-
dure or function identifier is a qualified-method identifier. This is an
object-type identifier followed by a period C.) and then by a
method identifier.
For constructor methods and destructor methods, the defining
declaration takes the form of a procedure method declaration,
except that the procedure reserved word is replaced by a con-
structor or destructor reserved word.
Optionally, a method's defining declaration can repeat the formal
parameter list of the method heading in the object type. If it does,
the defining declaration's method heading must match exactly the
order, types, and names of the parameters, and the type of the
function result, if any.
In the defining declaration of a method, there is always an impli-
cit parameter with the identifier Self, corresponding to a formal
variable parameter that possesses the object type. In the method
block, Self represents the instance whose method component was
designated to activate the method. Therefore, any changes made
to the values of the fields of Self are reflected in the instance.
The scope of a component identifier in an object type extends over
any procedure, function, constructor, or destructor block that
implements a method of the object type. The effect is the same as
if the entire method block was embedded in a with statement of
the form
with Self do begin ... end
Parameters
The declaration of a procedure or function specifies a formal
parameter list. Each parameter declared in a formal parameter list
is local to the procedure or function being declared. Your
~------~CD~·------~
r-rw-
parameter declaration
,...--------,
parameter type
Value parameters
A formal value parameter acts like a variable local to the proce-
dure or function, except it gets its initial value from the corres-
ponding actual parameter upon activation of the procedure or
function. Changes made to a formal value parameter don't affect
the value of the actual parameter.
A value parameter's corresponding actual parameter in a proce-
dure statement or function call must be an expression, and its
value must not be of file type or of any structured type that
contains a file type.
The actual parameter must be assignment-compatible with the
type of the formal value parameter. If the parameter type is string,
then the formal parameter is given a size attribute of 255.
Variable
parameters A variable parameter is used when a value must be passed from a
procedure or function to the caller. The corresponding actual
parameter in a procedure statement or function call must be a
variable reference. The formal variable parameter represents the
actual variable during the activation of the procedure or function,
so any changes to the value of the formal variable parameter are
reflected in the actual parameter.
File types can be passed Within the procedure or function, any reference to the formal
only as variable parameters.
variable parameter accesses the actual parameter itself. The type
of the actual parameter must be identical to the type of the formal
variable parameter (you can bypass this restriction through
untyped parameters).
For more information on The $P compiler directive controls the meaning of a variable
open-string parameters, see
page 717.
parameter declared using the string keyword. In the default {$P-}
state, string corresponds to a string type with a size attribute of
255. In the {$P+} state, string indicates that the parameter is an
open-string parameter.
Untyped
parameters When a formal parameter is an untyped parameter, the corres-
ponding actual parameter can be any variable or constant
reference, regardless of its type. An untyped parameter declared
using the var keyword can be modified, whereas an untyped
parameter declared using the const keyword is read-only.
Within the procedure or function, the untyped parameter is
typeless; that is, it is incompatible with variables of all other
types, unless it is given a specific type through a variable typecast.
This is an example of untyped parameters:
function Equal (var Source, Dest; Size: Word): Boolean;
type
TBytes = array[O .. 65534] of Byte;
var
N: Word;
begin
N := 0;
while (N < Size) and (TBytes(Dest) [N] = TBytes(Source) [N]) do
Inc (N);
Equal := N = Size;
end;
This function can be used to compare any two variables of any
size. For instance, given the declarations
type
TVector = array[l .. lO] of Integer;
TPoint = record
X, Y: Integer;
end;
Open parameters
Open parameters allow strings and arrays of varying sizes to be
passed to the same procedure or function.
Dispose(ZP, Done);
Dispose(SP, Done);
end;
You can also use New as afunction that allocates and returns a
dynamic variable of a specified type:
New(T)
or
New(T, Construct)
10
The program
heading The program heading specifies the program's name and its
parameters.
program parameters
Unit syntax
Units are the basis of modular programming in Turbo Pascal.
They're used to create libraries that you can include in various
programs without making the source code available, and to
divide large programs into logically related modules.
The
implementation The implementation part defines the block of all public proce-
dures and functions. In addition, it declares constants, types, vari-
part
ables, procedures, and functions that are private; that is, they
aren't available to the host.
implementation part
Implementation )-,;:::======:::::;-r-1 declaration part
The initialization
part The initialization part is the last part of a unit. It consists either of
the reserved word end (in which case, the unit has no initializa-
tion code) or of a statement part to be executed to initialize the
unit.
initialization part .~
Y
statement part ~
I
Indirect unit
references The uses clause in a module (program or unit) need only name
the units used directly by that module. Consider the following:
program Prog;
uses Unit2;
const a = b;
begin
end.
unit Unit2;
interface
uses Unit1;
const b = c;
implementation
end.
unit Unit1;
interface
const c = 1;
implementation
const d = 2;
end.
Unit2 is directly dependent on Unitl and Prog is directly
dependent on Unit2. Also, Prog is indirectly dependent on Unitl
(through Unit2), even though none of the identifiers declared in
Unitl are available to Prog.
To compile a module, the compiler must be able to locate all units
the module depends upon, either directly or indirectly. So, to
Circular unit
references If you place a uses clause in the implementation section of a unit,
you hide the inner details of the unit referenced in the uses
clause; the referenced unit is private and not available to the
program or unit using the unit it's referenced in. You can use this
technique to construct mutually-dependent units.
The following program demonstrates how two units can "use"
each other:
program Circular;
{ Display text using WriteXY }
uses
Crt, Display;
begin
ClrScr;
WriteXY{l, 1, 'Upper left corner of screen');
WriteXY{1000, 1000, 'Way off the screen');
WriteXY{81 - Length{'Back to reality'), 15, 'Back to reality');
end.
Sharing other If you want to modify the WriteXY and ShowError procedures to
declarations take an additional parameter that specifies a rectangular window
onscreen, you might write this:
procedure writeXY(SorneWindow: WindRec; X, Y: Integer;
Message: String);
procedure ShowError(SomeWindow: WindRec; ErrMsg: String);
These procedures are declared in the interface sections of different
units. Because both need to use the WindRec type, WindRec can't
be declared in either of the interface sections-that would make
them depend on each other. The solution is to create a third unit
that contains only the definition of the window record:
unit WindData;
interface
type
WindRec = record
Xl, Yl, X2, Y2: Integer;
ForeColor, BackColor: Byte;
Active: Boolean;
end;
implementation
end.
You can now add WindData to the uses clause in interface
sections of both the Display and Error units. Both of these units
125
126 Language Guide
c H A p T E R
11
System unit
The System unit implements low-level, run-time support routines
for all built-in features, such as file I/O, string handling, floating
point, and dynamic memory allocation. The System unit is used
automatically by any unit or program and doesn't need to be
referred to in a uses clause.
Printer unit
For more about the Printer The Printer unit lets you send standard Pascal output to your
unit, see page 747 in printer using Write and Writeln.
Chapter 73, "Input and
output."
Overlay unit
To read about the Overlay The Overlay unit enables you to reduce your program's total run-
unit, see Chapter 78, "Using
overlays. "
time memory requirements. In fact, you can write programs that
are larger than the total available memory because only parts of
your program will reside in memory at any given time.
Strings unit
See page 767 in Chapter 76, With Turbo Pascal's extended syntax and the Strings unit, your
"Using nUl/-terminated programs can use null-terminated strings, so that they are more
strings," for information about
using the Strings unit. compatible with any Windows programs you write.
Graph unit
Read about the Graph unit The Graph unit supplies a set of fast, powerful graphics routines.
in Chapter 77, "Using the It implements the device-independent Borland graphics handler
Borland Graphics Interface. "
that supports CGA, EGA, VGA, Hercules, AT&T 400, MCGA,
3270 PC, and 8514 graphics. The Graph unit isn't built into
TURBO.TPL, but is on the same disk with the .BGI (Borland
Graphic Interface) and .CHR files.
12
String procedures and These procedures and functions are used on the traditional
functions Pascal-style strings:
Table 12.5
String procedures and Procedure
functions or function Description
Coneat Concatenates a sequence of strings.
Copy Returns a substring of a string.
Delete Deletes a substring from a string.
Insert Inserts a substring into a string.
Length Returns the dynamic length of a string.
Pas Searches for a substring in a string.
Str Converts a numeric value to its string
representation.
Val Converts the string value to its numeric
representation.
Pointer and address The pointer and address functions are listed in this table:
functions
Table 12.7
Pointer and address Function Description
functions Addr Returns the address of a specified object.
Assigned Tests to determine if a pointer or procedural variable is
nil.
CSeg Returns the current value of the C5 register.
DSeg Returns the current value of the D5 register.
Ofs Returns the offset of a specified object.
Ptr Converts a segment base and an offset address to a
pointer-type value.
Seg Returns the segment of a specified object.
SPtr Returns the current value of the 5P register.
SSeg Returns the current value of the 55 register.
Predeclared variables The System unit also supplies several predeclared variables:
Table 12.9
Predeclared variables in the Variable Type Description
System unit ErrorAddr Pointer Run-time error address
ExitCode Integer Exit code
ExitProc Pointer Exit procedure
FileMode Byte File open mode
FreeList Pointer Free heap-block list
FreeZero Pointer Free zero
HeapEnd Pointer Heap end
HeapError Pointer Heap-error function
HeapOrg Pointer Heap origin
HeapPtr Pointer Heap pointer
Input Text Input standard file
InOutRes Integer IIO result buffer
Output Text Output standard file
13
Text files
In Turbo Pascal, the type This section summarizes 1/ a using file variables of the standard
Text is distinct from the type
type Text.
file of Char.
When a text file is opened, the external file is interpreted in a
special way: It's considered to represent a sequence of characters
formatted into lines, where each line is terminated by an end-of-
The FileMode
variable The FileMode variable defined by the System unit determines the
access code to pass to DOS when typed and untyped files (not text
files) are opened using the Reset procedure.
New files created using The default FileMode is 2, which allows both reading and writing.
Rewrite are always opened
Assigning another value to FileMode causes all subsequent Resets
in read/write mode,
corresponding to to use that mode.
FileMode=2.
The range of valid FileMode values depends on the version of DOS
in use. For all versions, however, the following modes are
defined:
o Read only
1 Write only
2 Read/Write
DOS version 3.x and higher defines additional modes, which are
primarily concerned with file-sharing on networks. (For more
details, see your DOS programmer's reference manual.)
DOS devices
DOS devices are implemented through reserved file names that
have a special meaning attached to them. DOS devices are com-
pletely transparent-in fact, Turbo Pascal isn't even aware when a
file variable refers to a device instead of a disk file. For example,
the program
var
Lst: Text;
begin
Assign(Lst, 'LPT1');
Rewrite(Lst);
Writeln(Lst, 'Hello World ... ');
Close(Lst) ;
end.
writes the string "Hello World ... " on the printer, even though the
syntax for doing so· is exactly the same as for a disk file.
The devices implemented by DOS are used for obtaining or
presenting legible input or output. Therefore, DOS devices are
normally used only in connection with text files. On rare occa-
sions, untyped files can also be useful for interfacing with DOS
devices.
The CON device CON refers to the CONsole device, in which output is sent to the
display, and input is obtained from the keyboard. The Input and
Output standard files and all files assigned an empty name refer to
the CON device when input or output isn't redirected.
Input from the CON device is line-oriented and uses the line-
editing facilities described in your DOS manual. Characters are
read from a line buffer, and when the buffer becomes empty, a
new line is input.
The LPTl, LPT2, and The line-printer devices are the three possible printers you can
LPT3 devices use. If only one printer is connected, it's usually referred to as
LPTl, for which the synonym can also be used.
The line-printer devices are output-only devices-an attempt to
Reset a file assigned to one of these generates an immediate end-
of-file.
The standard unit Printer declares a text-file variable called Lst,
and makes it refer to the LPTI device. To easily write something
on the printer from one of your programs, include Printer in the
program's uses clause, and use Write(Lst, ... ) and Writeln(Lst, .. .) to
produce your output.
The COM 1 and COM2 The communication-port devices are the two serial communi-
devices cation ports. The synonym AUX can be used instead of COMl.
The NUL device The NUL device ignores anything written to it, and generates an
immediate end-of-file when read from. You should use this when
you don't want to create a particular file, but the program
requires an input or output file name.
Text-file devices
Text-file devices are used to implement devices unsupported by
DOS or to provide another set of features similar to those
supplied by another DOS device. A good example of a text-file
device is the CRT device implemented by the Crt standard unit. It
provides an interface to the display and the keyboard, like the
CON device in DOS, but the CRT device is much faster and
supports such invaluable features as color and windows.
Unlike DOS devices, text-file devices have no reserved file names;
in fact, they have no file names at all. Instead, a file is associated
with a text-file device through a customized Assign procedure.
For example, the Crt standard unit implements an AssignCrt
procedure that associates text files with the CRT window.
The initialization code of the Crt unit assigns the Input and Output
standard text files to refer to the CRT instead of to DOS's standard
input and output files. These statements execute at the beginning
of a program:
AssignCrt(Input); Reset (Input) ;
AssignCrt(Output); Rewrite (Output) ;
This means that I/O redirection of the Input and Output files is no
longer possible unless these files are explicitly assigned back to
standard input and output by executing this:
Assign(Input, "); Reset (Input) ;
Assign (Output, "); Rewrite (Output) ;
Windows
Crt supports a simple yet powerful form of windows. The Window
procedure lets you define a window anywhere on the screen.
When you write in such a window, the window behaves exactly
as if you were using the entire screen, leaving the rest of the
screen untouched. In other words, the screen outside the window
isn't accessible. Inside the window, lines can be inserted and
deleted, the cursor wraps around at the right edge, and the text
scrolls when the cursor reaches the bottom line.
Special charactArs When writing to Output or a file that has been assigned to the
CRT, the following control characters have special meanings:
Table 13.2
Control characters Char Name Description
#7 BELL Emits a beep from the internal speaker.
#8 BS Moves the cursor left one column. If the cursor is
already at the left edge of the current window,
nothing happens.
#10 LF Moves the cursor down one line. If the cursor is
already at the bottom of the current window, the
window is scrolled up one line.
#13 CR Returns the cursor to the left edge of the current
window.
Line input When reading from Input or from a text file that has been assigned
to Crt, text is input one line at a time. The line is stored in the text
file's internal buffer, and when variables are read, this buffer is
used as the input source. Whenever the buffer has been emptied,
a new line is input.
When entering lines, the following editing keys are available:
Table 13.3
Line input editing keys Editing key Description
Backspace Deletes the last character entered.
Esc Deletes the entire input line.
Enter Terminates the input line and stores the end-of-line
marker (carriage return/line feed) in the buffer.
Ctrl+S Same as Backspace.
Ctrl+D Recalls one character from the last input line.
Ctrl+A Same as Esc.
Ctrl+F Recalls the last input line.
Ctrl+Z Terminates the input line and generates an end-of-file
marker.
Crt procedures
and functions The following table lists the procedures and functions defined in
the Crt unit.
Table 13.4
Crt unit procedures and Procedure
functions or function Description
AssignCrt Associates a text file with the CRT window.
ClrEol Clears all the characters from the cursor position to
the end of the line.
See the Programmer's ClrScr Clears the screen and returns cursor to the upper
Reference for more details left-hand corner.
about using the Crt
procedures and functions. Delay Delays a specified number of milliseconds.
DelLine Deletes the line containing the cursor and moves all
lines below that line one line up. The bottom line is
cleared.
GotoXY Positions the cursor. X is the horizontal position. Y is
the vertical position.
High Video Selects high-intensity characters.
InsLine Inserts an empty line at the cursor position.
KeyPressed Returns True if a key has been pressed on the
keyboard.
LowVideo Selects low-intensity characters.
Norm Video Selects normal characters.
NoSound Turns off the internal speaker.
Sound Starts the internal speaker.
TextBackground Selects the background color.
TextColor Selects the foreground character color.
TextMode Selects a specific text mode.
Window Defines a text window onscreen.
ReadKey Reads a character from the keyboard.
For example, to find the value of a constant that will color the text
in your program red, look up Text Color constants, and you'll
discover that the constant Red has a value of 4.
These are the variables in the Crt unit and the functions they
perform:
Table 13.6
crt unit variables Variable Description
CheckBreak Enables and disables checks for Ctrl+Break.
CheckEOF Enables and disables the end-of-file character.
CheckSnow Enables and disables "snow checking".
Direct Video Enables and disables direct memory access for Write
and Writeln statements that output to the screen.
LastMode Stores the current video mode when each time
TextMode is called.
TextAttr Stores the currently-selected text attributes.
WindMin Stores the screen coordinates of the upper-left comer
of the current window.
WindMax Stores the screen coordinates of the lower-right
corner of the current window.
The Open
function The Open function is called by the Reset, Rewrite, and Append
standard procedures to open a text file associated with a device.
On entry, the Mode field contains fmlnput, fmOutput, or fmlnOut to
indicate whether the Open function was called from Reset, Rewrite,
or Append.
The Open function prepares the file for input or output, according
to the Mode value. If Mode specifiedfmlnOut (indicating that Open
was called from Append), it must be changed to fmOutput before
Open returns.
Open is always called before any of the other device-interface
functions. For that reason, AssignDev only initializes the OpenFunc
field,leaving initialization of the remaining vectors up to Open.
Based on Mode, Open can then install pointers to either input- or
output-oriented functions. This saves the InOut, Flush functions
and the Close procedure from determining the current mode.
The InOut
function The InOut function is called by the Read, Readln, Write, Writeln,
Eof, Eoln, SeekEof, SeekEoln, and Close standard procedures and
functions whenever input or output from the device is required.
When Mode is fmlnput, the InOut function reads up to BufSize
characters into BufPtr A , and returns the number of characters read
in BufEnd. In addition, it stores zero in BufPos. If the InOut
function returns zero in BufEnd as a result of an input request, Eof
becomes True for the file.
When Mode is fmOutput, the InOut function writes BufPos
characters from BufPtr A , and returns zero in BufPos.
The Close
function The Close function is called by the Close standard procedure to
close a text file associated with a device. (The Reset, Rewrite, and
Append procedures also call Close if the file they are opening is
already open.) If Mode is jmOutput, then before calling Close,
Turbo Pascal's file system calls the InOut function to ensure that
all characters have been written to the device.
14
Comparing reals
Because real-type values are approximations, the results of
comparing values of different real types aren't always as
expected. For example, if X is a variable of type Single and Y is a
variable of type Double, then the following statements are False:
x := 1 / 3;
Y := 1 / 3;
Writeln(X = Y);
This is because X is accurate only to 7 to 8 digits, where Y is
accurate to 15 to 16 digits, and when both are converted to
Extended, they differ after 7 to 8 digits. Similarly, the statements
x := 1 / 3;
Writeln{X = 1 / 3);
are False, because the result of 1/3 in the Writeln statement is
calculated with 20 significant digits.
Detecting the
80x87 The Turbo Pascal 80x87 run-time library built into your program
(compiled with {$N+}) includes startup code that automatically
detects the presence of an 80x87 chip. If an 80x87 is available, then
the program will use it. If one isn't present, the program will use
the emulation run-time library. If the program was compiled in
the {$E-} state, and an 80x87 could not be detected at startup, the
program displays "Numeric coprocessor required," and ends.
You might want to override this default auto detection behavior
occasionally. For example, your own system might have an 80x87,
but you want to verify that your program will work as intended
on systems without a coprocessor. Or your program might need
to run on a PC-compatible system, but that particular system
returns incorrect information to the auto detection logic (saying
that an 80x87 is present when it's not, or vice versa).
Turbo Pascal provides an option for overriding the startup code's
default autodetection logic: the 87 environment variable.
15
Table 15.2
Dos unit interrupt support Procedure Description
procedures GetIntVec Returns the address stored in a specified
interrupt vector.
Jntr Executes a specified software interrupt with a
specified Registers package.
MsDos Executes a DOS function call with a specified
Registers package.
SetIntVec Sets a specified interrupt vector to a specified
address.
Table 15.4
Dos unit file-handling Procedure
procedures and functions or function Description
FExpand Takes a file name and returns a fully qualified file
name (drive, directory, name, and extension).
Fsearch Searches for a file in a list of directories.
Fsplit Splits a file name into its three component parts
(drive and directory, file name, and extension).
FindFirst Searches the specified directory for the first entry
matching the specified file name and set of
attributes.
FindNext Returns the next entry that matches the name
and attributes specified in a previous call to
FindFirst.
GetFAttr Returns the attributes of a file.
setFAttr Sets the attributes of a file.
Table 15.5
Dos unit environment- Function Description
handling functions EnvCount Returns the number of strings contained in the
DOS environment.
Envstr Returns a specified environment string.
GetEnv Returns the value of a specified environment
variable.
Table 15.6
Dos unit process-handling Procedure Description
procedures Exec Executes a specified program with a specified
command line.
Keep Keep (or Terminate Stay Resident) terminates the
program and makes it stay in memory.
Swap Vectors Swaps all saved interrupt vectors with the
current vectors.
Constants
The Dos unit defines several constants. These constants can be
grouped by their function. To learn more about these constants,
look them up as part of the group they belong to. For example, to
find the value of FParity, look up "Flag constants" in the
Programmer's Reference.
Table 15.8
Dos unit constants Constant group Description
Flag Used to test individual flag bits in the Flags
register after a call to Intr or MsDos: FCarry,
FParity, FAuxiliary, FZero, Fsign, FOverfLow
fmXXXX Defines the allowable values for Mode field of a
TextRec text file record:fmClosed,fmlnput,
fmOutput, fmlnOut
File attribute Used to construct file attributes for use with
FindFirst, GetFAttr, and setFAttr: ReadOnly,
Hidden, sysFile, VolumeID, Directory, Archive,
AnyFile
Variables DosError is used by many of the routines in the Dos unit to report
errors.
Table 15.11
WinDos unit interrupt support Procedure Description
procedures GetIntVec Returns the address stored in a specified
interrupt vector.
Don't use these functions Intr Executes a specified software interrupt with a
when running Windows in specified TRegisters package.
protected mode.
MsDos Executes a DOS function call with a specified
TRegisters package.
SetIntVec Sets a specified interrupt vector to a specified
address.
Table 15.12
WinDos unit disk status Function Description
functions DiskFree Returns the number of free bytes of a specified
disk drive.
DiskSize Returns the total size in bytes of a specified disk
drive.
Table 15.13
File-handling procedures and Procedure
functions or function Description
FileExpand Takes a file name and returns a fully qualified file
name (drive, directory, name, and extension).
FileSearch Searches for a file in a list of directories.
FileSplit Splits a file name into its three component parts
(directory, file name, and extension).
FindFirst Searches the specified directory for the first entry
matching the specified file name and set of
attributes.
FindNext Returns the next entry that matches the name
and attributes specified in a previous call to
FindFirst.
GetFAttr Returns the attributes of a file.
SetFAttr Sets the attributes of a file.
Table 15.15
WinDos unit environment- Function Description
handling functions GetArgCount Returns the number of parameters passed to the
program on the command line.
GetArgStr Returns a specified command-line argument.
GetEnvVar Returns a pointer to the value of a specified
environment variable.
Table 15.16
WinDos unit miscellaneous Procedure
procedures and functions or function Description
DosVersion Returns the DOS version number.
GetCBreak Returns the state of Ctrl+Break checking in DOS.
Get Verify Returns the state of the verify flag in DOS.
SetCBreak Sets the state of Ctri+Break checking in DOS.
Set Verify Sets the state of the verify flag in DOS.
Constants
The WinDos unit uses several constants. These constants can be
grouped by their function. To learn more about these constants,
look them up as part of the constant group they belong to. For
example, to find the value of fParity, look up "Flag constants" in
the Programmer's Reference.
Types
The WinDos unit defines these types:
Table 15.18
WinDos unit types Types Description
File record types TFileRec is used for both typed and untyped files;
TTextRec is the internal format of a variable of type
text.
TRegisters Variables of this type are used by Intr and MsDos to
specify the input register contents and examine the
output register contents of a software interrupt.
TDateTime Variables of this type are used to examine and
construct 4-byte, packed date-and-time values for
GetFTime, SetFTime, FindFirst, and FindNext.
TSearchRec Variables of this type are used by FindFirst and
FindNext to scan directories.
Variables
Dos Error is used by many of the routines in the WinDos unit to
report errors.
16
Character
pointers and When extended syntax is enabled, a string literal is assignment
string literals compatible with the PChar type. This means that a string literal can
be assigned to a variable of type PChar. For example,
var
P: PChari
begin
P .- 'Hello world ... 'i
endi
begin
P := @TempString;
end;
You can use string literals as actual parameters in procedure and
function calls when the corresponding formal parameter is of type
PChar. For example, given a procedure with the declaration
procedure PrintStr(Str: PChar);
the following procedure calls are valid:
PrintStr('This is a test');
PrintStr(#10#13);
Just as it does with an assignment, the compiler generates a null-
terminated copy of the string literal. The compiler passes a
pointer to that memory area in the Str parameter of the PrintStr
procedure.
Finally, you can initialize a typed constant of type PChar with a
string constant. You can do this with structured types as well,
such as arrays of PChar and records and objects with PChar fields.
const
Message: PChar = 'Program terminated';
Prompt: PChar = 'Enter values: 'i
Digits: array[O .. 9] of PChar = (
'Zero', 'One', 'Two', 'Three', 'Four',
'Five', 'Six', 'Seven', 'Eight', 'Nine');
A string constant expression is always evaluated as a Pascal-style
string even if it initializes a typed constant of type PChar;
therefore, a string constant expression is always limited to 255
characters in length.
begin
P := A;
PrintStr(A};
PrintStr(P} ;
end;
Because of this assignment statement, P now points to the first
element of A, so PrintStr is called twice with the same value.
You can initialize a typed constant of a zero-based character array
type with a string literal that is shorter than the declared length of
the array. The remaining characters are set to NULL (#0) and the
array effectively contains a null-terminated string.
type
TFileName = array[O .. 79) of Char;
const
FileNameBuf: TFileNarne = 'TEST.PAS';
FileNarnePtr: PChar = FileNarneBuf;
Character pointer
indexing Just as a zero-based character array is compatible with a character
pointer, so can a character pointer be indexed as if it were a zero-
based character array.
var
A: array[O .. 63) of Char;
P: PChar;
Ch: Char;
Null-terminated
strings and Turbo Pascal's extended syntax allows the Read, Readln, Str, and
standard Val standard procedures to be applied to zero-based character
arrays, and allows the Write, Writeln, Val, Assign, and Rename
procedures standard procedures to be applied to both zero-based character
arrays and character pointers. For more details, see the descrip-
tions of these standard procedures in the Programmer's Reference.
An example using
string-handling Here's a code example that shows how we used some of the
functions string-handling functions when we wrote the FileSplit function in
the WinDos unit:
{ Maximum file name component string lengths
const
fSPathName = 79;
fsDirectory = 67;
fsFileName = 8;
fsExtension = 4;
FileSplit return flags
const
fcExtension = $0001;
fcFileName = $0002;
fcDirectory = $0004;
fcWildcards = $0008;
FileSplit splits the file name specified by Path into its
three components. Dir is set to the drive and directory path
{ with any leading and trailing backslashes, Name is set to the
{ file name, and Ext is set to the extension with a preceding
{ period. If a component string parameter is NIL, the
{ corresponding part of the path is not stored. If the path
{ does not contain a given component, the returned component
{ string is empty. The maximum lengths of the strings returned
17
Drivers
Graphics drivers are provided for the following graphics adapters
(and true compatibles):
.CGA • Hercules
• MCGA • AT&T 400 line
• EGA .3270 PC
.VGA • IBM 8514
Coordinate
system By convention, the upper left corner of the graphics screen is (0,0).
The x values, or columns, increment to the right. The y values, or
rows, increment downward. In 320x200 mode on a eGA, the
screen coordinates for each of the four corners with a specified
point in the middle of the screen would look like this:
Figure 17.1
Screen with xv-coordinates (0,0) (319,0)
~----------------~
.(159,99)
(0,199) (319,199)
Text
An 8x8 bitmapped font and several stroked fonts are included for
text output while in graphics mode. A bitmapped character is
defined by an 8x8 matrix of pixels. A stroked font is defined by a
series of vectors that tell the graphics system how to draw the
font.
The advantage of using a stroked font is apparent when you start
to draw large characters. Because a stroked font is defined by
vectors, it retains good resolution and quality when the font is
enlarged.
When a bitmapped font is enlarged, the matrix is multiplied
by a scaling factor and, as the scaling factor becomes larger, the
Error handling
Internal errors in the Graph unit are returned by the function
GraphResuIt. GraphResuIt returns an error code that reports the
status of the last graphics operation. Find the error return codes
under GraphResult Errors in Chapter I, "Library reference," in
the Programmer's Reference.
The following routines set GraphResuIt:
Bar ImageSize SetF illPattern
Bar3D InitGraph SetF illS tyle
ClearViewPort Install User Driver SetGraphBufSize
CloseGraph InstallUserFont SetGraphMode
DetectGraph PieS lice SetLineStyle
DrawPoly Regis terB Gldriver SetPalette
FillPoly RegisterBGIfont SetTextJustify
FloodFill SetAllPalette SetTextStyle
GetGraphMode
GraphResuIt is reset to zero after it has been called. Therefore, the
user should store the value of GraphResuIt into a temporary
variable and then test it.
Heap
management Two heap management routines are used by the Graph unit:
routines GraphGetMem and GraphFreeMem. GraphGetMem allocates
memory for graphics device drivers, stroked fonts, and a scan
buffer. GraphFreeMem de allocates the memory allocated to the
drivers. The standard routines take the following form:
procedure GraphGetMem(var P: Pointer; Size: Word);
{ Allocate memory for graphics }
procedure GraphFreeMem(var P: Pointer; Size: Word);
{ Deallocate memory for graphics }
Two pointers are defined by Graph that, by default, point to the
two standard routines described here. The pointers are defined as
follows:
var
GraphGetMemPtr: Pointer; { Pointer to memory allocation routine }
GraphFreeMemPtr: Pointer Pointer to memory deal location routine }
The Graph unit calls the heap management routines referenced by
GraphGetMemPtr and GraphFreeMemPtr to allocate and deallocate
memory for three different purposes:
• A multi-purpose graphics buffer whose size can be set by a call
to SetGraphBujSize (default equals 4K)
• A device driver that is loaded by InitGraph (*.BGI files)
• A stroked font file that is loaded by SetTextStyle (*.CHR files)
The graphics buffer is always allocated on the heap. The device
driver is allocated on the heap unless your program loads or links
one in and calls RegisterBGldriver. The font file is allocated on the
heap when you select a stroked font using SetTextStyle-unless
your program loads or links one in and calls RegisterBGIfont.
When the Graph unit is initialized, these pointers point to the
standard graphics allocation and deallocation routines that are
defined in the implementation section of the Graph unit. You can
Constants
The Graph constants can be grouped by their function. To learn
more about these constants, see Chapter I, "Library reference," in
the Programmer's Reference. Look up the constant under the group
it belongs to. This table will help you identify the group you
want:
Table 17.3
Graph unit constant groups Constant group Description
Driver and mode Constants that specify video drivers and
modes; used with InitGraph, DetectGraph,
and GetModeRange.
grXXXX Constants that identify the type of error
returned from GraphResult.
Color Constants that specify colors; used with
setPalette and setAllPalette.
Color for setRGBPalette Constants used with setRGBPalette to select
standard EGA colors on an IBM 8514.
Line style Constants used to determine a line style
and thickness; used with GetLinesettings
and setLinestyle.
Font control Constants that identify fonts; used with
GetTextsettings and setTextstyle.
Justification Constants that control horizontal and
vertical justification; used with
setTextJustify.
Clipping Constants that control clipping; used with
Set ViewPort.
Bar Constants that control the drawing of a 3-D
top on a bar; used with Bar3D.
Fill pattern Constants that determine the pattern used
to fill an area; used with GetFillsettings and
setFillstyle.
Types
The Graph unit defines these types:
Table 17.4 J
Variables
The Graph unit has two variables you can use: GraphGetMemPtr
and GraphFreeMemPtr. They are used by heap-management
routines. Read about them in Chapter I, "Library reference," in
the Programmer's Reference.
18
Using overlays
Overlays are parts of a program that share a common memory
area. Only the parts of the program that are required for a given
function reside in memory at the same time; they can overwrite
each other during execution.
Overlays can significantly reduce a program's total run-time
memory requirements. In fact, with overlays you can execute pro-
grams that are much larger than the total available memory
because only parts of the program reside in memory at any given
time.
Turbo Pascal manages overlays at the unit level; this is the
smallest part of a program that can be made into an overlay.
When an overlaid program is compiled, Turbo Pascal generates
an overlay file (extension .OVR) in addition to the executable file
(extension .EXE). The .EXE file contains the static (nonoverlaid)
parts of the program, and the .OVR file contains all the overlaid
units that will be swapped in and out of memory during program
execution.
Except for a few programming rules, an overlaid unit is identical
to a nonoverlaid unit. In fact, as long as you observe these rules,
you don't even need to recompile a unit to make it into an over-
lay. The decision of whether or not a to overlay a unit is made by
the program that uses the unit.
When an overlay is loaded into memory, it's placed in the overlay
buffer, which resides in memory between the stack segment and
the heap. By default, the size of the overlay buffer is as small as
Overlay buffer
management The Turbo Pascal overlay buffer is best described as a ring buffer
that has a head pointer and a tail pointer. Overlays are always
loaded at the head of the buffer, pushing" older" ones toward the
tail. When the buffer becomes full (that is, when there isn't
enough free space between the head and the tail), overlays are
disposed of at the tail to make room for new ones.
Because ordinary memory isn't circular in nature, the actual
implementation of the overlay buffer involves a few more steps to
make the buffer appear to be a ring. Figure 18.1 illustrates the
process. The figure shows a progression of overlays being loaded
into an initially empty overlay buffer. Overlay A is loaded first,
followed by B, then C, and finally D. Shaded areas indicate free
buffer space.
Head
Overlay B
Head
Overlay A Overlay A
Tail Tail
Step 3 Step 4
......
Head
Overlay C
Overlay C
Overlay B
Overlay B
Tail
Head
Overlay A Overlay D
Tail
Result codes
Errors in the Overlay unit are reported through the OvrResult
variable. Look up "ovrXXXX constants" in Chapter 1, "Library
reference," in the Programmer's Reference to find OvrResult values.
Overlay code
generation Turbo Pascal allows a unit to be overlaid only if it was compiled
with {$O+}. In this state, the code generator takes special precau-
tions when passing string and set constant parameters from one
.overlaid procedure or function to another. For example, if UnitA
contains a procedure with the following header:
procedure WriteStr(S: string);
and if UnitB contains the statement
writeStr(IHello world ... ');
then Turbo Pascal places the string constant 'Hello world ... ' in
UnitB's code segment, and passes a pointer to it to the WriteStr
procedure. If both units are overlaid, this doesn't work because, at
the call to WriteStr, UnitB's code segment can be overwritten by
UnitA's and the string pointer becomes invalid. The {$O+} dir-
ective is used to avoid such problems; whenever Turbo Pascal
detects a call from one unit compiled with {$O+} to another unit
compiled with {$O+}, the compiler copies all code-segment-based
constants into stack temporaries before passing pointers to them.
The use of {$O+} in a unit doesn't force you to overlay that unit. It
just instructs Turbo Pascal to ensure that the unit can be overlaid,
if so desired. If you develop units that you plan to use in overlaid
as well as nonoverlaid applications, compiling them with {$O+}
ensures that you can do both with just one version of the unit.
Initializing the
overlay manager Here we'll take a look at some examples of how to initialize the
overlay manager. Place the initialization code before the first call
to an overlaid routine. Typically you would do this at the
beginning of the program's statement part.
The following code shows just how little you need to initialize the
overlay manager:
begin
Ovrlnit('EDITOR.OVR') ;
end;
No error checks are made. If there isn't enough memory for the
overlay buffer or if the overlay file was not found, run-time error
208 ("Overlay manager not installed") occurs when you attempt
to call an overlaid routine.
Here's another simple example that expands on the previous one:
begin
Ovrlnit('EDITOR.OVR') ;
OvrlnitEMS;
end;
In this case, provided there is enough memory for the overlay
buffer and that the overlay file can be located, the overlay
manager checks to see if EMS memory is available. If it is, it loads
the overlay file into EMS.
Initialization
sections Like static units, overlaid units can have an initialization section.
Although overlaid initialization code is no different from normal
overlaid code, the overlay manager must be initialized first so it
can load and execute overlaid units.
Referring to the earlier Editor program, assume that the EdInOut
and EdMain units have initialization code. This requires that
OvrInit is called before EdInOut's initialization code. The only way
to do that is to create an additional nonoverlaid unit that goes
before EdInOut and calls OvrInit in its initialization section:
unit Edlnit;
interface
implementation
uses Overlay;
const
OvrMaxSize = 80000;
begin
Ovrlnit('EDITOR.OVR') ;
OvrlnitEMS;
OvrSetBuf(OvrMaxSize) ;
end.
The EdInit unit must be listed in the program's uses clause before
any of the overlaid units:
program Editor;
{$F+}
uses Overlay, Crt, Dos, Edlnit, EdlnOut, EdFormat, EdPrint, EdFind,
EdMain;
{SO EdlnOut}
{SO EdFormat}
{SO EdPrint}
{SO EdFind}
{SO EdMain}
In general, although initialization code in overlaid units is indeed
possible, you should avoid it for a number of reasons.
First, the initialization code, even though it's executed only once,
is a part of the overlay, and occupies overlay-buffer space when-
ever the overlay is loaded. Second, if a number of overlaid units
What not to
overlay Certain units can't be overlaid. In particular, don't try to overlay
the following:
• Units compiled in the {$O-} state. The compiler reports an error
if you attempt to overlay a unit that wasn't compiled with
{$O+}. Such nonoverlay units include System, Overlay, Crt,
Graph, Turbo3, and Graph3.
• Units that contain interrupt handlers. Due to the non-reentrant
nature of the DOS operating system, units that implement
interrupt procedures should not be overlaid. An example of
such a unit is the Crt standard unit, which implements a
Ctrl+Break interrupt handler.
• BGI drivers or fonts registered with calls to RegisterBGldriver or
RegisterBGIfont.
Calling overlaid routines via procedure pointers is fully sup-
ported by Turbo Pascal's overlay manager. Examples of the use of
procedure pointers include exit procedures and text-file device
drivers.
The overlay manager also supports passing overlaid procedures
and functions as procedural parameters and assigning overlaid
procedures and functions to procedural type variables.
Debugging
overlays Most debuggers have very limited overlay debugging capabilities,
if any at all. This isn't so with Turbo Pascal and Turbo Debugger.
The integrated debugger fully supports single-stepping and
breakpoints in overlays in a manner completely transparent to
you. By using overlays, you can easily engineer and debug huge
applications-all from inside the IDE or by using Turbo
Debugger.
end.
207
208 Language Guide
c H A p T E R
19
Memory issues
This chapter describes in detail the ways Turbo Pascal programs
use memory. We'll look at the memory map of a Turbo Pascal
application, internal data formats, the heap manager, and direct
memory access.
Free memory
1
SSeg:SPtr- --------------------------- - -------
Free stack
SSeg:OOOO-I--------------I
Global variables
- -- - - - - -- - -- - - - -- - - - - - -- - -- - -- - --- - I + - - -
Typed constants
DSeg:OOOO _ i - - - - - - - - - - - - - - i
System unit code segment
1---
__---'-_-
Executing Release(HeapOrg) The Mark(P) statement marks the state of the heap just before Ptr3
completely disposes of the is allocated (by storing the current HeapPtr in P). If the statement
entire heap because
HeapOrg points to the Release(P) is executed, the heap layout becomes like that of
bottom of the heap. Figure 19.3, effectively disposing of all pointers allocated since the
call to Mark.
HeapPtr~-------------l
Contents of Ptr2"
Ptr2-.--------------i
Contents of Ptr1" Low
Ptr1 - - - - - - - - - - - - - - - - ' memory
Contents of Ptr2"
Ptr2
Contents of Ptr1" Low
Ptr1 memory
Figure 19.5
Enlarging the free block HeapEnd - - . - - - - - - - - - - - - - - - , High
memory
HeapPtr--t----------------i
Contents of Ptr5"
Ptr5 --t----~-------____i
Contents of Ptr2"
Ptr2 -+/------------____i
Contents of Ptr1" Low
Ptr1 - - - - - - - - - - - - - - - - ' memory
HeapPtr-t----------------i
Contents of Ptr2"
Ptr2 - t - - - - - - - - - - - - - - - - i
Contents of Ptr1" Low
Ptr1 - " " - - - - - - - - - - - - - - - - ' memory
Integer types
The format selected to represent an integer-type variable depends
on its minimum and maximum bounds:
• If both bounds are within the range -128 ..127 (Shortint), the
variable is stored as a signed byte.
• If both bounds are within the range 0.. 255 (Byte), the variable is
stored as an unsigned byte.
• If both bounds are within the range -32768 ..32767 (Integer), the
variable is stored as a signed word.
• If both bounds are within the range 0.. 65535 (Word), the variable
is stored as an unsigned word.
• Otherwise, the variable is stored as a signed double word
(Longint).
Char types
A Char, or a subrange of a Char type, is stored as an unsigned
byte.
Boolean types
A Boolean type is stored as a Byte, a ByteBool type is stored as a
Byte, a WordBool type is stored as a Word, and a LongBool type is
stored as a Longint.
A Boolean type can assume the values 0 (False) and 1 (True).
ByteBool, WordBool, and LongBool types can assume the value of 0
(False) or nonzero (True).
Floating-point
types The floating-point types (Real, Single, Double, Extended, and Camp)
store the binary representations of a sign (+ or -), an exponent, and
a significand. A represented number has the value
+/- significand x 2exponent
where the significand has a single bit to the left of the binary
decimal point (that is, 0 <= significand < 2).
In the figures that follow, msb means most significant bit, and lsb
means least significant bit. The leftmost items are stored at the
highest addresses. For example, for a real-type value, e is stored in
the first byte,fin the following five bytes, and s in the most
significant bit of the last byte.
The Real type A 6-byte (48-bit) Real number is divided into three fields:
width in bits
1 39 8
e
msb Isbmsb Isb
The value v of the number is determined by the following:
if 0 < e <= 255, then v = (-1)8 * 2(e-129) * (lof).
if e = 0, then v = o.
The Real type can't store denormals, NaNs, or infinities.
Denormals become zero when stored in a Real, and NaNs and
infinities produce an overflow error if an attempt is made to store
them in a Real.
The Double type An 8-byte (64-bit) Double number is divided into three fields:
width in bits
1 11 52
The Extended type A la-byte (80-bit) Extended number is divided into four fields:
width in bits
1 15 63
e
Pointer types
A Pointer type is stored as two words (a double word), with the
offset part in the low word and the segment part in the high
word. The pointer value nil is stored as a double-word zero.
String types
A string occupies as many bytes as its maximum length plus one.
The first byte contains the current dynamic length of the string,
and the following bytes contain the characters of the string. The
length byte and the characters are considered unsigned values.
Maximum string length is 255 characters plus a length byte
(stri ng [255]).
Set types
A set is a bit array, where each bit indicates whether an element is
in the set or not. The maximum number of elements in a set is 256,
so a set never occupies more than 32 bytes. The number of bytes
occupied by a particular set is calculated as
ByteSize = (Max div 8) - (Min div 8) +1
where Min and Max are the lower and upper bounds of the base
type of that set. The byte number of a specific element E is
ByteNumber = (E div 8) - (Min div 8)
and the bit number within that byte is
BitNumber = E mod 8
where E denotes the ordinal value of the element.
Record types
The fields of a record are stored as a contiguous sequence of
variables. The first field is stored at the lowest memory address. If
the record contains variant parts, then each variant starts at the
same memory address.
Object types
The internal data format of an object resembles that of a record.
The fields of an object are stored in order of declaration, as a
contiguous sequence of variables. Any fields inherited from an
ancestor type are stored before the new fields defined in the
descendant type.
If an object type defines virtual methods, constructors, or destruc-
tors, the compiler allocates an extra field in the object type. This
16-bit field, called the virtual method table (VMT) field, is used to
store the offset of the object type's VMT in the data segment. The
VMT field immediately follows after the ordinary fields in the
object type. When an object type inherits virtual methods, con-
structors, or destructors, it also inherits a VMT field, so an addi-
tional one isn't allocated.
Initialization of the VMT field of an instance is handled by the
object type's constructor(s). A program never explicitly initializes
or accesses the VMT field.
The following examples illustrate the internal data formats of
object types:
Virtual method tables Each object type that contains or inherits virtual methods, con-
structors, or destructors has a VMT associated with it, which is
stored in the initialized part of the program's data segment. There
is only one VMT per object type (not one per instance), but two
distinct object types never share a VMT, no matter how identical
they appear to be. VMTs are built automatically by the compiler,
and are never directly manipulated by a program. Likewise,
pointers to VMTs are automatically stored in object type instances
-8 -10
0 0
0 0
@TPoint.Done @TPoint.Done
@TPoint.Show @TCircle.Show
@TPoint.Hide @TCircle.Hide
@TPoint.MoveTo @TPoint.MoveTo
@TCircle.Fili
Notice how TCircle inherits the Done and MoveTo methods from
TPoint, and how it overrides the Show and Hide methods.
As mentioned already, an object type's constructors contain
special code that stores the offset of the object type's VMT in the
instance being initialized. For example, given an instance P of
type Pointer, and an instance C of type TCircle, a call to P.Init
automatically stores the offset of TPoint's VMT in P's VMT field,
and a call to C.lnit likewise stores the offset of TCircle's VMT in C's
VMT field. This automatic initialization is part of a constructor's
entry code, so when control arrives at the begin of the construc-
tor's statement part, the VMT field Self is already set up.
Therefore, if the need arises, a constructor can make calls to
virtual methods.
Dynamic method The VMT for an object type contains a four-byte entry (a method
tables pointer) for each virtual method declared in the object type and
any of its ancestors. In cases where ancestral type(s) define a large
number of virtual methods, the process of creating derived types
can use up quite a lot of memory, especially if many derived types
-4 Cached index
o 4
10
@TBase.Done
20
30
40
@TBase.P10
@TBase.P20
@TBase.P30
@TBase.P40
o 3
10
@TDerived.Done
30
50
@TDerived.P10
@TDerived.P30
@TDerived.P50
The first word of a DMT contains the data segment offset of the
parent DMT, or zero if there is no parent DMT.
The second and third words of a DMT are used to cache dynamic
method lookups, as is described on page 239.
The fourth word of a DMT contains the DMT entry count. It's
immediately followed by a list of words, each of which contain a
dynamic method index, and then followed by a list of correspond-
ing method pointers. The length of each list is given by the DMT
entry count.
File types
File types are represented as records. Typed files and untyped
files occupy 128 bytes, which are laid out in the Dos unit as
follows:
const
fmClosed = $D7BO;
fmlnput = $D7B1;
fmOutput = $D7B2;
fmlnOut = $D7B3;
fmClosed indicates that the file is closed. fmlnput and fmOutput
indicate that the file is a text file that has been reset (jmlnput) or
rewritten (jmOutput). fmlnOut indicates that the file variable is a
typed or an untyped file that has been reset or rewritten. Any
other value indicates that the file variable hasn't been assigned
(and thereby not initialized).
Procedural types
A procedural type is stored as a double word, with the offset part
of the referenced procedure in the low word and the segment part
in the high word.
20
Control issues
This chapter describes in detail the various ways that Turbo
Pascal implements program control. Included are calling con-
ventions and exit procedures.
Calling conventions
Parameters are transferred to procedures and functions via the
stack. Before calling a procedure or function, the parameters are
pushed onto the stack in their order of declaration. Before return-
ing, the procedure or function removes all parameters from the
stack. '
The skeleton code for a procedure or function call looks like this:
PUSH Paraml
PUSH Param2
PUSH PararnX
CALL ProcOrFunc
Parameters are passed either by reference orby value. When a
parameter is passed by reference, a pointer that points to the
actual storage location is pushed onto the stack. When a param-
eter is passed by value, the actual value is pushed onto the stack.
Value parameters
Value parameters are passed by value or by reference depending
on the type and size of the parameter. In general, if the value
parameter occupies 1, 2, or 4 bytes, the value is pushed directly
onto the stack. Otherwise a pointer to the value is pushed, and the
procedure or function then copies the value into a local storage
location.
The 8086 doesn't support byte-sized PUSH and POP instructions,
so byte-sized parameters are always transferred onto the stack as
words. The low-order byte of the word contains the value, and
the high-order byte is unused (and undefined).
An integer type or parameter is passed as a byte, a word, or a
double word, using the same format as an integer-type variable.
(For double words, the high-order word is pushed before the
low-order word so that the low-order word ends up at the lowest
address.)
A Char parameter is passed as an unsigned byte.
A Boolean parameter is passed as a byte with the value 0
or 1.
An enumerated-type parameter is passed as an unsigned byte if
the enumeration has 256 or fewer values; otherwise, it's passed as
an unsigned word.
A floating-point type parameter (Real, Single, Double, Extended,
and Comp) is passed as 4,6,8, or 10 bytes on the stack. This is an
exception to the rule that only 1-, 2-, and 4-byte values are passed
directly on the stack.
A pointer-type parameter is passed as two words (a double
word). The segment part is pushed before the offset part so that
the offset part ends up at the lowest address.
A string-type parameter is passed as a pointer to the value.
For a set type parameter, if the bounds of the element type of the
set are both within the range 0 to 7, the set is passed as a byte. If
Open parameters
Open string parameters are passed by first pushing a pointer to
the string and then pushing a word containing the size attribute
(maximum length) of the string.
Open array parameters are passed by first pushing a pointer to
the array and then pushing a word containing the number of
elements in the array less one.
When using the built-in assembler, the value that the High
standard function returns for an open parameter can be accessed
by loading the word just below the open parameter. In this
example, the FillString procedure, which fills a string to its
maximum length with a given character, demonstrates this.
procedure FillString(var Str: OpenString; Chr: Char); assembler;
asm
LES DI,Str { ES:DI = @Str }
MOV CX,Str.Word[-2) (CX = High(Str)
MOV AL,CL
CLD
STOSB ( Set Str[O) }
MOV AL,Chr
REP STOSB ( Set Str[l .. High)
end;
Function results
Ordinal-type function results are returned in the CPU registers:
Bytes are returned in AL, words are returned in AX, and double
words are returned in DX:AX (high-order word in DX, low-order
word in AX).
Real-type function results (type Real) are returned in the
DX:BX:AX registers (high-order word in DX, middle word in BX,
low-order word in AX).
Nested
procedures and A procedure or function is said to be nested when it's declared
functions within another procedure or function. By default, nested proce-
dures and functions always use the near call model, because they
are visible only within a specific procedure or function in the
same code segment. In an overlaid application, however, a {$F+}
Method calling
conventions Methods use the same calling conventions as ordinary procedures
and functions, except that every method has an additional
implicit parameter, Self, that corresponds to a var parameter of the
same type as the method's object type. The Self parameter is
always passed as the last parameter, and always takes the form of
a 32-bit pointer to the instance through which the method is
Virtual method
calls To call a virtual method, the compiler generates code that picks
up the VMT address from the VMT field in the object, and then
calls via the slot associated with the method. For example, given a
variable PP of type Point (see page 223), the call PP/\.Show
generates the following code:
LES DI,PP iLoad PP into ES:DI
PUSH ES iPass as Self parameter
PUSH DI
MOV DI,ES: [DI+6] iPick up VMT offset from VMT field
CALL DWORD PTR [DI+12] iCall VMT entry for Show
The type compatibility rules of object types allow PP to point at a
Point or a TCircle, or at any other descendant of TPoint. And if you
examine the VMTs shown on page 225, you'll see that for a TPoint,
the entry at offset 12 in the VMT points to TPoint.Show; whereas
for a TCircle, it points to TCircle.Show. Therefore, depending upon
the actual run-time type of PP, the CALL instruction calls
TPoint.Show or TCircle.Show, or the Show method of any other de-
scendant of TPoint.
If Show had been a static method, the compiler would have
generated this for the call to PP/\.Show:
Dynamic method
calls Dispatching a dynamic method call is somewhat more compli-
cated and time consuming than dispatching a virtual method call.
Instead of using a CALL instruction to call through a method
pointer at a static offset in the VMT, the object type's DMT and
parent DMTs must be scanned to find the topmost occurrence of a
particular dynamic method index, and then a call must be made
through the corresponding method pointer. This process involves
far more instructions than can be coded in-line, so the Turbo
Pascal run-time library (RTL) contains a dispatch-support routine
that is used when making dynamic method calls.
Had the Show method of the preceding type TPoint been declared
as a dynamic method (with a dynamic method index of 200), the
call PPA.Show, where PP is of type Point, would generate the
following code:
LES Ol,PP iLoad PP into ES:Dl
PUSH ES iPass as Self parameter
PUSH Ol
MOV Ol,EX: [0l+6] iPick up VMT offset from VMT field
MOV AX,200 iLoad dynamic method index into AX
CALL Dispatch iCall RTL routine to dispatch call
The RTL dispatcher first picks up the DMT offset from the VMT
pointed to by the DI register. Then, using the" cached index" field
of the DMT, the dispatcher checks if the dynamic method index of
the method being called is the same as the last one that was
called. If so, it immediately transfers control to the method, by
jumping indirectly through the method pointer stored at the
offset given by the" cached entry offset" field.
If the dynamic index of the method being called isn't the same as
the one stored in the cache, the dispatcher scans the DMT and the
parent DMTs (by following the parent links in the DMTs) until it
locates an entry with the given dynamic method index. The index
and the offset of the corresponding method pointer is then stored
in the DMT's cache fields, and control is transferred to the
Constructors and
destructors Constructors and destructors use the same calling conventions as
other methods, except that an additional word-sized parameter,
called the VMT parameter, is passed on the stack just before the
Self parameter.
For constructors, the VMT parameter contains the VMT offset to
store in Selfs VMT field to initialize Self.
When a constructor is called to allocate a dynamic object using the
extended syntax of the New standard procedure, a nil pointer is
passed in the Self parameter. The constructor allocates a new
dynamic object, the address of which is passed back to the caller
in DX:AX when the constructor returns. If the constructor can't al-
See "Constructor error locate the object, a nil pointer is returned in DX:AX.
recovery" on page 706.
Finally, when a constructor is called using a qualified-method
identifier (that is, an object type identifier, followed by a period
and a method identifier), a value of zero is passed in the VMT
parameter. This indicates to the constructor that it should not
initialize the VMT field of Self.
For destructors, a 0 in the VMT parameter indicates a normal call,
and a nonzero value indicates that the destructor was called using
the extended syntax of the Dispose standard procedure. This
causes the destructor to deallocate Self just before returning (the
size of Selfis found by looking at the first word of Self's VMT).
Register-saving
conventions Procedures and functions should preserve the BP, SP, SS, and DS
registers. All other registers can be modified.
Exit procedures
By installing an exit procedure, you can gain control over a
program's termination process. This is useful when you want to
make sure specific actions are carried out before a program
terminates; a typical example is updating and closing files.
The ExitProe pointer variable allows you to install an exit
procedure. The exit procedure is always called as a part of a
program's termination, whether it's a normal termination, a
termination through a call to Halt, or a termination due to a run-
time error.
An exit procedure takes no parameters and must be compiled
with a far procedure directive to force it to use the far call model.
When implemented properly, an exit procedure actually becomes
part of a chain of exit procedures. This chain makes it possible for
units as well as programs to install exit procedures. Some units
install an exit procedure as part of their initialization code and
then rely on that specific procedure to be called to clean up after
the unit. Closing files is such as example. The procedures on the
end;
begin
ExitSave := ExitProc;
ExitProc := @MyExit;
end.
On entry, the program saves the contents of ExitProc in ExitSave,
and then installs the MyExit exit procedure. After having been
called as part of the termination process, the first thing MyExit
does is reinstall the previous exit procedure.
The termination routine in the run-time library keeps calling exit
procedures until ExitProc becomes nil. To avoid infinite loops,
ExitProc is set to nil before every call, so the next exit procedure is
called only if the current exit procequre assigns an address to
ExitProc. If an error occurs in an exit procedure, it won't be called
again.
An exit procedure can learn the cause of termination by
examining the ExitCode integer variable and the ErrorAddr pointer
variable.
In case of normal termination, ExitCode is zero and ErrorAddr is
nil. In case of termination through a call to Halt, ExitCode contains
the value passed to Halt, and ErrorAddr is nil. Finally, in case of
termination due to a run-time error, ExitCodecontains the error
code and ErrorAddr contains the address of the statement in error.
Interrupt handling
The Turbo Pascal run-time library and the code generated by the
compiler are fully interruptible. Also, most of the run-time library
is reentrant, which allows you to write interrupt service routines
in Turbo Pascal.
Writing interrupt
procedures Declare interrupt procedures with the interrupt directive. Every
interrupt procedure must specify the following procedure header
(or a subset of it, as explained later):
procedure IntHandler(Flags, es, IP, AX, BX, ex, DX, SI, DI, DS, ES,
BP: Word};
interrupt;
begin
end;
As you can see, all the registers are passed as pseudoparameters
so you can use and modify them in your code. You can omit some
or all of the parameters, starting with Flags and moving towards
BP. It's an error to declare more parameters than are listed in the
preceding example, or to omit a specific parameter without also
omitting the ones before it (although no error is reported). For
example,
procedure IntHandler(DI, ES, BP: Word}; Invalid header }
procedure IntHandler(SI, DI, DS, ES, BP: Word}; { Valid header }
21
Constant folding
If the operand(s) of an operator are constants, Turbo Pascal
evaluates the expression at compile time. For example,
X := 3 + 4 * 2
generates the same code as X . - 11, and
S := 'In' + 'Out'
generates the same code as S : = InOut
I I.
Short-circuit evaluation
Turbo Pascal implements short-circuit Boolean evaluation, which
means that evaluation of a Boolean expression stops as soon as
the result of the entire expression becomes evident. This guaran-
tees minimum execution time and usually ~inimum code size.
Short-circuit evaluation also makes possible the evaluation of
constructs that would not otherwise be legal. For example,
while (I <= Length{S)) and (S[I] <> ' ') do
Inc (I) i
while (P <> nil) and (pA.Value <> 5) do
p := pA.Nexti
In both cases, the second test isn't evaluated if the first test is
False.
The opposite of short-circuit evaluation is complete evaluation,
which is selected through a {$B+} compiler directive. In this state,
every operand of a Boolean expression is guaranteed to be
evaluated.
Constant parameters
Read more about constant Whenever possible, you should use constant parameters instead
parameters on page 709. of value parameters. Constant parameters are at least as efficient
as value parameters and, in many cases, more efficient. In
particular, constant parameters generate less code and execute
faster than value parameters for structured and string types.
Constant parameters are more efficient than value parameters
because the compiler doesn't have to generate copies of the actual
parameters upon entry to procedures or functions. Value
parameters have to be copied into local variables so that
modifications made to the formal parameters won't modify the
Small sets
The compiler generates very efficient code for operations on small
sets. A small set is a set with a lower bound ordinal value in the
range 0.. 7 and an upper bound ordinal value in the range 0 .. 15.
For example, the following TByteSet and TWordSet are both small
sets.
type
TByteSet = set of 0.. 7;
TWordSet = set of O.. 15;
Small set operations, such as union (+), difference (-), intersection
(*), and inclusion tests (in) are generated inline using AND, OR,
NOT, and TEST machine code instructions instead of calls to run-
time library routines. Likewise, the Include and Exclude standard
procedures generate inline code when applied to small sets.
Order of evaluation
As permitted by the Pascal standards, operands of an expression
are frequently evaluated differently from the left to right order in
which they are written. For example, the statement
I := F(J) div G(J);
where F and G are functions of type Integer, causes G to be eval-
uated before F, because this enables the compiler to produce
better code. For this reason, it's important that an expression
never depend on any specific order of evaluation of the embed-
ded functions. Referring to the previous example, if F must be
called before G, use a temporary variable:
Range checking
Assignment of a constant to a variable and use of a constant as a
value parameter is range-checked at compile time; no run-time
range-check code is generated. For example, X : = 999, where X is
of type Byte, causes a compile-time error.
Smart linking
When compiling to memory, Turbo Pascal's built-in linker automatically removes unused code
Turbo Pascal's smart linker is and data when building an .EXE file. Procedures, functions, vari- '
disabled. This explains why
some programs become ables, and typed constants that are part of the compilation, but are
smaller when compiled to never referenced, are removed from the .EXE file. The removal of
disk. unused code takes place on a per procedure basis; the removal of
unused data takes place on a per declaration section basis.
Consider the following program:
program SmartLink;
const
H: array[O .. 15] of Char = '0123456789ABCDEF';
var
I, J: Integer;
X, Y: Real;
var
S: string[79];
var
A: array[l .. 10000] of Integer;
procedure P1 i
begin
A[l] := 1;
end;
procedure P2;
begin
I : = 1;
end;
begin
P3;
end.
The main program calls P3, which calls P2, so both P2 and P3 are
included in the .EXE file. Because P2 references the first var
declaration section, and P3 references the second var declaration,
I, /, X, Y, and S are also included in the .EXE file. No references
are made to Pl, however, and none of the included procedures
reference H and A, so these objects are removed.
Smart linking is especially valuable in connection with units that
implement procedure/ function libraries. An example of such a
unit is the Dos standard unit: It contains a number of procedures
and functions, all of which are seldom used by the same program.
If a program uses only one or two procedures from Dos, then only
these procedures are included in the final.EXE file, and the re-
maining ones are removed, greatly reducing the size of the .EXE
file.
253
254 Language Guide
c H A p T E R
22
Register use
In general, the rules of register use in an asm statement are the
same as those of an external procedure or function. An asm state-
ment must preserve the BP, SP, SS, and DS registers, but can
freely modify the AX, BX, CX, DX, SI, DI, ES, and Flags registers.
On entry to an asm statement, BP points to the current stack
frame, SP points to the top of the stack, SS contains the segment
address of the stack segment, and DS contains the segment
address of the data segment. Except for BP, SP, SS, and DS, an
8sm statement can assume nothing about register contents on
entry to the statement.
Labels
Only the first 32 characters of Labels are defined in assembler as they are in Pascal-by writing
an identifier are significant in a label identifier and a colon before a statement. And as they are
the built-in assembler.
in Pascal, labels defined in assembler must be declared in a label
declaration part in the block containing the asm statement. There
is one exception to this rule: local labels.
Local labels are labels that start with an at-sign (@). Because an
at-sign can't be part of a Pascal identifier, such local labels are
automatically restricted to use within asm statements. A local
label is known only within the asm statement that defines it (that
is, the scope of a local label extends from the asm keyword to the
end keyword of the asm statement that contains it).
Unlike a normal label, a local label doesn't have to be declared in
a label declaration part before it's used.
The exact composition of a local label identifier is an at-sign (@)
followed by one or more letters (A ..Z), digits (0 ..9), underscores
(_), or at-signs. As with all labels, the identifier is followed by a
colon (:).
Instruction
opcodes The built-in assembler supports all 8086/8087 and 80286/80287
instruction opcodes. 8087 opcodes are available only in the {$N+}
state (numeric processor enabled), 80286 opcodes are available
only in the {$G+} state (80286 code generation enabled), and 80287
opcodes are available only in the {$G+,N+} state.
For a complete description of each instruction, refer to your 80x86
and 80x87 reference manuals.
Automatic jump sizing Unless otherwise directed, the built-in assembler optimizes jump
instructions by automatically selecting the shortest, and therefore
most efficient form of a jump instruction. This automatic jump
sizing applies to the unconditional jump instruction OMP), and all
conditional jump instructions, when the target is a label (not a
procedure or function).
For an unconditional jump instruction OMP), the built-in
assembler generates a short jump (one byte opcode followed by a
one byte displacement) if the distance to the target label is within
-128 to 127 bytes; otherwise a near jump (one byte opcode
followed by a two byte displacement) is generated.
For a conditional jump instruction, a short jump (1 byte opcode
followed by a 1 byte displacement) is generated if the distance to
the target label is within -128 to 127 bytes; otherwise, the built-in
assembler generates a short jump with the inverse condition,
which jumps over a near jump to the target label (5 bytes in total).
For example, the assembler statement
JC Stop
where Stop isn't within reach of a short jump is converted to a
machine code sequence tha,t corresponds to this:
Assembler
directives Turbo Pascal's built-in assembler supports three assembler
directives: DB (define byte), DW (define word), and DD (define
double word). They each generate data corresponding to the
comma-separated operands that follow the directive.
The DB directive generates a sequence of bytes. Each operand can
be a constant expression with a value between -128 and 255, or a
character string of any length. Constant expressions generate one
byte of code, and strings generate a sequence of bytes with values
corresponding to the ASCII code of each character.
The DW directive generates a sequence of words. Each operand
can be a constant expression with a value between -32,768 and
65,535, or an address expression. For an address expression, the
built-in assembler generates a near pointer, that is, a word that
contains the offset part of the address.
The DD directive generates a sequence of double words. Each
operand can be a constant expression with a value between
-2,147,483,648 and 4,294,967,295, or an address expression. For an
address expression, the built-in assembler generates a far pointer,
that is, a word that contains the offset part of the address,
followed by a word that contains the segment part of the address.
The data generated by the DB, DW, and DD directives is always
stored in the code segment, just like the code generated by other
built-in assembler statements. To generate uninitialized or initial-
ized data in the data segment, you should use Pascal var or canst
declarations.
MOV AL,ByteVar
MOV BX,WordVar
The built-in assembler doesn't support such variable declarations.
In Turbo Pascal, the only kind of symbol that can be defined in an
built-in assembler statement is a label. All variables must be de-
clared using Pascal syntax, and the preceding construct corre-
sponds to this:
var
ByteVar: Byte;
WordVar: Word;
asm
MOV AL,ByteVar
MOV BX,WordVar
end;
Table 22.1
Built-in assembler reseNed AH CS LOW SI
words AL CX MOD SP
AND DH NEAR SS
AX DI NOT ST
BH DL OFFSET TBYTE
BL DS OR TYPE
BP DWORD PTR WORD
BX DX QWORD XOR
BYTE ES SEG
CH FAR SHL
CL HIGH SHR
asm
MOV CH, 1
end;
loads 1 into the CH register, not into the CH variable. To access a
user-defined symbol with the same name as a reserved word, you
must use the ampersand (&) identifier override operator:
asm
MOV &ch, 1
end;
It's strongly suggested that you avoid user-defined identifiers
with the same names as built-in assembler reserved words,
because such name confusion can easily lead to obscure and
hard -to-find bugs. .
Differences
between Pascal The most important difference between Pascal expressions and
built-in assembler expressions is that all built-in assembler expres-
and Assembler sions must resolve to a constant value, a value that can be
expressions computed at compile time. For example, given these declarations:
const
X = 10;
Y = 20;
var
Z: Integer;
the following is a valid built-in assembler statement:
asm
MOV Z,X+Y
end;
Because both X and Yare constants, the expression X + Y is
merely a more convenient way of writing the constant 30, and the
resulting instruction becomes a move immediate of the value 30
into the word-sized variable Z. But if you change X and Y to be
variables,
var
x, Y: Integer;
the built-in assembler can no longer compute the value of X + Yat
compile time. The correct built-in assembler construct to move the
sum of X and Y into Z is this:
asm
MOV l\t.,X
ADD l\t.,Y
MOV Z,l\t.
end;
Expression
elements The basic elements of an expression are constants, registers, and
symbols.
Numeric constants
Numeric constants must be integers, and their values must be
between -2,147,483,648 and 4,294,967,295.
By default, numeric constants use decimal (base 10) notation, but
the built-in assembler supports binary (base 2), octal (base 8), and
hexadecimal (base 16) notations as well. Binary notation is se-
lected by writing a B after the number, octal notation is selected
by writing a letter 0 after the number, and hexadecimal notation
is selected by writing an H after the number or a $ before the
number.
String constants
String constants must be enclosed in single or double quotes. Two
consecutive quotes of the same type as the enclosing quotes count
as only one character. Here are some examples of string constants:
'Z'
'Turbo Pascal'
"That's all folks"
'"That"s all folks," he said.'
'100'
Symbols The built-in assembler allows you to access almost all Pascal
symbols in assembler expressions, including labels, constants,
types, variables, procedures, and functions. In addition, the built-
in assembler implements the following special symbols:
asm
MOV AX, Start { MOV AX,xxxx }
MOV BX,Count { MOV BX, [xxxx]
MOV CX, [Start] { MOV CX, [xxxx]
MOV DX,OFFSET Count { MOV DX,xxxx }
end;
Because Start is an immediate value, the first MOV is assembled
into a move immediate instruction. The second MOV, however, is
translated into a move memory instruction, as Count is a memory
reference. In the third MOV, the square brackets operator is used
to convert Start into a memory reference (in this case, the word at
offset 10 in the data segment), and in the fourth MOV, the
OFFSET operator is used to convert Count into an immediate
value (the offset of Count in the data segment).
As you can see, the square brackets and the OFFSET operators
complement each other. In terms of the resulting machine code,
the following asm statement is identical to the first two lines of
the previous asm statement:
Expression types
Every built-in assembler expression has an associated type-or
more correctly, an associated size, because the built-in assembler
regards the type of an expression simply as the size of its memory
location. For example, the type (size) of an Integer variable is two,
because it occupies 2 bytes.
The built-in assembler performs type checking whenever possible,
so in the instructions
var
QuitFlag: Boolean;
OutBufPtr: Word;
asm
MOV AL,QuitFlag
MOV BX,OutBufPtr
end;
the built-in assembler checks that the size of QuitFlag is one (a
byte), and that the size of OutBufPtr is two (a word). An error
results if the type check fails. For example, this isn't allowed:
Expression
operators The built-in assembler provides a variety of operators, divided
into 12 classes of precedence. Table 22.6 lists the built-in
assembler's expression operators in decreasing order of
precedence.
Table 22.6
Summary of built-in Operator(s) Comments
asssembler expression & Identifier override operator
operators
0, [], • Structure member selector
Built-in assembler operator HIGH, LOW
precedence is different from
Pascal. For example, in a +,- Unary operators
built-in assembler expression, Segment override operator
the AND operator has lower
precedence than the plus OFFSE~SEG,TYPE,PTR,
(+) and minus (-) operators, *, I, MOD, SHL, SHR
whereas in a Pascal
+,- Binary addition/ subtraction
expression, it has higher
operators
precedence.
NOT, AND, OR, XOR Bitwise operators
Operator Description
& Identifier override. The identifier immediately following the ampersand is treated as a
user-defined symbol, even if the spelling is the same as a built-in assembler reserved
symbol.
( ... ) Subexpression. Expressions within parentheses are evaluated completely prior to being
treated as a single expression element. Another expression can optionally precede the
expression within the parentheses; the result in this case becomes the sum of the values of
the two expressions, with the type of the first expression.
[ ... ] Memory reference. The expression within brackets is evaluated completely prior to being
treated as a single expression element. The expression within brackets can be combined
with the BX, BP, sr, or Dr registers using the plus (+) operator, to indicate CPU register
indexing. Another expression can optionally precede the expression within the brackets; the.
result in this case becomes the sum of the values of the two expressions, with the type of the
first expression. The result is always a memory reference.
Structure member selector. The result is the sum of the expression before the period and
the expression after the period, with the type of the expression after the period. Symbols
belonging to the scope identified by the expression before the period can be accessed in the
expression after the period.
HIGH Returns the high-order 8 bits of the word-sized expression following the operator. The
expression must be an absolute immediate value.
LOW Returns the low-order 8 bits of the word-sized expression following the operator. The
expression must be an absolute immediate value.
+ Unary plus. Returns the expression following the plus with no changes. The expression
must be an absolute immediate value.
Unary minus. Returns the negated value of the expression following the minus. The
expression must be an absolute immediate value.
Segment override. Instructs the assembler that the expression after the colon belongs to the
segment given by the segment register name (CS, DS, SS, or ES) before the colon. The result
is a memory reference with the value of the expression after the colon. When a segment
override is used in an instruction operand, the instruction will be prefixed by an
appropriate segment override prefix instruction to ensure that the indicated segment is
selected.
OFFSET Returns the offset part (low-order word) of the expression following the operator. The result
is an immediate value.
SEG Returns the segment part (high-order word) of the expression following the operator. The
result is an immediate value.
TYPE Returns the type (size in bytes) of the expression following the operator. The type of an
immediate value is O. '
PTR Typecast operator. The result is a memory reference with the value of the expression
following the operator and the type of the expression in front of the operator.
* Multiplication. Both expressions must be absolute immediate values, and the result is an
absolute immediate value.
23
RET
The Pascal function definition would look like this:
function MyProc(I, J: Char): stringi externali
For more information about interfacing Turbo Assembler with
Turbo ,Pascal, refer to the Turbo Assembler User's Guide.
Inline statements
An inline statement consists of the reserved word inline followed
by one or more inline elements, separated by slashes and enclosed
in parentheses:
inline(lO/$2345/Count + l/Data - Offset);
Here's the syntax of an inline statement:
inline statement ~I in line element
1----~01+-, -------'
TeD--
Each inline element consists of an optional size specifier, < or >,
and a constant or a variable identifier, followed by zero or more
offset specifiers (see the syntax that follows). An offset specifier
consists of a + or a - followed by a constant.
inline element
Inline directives
With inline directives, you can write procedures and functions
that expand into a given sequence of machine code instructions
whenever they are called. These are comparable to macros in
Index 287
assignment Borland Graphics Interface 175-189
compatibility 40, 48 BP register 203, 241, 243
object type 82 brackets, in expressions 76, 77
statement syntax 82 Break procedure 87, 130
automatic BufEnd variable 230
call model selection, overriding 236 buffer
jump sizing, built-in assembler 258 overlay 193
word alignment 249 loading and freeing up 194
AX register 235, 286 optimization algorithm 194
probationary area 195
B text, size 230
BufPtr pointer 230
$B compiler directive 71, 246
BufSize variable 230
bar constants 188
built-in assembler
Bar3D procedure 175, 185
directives 255
Bar procedure 185
expressions 262-274
base type 43
classes 269-270
.BGlfiles 175
operators 272-274
binary
Pascal expressions versus 262
arithmetic operators 68
types 270-272
operands 65
instruction sizing 258-259
operators 25
opcodes 257-259
BIOS 142
operands 261
bit images 179
procedures and functions 274
BitBlt
registers, using 256
operations 180
reserved words 261
operators 188
BX register 235, 243
bitmapped fonts 178
Byte data type 25
bitwise operators 69
ByteBool data type 25, 218
blanks, defined 15
block
defined 93 C
scope 95 call model 279
subroutine 98 calling conventions 233
syntax 93 constructors and destructors 240
BlockRead procedure 135 methods 238
BlockWrite procedure 135 calls, near and far 236
Boolean case
data type 25, 218 sensitivity of Turbo Pascal 16
expression evaluation 246 statement syntax 85
complete 70 CGA 175
short-circuit 70 Char data type 26, 218
operators 70 character
boolean arrays 171
data types 25 pair special symbols 16
operators 26 pointer operators 71
types 218 pointers
variables 26 characters arrays and 171
Index 289
WinDos unit 165 declaration part, defined 11
constructor syntax 104 declaring
constructors 37, 38, 222, 225 an object type 36
calling conventions 240 methods 37
declaring 103 Delay procedure 144
defined 104 Delete procedure 131
error recovery 106 DelLine procedure 144
virtual methods and 104 descendants 34
Continue procedure 87, 130 of an object type 34
control designators
characters field 56
defined 15 method 56
embedding in strings 19 destructor syntax 105
in Crt unit 143 destructors 104
string syntax diagram 20 calling conventions 240
control characters 19 declaring 103
Copy function 131 defined 104
Cos function 130 DetectGraph procedure 185
CreateDir procedure 165 devices 140-141
creating objects 38 communication (COMl and COM2) 141
Crt console (CON) 140
mode constants 145 DOS 140
unit 128, 142 drivers 146
control characters in 143 handlers 243, 244
editing keys in 143 line printer (LPT1, LPT2, LPT3) 141
variables in 145 NUL 141
CS register 243 text file 141
CSeg function 132 DI register 243
CSEG segment 280 diagrams, syntax 14
current pointer 178 digit syntax diagram 15
CX register 243 digits, defined 15
direct
D memory access 230
port access 231
data directives
alignment 249
assembler, defined 259
internal formats 218-230 built-in assembler 255, 274, 275
ports 231
external 100
segment 279, 280
far 98
maximum size of 52 forward 99
data formats 218-230
inline 101
date and time procedures
interrupt 99
Dos unit 160 list of Turbo Pascal 17
WinDos unit 163
near 98
DateTime type 163 private 17
dead code eliminated 250
public 17
debugging overlays 202
standard 17
Dec procedure 131
Index 291
expressions 9 declarations 100
function 6 directive 100, 275
initializing virtual methods 38 procedures and functions 157, 279
Mem arrays 230 ExternProc 203
object-type declaration 34 EXTRN directive 280
record type 32
simple statements 8 F
subrange type 27
$F compiler directive 46, 99, 146, 198, 236
syntax diagram 14
faAnyFile constant 166
tokens 10
faArchive constant 166
variables 11
factor syntax 66
variant part of a record 33
faDirectory constant 166
Exclude procedure 133
faHidden constant 166
.EXE files 191
Fail procedure 107
building 250
False predefined constant identifer 26
Exec procedure 161
far
exit
ca11236
code 241, 275
model 197
functions 240
forcing use of 241
procedures 240, 241
requirement 193
Exit procedure 130
directive 98
ExitCode variable 133, 242
faReadOnly constant 166
exiting a program 241
faSysFile constant 166
ExitProc variable 241
FAuxiliary constant 162
Exp function 130
fAuxiliary constant 166
exponents 219
fa VolumeID constant 166
expression syntax 66-68
FCarry constant 162
expressions 65-79
fCarry constant 166
absolute, built-in assembler 270
fcDirectory constant 166
built-in assembler 262-274
fcExtension constant 166
classes 269-270
fcFileName constant 166
elements of 263-268
fcWildcards constant 166
versus Pascal 262
FExpand function 161
constant 21
Fibonacci numbers 154
address 59
fields
standard functions permitted in 22
designators syntax 56
defined 9
in record types 32
elements of, built-in assembler 263
list (of records) 32
order of evaluation 246
object 33
relocation, built-in assembler 270
scope 103
types, built-in assembler 270
record 55
Extended data type 28, 151, 152,220
figures, graphics 179
range arithmetic 152
file See also files
range of 150
buffer 230
extended syntax 20,31,43
handles 229
external
input and output 136-139
(reserved word) 283
modes 229
Index 293
external 100 G
headings 102 $G compiler directive 257
results 235 GetArcCoords procedure 185
returns, built-in assembler 275 GetArgCount function 165
syntax 101 GetArgStr function 165
functions 6, 97, See also procedures and GetAspectRatio procedure 185
functions GetBkColor function 185
address 132 GetCBreak procedure 162, 165
arithmetic 130 GetColor function 185
calls 233 GetCurDir function 165
directory-handling 165 GetDate procedure 160, 163
disk status GetDefaultPalette function 186, 189
Dos unit 161 GetDir procedure 135
WinDos unit 164 GetDriverName function 186
entry / exit code, built-in assembler 275 GetEnv function 161
environment-handling GetEnvVar function 165
Dos unit 161 GetFAttr procedure 161, 164
WinDos unit 165 GetFillPattern procedure 186
far 236 GetFillSettings procedure 186
file-handling GetFTime procedure 160, 163
Dos unit 161 GetGraphMode function 186
WinDos unit 164 GetImage procedure 175, 186
graphics 185 GetIntVec procedure 160, 164
heap-error 106 GetLineSettings procedure 186
High 112 GetMaxColor function 186
Low 112 GetMaxMode function 186
miscellaneous GetMaxX function 186
Dos unit 162 GetMaxY function 186
WinDos unit 165 GetMem procedure 56, 132,217
near 236 GetModeN arne function 186
nested 236 GetModeRange procedure 186
ordinal 131 GetPalette procedure 186, 189
OvrGetRetry 195 GetPaletteSize function 186
parameters, built-in assembler 274 GetPixel function 180, 186
pointer 132 GetTextSettings procedure 179, 186
private 119 GetTime procedure 160, 163
program example 6 GetVerify procedure 162, 165
SizeOf 112 GetViewSettings procedure 186
stack frame for, built-in assembler 275 GetX function 186
standard 129 GetY function 186
and constant expressions 22 goto statement syntax 83
string 131 GotoXYprocedure 144
transfer 130 Graph3 unit 128
FZero constant 162 Graph unit 128, 175, 199
fZero constant 166 bit images in 179
colors 180
constants 188
Index 295
index WinDos unit 164
dynamic method 38 Intr procedure 160, 164
syntax 55 IOResult function 135
types valid in arrays 30 IP flag 243
indexes in arrays 31 ISRs (interrupt service routines) 243
indexing character pointers 171
indirect unit references 120
infinite loop See loop, infinite
J
inheritance, rules of 33 jump sizing, automatic, built-in assembler 258
inherited (reserved word) 41 justify text constants 188
InitGraph procedure 176, 186
initialization part of a unit 120 K
initialized variables 58 Keep procedure 161
in assembler 279 keyboard status, testing 144
initializing virtual methods 37, 38 KeyPressed function 144
inline
directives 101,285
statements 284
L
InOutRes variable 133 $L compiler directive 279, 280, 283
input and output $L filename compiler directive 1~O, 157
file 136-139 label
with Crt unit 142-145 declaration part syntax 93
Input variable 133 syntax 19
Insert procedure 131 labels
InsLine procedure 144 built-in assembler 257
InstallUserDriver function 186 defined 19
InstallUserFont function 186 language overview 5
instances LastMode variable 145
dynamic object 39 l~te binding 37
of an object type 38 left
instantiating objects 38 brace special symbol 16
instruction opcodes, built-in assembler 257 bracket special symbol 16
Int function 130 length
Integer data type 25, 218 character strings 20
integer types 25 identifiers 17
interface part of a unit 119, 236 program lines 20
internal data formats 218-230 record 230
interrupt string-type value, finding 29
directive 243 Length function 131,245
directives 99 letters, defined 15
handlers 243 line
units and 202 input editing keys 143
handling routines 243 printer devices (LPTl, LPT2, LPT3) 141
procedures, writing 243 style constants 188
service routines (ISRs) 243 Line procedure 186
support procedures LineRel procedure 186
Dos unit 160 lines, maxiumum length of 20
LineTo procedure 186
Index 297
not operator 70, 180 of identifier in 36
NUL device 141 objects
NULL character 167 ancestor 34
null strings 19,29 constructors 222, 225
null-terminated strings 31, 128, 167-174 declaring 103
defined 167 defined 104
NULL character 167 error recovery 106
pointers and 169 virtual methods and 104
standard procedures and 173 creating 38
number constants 18 destructors 104
numbers declaring 103
counting 18 defined 104
hexadecimal 19 domain of 34
integer 19 dynamic
real 18 instances 39
numeric allocation and disposal of 104, 240
constants, built-in assembler 263 'method table 225
coprocessor fields
detecting 155 designators 56
emulating, assembly language and 157 scope 36, 103
evaluation stack 153 files in $L directive 280
using 149-157 instantiating 38
internal data format 222
o methods, scope 36
pointers to 39
$0 compiler directive 197
polymorphic 40, 110
nonoverlay units and 202
virtual
.OBJ files 279
method table 223
object
field 222
ancestor 34
pointer initialization 225
component designators 56
methods
descendant 34
call error checking 224
files 279
calling 238
scope 96
Odd function 131, 245
object-type
Ofs function 132
assignments 82
open
constants 62
parameters 108, 111
object types 33-42, See also objects
array 32, 108, 113
components 33
how passed 235
declaring 36
string 3D, 108, 111
domain 34
OpenString identifier 29, 108
fields 33
operands 65
instances 38
built-in assembler 261
methods 33
operators 65-75
rules of inheritance 33
@@ (double address-of) 79
scope @ (address-of) 43, 56, 75
in private sections 36
address-of (@) 79
in public sections 36
Index 299
OvrSeg variable 204 pointers
OvrSetBuf procedure 196, 199,211 assignment-compatibility of 40
OvrSetRetry procedure 195, 196 comparing 74
OvrTrapCount variable 196 to objects 39
types 43
p values 56
variables 56
$P compiler directive 111
polymorphism
Pack procedure 130
parameter type compatibility 110
packed
pointer assignment 40
reserved word 30
Port array 231
string type 31
PortW array 231
strings, comparing 74
Pos function 131
PackTime procedure 160, 163
pound (#) character 19
palette manipulation routines 177
precedence of operators 65, 69
ParamCount function 133
precision
parameters 107-114
of real-type values 28
actual 82
rules of arithmetic 25
command-line 133
Pred function 24, 131,245
constant 109
predecessor of a value, returning 24
floating-point 234
PrefixSeg variable 134, 209
formal 82, 107
Printer unit 128, 141
open 111
printing from a program 141
array 108, 113
private
string 108, 111
component sections 36
passing 83, 233-235
directive 17
Self 103
procedures and functions 119
defined 238
Private field 230
type compatibility 110
probationary area, overlay buffer 195
types of 108
PROC directive 281
untyped 110
procedural
value 108, 234
types 44-46
variable 109
in expressions 78-79
virtual method 240
type compatibility of 46
ParamStr function 133
variable typecasts and 58
Pascal strings 168
values 44
passing parameters 233-235
procedural-type constants 64
by reference 233
procedure
by value 233
call models 98
passing string variables of varying sizes 30
declaration syntax 97
PChar data type 43
declarations 97-101
Pi function 130
assembler 100
PieSlice procedure 187
external 100
pointer (A) symbol 43, 56
forward 99
pointer and address functions 132
inline 101
Pointer data type 43, 221
near and far 98
pointer-type constants.63
headings 98
Index 301
real Rename procedure 136
data types 28 repeat statement syntax 87
numbers 28, 149,219 repetitive statement syntax 87
Real data type 28 reserved words 16
real-type operations built-in assembler 261
80x87 floating type 28 defined 16
software floating point 28 external 283
record how identified in manuals 16
length 230 list of 16
scope 95 Reset procedure 136, 147
types 32 RestoreCrtMode procedure 176, 187
record-type constant syntax 62 RET instruction, built-in assembler 258
records 32, 55, 62, 222 RETF instruction, built-in assembler 258
fields 55 RETN instruction, built-in assembler 258
variant part 32 return character, defined 15
Rec5ize field 230 returning
Rectangle procedure 187 Char values 26
recursive loop See recursive loop the ordinality of a value 24
redeclaration of variables 51 the predecessor of a value 24
redirection 142 the successor of a value 24
reentrant code 243, 244 Rewrite procedure 136, 147
register-saving conventions 241 right
RegisterBGldriver function 176, 183, 187,202 brace special symbol 16
RegisterBGIfont function 183, 187, 202 bracket special symbol 1~
registers RmDir procedure 136
and inline statements 285 Round function 130, 245
AX 235, 286 round-off errors, minimizing 152
BP 241,243 rules
overlays and 203 governing boolean variables 26
built-in assembler 265, 269 of inheritance 33
BX235,243 of scope 95-96
C5243 run-time
CX243 errors 241, See also the Programmer's Reference
DI243 library overview 127-128
D5241,243 RunError procedure 130
DX235,243
E5243 5
51243
$5 compiler directive 52
5P241
5aveIntXXXXX variables 134
55241
scale factor syntax diagram 18
use, built-in assembler 256
scope
using 235,241,243
block 95
Registers type 163
in object types 36
relational operators 73-75
object 96
Release procedure 212
record 95
relocation expressions, built-in assembler 270
rules of 95, 95-96
RemoveDir procedure 165
type identifiers 23
Index 303
special symbols StrCat function 168
built-in assembler 265 StrComp function 168
character pairs listed 16 StrCopy function 168
single characters listed 16 StrDispose function 168
SPtr function 132 StrECopy function 168
Sqr function 131 StrEnd function 168
Sqrt function 131 StrIComp function 168
SS register 241 string See also strings
SSeg function 132 constants, built-in assembler 264
stack functions 131
80x87153 literals, assigning to PChar 169
frame, built-in assembler use of 275 operator 71
overflow 52 procedures 131
passing parameters and the 233 type
pointer 210 default size 29
segment 52, 210 ordering between two values 29
StackLimit variable 134 packed 31
standard typed, constants 60
directives 17 types 29, 221
functions 129 variables 55
procedure and function passing 30
defined 129 strings See also string
procedure or function used as a procedural value character 19
46 length of 20
procedures 129 comparing 74
units, list of 127 concatenating 71
statement part syntax 94 coverting 168
statements 81, 81~92 embedding control characters in 19
assignment 82 length byte 221
case 85 maximum length of 221
compound 84 null 19,29
conditional 84 null-terminated 31, 128, 167-174
for 88 Pascal 168
goto 83 Strings unit 128, 167
if 84 functions in 167
procedure 82 using the 167
repeat 87 StrLCat function 168
repetitive 87 StrLComp function 168
simple 81 StrLCopy function 168
structured 83 StrLen function 168
while 87 StrLIComp function 168
with 90 StrLower function 168
static methods 37 StrMove function 168
storing StrNew function 168
null-terminated strings 31 stroked fonts 175, 178
overlaid code 211 StrPas function 168
Str procedure 131 StrPCopy function 168
Index 305
Boolean 218 simple 23-29
boolean 25 Single 24, 151
Byte 25 string 29,221
ByteBool218 structured 30-42
Char 26,218 subrange 27
Comp 24,151 Word 25
compatibility 47 WordBool25,218
compatible 46
declaration part 49
Double 24, 151
u
enumerated 26, 219 unary
Extended 24, 151 arithmetic operators 69
file 42, 228 operands 65
floating-point 28, 151,219 unit syntax 118
Comp 221 units 118-124
comparing values of 153 80x87 coprocessor and 155
Double 220 circular references 121
Extended 220 Crt 128, 142
Single 220 defined 13
Graph unit 189 Dos 127, 159-163
host 27 Graph 128, 175
identical 46 Graph3128
identity 46 heading 118
Integer 25, 218 identifiers 17
integer implementation part 119
converting through typecasting 25 indirect references 120
format of 25 initialization
range of 25 code 201
LongBool 25, 218 part 120
Longint 25 interface part 119
major classes 23 nonoverlay 202
object 33-42 Overlay 128, 192
declaring 34 overlays and 193
ordinal 24-28 Printer 128, 141
characteristics of 24 reasons to use 13
predefined 25 scope of 96
user-defined 25 standard, list of 127
packed string 31 Strings 128, 167
PChar 43 System 127
Pointer 43,221 Turbo3128
procedural 44, 44-46, 78 uses clause 117
Real 24 version number 121
real 28 WinDos 127, 163-166
numbers 219 Unpack procedure 130
record 32, 222 UnpackTime procedure 160, 164
set 42,221 unsigned
Shortint 25 constant syntax 66
integer syntax diagram 18
Index 307
7.0
B o R L A N D
Corporate Headquarters: 1800 Green Hills Road, P.O. Box 660001 , Scotts Valley, CA 95067-0001 , (408) 438-8400. Offices in: Australia,
Belgium, Canada, Denmark, France, Germany, Hong Kong, Italy, Japan, Korea, Malaysia, Netherlands, New Zealand, Singapore, Spain,
Sweden, Taiwan, and United Kingdom ' Part 111 MN-TPL04-70 • BOR 4680