Jonathan E. Sisk's
Pick/BASIC: A Programmer's Guide
Chapter 1 - Pick Terminology and Concepts
The Pick System uses terms to define itself that are unique in the data processing world. Most of these terms are defined the first time they are mentioned, and a glossary of these and other Pick terms is found among the appendices.
ACCOUNTS AND FILES
Accounts are collections of logically related files, much like departments within a company. Each department has its own set of file cabinets. The name of the account is entered at the "LOGON PLEASE:" message to gain access to the system.
Files are collections of logically related items, much as a file cabinet contains file folders made up of similar types of information. For example, one file cabinet may hold file folders which contain information about your customers, while another cabinet may hold the folders for your suppliers. In the Pick System, the number of items that may be put into a file is only limited by the capacity of the disk.
PICK/BASIC programs, each of which is considered an item, are stored in a file commonly called BP. Note that BP (short for "Basic Programs") is used as a convention only; as with all files, the filename is free-form.
The Pick System gains much of its elegance from the fact that it has only one file structure available. It is known as a random access file structure because records physically reside in the file in random order. The Pick System is excellent for developing on-line, interactive application systems, since accessing data from files is very fast and independent of the size of the file.
An item is a collection of logically related attributes or fields. (Other computer systems typically call this a "record. ") For example, an item in the CUSTOMER-FILE might contain the name and address for a customer. All the items in the same file are typically formatted in a similar manner. For example, the first attribute in each item might be the customer's name, the second attribute might be the address, and so on.
The method by which Pick manages items is unique. Quite simply, any item in the Pick System is a collection, or string, of characters. Pick uses the ASCII1 coding scheme for representing characters. This character set represents 256 unique characters. Since the upper- and lowercase alphabet, numbers, punctuation, and control characters barely use up the first 128 characters, there are plenty of unused characters available for other purposes. Recognizing this fact, the Pick System uses the last four positions in the ASCII coding scheme, numbered 252 through 255, as special characters to be used by the file system. (Computers generally begin counting at zero, which explains why the last four characters are 252 through 255, rather than 253 through 256.)
Since the Pick System treats each item as a string of characters, there is no concept of "type" of fields. Other systems store data differently depending on the type of the data. The primary "types" of data on other systems are numeric (binary, floating-point decimal, Comp-l, Comp-3, packed decimal, etc.) and character fields, used for storing names and other string-type data.
Each item must have its own unique identifier. This is called its id, (pronounced "eye-dee" in most of the world, and "ahh-deee" in Texas) or item-M. This is often referred to by some as the "key," and by others as the "primary key." The item-id may be virtually any combination of alphabetic, numeric and (most) punctuation characters. Those characters that may not be used are: space ( ) .... ", and any control character. Choosing the item-id for items is not a trivial process. How the item-id is structured has a significant effect on how the item-id "hashes" to a file. A discussion of this selection process is presented in Chapter 13.
The Relationship of Files and Items
It might be helpful to consider the method by which Pick has implemented its file structures, and to see how items fit into this scheme. Each item ('record') that is placed into a file must also have a unique item-id, or key. This item-id is then hashed, or internally massaged to calculate the storage location where the item is to be placed. To retrieve an item, the unique item-id must be provided to the process, which then hashes it once again to the same location. This requires that the item-id be logical or easily known, because if you don't know the item-id, you can't get to an individual item. There are facilities provided to access the entire file, or even a "selected" subset, if the item-id is not known.
It is important to emphasize that since there is only one file structure in the Pick System, it is used not only by programmers, developers, and users, but by the operating system itself. This is both very powerful and vastly different from other operating system environments that provide their users/programmers with multiple file structures for the use of data and a different set of hidden file structures for use by the operating system or its various utilities.
In the Pick System, all files and items are accessible. From the data files up to the system files, everything is available to the user/programmer, who can greatly enhance the functionality of the system.
ATTRIBUTES, VALUES, AND SUB-VALUES
An attribute (which some people call a "field' ') is an object or a collection of logically related objects, like an address or list of addresses, within an item. In the Pick System, these objects are typically referred to as values.
For example, if there were an item called "100" in a file called CUSTOMER-FILE, and you were to display it by copying it to the terminal, it would appear as shown in Fig. 1-1. From visual inspection, it is apparent that the item has five attributes. All of the attributes have only one value, with the exception of second, which has two values, both of which are separated by a special "reserved" character called a value mark. It is displayed as a right-hand square bracket. Note that each value is similar in nature. That is, they are both addresses, but there must be a way to separate them. That's where multi-values come into use. There may be as many separate values as needed in an attribute, provided that each is separated by a value mark. This allows treatment of each value as one entity.
Values may, in turn, be broken up into multiple sub-values. The special reserved character to separate sub-values is called, creatively enough, a sub-value mark. It is displayed as a backslash ( \ ). There will be more about values and sub-values in Chapter 13, which discusses array management.
Each line number (along the left side of the screen) corresponds to an attribute. When writing programs in PICK/BASIC, each attribute must contain a legal statement or expression (i.e., no blank lines).
>COPY CUSTOMER-FILE 100 (T) <cr>
100 Item id 00l HAPPY CAMPERS MOTOR LODGE Attribute 1 002 2600 MOOSE STREET]P.O. BOX 1777 Attribute 2 003 EAST OVERSHOE Attribute 3 004 MN Attribute 4 005 80808 Attribute 5
Fig. 1-1. Sample display of an item.
WHY A VARIABLE-LENGTH ITEM STRUCTURE?
An attribute, or field, in a Pick item is merely a string of characters within an item that also is a string of characters. Pick distinguishes one attribute from another by attaching one of the special reserved characters previously mentioned to the end of the attribute. This is the character numbered 254 from the ASCII coding scheme. Not surprisingly, this is called an attribute mark.
This means that when the Pick System accesses an attribute, it merely "scans" the item one character at a time until it reaches an attribute mark. It doesn't matter how many characters occur between attribute marks, other than the fact that most Pick systems impose a maximum size limitation of 32K (about 32,267) characters on any single item. Consequently, items, attributes, values, and sub-values may be of variable length, which allows items to expand and contract as changes are made.
Most other computer operating systems utilize a fixed-length field concept which requires that each field within a record have indicated a specific length, along with a beginning and ending character position, to specify where the field is found or stored in the record. The total of all of these fixed-length fields indicates the record size.
The classic problem with this scheme is the five-digit ZIP code. When the record was originally laid out, five positions were provided to allow for the storage of a ZIP code. When the ZIP code expanded to nine characters, all the fixed-length-field victims had a real problem. They had to resize their record structures, rewrite their programs, and tell their bosses to wait.
This problem doesn't occur in the Pick System. With Pick, you simply change the programs to accept and display nine positions, change the dictionary items used by ACCESS for reporting, and life goes on.
The concept of using delimiters to separate attributes (fields), values, and sub- values significantly simplifies the problem of data management. All you tell the Pick System is what you want, not how to do it. It then scans through the item, counting the delimiters along the way, until the requested location is found. Simple.
This scheme leads to a phenomenon commonly referred to as the three-dimensional item structure. Attributes may contain multiple values, each of which is separated by a value mark. Values, in turn, may contain multiple sub-values, each of which is separated by a sub-value mark. Figure 1-2 illustrates the logical structure of the Pick System.
Systems are made up of accounts. Accounts are made up of files. Files are made up of Items. Items are made up of attributes. Attributes are made up of values. Values are made up of sub-values.
Fig. 1-2, Summary of the Pick data structure.
IF YOU HAVE WORKED ON OTHER SYSTEMS
Most systems which impose the fixed-length field and record structure require individual programs to be stored in separate source code files, with each 80-character record representing a single line or statement of source code.
Since Pick does not impose this fixed-length mentality, source programs in the Pick System are stored differently. Typically, a single file is created to contain multiple programs of a certain application such as "AR.BP," to contain "Accounts Receivable" programs. Each item in the file is a program. Each attribute (or field) in the (program) item is a single PICK/BASIC line of source code. Remember that Pick has only one file structure, which accommodates variable-length items, attributes, values, and sub-values. The only constraint is that the total length of the program cannot exceed 32,257 characters, which is too much to place in one program anyway.
Since each attribute (field) is of variable length, there is no concept of a continuation character used by other systems when a given line of source code exceeds the space allocated within the 80-character constraint. Also, there is no concept in the writing of PICK/BASIC source programs (unlike FORTRAN, for example) that the statements must start in the 7th or 8th column position of the line and end in the 72nd or 73rd column. PICK/BASIC source statements may begin in any column position.
The concept that multiple source programs (items) are stored in the same source code file affects how you indicate to the various utilities the program that you want to edit, compile, and run. This is covered in Chapter 2, but basically you have to tell the various utilities that the program is in a certain file and has a certain name (item id). This is no different than the way Pick manipulates items in other files: there is only one file structure.
Experienced programmers, just beginning to understand and appreciate the Pick file and item structure, soon realize that this environment easily provides the ability to write PICK/BASIC programs which can write other PICK/BASIC programs. There are several excellent "code generators" commercially available to the Pick System.
By now you are realizing that the Pick operating system provides many powerful features that address many problems plaguing other computer environments with the fixed- length record structures. The Pick System provides a very powerful language called PICK/BASIC. It is almost unfortunate that it is called "BASIC," because of the association with earlier and simpler BASIC languages. Pick has more high-level loop control constructs available than the ever-present COBOL language, plus an exceptional environment for tracing and analyzing program "bugs."
Since Pick provides this unique file structure with variable-length items, many additional functions also are provided to manipulate these structures of character strings. The concept that Pick retrieves a field without knowing what the data represents (no data typing) means that the Pick system provides an ideal environment for creating parameter- driven application systems. This provides the ability to write programs that read data files which contain the parameters and instructions which instruct the programs how to function. Parameter-driven systems avoid the necessity to "hard code" the functions of a program into its source code, which then requires recompilation if changes are needed. Such systems are typically more flexible and generic in application. This is a great aid for software developers.
Another distinction of the Pick System is the way it stores time and date values. In the instances where a date needs to be stored, it may be stored as a string, such as 07/04/1997, or you may utilize a function which converts the date to an integer representing the number of days that have elapsed since the reference date of 12/31/1967. This process is known as internal conversion. Dates before 12/31/1967 have a minus sign preceding the integer number of days. For example, if you were to take the date, 12/31/1967, and convert it with the date conversion function, the function yields the result 0 (zero). The string 1/3/1968, converted with the same function, yields the result 3, and 12/29/1967 yields -2.
The advantages of this internal conversion process are many. First, it makes it extremely easy to perform calculations on dates, since they are stored internally as integer numbers. Second, it optimizes disk storage, given that dates in "internal format" require less room than their "external-format" equivalents. Third and finally, it assists in "sorting" dates, since it is easy to compare two integer numbers to determine which is greater. Extensive functionality exists in Pick to utilize this format and to present dates in many different external formats. These are discussed at length in Chapter 7.
The storage of time has a similar internal conversion scheme. Hours and minutes are internally converted to an integer number that represents the number of seconds that have elapsed since midnight.
This unusual world of Pick, where items (records) automatically expand and contract and no attempt is made to "type" the data stored in fields means that an attribute in an item, which previously had been used to contain customer address information, may be changed quite easily --and without breaking any rules -- to accommodate a numeric value, such as the person's age.
TERMINOLOGY OF THE PICK/BASIC LANGUAGE
Now let's examine some standard programming concepts as they are implemented in Pick.
A statement is a list of words which comprise the detailed instructions from which the computer makes its decisions and performs its duties. It normally consists of constants, variables, expressions, and/or the special commands of the PICK/BASIC language. The PICK/BASIC language allows multiple statements to be put on one physical line (attribute) provided that each statement is separated by a semicolon (;). The first line of code in Fig. 1-3 illustrates what happens when this feature is abused.
PRINT "ENTER NAME" ; INPUT NAME; IF NAME = "" THEN STOP (first statement) (second) (third)
COUNTER = 0 ; * SET NUMBER OF ITEMS COUNTER TO ZERO
Fig. 1-3. Poor and acceptable uses of multiple statements on one source line.
As a rule of thumb, however, it is recommended to put only one statement per line. This makes programs more visually appealing and, consequently, easier to maintain. The one exception to this rule is when a comment, or remark, is included on a source line, as illustrated by the second line.
Constants and Literals
A constant is a value which remains unchanged. Numeric constants do not have to be enclosed in quotes. For example:
SECONDS.PER.HOUR = 3600
This replaces the current value of the variable SECONDS. PER.HOUR with the value 3600. "3600" is the constant.
Literal constants are any strings enclosed in single or double quotes, or between backslashes ( \ ). Any number of characters, up to the maximum item size of 32K, may occur between the quotes or backslashes. For example:
REPORT.TITLE = "PHYSICAL INVENTORY REPORT"
where "PHYSICAL INVENTORY REPORT" is the literal constant.
PRINT.LINE = 'NAME' : ' ' : 'PAY RATE'
where 'NAME ', ' ', and 'PAY RATE' are the literal constants.
Other acceptable literal constants include:
where the two double quotes represent the "null" string, meaning no value.
AGE = "0"
where "0" is the literal constant. Purely numeric values do not have to be enclosed in quotes. The equivalent statement is:
AGE = 0
Since no data typing occurs in Pick, these two statements produce the same effect.
A variable is a symbol that represents and contains a data value. As its name implies, the value, or contents, of a variable may change during program execution. Some other systems call these "data names."
In many versions of BASIC, as well as in languages such as Pascal, Ada, and PL/I, the "type" of a variable must be declared prior to storing data in it. This means that the computer is told what type of data to expect in a particular variable whether it will be a number or a combination of both letters and numbers. In other versions of BASIC, variable names are typically single alphabetic characters for numeric variables, which are used in arithmetic operations. "String" variable names are usually single alphabetic characters followed by a "$", character. "String" variables contain alphabetic and/or punctuation characters and, on occasion, numbers.
Self explanatory form: The "Guess What" form: AGING.TOTAL = 0 AT = 0 IF EXIT.FLAG THEN STOP lF X THEN STOP MATREAD CUSTOMER.ARRAY... MATREAD CA...
Fig. 1-4. Sample variable names.
In PICK/BASIC, no concept of data type exists. Variable names may be any length and therefore may be descriptively named. Variable names may include alphabetic characters, periods and dollar signs, but must begin with an alphabetic character. Figure 1- 4 illustrates samples of variable names that are all valid in PICK/BASIC.
Variables may be assigned an initial value in a program. For example:
ITEM.COUNTER = 0
This assigns the value of 0 (zero) to the variable named ITEM.COUNTER. This is also known as the process of replacement. When a variable name appears on the left side of an equals sign, then the result of whatever appears on the right side of the equals sign will be placed there. Typically, what appears on the right side is a function which produces some result, or a literal string enclosed in quotes, or even a number, as in the example.
This phenomenon is extremely important. There are many instances of using assignment throughout a program. These are examined throughout the tutorials.
When the program assigns the value of 0 (zero) to the variable ITEM .COUNTER, the variable is initialized. Initializing means that the program is making the first reference to a variable. The result of not initializing a variable before it is referenced results in an error message:
[B10] VARIABLE HAS NOT BEEN ASSIGNED A VALUE; ZERO USED!
It's a good idea to systematically assign initial values to variables.
The most important aspect of variables with regard to initializing is that they must be declared on the left side of an equals sign before referring to them on the right side of an equals sign. Part A of Fig. 1-5 illustrates the correct approach to initializing variables, while part B illustrates what happens when a variable is not initialized. TOTAL.AMOUNT appears at line 14 for the first time in this program, and will generate the runtime error message cited above.
003 TOTAL.AMOUNT = 0 * * 007 PRINT "ENTER DOLLAR AMOUNT OF CHECK" ' 008 INPUT CHECK.AMOUNT 014 TOTAL.AMOUNT = TOTAL.AMOUNT + CHECK.AMOUNT * * 014 TOTAL.AMOUNT = TOTAL.AMOUNT + CHECK.AMOUNT
Fig. 1-5. Example of A) properly initializing a variable, and B) failing to initialize.
Functions are operations on one or more variables, constants, or expressions (see nuclear tokens), which generate a single value. They are one of the kinds of elements that may be used in a PICK/BASIC expression. (The other two are variables and constants). Functions perform relatively complicated operations, like removing all extraneous blanks from a string or converting dates to alternate formats. Functions ordinarily do not stand alone in a statement. They are typically assigned to a variable or output with a PRINT statement. Here are a few of the various functions available in PICK/BASIC:
PRINT STR("!",25) CUSTOMER.ITEM(l) = TRIM(RESPONSE) CURRENT.TIME = TIME()
There are some rare occasions, however, where functions may effectively "stand alone." One such case is when a function is passed to an external subroutine. Essentially, the rule is that functions may be used anywhere an expression may be used.
Functions which are native to a language are called intrinsic functions. The intrinsic functions within PICK/BASIC have one syntactical common denominator. They are always immediately followed by a set of parentheses. Sometimes, depending on the type of function, there are one or more arguments or expressions within these parentheses. In a few exceptional cases, there are no expressions within the parentheses. Table 1-1 is a partial listing of PICK/BASIC intrinsic functions, showing required number of expressions within the parentheses.
Table 1-1. Partial Listing of Functions Showing Arguments Required.
Functions which require no expressions:
(Note: According to one leading Pick expert, the TIME(), DATE(), and TIMEDATE( ) functions would be more accurately called "global system variables." They just happen to have a syntax that makes them appear confusingly similar to functions. )
COL1(), COL2(), TIME(), DATE(), TIMEDATE()
Functions which require one expression:
RND, INT, NUM, ASCII
Functions which require two expressions:
COUNT, STR, ICONV, OCONV
Functions which require three expressions:
Functions which require four expressions:
Functions which require five expressions:
Operators are characters, and sometimes words, which perform logical, arithmetic, relational, or string-modifying operations. Operators include: + - / * < > < = > = #: and a few others. Figure 1-6 illustrates some of the operators available in PICK/BASIC.
Operators are classified into three categories:
- + (addition)
- - (subtraction)
- / (division)
- * (multiplication)
- ^ (exponentiation)
- = (equal to)
- > (greater than)
- < (less than)
- >= (greater than or equal to)
- <= (less than or equal to)
- # (not equal to) which may also be represented by ( <> or >< )
- : (concatenation, or "linking" strings together)
- the MATCHES relational operator, which detects "patterns" of characters.
In the first line of Fig. 1-6, ">" is a logical operator which means "greater than," and "+" is an arithmetic operator for addition. In the second line, "MATCHES" is a relational operator which checks patterns of characters, and ":" is a string-modifying operator which means concatenate. Concatenate is another way of saying "link together."
Expressions and Arguments
An expression is a valid series of constants, variables, and functions, connected by operators. These are also frequently referred to as arguments. The simplest expression is a single constant, variable or intrinsic function. For example:
TOTAL = TOTAL + NEXT.AMOUNT
This is an arithmetic expression, one which adds the two (presumably assigned) variables together and stores the result in a variable called TOTAL.
Expressions produce a result, like a string of characters or a number. The result they produce determines the type of expression. It is important to distinguish types of expressions in attempting to explain the capabilities of PICK/BASIC.
Some functions, for example, test for a "true" or "false" condition, which could be classified in this case as a conditional expression. As you proceed through the tutorials, you will see a variety of expressions, such as "string" expressions and "numeric" expressions. Each new type of expression is explained as it is encountered. For example:
ELIGIBLE.FOR.RETIREMENT = (AGE >= 65}
This is a known as a relational, logical or Boolean expression. Boolean expressions use the operators >, <, >=, <=, <>, ><, and #. Any such expression evaluates to a numeric nonzero value (normally 1 ) if true, and a 0 (zero or null) if false. This statement assigns the value 1 (one) to the variable ELIGIBLE.FOR.RETIREMENT if the variable AGE is greater than or equal to 65; otherwise, it is assigned a 0 (zero) if not true.
IF CHECK.AMOUNT > 0 THEN CHECK.TOTAL = CHECK.TOTAL + CHECK.AMOUNT
IF PART.NUMBER MATCHES "1A4N" THEN TITLE = TITLE : " " : RESPONSE
Fig. 1-6. Examples of using operators.
The parentheses not only clarify, but also determine the meaning of the statement. By the way, if you don't put the parentheses around the expression, then it will not work on some versions of Pick.
Logical or Boolean expressions are used within conditional expressions like the IF- THEN and LOOP-UNTIL constructs. They also have the property of being able to stand alone in an assignment statement.
This process of combining expressions continues in an ever-expanding combination of syntactical permutations when parentheses and the logical operators OR and AND are included. Figure 1-7 illustrates the use of parentheses and logical operators.
Functions and Nuclear Tokens
In the initial definition of functions it was mentioned that functions always are followed immediately by a set of parentheses, often containing one or more expressions. This is where the concept of "nuclear" or "atomic" tokens needs to be discussed. Effectively, a nuclear token is the smallest part of an expression. Functions may also contain other expressions, which in turn may contain other functions. This is known as an infix notional language. An example of this is the statement:
PRINT ABS(INT(X * Y))
In evaluating expressions, the computer starts from the innermost set of parentheses and works outward. This example has "X * Y" at its core. "X" and "Y" themselves are nuclear tokens, because they are variables which already contain a result by an assignment or a calculation. When X is multiplied by Y, the result itself becomes the nuclear token for the INT function. The INT function retrieves the integer portion (the numbers to the left of the decimal point) of the number, which becomes the nuclear token for the ABS function, which retrieves the absolute value of a numeric expression. The absolute value is always the positive value of a numeric variable; hence, the ABS function strips off the leading minus sign if the result is a negative number.
ELIGIBLE.FOR.RETIREMENT = (AGE >= 65) IF ELIGIBLE.FOR.RETIREMENT AND (YEARS.WORKED > 1 AND YEARS.WORKED <= 10 THEN RETIREMENT.GIFT = "TIMEX WATCH" END IF ELIGIBLE.FOR.RETIREMENT AND (YEARS.WORKED > 10) THEN RETIREMENT.GIFT = "ROLEX WATCH" END
Fig. 1-7. Using parentheses and logical operators.
MAINTAINING STANDARDS AND CONVENTIONS
Once you know how to program in one language, you discover that most of the same principles apply in almost all languages: programs are used to capture, manipulate, store and retrieve data on the computer. In current technology, data is stored on "hard" or "fixed" disks. In a few years, hard disks may be obsolete, but the principles of dealing with new media will remain the same. There will still be a need to have programs to organize and administer data management.
In any programming language as flexible as PICK/BASIC, it is important to consider adopting "standards." These are "standard" methods of doing things. In programming textbooks and training classes, discussion of "standards" often is left until the end, after habits are already started. Introducing some of the concepts early on allows you to take advantage of them from the start.
Many programming shops have lists of "programming standards." These are the guidelines which programmers follow in order to produce programs that everyone can understand and maintain. This text suggests many standards, such as the variable naming conventions about to be discussed. You may choose to implement some and/or use some of your own.
Most versions of Pick are implemented using the ASCII coding scheme? Any variable may contain a number or a character string. Since there are no "typed" variables in the Pick System, it is suggested that you use some variable naming conventions. For example, all variables that act as accumulators could have. TOTAL for the suffix. The next few sections illustrate some of the conventions that are used throughout this text.
File Variables. A file variable is used to refer to a DATA or DICT file and is always declared in an OPEN statement. The suggested convention is that the variable name of the file is always followed by the suffix ".FILE":
OPEN "CUSTOMER-FILE" TO CUSTOMER.FILE...
Item-ID Variables. An item-id variable is a variable used to contain an item-id (what many people call a "key' '). It's a good idea to always follow the name of the variable with the literal, ".ID":
Array Variables. An array variable is the resting place for an item read in through a READ or MATREAD statement. The suggested convention is that the name of the array is always followed by the suffix, ".ITEM":
arrayname.ITEM or arrayname.ARRAY
MATREAD CUSTOMER.ITEM FROM CUSTOMER.FILE,CUSTOMER.ID...
Flag Variables. A flag variable typically contains one of two possible conditions: 0 (zero) or (numeric) non-zero (normally 1). These end with the suffix, ".FLG":
Note that you may use any conventions that you like to name your variables. It is recommended that you do use some naming conventions, however, because many programmers have found that naming conventions make programs less difficult to create and/or modify.
You have just completed the "crash course" on programming concepts. In it, you learned important principles and terms like variables, expressions, and operators. These principles, with few exceptions, are generalized and apply to virtually every programming language. From now on, the topics become much more specialized.