Syntactic sugar

We will define some additional syntax to facilitate entry of some common expressions. Recall that we already allow the user to enter

(A B C)
instead of
(A . (B . (C . NIL)))

Quoting

In order to include a literal symbol or list in an expression, we need to use the QUOTE operator. As a shortcut, we will define

'EXPR
to be equivalent to
(QUOTE EXPR)

So for example the following forms are equivalent:
Abbreviation Canonical form Evaluates to
'FOO (QUOTE FOO) FOO
'(+ 1 2) (QUOTE (+ 1 2)) (+ 1 2)
'(A . B) (QUOTE (A . B)) (A . B)

The lexer needs to know that the quote mark is a prefix (i.e., it can appear immediately before another token but is not necessarily a delimeter).

int lex(const char *str, const char **start, const char **end)
{
	const char *ws = " \t\n";
	const char *delim = "() \t\n";
	const char *prefix = "()\'";
	.
	.
	.
}

Also read_expr must convert it to the correct list expresssion.

int read_expr(const char *input, const char **end, Atom *result)
{
	const char *token;
	Error err;

	err = lex(input, &token, end);
	if (err)
		return err;

	if (token[0] == '(') {
		return read_list(*end, end, result);
	} else if (token[0] == ')') {
		return Error_Syntax;
	} else if (token[0] == '\'') {
		*result = cons(make_sym("QUOTE"), cons(nil, nil));
		return read_expr(*end, end, &car(cdr(*result)));
	} else {
		return parse_simple(token, *end, result);
	}
}

Testing

> (define x '(a b c))
X
> x
(A B C)
> 'x
X
> (define foo 'bar)
FOO
> foo
BAR
> ''()
(QUOTE NIL)

Function definitions

It is cumbersome to have to type a lambda expression every time we wish to define a function, so we will modify the DEFINE operator to avoid this.

(DEFINE (name args...) body...)
is equivalent to
(DEFINE name (LAMBDA (args...) body...))

Here's how:

int eval_expr(Atom expr, Atom env, Atom *result)
{
	.
	.
	.
	if (op.type == AtomType_Symbol) {
		if (strcmp(op.value.symbol, "QUOTE") == 0) {
		.
		.
		.
		} else if (strcmp(op.value.symbol, "DEFINE") == 0) {
			Atom sym, val;

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

			sym = car(args);
			if (sym.type == AtomType_Pair) {
				err = make_closure(env, cdr(sym), cdr(args), &val);
				sym = car(sym);
				if (sym.type != AtomType_Symbol)
					return Error_Type;
			} else if (sym.type == AtomType_Symbol) {
				if (!nilp(cdr(cdr(args))))
					return Error_Args;
				err = eval_expr(car(cdr(args)), env, &val);
			} else {
				return Error_Type;
			}

			if (err)
				return err;

			*result = sym;
			return env_set(env, sym, val);
		} else if (strcmp(op.value.symbol, "LAMBDA") == 0) {
		.
		.
		.
		}
	}
	.
	.
	.
}

Testing

> (define (square x) (* x x))
SQUARE
> (square 3)
9

Sweet!