The Cornell Program Synthesizer: A Tutorial Introduction

Tim Teitelbaum

 

Department of Computer Science
Cornell University
Ithaca, New York 14853

First Edition July 1979

Second Edition January 1980

Third Edition June 1980

Fourth Edition August 1980

Revised January 1981

Revised August 1981

Copyright © 1980 by Ray (Tim) Teitelbaum

Acknowledgments

Many people have contributed to the development of the Synthesizer. It is a pleasure to acknowledge the special role of Thomas Reps who has worked closely with me from the beginning. I am deeply indebted to Alan Demers for our many stimulating discussions and for writing the LSI-11 operating system kernel. I am also extremely grateful for the valuable contributions of Richard Conway. Jim Archer. Carl Hauser, Dean Krafft, Ron Olsson, Steve Mahaney, Ralph Johnson, Susan Horwitz and Michael Fingerhut.

I am grateful to Sidney Siskin for her editorial assistance in the preparation of the first edition of this tutorial.

The development of the Cornell Program Synthesizer was supported in part by the National Science Foundation under Grants MCS77-08198 and MCS8004218.

1. Purpose

This tutorial introduces a novice student to the basic facilities of the Cornell Program Synthesizer for developing programs written in the PL/CS dialect of PL/I. No knowledge of programming is assumed or required. It is assumed that you possess a Synthesizer diskette and have access to a TERAK microcomputer. The tutorial shows how to create, modify, test, and run a PL/I program using the Synthesizer. The tutorial is not a text in programming, nor is it a manual for the PL/I programming language.

2. Getting started

The TERAK consists of three physically separate components:

keyboard

video display screen

disk drive and processor

By itself, the computer is useless. A fourth component. the programming system, is required before a session can begin. The process of loading the TERAK with your copy of the Cornell Program Synthesizer is known as booting. The following steps are required to boot the system:

If necessary, open the door to the disk drive by pressing the horizontal bar just below the door. The door should spring open by sliding up. Remove any diskette that remains in the drive.

The boot-switch is in the upper-right corner of the disk drive. Press the boot-switch up.

Insert your own diskette into the disk drive. The diskette should be oriented so that the label is on the top surface, with lettering upside-down. Hold the labeled edge and insert the opposite edge first. The entire diskette should disappear into the drive and remain there. Close the drive door by sliding it down until it latches. If your diskette is not fully inserted into the drive, the door will not close. Your disk will begin booting as soon as the door is closed. The process of loading your copy of the Synthesizer into the TERAK takes about 12 seconds.

3. The keyboard

Several of the keys on the TERAK keyboard have a special meaning for the Synthesizer. The layout of these keys is the following:

-------------                 ----------------------------------
| execute |  |                | diag | up  | {  |   }   | break |
|---------|   ---------      -----------------------------------|
| clip    | command . |      |   |   |down | ~  | resume |unused|
|---------------------|    |-    -------------------------------|
| insert  | LOCK      |    | RETURN  |left |... | delete | clear|
|---------------------|    |------------------------------------|
| CTRL    | SHIFT     |    | SHIFT   |right|   long      |rubout|
----------------------|    -------------------------------------
    (left side)                        (right side)

 

Note that in this document, a word enclosed in angle brackets (like <RETURN>) denotes one particular key on the keybord. The four keys labeled with triangles are known as <up>, <down>, <left> and <right>. The key labeled with a diagonal arrow is known as <diagonal>.

Upper and lower case letters are considered distinct characters. Thus, words like "max", "MAX", and "Max!" would each be considered distinct symbolic names in a program. All predefined PL/I names and keywords are expected to be typed in lower case.

Striking the <LOCK> key locks the keyboard in upper case. The red light on this key indicates that the keyboard is locked. Striking either <SHIFT> key unlocks the keyboard. Some of the special function keys have different meanings in upper case. If the keyboard does not seem to be responding normally. check to see if the keyboard is locked in upper case -- you may have typed <LOCK> by accident.

On the TERAK. there is no key for the not-sign. A tilde "~" is used instead. Thus, not equal is typed as "~=".

Be careful to distinguish between visually similar characters:

"i", "I" (letter "I"), "1" (one), "l" (letter "L") and "|" (bar)

"o", "O" (letter "O") and "0" (zero)

