BCPL(ID:374/bcp001)Basic CPLBasic CPL. Richards 1967. British systems language, a descendant of CPL and the inspiration for B and C. BCPL is low-level, typeless and block-structured, and provides only one-dimensional arrays. Case is not significant, but conventionally reserved words begin with a capital. Flow control: If-Then, Test-Then-Else, Unless-Do, While-Do, Until-Do, Repeat, Repeatwhile, Repeatuntil, For-to-By-Do, Loop, Break and Switchon-Into-Case-Default-Endcase. BCPL has conditional expressions, pointers, and manifest constants. BCPL had both procedures: 'Let foo(bar) Be command' and functions: 'Let foo(bar) = expression'. 'Valof $(..Resultis..$)' causes a compound command to produce a value. Parameters are call-by-value. Program segments communicate via the global vector where system and user variables are stored in fixed numerical locations in a single array. BCPL was used to implement the TRIPOS OS, which was subsequently reincarnated as AmigaDOS. Oxford BCPL differed slightly: Test-Ifso-Ifnot, and section brackets in place of $( $). Places People: Structures: Related languages
References: in [AFIPS] Proceedings of the 1969 Spring Joint Computer Conference SJCC 34 view details in Computers & Automation 21(6B), 30 Aug 1972 view details Choice of language As a deliberate act of policy it was decided to write the entire system in one high level language, as it seems to us that the current practice of writing software in an assembly language is one of the main sources of the 'software problem'. There are three main areas in which the use of a high level language can relieve a programmer of tedious organisational details: 1. The control of the path of execution. 2. Storage allocation. 3. The representation of information. For software work, and particularly in the programming of operating systems, elaborate provisions and conventions about storage allocation and data representation can be an embarrassment. It is usually the job of the operating system, for example, to provide a suitable storage allocation algorithm, and it is inappropriate that decisions about it should be prejudiced by the design of the language used. Moreover, the requirement that an operating system should deal with storage allocation implies that the language should allow addresses to be treated as data objects, and for calculations to be performed on them. In assembly code this is a matter of course, but few high level languages are equipped for it. Generally pointers and addresses, if treated at all, are either so limited that one may not even assign a new value to them (cf. arrays in ALGOL 60) or are strongly associated with the particular kinds of data structure available in the language (cf. LISP). Operating systems are concerned with the general problem of the allocation of the actual hardware resources, and are one of the few applications where the linear mode of addressing employed in most computer memories must be accessible in the language. Software writers also require great flexibility in their choice of data representation. It is probably the existence of too many constraints in these two areas that turns software writers away from high level languages back to their more permissive machine codes. On the other hand, there is general agreement about what facilities are desirable to control the path of execution- such things as conditional commands and expressions, functions and subroutines, cycle commands and recursion. Although in most existing languages all three areas are treated with comparable sophistication, it is by no means essential to do so. The resources of the ideal software language should, in our opinion, be concentrated around the control facilities, and matters concerning storage and representation left very much to the programmer. BCPL, the language used in OS6, is just such a language. It was invented by Martin Richards (1969a, b), and is superficially very like CPL (Barron, Buxton, Hartley, Nixon, and Strachey, 1963), from which it gets its name, with the same richness as CPL in the syntax of commands and expressions. There is only one type, the bit pattern: that is to say, the language deals directly with the representations of objects rather than with the abstract objects themselves. This property makes the language unsuitable for the general programmer, as it does not prevent his performing meaningless operations (such as multiplying together two labels); on the other hand, it provides the extra flexibility system programmers require. BCPL has no automatic storage allocation--except for a rudimentary stack for local variables and local vectors-but one of the operators in the language allows a bit pattern to be treated as an address, and the converse operation is also available: this provides the mechanism for the control of storage and the manipulation of data structures. Extract: BCPL v ALGOL Although this compromise is better than nothing, it is not entirely satisfactory. The difficulties are an example of those which often occur when it is attempted to impose hierarchical behaviour on a non-hierarchical structure (in this case a linear vector). Global functions which have been overwritten by subsequent definitions are (if only temporarily) completely inaccessible, and not merely hidden. One would prefer something more like the ALGOL scope rules, and a more sophisticated method of segmentation: but BCPL is more concerned with ease of implementation. All this is an example of the general tendency for the power of hierarchical expression in a language to be reduced by the lack of corresponding power in the mechanism for storage of variables. The ability to trap the application of an undefined global, whether or not it has been previously defined, has been used in a debugging facility, which is discussed further below Extract: Conclusions Conclusions This paper is a progress report: the research which it describes is still under way. It should not be regarded as a definitive statement even on single-user operating systems. It might, however, be useful to list what conclusions we have reached, and to discuss how our work relates to other research on operating systems. 5.1. The 'single-user' simplljication Our restriction to a single user situation separates us to a large extent from the mainstream of research, which is principally concerned with the problems of manipulating concurrent autonomous processes and controlling their interaction. The extension of our system to cover concurrent activities is our next step; then we expect to be able to draw considerably on work with other 'clean' systems, for example those of Dijkstra (1968), Hansen (1970), and Spooner (1971). 5.2. Hierarchy and autonomy It is interesting that both Dijkstra's system (op. cit.) and ours may be described as hierarchical. In fact the hierarchies are quite different. Dijkstra has an hierarchy of resource allocation, because it is easier to administer one resource at a time; we allow hierarchical use of the system, because it is easier to think about a problem at one level at a time. So Dijkstra has a strictly hierarchically structured system to service a set of autonomous user processes, whereas our system is an amorphous set of routines to service a single hierarchically structured process. Moreover, an attempt to impose a hierarchical structure on our system (by forbidding the possible mutual recursion of our routines) would effectively prevent any hierarchy in the structure of the user job. The conclusion to be drawn from this comparison is that hierarchy and autonomy are both essential features, in some way or other, of any operating system. Certainly our experience has been that most of our difficulties were examples of the clash between these two principles. So far we have simplified matters by having as little autonomy as possible; it remains to be seen what difficulties occur when we attempt to allow several autonomous, hierarchically structured processes. Clashes between hierarchy and autonomy are, of course, by no means confined to computing: history is full of more or less violent attempts to change the balance between them. We should perhaps study examples where fairly stable situations exist, to see if they can help us solve the computing problem. 7 5.3. Avoidance of a job control language Our hierarchy was made possible partly by our decision to avoid a 'job control language', and to use a high level language instead. Barron (1971), for example, is also thinking along similar lines, and rightly points out that the difficulties come when a system includes several different languages with disparate conventions. But this problem is not confined to job control languages : it may occur also when a user program calls on a system routine written in a different high level language. So far we have avoided this problem, too, by confining ourselves almost exclusively to a single language; we shall have to reckon with it seriously when we come to allow processes to be written in different languages, and even to be run on different virtual machines, controlled and serviced by the same operating system. 5.4. Machine independence The problem of language compatibility within a system is more conspicuous when the operating system itself is written in a high level language. The great advantage of such a system, on the other hand, is its freedom from many of the problems of hardware compatibility. Provided the machines we consider have viable BCPL implementations, and provided their peripheral arrangements are satisfactory, the choice of one particular order code before another is governed purely by questions of compactness of code and speed. So the details of the IC machine are irrelevant to the success of the system we have described. Indeed, during our work with the system we have used several different virtual machines. As the BCPL compiler is written in BCPL, it is not difficult to rewrite the code generator for a new machine; as the operating system is in BCPL, we may then simply recompile it. In the last such exercise, by the expenditure of about two research-studentmonths, we 'tuned' the order code, reducing the size of the code by about 25 % in core and (because the amount of relocation information was also reduced) by 30% on disc, and speeding up execution by about 15 %. 5.5. Importance of the interpreter The previous paragraph implies that it would be possible by using the sophisticated BCPL code generator for Modular One machine code (Bath, 1970), to run the system on the Modular One itself, without an interpreter.: But we are convinced that our decision to use an interpreter was wise. It is the only inexpensive way at present to do practical experiments in processor design. The alternative is to use a microprogrammable machine, and it is sadly true that much of the current research on microprogramming seems to neglect the question of what kind of complex instructions could usefully be implemented: instead, the hardware designers have a new opportunity to avoid considering the needs of the software. In our situation, however, the advantage of microprogramming (a tenfold increase in speed) does not justify the extra expense and complexity. But we feel it is essential for the requirements of our programs to begin to influence the design of our hardware, and the flexibility provided by the interpreter has been of immense We hope to publish the complete text of 0S6 as a Programvalue. ming Research Group Technical Monograph. in The Computer Journal 15(2) 1972 view details in The Computer Journal 15(2) 1972 view details in ACM Computing Reviews 15(04) April 1974 view details The exact number of all the programming languages still in use, and those which are no longer used, is unknown. Zemanek calls the abundance of programming languages and their many dialects a "language Babel". When a new programming language is developed, only its name is known at first and it takes a while before publications about it appear. For some languages, the only relevant literature stays inside the individual companies; some are reported on in papers and magazines; and only a few, such as ALGOL, BASIC, COBOL, FORTRAN, and PL/1, become known to a wider public through various text- and handbooks. The situation surrounding the application of these languages in many computer centers is a similar one. There are differing opinions on the concept "programming languages". What is called a programming language by some may be termed a program, a processor, or a generator by others. Since there are no sharp borderlines in the field of programming languages, works were considered here which deal with machine languages, assemblers, autocoders, syntax and compilers, processors and generators, as well as with general higher programming languages. The bibliography contains some 2,700 titles of books, magazines and essays for around 300 programming languages. However, as shown by the "Overview of Existing Programming Languages", there are more than 300 such languages. The "Overview" lists a total of 676 programming languages, but this is certainly incomplete. One author ' has already announced the "next 700 programming languages"; it is to be hoped the many users may be spared such a great variety for reasons of compatibility. The graphic representations (illustrations 1 & 2) show the development and proportion of the most widely-used programming languages, as measured by the number of publications listed here and by the number of computer manufacturers and software firms who have implemented the language in question. The illustrations show FORTRAN to be in the lead at the present time. PL/1 is advancing rapidly, although PL/1 compilers are not yet seen very often outside of IBM. Some experts believe PL/1 will replace even the widely-used languages such as FORTRAN, COBOL, and ALGOL.4) If this does occur, it will surely take some time - as shown by the chronological diagram (illustration 2) . It would be desirable from the user's point of view to reduce this language confusion down to the most advantageous languages. Those languages still maintained should incorporate the special facets and advantages of the otherwise superfluous languages. Obviously such demands are not in the interests of computer production firms, especially when one considers that a FORTRAN program can be executed on nearly all third-generation computers. The titles in this bibliography are organized alphabetically according to programming language, and within a language chronologically and again alphabetically within a given year. Preceding the first programming language in the alphabet, literature is listed on several languages, as are general papers on programming languages and on the theory of formal languages (AAA). As far as possible, the most of titles are based on autopsy. However, the bibliographical description of sone titles will not satisfy bibliography-documentation demands, since they are based on inaccurate information in various sources. Translation titles whose original titles could not be found through bibliographical research were not included. ' In view of the fact that nany libraries do not have the quoted papers, all magazine essays should have been listed with the volume, the year, issue number and the complete number of pages (e.g. pp. 721-783), so that interlibrary loans could take place with fast reader service. Unfortunately, these data were not always found. It is hoped that this bibliography will help the electronic data processing expert, and those who wish to select the appropriate programming language from the many available, to find a way through the language Babel. We wish to offer special thanks to Mr. Klaus G. Saur and the staff of Verlag Dokumentation for their publishing work. Graz / Austria, May, 1973 in ACM Computing Reviews 15(04) April 1974 view details in The Computer Journal 15(3) 1972 view details The method explored in this paper is the preferred mechanism for transferring BCPL and involves the use of an interpretive machine code called INTCODE. INTCODE is designed specifically for this purpose. Its design and the general strategy of using it in a transfer are described. in Machine Oriented Higher Level Languages (van der Poel, Maarsen, editors) North Holland 1974 view details in Machine Oriented Higher Level Languages (van der Poel, Maarsen, editors) North Holland 1974 view details in SIGPLAN Notices 11(04) April 1976 view details External link: Online copy in The Computer Journal 19(2) May 1976 view details in Proceedings of the 1978 annual conference 1978, Washington, D.C., United States view details in SIGPLAN Notices 13(11) Nov 1978 view details in SIGPLAN Notices 13(11) Nov 1978 view details in SIGPLAN Notices 14(07) July 1979 view details in SIGPLAN Notices 14(07) July 1979 view details in The Computer Journal 25(3) 1982 view details in The Computer Journal 25(3) 1982 view details in Software — Practice and Experience 14(04) April 1984 view details in Software — Practice and Experience 14(04) April 1984 view details BCPL was designed by Martin Richards in the mid-1960s while he was visiting MIT, and was used during the early 1970s for several interesting projects, among them the OS6 operating system at Oxford [Stoy 72], and parts of the seminal Alto work at Xerox PARC [Thacker 79]. We became familiar with it because the MIT CTSS system [Corbato 62] on which Richards worked was used for Multics development. The original BCPL compiler was transported both to Multics and to the GE-635 GECOS system by Rudd Canaday and others at Bell Labs [Canaday 69]; during the final throes of Multics's life at Bell Labs and immediately after, it was the language of choice among the group of people who would later become involved with Unix. BCPL, B, and C all fit firmly in the traditional procedural family typified by Fortran and Algol 60. They are particularly oriented towards system programming, are small and compactly described, and are amenable to translation by simple compilers. They are "close to the machine' in that the abstractions they introduce are readily grounded in the concrete data types and operations supplied by conventional computers, and they rely on library routines for input-output and other interactions with an operating system. With less success, they also use library procedures to specify interesting control constructs such as coroutines and procedure closures. At the same time, their abstractions lie at a sufficiently high level that, with care, portability between machines can be achieved. BCPL, B and C differ syntactically in many details, but broadly they are similar. Programs consist of a sequence of global declarations and function (procedure) declarations. Procedures can be nested in BCPL, but may not refer to non-static objects defined in containing procedures. B and C avoid this restriction by imposing a more severe one: no nested procedures at all. Each of the languages (except for earliest versions of B) recognizes separate compilation, and provides a means for including text from named files. Several syntactic and lexical mechanisms of BCPL are more elegant and regular than those of B and C. For example, BCPL's procedure and data declarations have a more uniform structure, and it supplies a more complete set of looping constructs. Although BCPL programs are notionally supplied from an undelimited stream of characters, clever rules allow most semicolons to be elided after statements that end on a line boundary. B and C omit this convenience, and end most statements with semicolons. In spite of the differences, most of the statements and operators of BCPL map directly into corresponding B and C. Some of the structural differences between BCPL and B stemmed from limitations on intermediate memory. For example, BCPL declarations may take the form let P1 be command and P2 be command and P3 be command … where the program text represented by the commands contains whole procedures. The subdeclarations connected by and occur simultaneously, so the name P3 is known inside procedure P1. Similarly, BCPL can package a group of declarations and statements into an expression that yields a value, for example E1 := valof ( declarations ; commands ; resultis E2 ) + 1 The BCPL compiler readily handled such constructs by storing and analyzing a parsed representation of the entire program in memory before producing output. Storage limitations on the B compiler demanded a one-pass technique in which output was generated as soon as possible, and the syntactic redesign that made this possible was carried forward into C. Certain less pleasant aspects of BCPL owed to its own technological problems and were consciously avoided in the design of B. For example, BCPL uses a "global vector" mechanism for communicating between separately compiled programs. In this scheme, the programmer explicitly associates the name of each externally visible procedure and data object with a numeric offset in the global vector; the linkage is accomplished in the compiled code by using these numeric offsets. B evaded this inconvenience initially by insisting that the entire program be presented all at once to the compiler. Later implementations of B, and all those of C, use a conventional linker to resolve external names occurring in files compiled separately, instead of placing the burden of assigning offsets on the programmer. Other fiddles in the transition from BCPL to B were introduced as a matter of taste, and some remain controversial, for example the decision to use the single character = for assignment instead of :=. Similarly, B uses /**/ to enclose comments, where BCPL uses //, to ignore text up to the end of the line. The legacy of PL/I is evident here. (C++ has resurrected the BCPL comment convention.) Fortran influenced the syntax of declarations: B declarations begin with a specifier like auto or static, followed by a list of names, and C not only followed this style but ornamented it by placing its type keywords at the start of declarations. Not every difference between the BCPL language documented in Richards's book [Richards 79] and B was deliberate; we started from an earlier version of BCPL [Richards 67]. For example, the endcase that escapes from a BCPL switchon statement was not present in the language when we learned it in the 1960s, and so the overloading of the break keyword to escape from the B and C switch statement owes to divergent evolution rather than conscious change. In contrast to the pervasive syntax variation that occurred during the creation of B, the core semantic content of BCPL is its type structure and expression evaluation rules?remained intact. Both languages are typeless, or rather have a single data type, the "word," or "cell," a fixed-length bit pattern. Memory in these languages consists of a linear array of such cells, and the meaning of the contents of a cell depends on the operation applied. The + operator, for example, simply adds its operands using the machine's integer add instruction, and the other arithmetic operations are equally unconscious of the actual meaning of their operands. Because memory is a linear array, it is possible to interpret the value in a cell as an index in this array, and BCPL supplies an operator for this purpose. In the original language it was spelled rv, and later !, while B uses the unary *. Thus, if p is a cell containing the index of (or address of, or pointer to) another cell, *p refers to the contents of the pointed-to cell, either as a value in an expression or as the target of an assignment. Because pointers in BCPL and B are merely integer indices in the memory array, arithmetic on them is meaningful: if p is the address of a cell, then p+1 is the address of the next cell. This convention is the basis for the semantics of arrays in both languages. When in BCPL one writes let V = vec 10 or in B, auto V[10]; the effect is the same: a cell named V is allocated, then another group of 10 contiguous cells is set aside, and the memory index of the first of these is placed into V. By a general rule, in B the expression *(V+i) adds V and I, and refers to the i-th location after V. Both BCPL and B each add special notation to sweeten such array accesses; in B an equivalent expression is V[i] and in BCPL V!i This approach to arrays was unusual even at the time; C would later assimilate it in an even less conventional way. None of BCPL, B, or C supports character data strongly in the language; each treats strings much like vectors of integers and supplements general rules by a few conventions. In both BCPL and B a string literal denotes the address of a static area initialized with the characters of the string, packed into cells. In BCPL, the first packed byte contains the number of characters in the string; in B, there is no count and strings are terminated by a special character, which B spelled "*e". This change was made partially to avoid the limitation on the length of a string caused by holding the count in an 8- or 9-bit slot, and partly because maintaining the count seemed, in our experience, less convenient than using a terminator. Individual characters in a BCPL string were usually manipulated by spreading the string out into another array, one character per cell, and then repacking it later; B provided corresponding routines, but people more often used other library functions that accessed or replaced individual characters in a string. in Software — Practice and Experience 14(04) April 1984 view details in Software — Practice and Experience 14(04) April 1984 view details in Software — Practice and Experience 14(04) April 1984 view details Resources
|