JES: Just Educational Services

Jonathan E. Sisk's
Pick/BASIC: A Programmer's Guide

Chapter 6 - String-Handling Intrinsic Functions

Click to enlarge

In program example 4, more of the intrinsic functions are discussed, along with some programming techniques for optimizing program code. Topics, statements and functions covered include EQU, EQUATE, CHAR, COUNT, DCOUNT, SLEEP, SEQ, and STR.

Enter Programming Example 4, shown in Fig. 6-1.

THE EQUATE (EQU) STATEMENT

It is normal to place assignment statements at the beginning of the program. The EQUATE statement is also used to assign constants:

009 EQUATE ATTRIBUTE.MARK TO CHAR(254)
010 EQUATE VALUE.MARK TO (CHAR(253))
011 EQUATE SUB.VALUE.MARK TO CHAR(252)
012 EQUATE CLEAR.SCREEN TO CHAR(12)
013 EQUATE BELL TO CHAR(7)
014 EQUATE TRUE TO 1
015 EQUATE FALSE TO 0

Naturally, there are some technical differences between assignment and the EQUATE statement. For example, the statement

EQUATE BELL TO CHAR(7)

Does apparently the same thing as:

BELL = CHAR(7)

The net effect is the same; that is, the constant BELL is assigned the value of the decimal character 7. It may be used to generate an audible "beep" by using the statement:

PRINT BELL

Fig. 6-1. Program Example 4.

>ED BP EX.004
TOP
.I
001 * EX.004
002 * DEALING WITH DELIMITERS AND OTHER STRING FUNCTIONS
003 * mm/dd/yy: date last modified
004 * JES: author's initials
005 *
006 * DEFINE STANDARD CONSTANTS
007 *
008 PROMPT ":"
009 EQUATE ATTRIBUTE.MARK TO CHAR(254)
010 EQUATE VALUE.MARK TO CHAR(253)
011 EQUATE SUB.VALUE.MARK TO CHAR(252)
012 EQUATE CLEAR.SCREEN TO CHAR(12)
013 EQUATE BELL TO CHAR(7)
014 EQUATE TRUE TO 1
015 EQUATE FALSE TO 0
016 *
017 * GET SENTENCE FOR COUNT AND DCOUNT TEST
018 *
019 PRINT
020 PRINT "ENTER A SENTENCE OF ABOUT 10 TO 15 WORDS"
021 INPUT SENTENCE
022 IF SENTENCE = "QUIT" THEN STOP
023 *
024 * TRIM EXTRA SPACES FIRST
025 *
026 SENTENCE = TRIM(SENTENCE)
027 *
028* DETERMINE THE NUMBER OF SPACES
029 *
030 PRINT
031 PRINT "IN THE SENTENCE, "
032 PRINT SENTENCE
033 PRINT
034 PRINT " THERE ARE " : COUNT(SENTENCE," ") : " SPACES"
035 *
036 * DETERMINE THE NUMBER OF WORDS
037 *
038 PRINT
039 PRINT "AND, THERE ARE " : DCOUNT(SENTENCE," ") : " WORDS"
040 *
041 * PICK A NUMBER OF SECONDS TO SLEEP FOR...
042 PRINT "ENTER NUMBER OF SECONDS TO SLEEP" : ; INPUT NAPTIME

043 PRINT
044 PRINT "I'M NOW SLEEPING FOR " : NAPTIME : " SECONDS"
046 SLEEP NAPTIME ; * ZZZZZZZZZZZZ
047 *
048 * GET A CHARACTER FOR SEQ TEST
049 *
050 PRINT
051 PRINT "LET'S TEST THE SEQ FUNCTION. PRESS ANY KEY " :
052 INPUT KEY,1
053 PRINT "THE SEQ OF ": KEY: " IS ": SEQ(KEY)
054 PRINT
055 *
056 * GET A CHARACTER FOR THE STR TEST
057 *
058 PRINT
059 PRINT "ENTER CHARACTER TO PRINT IN STR FUNCTION" '
060 INPUT CHARACTER
061 IF CHARACTER = "QUIT" THEN STOP
062 *
063 * GET NUMBER OF TIMES TO PRINT
064 *
065 PRINT "ENTER NUMBER OF TIMES TO PRINT "
066 INPUT NUMBER.OF.TIMES
067 IF NUMBER.OF.TIMES = "QUIT" THEN STOP
068 *
069 * NOW SHOW THE FUNCTION
070 *
071 PRINT "HERE GOES..."
072 PRINT STR(CHARACTER,NUMBER.OF.TIMES)
073 END


The EQUATE and assignment statements are treated differently, however. The EQUATE form is more efficient than the assignment statement using the "=" (equals) sign. This is due to the fact that the EQU or EQUATE statement is interpreted during the compilation phase, where the CHAR(7) is evaluated and object (i.e., executable) code is generated for this constant. This also saves the overhead of maintaining a variable during runtime, since there is no run-time storage allocation for this constant. (This is also the way quoted constant text strings are handled.)