"-" (arithmetic minus) and "_" (underscore)

"." (decimal point). "." (command dot), and "…" (ellipsis)
Note: command dot is not distinguished in this Web version.

As you type, use short key-strokes since a pressed key begins to repeat after about a second.

* The Appendix contains a duplicate copy of the keyboard layout that can be removed and affixed to the keyboard for reference.

4. Creating a data file

A file is a named place where you store either a program or data. The Synthesizer can retain many files simultaneously, each distinguished by a different name. In this step of the tutorial, you will create a file named "pairs" containing a list of numbers.

The Synthesizer is controled by commands. All commands begin with the special symbol ".". a boldface dot. Note that the boldface dot that identifies commands is not the same key as the decimal point. The <TAB> key is used for a boldface dot and is relabeled <command .>.

Creating or modifying a file is known as editing the file. The command ".ed pairs" says that you wish to edit a file named "pairs". The contents of the file will be displayed below the dashed line as the file is created. A command is displayed above the dashed line because it is not part of the file per se.

Type ".ed pairs" and then strike <RETURN>. (Do not type the quotation marks; type the characters that are enclosed in quotation marks.)

After issuing the command tt.ed pairstt, the display will look as follows:

                                        editing pairs 
-----------------------------------------------------
object

Since "pairs" is a new file, it is initially empty. The word "object" is a placeholder that says, in effect, "an object goes here".

The square of light around the letter "o" of the word "object" is known as the cursor.  The cursor serves as a pointer into the file being edited.

A data file consists of arbitrary lines of text. The command ".text" says that the currently edited file will consist of arbitrary text rather than a PL/I program:

Type ".text" and then strike <RETURN>.

After issuing the command ".text", the placeholder "object" will be replaced by the following:

pairs: TEXT

{text}

The heading line "pairs: TEXT" is descriptive information and is not considered part of the file per se. The word "{text}" is called a placeholder. Placeholders identify locations in the file where insertions can be made. The braces in "{text}" mean that a list of zero or more text lines is permitted at this point of the file.

Now type the following list of number pairs. At the end of each line, use the <RETURN> key to go on to the next line. If necessary, use <rubout> to erase typographical errors. The <rubout> key erases the character just typed. Be careful to type a numeric "1", not a lower case "L":

2, 2

19, 77

56 9 -3

1234, 4321

50, 50

0, 0

5. Modifying a data file

Files are modified by making insertions and deletions at the position of the editing cursor. The editing cursor can be moved wherever a change is desired by using special control keys.

5.1. Cursor notion

Four keys labeled with triangles are known as <up>, <down>, <left> and <right>. They are used to change the position of the cursor in the file. The automatic repeat feature of the keyboard is often useful with the cursor control keys. While a cursor control key is held down, the cursor moves rapidly through the file.

The cursor control keys move the cursor forward and backward through a file: <down> and <right> move the cursor forward, <up> and <left> move the cursor backward. The control keys move the cursor in different size increments: the keys <up> and <down> move the cursor one line at a time, the keys <left> and <right> move the cursor one character at a time:

Repeatedly strike <up> until the cursor is positioned in the first line of the file. Then strike <down> until reaching the last line again.

Repeatedly strike <left> until the cursor is positioned in the first line of the file. Then strike <right> until reaching the end of the file.

The <RETURN> key also controls the cursor. <RETURN> moves the cursor like <down> but also positions the cursor between lines. Note that as the cursor moves in between lines, the placeholder "{text}" appears; it disappears when the cursor moves onto an existing line. Thus, if youever wish to insert a new line between two lines. position the cursor on the first of the two lines and then strike <RETURN>.

Move the cursor to the top of the file using <up> and then repeatedly strike <RETURN> until reaching the bottom again.

5.2. Deleting and inserting

The <delete> key erases an entire line in a single operation. The placeholder "{text}" reappears when the line is deleted:

Position the cursor anywhere on the line "1234, 4321" and strike <delete>. Then retype the line.

Text can be inserted in the middle of a line. Typed text is inserted to the left of the cursor position:

Use <left> to position the cursor on the "," of the line "1234, 4321" and then type "wxyz".

Text can be deleted in the middle of a line. <Rubout> erases the character to the lef t of the cursor. Repeated use of <rubout> has the effect of erasing backward through the line:

