home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-10-19 | 61.9 KB | 1,625 lines |
- Chapter 3
- - continued -
- - Part 2 of 3 parts -
- of the
- Turbo Pascal Reference
-
- The Turbo Pascal Language
-
-
- This chapter is part of the Turbo Pascal Reference electronic freeware book (C)
- Copyright 1992 by Ed Mitchell. This freeware book contains supplementary
- material to Borland Pascal Developer's Guide, published by Que Corporation,
- 1992. However, Que Corporation has no affiliation with nor responsibility for
- the content of this free book. Please see Chapter 1 of the Turbo Pascal
- Reference for important information about your right to distribute and use this
- material freely. If you find this material of use, I would appreciate your
- purchase of one my books, such as the Borland Pascal Developer's Guide or
- Secrets of the Borland C++ Masters, Sams Books, 1992. Thank you.
-
-
- Pointers and Complex Data Structures
- Turbo Pascal provides a large variety of built-in data types. However, to
- create specific data structures such as list, queues, stacks, trees and so on,
- requires that you create and maintain the appropriate data structures yourself.
- Pointers are used extensively to create these types of data structures.
- Figure 3.4 illustrates a list structure containing a list of filenames.
- Each filename is stored in a record, together with pointers to the next and
- previous items in the list.
-
- ***03tpr04.pcx***
- Figure 3.4. Pointers are often used in record structures to create list data
- structures, as shown here. In a list, each element is linked, via a pointer,
- to another element in the list.
-
- Such a list structure is represented as a Pascal record, containing space
- for the filename and other information, plus pointer values to the next and
- previous list entries. Listing 3.6 shows a sample data record declared as the
- type TListEntry. A pointer to TListEntry is defined as PListEntry.
-
-
- Listing 3.6. A sample data record set up for use in a list data structure.
- Note the use of the separate PListEntry, defined as a pointer to TListEntry.
-
- type
- { Data record to create the list structure }
- PListEntry = ^TListEntry;
- TListEntry = record
- DirInfo : SearchRec;
- Next : PListEntry;
- Previous: PListEntry;
- end; {TListEntry}
-
- A list is constructed out of these records by creating a pointer to the first
- item in the list, and storing the first pointer in a variable called ListHead,
- and using New ( PListEntry ) to create each entry. The variable ListTail
- points to the last item in the list.
-
- var
- ListHead : PListEntry;
- ListTail : PListEntry;
-
- The Next field of the TListEntry record is used to point to the next
- succeeding item in the list. Each time an item is added to the list, the
- previous item's Next field is set to point to the new item, and the new item's
- Next field, if its the last item in the list, is set to nil to mark the end of
- the list.
- The Previous field is used to link the list of items in both directions.
- In this way, the items in the list can be accessed in both the forward and the
- backwards directions.
- Listing 3.7 presents a complete sample list program that reads the names
- of the files from the current subdirectory and places them into a list data
- structure. The program then displays the list in both the forward and backward
- directions, using the Next or Previous pointer to reach the next or previous
- element in the list structure.
-
- Listing 3.7. This program uses pointers to create and manipulate a list data
- structure.
- 1 program DemoList;
- 2 {
- 3 Demonstrates the use of pointers to create a list structure, demonstrates
- how
- 4 list traversal is done in both forwards and backwards directions, and
- provides
- 5 routines to add (or insert) and delete items in the list.
- 6
- 7 You can modify these routines for use as a general purpose list
- manipulation
- 8 tool, by changing the ListEntry data structure to hold other types of
- data.
- 9
- 10 This demonstration program uses the Dos library routines FindFirst and
- 11 FindNext to read the default file subdirectory.
- 12 }
- 13 uses Dos;
- 14
- 15 type
- 16 { Data record to create the list structure }
- 17 PListEntry = ^TListEntry;
- 18 TListEntry = record
- 19 DirInfo : SearchRec;
- 20 Next : PListEntry;
- 21 Previous: PListEntry;
- 22 end; {TListEntry}
- 23
- 24 var
- 25 ListHead : PListEntry;
- 26 ListTail : PListEntry;
- 27
- 28
- 29 function LowerCase (S : String ) : String;
- 30 Var
- 31 I : Integer;
- 32 begin
- 33 for I := 1 to length(s) do
- 34 if ((S[I]>='A') and (S[I]<='Z')) then
- 35 S[I] := Chr( Ord( S[I] ) + 32 );
- 36 LowerCase := S;
- 37 end;
- 38
- 39
- 40
- 41 procedure InitDirectoryList;
- 42 { Initialize the directory list structure.
- 43 For convenience, the first entry contains the default volumne name C:\.
- 44 }
- 45 begin
- 46 ListHead := New(PListEntry);
- 47 ListHead^.Next := NIL;
- 48 ListHead^.Previous := NIL;
- 49 ListTail := ListHead;
- 50 ListHead^.DirInfo.Name := 'C:\';
- 51 end; {InitDirectoryList}
- 52
- 53
- 54
- 55 function AddEntry ( Location : PListEntry;
- 56 Var ListEntry : SearchRec ) : PListEntry;
- 57 Var
- 58 NewEntry : PListEntry;
- 59 SavedNext : PListEntry;
- 60
- 61 begin
- 62 NewEntry := New ( PListEntry );
- 63 NewEntry^.DirInfo := ListEntry;
- 64
- 65 If Location = ListTail Then
- 66 {Adding an item on to the tail of the list}
- 67 begin
- 68 NewEntry^.Next := NIL;
- 69 NewEntry^.Previous := ListTail;
- 70 ListTail^.Next := NewEntry;
- 71 ListTail := NewEntry;
- 72 end
- 73 else
- 74 {inserting an item within the list}
- 75 begin
- 76 SavedNext := Location^.Next;
- 77 Location^.Next := NewEntry;
- 78
- 79 NewEntry^.Next := SavedNext;
- 80 NewEntry^.Previous := Location;
- 81
- 82 SavedNext^.Previous := NewEntry;
- 83
- 84 end;{begin}
- 85
- 86 AddEntry := NewEntry;
- 87
- 88 end;{AddEntry}
- 89
- 90
- 91
- 92 function RemoveEntry ( Location : PListEntry;
- 93 HowMany : Integer ) : PListEntry;
- 94
- 95 { Starting at the point in the list indicated by 'Location', delete
- 96 'HomeMany' entries from the list.
- 97 Return: A pointer to the first item after those that were deleted.
- 98 }
- 99
- 100 var
- 101 CountOfItems : Integer;
- 102
- 103 function DeleteEntry ( Location : PListEntry ) : PListEntry;
- 104 begin
- 105 if Location <> NIL then
- 106 begin
- 107 If Location^.Previous <> NIL Then
- 108 Location^.Previous^.Next := Location^.Next;
- 109 If Location^.Next <> NIL Then
- 110 Location^.Next^.Previous := Location^.Previous;
- 111 DeleteEntry := Location^.Next;
- 112 If Location = ListTail Then
- 113 ListTail := Location^.Previous;
- 114 Dispose(Location);
- 115 end
- 116 else
- 117 DeleteEntry := NIL;
- 118 end;
- 119
- 120 begin {RemoveEntry}
- 121 For CountOfItems := 1 to HowMany Do
- 122 Location := DeleteEntry ( Location );
- 123 RemoveEntry := Location;
- 124 end;{RemoveEntry}
- 125
- 126
- 127 function Move_Fwd ( Location : PListEntry;
- 128 HowFar : Integer ) : PListEntry;
- 129 {Starting from 'location' move ahead 'HowFar' items in the list
- 130 and return the new location
- 131 }
- 132 Var
- 133 I : Integer;
- 134 begin
- 135 For I := 1 to HowFar Do
- 136 If Location^.Next <> NIL Then
- 137 Location := Location^.Next;
- 138 Move_Fwd := Location;
- 139 end;{Move_Fwd}
- 140
- 141
- 142 function Move_Bwd ( Location : PListEntry;
- 143 HowFar : Integer ) : PListEntry;
- 144 {Starting from 'location' move backwards 'HowFar' items in the list
- 145 and return that new location
- 146 }
- 147 var
- 148 I : Integer;
- 149 begin
- 150 for I := 1 to HowFar do
- 151 if Location^.Previous <> NIL Then
- 152 Location := Location^.Previous;
- 153 Move_Bwd := Location;
- 154 end;{Move_Bwd}
- 155
- 156
- 157 Procedure DisplayFwdList;
- 158 Var
- 159 TempPtr : PListEntry;
- 160
- 161 begin
- 162 TempPtr := ListHead;
- 163 While TempPtr <> NIL do
- 164 begin
- 165 writeln(TempPtr^.dirinfo.name);
- 166 tempptr := TempPtr^.Next;
- 167 end;
- 168 end;
- 169
- 170 procedure DisplayBwdList;
- 171 Var
- 172 TempPtr : PListEntry;
- 173
- 174 begin
- 175 TempPtr := ListTail;
- 176 while TempPtr <> NIL do
- 177 begin
- 178 writeln (TempPtr^.dirinfo.name);
- 179 tempptr := TempPtr^.Previous;
- 180 end;
- 181 end;
- 182
- 183
- 184
- 185 procedure ReadDirectory
- 186 ( StartingEntry : PListEntry );
- 187
- 188 { Purpose:
- 189 Reads the directory contents and inserts
- 190 the list into the directory list beginning at 'StartingEntry'.
- 191
- 192 }
- 193 var
- 194 ListEntry : SearchRec; { Holds the contents of a directory entry
- 195 consisting of filename, size, etc }
- 196 CurLocation : PListEntry;
- 197 IsADirectory : Boolean;
- 198
- 199 begin
- 200 {Call FindFirst to locate all files. The '*.*' matches all filenames,
- 201 In this case we want to see ALL files so we use the AnyFile mask.
- 202 Note that for the purpose of this example program we are not doing
- 203 error checking. We should check the DosError variable after each
- 204 call to FindFirst and FindNext. Also, its possible that AddEntry
- 205 will run of memory and return a NIL value but we aren't checking
- 206 for that in this simplified application example.
- 207 }
- 208
- 209 FindFirst( '*.*', AnyFile, ListEntry );
- 210 while DosError = 0 do
- 211 begin
- 212 if ListEntry.Name[1] <> '.' then
- 213 {Add all names other than those beginning with '.'. This
- 214 eliminates our displaying the '.' and '..' names used by DOS}
- 215 begin
- 216 IsADirectory := (ListEntry.Attr and Directory) = Directory;
- 217 if not IsADirectory then
- 218 ListEntry.Name := LowerCase (ListEntry.Name);
- 219 {We convert file names to lowercase and leave directory names
- 220 in upper case for ease of reading the directory listing}
- 221 StartingEntry := AddEntry ( StartingEntry, ListEntry );
- 222 end; { begin }
- 223 FindNext( ListEntry );
- 224 end; { begin }
- 225 end; { ReadDirectory }
- 226
- 227 begin
- 228
- 229 InitDirectoryList;
- 230
- 231 ReadDirectory ( ListHead );
- 232
- 233
- 234 DisplayFwdList;
- 235 Readln;
- 236
- 237 DisplayBwdList;
- 238 Readln;
- 239
- 240 end.
-
-
- Pointers and the With Statement
- As with the record statement, a pointer to a record structure can use the
- with statement to abbreviate the number of identifiers that need to be written.
- For example,
-
- type
- { Data record to create the list structure }
- PListEntry = ^TListEntry;
- TListEntry = record
- DirInfo : SearchRec;
- Next : PListEntry;
- Previous: PListEntry;
- end; {TListEntry}
- var
- PersonInfo : PListEntry;
- ...
- New ( PersonInfo );
- with PersonInfo^ do
- begin
- DirInfo := DataRecord;
- Next := NextPointer;
- end;
- ...
-
- Turbo Pascal Arithmetic Operations
- Pascal provides each of the following data and arithmetic operations:
-
- Basic arithmetic operations: +, -, div, *, /, mod, unary + and -
-
- Relational operations: <, <=, =, >=, >, <>
-
- Logical or bit-level operations: and, or, xor, not, shl, shr
-
- Boolean operations: and, or, not, xor
-
- String operations
-
-
- In addition, through procedures and functions available from the Turbo Pascal
- libraries, additional features, including trigonometric, logarithmic, square
- root and other functions are available. These functions are described in
- chapter 5, "The System Library Reference", in this freeware book. Chapter 4
- of the Turbo Pascal Reference includes definitions that you can use for
- arc-cosine and arc-sine, two popular functions that are, for unknown reasons,
- omitted from Borland's System Library.
-
-
- Basic Arithmetic Operators
- Constants or variables are combined in arithmetic statements to calculate
- new values. Turbo Pascal's built-in arithmetic operators are:
-
- + Addition: A + B to compute A plus B.
-
- - Subtraction: A - B to subtract B from A.
-
- * Multiplication: A * B to multiple A times B.
-
- / Real number division: A / B to compute A divided by B.
-
- div Truncated integer division: A div B to compute A divided by B and
- truncated the result towards zero. For positive results, the truncation
- is towards the next lower integer; for negative results, the truncation
- is towards the next highest integer. Example: If the result is 3.7,
- the A div B produces 3.
-
- mod Modulus: A mod B returns the remainder of the integer division
- between A div B and is equivalent to A - ((A div B) * B). Example: 10
- mod 3 equals 1.
-
-
- When operators are mixed in an expression, such as A+B*C, the algebraic rules
- of hierachy apply, and B*C is evaluated first, before adding B. Turbo Pascal's
- expression evaluation ordering is described below in the section titled
- Evaluation Hierarchy.
- Note that division is indicated with the div operator for dividing Integer
- values, and the / division symbol when dividing Real values.
-
-
- Mixing Data Types in Expressions
- As a general rule, data types should be used consistently in an
- expression. For example, if Ch is of type Char and R is of type Real, it does
- not make sense to write Ch * R, and in fact, is not allowed by Turbo Pascal.
- However, it is possible to convert data types from one type to another, both
- implicitly and explictly.
- If you mix types in an expression in an unacceptable manner, the Turbo
- Pascal compiler will issue an Error 26: Type mismatch error.
- Many programmer's encounter this error frequently and fortunately, it is not
- particularly difficult to fix. If you see this error message, check your
- statements very carefullly, being certain that the data types are correct and
- that parentheses are placed in the proper locations.
-
-
- Implicit Type Conversion
- When you multiply a Real value times an Integer value, the result is a
- Real value that can be assigned to a real typed variable. The conversion of
- the Integer value to a Real is implicit whenever at least one item in the
- expression is a real value.
-
-
- Explicit Type Conversion
- You can also explicitly force a real type conversion of the data.
- Converting an integer to a real can be done by adding 0.0 to the integer, since
- the result of an arithmetic operation involving an integer and a real value is
- a real value. For instance,
-
- R := (N+0.0) * 4578;
-
- You can convert Char values to Integer type values using a type cast, as in
- this example which uses the type Integer like a function,
-
- N := Integer(Ch);
-
- or by referencing the ordinal function,
-
- N := Ord(Ch);
-
- which returns the ASCII code of the character represented by Ch. To convert an
- integer value back to a character, you can write,
-
- Ch := Chr(N);
-
- where Chr converts an integer value back to a character type.
- Changing the type of an expression with a type cast is limited to ordinal
- data types (Char, Byte, Shortint, Integer, Word, Longint) and to pointer types.
- A type rast only works when the internal memory size allocations are identical.
- Generally, type casting is used when accessing data that is pointed to by an
- untyped pointer variable.
- To convert a Real value to an Integer, use the Round(R) or Trunc(R)
- truncate function. Round will round its parameter up or down to the nearest
- whole number. Trunc disgards the fractional part and returns the mantissa.
- When converting Real values to Integer, you must insure that the real value
- falls within the acceptable range for integers.
-
-
- Address-of @ operator
- Turbo Pascal provides a special operator, the @ symbol, to compute the
- memory address of a particular object. For example,
-
- var I : Integer;
- ...
- APointer := @I;
-
- assigns the memory location of I to the variable APointer. This operator is
- used often in pointer operations and for passing procedures as parameters to
- other procedures and functions.
-
-
- Comparision or Relational Operators
- You can test how one variable or constant is related to another by using a
- relational operator. The result of a relational expression is a boolean True
- or False. and may be assigned to a Boolean variable, used in if-then statements
- for testing a conditional value, and in while and repeat statements. These
- statements are described later.
-
- Equality: A = B returns True if A and B have the same value, and A and
- B are of any standard type. Returns False if A is not equal to B.
-
- Less than: A < B returns True if A is less than B. In the case of Char
- and String values, the comparison is made according to the underlying
- ASCII code representation of the characters. Returns False if A is not
- less than B.
-
- Greater than: A > B returns True if A is greater than B. Returns False
- if A is not greater than B.
-
- Less than or equal: A <= B returns True if A <= B or A is less than B
- returns False if A is neither equal to B nor less than B.
-
- Greater than or equal: A >= B returns True if A = B or A is greater
- than B. Returns False if A is not equal to B nor greater than B.
-
- Not equal: A <> B returns True if A is not equal to B, and False if
- they are equal.
-
-
- The values represented by A and B may be any valid Turbo Pascal
- expression. You may write, for instance,
-
- I > (J+10) * 5;
-
- Since the result of a relational operator is either True or False, you may
- choose to assign this value to a declared Boolean variable, such as the boolean
- variable B, as shown here,
-
- B := I > (J+10) * 5;
-
- When comparing values, both operands should be compatible types, with the
- exception that if one operand is a Real value, then it is permissible for the
- other operand to be an Integer type expression. For example, (I*J) < 45.0;
- The relational operators = and <>. only, may also be used for comparing
- pointers to see if they are exactly equal or not equal, respecitvely. No other
- comparisons are allowed directly on pointers (although you can freely compares
- the values that the pointers point to).
-
-
- Logical or Bit Level Operations
- Logical operations may be applied to any scalar data type (Byte, Smallint,
- Integer, Word, Longint) and perform a bit-wise logical test. The table below
- describes each of the logical operators. The data type of the result of a bit
- wise test is determined by the type of the operands.
-
- and: A and B produces a resulting bit pattern that has bits set
- where the corresponding bits in A and in B are both set. If both
- positions have a 1, then the resulting bit in the same position is a 1.
- If either position is a zero, then the resulting bit position is also a
- zero. Example: If I is an integer having the decimal value 10 (binary
- 00001010), then I and 8 (binary 00001010) produces 00001000 since only
- this bit is set in both values.
-
- or: A or B produces a bit result such that for each bit position in A
- or B this a 1, the resulting bit position is set to 1. If either of the
- bits in A or B is 1, then the result is also 1. If both bits are zero,
- then resulting bit is a zero. Example: 7 or 32 (binary 00000111 or
- binary 0001000) produces 00010111.
-
- not: not A inverts each bit in A. 1 becomes 0 and a zero becomes 1.
-
- xor: A xor B produces the exclusive or of A and B. xor is like the or
- operation, except that the result of xor is a 1 only when 1 of the
- operands is a 1. If both operands are 1 or both operands are 0, then
- the result is 0.
-
- shl: A shl <expression> shifts the bits of A to left the number of bits
- specified by the value of the <expression>. Example: 0000 0011 shl 3
- produces 0001 1000
-
- shr: A shr <expression> shifts the bits of A to right the number of bits
- specified by the value of the <expression>. Example: 0101 0010 shr 4
- produces 0000 0101.
-
-
- Boolean Operations
- Boolean expressions are written using the following boolean operators:
-
- and: A and B, where A and B are boolean valued expressions, produces
- True if A and B are both True, and False if either A or B is False.
-
- or: A or B produces True if either A or B is True, and False only when
- both A and B are False.
-
- not: not A returns False if A is True, or returns True if A is False.
-
- xor: A xor B returns True if either A or B is True, but returns False
- if both A and B are True or both A and B are False.
-
-
- Boolean operators are frequently used when testing multiple conditions in a
- conditional expression, such as an if-then statement. For example,
-
- if (NumFiles > 10) and (DeleteFiles = 'YES') then ...
-
- evaluates both relational expressions, each of which returns either True or
- False, then ands the two boolean values together. If that result is True, the
- then part of the statement is executed.
-
-
- Short-Circuit versus Complete Evaluation
- A special feature of Turbo Pascal is the option to use either complete
- boolean expression evaluation or short-circuit boolean expression evaluation.
- In complete evaluation mode, the entire boolean expression is evaluated before
- testing the result. In short-circuit mode, Turbo Pascal can optimize the
- expression evaluation, often generating less code and on average, executing in
- less time. In the example,
-
- if (NumFiles > 10) and (DeleteFiles = 'YES') then ...
-
- if short-circuit evaluation is used, Turbo Pascal will jump to the next
- statement if NumFiles is less than or equal to 10, since regardless of the
- following expression, the overall expression can not possibly be True if the
- first operand is already False. Short-circuit evaluation is especially useful
- when checking to see if an array index is within the array bounds and then, in
- the same expression, referencing the index value. For example, in the
- statement,
-
- if (Index <= 20) and (DataItem[Index]=0) then ...
-
- short-circuit evaluation ignores the DataItem[Index]=0 relational comparison if
- Index is greater than 20. This is a convenient way to check for an out of
- bounds condition. Without short-circuit evaluation, you would otherwise have
- to write this statement as,
-
- if Index <= 20 then
- if DataItem[Index] = 0 then ...
-
- to prevent a possible out of bounds array indexing operation to occur.
- Complete evaluation is useful when the expression calls a function which,
- in turn, sets some other values elsewhere in the program. In this instance,
- the complete evaluation mode insures that the entire expression is evaluated
- fully before making a conditional test.
- The compiler's default operation is to use the short-circuit style of
- expression evaluation. The choice of evaluation methods is made using the $B
- compiler directive ($B+ enables complete evaluation, $B- enables short-circuit
- evaluation). See Compiler Directives, later in this chapter.
-
-
- String Operations
- The standard data type, String, is a packed array of Char, where the size
- of the string is set to 255 by default, plus a length byte, for a total of 256
- bytes of memory. By specifying a new string length in brackets, after String,
- a different maximum string length may be specified: For example,
-
- var
- S1 : String;
- S2 : String[80];
-
- S1 defines a default string of length 255; S2 is defined to hold up to a
- maximum of 80 characters. A string variable may, and usually does make use of
- fewer bytes than its maximum length, however the allocated memory is always
- equal to the maximum length, plus 1. Turbo Pascal tracks the string's current
- length by storing the number of characters in an invisible leading byte at the
- beginning of the string. Since a string is just an array of Char, this puts
- the length byte in the zero'th position of the string (for example, S1[0]).
- The normal method of referencing a string's length is to call the Length()
- function. If S1 contains 'THIS IS A STRING', then Length(S1) returns the
- value 16. If the compiler's range checking option is off {$R-}, you can
- directly access the string's length byte, as S1[0], which returns a Char typed
- value. To convert to an integer value, use Ord(S1[0])). You may also manually
- assign a new string length to a string by writing,
-
- S1[0] := Chr( NewLength );
-
- Even though referencing a string's length byte violates normal range checking,
- in practice it is a common occurrence in Turbo Pascal programs. And by
- default, the Turbo Pascal compiler operates with range checking turned off.
- You may concatenate two strings together (that is, add them together to
- make a longer string), using the + symbol. If S1 contains 'THIS', you could
- write,
-
- S1 := S1 + ' IS A TEST!';
-
- to assign S1 the new value 'THIS IS A TEST'. The operand that is added to the
- first string may be a string constant, variable, expression or a character Char
- type. The strings are concatenated together up to a maximum of 255 bytes in
- length, after which the excess characters are disgarded.
-
-
- Evaluation Hierarchy
- Turbo Pascal expressions can be written with their operands in any order
- (such as 3 + 5 * 8). However, the actual evaluation of the expression does not
- occur in the order written. Instead the expression's result is computed
- according to the standard rules of algebraic notation and hierachy. Elements
- of such expressions are evaluated in this order:
-
- The unary not operator has highest precedence,
- Expressions within parantheses are evaluated first,
-
- Then, *, /, div, mod, and the and operator,
-
- Then, the unary + or -
-
- Then, +, -, and the or operator
-
- Lastly, the relational operators =, <, >, <>, <=, >= and the set in
- operator.
-
-
- The short-circuit evaluation option (the normal mode of operation) may cause
- boolean expressions to terminate their evaluation before the entire expression
- is evaluated.
-
-
- Pascal Statements
- Turbo Pascal program statements describe the operations and flow of
- execution in the Pascal program. Each program statement consists of a
- sequence of keywords, arithmetic expressions and identifiers, terminated by a
- semicolon. The maximum length of a Turbo Pascal line is 126 characters.
- However, in most instances Pascal statements (between semicolons) may be
- extended across multiple lines with the only restriction being that character
- string constants must not be broken across lines. If you need to enter a
- string constant longer than the maximum 126 character line length allowed by
- Turbo Pascal, use the + string concatenation operator and separate the string
- into two statements, like this:
-
- S1 := 'This is going to be a really long character string '
- + 'constant that spreads across two lines!';
-
- The Pascal language syntax is often described using a graphic technique
- known as syntax diagram or "railroad diagrams" for their resemblence to a
- railroad switching yard. In this format, a Turbo Pascal program statement is
- described visually. An example syntax diagram for the if-then-else statement
- is shown in Figure 3.5.
-
- ***03tpr05.pcx***
- Figure 3.5. The Pascal syntax diagram for the if-then-else statement.
-
- An alternative notation is to describe this statement as,
-
- if <expression> then <statement>
-
- or
-
- if <expression> then <statement> else <statement>
-
- Both notations are used, where appropriate, in Turbo Pascal Reference.
-
-
- Program Comments
- Program comments are enclosed within "curly brackets" like this,
-
- { This is a program comment }
-
- The contents of a program comment are, with the exception of compiler
- directives, ignored by the compiler. Alternately, you may enclosed comments
- using this notation,
-
- (* This is a program comment *)
-
- During the process of developing your Turbo Pascal programs, you will find it
- convenient to standardize on one or the other comment statement formats. Most
- programmers have gravitated towards use of the curly brackets. An advantage of
- consistently using one or the other type is that while developing and testing
- sections of your program, you can comment out entire sections of code,
- including sections that already contain comments. Listing 3.8 shows an example
- using the (* and *) notation to temporarily eliminate a section of the program.
-
- Listing 3.8. Example use of the (* and *) to comment out an entire section of
- source code.
-
- (* COMMENT OUT THIS ENTIRE SECTION
- if StartEntry <> NIL then
- begin
- { We still have more path to traverse }
- StartEntry := Move_Fwd( StartEntry, 1);
- if StartEntry^.Level <= ThisLevel then
- { this subdirectory isn't open so we can't search any deeper }
- SearchFor := NIL
- else
- if PathName = '' then
- { Return the address of the subdirectory entry }
- SearchFor := Move_Bwd( StartEntry, 1 )
- else
- {Continuing searching down the path. Note that this uses
- a recursive function.}
- SearchFor := SearchFor ( PathName, StartEntry );
- end; {begin }
- END OF COMMENTED OUT SECTION *)
-
-
- Assignment Statements: :=
- Syntax:
-
- <variable name> := <expression of the appropriate type>;
-
- Examples:
- I := 10;
- AllDone := True;
- R := 213456.989;
- J := I * 5 - N;
- OkToPrint := (Answer='Y') and (PrintOption=10);
-
- Description:
-
- A variable is given a value with an assignment statement. Assignment
- statements are written as in this example,
-
- R := 1345.78 * I;
-
- The data type of the expression must be compatibile with the data type of
- the variable, or using techniques discussed previously, can be explicitly
- converted to the appropriate data type. Assignment statements are also used to
- return a function result value, by assigning an expression to the function name
- as if it was a variable. Functions are described later in this chapter.
-
-
- Conditional Statements: If-then-else and case
- Turbo Pascal has two conditional statements, the if-then-else statement
- and the case statement. Both evaluate some condition and execute exactly one
- of their possible outcomes selected by the value of the condition. The
- if-then-else statement is typically used for testing amongst a small number of
- selections, while the case statement compares one value against a large number
- of values or a range of values.
-
-
- The if-then and if-then-else statements
- Syntax:
- if <expression> then <statement>
-
- and
-
- if <expression> then <statement> else <statement>
-
- Examples:
- if InputLine = '***END MARKER' then
- begin
- Close(F);
- Close(OutFile);
- end;
-
- if Cos(Angle)*Theta + DeltaValue > 0.78934 then ...
-
- if Outlining then
- begin
- ThrowAway := FindPath ( Item, OutlineNumbers );
- Move( OutlineNumbers[1],
- StrBuffer[2], Length( OutlineNumbers ));
- Indent := Level*4 + 4;
- end
- else
- Indent := Indent + 2;
-
- Description:
-
- <expression> is any expression returning a boolean True or False value,
- ranging from a simple Boolean to a complex relational expression. If the
- expression is True, the statement following then is executed next, while if the
- expression is False, the then part is ignored. For example,
-
- if AllDone then
- Close( InputFile );
-
- In this statement, if AllDone is True, then the InputFile is closed. If
- AllDone is False, then the InputFile is left open and the Close statement is
- not executed.
- <statement> may be any Pascal statement, including a group of statements
- nestled between begin and end.
- In the if-then-else form, if the expression is True, the then part is
- executed, but if False, the else part is executed. if-then and if-then-else
- statements are often spread across multiple lines to improve readability. For
- example,
-
- if (Index <= MAXENTRIES) then
- XArray[Index] := DataItem
- else
- Writeln('The list is now full and cannot hold more entries');
-
- The <statement> part of an if-then or if-then-else may itself contain
- additional if statements. For example,
-
- if condition1 then
- if condition2 then
- <statement>
- else
- <statement>
-
- When if-then-else statements are nested like this, the else binds together with
- the most recent if-then. To use a different ordering, you may optionally
- enclose the statement within begin-end, like this:
-
- if condition1 then
- begin
- if condition2 then
- <statement>
- end
- else
- <statement>
-
-
- The case Statement
- Syntax:
- case <expression> of
- <constant> : <statement>;
- <constant> : <statement>;
- <constant> : <statement>;
- ...
- else
- <statement>
- end;
-
- The else part is optional. <constant> may specify a range of values using ".."
- notation, as for example, "1..10" to specify values in the range of 1 to 10.
-
- Examples of case statements:
- case EnteredChar of
- 'a'..'z' : EnteredChar := Chr( Ord(EnterChar) - 32 ); { convert to lower
- case }
- 'X' : DoExitCommand;
- 'O' : DoOpenFile;
- else
- writeln('Command entered is not recognized.');
- end;
-
- case Index of
- -32768..0: Writeln('Must use a positive valued index.');
- 1..10 : DoIndexProcessing (Index);
- 11..15: DoSpecialOperation (Index);
- 16..32767: Writeln('Index must be between 1 to 15.');
- end;
-
- Description:
- The case statement contains an initial expression called the selector,
- which is used to choose from among a list of various outcomes. When the
- selector matches an item in the list, the corresponding statement is executed.
- Only one match per case statement is permitted.
- The selector <expression> is any expression evaluating to a simple byte or
- word-sized result, such as an integer, word or char data type.
- The <constant> value should correspond to the type of the selector
- expression and may be either a single value or a range of values. A value
- range is written as,
-
- 100..199:
-
- where .. is placed between the start and end values for the range.
- Each <statement> may be any Turbo Pascal statement including a group of
- statements nested inside begin and end.
- The else part of a case statement is optional, and specifies what to do in
- the event that no value in the case list matches the selector. If there is no
- match in the case list and there is no else part, then no statements are
- executed.
-
-
-
-
- Looping Statements: For, While and Repeat
-
- Looping statements provide a mechanism for repeatedly executing
- one or more program statements. Turbo Pascal provides 3 looping
- constructs: the for loop, the while loop and the repeat-until loop.
-
-
- The for loop
- Syntax:
- for <control variable> :=
- <starting expression> to <ending expression> do <statement>
-
- and
-
- for <control variable> :=
- <starting expression> downto <ending expression> do
- <statement>
-
- Examples:
- for I := 1 to 10 do
- Writeln('Count = ', I);
-
- { Prints the alphabet from A to Z }
- For Ch := 'A' to 'Z' do Write(Ch);
-
- { Convert string S to lower case letters }
- for I := 1 to length(S) do
- if ((S[I]>='A') and (S[I]<='Z')) then
- S[I] := Chr( Ord( S[I] ) + 32 );
-
- Description:
- The for loop repeatedly executes a sequence of
- statements while incrementing or decrementing a loop control variable
- during each repetition. ntrol variable> must be a simple ordinal type
- (Byte, Char, Smallint, Integer, Word or Longint) variable (not an
- array element, record field or real typed) defined locally to a
- procedure or function, or a global value only for loops located in the
- main body of the program. The control variable is given an initial
- value specified by <starting expression>.
-
- If the control variable is within the range specified by the
- <starting expression> and the <ending expression>, then the
- <statement> part is executed. The <statement> part may include a group
- of statements between begin and end. he statements have executed, the
- control variable is incremented (or decremented in the case of the
- downto). If the new value of the control variable is still within the
- range of the starting and ending expression, the loop is executed
- again. On ce the control variable falls outside the range of the
- starting and ending expressions, program control resumes at the point
- immediately after the for statement. the loop, the control variable
- should be treated as read only meaning that you must not assign a new
- value to the control variable. While the compiler allows you to assign
- a new value, the result of this operation is undefined and should not
- be u sed. Similarly, the value of the control variable is undefined
- after the loop has completed and it should not be relied upon in any
- future expressions or conditional expressions. However, if a goto
- statement (see below) transfers control out of the for loop you may
- then reference the control variable outside the scope of the loop.
-
-
-
- While Loop
- Syntax:
-
- while <expression> do <statement>
-
- Examples:
- while not Eof(InputFile) do
- begin
- Readln(InputFile, InputLine);
- SaveLine(InputLine);
- end;
-
- while (I>1) and (S[I-1] <> ' ') do
- begin
- Insert (',', S, I);
- I := I - 3;
- end;
-
- Description:
- The while loop repeatedly executes a statement or group of statements as
- long the control expression is True. The control expression must always
- return a boolean True or False value. As soon as the expression is False, the
- loop terminates and the program resumes execution at the statement after the
- while loop.
- The while loop always evaluates the expression at the beginning of the
- loop. (See also the repeat-until loop for a loop that evaluates the expression
- at the end of the loop.)
-
- Repeat Loop
-
- Syntax:
- repeat <statement> until <expression>
-
- Examples:
- I := 0;
- repeat
- I := I + 1;
- Writeln(I);
- I := I + 1;
- until I = 10;
-
- { Keep reading keyboard commands until user selects a Done
- function }
- MenusDone := False;
- repeat
- MenuCommand := GetKey;
- Command := MenuCommand; {Set up default value for
- return'd command}
- case MenuCommand of
- KEY_LEFTARROW:
- begin
- ...
- end; { begin }
- ...
- KEY_ENTER:
- begin
- MenuPtr := FindItem(CurrentMenu, MenuIndex);
- Command := MenuPtr^.CmdCode;
- MenusDone := True;
- end; { begin }
- KEY_ESCAPE: MenusDone := TRUE;
- else begin {all other keys} end;
- End; { case }
- Until MenusDone;
-
- Description:
- repeat-until repetitively executes one or more statements appearing
- between the repeat and the until keywords. The statements are executed as long
- as the conditional expression after the until is False. When the condition
- evaluates to True, the loop terminates and program execution resumes at the
- statement following until.
- The repeat-until statement always executes the loop at least once since
- the conditional test is not performed until reaching the until statement.
- Unlike the other looping statements, the repeat and until keywords suffice
- to delineate multiple statements, hence, you do not need to enclose multiple
- statements with begin-end.
-
-
- Labels and Goto
- Goto Syntax:
- goto <label>
-
- Example goto:
- goto 100;
-
- Label declaration Syntax:
- label <list of labels>
-
- Example Label declaration:
- label 100, 200, 300;
-
- Label usage Syntax:
- <label>:
-
- Example label usage:
- 100:
-
- Example use of Label and Goto:
- procedure LabelDemo;
- label 999;
- var I : Integer;
- begin
- for I := 1 to MAXLINES do
- begin
- Writeln(Outfile, Lines[I] );
- if IoResult <> 0 then
- begin
- Writeln('Error occurred while writing output
- file.');
- goto 999;
- end;
- end;
- 999: Close(OutFile);
- end;
-
- Description:
- The goto statement transfers program execution directly to some other
- location in the program specified by a label, where <label> is an unsigned
- integer up to 4 digits in length and is located somewhere within the program or
- program unit. Each label must be explicitly declared in a label declarations
- section at the beginning of the program, unit, procedure or function, just like
- any other identifier. The actual location of the label is determined by
- placing the label, followed by a colon, somewhere within the program text.
- A label and a goto statement are sometimes used within procedures to
- quickly transfer program execution to the end of the procedure. An error
- condition or a user input request to finish up might prompt an early completion
- to execution of a sequence of statements. The example label, shown as "999" in
- the example above, must be declared before use with the label statement, and
- then is positioned within the program text by writing "999:" at the beginning
- of a statement. The label is referenced by the goto 999 statement.
-
- Important note: Do not use Goto to jump into a lower level block
- Do not use goto and a label to jump into the middle of a looping
- construct, such as,
-
- for I := 1 to 30 do
- begin
- 1: {Don't jump to the middle of a loop}
- ...
- end;
-
- The compiler will not generate an error if you compile such code, however,
- the result is potentially random. Never jump into a deeper nesting level, only
- to the same level or to a higher level.
- The label and the goto statement that refers to it, should always be in
- the same program block. That means you can not use goto to jump from within
- one procedure or function into another procedure or function.
- Lastly, do not place a label directly after a then statement, such as,
-
- if I = 10 then 1: ...
-
- although you may place a label within a begin-end block that follows a then
- statement.
-
-
- Procedures and Functions
- Few Pascal programs consist of a single main program body. Most are split
- into subtasks or subroutines, called procedures (or their close cousin, the
- function). The use of procedures and functions is an essential part of Turbo
- Pascal programming, and through appropriate use of procedures you can use
- structured program techniques to create modular programs that are more reliable
- and easier to maintain.
- Procedures provide a method of isolating portions of your program into
- separate, callable routines, which you can call or activate from anywhere
- within your program. Procedures may have a list of parameters, which are used
- to pass values into the procedure, and to return results.
- Functions are like procedures, except that a function is called from
- within an expression and directly returns a result to be used in evaluating the
- expression.
- Turbo Pascal provides enhancements to the basic Pascal procedure to
- provide for support of the underlying 80x86 microprocessor, and the creation of
- Pascal language interrupt handlers and assembly language interfacing. These
- features are specified with the keywords, near, far, and interrupt. Assembly
- language statements are incorporated directly into the Pascal source using
- either the asm or inline facilities.
-
- Procedures
- Syntax:
- procedure <identifier> <optional parameter list> <procedure body>
-
- The <optional parameter list> defines the values and data types that may
- be passed to the procedure at the time the procedure is called, and if the
- procedure may return values to the caller. Parameter lists are described in
- more detail, below.
- The <procedure body> normally consists of a paired begin-end statement,
- enclosing zero or more program statements. In Turbo Pascal, the <procedure
- body> may be optionally prefaced with:
-
- near; Use the 80x86 near procedure calling convention.
-
- far; Use the 80x86 far calling convention.
-
- interrupt; For creating special interrupt handler procedures.
-
- library; To create a dynamic link library procedure. See
- Chapter 2, "Units and Dynamic Link Libraries" in
- the Borland Pascal Developer's Guide, Que, 1992.
-
- Instead of the normal begin-end statement block, you may write:
-
- forward;
-
- to specify that the procedure body is specified later in the
- program.
-
- Use external when the procedure body is defined in a separately compiled
- object module that has been written in assembly language.
-
- Use inline() to incorporates machine code directly into the compiled code,
- rather than generating a call to the procedure. See Chapter 6, "Assembly
- Language Programming" in the Borland Pascal Developer's Guide.
-
-
- The <Optional parameter list>
- Parameters to a procedure or function are specified within parentheses,
- after the procedure or function identifier. The parameter list specifies one
- or more parameters, their type, and if the parameter is passed by value (a
- value parameter) or by reference (a variable parameter). When defining the
- parameter list, you create a list of variables (similar to a var declaration)
- assigning an identifier and data type to each parameter, and specifying whether
- the parameter is a value parameter or a variable parameter. For example,
-
- procedure PrintSum (A, B : Integer);
- begin
- Writeln('Sum of ',A,' + ',B, ' = ',A + B);
- end;
-
- defines a procedure PrintSum having two integer parameters A and B, both passed
- by value. The parameters A and B become local variables to the procedure
- PrintSum, and are undefined outside the scope of the procedure.
- To use this procedure, you call the procedure by placing the procedure
- name and the values for the parameters in a statement, like this:
- begin
- PrintSum( 10, 20 );
-
- which results in this output:
-
- Sum of 10 + 20 = 30
-
- The first parameter value, 10, is assigned to the parameter variable A, and the
- second parameter value, 20, is assigned to the parameter variable B. In the
- case of value parameters such as A and B, you can use any expression, which
- will be evaluated during program execution at the time of the procedure call.
- For example,
-
- PrintSum( 10+30, 5*TotalSize );
-
- The expression 10+30 will evaluate to 40, and A will get the value of 40.
- Variable parameters provide a way for the procedure to modify the contents
- of a variable passed to it. For example, by redefining PrintSum as shown
- below, the variable C becomes a var variable parameter. Inside PrintSum, C is
- assigned the result of A+B.
-
- procedure PrintSum( A, B: Integer; var C: Integer);
- begin
- Writeln('Sum of ',A,' + ',B, ' = ',A + B);
- C := A + B;
- end;
-
- In this way, when PrintSum is called like this,
-
- PrintSum( 10+30, 40, AValue );
-
- the local variable C gets assigned the sum, 80. The variable passed as a
- parameter to PrintSum, AValue, also gets assigned the sum, 80. A parameter
- defined as a var type, can only have a matching variable passed to it as a
- parameter, so that it can return a value. You must not try to pass an
- expression to a matching variable parameter, only to a value parameter.
-
-
- Arrays as Parameters
- Arrays and array elements may be passed to procedures as value parameters
- or as variable parameters.
- To pass an individual array element requires only that the parameter
- expression match the data type of the defined value parameter. For example,
-
- var
- AnArray : Array[1..10] of Integer;
-
- procedure P ( X : Integer );
- begin
- ...
- end;
- ...
- P ( AnArray[5] );
-
- Array elements may also be passed as variable parameters. For example,
-
- procedure P ( var X : Integer );
- begin
- ...
- end;
- ...
- P ( AnArray[5] );
-
- To pass an entire array to a procedure or function parameter requires that
- a user defined type be declared to describe the array. For example,
-
- type
- TArray : Array[1..10] of Integer;
- var
- AnArray : TArray;
-
- procedure P ( X : TArray );
- begin
- ...
- end;
- ...
- P ( AnArray );
-
- Turbo Pascal requires the parameter's type to be a simple identifier, so you
- cannot write:
-
- procedure P ( X : Array[1..10] of Integer );
-
- Instead, you must always define a new type equivalent to the array definition,
- and use that to declare array parameters.
- The example above passes an array by value. Internally, this is
- implemented by copying the entire array onto the stack, and then call the
- procedure. Not surprisingly, for large arrays this is both a time and memory
- consumer. Instead, for large structures, such as arrays or large records, it
- is recommend that you pass arrays as var parameter types, like this:
-
- procedure P ( var X : TArray );
-
-
- Strings as Parameters
- Strings may be passed either by value or as variable parameters. When a
- string is passed to a procedure parameter by value, any string expression may
- be used at the point of call. The compiler will generate code to evaluate the
- expression and then make a copy of the result, which is then passed to the
- procedure. In some instances, this extra overhead of making a copy of the
- string value may be prohibitive. Instead, you may wish to pass the string as a
- variable parameter since the compiler will then reference the original string,
- rather than making a copy of the string. For example,
-
- Procedure StringDemo( var S : String );
- begin
- S := '/' + S + '/';
- end;
-
- which is then called with,
-
- var AString : String;
- ...
- AString := 'TOOLS';
- StringDemo( AString );
-
- results in AString getting the value, '/TOOLS/'. When using a variable
- parameter, you must always pass a variable identifier when the procedure is
- called. Using a string expression, such as,
-
- StringDemo('TOOLS');
-
- will result in a compiler error message. Keep in mind that any changes you
- make to the parameter variable within the procedure will be reflected in the
- string that was passed to the procedure.
-
- Important Note: Mixing String Types and Var Parameters
- Normally Turbo Pascal will permit mixing of different string types when
- they passed as variable parameters. For instance, if AString is defined as,
-
- var AString : String[30];
-
- then,
-
- StringDemo( AString );
-
- will result in an error because the parameter variable S is defined as type
- String, which is equivalent to String[255]. Normally, Turbo Pascal performs
- "strict type checking" on parameter strings. This means that the string type
- and length must be identical. However, you can disable strict type checking
- for var-parameter strings, by using the {$V-} directive to disable
- var-parameter string type checking. With {$V-} in effect, Turbo Pascal will
- allow you to mix different length strings for var-string parameters. You must
- insure that you do not inadvertently access portions of the string parameter
- that are out of bounds. See "Compiler Directives" later in this chapter for
- more information about the $V directive.
- Another standard method of passing strings as var parameters is to create
- a user defined type and then to use that type consistently for string
- variables. For instance,
-
- type
- String80 = String[80];
- var
- AString : String80;
- procedure P ( var StringParam : String80 );
- begin
- ...
- end;
-
- Now, when the statement P( AString) is executed, AString has exactly the same
- type P's StringParam parameter.
-
-
- Records as Parameters
- To pass a record structure as either a value or variable parameter
- requires that you create a user defined data type equivalent to the record's
- definition. Example:
-
- type
- TPersonInfo = record
- Name : String[30];
- Phone : String[14];
- Age : Integer;
- end;
- var
- PersonInfo : TPersonInfo;
-
- procedure P ( PersonRecord : TPersonInfo );
- begin
- ...
- end;
- ...
- P ( PersonInfo );
-
-
- Summary of Using Parameter Values and Variables
- To summarize, parameter variables define a list of local variables to the
- procedure, each of which is matched to a parameter value at the time the
- procedure is invoked. Parameter variables may be either value parameters or
- variable parameters. A value parameter may receive any expression, which will
- be evaluated at the time of the procedure call. A variable parameter must only
- receive another variable as its parameter, and may be used by a procedure to
- return a value to the procedure's caller.
- Structured data types must make use of a user defined type to specify the
- parameter's data type.
-
-
- The Procedure Body
- Syntax:
- <optional variable declarations>
- <optional procedure declarations>
- begin
- statements;
- end;
-
- Example:
- Listing 3.8. The DrawWindow procedure.
-
- Procedure DrawWindow (X1, Y1, X2, Y2 : Integer );
- { Draws a window for a menu or dialog. Essentially this declares
- a text viewport using the Turbo Window procedure and proceeds to
- draw a border "around" the window. In this case, the border
- occupies one character on all sides of the requested area.}
- Var
- Width : Integer;
- S : String[80];
- Y : Integer;
-
- Begin
- {Create Window area on the screen}
- Window (X1, Y1, X2, Y2+1);
- Width := X2-X1+1;
-
- {Draw border around the window}
- {First draw the top line across the window border}
- FillChar ( S, Width, Chr(196) );
- S[0] := Chr(Width);
- S[1] := Chr(218);
- S[Width] := Chr(191);
- WriteStr( 1, 1, S, LightGray, Black );
-
- {Next, Draw the sides of the window border}
- FillChar ( S, Width, ' ' );
- S[0] := Chr(Width);
- S[1] := Chr(179);
- S[Width] := Chr(179);
- For Y := 2 To Y2-Y1 Do
- WriteStr(1, Y, S, LightGray, Black );
-
- {Then Draw the bottom border}
- FillChar ( S, Width, Chr(196) );
- S[0] := Chr(Width);
- S[1] := Chr(192);
- S[Width] := Chr(217);
- WriteStr( 1, Y2-Y1+1, S, LightGray, Black);
- End;
-
- Description:
- The body of a procedure may contain additional identifier declarations,
- including local procedures and functions that are defined inside the procedure
- or function. Such identifiers, including sub-procedures or functions, are
- available for use solely within the scope of the outer procedure.
- The main body of the procedure consists of the keyword begin, followed by
- zero or more Pascal statements, and terminated by the keyword end. Listing 3.8
- presents a sample procedure DrawWindow, which displays a rectangular window on
- the screen, complete with a border. DrawWindow has 4 parameter variables, X1,
- Y1, and X2,Y2 which are integer values describing the screen coordinates of the
- upper left and lower right corner of the window. DrawWindow also has 3 local
- variables, Width, S, and Y. Both the parameters and the local variables are
- all local to procedure DrawWindow meaning that they are not defined nor
- available outside the procedure.
-
-
- Forward declared procedures
-
- Syntax:
- procedure <identifier> <parameter list>; forward;
- ...
- procedure <identifier>; <procedure body>
- or external or asm keywords.
-
- Example:
- The following is an illustration of a forward declared procedure named
- DoCommand. DoCommand is declared as forward because it must be called by the
- DoStatement procedure; however, DoCommand may also need to call DoStatement so
- it would not be possible to define either before the other except to make one a
- forward declared procedure.
-
- Listing 3.9. The use of forward declared procedures.
-
- procedure DoCommand ( TheCommand : Word ); forward;
-
- procedure DoStatement ( Location : Integer );
- begin
- ...
- if InputLine[Location]= '.' then
- DoCommand ( HitPeriod );
- end;
-
- procedure DoCommand;
- begin
- case TheCommand of
- OnStatement : DoStatement ( Location );
- HitPeriod : DoPeriod;
- ...
- end;
- end;
-
- Description:
- At times, a procedure identifier needs to be declared early in a program
- so that subsequently defined procedures can call it. However, since this
- procedure, in turn, needs to call other procedures that have not yet been
- defined, the main body of the procedure must be defined after the declaration
- of those procedures that it needs to use. Such a procedure is declared using
- the forward declaration instead of a procedure block. The actual
- implementation then appears later in the program or unit.
- The actual definition that appears later is not allowed to be another
- forward declaration, nor a near, far or inline declaration. However, it may
- contain the external or asm assembly language directives. Further, at the
- point that the forward declared procedure is actually implemented, it should
- not redefine the parameter list.
- In between the procedure's forward declared header and the subsequent
- procedure definition, other procedures and functions may be defined. In this
- way, procedures can be written that call each other as shown in Listing 3.9,
- above.
-
-
- Near and Far procedure call models
- Example:
- Example of a procedure declared using the far declaration. This example
- uses the Turbo Vision TCollection feature ForEach, which requires a pointer to
- a far procedure as a parameter, shown in the PhoneBook^.ForEach( @PrintEntry )
- statement.
-
- procedure PrintEntry( OneEntry : PPersonInfo ); far;
- begin
- with OneEntry^ do
- Writeln(Name,Address,City,State,Zip,Age);
- end; { PrintEntry }
-
- begin
- PhoneBook^.ForEach( @PrintEntry );
- end;
-
- Description:
- The 80x86 CPU architecture divides memory in to 64k byte chunks called
- segments. Procedures may be called within a segment or across segment
- boundaries. When a procedure call is made within a segment, it is a near
- procedure call. When a procedure call is made across segment boundaries, it is
- a far procedure call.
- A near procedure call requires fewer machine instructions, hence it
- requires less memory and executes slightly faster than a far call. However,
- near procedures can only be called from within the same module (or unit) that
- they are defined, while a far defined procedure can be called from any code
- module.
- Turbo Pascal automatically determines if a procedure or function should
- use the near or far call memory model. Normally, all procedures or functions
- declared in the Interface section of a program unit are far declared. All
- procedures or functions defined within the program or implementation section of
- a unit are near model calls.
- Using the near or far declarations, you can override the automatically
- determined procedure call type. Some examples of procedure or functions that
- you might override are:
-
- Procedures or functions which are themselves passed as variable
- parameters must be declared as far procedures.
-
- Overlay procedures (those that are swappable out of memory) must be far
- procedures.
-
- In addition to using the far directive, you can force the compiler to generate
- far calls for all procedures and functions by using the {$F+} compiler
- directive. The normal state is {$F-}, meaning that the compiler will
- automatically choose either near or far as appropriate. In the {$F+} state,
- the compiler will always generate far calls.
-
-
- Interrupt Procedures
- Interrupt declarations specify that the procedure is an interrupt handler
- procedure. Interrupt handlers in Turbo Pascal are fully explained in Chapter
- 11. The basic interrupt procedure must follow this format:
-
- procedure Handler
- (Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : Word);
- interrupt;
- begin
- ...
- end;
-
- The procedure header must be specified as shown, so that all of the CPU
- registers may be accessed as if they were parameter variables (even though the
- var keyword is not specified).
- Interrupt procedures should be activated only by an interrupt condition
- and cannot be called from within your Turbo Pascal program as if they were a
- normal procedure. Chapter 11 provides additional details and examples of
- interrupt procedures.
-
-
- Assembly language procedures: External, Inline and Asm
- Turbo Pascal provides 3 types of assembly language interfacing.
- Assembly language routines can be written and assembled using an
- external assembler such as Turbo Assembler, and then linked to your
- Turbo Pascal programs. Such routines are made visible to the Turbo
- Pascal code by defining a corresponding procedure or function header
- within your Turbo Pascal source and declaring it as external. The
- external assembly language routine is then linked from the assembled
- object module.
- Turbo Pascal contains a built-in assembler that let's you write complete
- assembly language routines without leaving the Turbo Pascal compiler.
- Such routines are written using the asm keyword.
- Lastly, you can embed values, such as machine code or data values
- directly into the generated code using the inline statement.
- Turbo Pascal's built-in assembly language features and the Turbo Assembler are
- described in Chapter 6, "Assembly Language Programming" in the Borland Pascal
- Developer's Guide, Que Books, 1992.
-