|
Unix Programming - Applying Minilanguages - Case Study: bc and
Case Study: bc and
dc
We first examined
bc(1)
and
dc(1)
in Chapter7 as a case
study in shellouts. They are examples of domain-specific
minilanguages of the imperative type.
|
dc is the oldest language on Unix; it
was written on the PDP-7 and ported to the PDP-11 before Unix [itself]
was ported.
|
|
| --
Ken Thompson
|
|
The domain of these two languages is unlimited-precision
arithmetic. Other programs can use them to do such calculations
without having to worry about the special techniques needed to do
those calculations.
|
In fact, the original motivation for dc had nothing to do with
providing a general-purpose interactive calculator, which could have
been done with a simple floating-point program. The motivation was
Bell Labs' long interest in numerical analysis: calculating constants
for numerical algorithms,
accurately
is greatly
aided by being able to work to much higher precision than the
algorithm itself will use. Hence dc's arbitrary-precision
arithmetic.
|
|
| --
Henry Spencer
|
|
Like SNG and Glade markup, one of the
strengths of both of these languages is their simplicity. Once you
know that
dc(1)
is a reverse-Polish-notation calculator and
bc(1)
an algebraic-notation calculator, very little about interactive use of
either of these languages is going to be novel. We'll return to the
importance of the Rule of Least Surprise in interfaces in Chapter11.
These minilanguages have both conditionals and loops; they are
Turing-complete, but have a very restricted ontology of types
including only unlimited-precision integers and strings. This puts
them in the borderland between interpreted minilanguages and full
scripting languages. The programming features have been
designed not to intrude on the common use as a calculator; indeed,
most dc/bc users
are probably unaware of them.
Normally,
dc/bc are used
conversationally, but their capacity to support libraries of
user-defined procedures gives them an additional kind of utility
— programmability. This is actually the most important advantage
of imperative minilanguages, one that we observed in the case study
of the Documenter's Workbench tools to be very powerful whether or not
a program's normal mode is conversational; you can use them to write
high-level programs that embody task-specific intelligence.
Because the interface of
dc/bc is so
simple (send a line containing an expression, get back a line
containing a value) other programs and scripts can easily get access
to all these capabilities by calling these programs as slave
processes. Example8.6 is one famous example, an implementation of the
Rivest-Shamir-Adelman public-key cipher in
Perl that
was widely published in signature blocks and on T-shirts as a protest
against U.S. export retrictions on cryptography, c. 1995; it shells
out to dc to do the unlimited-precision
arithmetic required.
Example8.6.RSA implementation using dc.
print pack"C*",split/\D+/,`echo "16iII*o\U@{$/=$z;[(pop,pop,unpack
"H*",<>)]}\EsMsKsN0[lN*1lK[d2%Sa2/d0<X+d*lMLa^*lN%0]dsXx++\
lMlN/dsM0<J]dsJxp"|dc`
[an error occurred while processing this directive]
|