Text preview for : BCPL_Reference_Manual_Sep75.pdf part of xerox BCPL Reference Manual Sep75 xerox alto bcpl BCPL_Reference_Manual_Sep75.pdf
Back to : BCPL_Reference_Manual_Sep | Home
BCPL
Reference Manual
James E. Curry
Compiled on: September 9, 1975
Computer Sciences Laboratory
Xerox Palo Alto Research Center
3333 Coyote Hill Road
Palo Alto, California 94304
Copyright @) 1975 by Xerox Corporation.
Revised BCPL Manual, September 9, 1975
TABLE OF CONTENTS
SECTION PAGE
1 INTRODUCTION
2 A SAMPLE PROGRAM
2-1 The Queens Problem 2.1
2-2 Source Code -- QUEENS. 2.2
2-3 Source. Code -- QUEENS1 2.3
2-4 Notes on the Source Code 2.4
2-5 Compiling and Loading QUEENS . . . . . . . . 2.4
3 DECLARATIONS AND PROCEDURES
3-1 BCPL Variables 3.1
3-2 Scope Rules. . 3.1
3-3 Manifest Constants 3.3
3-4 Structure Declarations 3.3
3-5 Static and External Variables . . . . . . . . . . 3.3
3-6 Procedure Declarations 3.5
3-7 Procedure Execution . . 3.6
3-8 Dynll;mic Variables. . 3.7
4 EXPRESSIONS
4-1 Memory References 4.1
4-2 Constants . . . . 4.2
4-3 Precedence of Expressions 4.3
4-4 BCPL Expressions . . . . 4.4
5 STATEMENTS
5-1 Assignment Statements: 5.1
i
Revised BCPL Manual, September 9, 1975 TABLE OF CONTENTS
5-2 Routine Calls: . 5.1
5-3 Conditionals and Iterative Statements:. 5.1
5-4 Condi tional Compilation Statements: 5.3
5-5 Labels and Goto Statements:. 5.4
5-6 Returns: . 5.5
5-7 Switches: 5.5
5-8 Single-Word Statements 5.6
6 STRUCTURES
6-1 Structure declarations and references . 6.1
6-2 Nested fields 6.3
6-3 Subscripted fields. 6.5
6-4 Overlays. 6.8
6-5 Left-lump structure references . 6.8
6-6 Other structure operators 6.10
6-7 Syntax of structure declarations 6.11
7 SOURCE FILE CONVENTIONS
7-1 Declaration files 7.1
7-2 Labeled brackets 7.1
7-3 Semicolon insertion 7.1
7-4 Do/Then insertion. 7.2
7-5 Comments 7.2
7-6 Upper case vs. Lower Case 7.3
8 COMPILATION
8-1 Normal compilation 8.1
8-2 Global swi tches 8.2
8-3 Local swi tches . 8.3
9 LOADING
9-1 Normal loading. 9.1
ii
Revised BCPL Manual, September 9, 1975 TABLE OF CONTENTS
9-2 Errors . . . . ... .. . . 9.2
9-3 Global switches .... . . . . . 9.3
9-4 Local switches -- group 1 9.3
9-5 Local switches -- group 2 9.5
9-6 Save file image 9.5
9-7 Overlays. . . . . . . 9.6
10 RUNTIME ENVIRONMENT
10-1 Procedure Frame Format. 10.1
10-2 Procedure Calls 10.1
10-3 Frame Allocation on the Nova 10.3
11 NOVA 1/0 and UTILITY ROUTINES
11-1 Introduction 11.1
11-2 Global Names'. 11.1
11-3 Procedures . . 11.2
12 APPENDICES
12-1 BCPL Reserved Words . . . . . . . . . . . . . 12.1
iii
Revised BCPL Manual, September 9, 1975
SECTION 1
INTRODUCTION
BCPL is a general purpose recursive programming language which is particularly
suitable for systems programming applications. Versions of BCPL exist on various
computer systems, including CTSS at Project MAC, the GE635 under GE COS, the
TX-2 at Lincoln Lab, and the PDP-ll, as well as for the Nova. The Nova version of
BCPL was bootstrapped from the TX-2 implementation, and incorporates most of the
features introduced mto BCPL at Lincoln, including a version of structures.
This manual uses an informal syntactic notation. Ellipsis (" ... ") indicates repetition.
Lower-case words are reserved words. Upper-case words represent syntactic classes,
the most common of which are:
NAME: an identifier
EXP: a BCPL expression
CONST: an expression involving only constants
REF: a memory reference expression
STAT: a BCPL statement or compound statement
1.1
Revised BCPL Manual, September 9, 1975
SECTION 2
A SAMPLE PROGRAM
2-1 . . . . . . . The Queens Problem
The following program is a complete, working example of BCPL. It solves the "8-
Queens" problem, generating all 8*8 chessboard configurations of eight queens such
that no queen can capture any of the others. The central procedure "Queens(Col}" is
called with a column number as its argument; it assumes that there are no conflicts
in the columns to the left, and tries to place a queen in the current column.
"Queens" calls itself recursively to iterate over the columns to the right, or p.rints a
J?icture of the board if a solution has been found. Three global vectors, "Horiz",
'UpDiag", and "DnDiag", are maintained to indicate whether a queen has already been
placed in a particular row, upward-diagonal, or downward-diagonal; an attempt to
place a queen in an occupied line results in rejection. A solution vector "Row" is
maintained for typeout, remembering which row the queen is in for each column.
The program consists of two source files: "QUEENS" and "QUEENSl". The first file
contains the main program and some 10 procedures; the second contains the "Queens"
procedure.
2.1
Revised BCPL Manual, September 9, 1975 A SAMPLE PROGRAM
2-2 . . . . . Source Code -- QUEENS
II Solution of 8 Queens problem -- Main Program
get "iox" II Include definitions for 10 package
manifest boardsize = 7 II Rows & Columns are numbered 0-7
external
[ Solutions II Total number of solutions
Row II Row!I = occupied column in row I
Horiz II Horiz!I = true if row I is occupied
UpDiag II UpDiag!I= true if up-dia~onal I is occupied
DnDiag II DnDiag!I= true if down-dlagonal I is occupied
]
external Queens II The procedure that does the work
external II Some extra 10 procedures
[ WriteS
WriteN
WriteL
]
static
[ Solutions = 0 II No solutions initially
Row = nil II Global vectors -- set up by Main
Horiz = nil
UpDiag = nil
DnDiag = nil
st~tic TTYstream II The stream used by WriteS. etc.
let MainO be
[main
II Initialize the Q1oba1 vectors
let v = vec boardslze; Row = v
let v = vec boardsize; Horiz = v
for i = 0 to boardsize do Horiz!i = false
let v = vec boardsize*2; UpDiag = v
let v = vec boardsize*2; DnDiag = v
for i = 0 to boardsize*2 do UpDiag!i. DnDiag!i = false, false
II Initialize output to TTY
initbcp1 io()
TTYstream = open("")
II Do the work
Queens(O)
II Print number of solutions
WriteN(Solutions)
WriteS(" solutions found*n")
]main
and WriteS(S) be writestr(TTYstream, S)
and WriteN(N) be writedec(TTYstream, N)
and WriteL() be writestr(TTYstream, "*n")
2.2
Revised BCPL Manual, September 9, 1975 A SAMPLE PROGRAM
2-3 . . . . . . . Source Code -- QUEENS 1
II Solution of 8 Queens problem -- Queens procedure
manifest boardsize = 7 II Rows & Columns are numbered 0-7
external
[ Solutions II Total number of solutions
Row II Row!1 = occupied column in row 1
Horiz II Horiz!1 = true if row 1 is occupied
UpDiag II UpDiag!l= true if up-diaQonal 1 is occupied
DnDiag II DnDiag!l= true if down-dlagonal 1 is occupied
]
external Queens II The procedure that does the work
external II Some extra 10 procedures
[ WriteS
WriteN
Writel
]
let Queens(Col) be
[queens
II There are no conflicts in columns left of Col
let UpDiag2. DnDiag2 = UpDiag+boardsize-Col, DnDiag+Co1
II UpDiag2, Dndiag2 are the diagonal vectors for this.co1umn
for n = 0 to boardsize do
[row100p 1/ Try to put a Queen .in each row of this column
if Horiz!n % UpDiag2!n % DnDiag2!n loop II Can't - go on
II There are no conflicts to the left, so we can
Row!Co1 = n /1 Remember for typeout
test Col eq boardsize II Done?
ifnot [ Horiz!n,UpDiag2!n,DnDiaQ2!n = true,true,true
/1 Now a Queen is in thlS column
Queens(Co1+1) II Find all solutions to the right
/1 Now remove the Queen
Horiz!n,UpDiag2!n,DnDiag2!n = fa1se,fa1se,false
]
ifso [II Print the solution
Writel()
for r = 0 to boardsize do
[ for c = 0 to boardsize do
WriteS(Row!r eq c ? ~ Q", " .")
Wr HelO
S~lutions = Solutions + 1
]
]row100p II Do the next row
]queens
2.3
Revised BCPL Manual, September 9, 1975 A SAMPLE PROGRAM
2-4 . . . . . . . Notes on the Source Code
The file "lOX" contains external declarations for a basic 10 library; "QUEENS" uses
"initbcplio", "open", "writestr", and "writedec" from this library.
The manifest and external declarations appear in both source files. These
declarations would usually be put into a separate file; each source file would "get"
this file in order to include the declarations.
The static declarations appear only in "QUEENS"; static variables must be declared as
static only once, although they may be declared external in many files. "Solutions"
is initialized to 0; the statics for the global vectors will be initialized by the main
procedure, so they are initialized to "nil". "TTYstream" is declared static but not
external, so it is local to "QUEENS", as is "Main".
The main program allocates the vector space for the global vectors by declaring four
local vectors (all named "v") and storing the address of the first elements in the
external variables for the vectors. This is the simplest way to get space which is
global to several procedures (or to a recursive procedure); the space is global to
"Queens" since it is allocated by the procedure which calls "Queens".
Note that declarations may be intermixed with statements.
2-5 . . . . . . . Compiling and Loading QUEENS
To compile the source file QUEENS, just type
BCPL QUEENS
(Only one source file may be compiled at a time.) The compiler will print
BCPL 2.0 -- QUEENS.BR = QUEENS
and begin compiling the program. If no errors are detected, the BCPL relocatable
binary file QUEENI:?BR will be created, and the compiler will print
QUEENS.BR -- 217 (143) WORDS
The numbers are the length of the code generated in octal (decimal). QUEENS1 is
compiled similarly.
To load the program, type
BLDR/D/L/V QUEENS QUEENS1 101 102
This will create the file QUEENS.SV, an executable Nova save file, from the BCPL
relocatable binary files QUEENS.BR, QUEENS1.BR, I01.BR, and I02.BR. (The latter
two files are the input-output routines.) The ID switch causes the Nova debugger to
be loaded into the save file. The IL/V switches create a symbol table file named
QUEENS.BS, containing information about where things will be in core when the
program runs; a listing of this file is included in the section on Loading (Section 9).
The loader prints
BLDR 2.0 -- QUEENS.SV, QUEENS.BS
2.4
Revised BCPL Manual, September 9, 1975 A SAMPLE PROGRAM
at the beginning of the loading process, and when it is done,
QUEENS.SV -- 14162 (6256) WORDS
The numbers give the size of the save file in octal (decimal).
To run the program, just type QUEENS. It will print out 92 solutions.
2.5
Revised BCPL Manual, September 9, 1975
SECTION 3
DECLARATIONS AND PROCEDURES
3-1 . . . . . BCPL Variables
BCPL is a vaguely ALGOL-like language (it is block-structured; it allocates procedure
space dynamically, so recursion is permissible; and most BCPL statements correspond
roughly to ALGOL statements, although there are syntactic differences). The major
difference between BCPL and ALGOL is that all ALGOL variables are declared with
data-types (integer, real, boolean, string, array, procedure, label, pointer, etc.),
whereas all BCPL variables have the same data-type: a I6-bit number. In ALGOL,
the meaning of an expression is dependent both on its context and on the data-t},pes
of the entities involved, and only expressions with certain data-types may appear 10 a
given context. In BCPL, any expression may be used in any context; the context
alone determines how the I6-bit value of the expression is interpreted. BCPL never
checks that a value is "appropriate" for use in a given way. For example, an
expression which appears in a "goto" statement is assumed to have "as its value the
address of someplace which is reasonable to jump to; the thing following a "goto"
need not be a label. The advantages of this philosophy about data-types are that it
allows the programmer to do almost anything, and that it makes the language
conceptually simple. The disadvantages are that the user can make errors which
would have been caught by data-type checking, and that some things must be done
explicitly which ALGOL-type languages would do automatically (implicit indirection
on pointer variables, operations on multi-word values such as real numbers and
strings, type conversion, etc.).
Although BCPL has only one data-type, it does distinguish between two kinds of
variables: static and dynamic. They differ as to when and where the cells to which
they refer are allocated. A static variable refers to a cell which is allocated at the
beginning of program execution (i.e., by the BCPL loader); it refers to the same
memory cell for as long as the program runs. A dynamic variable refers to a cell
which is (conceptually) allocated when the block in which it is defined is entered,
and exists only until execution of that block terminates. The space from which the
dynamic variable is allocated is created dynamically when the procedure containing
its defining block is called. "
As in ALGOL, variable names (and other names) are defined in declarations. The
lexical scope of a declared name (the portion of the source .text in which the name is
defined) is governed by BCPL's block structure.
3-2 . . . . . . . Scope Rules
At the outermost level, a BCPL source file consists of a sequence of global
declarations followed by a multiple procedure declaration. The possible global
declarations are:
external [NAME; ... ; NAME]
3.1
Revised BCPL Manual, September 9, 1975 DECLARATIONS AND PROCEDURES
static [NAME = CONSTj ... j NAME = CONST]
manifest [NAME = CONSTj ... j NAME = CONST]
structure NAME: [ ... ]
The external and static declarations define static variables; the manifest declaration
defines literals; the structure declaration defines templates for symbolic references to
partial-word and multi-word data.
A multiple procedure declaration has the form
let NAME(ARG, ... , ARG) BODY
and NAME(ARG, ... , ARC) BODY
and NAME(ARG, ... , ARG) BODY
where BODY is either "be STAT" or "= EXP".
The NAMEs in external, static, manifest, and structure declarations at the outermost
level are defined from the point of declaration to the end of the source file; all of
the NAMEs in the "let ... and ... " sequence at the outermost level are defined in all
of the BODYs. These are the only names which are globally defined. All other
names are defined either as ARGs in the procedure declarations, or in local
declarations within compound statements in the BODYs.
A compound statement is a sequence of statements and declarations, separated by
semicolons, and enclosed within the brackets "[" and "]". (If a carriage return
separates two statements, the semicolon can be omitted.) The brackets have a function
similar to that. of the words "begin" and "end" in ALGOL. A compound statement
may be used wherever a simple statement can be; in this manual, "STAT" always
means either a simple statement or a compound statement. Compound stat.ements are
used when two or more st.atements are needed in a context in which BCPL expects a
single statement (e.g., as the body of a procedure, or as one of the arms of a
conditional statement). Compound statements delimit the scope of locally declared
names.
Local declarations may be intermixed with statements (unlike ALGOL, in which
declarations may appear only at the beginning of a comJilOund statement).
"Declaration" here includes dynamic variable declarations (let NAMEl, ... ,
NAMEn = EXPl, ... , - EXPn"), as well as the external, static, manifest, structure, and
procedure declarations mentioned above. The following rules govern the scope of
local declarations:
1) A local declaration may appear in a compound statement only in the
following contexts: at the beginning of a statement, or after a semicolon
(including a semicolon implicitly inserted by the compiler between
statements on different lines), or following a statement label that follows a
semicolon. The effect of this rule is to disallow things like
"if x eq 0 then let y = 0 (although "if x eq 0 then [ let y = 0 ... ] is
perfectly legal). A declaration may be labeled.
2) A declaration starts a block; the block ends at the end of the compound
statement containing the declaration. A name defined in the declaration is
known only within the block introduced by the declaration, and in
sub-blocks contained within that block if the name is not redeclared.
3) (Exception to rule (2).) A dynamic variable is not known in any procedure
body other than the one in which it was declared. Thus, if the procedure
3.2
Revised BCPL Manual, September 9, 1975 DECLARATIONS AND PROCEDURES
"g" is declared inside of the body of procedure "f", the dynamic variables
defined in "f" are not known to "g". (This is because the dynamic
variables of "f" reside in space which is dynamically allocated when "f" is
called. When "g" is called, it does not know where this space is; in fact,
there might be more than one execution of "f" in progress when "g" is
called, or there might not be any active execution of "f".)
4) A statement label ("NAME: ... ") appearing within a block is treated as if it
were a static variable declared immediately after the declaration which
begins the block. So a label is known throughout its enclosing block, but
not outside that block.
3-3 Manifest Constants
The declaration
manifest [NAME1 = CONST1; ... ; NAMEn = CONSTn]
defines NAME! through NAMEn as manifest constants. (If there is only one NAME,
the brackets are not necessary.) The expressions CONST! through CONSTn must be
constant expressions; that is, their values must be computable by the compiler. The
meaning of a program would be unchanged if each manifest name were replaced by a
string of digits representing its value. In particular, manifest names do not have
addresses.
3-4 . . . . Structure Declarations
(Structures are described in Section 6 of this manual.)
3-5 . Static and External Variables
Static variables may be declared in four ways: by a static or external declaration, by
a procedure declaration, or by a statement label assignment.
The declaration
static [NAME1 = CONST!; ... ; NAMEn = CONSTn]
defines NAME! through NAMEn as static variables, and causes them to be initialized
with the values CONST! through CONSTn at the beginning of program execution
(i.e., in the "save file" created by the loader). (If there is only one NAME, the
brackets are not necessary.) The CONSTs must be expressions whose values are
computable by the compiler. If it doesn't matter what the variable is initialized to,
the " = CONST" should be left out, or " = nil" should be used.
Any of the NAMEs that are preceded by an "@" will be allocated by the loader in
3.3
Revised BCPL Manual. September 9. 1975 DECLARATIONS AND PROCEDURES
page zero. Such variables are called "common" variables. They can be addressed
directly by the compiled code, whereas normal static variables must be addressed by
indirection through a literal; so common variables are more efficient. However, there
is room in page zero for only about 150 (decimal) common variables; the loader will
complain if too many common variables are assigned.
The procedure declarations
let NAME(ARG..... ARG) be STAT
let NAME(ARG, .... ARG) = EXP
declare NAME as a static variable which is to be initialized by the loader to the
address of the code compiled for the procedure.
The procedure declaration is discussed fully in the sections on procedure and dynamic
variable declarations.
A statement label assignment
NAME: STAT
declares NAME as a static variable which is to be initialized by the loader to the
address of the code compiled for STAT. A label assignment does not begin a block;
the name is treated as if it were declared immediately after the declaration which
begins the smallest enclosing block. Thus. a label is defined throughout the block in
which it appears.
The declaration
external [NAMEl; ... ; NAMEnl
declares NAME! through NAMEn as external static variables. (If there is only one
NAME. the brackets are not necessary.) The purpose of the external declaration is to
allow separately compiled pieces of a program to reference the same variables.
Within a given source file, the scope of an external variable is the same as that of
other types of variables; but if two or more separately compiled source files declare a
given name external, the loader will make each refer to the same cell. In (exactly)
one of the source files in which a given name is declared external, the name should
also be declared as a static variable (by a static declaration, a procedure declaration,
or a statement label assignment) someplace within the scope of the external
declaration. (Note that the static declaration must follow the external declaration.)
This is not a re-definition of the name, but rather tells the loader how to initialize
the external static variable: The loader will complain about an external variable
which is not declared static someplace, or about one which is declared static more
than once.
NAMEs that are preceded by an "@" in an external declaration will be defined as
common variables. A NAME that is declared both external and static may be
designated as common in either or both declarations.
Note that only static variables may be external.
3.4
Revised BCPL Manual, September 9, 1975 DECLARATIONS AND PROCEDURES
3-6 . . Procedure Declarations
There are two kinds of BCPL procedures: "functions", which return a value upon
completion, and "routines", which do not. A function is defined by a declaration of
the form
let NAME (ARG1, ... , ARGn) = EXP
A routine is defined by
let NAME(ARG1, ... , ARGn) be STAT
NAME is the name of the function or routine being defined. (Actually, NAME
becomes a static variable which will be initialized with the address of the procedure,
as noted in the section on static variables.) ARG 1 through ARGn are the formal
parameters (dummy arguments) of the procedure. They are either NAMEs, or the
special symbol "nil", indicating an unnamed argument. ARGl through ARGn become
the first n dynamic variables declared in the procedure body. If there are no .dummy
arguments, the declaration is of the form "let NAME() be STAT" or "let
NAME( ) = EXP".
In the function declaration, EXP is the expression whose value is returned when the
function is called. EXP may be a simple BCPL expression; but for most functions it
will be an expression of the form "valof STAT", where STAT may be a compound
statement. The STAT in a "valof" expression should contain at least one "resultis"
statement. The STAT is executed until a statement of the form "resultis EXP" is
encountered; then EXP becomes the value of the "valof" expression, and therefore the
result of the function. The "valof" expression will also terminate when control would
otherwise pass to the statement following STAT. If ihis happens, the value of the
"valof" expression is garbage.
In the routine declaration, STAT is the statement which is executed when the routine
is called. STAT may be a compound statement. STAT may contain one or more
"return" statements; the routine returns when a "return" statement is executed, or
when control would otherwise pass to the statement following STAT.
A multiple procedure declaration has the form
let NAMEl(ARG, ... , ARG) be STAT (=EXP)
and NAME2(ARG, ... , ARG) be STAT (=EXP)
and NAMEn(ARG, ... , ARG) be STAT (= EXP)
This declares the procedures NAMEl through NAMEn "simultaneously"; that iE, all of
the NAMEi's are known in each of the procedure bodies. (So, for example, NAME1
can call NAME2 and NAME2 can call NAME1.) The ARGs, of course, are defined
only in their' corresponding procedure bodies.
A procedure body may contain procedure declarations; the names of such procedures
will be local to the defining body (unless they are declared external). But remember
rule (3) in the section on the scope of dynamic variables: dynamic variables are
defined only in the body of the defining procedure, and not in sub-procedure bodies.
For this reason, all procedures in a BCPL program are usually defined at the top
level.
3.5
Revised BCPL Manual. September 9. 1975 DECLARATIONS AND PROCEDURES
3-7 . . . . . . . Procedure Execution
A procedure is called by a statement or expression of the form
EXP(EXPI. EXP2 ..... EXPn)
EXP determines the procedure to be executed; EXP1 through EXPn are the actual
parameters. If there are no actual parameters. the form is "EXP( )". A procedure
call is an expression if it appears in a context in which a value is expected (e.g .