2.2. Differences Between UCSD Pascal and Standard Pascal

Version II.0, February 1979

page133 This section is a summary and quick reference guide which notes the areas in which UCSD Pascal differs from Standard Pascal, and refers the user to the appropriate documents which explain various aspects of UCSD Pascal. The Standard Pascal referred to by this section is defined in PASCAL USER MANUAL AND REPORT (2nd edition) by Kathleen Jensen and Niklaus Wirth (Springer-Verlag, 1975).

Many of the differences lie in the area of FILES and I/O in general. It is recommended that the reader first concentrate upon the sections which describe the differences associated with the standard procedures EOF, EOLN, READ, WRITE, RESET, and REWRITE.

2.2.1. Case Statements

Jensen and Wirth on page 31, state that if there is no label equal to the value of the case statement selector, the result of the case statement is undefined. UCSD Pascal defines that if there is no label matching the value of the case selector then the next statement executed is the statement following the case statement. For example, the following sample program will only output the line “THAT'S ALL FOLKS” since the case statement will “fall through” to the WRITELN statement following the case statement:
PROGRAM FALLTHROUGH;
  VAR CH:CHAR;
BEGIN
  CH := 'A';
  CASE CH OF
    'B': WRITELN(OUTPUT, 'HI THERE');
    'C': WRITELN(OUTPUT, 'THE CHARACTER IS A ''C''')
  END;
  WRITELN(OUTPUT, 'THAT''S ALL FOLKS');
END.

page134 2.2.2. Comments

The UCSD Pascal compiler recognizes any text appearing between either the symbols “(*” and “*)” or the symbols “{” and “}” as a comment. Text appearing between these symbols is ignored by the compiler unless the first character of the comment is a dollar sign, in which case the comment is interpreted as a compiler control comment. See section 1.6 “Pascal Compiler” for details on compiler control comments.

If the beginning of the comment is delimited by the “(*” symbol, the end of the comment must be delimited by the matching “*)” symbol, rather than the “}” symbol. When the comment begins with the “{” symbol, the comment continues until the matching “}” symbol appears. This feature allows a user to “comment out” a section of a program which itself contains comments. For example:

{ XCP := XCP + 1;  (* ADJUST FOR SPECIAL CASE... *)  }

The compiler does not keep track of nested comments. When a comment symbol is encountered, the text is scanned for the matching comment symbol. The following text will result in a syntax error:

(* THIS IS A COMMENT (* NESTED COMMENT *)  END OF FIRST COMMENT *)
                                           ^error here.

2.2.3 Dynamic Memory Allocation

The standard procedure DISPOSE defined on page 158 of Jensen and Wirth is not implemented in UCSD Pascal. However, the function of DISPOSE can be approximated by a combined use of the UCSD intrinsics MARK and RELEASE. The process of recovering memory space described below is only an approximation to the function of DISPOSE as one cannot explicitly ask that the storage occupied by one particular variable be released by the system for other uses.

The current UCSD implementation allocates storage for variables created by use of the standard procedure NEW in a stack-like structure called the “heap”. The following program is a simple demonstration of how MARK and RELEASE can be used to change in the size of the heap.

PROGRAM SMALLHEAP;

TYPE PERSON =
  RECORD
    NAME: PACKED ARRAY[0..15] OF CHAR;
    ID: INTEGER
  END;
page135
  VAR P: ^PERSON; (* "^" means "pointer to" as defined in J&W *)
  HEAP: ^INTEGER;

BEGIN
  MARK(HEAP);
  NEW(F);
  P^.NAME := 'FARKLE, HENRY J.';
  P^.ID := 999;
  RELEASE(HEAP);
END.

The above program first calls MARK to place the address of the current top of heap into the variable HEAP. HEAP must be declared to be a pointer to an INTEGER. The parameter supplied to MARK must be a pointer to an INTEGER. This is a UCSD restriction. This is a particularly handy construct for deliberately accessing the contents of memory which is otherwise inaccessible. Below is a pictorial description of the heap at this point in the program's execution:

TOP OF HEAP --> |______________________| <--- HEAP
                |                      |
                | contents of heap at  |
                |   start of program   |

Next the program calls the standard procedure NEW and this results in a new variable P^ which is located in the heap as shown in the diagram below:

TOP OF HEAP --> |______________________|
                |                      |
                |          P^          |
                |______________________| <--- HEAP
                |                      |
                | contents of heap at  |
                |   start of program   |
                |                      |

After the RELEASE the heap is as follows:

TOP OF HEAP --> |______________________| <--- HEAP
                |                      |
                | contents of heap at  |
                |   start of program   |

page136 Once the program no longer needs the variable P^ and wishes to “release” this memory space to the system for other uses, it calls RELEASE which resets the top of heap to the address contained in the variable HEAP.

If the above sample program had made a series of calls to the standard procedure NEW between the calls to MARK and RELEASE, the storage occupied by several variables would have been released at once. Note that due to the stack nature of the heap it is not possible to release the memory space used by a single item in the middle of the heap. It is for this reason the use of MARK and RELEASE can only approximate the function of DISPOSE as described in Jensen and Wirth.