With the assignment form BELL=CHAR(7), evaluation occurs at runtime, and a small amount of overhead is required during the initialization phase of the program. Admittedly this overhead is hardly noticeable, but any time that there are opportunities to optimize programs, you should jump at the chance.

Using EQU or EQUATE also has what could be considered a down side. Once the constant has been assigned, it may not be changed later in the program. For example, if this instruction appeared near the top of the program:

EQU VALUE.MARK TO CHAR(253) 

and later in the program, this instruction appeared:

VALUE.MARK = CHAR(252) 

An error message will appear:

[B121] LABEL 'VALUE.MARK' IS A CONSTANT AND MAY NOT BE WRITTIEN INTO

The program stops, leaving you in the PICK/BASIC debugger.

Realistically speaking, you would never want to change the reference to VALUE.MARK anyway. That's why it's called a constant. After all, value marks are always value marks.

THE CHAR FUNCTION

The CHAR function converts a decimal integer into its ASCII equivalent. The ASCII character set is simply a standardized means of referring to the numeric, alphabetic, punctuation, and control characters. The same set of program lines that demonstrated the EQUATE statement in the preceding section also show the use of CHAR( ):

009 EQUATE ATTRIBUTE.MARK TO CHAR(254)
010 EQUATE VALUE.MARK TO CHAR(253)
011 EQUATE SUB.VALUE.MARK TO CHAR(252)
012 EQUATE CLEAR.SCREEN TO CHAR(12)
013 EQUATE BELL TO CHAR(7)

For example, the standard character to sound the "bell" in your terminal (and some printers) is Control-G. It would require entering a Control-G into a program to use it in program. Entering control characters directly into programs should always be avoided! The CHAR function takes care of this potential problem for you.

It is normal to see a series of assignment statements at the top of a program to define regularly used variables or constants. For instance:

BELL = CHAR(7)
or
EQUATE BELL TO CHAR(7)

When this is interpreted by the compiler, it figures out what the ASCII character equivalent of a decimal 7 is, and assigns it to the variable called BELL. Throughout the rest of the program, whenever a "beep" is needed, it may be performed with the following statement:

PRINT BELL

A bell also may be generated simply by issuing this statement:

PRINT CHAR(7)

However, it is generally considered more efficient to assign the constant BELL at the beginning of the program rather than referring to CHAR(7) every time it is required. This also tends to make the program more readable.

Example 4 illustrates the most commonly used constants in PICK/BASIC, listed in Fig. 6-2.

THE COUNT AND DCOUNT FUNCTIONS

The COUNT function was discussed in Example 2. It is used to determine and report the number of occurrences of a character (or character string) within another string.

This example asks you to enter a sentence of about 10 to 15 words. The COUNT function on line 34 displays the number of spaces in the sentence.

034 PRINT " THERE ARE " :COUNT(SENTENCE," ") :" SPACES"

Consider this, however: Since the space character is being used as a delimiter to separate words, is the number of spaces displayed an accurate count of the number of words in the sentence?

Probably not. The number of spaces is one less than the number of words in the sentence. This is an extremely important principle. When you are trying to determine the number of objects by counting the delimiters that normally separate these objects, an allowance has to be made for correcting the oversight. In other words, 1 (one) must be added to the final result, but only when the string being counted is not null. That brings us to the DCOUNT function:

039 PRINT  "AND, THERE ARE " :DCOUNT(SENTENCE," ") :" WORDS "

Constant name    Decimal equivalent  Assigned with
ATTRIBUTE.MARK       254                 CHAR(254)
VALUE.MARK           253                 CHAR(253)
SUB.VALUE.MARK       252                 CHAR(252)
CLEAR.SCREEN         12                  CHAR(12)
BELL                 7                   CHAR(7)
ESCAPE               27                  CHAR(27)

Fig. 6-2. Commonly used constants.




The DCOUNT function behaves exactly like the COUNT function, but with one minor difference: it corrects for the fact that the character being counted is being treated as a delimiter and adds 1 to the result. In other words, the DCOUNT function determines the number of data items delimited by the given string, where COUNT determines the number of occurrences of the given string.

This normally happens when counting the number of attributes in an item, or the number of values within an attribute, or the number of subvalues within a value. It returns a zero only when counting a null string. Figure 6-3 illustrates the various effects of the COUNT and DCOUNT functions. (Note that the "]" character represents a value mark.) Note also that this DCOUNT statement works correctly only because we trimmed the string (using TRIM) before performing the DCOUNT.

THE SLEEP STATEMENT

The SLEEP (or alternately RQM) statement is used to put a process "to sleep" for a certain period of time:

046 SLEEP NAPTIME	; * ZZZZZZZZZZZZ

This is useful for process control, like running a FILE-SAVE at a certain time, or when you feel like annoying your data entry operators. Note: Some implementations of Pick automatically disable the break key when the SLEEP statement is executed.


