• Keine Ergebnisse gefunden

More on Expressions and Strings; the Expression, Case, and Empty Statements; Random Access to Files

8.S. Tables of Operations

10. More on Expressions and Strings; the Expression, Case, and Empty Statements; Random Access to Files

The expressions, statements, and system procedures introduced in this chapter are less

"fundamental" than those introduced in previous chapters. However, many of them provide syntactic convenience that greatly contributes to the readability of MAINSAIL programs.

Random access to files is not a syntactic convenience, but rather an essential input/output technique.

10.1. Procedure "BEGIN" and "END"

If a procedure consists of a single statement and has no local declarations, the "BEGIN" and

"END" bracketing the body of the procedure may be omitted. See Example 10.2-1.

10.2. The If Expression

The keyword "IF" may begin an expression as well as a statement. The fonn of an If Expression is:

IF <expression one> THEN <expression two> ELSE

<expression three>

If expression one has a non-Zero value for its data type, the value of the If Expression is the value of expression two; otherwise, it is the value of expression three. Expressions two and three must have the same data type~ which need not be the same as the data type of expression one.

If Expressions may be nested. The abbreviations "EF" and "EL" may be used in If Expressions, just as in If Statements.

The procedure "ack" of Example 7.4-1 can be written to use an If Expression inside its Return Statement, provided the code to check recursion qepth is removed. See Example 10.2-1;

compare the two versions of ack.