Furthermore, it should be noted that careless use of the intrinsics MARK and RELEASE can leave “dangling pointers”, pointing to areas of memory which are no longer part of the defined heap space.

2.2.4. Eof

To set EOF to TRUE for a text file F being used as an input file from the CONSOLE device, the user must type the EOF character. The EOF character can be altered by a suitable reconfiguration of the system variable SYSCOM^.CRTINFO.EOF using SETUP. For further information concerning system configuration and the SETUP program see Section 4.3.

If F is closed, for any file F, EOF(F) will return the value TRUE. If EOF(F) is TRUE, and F is a file of type TEXT, EOLN(F) is also TRUE. After a RESET(F), EOF(F) is FALSE. If EOF(F) becomes TRUE during a GET(F) or a READ(F,...) the data obtained thereby is not valid.

When a user program starts execution, the system performs a RESET on the predeclared files INPUT, OUTPUT and KEYBOARD. See section 2.2.11 “Read” for further details concerning the predeclared file KEYBOARD.

As defined in Jensen and Wirth, EOF and EOLN by default will refer to the file INPUT if no file identifier is specified.

2.2.5. Eoln

EOLN(F) is defined only If the <type> of the window variable, F^, is of type CHAR. EOLN becomes TRUE only after reading the end of line character. The end of line character is a carriage return. In the example program below, care must be taken as regards when the carriage return is typed while inputing data: page137
PROGRAM ADDLINES;
VAR K, SLM: INTEGER;

BEGIN
  WHILE NOT EOF(INPUT) DO
    BEGIN
      SUM := 0;
      READ(INPUT, K);
      WHILE NOT EOLN(INPUT) DO
        BEGIN
          SUM := SUM + K;
          READ(INPUT, K);
        END;
      WRITELN(OUTPUT);
      WRITELN(OUTPUT, 'THE SUM FOR THIS LINE IS ', SUM);
    END;
END.

In order for EOLN(F) to be TRUE in the above program, the carriage return must be typed immediately after the last digit of the last integer on that line. If instead a space is typed followed by the carriage return, EOLN will remain FALSE and another READ will take place. See Section 2.2.11 for details on the behavior of READ(integer).

2.2.6. Files

A. Interactive Files

Files of <type> INTERACTIVE behave exactly as files of <type> TEXT. The standard predeclared files INPUT and OUTPUT will always be defined to be of <type> INTERACTIVE. All files of any <type> other than INTERACTIVE, are defined to operate exactly as described in Jensen and Wirth. For files which are not of <type> INTERACTIVE, the definitions of EOF(F), EOLN(F), and RESET(F) are exactly as presented in Jensen and Wirth. For more details concerning files of <type> INTERACTIVE see section 2.2.11 “Read and Readln” and section 2.2.12 “Reset” and section 2.1.2.

B. Untyped Files

UCSD Pascal has one type of file declaration which in not found in the syntax of Jensen and Wirth. This type and its use is demonstrated in the sample program below: page138
(*$I-*)
PROGRAM FILEDEMO;

VAR
  BLOCKNUMBER, BLOCKSTRANSFERRED: INTEGER;
  BADIO: BOOLEAN;
  G, F: FILE;
  BUFFER: PACKED ARRAY[0..511] OF CHAR;

(* This program reads a disk file called 'SOURCE.DATA' and
copies the file into another disk file called 'DESTINATION'
using untyped files and the intrinsics BLOCKREAD and
BLOCKWRITE. *)

BEGIN
  BADIO := FALSE;
  RESET(G, 'SOURCE.DATA');
  REWRITE(F, 'DESTINATION');
  BLOCKNUMBER := 0;
  BLOCKSTRANSFERRED := BLOCKREAD(G, BUFFER, 1, BLOCKNUMBER);
  WHILE (NOT EOF(G)) AND (IORESULT = 0) AND (NOT BADIO) AND
      (BLOCKSTRANSFERRED = 1) DO
    BEGIN
      BLOCKSTRANSFERRED := BLOCKWRITE(F, BUFFER, 1, BLOCKNUMBER);
      BADIO := ((BLOCKSTRANSFERRED < 1) OR (IORESULT <> 0));
      BLOCKNUMBER := BLOCKNUMBER + 1;
      BLOCKSTRANSFERRED := BLOCKREAD(G, BUFFER, 1, BLOCKNUMBER)
    END;
  CLOSE(F, LOCK)
END.

The two files which are declared and used in the above sample program are both untyped files. An untyped file F can be thought of as a file without a window variable F^ to which all I/O must be accomplished by using the functions BLOCKREAD and BLOCKWRITE. Note that any number of blocks can be transferred using either BLOCKREAD or BLOCKWRITE. The functions return the actual number of blocks read. A somewhat sneaky approach to doing a quick transfer would be:

WHILE BLOCKWRITE(F, BUFFER, BLOCKREAD(G, BUFFER, BUFBLOCKS)) > 0
  DO (* it *);
This is, however, considered unclean. The program above has been compiled using the (*$I-*) Compile Time Option, thereby requiring that the function IORESULT and the number of blocks transferred be checked after each BLOCKREAD or BLOCKWRITE in order to detect any I/O errors that might have occurred.

page139 C. Random Access of Files