Erase "wxyz" by striking <rubout> four times.

<Clear> can be used to erase the character at the cursor position. Repeated use of <clear> has the effect of erasing forward through the line:

Once again type "wxyz" in the middle of the line. This time, use <left> to reposition the cursor at the "w". Erase "wxyz" by striking <clear> four times.

5.3. Moving lines

It is possible to move entire lines in order to reorganize a file. The <clip> key temporarily removes a line from the file. The cursor can then be repositioned at a "[text}" placeholder where you wish to reinsert the line. The <insert> key inserts the "clipped' line at the position of the cursor.

We illustrate the use of <clip> and <insert> to move the line "50, 50" immediately after the line "2, 2":

Position the cursor on "50, 50", the line to be moved.

Clip the line out of the f ile by striking <clip>. (This actually moves the line to a file named "CLIPPED".)

Position the cursor on a "{text}" placeholder at the desired destination af ter the line "2, 2". Remember that the way to make a placeholder appear between two lines is to put the cursor on the first of the two lines and then strike <RETURN>.

Reinsert the line into the file by striking <insert>.

The <clip> key, by itself, clips only one line at a time. In order to move several consecutive lines, you must specify the first and last lines to be clipped. The two keys <long> and <clip>, struck one after the other, mean "clip a list of lines starting at the current cursor position". After typing <long><clip>, you reposition the cursor on the last of the list of lines to be clipped and strike ".".

We illustrate the use of <long><clip> to move the lines

19, 77

56, -3

1234, 4321

immediately after the line "2, 2". This will restore the list to its original order:

Position the cursor at "19, 77", the first line to be moved. Type <Iong><clip>.

Position the cursor at "1234, 4321",. the last line to be moved. Strike <command .>. (The specified list of lines is actually moved to the file named "CLIPPED".)

Position the cursor on a "{text}" placeholder at the desired destination af ter the line "2, 2". Remember that the way to make a placeholder appear between two lines is to put the cursor on the first of the two lines and then strike <RETURN>.

Type <insert>.

6. Creating a program file

In this section of the tutorial, you will create a program that reads pairs of numbers and prints their sums. Then, in the next section, you will run the program on the data already typed into file "pairs".

The program will be stored separately from its data in a new file named "adder". Typing the command ".ed adder" redirects the attention of the Synthesizer from file "pairs" to file "adder":

Type ".ed adder" and then strike <RETURN>.

Since "adder" is currently empty, just an "object" placeholder is displayed. The "pairs" file still exists but is no longer visible on the screen because you are not currently editing it.

The program that will eventually be created is shown below. Don't type it now -- a complete script will be provided later.

/* print each input data pair and its sum */
adder: PROCEDURE OPTIONS ( MAIN );
   DECLARE ( x, y  /* number pair to be summed */ ) FIXED;
   /** process data until x not positive */
      GET LIST (x, y);
      DO WHILE ( x>0 );
      PUT SKIP LIST ( x, y, x+y );
      GET LIST ( x, y );
      END;
   END adder;

It is not necessary for you to understand how this program works. Our current interest is how to create programs using the Synthesizer.

Program files are created in a different way from data files. You cannot type the program text into the file character-by-character. Rather, you must use commands to insert predefined templates for the various PL/I language constructs. Only a fraction of the total program will be explicitly typed; the rest will be "synthesized" as a result of the commands. A command is not part of the f ile; rather, it is a directive to the Synthesizer to insert a given template into the file. A complete list of the commands for inserting program templates appears in Appendix A.

Type ".main" and then strike <RETURN>.

The ".main" command causes the placeholder "object" to be replaced by the template

/* comment */
adder: PROCEDURE OPTIONS ( MAIN );
   {declaration}
   {statement}
   END adder;

In this insertion of one template, part of the progran's first line, and all of its second and last lines, have been provided. "Comment","{statement}". and "{declaration}" are placeholders that identify locations where subsequent insertions will be made. The cursor has been advanced to the "comment" placeholder.

Although, at first, it may seem circuitous to enter templates by command, the commands will allow you to enter the program quickly and accurately. Since the template is predefined, you can not make a mistake in typing it, The placeholders of a template serve as prompts that guide your subsequent insertions and allow the Synthesizer to validate the syntactic correctness of your program as it is created. The indenting of the program is provided automatically as part of the predefined templates.

