Dc, the venerable desktop calculator

Here’s a video demo and presentation, on dc, the Unix program which predates ‘C’ and indeed constitutes a programming language:

dc will run to arbitrary precision, limited by memory, and you’ll see from the thumbnail it supports macros and recursion. In fact that’s its only offering, but it’s enough. The paradigm is stack-based, RPN, with single-character syntax (and therefore something like 26 registers and 26 macros, I will guess.)

Not only is it very old, but it’s also current - my MacBook has a dc, which turns out to be a GNU dc. And what’s more, as bc, the more user-friendly but in some ways less capable ‘basic calculator’, was originally built on top of dc, it turns out dc has probably been very widely used indeed.

Ken Thompson has said that Robert Morris wrote dc (in assembly language, apparently) and that it was the very first program written on their PDP 11/20, at a point when the disk hadn’t yet been delivered and the machine ran their nascent Unix port from paper tape.

But note that Doug McIlroy has a slightly different take here:

On the tiny PDP-7 the assembler was supplemented by tmg, Doug McIlroy’s version of Bob McClure’s compiler-compiler. Using it Thompson wrote B, the evolutionary link between Martin Richards’s (Cambridge University) BCPL and C. The PDP-11 assembler, a desk calculator dc, and B itself were written in B to bootstrap the system to the PDP-11. Because it could run before the disk had arrived, dc - not the assembler - became the first language to run on our PDP-11. Soon revised to handle arbitrary precision numbers (v1), dc was taken over by Bob Morris and Lorinda Cherry. It now ranks as the senior language on UNIX systems.

If you like keystroke-programmed arbitrary-precision RPN, or HP’s 48g calculator (from 1990), you might also like calc-mode within Emacs, also from 1990, as described in this nearby video:

You’ll get some of the features of the HP 28 calculator, but at arbitrary precision and unbounded stack depth. You’ll get RPN, keystroke, and algebraic modes of operation. You’ll get arrays and complex numbers.

See also Brian Kernighan interviews Ken Thompson at VCF East and Repairing HP’s 9100B desktop computer/calculator - videos

8 Likes

If you think dc is interesting, you should also check out the Forth programming language.

1 Like

Years ago, a game of code golf erupted on our local Linux mailing list after someone posted this in their .sig:

> 01001001 00100000 01100011 01100001 01101110 00100111 01110100 00100000 
> 01100010 01100101 01101100 01101001 01100101 01110110 01100101 00100000 
> 01111001 01101111 01110101 00100000 01100001 01100011 01110100 01110101 
> 01100001 01101100 01101100 01111001 00100000 01110100 01110010 01100001 
> 01101110 01110011 01101100 01100001 01110100 01100101 01100100 00100000 
> 01110100 01101000 01101001 01110011 00100001 00100000 01001100 01001111 
> 01001100

My entry, which I sat down and wasted[1] a lovely afternoon on, was:

dc -e '[rSS1+]sa[LSan1-]sb2i?10i0[z1<az1<c]sc[d0<bd0<d]sdlcxldx'

I have no idea what that does now (which explains my footnote on that post: “Now that’s job security!”)

1: “Time you enjoy wasting is not wasted time” - Lennon.

2 Likes

I thought that might be two reverse-engineering challenges, but with the help of this site I think it might only be one… but perhaps it’s zero, and I don’t quite see it yet…

1 Like

It looks like a list of bytes in base 2, nicely padded with leading zeroes, so let’s make a binary bigint out of that by removing all chars not equal to the binary digits and let DC print it as string:

tr -cd 01 <<endtr | dc -e '2i ? PAP'
... the pasted signature ...                                                                      
endtr                                                                                                 
Spoilers
$ cat dc.org 
#+begin_src sh :results output :exports both
tr -cd 01 <<endtr | dc -e '2i ? PAP'
> 01001001 00100000 01100011 01100001 01101110 00100111 01110100 00100000
> 01100010 01100101 01101100 01101001 01100101 01110110 01100101 00100000
> 01111001 01101111 01110101 00100000 01100001 01100011 01110100 01110101
> 01100001 01101100 01101100 01111001 00100000 01110100 01110010 01100001
> 01101110 01110011 01101100 01100001 01110100 01100101 01100100 00100000
> 01110100 01101000 01101001 01110011 00100001 00100000 01001100 01001111
> 01001100
endtr
#+end_src

#+RESULTS:
: I can't believe you actually translated this! LOL

It’s just someone sticking a binary version of an ASCII message into their .sig. It wasn’t meant to be a challenge (especially after the message is decoded) as such. I think all the answers but mine were Perl. I’d not really used dc before then, or since.