The UCSD implementation of structured files supports the ability to randomly access individual records within a file by means of the intrinsic SEEK. SEEK expects two parameters, the first being the file identifier, and the second an integer specifying the record number to which the window should be moved. The first record of a structured file is numbered record 0. The following sample program demonstrates the use of SEEK to randomly access and update records in a file:

PROGRAM RANDOMACCESS;
VAR
  RECNUMBER: INTEGER;
  CH: CHAR;
  DISK: FILE OF RECORD
                  NAME: STRING[20];
                  DAY, MONTH, YEAR: INTEGER;
                  ADDRESS: PACKED ARRAY[0..49] OF CHAR;
                  ALIVE: BOOLEAN
                END;

BEGIN
  RESET(DISK, 'RECORDS.DATA');

  WHILE NOT EOF(INPUT) DO
  BEGIN
    WRITE(OUTPUT, 'Enter record number -->');
    READ(INPUT, RECNUMBER);

    SEEK(DISK, RECNUMBER);
    GET(DISK);

    WITH DISK^ DO
      BEGIN
        WRITELN(OUTPUT, NAME, DAY, MONTH, YEAR ,ADDRESS);
        WRITE(OUTPUT, 'Enter correct name --->');
        READLN(INPUT, NAME);
        ...
        ...
        ...
      END;

    (* Must point the window back to the record
    since GET(DISK) advances the window to
    the next record after loading DISK^ *)

    SEEK(DISK, RECNUMER);
    PUT(DISK)
  END
END.

page140 Attempts to PUT records beyond the physical end of tile will set EOF to the value TRUE. (The physical end of file is the point where the next record in the file will overwrite another file on the disk.) SEEK always sets EOF and EOLN to FALSE. The subsequent GET or PUT will set these conditions as is appropriate. See Section 2.1.2.

D. Read and Write from Arbitrarily Typed Files

It is not currently possible to READ or WRITE to files of type other than TEXT or FILE OF CHAR.

2.2.7. Goto and Exit Statements

UCSD has a more limited form of GOTO statement than is defined as the standard in Jensen and Wirth. UCSD's GOTO statement prohibits a GOTO statement to a label which is not within the same procedure block as the GOTO statement itself. The examples presented on pages 31–32 of Jensen and Wirth are not legal in UCSD Pascal.

EXIT is a UCSD extension which accepts as its single parameter the identifier of a procedure to be exited. The use of an EXIT statement to exit a FUNCTION can result in the FUNCTION returning undefined values if no assignment to the FUNCTION identifier is made prior to the execution of the EXIT statement. Below is an example of the use of the EXIT statement:

PROGRAM EXITDEMO;
VAR T: STRING;
    CN: INTEGER;

  PROCEDURE Q; FORWARD;

  PROCEDURE P;
  BEGIN
    READLN(T);
    WRITELN(T);
    IF T[1] = '#' THEN EXIT(Q);
    WRITELN('LEAVE P');
  END;
page141
  PROCEDURE Q;
  BEGIN
    F;
    WRITELN('LEAVE Q')
  END;

  PROCEDURE R;
  BEGIN
    IF CN <= 10 THEN Q;
    WRITELN('LEAVE R')
  END;

BEGIN
  CN := 0;
  WHILE NOT EOF DO
    BEGIN
      CN := CN + 1;
      R;
      WRITELN
    END
END.
If the above program were supplied the following input
THIS IS THE FIRST STRING
#
LAST STRING
the following output will result:
THIS IS THE FIRST STRING
LEAVE P
LEAVE Q
LEAVE R

#
LEAVE R

LAST STRING
LEAVE P
LEAVE Q
LEAVE R

The EXIT(Q) statement causes the PROCEDURE P to be terminated followed by the PROCEDURE Q. Processing continues following the call to Q inside PROCEDURE R. Thus the only line of output following “#” is “LEAVE R” at the end of PROCEDURE R. In the two cases where the EXIT(Q) statement is not executed, processing proceeds normally through the terminations of procedures P and Q.

page142 If the procedure identifier passed to EXIT is a recursive procedure, the most recent invocation of that procedure will be exited. If, in the above example, one or both of the procedures P and Q declared and opened same local files, an implicit CLOSE(F) is done when the EXIT(Q) statement is executed, as if the procedures P and Q terminated normally.

The EXIT statement may also be used to exit a Pascal program by EXIT(PROGRAM) or EXIT(program-name).

The creation of the EXIT statement at UCSD was inspired by the occasional need for a straightforward means to abort a complicated and possibly deeply nested series of procedure calls upon encountering an error. An example of such a use of the EXIT statement can be found in the recursive descent UCSD Pascal compiler. The routine use of the EXIT statements, nevertheless, discouraged.

2.2.8. Packed Variables

A. Packed Arrays

The UCSD compiler will perform packing of arrays and records if the ARRAY or RECORD declaration is preceded by the word PACKED. For example, consider the following declarations:
A: ARRAY[0..9] OF CHAR;
B: PACKED ARRAY[0..9] OF CHAR;

The array A will occupy ten 16 bit words of memory, with each element of the array occupying one word. The PACKED ARRAY B on the other hand will occupy a total of only five words, since each 16 bit word contains two 8-bit characters. In this manner each element of the PACKED ARRAY B is 8 bits long.