INTEGER PROCEDURE ack (INTEGER m,n) ; RETURN (

IF NOT m THEN n + 1

EF NOT n THEN ack(m - 1,1) EL ack(m - 1,ack(m,n - 1»);

Example 10.2-1. An If Expression inside a Return Statement

10.3. The Assignment Expression

An Assignment Expression has the same form as an Assignment Statement. The value of the expression is the same as the value assigned to the variable on the left side of the assignment operator and is of the same data type as that variable.

Assignment Expressions permit the use of "chain" or "multiple" assignments; see Example 10.3·1.

If a, b, and c are all integer variables, then:

a := b := c := 0

sets all three variables to have the value

O.

The statement could also be written as:

a := (b := (c :=

Example 10.3-1. Chain Assignments Using the Assignment Expression

The precedence of the assignment operator in an Assignment Expression is not quite the same as in an Assignment Statement. In the Assignment Statement, the assignment operator has a lower precedence than any other operator; in an Assignment Expression, it has a higher

precedence than the comparison operators, "NOT", "ANO", and "OR". See Example 10.3-2. If you find the precedence rules too confusing to remember, you may use redundant parentheses to specify the order of evaluation of expressions.

IF

v := el

OR

e2

THEN ...

is equivalent to:

IF (v := el) OR e2 THEN

...

NOT equivalent to:

IF v := (el OR e2) THEN

...

But the statement:

v := el OR e2i is equivalent to:

v

.=

(el OR e2) ;

Example 10.3-2. Precedence of the Assignment Operator in Expressions and Statements

10.4. Short-Circuit Evaluation

The operators "AND" and "OR" evaluate their second operands only if the first operand is non-Zero or non-Zero, respectively. That is, the "AND" or "OR" expression is evaluated only far enough to determine its value. If the first operand to "AND" is false, the entire expression is necessarily false, so the second operand need not be evaluated; likewise, if the first operand to

"OR" is true, the entire expression is true, regardless of the value of the second operand. This property of "AND'.' and "OR" is referred to as "short-circuit evaluation". See Example lOA-I.

The short-circuit evaluation of" AND" is particularly useful in connection with pointers; see Example 11.3-1.

10.5. Substrings

A substring is a string expression which, as the name implies, is calculated as a sequence of characters contained within another string. A substring is specified by giving the string of which the substring is to be taken, the starting position, and the ending position in the form:

<string> [ <start position> TO <end position> ]

Assume a procedure "lookUp" should be called for a string s only if s is not the null string. If s is

"", or if lookUp returns a Zero value, then action A should be taken; otherwise, some other action B should be taken. The code to do this looks like:

IF s AND lookUp(s) THENB

code for action B ... END EB ... code for action A ... END Note that lookUp is not called if s is ""

Example 10.4-1. The Use of Short-Circuit Evaluation

or the form:

<string> [ <start position> FOR <number of characters> ] The string may be any string expression. The positions are integers; the first position in a string is number one. The first form of substring specifies the end position absolutely; the second specifies it relative to the start position. Example 10.5-1 shows an example of the second form.

Other examples of both forms appear in the "MAINSAIL Language Manual" and Example 16.4-1.

One way to see if a string begins with a certain sequence of characters is to use 'a substring. The following code checks to see whether a string s begins with "new file" (ignoring case) :

IF cvu(s) [1 FOR length ("NEW FILE")]

=

"NEW FILE" ...

Example 10.5-1. A Common Use of Substrings

"INF" is a special integer expression that may appear only within substring brackets. It represents the length of the string of which the substring is taken. For example. "s[1 TO INF -2]" represents the string that is s with its last two characters removed.

10.6. String Comparison

Strings may be (and frequently are) compared with the standard comparison operators "=",

"NEQ", ">", "<", "GEQ", and "LEQ". However, there are some circumstances in which it is more efficient to call the system procedure "compare" or the system procedure "equ".

"compare(r,s)" , where rand s are strings, returns -1 if r < s, 0 if r = s, and 1 if r > s. If a program needs to do something different in each of the three cases, compare may be called just once, whereas at least two of the standard comparison operators would have to be called to achieve the same end. See Example 10.6-1.

Assume rand s are strings and i an integer variable.

Then the code:

IF (i "= compare(r,s» < 0 THENB

...

code for r < s. " . END EF i

=

0 THENB

code for r

=

s ... END

EB

· .

" code for r > s ... END

achieves the same thing as:

IF r < s THENB

· .

" code for r

<

s ... END

EF r

=

s THENB

code for r

=

s. " . END EB

· ..

code for r > s ... END

However, the first e~ample calls compare only once, whereas the second example uses

n<n

once and

n="

once.

Since "compare", "<", and

n="

all result in approximately the same execution overhead, the first example is more efficient. If you feel that the second example is more legible and that execution efficiency is not important, then use the second form; otherwise, use the first form.

Example 10.6-1. The Procedure "compare" and the Comparison Operators

"compare(r,s,upperCase)" performs a caseless comparison by first converting rand s to upper case. It is more efficient than doing the case conversion explicitly, i.e., than

"compare(cvu(r),cvu(s»" .

The procedure equ checks for equality only. "equ(r,s)"returns true if "compare(r,s)" returns 0;

"equ(r,s,upperCase)" returns true if "compare(r,s,upperCase)" returns O. equ is not more efficient than "=" unless the upperCase bit is specified. Most programmers prefer "=" to equ if the upperCase option is not specified, since they feel the former is easier to understand.

Using equ, the code in Example 10.5-1 could be written more efficiently as:

IF equ(s[l FOR length("NEW FILE")],"NEW FILE", upperCase) ...

10.7. The Procedure "scan"

The procedure "scan" is used to remove a prefix of a string based on the characters in the string.

The form of "scan" in which the scanCtrl parameter is a string is the only form described here.

For some purposes, the forms in which the scanCtrl is an integer or a bits are more efficient;

these forms are described in the "MAINSAIL Language Manual". "scan" may be used to read characters from a file as well as string; details may be found in the "MAINSAIL Language Manual".

The declaration of the form of "scan" discussed here is shown in Figure 10.7-1.

STRING PROCEDURE scan (MODIFIES STRING source;

STRING scanCtrl;

OPTIONAL BITS ctrlBits;

PRODUCES OPTIONAL INTEGER brkChr)

"scan" is actually a generic procedure. Consult the

"MAINSAIL Language Manual" for details.

"Figure 10.7-1. Declaration of the Procedure "scan"

If neither optional parameter is specified, "scan" breaks the source string into two parts. It looks for the first character in source that is the same as one of the characters in scanCtrl; this character is called the "break character". The portion of source up to the break character is returned by "scan"; the remainder of the string is left in the changed value of source. For example, if the string variable s has the value:

"Hello, there"

then "scan(s," ,")" returns "Hello" and changes the value of s to:

If,

there"

The break character is returned in the parameter brkChr. In this case, the break character is ",".

If no character is found that matches a character in scanCtrl, "scan" returns the entire source string, sets source to "", and returns -1 for brkChr.

The parameter ctrlBits may be used to specify the options shown in Figure 10.7-2. Other options exist but are more rarely used; see the "MAINSAll.. Language Manualtt

Control Bit Name proceed

discard

append

omit

Meaning

Instead of scanning up to a break character that is in scanCtrl,

"scan" scans for the first character NOT in scanCtrl.

Remove the break character from source before returning.

Remove the break character from source and append i t to the returned string.

Discard characters scanned; i.e., the result string is always "H.

This is more efficient if the result string is not to be used.

Figure 10.7-2. Named Control Bits for ttscantt

Using ttscan", the procedure ttgetTokentt of Example 7.2.2-2 could be rewritten as shown in Example 10.7-3. Note that the second call to ttscantt removes no characters from s and returns the null string if s does not begin with a digit.