CPL, BCPL, B - the origins of C

Nice history article here, from Strachey and Titan, via Wilkes, to Richards and then Ken Thompson. More links and video within.

CPL was a step too far: a new language when none was needed. “We thought this was an opportunity to have fun with a new language—which, in hindsight, was a damn stupid thing to do.” But the report on existing languages deliberately under-rated them.

Wilkes required an analysis of available programming languages before approving a proposal to develop a new language. “We chose them very carefully,” Hartley said, “in order to decide that none of them were suitable.” Notably, the working group evaluated Fortran IV without consulting Fortran users at Cambridge who could have explained the additional features included with other varieties of Fortran. Because of this, Hartley recalled the group being convinced that “we could easily define and develop something significantly better,” before noting, “this failing came home to roost in a few years.”

…it was socially acceptable to “prowl around” the MIT mainframes looking at other projects, and this was how [Ken] found both the code and documentation for BCPL…
Thompson took his copy of BCPL—which was CPL with reduced functionality—and further compressed it so that it would fit into the available 4k of memory on the PDP-7. In the course of doing this, he borrowed from a language he had encountered while a student at the University of California, Berkeley. That language, “SMALGOL,” was a subset of ALGOL 60 designed to run on less powerful computers.

The language that Thompson eventually ended up using on the PDP-7 was, as he described it to Ars, “BCPL semantics with a lot of SMALGOL syntax,” meaning that it looked like SMALGOL and worked like BCPL. Because this new language consisted only of the aspects of BCPL that Thompson found most useful and that could be fit into the rather cramped PDP-7, he decided to shorten the name “BCPL” to just “B.”

3 Likes

Looking for SMALGOL I notice you had a lot of compilers in the early 60’s created,
made a footnote in some computer paper, and totaly forgtton when
the host machine got replaced or updated, and all soure code lost
or thrown out. Compilers were said to slow, but when you use a serial
drum based computer,what do you expect for speed?

1 Like

I note that this story is somewhat different from the story that Thompson told at VCF East 2019, when he claimed that he started from Fortran, not from BCPL; I suspect that, as with all large undertakings, the truth is complicated!

(The interview starts 8-10 minutes in, C is somewhat later.)

1 Like

Oh, it’s awkward to have two versions of a history! That bit appears about the 41min mark of the video…

See also this interview transcript from '89…

Thompson: After UNIX was up, or, simultaneous with UNIX coming out, BCPL was just emerging and that was a clear winner with both of us. Both of us were really taken by the language and did a lot of work with it.

MSM: How did you come up with it, it’s an English language wasn’t it?

Thompson: Ah yes, but the guy who did, Martin Richards, actually developed it at MIT. It was available in a very informal way, on CTSS and we pulled it off of CTSS and got a version running on GECOS here and did system programming there. It was too big a language to run on the UNIX machines that were 4K machines. That’s when B was developed. Which was …

MSM: Did you develop B?

Thompson: I did B.

MSM: As a subset of BCPL

Thompson: It wasn’t a subset. It was almost exactly the same. It was a interpreter instead of a compiler. It had two passes. One went into intermediate language and which one was the interpreter of the intermediate language. Dennis wrote a compiler for B, that worked out of the intermediate language.

1 Like

I thought the Fortran thing came after in an effort to allow people without access to Unix and C to benefit from their “Software Tools” system. It was a preprocessor called Ratfor (Rational Fortran) that allowed you to write in a C style and feed the transformed result into your regular Fortran compiler.

Ratfor was Kernighan and … Plauger? I’m not sure Thompson was involved.

This is also interesting, from Dennis Ritchie:
Five Little Languages and How They Grew: Talk at HOPL

Bliss, Pascal, Algol 68, BCPL, C. All these were developed in more or less the same period. I’m going to argue that they’re very much similar in a lot of ways. And each succeeded in various ways, either by use or by influence

Edit: and this classic also by Ritchie:
The Development of the C Language

B can be thought of as C without types; more accurately, it is BCPL squeezed into 8K bytes of memory and filtered through Thompson’s brain.

1 Like

Interestingly, Thompson gave an interview to Peter Seibel for the book Coders at Work: Reflections on the Craft of Programming (2009), where he says:

Thompson: […] I wrote a Fortran compiler for Unix early, and B was a Fortran compiler that got away from me.
Seibel: I thought B was your translation of BCPL.
Thompson: It sort of was. It started off as—I don’t know what it was. Semantically, it turned out to be BCPL. As I started it, it was going to be Fortran. And at that point I got my first description of BCPL. And I liked the clean semantics. And that’s when I abandoned Fortran and it turned into essentially C syntax and BCPL semantics.