PACKED ARRAYs need not be restricted to arrays of type CHAR, for example:

C: PACKED ARRAY[0..1] OF 0..3;
D: PACKED ARRAY[1..9] OF SET OF 0..15;
D2: PACKED ARRAY[0..239, 0..319] OF BOOLEAN;

Each element of the PACKED ARRAY C is only two bits long, since only two bits are needed to represent the values in the range 0..3. Therefore C occupies only one 16 bit word of memory, and 12 of the bits in that word are unused. The PACKED ARRAY D is a nine word array, since each element of D is a SET which can be represented in a minimum of 16 bits. Each element of a PACKED ARRAY OF BOOLEAN, as in the case of D2 in the above example, occupies only one bit.

page143 The following two declarations are not equivalent due to the recursive nature of the compiler:

E: PACKED ARRAY[O..9] OF ARRAY[0..3] OF CHAR;
F: PACKED ARRAY[0..9, 0..3] OF CHAR;
The second occurrence of the reserved word ARRAY in the declaration of E causes the packing option in the compiler to be turned off, E becomes an unpacked array of 40 words. On the other hand, the PACKED ARRAY F occupies 20 total words because the reserved word ARRAY occurs only once in the declaration. If E had been declared as
E: PACKED ARRAY[0..9] OF PACKED ARRAY[0..3] OF CHAR;
or as
E: ARRAY[0..9] OF PACKED ARRAY[0..3] OF CHAR;
F and E would have had identical configurations.

The reserved word PACKED only has true significance before the last appearance of the reserved word ARRAY in a declaration of a PACKED ARRAY. When in doubt a good rule of thumb when declaring a multidimensional PACKED ARRAY is to place the reserved word PACKED before every appearance of the reserved word ARRAY to insure that the resultant array will be PACKED.

The resultant array will only be packed if the final type of the array is scalar, or subrange, or a set which can be represented in eight bits or less. The final type can also be BOOLEAN or CHAR. The following declaration will result in no packing whatsoever because the final type of the array cannot be represented in a field of eight bits:

G: PACKED ARRAY[0..3] OF 0..1000;
G will be an array which occupies four 16-bit words.

Packing never occurs across word boundaries. This means that if the type of the element to be packed requires a number of bits which does not divide evenly into 16, there will be some unused bits at the high order end of each of the words which comprise the array.

Note that a string constant may be assigned to a PACKED ARRAY OF CHAR but not to an unpacked ARRAY OF CHAR. Likewise, comparisons between an ARRAY OF CHAR and a string constant are illegal. (These are temporary implementation restrictions which will be removed in the next major release.) Because of their different sizes, PACKED ARRAYs cannot be compared to ordinary unpacked ARRAYs. For further information regarding PACKED ARRAYs OF CHARacters see section 2.2.16 “Strings”.

page144 A PACKED ARRAY OF CHAR may be output with a single write statement:

PROGRAM VERYSLICK;
VAR T: PACKED ARRAY[0..10] OF CHAR;
BEGIN
  T := 'HELLO THERE';
  WRITELN(T)
END.

Initialization of a PACKED ARRAY OF CHAR can be accomplished very efficiently by using the UCSD intrinsics FILLCHAR and SIZEOF:

PROGRAM FILLFAST;
VAR A: PACKED ARRAY[0..10] OF CHAR;
BEGIN
  FILLCHAR(A[0], SIZEOF(A), ' ');
END.

The above sample program fills the entire PACKED ARRAY A with blanks. For further documentation on FILLCHAR, SIZEOF, and the other UCSD intrinsics, see section 2.1.5 “Character Array Manipulation”.

B. Packed Records

The following RECORD declaration declares a RECORD with four fields. The entire RECORD occupies one 16-bit word as a result of declaring it to be a PACKED RECORD.
VAR R: PACKED RECORD
         I, J, K: 0..31;
         B: BOOLEAN
       END;
The variables I, J and K each take up 5 bits in the word. The boolean variable B is allocated to the 16th bit of the same word.

In much the sane manner that PACKED ARRAYs can be multidimensional PACKED ARRAYs, PACKED RECORDs may contain fields which themselves are PACKED RECORDs or PACKED ARRAYs. Again, slight differences in the way in which declarations are made will affect the degree of packing achieved. For example, note that the following two declarations are not equivalent:

VAR A: PACKED RECORD
         C: INTEGER;
         F: PACKED RECORD
              R: CHAR;
              K: BOOLEAN
            END;
         H: PACKED ARRAY[0..3] OF CHAR
       END;
VAR B: PACKED RECORD C: INTEGER; F: RECORD R: CHAR; K: BOOLEAN END; H: PACKED ARRAY[0..3] OF CHAR END;

page145 As with the reserved word ARRAY, the reserved word PACKED must appear with every occurrence of the reserved word RECORD in order for the PACKED RECORD to retain its packed qualities throughout all fields of the RECORD. In the above example, only RECORD A has all of its fields packed into one word. In B, the F field is not packed and therefore occupies two 16 bit words. It is important to note that a packed or unpacked ARRAY or RECORD which is a field of a PACKED RECORD will always start at the beginning of the next word boundary. This means that in the case of A, even though the F field does not completely fill one word, the H field starts at the beginning of the next word boundary.

