1 /*******************************************************************
3 * A Lisp interpreter
, written
in Prolog
5 * (lisp_interpreter
.pl
)
9 * This program is a small interpreter
for Lisp
. It was written
10 * in LPA Prolog v3
.6
, running under Windows
. It should be fairly
11 * easy to convert it to other Prologs
.
13 * It supports real Lisp syntax
, excessive brackets
and all
. You don
't
14 * need to terminate input with a full stop. It also understands
15 * 'x
for (quote x
) and #'func for (function func)
17 * Variables are lexically scoped
, except where
defined as special
.
19 * read_words code from
"The Craft of Prolog", R
.A
.O
'Keefe
20 * lisp evaluator from "Lisp" (3rd ed), Winston & Horn.
22 *******************************************************************/
25 :- style_check([+singleton, +no_effect, +var_branches, +atom, +discontiguous,
32 % :- initialization lisp.
39 write('Welcome to Pro
-Lisp
!'),nl,
40 write('This is a miniscule Lisp interpreter
, written
in Prolog
'),nl,
42 % prompts(Old1, Old2),
43 % prompts('> ', '> '),
46 read_eval_print(Result),
49 % prompts(Old1, Old2).
56 retractall(lambda(_, _)).
59 read_eval_print(Result):- % dodgy use of cuts to force a single evaluation
60 read_and_parse(Expression),
61 eval(Expression, Result),
62 writeExpression(Result),
67 % basic EVAL statements for built-in procedures
69 eval(Expression, Result):-
71 eval(Expression, Bindings, Result).
74 macro_expand([],[]):-!.
75 macro_expand([#, '''', X|Xs], [[function, MX]|MXs]):-
78 macro_expand(Xs, MXs).
79 macro_expand(['''', X|Xs], [[quote, MX]|MXs]):-
82 macro_expand(Xs, MXs).
83 macro_expand([X|Xs], [MX|MXs]):-
86 macro_expand(Xs, MXs).
92 eval(quit, _, quit):-!.
96 eval([quote, X], _, X):-!.
97 eval([quit], _, quit):-!.
98 eval([defvar, Name], _, Name):-
100 retract(bindings(GlobalBindings)),
101 assert(bindings([binding(Name, [])|GlobalBindings])),
103 eval([setq, Name, Value], Bindings, EvalValue):-
105 bindings(GlobalBindings),
106 append(Pre, [binding(Name, _)|Post], GlobalBindings),
107 eval(Value, Bindings, EvalValue),
108 retract(bindings(GlobalBindings)),
109 append(Pre, [binding(Name, EvalValue)|Post], GlobalBindings1),
110 assert(bindings(GlobalBindings1)),
112 eval([defun, Name, FormalParms, Body], _, Name):-
114 assert(lambda(Name, [lambda, FormalParms, Body])),
116 eval([apply|Arguments], Bindings, Result):-
118 evalL(Arguments, Bindings, [Function, ActualParams]),
119 apply(Function, ActualParams, Result),
121 eval([function, [lambda, FormalParams, Body]], Bindings,
122 [closure, FormalParams, Body, Bindings]):-!.
123 eval([Procedure|Arguments], Bindings, Result):-
124 evalL(Arguments, Bindings, EvalArguments),
125 apply(Procedure, EvalArguments, Result),
130 eval(X, Bindings, Val):-
132 member(binding(X, Val), Bindings)
133 ; (bindings(GlobalBindings),
134 member(binding(X, Val), GlobalBindings)),
137 write('ERROR
! Cannot find a binding
for `'),
144 evalL([H|T], Bindings, [EvalH|EvalT]):-
145 eval(H, Bindings, EvalH),
146 evalL(T, Bindings, EvalT),
150 apply(car, [[Result|_]], Result):-!.
151 apply(cdr, [[_|Result]], Result):-!.
152 apply(list, Args, Args):-!.
153 apply(cons, [Arg1, Arg2], [Arg1|Arg2]):-!.
154 apply(eq, [Arg1, Arg2], Result):-
155 (Arg1 = Arg2 -> Result = Arg1
158 apply(if, [Test, Success, Failure], Result):-
159 eval(Test, TestResult),
160 eval(Success, EvalSuccess),
161 eval(Failure, EvalFailure),
162 (TestResult = [] -> Result = EvalFailure
163 ; Result = EvalSuccess),
165 apply([lambda, FormalParams, Body], ActualParams, Result):-
167 bind_variables(FormalParams, ActualParams, Bindings),
168 eval(Body, Bindings, Result),
170 apply([closure, FormalParams, Body, Bindings0], ActualParams, Result):-
172 bind_variables(FormalParams, ActualParams, Bindings0, Bindings),
173 eval(Body, Bindings, Result),
175 apply(ProcedureName, Args, Result):-
176 lambda(ProcedureName, LambdaExpression),
177 apply(LambdaExpression, Args, Result),
180 write('ERROR
! Cannot find a procedure description
for `'),
187 bind_variables(Formal, Actual, Bindings):-
188 bind_variables(Formal, Actual, [], Bindings).
190 bind_variables([], [], Bindings, Bindings).
191 bind_variables([FormalParam|FormalParams], [ActualParam|ActualParams],
192 Bindings0, Bindings):-
193 bind_variables(FormalParams, ActualParams,
194 [binding(FormalParam, ActualParam)|Bindings0], Bindings).
199 % read and parse a line of Lisp
201 read_and_parse(Expression):-
203 ( sexpr(Expression, TokenL, [])
205 ( write('ERROR
! Could
not parse
`'),
214 % read a line of supposed Lisp code
219 read_words(C, Words).
224 read_words(C, Words):-
228 read_words(C, [Word|Words]):-
233 read_words(C, [Word|Words]):-
236 read_rest_of_word(Chars, LeftOver),
237 name(UCWord, [C|Chars]),
238 ( atom(UCWord) -> downcase_atom(UCWord, Word)
241 read_words(LeftOver, Words).
244 read_rest_of_word(Chars, LeftOver):-
247 read_rest_of_word(C, Chars, LeftOver).
250 read_rest_of_word(C, [], C):-
253 read_rest_of_word(C, [C|Chars], LeftOver):-
256 read_rest_of_word(Chars, LeftOver).
289 \+ punctuation(Char).
292 % Grammar rules for parsing Lisp s-expressions.
293 % Given a list of tokens, lisplist does all the nesting of lists
296 sexpr([function, Expression]) --> [#, ''''], !, sexpr(Expression).
297 sexpr([quote, Expression]) --> [''''], !, sexpr(Expression).
298 sexpr(Xs) --> ['('], lisplist(Xs), !.
299 sexpr(X) --> [X], {atomic(X), X \= '.'}, !.
302 lisplist([]) --> [')'], !.
303 lisplist([X|Xs]) --> sexpr(X), lisplist(Xs), !.
304 lisplist([X|Y]) --> sexpr(X), ['.'], sexpr(Y), [')'], !.
308 % writeExpression/1 displays a lisp expression
310 writeExpression(quit):-
312 write('Terminating Pro-Lisp'),nl.
313 writeExpression(Expression):-
314 sexpr(Expression, TokenL, []),
321 writeTokenL(['(', ')'|TokenL]):-
325 writeTokenL([Token|TokenL]):-
328 % lwrupr(Token, UCToken),
330 downcase_atom(Token, LCToken),
334 writeTokenL([Token|TokenL]):-