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.
Expression | Result |
---|---|
(+ 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.
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));
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)
.