There is also CSTR #8, which is a report by Steve Johnson and Brian Kernighan describing the B implementation on Honeywell equipment.
The language being described was really the same, but it's interesting to look at the differences in description and environment. To describe the BNF syntax, Ken used a variant that depends on super- and subscripts to say "how many", which in the original were stacked above each other when they occurred simultaneously. This doesn't look too awful in the HTML rendering, but was probably better in the original.
The other thing that is observable is the degree to which the GCOS version had to struggle to work in that environment. Its library description is full of odd concepts like "the AFT" the *SRC file, and other peculiarities.
--DMR, July 1997 ]
{..}m m,m+1,... {..}mn m,m+1,...,n
program ::= {definition}0 definition ::= name {[ {constant}01 ]}01 {ival {, ival}0}01 ; name ( {name {, name}0}01 W) statement ival ::= constant name statement ::= auto name {constant}01 {, name {constant}01}0 ; statement extrn name {, name}0 ; statement name : statement case constant : statement { {statement}0 } if ( rvalue ) statement {else statement}01 while ( rvalue ) statement switch rvalue statement goto rvalue ; return {( rvalue )}01 ; {rvalue}01 ; rvalue ::= ( rvalue ) lvalue constant lvalue assign rvalue inc-dec lvalue lvalue inc-dec unary rvalue & lvalue rvalue binary rvalue rvalue ? rvalue : rvalue rvalue ( {rvalue {, rvalue}0 }01 ) assign ::= = {binary}01 inc-dec ::= ++ -- unary ::= - ! binary ::= | & == != < <= > >= << >> - + % * lvalue ::= name * rvalue rvalue [ rvalue ] constant ::= {digit}1 ' {char}12 ' " {char}0 " name ::= alpha {alpha-digit}07 alpha-digit ::= alpha digit
*0 null *e end-of-file *( { *) } *t tab ** * *' ' *" " *n new line
(b? f:g[i] )(1, x>1)
*X
&x
lvalue op rvalue
if(rvalue) statement1
if(rvalue) statement1 else statement2
if(x=(rvalue)) statement1 if(!x) statement2
while(rvalue) statement
x: if(rvalue) { statement goto x; ]
switch rvalue statement1
case constant:
goto rvalue ;
return ;
return ( rvalue ) ;
extrn name1 , name2 ... ;
auto name1 {constant}01 , name2 {constant]01 ... ;
name :
main(); exit();
name {ival , ival ...}0 ;
name [ {constant}01 ] {ival , ival ...}0 ;
name ( arguments ) statement
/* The following function will print a non-negative number, n, to the base b, where 2<=b<=10, This routine uses the fact that in the ANSCII character set, the digits O to 9 have sequential code values. */ printn(n,b) { extrn putchar; auto a; if(a=n/b) /* assignment, not test for equality */ printn(a, b); /* recursive */ putchar(n%b + '0'); }
/* The following program will calculate the constant e-2 to about 4000 decimal digits, and print it 50 characters to the line in groups of 5 characters. The method is simple output conversion of the expansion 1/2! + 1/3! + ... = .111.... where the bases of the digits are 2, 3, 4, . . . */ main() { extrn putchar, n, v; auto i, c, col, a; i = col = 0; while(i<n) v[i++] = 1; while(col<2*n) { a = n+1 ; c = i = 0; while (i<n) { c =+ v[i] *10; v[i++] = c%a; c =/ a--; } putchar(c+'0'); if(!(++col%5)) putchar(col%50?' ': '*n'); } putchar('*n*n'); } v[2000]; n 2000;
/* The following function is a general formatting, printing, and conversion subroutine. The first argument is a format string. Character sequences of the form `%x' are interpreted and cause conversion of type 'x' of the next argument, other character sequences are printed verbatim. Thus printf("delta is %d*n", delta); will convert the variable delta to decimal (%d) and print the string with the converted form of delta in place of %d. The conversions %d-decimal, %o-octal, *s-string and %c-character are allowed. This program calls upon the function `printn'. (see section 9.1) */ printf(fmt, x1,x2,x3,x4,x5,x6,x7,x8,x9) { extrn printn, char, putchar; auto adx, x, c, i, j; i= 0; /* fmt index */ adx = &x1; /* argument pointer */ loop : while((c=char(fmt,i++) ) != `%') { if(c == `*e') return; putchar(c); } x = *adx++; switch c = char(fmt,i++) { case `d': /* decimal */ case `o': /* octal */ if(x < O) { x = -x ; putchar('-'); } printn(x, c=='o'?8:1O); goto loop; case 'c' : /* char */ putchar(x); goto loop; case 's': /* string */ while(c=char(x, j++)) != '*e') putchar(c); goto loop; } putchar('%') ; i--; adx--; goto loop; }
/etc/bc source interm
/etc/ba interm asource rm interm
as asource mv a.out object rm asource
ld object /etc/brt1 -lb /etc/bilib /etc/brt2
a.out
sh /usr/b/rc x
automatic = external + 100.; va; 4 / lvalue of first automatic on stack x; .external / rvalue of external on stack c; 100. / rvalue of constant on stack b12 / binary operator #12 (+) b1 / binary operator #1 (=) ... va: mov (r3)+,r0 add r4,rO / dp+offset of automatic asr rO / lvalues are word addresses mov r0,(r5)+ jmp *(r3)+ / linkage between subroutines x: mov *(r3)+,(r5)+ jmp *(r3)+ c: mov (r3)+,(r5)+ jmp *(r3)+ b12: add -(r5),-2(r5) jmp *(r3)+ b1: mov -(r5),r0 / rvalue mov -(r5),r1 / lvalue asl r1 / now byte address mov r0,(r1) / actual assignment mov r0,(r5)+ / = returns an lvalue jmp *(r3)+
b103 =& b104 === b105 =!= b106 =<= b107 =< b110 =>= b111 => b120 =/
error name meaninq $) -- {} imbalance () -- () imbalance */ -- /* */ imbalance [] -- [] imbalance >c -- case table overflow (fatal) >e -- expression stack overflow (fatal) >i -- label table overflow (fatal) >s -- symbol table overflow (fatal) ex -- expression syntax lv -- rvalue where lvalue expected rd name name redeclaration sx keyword statement syntax un name undefined name xx -- external syntax