DOS65 Pascal

20160330_141921_HDRPieter de Visser has written an ISO standard Pascal compiler (according to Pascal User and Manual, Jensen & Wirth) for DOS65. Including floating point!
Quite an achievement, since the limited memory in a DOS65 system and the unfriendly nature of the 6502 towards stackframe based languages.

The compiler is written in assembler, in two flavours: 6502 and 65C02. For the 65C02 version the assembler sources are available.

Here an archive with sources and the compiler files. And some test files here.

PPPP     A     SSS    CCC     A    L
P   P   A A   S   S  C   C   A A   L
P   P  A   A  S      C      A   A  L
P      A   A      S  C      A   A  L
P      A   A  S   S  C   C  A   A  L
P      A   A   SSS    CCC   A   A  LLLLL
DOS65 Pascal version 1.0 manual
Copyright (c) 1988 by Pieter de Visser
Nijverheidslaan 6
5506 EE Veldhoven
The Netherlands
0. Introduction
1. Installation
2. Starting the compiler
3. Extensions
4. Implementation defined and other features
5. Compiler errors
6. Runtime errors
7. Undetected errors 
0. Introduction
This manual describes version 1.0 of the DOS65 Pascal compiler, named pascal.
This compiler complies with the level 1 ISO Pascal standard, which is defined
Pascal user manual and report
Kathleen Jensen and Niklaus Wirth
Third edition
References to the report will be represented by enclosing the section number
in parentheses.
The compiler possesses an option for enabling some extensions, which will be
described later on.
1. Installation
Two versions of pascal are available, one for the normal 6502 processor and
one for the 65C02 processor (all manufacturers). The 65C02 version compiler
can only be run on a 65C02 system, and the same applies for the code it
generates. Of course, the normal 6502 version can be run on a 65C02 system as
well. The 65C02 version has two advantages: both the compiler itself and the
code it generates are somewhat smaller (in terms of memory space) and a bit
Four files are needed to use the compiler: "pascal", "paaa", "runc.bin" and
"runctab.mac". "pascal" and "paaa" are to be put on the system drive,
"runc.bin" and "runctab.mac" on the user drive. "pascal" contains the compiler
proper; "paaa" contains invocations of "as", "append" and "setmode";
"runc.bin" contains the runtime routines, and "runctab.mac" their addresses.
2. Starting the compiler
The command line syntax for starting the compiler is the following:
pascal [-aeo] <filespec>
Here, <filespec> stands for any file specification. "pascal" may be
abbreviated to "pa". Let <name> be a sequence of characters such that the
first file found corresponding to "<filespec>.pas" is "<name>.pas". If no such
file exists, the file specification is considered to be wrong.
Otherwise, if no options are selected, file "<name>.pas" is compiled and
assemblerfile "<name>.mac" is generated. Any error messages are written to the
standard output. If no errors are detected, "<name>.mac" is assembled and
objectfile "<name>.bin" is generated. The latter may be used as an ordinary
commandfile. If errors are detected however, "<name>.mac" is not assembled and
no assumptions should be made about its contents.
If, for some reason, one wants to assemble "<name>.mac", command "paaa" should
be used: paaa <name>.
The following compiler options are provided:
-A: Inhibits assembly of the compiler output file ("<name>.mac").
-E: Enables extensions; see section 3.
-O: Inhibits any code output; "<name>.mac" is not created.
If a wrong file specification is given in the command line (e.g. it is too
long), an error is reported. Any other error in the command line will cause a
help message to be shown.
3. Extensions
Some extensions to the ISO standard are available, when the -E option has been
- The '_' (underscore) character can be used in an identifier at any place
(i.e. instead of a letter).
- Comments are nested, i.e. any '(*' or '{' appearing within a comment starts
a new comment and must be matched by a '*)' or a '}'.
- An else-clause is possible in a case-statement; the syntax of a
case-statement now becomes
"case" CaseIndex "of"
Case { ";" Case }  [ "else" Statement ]  [ ";" ]
If there is no constant prefixing a statement with the same value as that of
the case index, the statement following the else is executed.
4. Implementation defined and other features
maxint = 32767 (4, 5, 6.1.2)
Characters and their corresponding values correspond to the standard ascii
set. All values except decimal 13 (carriage return) and 39 (apostrophe) are
permitted in character strings. However, a valid character corresponds with
all ordinal numbers in the range 0..255 (4, 6.1.2).
A real number r is representable if and only if it is zero or there exist
natural numbers m and e such that 2^31 <= m < 2^32 and -127 <= e <= 127 and
either r = m * 2^(e-32) or r = - m * 2^(e-32), where the operator "^" stands
for "raised to the power". More specifically, the absolute values of both the
smallest and the largest number representable are about 1.7 * 10^38; the
accuracy is 9 digits (6.1.2).
The default field widths for procedure write are 7 for type integer, 12 for
type real and 6 for type boolean (12.3).
The number of digits occurring in the scale factor of the floating-point
representation is 2 (
The letter occurring just before this scale factor is the 'E' (
The boolean values are entirely written in lower-case (12.3.4).
The effect of page(f) is to append a character with decimal value 12
(formfeed) to f (12.5).
The delayed evaluation of input^ is supported (manual (sic!) 12.A).
A program parameter must stand for a file variable. Except for input and
output, the name of the actual file must be given in the commandline at the
time the object commandfile is called. The order of the actual and the formal
parameters is the same (13).
The name of a local file variable (i.e., not a program parameter) is of the
form paslocfdX, where X stands for a digit in the range 4..9.
Applying reset or rewrite to either input or output has no single effect (13).
If the two arguments of a read procedure are input and a variable with type
integer or real (or subrange of integer), a whole line must be returned,
terminated by a carriage return. Special characters are ^V, ^U, ^Y and <del>,
just as in DOS65. The characters on this line, up to and including the
carriage return, are inserted before the normal input character stream.
Except for input and output, at most 6 program parameters may be specified.
The maximum block nesting is 16.
The maximum for statement nesting is 8.
The maximum with statement nesting is 8.
All elements of any set should have ordinal values in range 0..127 only.
5. Compiler errors
Each error message consists of a line number (numbering starts at 1), the
message itself, the contents of the indicated line, and in most cases an arrow
indicating a position in that line. This position is not always the exact
place where the error occurs. Some errors are fatal and cause compilation to
be aborted; in all other cases, the compiler recovers from the error. The list
of possible errors is shown below. A "%s" will be replaced by a name, a "%d"
by a number.
The cardinality of a type is too high.
Name clash
The name of the constant or type being declared should not appear
after the '='.
Unexpected end of file (fatal)
External file %s not declared (13)
Constant(s) missing
All values of the tag type must be specified (6.2.2).
Invalid label
The apparent value of a label must not exceed 9999 (10.1).
Incorrect number
Incorrect type
The minimum and maximum ordinal value of any set base type should be
in range 0..127.
The constants in a subrange type specification should possess the same
type; the value of the second constant should be at least that of the
first one (6.1.3).
The component type of a file type should be assignable (6.2.4).
Invalid variable
A for control variable is threatened or used as another for control
variable, or a nonlocal or non-ordinal variable is used as for control
variable, or a for control variable, a component of a packed array or
record variable or a tag field is used as an actual variable parameter
Line too long
The maximum line length is 80 characters.
Memory full (fatal)
This error can occur in a very complicated construction; a remedy is
then to simplify this construction.
Another cause can be the nesting of several case statements; try to
narrow the range of constants used in those statements.
Finally, it can be caused by the introduction of too many names or
entities (variables etc.); try to get rid of some.
Memory space exceeded
The memory size needed for the variables, fields or formal parameters
declared exceeds 64K.
Nesting too deep (fatal)
This error can have saveral causes:
- More than 6 program parameters (input and output excepted).
- More than 8 nested for statements.
- More than 8 nested with statements.
- More than 16 nested blocks.
- More than 3 nested set constructors.
- More than 255 names in a variable declaration, an enumerated
type definition, a record section or a formal parameter section.
- A comment nesting greater than 255 (with -E option only).
- The usage of more than 32 registers (i.e., in a very complicated
Not found
The pointed label or identifier hasn't been declared; this can also
refer to input or output in a statement where those two are the
default argument.
Numerical error
In a case statement this means the specified constant is not in the
permissible range.
In a set constructor, this refers to a constant whose value exceeds
The argument of the chr function should be in range 0..255 (11.5.4).
The second argument of the div operator should not be 0 (8.2.1).
The second argument of the mod operator should be greater than 0
If none of these cases apply, a numerical overflow is meant.
Not ordinal
The specified numeral constant is too large to be represented.
Pointer domain type %s not defined (6)
Parameter lists do not match (11.3)
Procedure or function %s not defined (11.1, 11.2)
Invalid string
The string is empty or not closed by a second ' (4).
Syntax error
The compiler encounters a token it doesn't expect.
Type mismatch
Two types are not compatible, or the one specified type is not
Unrecognized character
Label %d not used (10.1)
Was already forward
Wrong kind
The most recent declaration or definition of the pointed identifier is
faulty at the current place.
6. Runtime errors
The following, fatal, errors are detected at runtime:
Nil error
An effort is made to obtain a reference to an identified variable by
means of a pointer variable with the value nil, or the argument of a
dispose procedure is nil (7.3, 11.4.2).
Case error
The value of the case index is not that of one of the constants
specified in the case statement (
Stack error
No memory space is left on the stack for an activation.
Heap error
No memory space is available for the identified variable corresponding
to the argument of a "new" procedure.
Overflow error
An overflow is detected during a calculation (real type only).
Illegal number error
The second argument of a mod operator is negative (8.2.1), or
the argument of a ln function is not positive (11.5.1), or
the field width value of a write procedure is not positive (12.3), or
the string argument of a write procedure has zero length (4).
Division by zero error (8.2.1)
Eof error
A get, read or eoln operation is performed on a file f, for which
eof(f) has the value true (11.4.1, 11.5.2, 12.1).
Input error
The integer or real number read has a wrong syntax (4).
File not open error
The file referred to hasn't been reset or rewritten at all, or the
wrong operation (of the two) has been performed last (11.4.1, 11.5.2,
7. Undetected errors
In this section a number of features are summarized, which are not allowed by
the Pascal definition, but which are not detected by the compiler.
The restrictions on a goto statement and the label it refers to, as mentioned
in (9.1.3), are not checked.
The compiler doesn't check whether a function block contains an assignment to
the corresponding function identifier.
The constants specified in the long form of the new and dispose procedures
(11.4.2), are ignored. Any error resulting from this ignorance is not
There is no detection of (totally) undefined variables, and any error
resulting from this lack remains undetected. However, there is one exception:
all predeclared procedures and functions will cause an error when operating on
an undefined file variable. An undefined function result isn't detected
References to variables are not checked; e.g., altering the sequence of a file
variable when a reference to the buffer variable exists, is not detected as an
error; furthermore, the same applies when a variant is or becomes inactive
while there is an access or reference to any of its components.
Only limited runtime overflow and bounds checking is performed; in particular,
array bounds checking and subrange checking is not performed. Furthermore,
invalid arguments of the chr, pred and succ functions are not detected, and
overflow resulting from the application of an operator to integer operand(s)
is detected in only a limited number of cases.