PC_PRLIB(7ACK)

NAME
pc_prlib - library of Pascal runtime routines

SYNOPSIS
type	alpha=packed array[1..8] of char;
	pstring= ^packed array[] of char;
function	_abi(i:integer):integer;
function	_abl(i:long):long;
function	_mdi(j,i:integer):integer;
function	_mdl(j,i:long):long;
function	_abr(r:real):real;
function	_sin(r:real):real;
function	_cos(r:real):real;
function	_atn(r:real):real;
function	_exp(r:real):real;
function	_log(r:real):real;
function	_sqt(r:real):real;
function	_rnd(r:real):real;
type	compared=-1..1;
	gotoinfo=record
	    pcoffset:^procedure; { procedure id. without static link }
	    nlocals: integer;
	end;
function	_bcp(sz:integer; s2,s1:pstring):compared;
function	_bts(size,high,low:integer; base:^set 0..(8*size-1))
			:set of 0..(8*size-1);
procedure	_gto(lb:^integer; p:^gotoinfo);
procedure	_new(size:integer; var p:^integer);
procedure	_dis(size:integer; var p:^integer);
procedure	_sav(var p:^integer);
procedure	_rst(var p:^integer);
type	arrdescr=record
	    lowbnd:  integer;
	    diffbnds:integer;
	    elsize:  integer;
	end;
	arr1=array[] of ?;
	arr2=packed array[] of ?;
procedure	_pac(var ad,zd:arrdescr; var zp:arr2; i:integer;
		      var ap:arr1);
procedure	_unp(var ad,zd:arrdescr; i:integer; var ap:arr1;
		      var zp:arr2;);
function	_asz(var dp:arrdescr):integer;
procedure	_ass(line:integer; b:boolean);
procedure	procentry(var name:alpha);
procedure	procexit(var name:alpha);
const	lowbyte=[0..7];
	MAGIC  =[1,3,5,7];
	WINDOW =[11];
	ELNBIT =[12];
	EOFBIT =[13];
	TXTBIT =[14];
	WRBIT  =[15];
type	file=record
	    ptr:	^char;
	    flags:	set of [0..15];
	    fname:	string;
	    ufd:	0..15;
	    size:	integer;
	    count:	0..buflen;
	    buflen:	max(512,size) div size * size;
	    bufadr:	packed array[1..max(512,size)]
			     of char;
	end;
	filep=^file;
const	NFILES=15;
	_extfl:^array[] of filep;
procedure	_ini(var args:integer; var hb:integer;
			    var p:array[] of filep; var mainlb:integer);
procedure	_hlt(status:0..255);
procedure	_opn(size:integer; f:filep);
procedure	_cre(size:integer; f:filep);
procedure	_cls(f:filep);
procedure	_get(f:filep);
procedure	_put(f:filep);
function	_wdw(f:filep):^char;
function	_efl(f:filep):boolean;
function	_eln(f:filep):boolean;
function	_rdc(f:filep):char;
function	_rdi(f:filep):integer;
function	_rdl(f:filep):long;
function	_rdr(f:filep):real;
procedure	_rln(f:filep);
procedure	_wrc(c:char; f:filep);
procedure	_wsc(w:integer; c:char; f:filep);
procedure	_wri(i:integer; f:filep);
procedure	_wsi(w:integer; i:integer; f:filep);
procedure	_wrl(l:long; f:filep);
procedure	_wsl(w:integer; l:long; f:filep);
procedure	_wrr(r:real; f:filep);
procedure	_wsr(w:integer; r:real; f:filep);
procedure	_wrf(ndigit:integer; w:integer; r:real; f:filep);
procedure	_wrs(l:integer; s:pstring; f:filep);
procedure	_wss(w:integer; l:integer; s:pstring; f:filep);
procedure	_wrb(b:boolean; f:filep);
procedure	_wsb(w:integer; b:boolean; f:filep);
procedure	_wrz(s:string; f:filep);
procedure	_wsz(w:integer; s:string; f:filep);
procedure	_wln(f:filep);
procedure	_pag(f:filep);

DESCRIPTION
This library is used by the Pascal to EM compiler and contains all the runtime routines for standard Pascal programs. Most routines are written in C, a few in EM assembly language. These routines can be divided into several categories. A description of each category with its routines follows.