A case variant may be used as the last field of a PACKED RECORD, and the amount of space allocated to it will be the size of the largest variant among the various cases. The actual nature of the packing is beyond the scope of this document.

VAR K: PACKED RECORD
         B: BOOLEAN;
         CASE F: BOOLEAN OF
           TRUE: (Z:INTEGER);
           FALSE: (M: PACKED ARRAY[O..3] OF CHAR)
         END
       END;

In the above example the B and F fields are stored in two bits of the first 16 bit word of the record. The remaining 14 bits are not used. The size of the case variant field is always the size of the largest variant, so in the above example, the case variant field will occupy two words. Thus the entire PACKED RECORD will occupy 3 words.

C. Using Packed Variables as Parameters

No element of a PACKED ARRAY or field of a PACKED RECORD may be passed as a variable (call-by-reference) parameter to a PROCEDURE or FUNCTION. Packed variables may, however, be passed as call by value parameters, as stated in Jensen and Wirth.

D. Pack and Unpack Standard Procedures

UCSD Pascal does not support the standard procedures PACK and UNPACK as defined in Jensen and Wirth on page 106. If a type or variable is declared as packed, the packing and unpacking in UCSD's Pascal system is implicit.

page146 2.2.9. Parametric Procedures and Functions

UCSD Pascal does not support the construct in which PROCEDUREs and FUNCTIONs may be declared as formal parameters in the parameter list of a PROCEDURE or FUNCTION.

See Section 5.9 for a revised syntax diagram of <parameter-list>.

2.2.10. Program Headings

Although the UCSD Pascal compiler will permit a list of file parameters to be present following the program identifier, these parameters are ignored by the compiler and will have no affect on the program being compiled. As a result the following two program headings are equivalent:


PROGRAM DEMO(INPUT,OUTPUT);
 and 
PROGRAM DEMO;

With either of the above program headings, a user program will have three files predeclared and opened by the system. These are: INPUT, OUTPUT, and KEYBOARD and are defined to be of <type> INTERACTIVE. It the program wishes to declare any additional files, these file declarations must be declared together with the program's other VAR declarations.

2.2.11. Read and Readln

Given the following declarations:
VAR CH:CHAR;
    F: TEXT; (* TYPE TEXT = FILE OF CHAR *)

the statement READ(F, CH) is defined by Jensen and Wirth on page 35 to be equivalent to the the statement sequence:

CH := F^;
GET(F);
J&W
method

In other words, the standard definition of the standard procedure READ requires that the process of opening a file load the “window variable” F^ with the first character of the tile. In an interactive programming environment, it is not convenient to require a user to type in the first character of the input file at the time when the file is opened. If this were the case, every program would “hang” until a character was typed, whether or not the program performed any input operations at all. In order to overcome this problem, UCSD Pascal defines an additional file <type> called INTERACTIVE. Declaring a file F to be of <type> INTERACTIVE is equivalent to declaring F to be of type TEXT, the difference being that the definition of the statement READ(F, CH) is the reverse of the sequence specified by the standard page147 definition for files of <type> TEXT: i.e.

GET(F);
CH := F^;
UCSD
method

This difference affects the way in which EOLN must be used within a program when reading from a text file of type INTERACTIVE. As described in section 5, EOLN becomes true only after reading the end of line character, a carriage return. When this is read, EOLN is set to true and the character returned as a result of the READ will be a blank. In the following example, the left fragment is taken from Jensen and Wirth; only the RESET and REWRITE statements have been altered. The program on the left will correctly copy the text file represented by the file X to the file Y. The program fragment on the right performs a similar task, except that the source file being copied is declared to be a file of <type> INTERACTIVE, thereby forcing a slight change in the program in order to produce the desired result.

PROGRAM JANDW;
VAR X, Y: TEXT;
    CH: CHAR;
BEGIN
  RESET(X, 'SOURCE.TEXT');
  REWRITE(Y, 'SOMETHING.TEXT');

  WHILE NOT EOF(X) DO
    BEGIN
      WHILE NOT EOLN(X) DO
        BEGIN
          READ(X, CH);
          WRITE(Y, CH)
        END;
      READLN(X);
      WRITELN(Y)
    END;
  CLOSE(Y, LOCK)
END.
PROGRAM UCSDVERSION;
VAR X, Y: INTERACTIVE;
    CH: CHAR;
BEGIN
  RESET(X, 'CONSOLE:');
  REWRITE(Y, 'SOMETHING.TEXT');
  READ(X, CH);
  WHILE NOT EOF(X) DO
    BEGIN
      WHILE NOT EOLN(X) DO
        BEGIN
          WRITE(Y, CH);
          READ(X, CH)
        END;
      READLN(X);
      WRITELN(Y)
    END;
  CLOSE(Y, LOCK);
END.

Note that the text files X and Y in the above two programs had to be opened by using the UCSD extended form of the standard procedures RESET and REWRITE.