This seems to unify the Thompson and Ritchie stories, and the common story floating around, in a satisfying way (and predates the above video by about a decade).

2 Likes

“Yaccman” Steven Johnson went on a sabbatical from Bell Labs to Waterloo University and took B with him. A group of people there formed a company which still offers B for GCOS: B Language Reference Manual

4 Likes

@elb - that really seems to clear things up! Thanks. It all makes sense now. If I recall the video correctly he said that he kept stripping down his what-was-meant-to-become-Fortran until it fit, and ended up with B… so the missing link would then be that he at the same time looked at BCPL semantics and that was incorporated during that process, the Fortran origins melted away and out came B.

3 Likes

The Honeywell B was somewhat different to the early Unix B, and unlike early unix B actually got used a lot. It imported a bunch of the C fixes for ambiguous operations such as adding && and ||, as well as += and the like. It also had varargs of sorts, but instead of being based upon parsing format info the number was passed explicitly and available to the called function. Thus you had nice stuff like

            concat(a, "hello ", name, ".");

I still miss one or two things it had. In particular switch cases supported ranges and you could also specify end ranges.

On what was fundamentally a 36 bit word based machine B worked really well. There were some other little documented oddities too. You could free() a function, and because of the way the indexing worked on an L66 (everything is layers of indexing - even the register and other modifiers are available) you could do stupid stuff like assign a new value to printf and it would change printf.

3 Likes

At this point I suppose it should also be mentioned that one significant body of B code is AberMUD, which is the “first popular open source MUD” according to Wikipedia. It was written by @EtchedPixels and others at Aberystwyth University. The code still exists, but only in paper form.

So how does indexing work compared to other software?

@larsbrinkhoff I think Alec Muffet has a printout somewhere. I don’t.

Everything is a machine word. So x[6] is simply adding 6. You can also thus write 6[x] and the same happens.

Character operations are done by function calls, so you can ask for the nth character, blocks of characters and so on, and you can combine and compare strings etc. You could do direct string manipulation but it still works in machine words so you’d have to mask and shift stuff. In practice nobody actually does much direct string manipulation in C anyway so it works fine for the same reasons C does on a word machine.

1 Like

Like a lot of old machines the Honeywell systems support indirect addressing. If you do an indirecting load/store then it fetches a machine word and uses that. Only in this case it’s not a simple single indirect. If that has indirections then it doesn’t just indirect again it can be told to apply all the index register modifications and addressing bits in that word to get a new address and repeats the exercise (I think it traps after 8 levels or so to stop loops). It also has tally mode which does some byte/character/bit stuff.

1 Like

Which, of course, is retained by C, it simply adjusts the offset by the type of the array first. :slight_smile:

This is always an interesting thing to explain to students; a[6] is simply *(a + 6), and *(6 + a) yields the same result, so…

1 Like

Multi-level indirection is a powerfull feature, just not someting visable with a modern high level language. Tiny computers with 32 bit words, (IBM 360) don’t have a spare bit for indirection.
The PDP 11 is interesting in that it had a character type, other machines
used packed bytes as default. IBM in thier great wisdom forced 8 bit bytes, and
32 bits as the forever computing standard, some thing too small for what I consider
real computing, A bit for byte addressing, a bit for indiection, a bit for immedate addressiing, a bit for signed, unsigned, back to 36 bits again. PS: I forgot to add,
a bit for binary or decimal operations.

This is always an interesting thing to explain to students; a[6] is simply *(a + 6), and *(6 + a) yields the same result, so…
What if 6 is 6.31?
Can I define a = 1332 and then go a[6]?
a is really a constant, with some flags to indicate what variable it relative with
and some times it is pointer instead.
I think array data types, need always to converted to ponters,
and variables declared to keep varables local.
define i,Foo[10000], j let i=0 for j=1 to 10000 , j = h+ 1 do i=i+foo[j]
does require large offsets for the variable j

My problem is with Pascal and Algol, where is ‘a’ from, with the way variable
blocks and routines are structured. C was easy, you just had global and local
variables, and 3 data sizes char, short,long.
Ben,

Not in C, but you can in B. In neither language can a be 6.31 (words are words are words in B, so it would be interpreted as the integer equivalent of whatever 6.31 is, and types save you in C), but in (at least some implementations of?) B you can absolutely dereference any given word and receive the word at that logical location. I wouldn’t be surprised if V6 C would allow an arbitrary integer-valued a to be used as an array, but V7 and ANSI C and later will not. A pointer-valued a, on the other hand…