PL/I constructs for which templates are provided must be entered by command -- they cannot be typed explicitly.  PL/I constructs for which templates are not provided are typed explicitly by the user and are known as phrases. The editing of a phrase is exactly like the editing of a {text) line in a data file -- you just type directly into the file at the position of the editing cursor.

At this point, with the editing cursor positioned at the "comment" placeholder, you can enter an English phrase describing what the program does:

Type "print each input data pair and its sum" and then strike <RETURN>. (In the event of a typographical error. an individual typed phrase can be modified exactly like a "{text}" line in a data file. In particular, you can use <rubout> to erase the last character typed or <delete> to erase the entire phrase.)

The typed phrase replaces the "comment" placeholder and the cursor is advanced to the "{declaration)" placeholder for the next insertion. Note that the cursor skips over the line

adder: PROCEDURE OPTIONS ( MAIN );

because it is not meaningful to make any insertions on that line of the template.

By following the script below, you will complete the creation of the desired program. (Be careful not to omit the <RETURN> in the third line of the script. It is essential that the ".c" in the fourth line of the script be typed with the cursor positioned at "{statement)", not "{declaration}".)

WITH THE CURSOR POSITIONED AT: YOU TYPE:
--------------- ----------------------------------------------
{declaration} .fx <RETURN>
list-of-variables x,y /* number pair to be summed */ <RETURN>
{declaration} <RETURN>
{statement} .c <RETURN>
comment process data until x not positive <RETURN>
{statement} .g <RETURN>
list-of-variables x,y <RETURN>
{statement} .dw <RETURN>
condition x>0  <RETURN>
{statement} .p <RETURN>
list-of-expressions x,y,x+y <RETURN>
{statement} .g <RETURN>
list-of-variables x,y <RETURN>

When you have completed the script, verify that the program on the display screen matches the program above. (The one exception to a perfect match is that the cursor will be positioned at a "{statement}" placeholder). If you have made mistakes, read the section "Modifying a program file" and correct the program before running it.

7. Running a program

The purpose of the "adder" program is to add pairs of numbers. You will now run the "adder" program on the data stored in the file named "pairs". Running a program is also called executing the program.

The command ".ex pairs" initiates the execution of the "adder" program with input data taken from the file "pairs". Notice that you only mention the name of the data file in the command. The Synthesizer assumes that the program you wish to execute is "adder", the most recent program to have been edited. Notice also that it is not necessary to make the "{statement}" placeholder disappear before executing the program.

Type ".ex pairs" and then strike <RETURN>.

While the program is executing, the display of the "adder" file is replaced by the programs output. Each pair of numbers and its sum appears on a separate line.

When the program has finished. it pauses and you are prompted to "type any character to continue". This provides an opportunity for you to review the output on the screen. Notice that no line of output appears for the pair of numbers "0, 0". The program, as written, uses "0, 0" only to signal the end of the data file. Thus, the omission of output for the "0. 0" is deliberate.

The Synthesizer is waiting for a signal from you before it continues. When any character is typed, the execution output is erased and the adder file reappears:

Strike the <space> key once.

8. Getting a printout:

From time to time, you may wish to have a paper printout of your program or its output. (If you Terak is not connected to a hard copy printer either directly, or via a switch, then omit this section.)

The command "..pr" prints the file that is currently being edited on the printer. The command ".ex pairs PRT" executes the program with input from the file named "pairs" and output directed to the printer (as well as the video display).

Verify that the printer is not in use. If necessary, switch it to your TERAK.

Type ".pr" and then strike <RETURN>. (If this command seems to have no effect, verify that the printer is turned on, is "on line", and is connected to your Terak. When "hung" waiting for the printer, you can abort the ".pr" command by holding <CTRL> and striking the <break> key.)

After the printer stops, type ".ex pairs PRT" and then strike <RETURN>.

When the execution of your program terminates, you will be prompted to "type any character to continue". Strike the <space> key once and then retrieve your printout from the printer.

9. Getting off

The next step of this tutorial is to terminate the session at the TERAK as if you were finished.