The CLOSE intrinsic was applied to the file Y in both versions of the program in order to make it a permanent file in the disk directory called “SOMETHING.TEXT”. Likewise, the text file X could have been a disk file instead of coming from the CONSOLE device in the right hand version of the program.

There are three predeclared text files which are automatically opened by the system for a user program. These files are INPUT, OUTPUT, and KEYBOARD. The file INPUT defaults to the CONSOLE device, page148 and is always defined to be of <type> INTERACTIVE. The statement READ(INPUT, CH) where CH is a character variable, will echo the character typed from the CONSOLE back to the CONSOLE device. WRITE statements to the file OUTPUT will, by default, cause the output to appear on the CONSOLE device. The file KEYBOARD is the non-echoing equivalent to INPUT. For example, the two statements p>

READ(KEYBOARD, CH); WRITE(OUTPUT, CH);
are equivalent to the single statement
READ(INPUT, CH);

Reading the type integer causes preceding blanks and end-of-lines to be flushed until a non-blank character is observed. Reading the type BOOLEAN is not implemented.

For more documentation regarding the use of files see sections:

2.2.6 “Files”
2.2.4 “Eof”
2.2.5 “Eoln”
2.2.17 “Write and Writeln”
2.2.12 “Reset”

See section 2.1.2 “Input and Output Intrinsics” for more details on the UCSD intrinsics.

2.2.12. Reset

The standard procedure RESET, as defined on page 9 of Jensen and Wirth, resets the file window to the beginning of the file F. The next GET(F) or PUT(F) will affect record number 0 of the file. In addition, the standard definition of RESET(F) states that the window variable F^ be loaded with the first record in the file. The UCSD implementation of RESET(F) operates exactly as the standard definition, unless the file F is declared to be of <type> INTERACTIVE in which case the statement RESET(F) points the file window to the start of the file, but does not load the window variable F^. Thus, for files of <type> INTERACTIVE, the UCSD equivalent of the standard definition of RESET(F) is the two statement sequence:

RESET(F);
GET(F);
makes INTERACTIVE
look like TEXT

UCSD Pascal defines an alternative form of the standard procedure RESET which is used to open a pre-existing file. In it, RESET has two parameters, the first being the file identifier; the second, either a STRING constant or variable which corresponds to the directory filename of the file being opened. See section 2.1.2 “Input and Output Intrinsics” for more information on this use of RESET.

page149 2.2.13. Rewrite

The standard procedure REWRITE is used to open and create a new file. REWRITE has two parameters, the first being the file identifier, the second corresponds to the directory filename of the file being opened, and must be either a STRING constant or variable. For example, the statement REWRITE(F, 'SOMEINFO.TEXT') causes the file F to be opened for output, and, if the file is locked onto the disk, the filename of the file in the directory will be “SOMEINFO.TEXT”. See section 2.1.2 “Input / Output Intrinsics” for further documentation regarding the use of REWRITE to open a file.

2.2.14. Segment Procedures

The concept of the SEGMENT PROCEDURE is a UCSD extension to Pascal, the primary purpose of which is to allow a programmer the ability to explicitly partition a large program into segments, of which only a few need be resident in memory at any one time. The UCSD Pascal system is necessarily partitioned in this manner because it is too large to fit into the memory of most small interactive computers at one time.

The following is an example of the use of SEGMENT PROCEDUREs:

PROGRAM SEGMENTDEMO;

(* global declarations go here *)

PROCEDURE PRINT(T: STRING); FORWARD;

SEGMENT PROCEDURE ONE;
  BEGIN
    PRINT('SEGMENT NUMBER ONE');
  END;

SEGMENT PROCEDURE TWO;
  SEGMENT PROCEDURE THREE;
    BEGIN
      ONE;
      PRINT('SEGMENT NUMBER THREE');
    END;

  BEGIN (* segment number two *)
    THREE;
    PRINT('SEGMENT NUMBER TWO');
  END;

PROCEDURE PRINT;
  BEGIN
    WRITELN(OUTPUT,T);
  END;

BEGIN
  TWO;
  WRITELN('I''M DONE');
END.

page150 The above program will give the following output:

SEGMENT NUMBER ONE
SEGMENT NUMBER THREE
SEGMENT NUMBER TWO
I'M DOME

For further documentation on SEGMENT PROCEDUREs, their use and syntax governing their declaration, see Section 3.3 “Segment Procedures”

2.2.15. Sets

UCSD Pascal supports all of the constructs defined for sets on pages 50-51 of Jensen and Wirth. Sets (of enumeration values) are limited to positive integers only. Space is assigned, rounding up to word boundaries, in a bitwise fashion, starting at zero, up to 4079, inclusive. Therefore a set can be at most 255 words in size, and have at most 4080 elements.

Comparisons and operations on sets are allowed only between sets which are either of the same base type or subranges of the same underlying type. For example, in the sample program below, the base type of the set S is the subrange type 0..149, while the base type of the set R is the subrange type 1. .100. The underlying type of both sets is the type INTEGER, which by the above definition of comparability, implies that the comparisons and operations on the sets S and R in the following program are legal:

PROGRAM SETCOMPARE;
VAR S: SET OF 0..149;
    R: SET OF 1..100;