Arithmetic routines:

    _abi
        Compute the absolute value of an integer.
    _abl
        Compute the absolute value of a long.
    _mdi
        Perform the Pascal modulo operation on integers.
    _mdl
        Perform the Pascal modulo operation on longs.
    _abr
        Compute the absolute value of a real.
    _sin
        Compute the sine of a real.
    _cos
        Compute the cosine of a real.
    _atn
        Compute the arc tangent of a real.
    _exp
        Compute the e-power of a real.
    _log
        Compute the natural logarithm of a real.
    _sqt
        Compute the square root of a real.
    _rnd
        Return a real that when truncated will result in the nearest integer (-3.5->-4).

Miscellaneous routines:

    _bcp
        Compare two strings. Use dictionary ordering with the ASCII character set. The EM instruction CMU can not be used, because it needs an even number of bytes.
    _bts
        Include a range of elements from low to high in a set of size bytes at address base.(size can be divided by the wordsize)
    _gto
        Execute a non-local goto. Lb points to the local base of the target procedure. A lb of zero indicates a jump to the program body, the lb of the main program is found in _m_lb, which is set by _ini. The new EM stack pointer is calculated by adding the number of locals to the new local base (jumping into statements is not allowed; there are no local generators in Pascal!).

Heap management:

    There is one way to allocate new heap space (_new), but two different incompatible ways to deallocate it.

    The most general one is by using dispose (_dis). A circular list of free blocks, ordered from low to high addresses, is maintained. Merging free blocks is done when a new block enters the free list. When a new block is requested (_new), the free list is searched using a first fit algorithm. Two global variables are needed:

    _highp
        Points to the free block with the highest address.
    _lastp
        Points to the most recently entered free block or to a block in the neighborhood of the most recently allocated block. The free list is empty, when one of these pointers (but then at the same time both) is zero.

    The second way to deallocate heap space is by using mark (_sav) and release (_rst). Mark saves the current value of the heap pointer HP in the program variable passed as a parameter. By calling release with this old HP value as its argument, the old HP value is restored, effectively deallocating all blocks requested between the calls to mark and release. The heap is used as second stack in this case.

    It will be clear that these two ways of deallocating heap space can not be used together. To be able to maintain the free list, all blocks must be a multiple of n bytes long, with a minimum of n bytes, where n is the sum of the size of a word and a pointer in the EM implementation used.

    In summary:

    _new
        Allocate heap space.
    _dis
        Deallocate heap space.
    _sav
        Save the current value of HP.
    _rst
        Restore an old value of HP.

Array operations:

    The only useful form of packing implemented, is packing bytes into words. All other forms of packing and unpacking result in a plain copy.

    _pac
        Pack an unpacked array a into a packed array z. ap and zp are pointers to a and z. ad and zd are pointers to the descriptors of a and z. i is the index in a of the first element to be packed. Pack until z is full.
    _unp
        Unpack z into a. ap, zp, ad and zd are as for _pac. i is the index in a where the first element of z is copied into. Unpack all elements of z.
    _asz
        Compute array size. Used for copying conformant arrays.

Debugging facilities:
    The compiler allows you to verify assertions. It generates a call to the routine _ass to check the assertion at runtime. Another feature of the compiler is that it enables you to trace the procedure calling sequence. If the correct option is turned on, then a call to the procedure procentry is generated at the start of each compiled procedure or function. Likewise, the routine procexit is called just before a procedure or function exits. Default procedure procentry and procexit are available in this library.

    _ass
        If b is zero, then change eb[0] to line (to give an error message with source line number) and call the error routine.
    procentry
        Print the name of the called procedure with up to seven argument words in decimal on standard output. Output must be declared in the program heading.
    procexit
        Print the name of the procedure that is about to exit. Same remarks as for procentry.

Files:

    Most of the runtime routines are needed for file handling. For each file in your Pascal program a record of type file, as described above, is allocated, static if your file is declared in the outermost block, dynamic if it is declared in inner blocks. The fields in the file record are used for:

    bufadr
        IO is buffered except for standard input and output if terminals are involved. The size of the buffer is the maximum of 512 and the file element size.
    buflen
        The effective buffer length is the maximum number of file elements fitting in the buffer, multiplied by the element size.
    size
        The file element size (1 or even).
    flags
        Some flag bits are stored in the high byte and a magic pattern in the low byte provides detection of destroyed file information.
    ptr Points to the file window inside the buffer.
    count
        The number of bytes (the window inclusive) left in the buffer to be read or the number of free bytes (the window inclusive) for output files.
    ufd The UNIX file descriptor for the file.
    fname
        Points to the name of the file (INPUT for standard input, OUTPUT for standard output and LOCAL for local files). This field is used for generating error messages.

    The constants used by the file handling routines are:

    WINDOW
        Bit in flags set if the window of an input file is initialized. Used to resolve the famous interactive input problem.
    EOFBIT
        Bit in flags set if end of file seen
    ELNBIT
        Bit in flags set if linefeed seen
    TXTBIT
        Bit in flags set for text files. Process linefeeds.
    WRBIT
        Bit in flags set for output files
    MAGIC
        Pattern for the low byte of flags
    NFILES
        The maximum number of open files in UNIX

