Object Pascal uses the ASCII character set, including the letters A through Z and a through z, the digits 0 through 9, and other standard characters. It is not case-sensitive. The space character (ASCII 32) and the control characters (ASCII 0 through 31--including ASCII 13, the return or end-of-line character) are called blanks.
Fundamental syntactic elements, called tokens, combine to form expressions, declarations, and statements. A statement describes an algorithmic action that can be executed within a program. An expression is a syntactic unit that occurs within a statement and denotes a value. A declaration defines an identifier (such as the name of a function or variable) that can be used in expressions and statements, and, where appropriate, allocates memory for the identifier.
On the simplest level, a program is a sequence of tokens delimited by separators. A token is the smallest meaningful unit of text in a program. A separator is either a blank or a comment. Strictly speaking, it is not always necessary to place a separator between two tokens; for example, the code fragment
Size:=20;Price:=10;
is perfectly legal. Convention and readability, however, dictate that we write this as
Size := 20; Price := 10;
Tokens are categorized as special symbols, identifiers, reserved words, directives, numerals, labels, and character strings. A separator can be part of a token only if the token is a character string. Adjacent identifiers, reserved words, numerals, and labels must have one or more separators between them.
Special symbols are non-alphanumeric characters, or pairs of such characters, that have fixed meanings. The following single characters are special symbols.
# $ & ' ( ) * + , - . / : ; < = > @ [ ] ^ { }
The following character pairs are also special symbols.
(* (. *) .) .. // := <= >= < >
The left bracket -- [ -- is equivalent to the character pair of left parenthesis and period -- (. ; the right bracket -- ] -- is equivalent to the character pair of period and right parenthesis -- .) . The left-parenthesis-plus-asterisk and asterisk-plus-right-parenthesis -- (* *) -- are equivalent to the left and right brace -- { } .
Notice that !, " (double quotation marks), %, ?, \, _ (underscore), | (pipe), and ~ (tilde) are not special characters.
Identifiers denote constants, variables, fields, types, properties, procedures, functions, programs, units, libraries, and packages. An identifier can be of any length, but only the first 255 characters are significant. An identifier must begin with a letter or an underscore (_) and cannot contain spaces; letters, digits, and underscores are allowed after the first character. Reserved words cannot be used as identifiers.
Since Object Pascal is case-insensitive, an identifier like CalculateValue could be written in any of these ways:
CalculateValue calculateValue calculatevalue CALCULATEVALUE
When you use an identifier that has been declared in more than one place, it is sometimes necessary to qualify the identifier. The syntax for a qualified identifier is
where identifier1 qualifies identifier2. For example, if two units each declare a variable called CurrentValue, you can specify that you want to access the CurrentValue in Unit2 by writing
Unit2.CurrentValue
Qualifiers can be iterated. For example,
Form1.Button1.Click
calls the Click method in Button1 of Form1.
If you don't qualify an identifier, its interpretation is determined by the rules of scope described in "Blocks and scope".
The following reserved words cannot be redefined or used as identifiers.
In addition to the words in Table 4.1, private, protected, public, published, and automated act as reserved words within object type declarations, but are otherwise treated as directives. The words at and on also have special meanings.
Directives have special meanings in Object Pascal, but, unlike reserved words, appear only in contexts where user-defined identifiers cannot occur. Hence--although it is inadvisable to do so--you can define an identifier that looks exactly like a directive.
Integer and real constants can be represented in decimal notation as sequences of digits without commas or spaces, and prefixed with the + or - operator to indicate sign. Values default to positive (so that, for example, 67258 is equivalent to +67258) and must be within the range of the largest predefined real or integer type.
Numerals with decimal points or exponents denote reals, while other numerals denote integers. When the character E or e occurs within a real, it means "times ten to the power of". For example, 7E-2 means 7 × 10-2, and 12.25e+6 and 12.25e6 both mean 12.25 × 106.
The dollar-sign prefix indicates a hexadecimal numeral--for example, $8F. Hexadecimals must be within the range $00000000 to $FFFFFFFF. The sign of a hexadecimal is determined by the leftmost (most significant) bit of its binary representation.
For more information about real and integer types, see Chapter 5, "Data types, variables, and constants." For information about the data types of numerals, see "True constants".
A label is a sequence of no more than four digits--that is, a numeral between 0 and 9999. Leading zeros are not significant. Identifiers can also function as labels.
Labels are used in goto statements. For more information about goto statements and labels, see "Goto statements".
A character string, also called a string literal or string constant, consists of a quoted string, a control string, or a combination of quoted and control strings. Separators can occur only within quoted strings.
A quoted string is a sequence of up to 255 characters from the extended ASCII character set, written on one line and enclosed by apostrophes. A quoted string with nothing between the apostrophes is a null string. Two sequential apostrophes in a quoted string denote a single character, namely an apostrophe. For example,
'BORLAND' { BORLAND }
'You''ll see' { You'll see }
'''' { ' }
'' { null string }
' ' { a space }
A control string is a sequence of one or more control characters, each of which consists of the # symbol followed by an unsigned integer constant from 0 to 255 (decimal or hexadecimal) and denotes the corresponding ASCII character. The control string
#89#111#117
is equivalent to the quoted string
'You'
You can combine quoted strings with control strings to form larger character strings. For example, you could use
'Line 1'#13#10'Line 2'
to put a carriage-return-line-feed between "Line 1" and "Line 2". However, you cannot concatenate two quoted strings in this way, since a pair of sequential apostrophes is interpreted as a single character. (To concatenate quoted strings, use the + operator described in "String operators", or simply combine them into a single quoted string.)
A character string's length is the number of characters in the string. A character string of any length is compatible with any string type, and with the PChar type when extended syntax is enabled ({$X+}). A character string of length 1 is compatible with any character type, and a character string of length n > 0 is compatible with packed arrays of n characters. For more information about string types, see "Data types, variables, and constants."
Comments are ignored by the compiler, except when they function as separators (delimiting adjacent tokens) or compiler directives.
There are several ways to construct comments:
{ Text between a left brace and a right brace constitutes a comment. }
(* Text between a left-parenthesis-plus-asterisk and an
asterisk-plus-right-parenthesis also constitutes a comment. *)
// Any text between a double-slash and the end of the line constitutes a comment.
A comment that contains a dollar sign ($) immediately after the opening { or (* is a compiler directive. For example,
{$WARNINGS OFF}
tells the compiler not to generate warning messages.
An expression is a construction that returns a value. For example,
X { variable }
@X { address of a variable }
15 { integer constant }
InterestRate { variable }
Calc(X,Y) { function call }
X * Y { product of X and Y }
Z / (1 - Z) { quotient of Z and (1 - Z) }
X = 1.5 { Boolean }
C in Range1 { Boolean }
not Done { negation of a Boolean }
['a','b','c'] { set }
Char(48) { value typecast }
The simplest expressions are variables and constants (described in "Data types, variables, and constants"). More complex expressions are built from simpler ones using operators, function calls, set constructors, indexes, and typecasts.
Operators behave like predefined functions that are part of the Object Pascal language. For example, the expression (X + Y) is built from the variables X and Y--called operands--with the + operator; when X and Y represent integers or reals, (X + Y) returns their sum. Operators include @, not, ^, *, /, div, mod, and, shl, shr, as, +, -, or, xor, =, >, <, <>, <=, >=, in, and is.
The operators @, not, and ^ are unary (taking one operand). All other operators are binary (taking two operands), except that + and - can function as either unary or binary. A unary operator always precedes its operand (for example, -B), except for ^, which follows its operand (for example, P^). A binary operator is placed between its operands (for example, A = 7).
Some operators behave differently depending on the type of data passed to them. For example, not performs bitwise negation on an integer operand and logical negation on a Boolean operand. Such operators appear below under multiple categories.
Except for ^, is, and in, all operators can take operands of type Variant. For details, see "Variant types".
The sections that follow assume some familiarity with Object Pascal data types. For information about data types, see "Data types, variables, and constants."
For information about operator precedence in complex expressions, see "Operator precedence rules".
Arithmetic operators, which take real or integer operands, include +, -, *, /, div, and mod.
The following rules apply to arithmetic operators.
The Boolean operators not, and, or, and xor take operands of any Boolean type and return a value of type Boolean.
These operations are governed by standard rules of Boolean logic. For example, an expression of the form x and y is True if and only if both x and y are True.
The Delphi compiler supports two modes of evaluation for the and and or operators: complete evaluation and short-circuit (partial) evaluation. Complete evaluation means that each conjunct or disjunct is evaluated, even when the result of the entire expression is already determined. Short-circuit evaluation means strict left-to-right evaluation that stops as soon as the result of the entire expression is determined. For example, if the expression A and B is evaluated under short-circuit mode when A is False, the compiler won't evaluate B; it knows that the entire expression is False as soon as it evaluates A.
Short-circuit evaluation is usually preferable because it guarantees minimum execution time and, in most cases, minimum code size. Complete evaluation is sometimes convenient when one operand is a function with side effects that alter the execution of the program.
Short-circuit evaluation also allows the use of constructions that might otherwise result in illegal runtime operations. For example, the following code iterates through the string S, up to the first comma.
while (I <= Length(S)) and (S[I] <> ',') do begin ... Inc(I); end;
In a case where S has no commas, the last iteration increments I to a value which is greater than the length of S. When the while condition is next tested, complete evaluation results in an attempt to read S[I], which could cause a runtime error. Under short-circuit evaluation, in contrast, the second part of the while condition -- (S[I] <> ',') -- is not evaluated after the first part fails.
Use the $B compiler directive to control evaluation mode. The default state is {$B-}, which enables short-circuit evaluation. To enable complete evaluation locally, add the {$B+} directive to your code. You can also switch to complete evaluation on a project-wide basis by selecting Complete Boolean Evaluation in the Compiler Options dialog.
The following logical operators perform bitwise manipulation on integer operands. For example, if the value stored in X (in binary) is 001101 and the value stored in Y is 100001, the statement
Z := X or Y;
assigns the value 101101 to Z.
The following rules apply to bitwise operators.
N shl 1 returns 11010 (decimal 26).
The relational operators =, <>, <, >, <=, and >= all take string operands (see "Relational operators"). The + operator concatenates two strings.
The following rules apply to string concatenation.
The relational operators <, >, <=, and >= can take operands of type PChar (see "Relational operators"). The following operators also take pointers as operands. For more information about pointers, see "Pointers and pointer types".
The ^ operator dereferences a pointer. Its operand can be a pointer of any type except the generic Pointer, which must be typecast before dereferencing.
P = Q is True just in case P and Q point to the same address; otherwise, P <> Q is True.
You can use the + and - operators to increment and decrement the offset of a character pointer. You can also use - to calculate the difference between the offsets of two character pointers. The following rules apply.
The following operators take sets as operands.
The following rules apply to +, -, and *.
The following rules apply to <=, >=, =, <>, and in.
Relational operators are used to compare two operands. The operators =, <>, <=, and >= also apply to sets (see "Set operators"); = and <> also apply to pointers (see "Pointer operators").
simple, class, class reference, interface, string, packed string | ||||
simple, class, class reference, interface, string, packed string | ||||
For most simple types, comparison is straightforward. For example, I = J is True just in case I and J have the same value, and I <> J is True otherwise. The following rules apply to relational operators.
The operators as and is take classes and instance objects as operands; as operates on interfaces as well. For more information, see "Classes and objects" and Chapter 10, "Object interfaces."
The relational operators = and <> also operate on classes. See "Relational operators".
The @ operator returns the address of a variable, or of a function, procedure, or method; that is, @ constructs a pointer to its operand. For more information about pointers, see "Pointers and pointer types". The following rules apply to @.
@TMyClass.DoSomething
points to the DoSomething method of TMyClass. For more information about classes and methods, see "Classes and objects."
In complex expressions, rules of precedence determine the order in which operations are performed.
An operator with higher precedence is evaluated before an operator with lower precedence, while operators of equal precedence associate to the left. Hence the expression
X + Y * Z
multiplies Y times Z, then adds X to the result; * is performed first, because is has a higher precedence than +. But
X - Y + Z
first subtracts Y from X, then adds Z to the result; - and + have the same precedence, so the operation on the left is performed first.
You can use parentheses to override these precedence rules. An expression within parentheses is evaluated first, then treated as a single operand. For example,
(X + Y) * Z
multiplies Z times the sum of X and Y.
Parentheses are sometimes needed in situations where, at first glance, they seem not to be. For example, consider the expression
X = Y or X = Z
The intended interpretation of this is obviously
(X = Y) or (X = Z)
Without parentheses, however, the compiler follows operator precedence rules and reads it as
(X = (Y or X)) = Z
--which results in a compilation error unless Z is Boolean.
Parentheses often make code easier to write and to read, even when they are, strictly speaking, superfluous. Thus the first example above could be written as
X + (Y * Z)
Here the parentheses are unnecessary (to the compiler), but they spare both programmer and reader from having to think about operator precedence.
Because functions return a value, function calls are expressions. For example, if you've defined a function called Calc that takes two integer arguments and returns an integer, then the function call Calc(24, 47) is an integer expression. If I and J are integer variables, then I + Calc(J, 8) is also an integer expression. Examples of function calls include
Sum(A, 63) Maximum(147, J) Sin(X + Y) Eof(F) Volume(Radius, Height) GetValue TSomeObject.SomeMethod(I,J);
For more information about functions, see "Procedures and functions."
A set constructor denotes a set-type value. For example,
[5, 6, 7, 8]
denotes the set whose members are 5, 6, 7, and 8. The set constructor
[ 5..8 ]
could also denote the same set.
The syntax for a set constructor is
where each item is either an expression denoting an ordinal of the set's base type or a pair of such expressions with two dots (..) in between. When an item has the form x..y, it is shorthand for all the ordinals in the range from x to y, inclusive; but if x is greater than y, then x..y denotes nothing and [x..y] is the empty set. The set constructor [ ] denotes the empty set, while [x] denotes the set whose only member is the value of x.
[red, green, MyColor] [1, 5, 10..K mod 12, 23] ['A'..'Z','a'..'z', Chr(Digit + 48)]
For more information about sets, see "Sets".
Strings, arrays, array properties, and pointers to strings or arrays can be indexed. For example, if FileName is a string variable, the expression FileName[3] returns the third character in the string denoted by FileName, while FileName[I + 1] returns the character immediately after the one indexed by I. For information about strings, see "String types". For information about arrays and array properties, see "Arrays" and "Array properties".
It is sometimes useful to treat an expression as if it belonged to different type. A typecast allows you to do this by, in effect, temporarily changing an expression's type. For example, Integer('A') casts the character A as an integer.
If the expression is a variable, the result is called a variable typecast; otherwise, the result is a value typecast. While their syntax is the same, different rules apply to the two kinds of typecast.
In a value typecast, the type identifier and the cast expression must both be ordinal types or both be pointer types. Examples of value typecasts include
Integer('A')
Char(48)
Boolean(0)
Color(2)
Longint(@Buffer)
The resulting value is obtained by converting the expression in parentheses. This may involve truncation or extension if the size of the specified type differs from that of the expression. The expression's sign is always preserved.
I := Integer('A');
assigns the value of Integer('A')--that is, 65--to the variable I.
A value typecast cannot be followed by qualifiers and cannot appear on the left side of an assignment statement.
You can cast any variable to any type, provided their sizes are the same and you do not mix integers with reals. (To convert numeric types, rely on standard functions like Int and Trunc.) Examples of variable typecasts include
Char(I) Boolean(Count) TSomeDefinedType(MyVariable)
Variable typecasts can appear on either side of an assignment statement. Thus
var MyChar: char; ... Shortint(MyChar) := 122;
assigns the character z (ASCII 122) to MyChar.
You can cast variables to a procedural type. For example, given the declarations
type Func = function(X: Integer): Integer; var F: Func; P: Pointer; N: Integer;
you can make the following assignments.
F := Func(P); { Assign procedural value in P to F }
Func(P) := F; { Assign procedural value in F to P }
@F := P; { Assign pointer value in P to F }
P := @F; { Assign pointer value in F to P }
N := F(N); { Call function via F }
N := Func(P)(N); { Call function via P }
Variable typecasts can also be followed by qualifiers, as illustrated in the following example.
type
TByteRec = record
Lo, Hi: Byte;
end;
TWordRec = record
Low, High: Word;
end;
PByte = ^Byte;
var
B: Byte;
W: Word;
L: Longint;
P: Pointer;
begin
W := $1234;
B := TByteRec(W).Lo;
TByteRec(W).Hi := 0;
L := $01234567;
W := TWordRec(L).Low;
B := TByteRec(TWordRec(L).Low).Hi;
B := PByte(L)^;
end;
In this example, TByteRec is used to access the low- and high-order bytes of a word, and TWordRec to access the low- and high-order words of a long integer. You could call the predefined functions Lo and Hi for the same purpose, but a variable typecast has the advantage that it can be used on the left side of an assignment statement.
For information about typecasting pointers, see "Pointers and pointer types". For information about casting class and interface types, see "The as operator" and "Interface typecasts".
Aside from the uses clause (and reserved words like implementation that demarcate parts of a unit), a program consists entirely of declarations and statements, which are organized into blocks.
The names of variables, constants, types, fields, properties, procedures, functions, programs, units, libraries, and packages are called identifiers. (Numeric constants like 26057 are not identifiers.) Identifiers must be declared before you can use them; the only exceptions are a few predefined types, routines, and constants that the compiler understands automatically, the variable Result when it occurs inside a function block, and the variable Self when it occurs inside a method implementation.
A declaration defines an identifier and, where appropriate, allocates memory for it. For example,
var Size: Extended;
declares a variable called Size that holds an Extended (real) value, while
function DoThis(X, Y: string): Integer;
declares a function called DoThis that takes two strings as arguments and returns an integer. Each declaration ends with a semicolon. When you declare several variables, constants, types, or labels at the same time, you need only write the appropriate reserved word once:
var Size: Extended; Quantity: Integer; Description: string;
The syntax and placement of a declaration depend on the kind of identifier you are defining. In general, declarations can occur only at the beginning of a block or at the beginning of the interface or implementation section of a unit (after the uses clause). Specific conventions for declaring variables, constants, types, functions, and so forth are explained in the chapters on those topics.
Statements define algorithmic actions within a program. Simple statements--like assignments and procedure calls--can combine to form loops, conditional statements, and other structured statements.
Multiple statements within a block, and in the initialization or finalization section of a unit, are separated by semicolons.
A simple statement doesn't contain any other statements. Simple statements include assignments, calls to procedures and functions, and goto jumps.
An assignment statement has the form
where variable is any variable reference--including a variable, variable typecast, dereferenced pointer, or component of a structured variable--and expression is any assignment-compatible expression. (Within a function block, variable can be replaced with the name of the function being defined. See "Procedures and functions.") The := symbol is sometimes called the assignment operator.
An assignment statement replaces the current value of variable with the value of expression. For example,
I := 3;
assigns the value 3 to the variable I. The variable reference on the left side of the assignment can appear in the expression on the right. For example,
I := I + 1;
increments the value of I. Other assignment statements include
X := Y + Z; Done := (I >= 1) and (I < 100); Hue1 := [Blue, Succ(C)]; I := Sqr(J) - I * K; Shortint(MyChar) := 122; TByteRec(W).Hi := 0; MyString[I] := 'A'; SomeArray[I + 1] := P^; TMyObject.SomeProperty := True;
A procedure call consists of the name of a procedure (with or without qualifiers), followed by a parameter list (if required). Examples include
PrintHeading;
Transpose(A, N, M);
Find(Smith, William);
Writeln('Hello world!');
DoSomething();
Unit1.SomeProcedure;
TMyObject.SomeMethod(X,Y);
Function calls, like calls to procedures, can be treated as statements in their own right:
MyFunction(X);
When you use a function call in this way, its return value is discarded.
For more information about procedures and functions, see "Procedures and functions."
A goto statement, which has the form
transfers program execution to the statement marked by the specified label. To mark a statement, you must first declare the label. Then precede the statement you want to mark with the label and a colon:
You can declare several labels at once:
A label can be any valid identifier or any numeral between 0 and 9999.
The label declaration, marked statement, and goto statement must belong to the same block. (See "Blocks and scope".) Hence it is not possible to jump into or out of a procedure or function. Do not mark more than one statement in a block with the same label.
label StartHere; ... StartHere: Beep; goto StartHere;
creates an infinite loop that calls the Beep procedure repeatedly.
The goto statement is generally discouraged in structured programming. It is, however, sometimes used as a way of exiting from nested loops, as in the following example.
procedure FindFirstAnswer;
var X, Y, Z, Count: Integer;
label FoundAnAnswer;
begin
Count := SomeConstant;
for X := 1 to Count do
for Y := 1 to Count do
for Z := 1 to Count do
if ... { some condition holds on X, Y, and Z } then
goto FoundAnAnswer;
... {code to execute if no answer is found }
Exit;
FoundAnAnswer:
... { code to execute when an answer is found }
end;
Notice that we are using goto to jump out of a nested loop. Never jump into a loop or other structured statement, since this can have unpredictable effects.
Structured statements are built from other statements. Use a structured statement when you want to execute other statements sequentially, conditionally, or repeatedly.
A compound statement is a sequence of other (simple or structured) statements to be executed in the order in which they are written. The compound statement is bracketed by the reserved words begin and end, and its constituent statements are separated by semicolons. For example:
begin Z := X; X := Y; Y := Z; end;
The last semicolon before end is optional. So we could have written this as
begin Z := X; X := Y; Y := Z end;
Compound statements are essential in contexts where Object Pascal syntax requires a single statement. In addition to program, function, and procedure blocks, they occur within other structured statements, such as conditionals or loops. For example:
begin
I := SomeConstant;
while I > 0 do
begin
...
I := I - 1;
end;
end;
You can write a compound statement that contains only a single constituent statement; like parentheses in a complex term, begin and end sometimes serve to disambiguate and to improve readability. You can also use an empty compound statement to create a block that does nothing:
begin end;
A with statement is a shorthand for referencing the fields of a record or the fields, properties, and methods of an object. The syntax of a with statement is
with obj1, ..., objn do statement
where obj is a variable reference denoting an object or record, and statement is any simple or structured statement. Within statement, you can refer to fields, properties, and methods of obj using their identifiers alone--without qualifiers.
For example, given the declarations
type TDate = record Day: Integer; Month: Integer; Year: Integer; end; var OrderDate: TDate;
you could write the following with statement.
with OrderDate do
if Month = 12 then
begin
Month := 1;
Year := Year + 1;
end
else
Month := Month + 1;
if OrderDate.Month = 12 then begin OrderDate.Month := 1; OrderDate.Year := OrderDate.Year + 1; end else OrderDate.Month := OrderDate.Month + 1;
If the interpretation of obj involves indexing arrays or dereferencing pointers, these actions are performed once, before statement is executed. This makes with statements efficient as well as concise. It also means that assignments to a variable within statement cannot affect the interpretation of obj during the current execution of the with statement.
Each variable reference or method name in a with statement is interpreted, if possible, as a member of the specified object or record. If there is another variable or method of the same name that you want to access from the with statement, you need to prepend it with a qualifier, as in the following example.
with OrderDate do
begin
Year := Unit1.Year
...
end;
When multiple objects or records appear after with, the entire statement is treated like a series of nested with statements. Thus
with obj1, obj2, ..., objn do statement
with obj1 do
with obj2 do
...
with objn do
statement
In this case, each variable reference or method name in statement is interpreted, if possible, as a member of objn; otherwise it is interpreted, if possible, as a member of objn-1; and so forth. The same rule applies to interpreting the objs themselves, so that, for instance, if objn is a member of both obj1 and obj2, it is interpreted as obj2.objn.
There are two forms of if statement: if...then and the if...then...else. The syntax of an if...then statement is
where expression returns a Boolean value. If expression is True, then statement is executed; otherwise it is not. For example,
if J <> 0 then Result := I/J;
The syntax of an if...then...else statement is
if expression then statement1 else statement2
where expression returns a Boolean value. If expression is True, then statement1 is executed; otherwise statement2 is executed. For example,
if J = 0 then Exit else Result := I/J;
The then and else clauses contain one statement each, but it can be a structured statement. For example,
if J <> 0 then begin Result := I/J; Count := Count + 1; end else if Count = Last then Done := True else Exit;
Notice that there is never a semicolon between the then clause and the word else. You can place a semicolon after an entire if statement to separate it from the next statement in its block, but the then and else clauses require nothing more than a space or carriage return between them. Placing a semicolon immediately before else (in an if statement) is a common programming error.
A special difficulty arises in connection with nested if statements. The problem arises because some if statements have else clauses while others do not, but the syntax for the two kinds of statement is otherwise the same. In a series of nested conditionals where there are fewer else clauses than if statements, it may not seem clear which else clauses are bound to which ifs. Consider a statement of the form
if expression1 then if expression2 then statement1 else statement2;
There would appear to be two ways to parse this:
if expression1 then [ if expression2 then statement1 else statement2 ];
if expression1 then [ if expression2 then statement1 ] else statement2;
The compiler always parses in the first way. That is, in real code, the statement
if ... { expression1 } then
if ... { expression2 } then
... { statement1 }
else
... { statement2 } ;
if ... { expression1 } then
begin
if ... { expression2 } then
... { statement1 }
else
... { statement2 }
end;
The rule is that nested conditionals are parsed starting from the innermost conditional, with each else bound to the nearest available if on its left. To force the compiler to read our example in the second way, you would have to write it explicitly as
if ... { expression1 } then
begin
if ... { expression2 } then
... { statement1 }
end
else
... { statement2 } ;
The case statement provides a readable alternative to complex nested if conditionals. A case statement has the form
case selectorExpression of
caseList1: statement1;
...
caseListn: statementn;
end
where selectorExpression is any expression of an ordinal type (string types are invalid) and each caseList is one of the following:
7, True, 4 + 5 * 3, 'A', and Integer('A') can all be used as caseLists, but variables and most function calls cannot. (A few built-in functions like Hi and Lo can occur in a caseList. See "Constant expressions".)
, ..., itemn, where each item satisfies one of the criteria above.
Each value represented by a caseList must be unique in the case statement; subranges and lists cannot overlap. A case statement can have a final else clause:
case selectorExpression of
caseList1: statement1;
...
caseListn: statementn;
else
statement;
end
When a case statement is executed, at most one of its constituent statements is executed. Whichever caseList has a value equal to that of selectorExpression determines the statement to be used. If none of the caseLists has the same value as selectorExpression, then the statement in the else clause (if there is one) is executed.
case I of 1..5: Caption := 'Low'; 6..9: Caption := 'High'; 0, 10..99: Caption := 'Out of range'; else Caption := ''; end;
is equivalent to the nested conditional
if I in [1..5] then
Caption := 'Low'
else if I in [6..10] then
Caption := 'High'
else if (I = 0) or (I in [10..99]) then
Caption := 'Out of range'
else
Caption := '';
Other examples of case statements:
case MyColor of Red: X := 1; Green: X := 2; Blue: X := 3; Yellow, Orange, Black: X := 0; end; case Selection of Done: Form1.Close; Compute: CalculateTotal(UnitCost, Quantity); else Beep; end;
Loops allow you to execute a sequence of statements repeatedly, using a control condition or variable to determine when the execution stops. Object Pascal has three kinds of control loop: repeat statements, while statements, and for statements.
You can use the standard Break and Continue procedures to control the flow of a repeat, while, or for statement. Break terminates the statement in which it occurs, while Continue begins executing the next iteration of the sequence. For more information about these procedures, see the online Help.
The syntax of a repeat statement is
repeat statement1; ...; statementn; until expression
where expression returns a Boolean value. (The last semicolon before until is optional.) The repeat statement executes its sequence of constituent statements continually, testing expression after each iteration. When expression returns True, the repeat statement terminates. The sequence is always executed at least once because expression is not evaluated until after the first iteration.
Examples of repeat statements include
repeat
K := I mod J;
I := J;
J := K;
until J = 0;
repeat
Write('Enter a value (0..9): ');
Readln(I);
until (I >= 0) and (I <= 9);
A while statement is similar to a repeat statement, except that the control condition is evaluated before the first execution of the statement sequence. Hence, if the condition is false, the statement sequence is never executed.
The syntax of a while statement is
where expression returns a Boolean value and statement can be a compound statement. The while statement executes its constituent statement repeatedly, testing expression before each iteration. As long as expression returns True, execution continues.
Examples of while statements include
while Data[I] <> X do I := I + 1; while I > 0 do begin if Odd(I) then Z := Z * X; I := I div 2; X := Sqr(X); end; while not Eof(InputFile) do begin Readln(InputFile, Line); Process(Line); end;
A for statement, unlike a repeat or while statement, requires you to specify explicitly the number of iterations you want the loop to go through. The syntax of a for statement is
for counter := initialValue to finalValue do statement
for counter := initialValue downto finalValue do statement
The for statement assigns the value of initialValue to counter, then executes statement repeatedly, incrementing or decrementing counter after each iteration. (The for...to syntax increments counter, while the for...downto syntax decrements it.) When counter returns the same value as finalValue, statement is executed once more and the for statement terminates. In other words, statement is executed once for every value in the range from initialValue to finalValue. If initialValue is equal to finalValue, statement is executed exactly once. If initialValue is greater than finalValue in a for...to statement, or less than finalValue in a for...downto statement, then statement is never executed. After the for statement terminates, the value of counter is undefined.
For purposes of controlling execution of the loop, the expressions initialValue and finalValue are evaluated only once, before the loop begins. Hence the for...to statement is almost, but not quite, equivalent to this while construction:
begin
counter := initialValue;
while counter <= finalValue do
begin
statement;
counter := Succ(counter);
end;
end
The difference between this construction and the for...to statement is that the while loop re-evaluates finalValue before each iteration. This can result in noticeably slower performance if finalValue is a complex expression, and it also means that changes to the value of finalValue within statement can affect execution of the loop.
for I := 2 to 63 do
if Data[I] > Max then
Max := Data[I];
for I := ListBox1.Items.Count - 1 downto 0 do
ListBox1.Items[I] := UpperCase(ListBox1.Items[I]);
for I := 1 to 10 do
for J := 1 to 10 do
begin
X := 0;
for K := 1 to 10 do
X := X + Mat1[I, K] * Mat2[K, J];
Mat[I, J] := X;
end;
for C := Red to Blue do Check(C);
Declarations and statements are organized into blocks, which define local namespaces (or scopes) for labels and identifiers. Blocks allow a single identifier, such as a variable name, to have different meanings in different parts of a program. Each block is part of the declaration of a program, function, or procedure; each program, function, or procedure declaration has one block.
A block consists of a series of declarations followed by a compound statement. All declarations must occur together at the beginning of the block. So the form of a block is
declarations
begin
statements
end
The declarations section can include, in any order, declarations for variables, constants (including resource strings), types, procedures, functions, and labels. In a program block, the declarations section can also include one or more exports clauses (see "Dynamic-link libraries and packages").
For example, in a function declaration like
function UpperCase(const S: string): string; var Ch: Char; L: Integer; Source, Dest: PChar; begin ... end;
the first line of the declaration is the function heading and all of the succeeding lines make up the block. Ch, L, Source, and Dest are local variables; their declarations apply only to the UpperCase function block and override--in this block only--any declarations of the same identifiers that may occur in the program block or in the interface or implementation section of a unit.
An identifier, such as a variable or function name, can be used only within the scope of its declaration. The location of a declaration determines its scope. An identifier declared within the declaration of a program, function, or procedure has a scope limited to the block in which it is declared. An identifier declared in the interface section of a unit has a scope that includes any other units or programs that use the unit where the declaration occurs. Identifiers with narrower scope--especially identifiers declared in functions and procedures--are sometimes called local, while identifiers with wider scope are called global.
The rules that determine identifier scope are summarized below.
from the point where it is declared to the end of the current block, including all blocks enclosed within that scope. | |
from the point where it is declared to the end of the unit, and to any other unit or program that uses that unit. (See "Programs and units.") | |
the implementation section of a unit, but not within the block of any function or procedure | from the point where it is declared to the end of the implementation section. The identifier is available to any function or procedure within that implementation section. |
the definition of a record type (that is, the identifier is the name of a field in the record) | from the point of its declaration to the end of the field-type definition. (See "Records".) |
the definition of a class (that is, the identifier is the name of a property or method in the class) | from the point of its declaration to the end of the class-type definition, and also includes descendants of the class and the blocks of all methods in the class and its descendants. (See "Classes and objects.") |
When one block encloses another, the former is called the outer block and the latter the inner block. If an identifier declared in an outer block is redeclared in an inner block, the inner declaration overrides the outer one and determines the meaning of the identifier for the duration of the inner block. For example, if you declare a variable called MaxValue in the interface section of a unit, and then declare another variable with the same name in a function declaration within that unit, any unqualified occurrences of MaxValue in the function block are governed by the second, local declaration. Similarly, a function declared within another function creates a new, inner scope in which identifiers used by the outer function can be redeclared locally.
The use of multiple units further complicates the definition of scope. Each unit listed in a uses clause imposes a new scope that encloses the remaining units used and the program or unit containing the uses clause. The first unit in a uses clause represents the outermost scope and each succeeding unit represents a new scope inside the previous one. If two or more units declare the same identifier in their interface sections, an unqualified reference to the identifier selects the declaration in the innermost scope--that is, in the unit where the reference itself occurs, or, if that unit doesn't declare the identifier, in the last unit in the uses clause that does declare the identifier.
The System unit is used automatically by every program or unit. The declarations in System, along with the predefined types, routines, and constants that the compiler understands automatically, always have the outermost scope.
You can override these rules of scope and by-pass an inner declaration by using a qualified identifier (see "Qualified identifiers") or a with statement (see "With statements").
pubsweb@inprise.com
Copyright © 1999, Inprise Corporation. All rights reserved.
Otros Links de Interés:
Cocina - Videos - Juegos Gratis - Postales cachondas - Cine - Programas Gratis - Letras de Canciones
Listas de todos los Tutoriales Gratis. 1998- 2007 - -
Los
tutoriales y cursos aquí reunidos son una recopilación de los mejores encontrados en
Internet.
El crédito y copyright de los mismos si lo hubiere corresponde al autor de cada
uno de ellos.
Si tu tutorial o curso está aquí, y deseas darlo de baja de esta recopilación o
quieres añadir el tuyo,
envíanos un mensaje desde
aquí