Type the command ".off" and then strike <RETURN>. After a few seconds, the Synthesizer should respond with the message "Session ended".

Open the door to the disk drive by pressing the horizontal bar just below the door. The door should spring open by sliding up. Remove your diskette.

Unless the TERAK is about to be used, turn the power off by pressing the boot-switch down.

Never remove your diskette or turn the power off without first issuing the ".off" command and receiving the "Session ended" message. You can type ".off" whenever commands are permitted.

10. Modifying a program file

To continue with the tutorial, get back on the TERAK by following the booting instructions in Section 2 above. The system will be restored exactly as it was at the time you issued the ".off" command, editing the file "adder".

10.1. Cursor notion

The cursor motion keys <up> and <down> move the cursor backwards and forwards through the program one phrase, template, or placeholder at a time:

Repeatedly strike <down> until the cursor advances no further. Then strike <up> until reaching the top again.

The cursor motion keys <left> and <right> also move the cursor to the next phrase, template, or placeholder but within a phrase, advance the cursor one character at a time:

Repeatedly strike <right> until the cursor advances no further. Then strike <left> until reaching the top again.

<RETURN> moves the cursor like <down> but also positions the cursor between consecutive declarations or statements. When the cursor moves between declarations, the placeholder {declaration} appears; when it moves between statements, the placeholder {statement) appears. These placeholders identify locations in the file where insertions can be made. The placeholders disappear when the cursor moves onto an existing declaration or statement. Thus, when you wish to insert a new declaration or statement into your programs position the cursor above the desired destination and strike <RETURN>.

Repeatedly strike <RETURN> until the cursor advances no further.

10.2. Deleting, inserting and moving program elements

In a data f ile, <delete> or <clip> removes one line of text at a time. In a program f ile, <delete> or <clip> removes a whole structural unit from the program. A given structural unit may be only part of a line or it may extend accross many lines of the program.  (There is actually no difference between editing a text file and editing a program file. The "structural units" of a text file just happen to be lines of {text}.)

When the cursor is positioned anywhere in a phrase, <clip> or <delete> removes the entire phrase. When the phrase has been removed, the appropriate placeholder reappears:

Position the cursor in the phrase "x>O" and strike <delete>. Then retype the phrase "x>0".

When the cursor is positioned at a template, the entire template and all its components are removed:

Position the cursor at "DO" and strike <clip>. Reinsert the clipped template at the same location by striking <insert>.

Position the cursor at "/**" and strike <clip>. Reinsert the clipped template at the same location by striking <insert>.

When the cursor is positioned at a template the entire template and all its components can be deleted in a single step. However, the most recently deleted phrase or template is saved in a file named "DELETED". Thus. if you delete a section of the program by accident. it can be recovered by typing ".ins DELETED":

With the cursor still positioned at "/**", strike <delete>. Recover the deleted template by typing ",ins DELETED" and then strike <RETURN>. (The capital letters in "DELETED" are essential since the names "DELETED" and "deleted" denote two different files.)

The way to delete an entire file is to position the cursor at the very top at the outermost template of the file and strike <delete>.

10.3. Hidden placeholders

Placeholders for optional program elements are not normally displayed. For example, the full form of a "DO WHILE' template is

   [loop-name:] DO WHILE ( condition );
      {statement}
       END; 

but the "[loop-name:]" placeholder is normally hidden from view. In order to enter a loop-name, it is first necessary to make the "[loop- name:]" placeholder appear. The special command ".o" ("move to option") is used to make a hidden placeholder appear:

Position the cursor at "DO". then type ".o" and then strike <RETURN>.

Type "readloop" and then strike <RETURN>. Note that the loop-name "readloop" is automatically inserted after the appropriate "END".

Suppose we now wish to change "readloop" to "Readloop":

Position the cursor at "readloop".

The cursor now denotes the entire "DO WHILE" template. This can be verified as follows:

Strike <clip>. (Note that the entire template is clipped.) Then reinsert the template by striking <insert>.

In order to position the cursor on the individual phrase "readloop" you must type the command ".o":

Type ".o" and then strike <RETURN>.

Note that the cursor did not change position when you typed ".o". This is because the same cursor position on the screen denotes both the entire "DO WHILE" template and also denotes the individual phrase fireadloop". Fortunately, this is the only example in the Synthesizer where the meaning of the cursor position on the screen is ambiguous.

