He got an infinite loop. First, Calc did as expected and rewrote `2 + 3 x' to `f(2, 3, x)'. Then it looked for ways to apply the rule again, and found that `f(2, 3, x)' looks like `a + b x' with `a = 0' and `b = 1', so it rewrote to `f(0, 1, f(2, 3, x))'. It then wrapped another `f(0, 1, ...)' around that, and so on, ad infinitum. Joe should have used M-1 a r to make sure the rule applied only once.
(Actually, even the first step didn't work as he expected. What Calc really gives for M-1 a r in this situation is `f(3 x, 1, 2)', treating 2 as the "variable," and `3 x' as a constant being added to it. While this may seem odd, it's just as valid a solution as the "obvious" one. One way to fix this would be to add the condition `:: variable(x)' to the rule, to make sure the thing that matches `x' is indeed a variable, or to change `x' to `quote(x)' on the lefthand side, so that the rule matches the actual variable `x' rather than letting `x' stand for something else.)