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 shifts the bits of A to left the number of bits specified by the value of the . Example: 0000 0011 shl 3 produces 0001 1000 shr: A shr shifts the bits of A to right the number of bits specified by the value of the . 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 then or if then else 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: := ; 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 then and if then else 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: 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. 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 part of an if-then or if-then-else may itself contain additional if statements. For example, if condition1 then if condition2 then else 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 end else The case Statement Syntax: case of : ; : ; : ; ... else end; The else part is optional. 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 is any expression evaluating to a simple byte or word-sized result, such as an integer, word or char data type. The 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 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 := to do and for := downto do 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 . If the control variable is within the range specified by the and the , then the part is executed. The 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 do 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 until 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