STRING          instruction                 Result
"abc]def]ghi"   COUNT(STRING,VALUE.MARK)    2
                DCOUNT(STRING,VALUE.MARK)   3

"abc]def"       COUNT(STRING,VALUE.MARK)    1
                DCOUNT(STRING,VALUE.MARK)   2

"abc"           COUNT(STRING,VALUE.MARK)    0
                DCOUNT(STRING,VALUE.MARK)   1
(null)          COUNT(STRING,VALUE.MARK)    0
                DCOUNT(STRING,VALUE.MARE)   0

Fig. 6-3. Effects of the COUNT and DCOUNT functions.


There are two ways to put a process to sleep. The first is when the numeric expression following the SLEEP statement contains a number. For instance:

SLEEP 300

The number defines, in seconds, the length of program inactivity. This statement tells the PICK/BASIC program to sleep for 5 minutes. The second form consists of making the expression following the SLEEP statement contain a time in "military" (24-hour) format. For example:

SLEEP 23:59

This leaves a wake-up call for 11:59 P.M.

NAPTIME=RND(10)+3

The RND (random) function is used in this example to generate a random number between 0 and 9, and then to add 3 to the result. This will set up in a naptime of 3 to 12 seconds. Don't worry about being quiet around a sleeping terminal. (It sometimes takes a system crash to wake them up.)

RESTRICTIONS ON THE INPUT STATEMENT

Normally when an INPUT statement is executed, up to 140 characters may be entered before pressing the Return key. The reason that 140 characters are allowed is because that happens to be the length of the Primary Input Buffer on most Pick systems. The INPUT statement also allows the name of the variable that receives input to be followed by an expression which evaluates to a number:

052 INPUT KEY,1

This indicates the maximum number of characters that will be accepted by the INPUT statement. What's more, when the designated number of characters is received, the program automatically issues a carriage return, whether or not the operator is ready.

In this example, the INPUT statement waited for one character to be entered prior to continuing execution. Any key which produces output is adequate. Some keys on the keyboard, like the Shift and Control keys, don't actually generate "output," so the INPUT statement is unable to detect that input has been provided. By the way, if you're looking for the "any" key, you won't find it. Simply press the space bar.

As a suggestion, don't use the length parameter because of the inconsistencies that it imposes on the operator. (Sometimes it does carriage returns for you, and sometimes it doesn't.)

THE SEQ FUNCTION

The SEQ function is exactly the opposite of the CHAR function covered earlier in this example. It produces the decimal equivalent of any ASCII character:

053 PRINT "THE SEQ OF " : KEY: " IS " : SEQ(KEY)

For example, if you were to press the "A" key on your keyboard at the "... PRESS ANY KEY "prompt, it prints the message that the sequence of "A" is 65. This function is useful for situations like determining if a control character has been entered. Control characters have decimal values in the range 1 to 31, and all characters above 127 are Pick control characters.

THE STR FUNCTION

The STR function is used to generate or print a string of characters of a predetermined length. In Program Example 4, line 72, it displays such a string based on operator input:

072 PRINT STR(CHARACTER,NUMBER.OF.TIMES)

If an asterisk and the number 20 had been entered at the appropriate prompts, line 72 would be equivalent to:

PRINT STR("*" ,20)

and a row of 20 asterisks would be sent to the screen or printer. This technique is much more efficient than printing the row of asterisks as a literal:

PRINT "********************"

If there's no other reason, at least you won't have to find a pencil and count the characters on your screen or program listing. It also saves object code space.

Admittedly, this is more a programmer efficiency technique than a program efficiency consideration. (Sometimes the issue of program maintenance efficiency overrides the run-time efficiency considerations.)

By the way, the STR function may be used to generate a string of spaces, just like the SPACE function. For example:

PRINT STR(" ",25) 

is the same as saying:

PRINT SPACE(25)

Using the STR function, however, is less efficient than the SPACE function when generating strings of spaces.

REVIEW QUIZ 4

  1. What advantage does the EQUATE statement have over an assignment statement using the "=" sign?
  2. Which of the following statements is more efficient?
        EQU CLEAR.SCREEN TO CHAR(12)
        CLEAR.SCREEN = CHAR(12)
    
  3. What is the difference between the COUNT and DCOUNT statements?
  4. What does the SLEEP statement do?
  5. What statement puts a process to sleep for 10 minutes?
  6. What statement puts a process to sleep until 5:30 P.M.?
  7. What does the SEQ function do?
  8. What does the STR function do?
  9. What instruction prints a row of 10 "-" (hyphen) characters?

Previous chapter Next chapter Top

 

Creative Commons License
Jonathan E. Sisk's "Pick/BASIC: A Programmer's Guide" by Jonathan E. Sisk is licensed under a Creative Commons Attribution 3.0 Unported License.
Based on a work at jes.com.