Prelude and postlude:

    These routines are called once for each Pascal program:

    _ini
        When a file mentioned in the program heading is opened by reset or rewrite, its file pointer must be mapped onto one of the program arguments. The compiler knows how to map and therefore builds a table with a pointer to the file structure for each program argument. One of the first actions of the Pascal program is to call this procedure with this table as an argument. The global variable _extfl is used to save the address of this table. Another task of _ini is to initialize the standard input and output files. For standard output it must decide whether to buffer or not. If standard output is a terminal, then buffering is off by setting buflen to 1. Two other task of _ini are the copying of two pointers from the argument list to global memory, mainlb to _m_lb and hb to _hbase. The first contains the local base of the program body, the second contains the address of the hol containing the global variables of the program. A last task of _ini is to set the global variables _argc, _argv and _environ from args for possible reference later on. Args points to the argument count placed on the stack by the EM runtime system, see chapter 8 in [1].
    _hlt
        If the program is about to finish, the buffered files must be flushed. That is done by this procedure.

Opening and closing:

    Files in Pascal are opened for reading by reset and opened for writing by rewrite. Files to be rewritten may or may not exist already. Files not mentioned in the program heading are considered local files. The next steps must be done for reset and rewrite:

    1.  If size is zero, then a text file must be opened with elements of size 1.
    2.  Find out if this file is mentioned in the program heading (scan table pointed to by _extfl). If not, then it is a local file and goto 7.
    3.  If the file is standard input or output then return.
    4.  If there are not enough arguments supplied, generate an error.
    5.  If the file was already open, flush the buffer if necessary and close it. Note that reset may be used to force the buffer to be flushed. This is sometimes helpful against program or system crashes.
    6.  If it is a reset, open the file, otherwise create it. In both cases goto 9.
    7.  If the local file is to be written, then close it if it was open and create a new nameless file. First try to create it in /usr/tmp, then in /tmp and if both fail then try the current directory. See to it that the file is open for both reading and writing.
    8.  If the local file is to be read and the file is opened already, then flush the buffer and seek to the beginning. Otherwise open a temporary file as described in 7.
    9.  Initialize all the file record fields.

    The necessary procedures are:

    _opn
        Reset a file
    _cre
        Rewrite a file
    _cls
        Close a file. Closing of files is done for local files when the procedure in which they are declared exits. The compiler only closes local files if they are not part of a structured type. Files allocated in the heap are not closed when they are deallocated. There is an external routine pclose in libP(VII), that may be called explicitly to do the closing in these cases. Closing may be necessary to flush buffers or to keep the number of simultaneously opened files below NFILES. Files declared in the outermost block are automatically closed when the program terminates.

General file IO:

    These routines are provided for general file IO:

    _put
        Append the file element in the window to the file and advance the window.

    _get
        Advance the file window so that it points to the next element of the file. For text files (TXTBIT on) the ELNBIT in flags is set if the new character in the window is a line feed (ASCII 10) and the character is then changed into a space. Otherwise the ELNBIT is cleared.

    _wdw
        Return the current pointer to the file window.

    _eof
        Test if you reached end of file. Is always true for output files.

Textfile routines:

    The rest of the routines all handle text files.

    _eln
        Return true if the next character on an input file is an end-of-line marker. An error occurs if eof(f) is true.
    _rdc
        Return the character currently in the window and advance the window.
    _rdi
        Build an integer from the next couple of characters on the file, starting with the character in the window. The integer may be preceded by spaces (and line feeds), tabs and a sign. There must be at least one digit. The first non-digit signals the end of the integer.
    _rdl
        Like _rdi, but for longs.
    _rdr
        Like _rdi, but for reals. Syntax is as required for Pascal.
    _rln
        Skips the current line and clears the WINDOW flag, so that the next routine requiring an initialized window knows that it has to fetch the next character first.
    _wrc
        Write a character, not preceeded by spaces.
    _wsc
        Write a character, left padded with spaces up to a field width of w.
    _wri
        Write an integer, left padded with spaces up to a field width of 6.
    _wsi
        Write an integer, left padded with spaces up to a field width of w.
    _wrl
        Write a long, left padded with spaces up to a field width of 11.
    _wsl
        Write a long, left padded with spaces up to a field width of w.
    _wrr
        Write a real in scientific format, left padded with spaces up to a field width of 13.
    _wsr
        Write a real in scientific format, left padded with spaces up to a field width of w.
    _wrf
        Write a real in fixed point format, with exactly ndigit digits behind the decimal point, the last one rounded; it is left padded up to a field width of w.
    _wrs
        Write a string of length l, without additional spaces.
    _wss
        Write a string of length l, left padded up to a field width of w.
    _wrb
        Write a boolean, represented by "true" or "false", left padded up to a field width of 5.
    _wsb
        Write a boolean, represented by "true" or "false", left padded up to a field width of w.
    _wrz
        Write a C-type string up to the zero-byte.
    _wsz
        Write a C-type string, left padded up to a field width of w.
    _wln
        Write a line feed (ASCII 10).
    _pag
        Write a form feed (ASCII 12).

