Version II.0, February 1979
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.
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.
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.
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;
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 |
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.
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.
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).
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.
(*$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:
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.WHILE BLOCKWRITE(F, BUFFER, BLOCKREAD(G, BUFFER, BUFBLOCKS)) > 0 DO (* it *);
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.
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.
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;
If the above program were supplied the following inputPROCEDURE 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.
the following output will result:THIS IS THE FIRST STRING # LAST STRING
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.
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.
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.
The following two declarations are not equivalent due to the recursive nature of the compiler:
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 asE: PACKED ARRAY[O..9] OF ARRAY[0..3] OF CHAR; F: PACKED ARRAY[0..9, 0..3] OF CHAR;
or asE: PACKED ARRAY[0..9] OF PACKED ARRAY[0..3] OF CHAR;
F and E would have had identical configurations.E: ARRAY[0..9] OF PACKED ARRAY[0..3] OF CHAR;
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 will be an array which occupies four 16-bit words.G: PACKED ARRAY[0..3] OF 0..1000;
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”.
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”.
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.VAR R: PACKED RECORD I, J, K: 0..31; B: BOOLEAN END;
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; |
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.
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>.
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.
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 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, 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.
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.
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.
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.
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”
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.
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.
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: STRING; (* defaults to a maximum length of 80 characters *) NAME: STRING[20]; (* allows the STRING to be a maximum of 20 characters *)
orTITLE := ' THIS IS A TITLE ';
orREADLN(TITLE);
The individual characters within a STRING are indexed from 1 to the LENGTH of the STRING, for example:NAME := COPY(TITLE, 1, 20);
TITLE[1] := 'A';
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.
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”.
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:
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.THE BIG BROWN FOX JUMPED... THE BIG BROWN FOX JUMPED... THE BIG BR
Intrinsic | Section | Description |
---|---|---|
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 | 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 | 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. |