BEGIN
  S:= [0, 5, 10, 15, 20, 25, 30, 35, 140, 145];
  R:= [1O, 2O, 3O, 4O, 5O, 60, 70, 80, 90];
  IF S = R THEN
    WRITELN('... OOPS ...')
  ELSE
    WRITELN('SETS WORK');
  S := S + R;
END.

In the following example, the construct I = J is not legal since the the sets are of two distinct underlying types.

page151

PROGRAM ILLEGALSETS;
TYPE STUFF: (ZERO, ONE, TWO);
VAR I: SET OF STUFF;
    J: SET OF 0..2;

BEGIN
  I:= [ZERO];
  J:= [1,2];
  IF I = J THEN ... <<<< error here
END.

2.2.16. Strings

UCSD Pascal has an additional predeclared type STRING. Variables of type STRING are essentially PACKED ARRAYs OF CHAR that have a dynamic LENGTH attribute, the value of which is returned by the intrinsic LENGTH. The default maximum LENGTH of a STRING variable is 80 characters but can be overridden in the declaration of a STRING variable by appending the desired LENGTH of the STRING variable within [ ] after the reserved type identifier STRING. Examples of declarations of STRING variables are:
TITLE: STRING; (* defaults to a maximum length of 80 characters *)

NAME: STRING[20]; (* allows the STRING to be a maximum of 20 characters *)
Note that a STRING variable has an absolute maximum length of 255 characters. Assignments to string variables can be performed using the assignment statement, the UCSD STRING intrinsics, or by means of a READ statement:
TITLE := '    THIS IS A TITLE    ';
or
READLN(TITLE);
or
NAME := COPY(TITLE, 1, 20);
The individual characters within a STRING are indexed from 1 to the LENGTH of the STRING, for example:
TITLE[1] := 'A';
page152
TITLE[LENGTH(TITLE)] := 'Z';

A variable of type STRING may not be indexed beyond its current dynamic LENGTH; beware of strings of length zero! The following sequence will result in an invalid index run time error:

TITLE:= '1234';
TITLE[5]:= '5';

A variable of type STRING may be compared to any other variable of type STRING or a string constant no matter what its current dynamic LENGTH. Unlike comparisons involving variables of other types, STRING variables may be compared to items of a different LENGTH. The resulting comparison is lexicographical. The following program is a demonstration of legal comparisons involving variables of type STRING:

PROGRAM COMPARESTRINGS;
VAR S: STRING;
    T: STRING[4O];

BEGIN
  S := 'SOMETHING';
  T := 'SOMETHING BIGGER';
  IF S = T THEN
    WRITELN('Strings do not work very well')
  ELSE
  IF S > T THEN
    WRITELN(S, ' is greater than ', T)
  ELSE
   IF S < T THEN
     WRITELN(S, ' is less than ', T);
  IF S = 'SOMETHING' THEN
    WRITELN(S, ' equals ', S);
  IF S > 'SAMETHING' THEN
    WRITELN(S, ' is greater than SAMETHING');
  IF S = 'SOMETHING               ' THEN
    WRITELN('BLANKS DON''T COUNT')
  ELSE
    WRITELN('BLANKS APPEAR TO MAKE A DIFFERENCE');
  S := 'XXX';
  T := 'ABCDEF';
  IF S > T THEN
    WRITELN(S, ' is greater than ', T)
  ELSE
    WRITELN(S, ' is less than ', T);
END.

page153 The above program produces the following output:

SOMETHING is less than SOMETHING BIGGER
SOMETHING equals SOMETHING
SOMETHING is greater than SAMETHING
BLANKS APPEAR TO MAKE A DIFFERENCE
XXX is greater than ABCDEF

One of the most common uses of STRING variables in the UCSD Pascal system is reading file names from the CONSOLE device:

PROGRAM LISTER;
VAR BUFFER: PACKED ARRAY[O..51l] OF CHAR;
    FILENAME: STRING;
    F: FILE;

BEGIN
  WRITE('Enter filename of the file to be listed --->');
  READLN(FILENAME);
  RESET(F,FILENAME);
  WHILE NOT EOF(F) DO
    BEGIN
      ...
      ...
      ...
    END;
END.

When a variable of type STRING is a parameter to the standard procedure READ and READLN, all characters up to the end of line character (a carriage return) in the source file will be assigned to the STRING variable. Note that care must be taken when reading STRING variables, for example, the single statement READLN(S1,S2) is equivalent to the two statement sequence READ(S1); READLN(S2). In both cases the STRING variable S2 will be assigned the empty string.

For further information concerning the predeclared type STRING see Section 2.1.1 “String Intrinsics”.

2.2.17. Write and Writeln

The standard procedures WRITE and WRITELN are compatible with Standard Pascal, except with respect to a WRITE or a WRITELN of a variable of type BOOLEAN. UCSD Pascal does not support the output of the words TRUE or FALSE when writing out the value of a BOOLEAN variable.

page154 For a description of WRITE statements of variables of type STRING see Section 2.1.1 “String Intrinsics”.

UCSD's WRITE and WRITELN do support the writing of entire PACKED ARRAYs OF CHAR in a single WRITE statement:

