## Êíèãà: Learning GNU Emacs, 3rd Edition

## 11.5.3 The Calculator Mode

11.5.3 The Calculator Mode

The complete Lisp code for the calculator mode appears at the end of this section; you should refer to it while reading the following explanation. If you download or type the code in, you can use the calculator by typing **M-x calc-mode Enter**. You will be put in the buffer `*Calc*`

. You can type a line of numbers and operators and then type **C-j** to evaluate the line. Table 11-7 lists the three commands in calculator mode.

**Table 11-7. Calculator mode commands**

Command | Action |
---|---|

`=` |
Print the value at the top of the stack. |

p | Print the entire stack contents. |

`c` |
Clear the stack. |

Blank spaces are not necessary, except to separate numbers. For example, typing this:

`4 17*6-=`

followed by **C-j**, evaluates (4 * 17) - 6 and causes the result, 62, to be printed.

The heart of the code for the calculator mode is the functions **calc-eval** and **calc-next-token**. (See the code at the end of this section for these.) **calc-eval** is bound to **C-j** in Calculator mode. Starting at the beginning of the line preceding **C-j**, it calls **calc-next-token** to grab each *token* (number, operator, or command letter) in the line and evaluate it.

**calc-next-token** uses a **cond** construct to see if there is a number, operator, or command letter at point by using the regular expressions **calc-number-regexp**, **calc-operator-regexp**, and **calc-command-regexp**. According to which regular expression was matched, it sets the variable **calc-proc-fun** to the name (symbol) of the function that should be run (either **calc-push-number**, **calc-operate**, or **calc-command**), and it sets `tok`

to the result of the regular expression match.

In **calc-eval**, we see where the idea of a function as a list comes in. The **funcall** function reflects the fact that there is little difference between code and data in Lisp. We can put together a list consisting of a symbol and a bunch of expressions and evaluate it as a function, using the symbol as the function name and the expressions as arguments; this is what **funcall** does. In this case, the following:

`(funcall calc-proc-fun tok)`

treats the symbol value of **calc-proc-fun** as the name of the function to be called and calls it with the argument `tok`

. Then the function does one of three things:

• If the token is a number, **calc-push-number** pushes the number onto the stack.

• If the token is an operator, **calc-operate** performs the operation on the top two numbers on the stack (see below).

• If the token is a command, **calc-command** performs the appropriate command.

The function **calc-operate** takes the idea of functions as lists of data a step further by converting the token from the user directly into a function (an arithmetic operator). This step is accomplished by the function **read**, which takes a character string and converts it into a symbol. Thus, **calc-operate** uses **funcall** and **read** in combination as follows:

`(defun calc-operate (tok)`

(let ((op1 (calc-pop))

(op2 (calc-pop)))

(calc-push (funcall (read tok) op2 op1))))

This function takes the name of an arithmetic operator (as a string) as its argument. As we saw earlier, the string `tok`

is a token extracted from the `*Calc*`

buffer, in this case, an arithmetic operator such as `+`

or `*`

. The **calc-operate** function pops the top two arguments off the stack by using the **pop** function, which is similar to the use of `cdr`

earlier. **read** converts the token to a symbol, and thus to the name of an arithmetic function. So, if the operator is `+`

, then **funcall** is called as here:

`(funcall '+ op2 op1)`

Thus, the function **+** is called with the two arguments, which is exactly equivalent to simply **(+ op2 op1)**. Finally, the result of the function is pushed back onto the stack.

All this voodoo is necessary so that, for example, the user can type a plus sign and Lisp automatically converts it into a plus function. We could have done the same thing less elegantly—and less efficiently—by writing **calc-operate** with a **cond** construct (as in **calc-next-token**), which would look like this:

`(defun calc-operate (tok)`

(let ((op1 (calc-pop))

(op2 (calc-pop)))

(cond ((equal tok "+")

(+ op2 op1))

((equal tok "-")

(- op2 op1))

((equal tok "*")

(* op2 op1))

((equal tok "/")

(/ op2 op1))

(t

(% op2 op1)))))

The final thing to notice in the calculator mode code is the function **calc-mode**, which starts the mode. It creates (and pops to) the `*Calc*`

buffer. Then it kills all existing local variables in the buffer, initializes the stack to `nil`

(empty), and creates the local variable **calc-proc-fun** (see the earlier discussion). Finally it sets Calculator mode as the major mode, sets the mode name, and activates the local keymap.

- 11.5 Programming a Major Mode
- 11.5.1 Components of a Major Mode
- 11.5.4 Lisp Code for the Calculator Mode
- 4.4.4 The Dispatcher
- About the author
- Chapter 7. The state machine
- Appendix E. Other resources and links
- Example NAT machine in theory
- The final stage of our NAT machine
- Compiling the user-land applications
- The conntrack entries
- Untracked connections and the raw table