All the routines to which calls are generated by the compiler are described above. They use the following global defined routines to do some of the work:

_rf Check input files for MAGIC and WRBIT. Initialize the window if WINDOW is cleared.
_wf Check output files for MAGIC and WRBIT.
_incpt
    Advance the file window and read a new buffer if necessary.
_outcpt
    Write out the current buffer if necessary and advance the window.
_flush
    Flush the buffer if it is an output file. Append an extra line marker if EOLBIT is off.
_wstrin
    All output routines make up a string in a local buffer. They call _wstrin to output this buffer and to do the left padding.
_skipsp
    Skip spaces (and line feeds) on input files.
_getsig
    Read '+' or '-' if present.
_fstdig
    See to it that the next character is a digit. Otherwise error.
_nxtdig
    Check if the next character is a digit.
_getint
    Do the work for _rdi.
_ecvt
    Convert real into string of digits for printout in scientific notation.
_fcvt
    Convert real into string of digits for fixed point printout
-fif
    Split real into integer and fraction part
_fef
    Split real into exponent and fraction part

The following global variables are used:

_lastp
    For heap management (see above).
_highp
    For heap management (see above).
_extfl
    Used to save the argument p of _ini for later reference.
_hbase
    Used to save the argument hb of _ini for later reference.
_m_lb
    Used to store the local base of the main program.
_curfil
    Save the current file pointer, so that the error message can access the file name.
_pargc, _pargv, _penvp
    Used to access the arguments of the main program.

FILES

~em/lib/*/tail_pc
    The library used by ack[5] to link programs.

~em/etc/pc_rterrors
    The error messages

SEE ALSO

[1] A.S. Tanenbaum, Ed Keizer, Hans van Staveren & J.W. Stevenson "Description of a machine architecture for use of block structured languages" Informatica rapport IR-81.
[2] K.Jensen & N.Wirth "PASCAL, User Manual and Report" Springer-Verlag.
[3] An improved version of the ISO standard proposal for the language Pascal ISO/TC97/SC5-N462, received November 1979.
[4] Ed Keizer, "The Amsterdam Compiler Kit reference manual".
    (try nroff ~em/doc/pcref.doc).
[5] ack(1), pc_pem(6)

DIAGNOSTICS
All errors discovered by this runtime system cause an EM TRP instruction to be executed. This TRP instruction expects the error number on top of the stack. See [1] for a more extensive treatment of the subject.

EM allows the user to specify a trap handling routine, called whenever an EM machine trap or a language or user defined trap occurs. One of the first actions in _ini is to specify that the routine _fatal, available in this library, will handle traps. This routine is called with an error code (0..252) as argument. The file "~em/etc/pc_rterrors" is opened and searched for a message corresponding with this number. If the file can not be opened, or if the error number is not recorded in the file, then the same trap is generated again, but without a user-defined trap handler, so that the low levels generate an error message. Otherwise the following information is printed on file descriptor 2:

-   The name of the Pascal program
-   The name of the file pointed to by _curfil, if the error number is between 96 and 127 inclusive.
-   The error message (or the error number if not found).
-   The source line number if not equal to 0.

The routine _fatal stops the program as soon as the message is printed.

The following error codes are used by the Pascal runtime system:

64  more args expected
65  error in exp
66  error in ln
67  error in sqrt
68  assertion failed
69  array bound error in pack
70  array bound error in unpack
71  only positive j in i mod j
72  file not yet open
73  dispose error

96  file xxx: not writable
97  file xxx: not readable
98  file xxx: end of file
99  file xxx: truncated
100 file xxx: reset error
101 file xxx: rewrite error
102 file xxx: close error
103 file xxx: read error
104 file xxx: write error
105 file xxx: digit expected
106 file xxx: non-ASCII char read

AUTHORS
Johan Stevenson and Ard Verhoog, Vrije Universiteit.