VAR BUFFER: PACKED ARRAY [0..10] OF CHAR;
BEGIN
  BUFFER := 'HELLO THERE'; (* contains exactly 11 characters *)
  WRITELN(OUTPUT, BUFFER);
END.

The above construct will work only if the ARRAY is a PACKED ARRAY OF CHAR. See section 2.2.8 “Packed Variables” for further information.

The following program demonstrates the effects of a field width specification within a WRITE statement for a variable of type STRING:

PROGRAM WRITESTRING;
VAR S: STRING;

BEGIN
  S := 'THE BIG BROWN FOX JUMPED...';
  WRITELN(S);
  WRITELN(S: 30);
  WRITELN(S: 10);
END.

The above program will produce the following output:

THE BIG BROWN FOX JUMPED...
THE BIG BROWN FOX JUMPED...
THE BIG BR
Note that when a string variable is written without specifying a field width, the actual number of characters written is equal to the dynamic length of the string. If the field width specified is longer than the dynamic length of the string, leading blanks are inserted and written. If the field width is smaller than the dynamic length of the string, the excess characters will be truncated on the right.

2.2.18. Implementation Size Limits

The following is a list of maximum size limitations imposed upon the user by the current implementation of UCSD Pascal:
  1. page155 Maximum number of bytes of object code in a PROCEDURE or FUNCTION is 1200. Local variables in a PROCEDURE or FUNCTION can occupy a maximum of 16383 words of memory.
  2. Maximum number of characters in a STRING variable is 255.
  3. Maximum number of elements in a SET is 255*16 = 4080.
  4. Maximum number of SEGMENT PROCEDUREs and SEGMENT FUNCTIONs is 16 (9 are reserved for the Pascal system, 7 are available for use by the user program).
  5. Maximum number of PROCEDURES or FUNCTIONs within a segment is 127.

2.2.19. Extended Comparisons

UCSD Pascal allows = and <> comparisons of any array or record structure.

2.2.20. Long Integers

UCSD Pascal allows integers of up to 36 digits. See section 3.3.3 for details regarding long integers.

2.2.21. Units

UCSD Pascal now supports the modularity concept of UNITs. See section 3.3.2 for details regarding UNITs.

2.2.22. Summary of UCSD Intrinsics

IntrinsicSectionDescription
BLOCKREAD 2.1.2 Function which reads a variable number of blocks from an untyped file.
BLOCKWRITE 2.1.2 Function which writes a variable number of blocks from an untyped file.
CLOSE 2.1.2 Procedure to close files.
CONCAT 2.1.1 STRING intrinsic used to concatenate strings together.
DELETE 2.1.1 STRING intrinsic used to delete characters from STRING variables.
EXIT 2.1.3 Intrinsic used to exit PROCEDURES cleanly.
BLOCKREAD 2.1.2 page156 Function which reads a variable number of blocks
GOTOXY 2.1.3 Procedure used for cursor addressing whose two parameters X and Y are the column and line numbers on the screen where the cursor is to be placed.
FILLCHAR 2.1.5 Fast procedure for initializing PACKED ARRAYs CF CHAR.
HALT 2.1.3 Halts a user program which may result in a call to the interactive Debugger.
IDSEARCH --- Routine used by the Pascal compiler, and the PDP-l1 assembler.
INSERT 2.1.1 STRING intrinsic used to insert characters in STRING variables.
IORESULT 2.1.2 Function returning the result of the previous I/O operation. (See section 5.2 for a list of values)
LENGTH 2.1.1 STRING intrinsic which returns the dynamic length of a STRING variable.
MARK 2.1.3 Used to mark the current top of the heap in dynamic memory allocation.
MEMAVAIL 2.1.3 Returns number of words between Heap and Stack.
MOVELEFT 2.1.5 Low level intrinsic for moving mass amounts of bytes.
MOVERIGHT 2.1.5 Low level intrinsic for moving mass amounts of bytes.
REWRITE 2.1.2 Procedure for opening a new file.
RESET 2.1.2 Procedure for opening an existing file.
POS 2.1.1 STRING intrinsic returning the position of a pattern in a STRING variable.
PWROFTEN 2.1.3 Function which returns as a REAL result the number 10 raised to the power of the integer parameter supplied.
RELEASE 2.1.3 Intrinsic used to release memory occupied by variables dynamically allocated In the heap.
SEEK 2.1.2 Used for random accessing of records within a file.
SIZEOF 2.1.3 Function returning the number of bytes allocated to a variable.
STR 2.1.1 Procedure to convert long integer into string.
TIME 2.1.3 page157 Function returning the time since last bootstrap of system (returns zero if microcomputer has no real time clock).
TREESEARCH --- Routine used solely by the Pascal compiler.
UNITBUSY 2.1.2 Low level intrinsic for determining the status of a peripheral device.
UNITCLEAR 2.1.2 Low level intrinsic to cancel I/O from a peripheral device.
UNITREAD 2.1.2 Low level intrinsic for reading from a peripheral1 device.
UNITWAIT 2.1.2 Low level intrinsic for waiting until a peripheral device has completed an I/O operation.
UNITWRITE 2.1.2 Low level intrinsic used for writing to a peripheral device.

page158
This page last regenerated Sun Jul 25 01:09:11 2010.