^^ .TITLE BCPL/RSX11D USER MANUAL .SKIP .SPACING 1 .FIGURE 10 .CENTER BCPL/RSX11D USER MANUAL .CENTER ----------------------- .SKIP .CENTER Jeremy Holden .CENTER Department of Computer Science .CENTER University of York .CENTER June 1976 .BREAK ^^ .BREAK .LEFT MARGIN 6 .PAGE .LEFT MARGIN 0 .SPACING 1 .NOFILL .CENTER CONTENTS .CENTER -------- .SKIP 2 Page 3 Introduction 5 The compiler 11 The translator 13 Operating procedures 16 Store utilisation 18 The object-time environment 24 The runtime system 30 Task building BCPL programs 32 References 33 Appendix A - The character set 34 Appendix B - Files used in the system 35 Appendix C - Changes for RSX11D version 6 36 Appendix D - The BCPL library 39 Index .FILL .LEFT MARGIN 6 .PAGE .PARAGRAPH -6 1#####INTRODUCTION .BREAK ------------ .SKIP BCPL is a programming language originally developed and implemented by Martin Richards at MIT project MAC for systems and non-numerical programming. It originated as a subset of CPL, the never-implemented language designed for TITAN by Barron et. al. [0], and is notable for its varied and efficient control constructs and for the fact that it is a typeless language. The BCPL compiler is written in BCPL and produces object code (OCODE) for an idealised stack machine. The compiler is therefore portable and can be transported by the provision of an OCODE translator for the target machine. It was by this method that BCPL was first implemented in England, at Cambridge, and it is from this implementation, via ICL 4130 implementations at Warwick and York, that the present system is derived. The BCPL language is defined in the BCPL Reference Manual [1] and an extended version of the language in use at Essex is defined in [2] . This document describes an implementation of BCPL to run on a PDP-11/40 or 45 under the RSX-11D V004A operating system [3]. .PARAGRAPH -6 1.1###Contents of the system .BREAK ---------------------- .BREAK The BCPL system consists of two programs, the compiler and the translator, and run-time library modules. .PARAGRAPH -6 1.1.2#The compiler .INDEX COMPILER .SKIP The compiler compiles BCPL into OCODE, optionally producing a source listing. It is a modified and extended version of the 4130 BCPL compiler and is described in detail in Section 2. .PARAGRAPH 1.1.3#The translator .INDEX TRANSLATOR .SKIP The translator takes as input an OCODE program and produces as output a translation of the program into MACRO-11. The MACRO-11 produced is compatible with the RSX assembler [4], although it is incompatible with earlier DEC assembler formats such as DOS and RT-11. The translator is described in Section 3. .TEST PAGE 6 .PARAGRAPH -6 1.1.4#Runtime library modules .INDEX Runtime system .SKIP The runtime library consists of object modules which provide various I/O, store management and other facilities. The modules are collected in an object code library and the required modules are linked with a BCPL program at# task-build# time using the DEC task builder [8] (see Section 8) to form a runnable program. The modules are written in BCPL and MACRO-11 and are described in Section 6 and Section 7. .PAGE .PARAGRAPH 2#####THE COMPILER .INDEX COMPILER .BREAK ------------ .SKIP The BCPL compiler is written in BCPL and consists of two parts, the parser which reads in BCPL source one segment at a time producing a tree, and the codegenerator which walks the tree producing OCODE from it. The compiler was developed from that used on the 4130 at York, which is described in [5] and [6]. The main changes to the compiler were to the machine dependant parts at the beginnning of the parser which deal with I/O and wordlength-dependent routines. Other changes to the compiler involve a number of enhancements and extensions .PARAGRAPH 2.1###Enhancements to the 4130 compiler .BREAK --------------------------------- .PARAGRAPH 2.1.1#Constant expressions .SKIP The compiler completely evaluates all compile-time evaluable expressions (that is, all those expressions consisting of manifest constants, constant denotations and any BCPL operators other than %, LV, RV). .PARAGRAPH 2.1.2#Conditional compilation .INDEX Conditional compilation .SKIP The compiler performs conditional compilation. That is, all conditional expressions (using ->) and commands (IF, UNLESS, TEST) whose conditions are evaluable at compile time do not produce any code for the test and unsatisfied condition. .PARAGRAPH 2.2###The GET facility .INDEX GET command .BREAK ---------------- .BREAK Textual insertions from another file may be made into the BCPL source text. This allows global and manifest declarations to be filed and inserted where needed. .SKIP A GET command is used to specify where the insertion is to occur. The syntax of a GET command is:- .SKIP #######::=#GET# .SKIP e.g. GET "DK1:BCPLIB.GET" .SKIP Semantically, the string is treated as an RSX dataset identification and the whole of the line containing the GET statement is replaced by the contents of the specified dataset. .SKIP Any number of GET commands may occur within a segment, with the proviso that they cannot be nested. That is, the replacement text may not contain another GET command. .PARAGRAPH 2.3###The character set (Appendix A) .INDEX Character set .BREAK ----------------- .BREAK BCPL uses the full ASCII character set (even those which have no equivalents in the 4130 character code). .PARAGRAPH 2.3.1#Lower case letters .INDEX Lower case letters .SKIP Identifiers may use lower case letters, as well as upper case, digits and full stops. They are regarded as being different from the corresponding upper case characters. All BCPL keywords must be in upper case. .PARAGRAPH 2.3.2#Braces {, } .SKIP These may be used synonymously with the BCPL section brackets, $( and $), and may be similarly subscripted with an identifier. There is a problem however, in that the present version of the teletype handler for RSX-11D will not print }. .PARAGRAPH 2.3.3#Tilde ~ .SKIP The tilde symbol may be used in place of the keyword NOT. .PARAGRAPH 2.3.4#Vertical bar | .SKIP The vertical bar character may be used as the vector application operator in place of %. .INDEX Language extensions .PARAGRAPH 2.4###Language extensions .BREAK ------------------- .BREAK The compiler accepts a number of the more useful language extensions as defined in [2]. These are:- .PARAGRAPH 2.4.1#Comments .INDEX Comments .SKIP As well as // which causes the remainder of the line to be treated as comment, the compiler also accepts /* and */ which may be used in pairs to delimit comments which may span one or more lines. .TEST PAGE 5 .PARAGRAPH 2.4.2#Infix function calls .INDEX Infix functions .SKIP The construct A !PLUS B is equivalent to the function call PLUS(A,B). In general, any identifier preceded by '!' is treated as a dyadic operator with the same precedence as vector application, and the result is the value of the function call on the identifier, using the two operands as parameters. .PARAGRAPH 2.4.3#Very binding semicolon .SKIP This is used to join two commands together as if they were a section. There are two representations of it, ;; and <> .SKIP e.g.#####IF#I<10###I#:=#I+1<>WRITEN(I) .SKIP is equivalent to .SKIP #########IF#I<10###$(#I:=I+1;#WRITEN(I)#$) .PARAGRAPH 2.4.4#LOOP command .INDEX LOOP command .SKIP This is similar to a BREAK command, in that it can occur inside the body of any loop (FOR, UNTIL, WHILE, etc) command. Whereas a BREAK transfers control to the command immediately after the loop command, a LOOP transfers control to the point immediately before the condition is evaluated. .NOFILL e.g. FOR I=1 TO 10 $( IF V%I=0 LOOP; V%I:=3 $) .FILL is equivalent to .NOFILL FOR I=1 TO 10 $( IF V%I=0 GOTO L V%I:=3 L: $) .FILL .PARAGRAPH 2.4.5#WHERE statement .SKIP This statement is used to associate a declaration with a command and is of the form .SKIP ###### WHERE .SKIP The scope of the declaration is the preceding command. A WHERE can introduce any declaration which can be used in a LET statement. .NOFILL e.g.#####x:=f(7) WHERE f(n) = (n=0)->1, n*f(n-1) .FILL Since a WHERE command can be used to declare routines, the keyword IS is allowed (universally) as a synonym for BE. .PARAGRAPH 2.5###CODE statement .INDEX Code statements .BREAK -------------- .BREAK Code statements containing MACRO-11 bodies may be used within BCPL programs. Code statements may be used syntactically as either commands or expressions. In either case the syntax is .SKIP ######CODE# .SKIP In the case of code statements which are used as expressions, the value of the code statement is that which is held in the result register on exit from the code body. The result register is R0. .NOFILL e.g. LET LEVEL() BE CODE " MOV 2(P), R0 ASR R0" .INDEX Register usage or X := CODE " MOV _#4, R0" * 3 /* X should now be 12 */ .SKIP .FILL [ See Section 6.3 ] .PARAGRAPH 2.6###Compiler output .INDEX Compiler output .BREAK --------------- .BREAK During the first pass over each segment the source is listed as it is read in, if a listing dataset is specified. The listing is provided with sequential line numbers. At the end of the first pass the compiler prints .SKIP #######TREESIZE#=#n .SKIP where n is the decimal number of words in the tree. At the end of the program, provided the compilation was error free, the compiler prints .SKIP #######COMPILATION#OK#-#0#ERRORS .SKIP .TEST PAGE 3 otherwise it prints .SKIP #######COMPILATION#FAILED#-#n#ERRORS .PARAGRAPH 2.7###Error handling .INDEX Compiler error handling .INDEX Error handling .BREAK -------------- .BREAK There are three classes of error which the compiler recognises. These are: .PARAGRAPH 2.7.1#Irrecoverable errors .SKIP These include syntax errors in the command string (See Section 4.1), or failure to open any of the datasets in the command string. The compiler prints an appropriate message, immediately terminates compilation and reissues its prompt. .PARAGRAPH 2.7.2#Syntax errors .INDEX Syntax errors .SKIP These are errors discovered by the parser. The compiler issues a message of the form: .SKIP .NOFILL 53 IF I = 10 BREAK _^ *** SYNTAX ERROR, ILLEGAL USE OF BREAK .FILL .SKIP If no listing is being produced the offending source line is issued on the console. The arrow marks the point which the parser had reached when the error was detected. .PARAGRAPH 2.7.3#Semantic errors .INDEX Semantic errors .SKIP These are errors discovered during the codegeneration phase. As the compiler no longer has the source text of the program available it prints out the number of commands it had compiled so far in the current segment. The error message is of the form: .NOFILL .SKIP *** ERROR, NAME NOT DECLARED XYZ COMMANDS COMPILED = 17 .FILL .SKIP Syntax and semantic errors are not immediately regarded as fatal; compilation and output of OCODE continue until a maximum of six errors are reported whereupon the compilation is terminated. .PARAGRAPH 2.8###Limitations .INDEX Compiler limitations .BREAK ----------- .BREAK A number of items have statically determined maximum values which will cause errors if they are exceeded. Violation of any of these limits is regarded as an irrecoverable error, and compilation is aborted with a suitable error message. They are: .PARAGRAPH 2.8.1#The tree .SKIP At the moment 5500 (decimal) words are allocated to the tree. This should be enough for at least 200 lines of BCPL. If a segment causes the tree to be filled then the segment must be split into smaller units. .PARAGRAPH 2.8.2#Strings .SKIP Strings are permitted a maximum length of 255 characters. .PARAGRAPH 2.8.3#Globals .SKIP The maximum number of global variables allowed in a segment is 100, although more than this can be used in a program. .PARAGRAPH 2.8.4#Identifiers .SKIP Identifiers may not exceed 100 characters in length. .PARAGRAPH 2.8.5#Cases .SKIP The maximum number of cases in a SWITCHON command is 150. .PAGE .PARAGRAPH 3#####THE#TRANSLATOR .INDEX TRANSLATOR .BREAK -------------- .SKIP The translator, which is also written in BCPL, accepts OCODE as input and produces MACRO-11 as output. .PARAGRAPH 3.1###The CODE instruction .INDEX Code statements .INDEX Code instruction .BREAK -------------------- .BREAK The repertoire of OCODE instructions accepted by the translator has been extended to cover a new instruction, the CODE instruction. This has the format .SKIP .NOFILL CODE n C1 C2 C3 .. Cn .FILL .SKIP where the Ci are the decimal equivalents of the ASCII characters forming the body of a BCPL CODE statement. .PARAGRAPH 3.2###Optimisation .INDEX Translator optimisation .BREAK ------------ .BREAK The translator attempts various optimisations on the code it produces. The topmost elements of the OCODE stack are kept in registers whenever possible, to produce faster and more compact code. Conditional branch instructions are generated wherever possible, again reducing the code length. Various redundant operations generated by the compiler are trapped and removed. .PARAGRAPH 3.3###Elaboration of assignments .BREAK -------------------------- .BREAK BCPL constructs such as .SKIP .NOFILL LET I = 3 AND J = I + 1 or A, B := A+1, A-1 .FILL .SKIP have no defined order of elaboration and different translators may produce code which gives different ordering for the elaboration of multiple assignments. Due to the optimisation algorithms employed by the translator the code it produces will not necessarily elaborate the assignments in textual order. On the other hand when the ordering of statements is explicitly stated e.g. .SKIP .NOFILL LET I = 3 LET J = I + 1 or A := A+1; B := A-1 .FILL .SKIP the translator produces code to elaborate the assignments in textual order. .PAGE .PARAGRAPH 4#####OPERATING PROCEDURES .INDEX OPERATING PROCEDURES .BREAK -------------------- .PARAGRAPH 4.1###Running the compiler .INDEX Compiler commands .BREAK -------------------- .BREAK The compiler is an MCR task and as such can be run by replying to MCR with: .SKIP .NOFILL MCR>BCPL command string or MCR>BCPL BCPL>command string .FILL A command string for the compiler may be an indirect command (see 4.3) or in the form .SKIP .NOFILL ocode, listing/switches = bcpl1, bcpl2, ... .FILL where .NOFILL .BREAK #######ocode###is the OCODE output dataset (optional) #######listing#is the listing dataset (optional) #######bcpl1###is the BCPL source dataset #######bcpl2..#are BCPL datasets (optional) .FILL .SKIP The usual RSX conventions for default device names and UICs apply to all command strings. .PARAGRAPH 4.1.1#Default file extensions .INDEX Default extensions .SKIP .NOFILL #######OCODE output####.OCO #######Listing output##.LST #######BCPL source#####.BCL .FILL .SKIP The default file name and extension for GET datasets (See 2.3) is .SKIP #######BCPLIB.GET .PARAGRAPH 4.1.2#Switches .INDEX Compiler switches .INDEX TR compiler switch .INDEX NA compiler switch .INDEX GE compiler switch .SKIP All switches apply to the listing dataset only. .SKIP .NOFILL #######/TREE##print tree for each segment #######/NAMES#print names used in each segmaent #######/GET###list replacement text for GET commands .FILL .SKIP .BREAK Only the first two letters of each switch are mandatory. If no listing dataset is specified the first two switches will still cause the tree or names to be printed (on CO:) but the GET switch will be ignored. .TEST PAGE 6 .PARAGRAPH 4.1.3#Examples .SKIP .SKIP .NOFILL #######BCPL>DK1:TEMP=DK1:TEMP .FILL .SKIP Compiles the program in DK1:TEMP.BCL and produces the output file DK1:TEMP.OCO. No listing is produced. .SKIP .NOFILL #######BCPL>DK1:TRAN,TT:/GE=DK1:TRAN1,DK1:TRAN2 .FILL .SKIP Compiles the source in DK1:TRAN1.BCL and DK1:TRAN2.BCL into the OCODE file DK1:TRAN.OCO. A listing of the source including expansion of GET commands is produced on TT:. .PARAGRAPH 4.2###Running the translator .INDEX Translator commands .BREAK ---------------------- .BREAK The translator is an MCR task and can be run by replying to MCR with: .SKIP .NOFILL #######MCR>TRAN command string .SKIP or#####MCR>TRAN #######TRAN>command string .FILL .SKIP A command string for the translator may be an indirect command (see 4.3) or in the form .SKIP .NOFILL #######macro/switches = ocode1, ocode2, ... .FILL .SKIP where .BREAK .NOFILL #######macro#######is the MACRO-11 output dataset #######ocode1######is the OCODE source dataset #######ocode2#...##are more OCODE datasets (optional) .FILL .SKIP Note that an OCODE segment can not cross dataset boundaries. Also, the translator produces a complete MACRO program module so that separately translated OCODE segments must be separately assembled. .PARAGRAPH 4.2.1#Default file extensions .INDEX Default extensions .SKIP .NOFILL #######MACRO-11#output####.MAC #######OCODE#input########.OCO .FILL .TEST PAGE 10 .PARAGRAPH 4.2.2#Switches .INDEX Translator switches .INDEX TI translator switch .INDEX ID translator switch .INDEX PS Translator switch .SKIP Switches may only be supplied to the output dataset. They are .SKIP .NOFILL #######/TI:title Program title #######/ID:ident Program identification #######/PS:psect Psect name for code .FILL .SKIP All values are ASCII strings of upto 6 characters. If not supplied the title and psect name both default to "BCPL" and the identification is omitted. .PARAGRAPH 4.2.3#Example .SKIP #######TRAN>DK1:TEMP/TI:XTASK=DK1:TEMP .SKIP The OCODE file in DK1:TEMP.OCO is translated into a MACRO-11 module with the title 'XTASK', and stored in DK1:TEMP.MAC. .PARAGRAPH 4.3###Indirect command files .INDEX Indirect commands .BREAK ---------------------- .BREAK Both the compiler and the translator accept one level of indirect command files. For example, the two BCPL programs TSYN and NTRN will be compiled in response to the single command .SKIP #######BCPL>@BCPLCOM .SKIP where the file BCPLCOM.CMD conntains .SKIP .NOFILL #######DK1:TSYN=DK1:TSYN #######DK1:NTRN=DK1:NTRN .FILL .PAGE .FILL .PARAGRAPH 5#####STORE UTILISATION .INDEX Storage utilisation .BREAK ----------------- .SKIP The address space of a BCPL task is composed of a number of discrete areas: a static storage region (for code, static data items, I/O buffers) and a dynamic storage region (for run-time stack and heap). The address space may also contain core-resident libraries or global common areas. The storage map for a BCPL task will usually have the following form: .SKIP 2 .NOFILL |--------------| | | | SYSRES | system resident | | library 160000 - |--------------| | BLANK | unused address | | space |--------------| | | | CODE | static storage | | region ( code, | | static data, | | I/O buffers) n - - - |--------------| | | | HEAP | heap |--------------| | || | | _\/ | | | | /_\ | | || | |--------------| | | | STACK | runtime stack | | 1000 - - |--------------| | SP | processor stack |--------------| | || | | _\/ | | | 0 - - - |--------------| virtual zero .FILL .SKIP 2 The positioning of the various areas can be altered using appropriate Task-Builder directives. .TEST PAGE 5 .PARAGRAPH 5.1###Static data .INDEX Static storage .BREAK ----------- .BREAK This consists of all BCPL objects whose extent is that of the whole program, i.e. static variables, global variables, tables and string bodies. The global vector is allocated in a special psect called GLOBAL which has the attributes 'global' and 'overlayable'. The other static data items are allocated storage in a psect called CONST. .PARAGRAPH 5.2###Dynamic storage .INDEX Dynamic storage .BREAK --------------- .BREAK Dynamic storage is required for all objects whose storage requirements are not statically determined. It is allocated from two areas, the runtime stack and the heap. All dynamic storage must be allocated at task-build time by the directive .SKIP .NOFILL STACK=n .FILL .SKIP This causes the allocation of n (decimal) words of address space from virtual 0, of which the first 256 are used for the processor stack, and the remainder for the runtime stack and the heap. .PARAGRAPH 5.2.1#The runtime stack .INDEX Stack .INDEX Runtime stack .SKIP This is used for the storage of all local variables. It is allocated upwards from the base of the processor stack. .PARAGRAPH 5.2.2#The heap .INDEX Heap .SKIP This is used for the storage of all dynamic objects whose extent is not related to the block structure of the program. In particular it is used by library I/O modules for the storage of FDBs, record buffers etc. It is allocated downwards from the top of the area reserved by the STACK directive. .PAGE .PARAGRAPH 6#####THE OBJECT-TIME ENVIRONMENT .INDEX Data representation .BREAK --------------------------- .PARAGRAPH 6.1###Representation of data .BREAK ---------------------- .BREAK As defined in the BCPL language all data items are represented by single words, which in the case of the PDP11 are of 16 bits each. .PARAGRAPH 6.1.1#Integers .SKIP These are represented by signed twos complement integers. .PARAGRAPH 6.1.2#Booleans .SKIP .BREAK .NOFILL TRUE is represented by -1 FALSE is represented by 0 .FILL .SKIP When testing a Boolean any non-zero value is regarded as TRUE. .PARAGRAPH 6.1.3#Labels .SKIP All global and static labels, including functions and routines, are represented by the 16 bit virtual address of the associated code. .PARAGRAPH 6.1.4#Strings .SKIP These are represented by a word containing half the virtual address of the body of the string. The body of the string is stored as a word containing the length of the string followed by the characters in the string packed one per byte. .PARAGRAPH 6.1.5#Vectors .SKIP These are represented by a word containing half the virtual address of the zeroth word of the vector. .SKIP This seemingly peculiar representation of strings and vectors is due to the fact that BCPL models a word machine in that consecutive data items, such as the elements of an array, are assumed to have consecutive integral addresses (L-values). The L-value of any word is thus represented by a value equal to half the true virtual address of the word. .TEST PAGE 10 .PARAGRAPH 6.2###Addressing of variables .BREAK ------------------------ .PARAGRAPH 6.2.1#Local variables .INDEX Local variables .SKIP All local variables are stored on the runtime stack. The form of a stack frame is .TEST PAGE 17 .SKIP 2 .NOFILL | | .INDEX Stack | local | | variables | | | |------------| | | | parameters | 6 | | |------------| 4 | proc name | |------------| 2 | old P | |------------| P -> 0 | link | |------------| .FILL .SKIP 2 The current frame is always pointed to by P (Register 5). All local variables are referenced by an index off this register. .SKIP e.g.###MOV####6(P),#R0####;#GET#FIRST#PARAMETER .SKIP The first three words of a stack frame are reserved for the frame head which consists of: .BREAK .LEFT MARGIN 13 .INDENT -7 Link#-#the return address to the point of call of the current stack frame. .INDENT -7 Old#P-#The stack pointer P for the previous environment .INDENT -7 Name#-#A pointer to the name of the current routine. .LEFT MARGIN 6 .PARAGRAPH 6.2.2#Global variables .INDEX Global variables .SKIP The global vector is allocated in an overlayable psect called GLOBAL. The module header produced by the translator contains the following code: .SKIP .NOFILL ###############.PSECT##GLOBAL,OVR #######GV:: .FILL .SKIP All references to global variables are by constant offset from the symbol GV. .SKIP .NOFILL ###############MOV####_#14,#GV+124.###;#GLOBAL 62 := 12 .FILL .PARAGRAPH 6.2.3#Static variables .INDEX Static variables .SKIP There are two types of static variables in BCPL, label and numeric valued variables. These correspond to, in the first case, label function and routine definitions, and in the second case to STATIC and TABLE declarations. Storage for static variables is allocated in the CONST psect. The code produced by .SKIP .NOFILL STATIC $( S = 3 $) .SKIP is .PSECT CONST .BREAK L7: .WORD 3 .SKIP Referencing this variable by .SKIP S := 17 .SKIP gives rise to code of the form .SKIP MOV _#21, L7 .SKIP The code produced by .SKIP LABEL: FOR I =1 TO .... .SKIP is .PSECT CONST L9: .WORD L7 .SKIP .FILL where L7 is the address of the code associated with the label 'LABEL'. Referencing such a variable by .SKIP .NOFILL GOTO LABEL .SKIP causes the code .SKIP JMP @L9 .SKIP to be produced. .FILL .PARAGRAPH 6.3###Register usage .INDEX Register usage .BREAK -------------- .BREAK .NOFILL R7##(PC)##Normal usage (program counter) R6##(SP)##Normal usage (processor stack) R5##(P)###Current stack frame pointer R4...R0###Allocated by translator as work registers R0########Result register for returning values from ##########function, VALOF and CODE expressions .FILL .TEST PAGE 8 .PARAGRAPH 6.4###Code conventions .BREAK ---------------- .PARAGRAPH 6.4.1#Function and routine calls .SKIP These are performed by code of the form .SKIP .NOFILL JSR R0, @GV+120. .BREAK .WORD 24 .SKIP .FILL The word following the JSR is used to pass the offset for the new stack frame (actually the byte offset of the first parameter of the new frame from the base of the current frame). .PARAGRAPH 6.4.2#Function and routine entry .SKIP These produce code of the form .SKIP .NOFILL .PSECT CONST L9999: .WORD 4 .ASCII /NAME/ .PSECT BCPL L3: JSR R1, ENTER .WORD L9999 .SKIP .FILL where NAME is the function or routine name, and ENTER is a library module which performs the entry code. .PARAGRAPH 6.4.3#Function and routine return .SKIP This is performed by the code .SKIP .NOFILL JMP EXIT .FILL .SKIP where EXIT is another library module. The result from a function is always passed in R0. .PARAGRAPH 6.4.4#Program termination .SKIP This is performed by the code .SKIP .NOFILL JMP STOP .FILL .SKIP where STOP is a library module. .PARAGRAPH 6.5###Extended instruction set (EIS) .INDEX EIS .BREAK ------------------------------ .BREAK Full use is made of the EIS option (which must be present in RSX systems). The translator generates inline code for multiplication, division and shifts using the EIS. .BREAK Shifts, as defined in BCPL, are logical shifts. Due to the peculiarities of the EIS, shifts are undefined except in the range 0 to 15. .PARAGRAPH 6.6###Inter-module linking .BREAK -------------------- .BREAK Certain conventions are used to allow programs to be linked with object modules from object code libraries and to allow the production of such modules. .SKIP The global variables 1-49 are treated in a special way. Definition of such a variable, by label function or routine declarations, gives rise to the definition of a global symbol Gn (n = 1-49) which is equated to the value of the variable. .SKIP .NOFILL e.g. GLOBAL $( RTNE:5 $) LET RTNE() BE .... .SKIP would normally produce the code .SKIP .PSECT GLOBAL .=GV+10. .WORD L7 .SKIP .FILL As the variable being defined is in the range 1-49, the code .SKIP .NOFILL G5==L7 .FILL .SKIP is also produced. .BREAK Any global variables in this range which are referenced but not defined in a module, e.g. by .SKIP .NOFILL IF Y<3 DO RTNE() .FILL .SKIP cause the generation of the additional code .SKIP .NOFILL .GLOBL G5 .FILL .SKIP The module which contains this reference will thus contain an unresolved reference to the symbol G5, and task-builder will try to resolve this reference at task-build time by searching libraries for this symbol and including the associated object module into the task image. .PARAGRAPH 6.7###Position independance and reentrancy .BREAK ------------------------------------ .BREAK Object modules produced from BCPL programs are neither position independent nor reentrant and so can not be used in resident libraries. .PAGE .PARAGRAPH 7#####THE RUN-TIME SYSTEM .BREAK ------------------- .SKIP The runtime system consists of a number of object modules which are stored in an object-code library, called BCPLIB. The modules required by a program are linked with it at task-build time (See 6.6 and 8.2). .PARAGRAPH 7.2###Utility routines .INDEX Library modules .BREAK ---------------- .BREAK These are MACRO-11 routines referenced by the code of BCPL programs. .SKIP .NOFILL ENTER routine entry EXIT routine exit STOP program exit GO program entry .SKIP .FILL The module GO contains the transfer address for the task and enters the user program at global label 1. .PARAGRAPH 7.3###Character I/O modules .INDEX I/O library modules .BREAK --------------------- .BREAK These modules provide simple character based I/O facilities. They are all written in BCPL. Details of the character set are given in appendix A. A listing of the source of these modules is included in APPENDIX D. .PARAGRAPH 7.3.1#Streams .INDEX Streams .SKIP The streams used resemble fairly closely those used in the Essex system [2] and the fast streams of OS6 [7]. A stream is a single word item and two special global variables, INPUT and OUTPUT are provided to hold the values of the current input and output streams. All stream input routines act on the stream INPUT and output routines on the stream OUTPUT. .PARAGRAPH 7.3.2#Input functions .SKIP .LEFT MARGIN 20 .SKIP .TAB STOPS 20 .INDENT -14 READC() .BREAK Returns next character. A newline character signifies end-of-record; an end-of-file character signifies that the input stream is exhausted. .SKIP .INDENT -14 READN() .BREAK Reads signed decimal integer. Leading non-numeric characters (except '-') are ignored. .SKIP .INDENT -14 READO() .BREAK Reads unsigned octal integer. Leading non-numeric characters are ignored. .LEFT MARGIN 6 .PARAGRAPH -6 7.3.3#Output routines .SKIP .LEFT MARGIN 20 .INDENT -14 WRITEC(C) .BREAK Writes character C. A newline character signifies end-of-record. .SKIP .INDENT -14 WRITEN(N) .BREAK Writes N as a signed decimal integer. .SKIP .INDENT -14 WRITEO(N) .BREAK Writes N as an unsigned octal integer. .SKIP .INDENT -14 WRITES(S) .BREAK Writes string S. .SKIP .INDENT -14 WRITED(N,D) .BREAK Writes N as a signed decimal integer right-justified in a field of width D, packed with spaces. If D is less than the number of characters required for N, N is printed in full with no leading spaces. .SKIP .INDENT -14 WRITEOCT(N,D) .BREAK As WRITED, but N is written as an unsigned octal number and the field is packed with zeroes. .SKIP .INDENT -14 WRITEF(F,A,B, .. ) .BREAK Writes the parameters A, B etc. according to the format string F. The format string is written out a character at a time until the escape character '%' is found. If the next character is one of the following then the next parameter is output using the appropriate routine. If not the character is output itself. .NOFILL .SKIP %C WRITEC %N WRITEN %S WRITES %O WRITEO %Dd WRITED using field d .SKIP e.g. WRITEF("%S=%%%N", "PC", 7) .SKIP would produce the output .SKIP PC=%7 .SKIP .FILL .INDENT -14 NEWLINE() .BREAK Writes a newline character. .INDEX Stream functions .LEFT MARGIN 6 .PARAGRAPH -6 7.3.4#Stream functions .SKIP Standard functions are provided for creating and destroying streams corresponding to RSX datasets. The datasets must be record structured with variable length records. .SKIP .LEFT MARGIN 20 .INDENT -14 CREATEOUTPUT(S) .BREAK Returns a stream for output.The string S must contain a legal RSX dataset specification. e.g. .SKIP .NOFILL OUTPUT := CREATEOUTPUT("DK1:TEMP") .SKIP .FILL .INDENT -14 FINDINPUT(S) .BREAK Returns an input stream, parameter as for CREATEOUTPUT. .SKIP .INDENT -14 ENDREAD(I) .BREAK Terminates the input stream I, causing deallocation of all storage for the stream. .SKIP .INDENT -14 ENDWRITE(O) .BREAK Terminates the output stream O, causing deallocation of all storage for the stream. .LEFT MARGIN 6 .PARAGRAPH -6 7.4###MACRO-11 library functions .BREAK ----------------------- .BREAK .LEFT MARGIN 20 .SKIP .INDENT -14 INITIALIZEIO() .BREAK This routine must be called before any I/O routines are used. .SKIP .INDENT -14 PACKSTRING(V,S) .BREAK This function packs the characters V%1 to V%n, where V%0 = n, into the string S. It returns S. .SKIP .INDENT -14 UNPACKSTRING(S,V) .BREAK This function unpacks the string S into the vector V, with the length of the string in V%0. It returns V. .SKIP .INDENT -14 LEVEL() .BREAK This function returns the value of the current environment, i.e. the current stack pointer. .SKIP .INDENT -14 LONGJUMP(P,L) .BREAK This routine resets the environment to P and jumps to the label L. It is used in conjunction with LEVEL for non-local GOTOs. .LEFT MARGIN 6 .PARAGRAPH -6 7.5###RSX-11 functions and routines .INDEX RSX library functions .BREAK ----------------------------- .BREAK These library functions allow the use of some of the more common RSX subroutines. They are all written in MACRO-11. .BREAK Since a number of these functions can detect error conditions a standard error action is taken, the runtime error routine (global 2) is called. A default error routine is always linked with a BCPL task, but this can be superceded by assigning a new routine to this global variable. .LEFT MARGIN 20 .SKIP .INDENT -14 ERROR() .BREAK This is the default runtime error routine. It causes messages of the form: .SKIP .NOFILL Z -- RUN TIME ERROR IN ROUTINE X .FILL .SKIP where Z is the task name and X the routine where the error occured. The task is then aborted. .SKIP .INDENT -14 READCOMMAND(P,B) .BREAK This function uses the GCML routines to read a command line from the console into the buffer B. The prompt string P is issued when necessary. One level of indirect files is allowed. An error is generated if an illegal indirect file is supplied. The function returns B, or 0 if command input has been terminated. .SKIP .INDENT -14 ANALYZE(S) .BREAK This function uses the CSI1 routine to perform syntax analysis## of an ##RSX command string S. A syntax error will result in an error call. The function returns a CSI block allocated from the heap. .SKIP .INDENT -14 PARSEINPUT(C,S) .INDENT -14 PARSEOUTPUT(C,S) .BREAK These functions use the CSI2 routine to form a dataset descriptor for the next input/output dataset specified in the command line used to generate the CSI block C. A switch table (S or 0) may be provided. Error is generated for illegal switches. The functions return a dataset descriptor. .SKIP .INDENT -14 OPENINPUT(D,F,S) .INDENT -14 .BREAK OPENOUTPUT(D,F,S) .BREAK These functions use the OPEN routine to open the dataset specified by the dataset descriptor D and the default file name block F. The dataset is opened for varaiable length record, move mode record I/O with maximum record size S. Error is called if the dataset cannot be opened. The functions return a FDB allocated from the heap. .SKIP .INDENT -14 READREC(F,B) .BREAK This routine reads a record from the dataset specified by the FDB F into the buffer B using the GET routine. Error is generated by a read fail. .SKIP .INDENT -14 WRITEREC(F,B) .BREAK This routine uses the PUT routine to write a record from the buffer B to the dataset specified by the FDB F. Error is generated by a write fail. .SKIP .INDENT -14 ENDOFFILE(F) .BREAK This function returns TRUE whenever the end-of-file has been reached on the dataset specified by the FDB F, and FALSE otherwise. .SKIP .INDENT -14 CLOSE(F) .BREAK This routine uses the CLOSE routine to close the dataset specified by the FDB F, and frees the storage used by the FDB. .LEFT MARGIN 6 .PARAGRAPH -6 7.6###Store management routines .BREAK ------------------------- .BREAK These routines are used to allocate and free areas of storage from the heap. .SKIP .LEFT MARGIN 20 .INDENT -14 HEAP(N) .BREAK This function delivers a N+1 word vector, allocated from the heap. .SKIP .INDENT -14 UNHEAP(V) .BREAK This routine returns the vector V to free storage. .LEFT MARGIN 6 .PARAGRAPH -6 7.7###Streams - implementation .INDEX Streams .BREAK ------------------------ .BREAK A stream is a BCPL vector of at least 5 words in length. It must contain the following elements:- .SKIP .LEFT MARGIN 20 .INDENT -14 FILE A variable .INDENT -14 BUFFER A vector .INDENT -14 TRANSFER A routine such that .BREAK ######TRANSFER(FILE,BUFFER) .BREAK causes a string to be transferred into the buffer in the case of an input stream, or out of the buffer in the case of an output stream. .INDENT -14 ENDOF A Boolean function such that .BREAK ######ENDOF(FILE) .BREAK returns TRUE if and only if no more TRANSFERs may take place on the FILE. .INDENT -14 POINTER An integer marking the current character position in the buffer. .SKIP .LEFT MARGIN 6 When these five elements are provided any of the library I/O functions detailed in 7.2.3 and 7.2.4 can be used on the stream. Conversely, if an I/O routine is written in terms of these five elements then it can be used on any stream, and in particular on those generated by FINDINPUT and CREATEOUTPUT. .PARAGRAPH 7.8###Logical unit (LUN) assignments .INDEX Logical units .BREAK ------------------------------ .BREAK The allocation of LUNs when using the library I/O routines is invisible to the user. The routines OPENINPUT and OPENOUTPUT allocate LUNs starting from 2 and working upwards. The routine CLOSE frees the associated LUN and subsequent OPENs may reuse it. .SKIP LUN 1 is dynamically assigned to the console input device (CI:) on program entry and is used by the error routine and the GCML routines. .PAGE .PARAGRAPH 8#####TASK BUILDING BCPL PROGRAMS .BREAK --------------------------- .PARAGRAPH 8.1###Separate assembly .INDEX Task building .INDEX Assembly .BREAK ----------------- .BREAK BCPL program segments may be separately compiled, translated and assembled. The resulting modules may be linked together at task-build time, since all communication between segments is via the global vector and this is an overlayed psect. .PARAGRAPH 8.2###Library modules .BREAK --------------- .INDEX Library modules .BREAK All BCPL programs must give the filename BCPLIB.OBJ as the final input dataset to task-builder. The /LB switch must be used to inform task builder that this is an object code library. All references to the functions and routines described in 7.2-7.5 will be resolved by the inclusion of the appropriate object modules into the task. .PARAGRAPH 8.3###Stack requirements .INDEX Stack .BREAK ------------------ .BREAK The STACK directive must always be used to allocate enough space for the runtime stack, the processor stack and the heap. For a BCPL program using the standard stream I/O functions the formula for calculating the exact requirement is: .SKIP STACK = 280+S+232*N (words) .SKIP where S is the size of the runtime stack, and N the maximum number of streams open simultaneously. .PARAGRAPH 8.4###Block buffer requirements .INDEX I/O buffers .BREAK ------------------------- .BREAK Since all the stream I/O is via the RSX11D filing system, space must be allocated for the block buffer requirements of the program. This is done by using the EXTSCT directive to extend the size of the psect $$FSR1. Each block buffer and header will require 1020 octal bytes of store, and buffers are required for the maximum number of streams which may be open concurrently. .PARAGRAPH 8.5###Logical unit requirements .INDEX Logical units .BREAK ------------------------- .BREAK The default task-builder allocation of 6 LUNs to a task is sufficient to allow a BCPL task to have 5 streams open concurrently. If more than this is necessary then the further LUNs must be allocated by using the UNITS directive to task-builder. .PARAGRAPH 8.6###Example .BREAK ------- .BREAK To## build #a# BCPL task##"TEST" from the two object modules TEST1 and TEST2 which has a maximum of two streams open simultaneously the following task-builder dialogue would be necessary. .SKIP .NOFILL TKB>DK1:TEST,TT:/SH=DK1:TEST1, TKB>DK1:TEST2,DK1:BCPLIB/LB TKB>/ ENTER OPTIONS: TKB>STACK=2000 TKB>EXTSCT=$$FSR1:2040 TKB>LIBR=SYSRES:RO TKB>TASK=TEST TKB>// .FILL .SKIP The STACK directive reserves about 1.3K words for the runtime stack. The LIBR directive is optional but if used forces the sharing of the resident library, thereby reducing the physical storage required by the task. .PARAGRAPH 8.7###Alternative library functions .BREAK ----------------------------- .BREAK Different versions of the standard library functions, such as special procedure entry and exit routines for tracing, may be included in a task simply by using the appropriate global names in the new versions and supplying them as input to task-builder. .BREAK e.g. For procedure tracing: appropraiate routines with the global names ENTER and EXIT are assembled into an object module called TRACE.OBJ. To build a task using these routines in place of the usual ones the following form of command line would be required: .SKIP .NOFILL TKB>DK1:TEST=DK1:TEST,DK1:TRACE, TKB>DK1:BCPLIB/LB .FILL .SKIP .PAGE .CENTER References .CENTER ---------- .NOFILL .LEFT MARGIN 0 0 D. W Barron et. al. The Main Features of CPL Computer Journal. 6 (1963), pp 134-143 1 Martin Richards, The BCPL Reference Manual University of Cambridge Computing laboratory. 1970. 2 Pete Gardner, The BCPL Reference Manual University of Essex Computing Centre. 1974. 3 Introduction to RSX-11D. Digital Equipment Corporation DEC-11-OXINA-A-D 4 RSX-11D MACRO Assembler. Digital Equipment Corporation DEC-11-OXDMA-B-C 5 Jeremy Holden, An OCODE Translator University of York. 1974. 6 D. L. Atkin, BCPL for writing KOS subsystems University of York. 1975. 7 J. E. Stoy and C. Strachey, OS6 Input/Output and Filing System Computer Journal. 15 (1972), pp 195-203 8 RSX-11D Task Builder. Digital Equipment Corporation DEC-11-OXDLA-B-D .FILL .PAGE .CENTER APPENDIX A .CENTER ---------- .LEFT MARGIN 6 .PARAGRAPH ######The character set .BREAK ----------------- .INDEX Character set .INDEX Escape characters .BREAK BCPL uses the standard ASCII character set. The two special characters newline and end-of-file which are recognised by the I/O system are represented by the ASCII characters line-feed (LF) and control-Z (SUB). .PARAGRAPH ######Representation .BREAK -------------- .BREAK All printing characters may be used within BCPL string and character denotations. Some special escape conventions are used to allow the representation of non-printing characters. They are: .TAB STOPS 13 26 42 .NOFILL .LEFT MARGIN 0 .SKIP Representation ASCII -------------- ----- *S SP-40 space *T HT-11 tab *N LF-12 newline *L LF-12 newline *C CR-15 carriage return *P FF-14 page *E SUB-32 escape *_^c where c is any printing character .LEFT MARGIN 26 .FILL is the control character (ASCII 0-37) corresponding to the low order 5 bits of c. e.g. *_^G is BEL (ASCII 7) .NOFILL .LEFT MARGIN 6 Also, .BREAK ** is * .BREAK *" is " *' is ' .FILL .SKIP Note that both ' and " can be used in matched pairs to delimit strings, except in the case of strings of length 1 in which case "C" is a string and 'C' is a character. The ' quote can be freely used within strings delimited by " and vice versa. .PAGE .CENTER APPENDIX B .CENTER ---------- .PARAGRAPH .INDEX Files ######Files used in the system .BREAK ------------------------ .BREAK .SKIP .NOFILL The compiler ------------ Compiler task BCPL.TSK Compiler source TSYN.BCL, NTRN.BCL Compiler globals TSYN.GET, NTRN.GET Compiler build file BCPL.CMD .SKIP The translator -------------- Translator task TRAN.TSK Translator source TRAN.BCL Translator globals TRAN.GET Translator build file TRAN.CMD .SKIP Runtime system -------------- Library modules BCPLIB.OBJ Standard globals BCPLIB.GET Source files: BCPL functions BCPLIB.BCL RSX functions RSXLIB.MAC Ancillary functions MACLIB.MAC .FILL .PAGE .CENTER APPENDIX C .CENTER ---------- .SKIP 2 .NOFILL Changes for RSX11D version 6 ---------------------------- .FILL .SKIP The only difference between the two systems is that the device TI: is used instead of CI: and CO: in all cases. .PAGE .CENTER APPENDIX D .CENTER ---------- .SKIP 2 .LEFT MARGIN 0 The BCPL libary .BREAK --------------- .BREAK .SPACING 1 .NOFILL GET "DK1:[100,10]BCPLIB.GET" LET makestream(open, t, string) = VALOF { LET s = heap(streamsize) LET c = analyze(string) LET dataset = parseoutput(c, 0) s|file := open(dataset, 0, buffersize) s|buffer := heap(buffersize) s|pointer, s|ended := 0, FALSE s|endof, s|transfer := endoffile, t unheap(c) RESULTIS s } AND findinput(s) = makestream(openinput, readrec, s) AND createoutput(s) = makestream(openoutput, writerec, s) AND readc() = VALOF { LET line = input|buffer AND next = input|pointer + 1 IF next = 1 { LET f = input|file IF input|ended RESULTIS eofch (input|transfer)(f, line) unpackstring(line, line) IF (endof|input)(f) { input|ended := TRUE ; RESULTIS eofch } } input|pointer := next IF next > line|0 { input|pointer := 0 ; RESULTIS '*N' } RESULTIS line|next } AND writec(ch) BE { LET line = output|buffer AND next = output|pointer + 1 TEST ch = '*N' THEN { line|0 := output|pointer packstring(line, line) (output|transfer)(output|file, line) output|pointer := 0 } OR { IF next > buffersize { writec('*N') ; next := 1 } output|pointer := next line|next := ch } } AND endread(stream) BE { close(stream|file) unheap(stream|buffer) unheap(stream) } AND endwrite(stream) BE { UNLESS stream|pointer = 0 { LET o = output output := stream writec('*N') output := o } endread(stream) } AND readn() = VALOF { LET s, n, c = 1, 0, 0 UNTIL '0' <= c <= '9' DO { c := readc() ; IF c = '-' s := -s } WHILE '0' <= c <= '9' DO { n := 10*n+c-'0' ; c := readc() } RESULTIS s*n } AND reado() = VALOF { LET n, c = 0, 0 UNTIL '0' <= c <= '7' DO c := readc() WHILE '0' <= c <= '7' DO { n := 8*n+c-'0' ; c := readc() } RESULTIS n } AND writed(n, d) BE { STATIC { negative = FALSE } LET w(n, d) BE TEST n > 9 THEN { w(n/10, d-1) writec(n REM 10 + '0') } OR { FOR i=2 TO d writec('*S') IF negative writec('-') writec(n + '0') } negative := n<0 TEST negative THEN w(-n, d-1) OR w(n, d) } AND writen(n) BE writed(n, 0) AND writes(s) BE { LET v = VEC 256 unpackstring(s, v) FOR i=1 TO v|0 writec(v|i) } AND writeoct(n, d) BE TEST 0 <= n <= 7 THEN { FOR i=2 TO d writec('0') writec(n + '0') } OR { writeoct(n>>3, d-1) writec((n_&7)+'0') } AND writeo(n) BE writeoct(n, 0) AND newline() BE writec('*N') AND writef(s, a, b, c, d, e, f, g, h, i, j) BE { LET v = VEC 256 LET param, j = @s, 1 unpackstring(s, v) FOR i=1 TO v|0 { LET c = v|i TEST c = '%' THEN { LET val = param|j i, j := i+1, j+1 SWITCHON v|i INTO { CASE 'C': writec(val) ; ENDCASE CASE 'S': writes(val) ; ENDCASE CASE 'N': writen(val) ; ENDCASE CASE 'O': writeo(val) ; ENDCASE CASE 'D': writed(val, param|j) j := j+1 ; ENDCASE DEFAULT: j := j-1 ; writec(v|i) } } OR writec(c) } } .PAGE .CENTER INDEX .CENTER ----- .SKIP 2 .PRINT INDEX