Strike <clear>. Then type "R". Then strike <RETURN>.

11. Error prevention

A program that is ungrammatical is said to contain a "syntax error". The Synthesizer will detect syntax errors on a phrase-by-phrase basis and will only permit you to create grammatically correct programs. We illustrate the Synthesizer's error prevention mechanism by making some intentional mistakes.

Position the cursor at the beginning of the phrase "x>0" and strike "/". Then strike <RETURN>.

The phrase "/x>0" is not a syntactically correct condition. The syntax error is detected: the buzzer sounds, an error message appears on the top line of the screen and the cursor is positioned at the point of error*

The error can be corrected immediately:

Strike <clear> to erase the "/" and then strike <RETURN>.

Errors do not have to be corrected immediately. However, if allowed to remain in the program, an incorrect phrase is highlighted to alert you to its presence:

Position the cursor at the phrase "x>0" [and] strike "/".   Then strike <RETURN>. When the syntax error is detected, strike <RETURN> again without first correcting the phrase.

An incorrect, highlighted phrase can be re-edited like any other phrase. Thus. you can now go back to the invalid phrase and correct it:

Strike <up> to position the cursor at the incorrect phrase. Strike <clear> once to erase the leading blank on the invalid phrase. Then strike <clear> again to erase the "/". Then strike <RETURN>.

Sometimes, a change in one part of the program causes errors in another part of the program. For example, if the declaration

DECLARE ( x, y /* number pair to be summed */ ) FIXED;

is deleted, the names "x" and "y" are said to be "undeclared". Since it is an error to use an undeclared name, all remaining phrases containing "x" and "y" are then highlighted to indicate that they contain errors. The display returns to normal when the declaration is restored:

Position the cursor at the word "DECLARE" and strike <clip>. (Notice that phrases containing "x" or "y" are highlighted.)

Reinsert the declaration by striking <insert>.

12. Abbreviated file display

When programs get large, it is useful to be able to suppress the display of selected parts. The display of program statements that are subordinate to a "/**" type of comment can be suppressed by striking the ellipsis key <...>. This is not the same as "clipping" or "deleting" which actually removes statements from the program. <...> just suppresses the display of statements that remain in the file:

Position the cursor at the comment symbol "/**" and strike <...>. Strike <...> again and the statements reappear.

13. Progran execution features

This section of the tutorial introduces features of the Progran Synthesizer that allow you to monitor and control the execution of a program. These features will be especially valuable to you when your pro- gram doesn't work and you are trying to determine why.

The "trace feature" allows you to monitor the steps the computer takes as it moves through a program during execution. The command ".trace" turns on the feature. A "T" in the upper right corner of the screen indicates that the trace feature is on. When the trace feature is enabled, the program is displayed in the upper partition of the screen; the execution output is displayed in the lower partition. As the program executes, the cursor indicates the position of the computer's "instruction pointer":

Type ".trace" and then strike <RETURN>.

Now that the trace feature has been turned on, run the "adder" program again on the data in "pairs". You should be able to observe the cursor tracing through the program as it executes although it happens too rapidly to follow in detail:

Type ".ex pairs" and then strike <RETURN>.

The "pace feature" causes the Synthesizer to pace itself so that you can follow the separate steps of a computation. The pace is measured in 1/60 seconds per program step. Thus, the command ".pace 60" sets a pace of 1 second per program step. A "P" in the upper right corner of the screen indicates that the pace feature is on:

Type ".pace 60" and then strike <RETURN>.

Now run the program again. This time you will be able to observe the step-by-step operation of the program:

Type ".ex pairs" and then strike <RETURN>.

The "check feature" allows you to monitor the values of the program variables during execution. The command ".check" turns on the feature for all variables of the current procedure. A third partition of the screen (in the middle) is used to display the values of the variables:

Type ".check" and then strike <RETURN>.

Now run the "adder" program again on the data in "pairs". You should be able to observe the values in the variables changing as the program runs:

Type ".ex pairs" and then strike <RETURN>.

You will often need to suspend the execution of a program before it terminates on its own. For example, an error in the program may cause it to "run forever". Or the pace may be far too slow. Or you may want to