Arithmetic

So far all we've been able to do is create and name objects. Some of those objects have been numbers — naturally we would like to do calculations with those numbers.

In the last chapter we saw how to create built-in functions to tell eval_expr how to process arguments into a return value. We will now create four more builtins to perform the basic arithmetic operations.

ExpressionResult
(+ X Y) The sum of X and Y
(- X Y) The difference of X and Y
(* X Y) The product of X and Y
(/ X Y) The quotient of X and Y

In the definitions above, when we write "the sum of X and Y", what we really mean is "the sum of the values obtained by evaluating X and Y". Remember that eval_expr will evaluate all the arguments to a functions by default; this is usually what we want to happen, so from now on we will not explicitly state this where the intent is obvious.

Implementation

Once again almost all of our function consists of checking that the correct arguments were supplied. Finally the result is constructed by the call to make_int.

int builtin_add(Atom args, Atom *result)
{
	Atom a, b;

	if (nilp(args) || nilp(cdr(args)) || !nilp(cdr(cdr(args))))
		return Error_Args;

	a = car(args);
	b = car(cdr(args));

	if (a.type != AtomType_Integer || b.type != AtomType_Integer)
		return Error_Type;

	*result = make_int(a.value.integer + b.value.integer);

	return Error_OK;
}

The other three functions differ by only one character, so I will omit them here.

Finally we need to create bindings for our new functions in the initial environment:

env_set(env, make_sym("+"), make_builtin(builtin_add));
env_set(env, make_sym("-"), make_builtin(builtin_subtract));
env_set(env, make_sym("*"), make_builtin(builtin_multiply));
env_set(env, make_sym("/"), make_builtin(builtin_divide));

Testing

We now have our very own LISP-style calculator.

> (+ 1 1)
2
> (define x (* 6 9))
X
> x
54
> (- x 12)
42

In the last expression above, note that X is a symbol, not an integer. We have to evaluate the arguments so that builtin_subtract can operate on the integer value bound to X and not the symbol X itself. Similarly the value bound to X is the integer result of evaluating the expression (* 6 9).