5 #include <boost/variant.hpp>
6 #include <boost/function.hpp>
7 #include <boost/shared_ptr.hpp>
8 #include <boost/unordered_map.hpp>
9 #include <boost/algorithm/string.hpp>
14 std::string
name(boost::shared_ptr
<lisp::object
> token
) {
15 return boost::get
<lisp::atom
>(*token
).name
;
18 boost::shared_ptr
<lisp::object
>& car(boost::shared_ptr
<lisp::object
> x
) {
20 return boost::get
<lisp::cons
>(*(boost::static_pointer_cast
<lisp::base_object
, lisp::object
>(x
))).car
;
23 boost::shared_ptr
<lisp::object
>& cdr(boost::shared_ptr
<lisp::object
> x
) {
24 return boost::get
<lisp::cons
>(*(boost::static_pointer_cast
<lisp::base_object
, lisp::object
>(x
))).cdr
;
27 boost::shared_ptr
<lisp::object
> make_cons(boost::shared_ptr
<lisp::object
> car
,
28 boost::shared_ptr
<lisp::object
> cdr
) {
29 return boost::shared_ptr
<lisp::object
>(new lisp::object(lisp::cons(car
, cdr
)));
32 boost::shared_ptr
<lisp::object
> make_lambda(boost::shared_ptr
<lisp::object
> args
,
33 boost::shared_ptr
<lisp::object
> sexp
) {
34 return boost::shared_ptr
<lisp::object
>(new lisp::object(lisp::lambda(args
, sexp
)));
37 void append(boost::shared_ptr
<lisp::object
> list
, boost::shared_ptr
<lisp::object
> obj
) {
38 boost::shared_ptr
<lisp::object
> ptr
;
40 while (cdr(ptr
) != NULL
) {
43 cdr(ptr
) = boost::shared_ptr
<lisp::object
>(make_cons(obj
, boost::shared_ptr
<lisp::object
>()));
46 boost::shared_ptr
<lisp::object
> fn_car(boost::shared_ptr
<lisp::object
> args
,
47 boost::shared_ptr
<lisp::object
> env
) {
48 return car(car(args
));
51 boost::shared_ptr
<lisp::object
> fn_cdr(boost::shared_ptr
<lisp::object
> args
,
52 boost::shared_ptr
<lisp::object
> env
) {
53 return cdr(car(args
));
56 boost::shared_ptr
<lisp::object
> fn_quote(boost::shared_ptr
<lisp::object
> args
,
57 boost::shared_ptr
<lisp::object
> env
) {
61 boost::shared_ptr
<lisp::object
> fn_cons(boost::shared_ptr
<lisp::object
> args
,
62 boost::shared_ptr
<lisp::object
> env
) {
64 boost::shared_ptr
<lisp::object
> list
= make_cons(car(args
), boost::shared_ptr
<lisp::object
>());
65 args
= car(cdr(args
));
67 while ((args
!= NULL
) && (args
->which() == lisp::e_CONS
)) {
68 append(list
, car(args
));
74 boost::shared_ptr
<lisp::object
> tee
;
75 boost::shared_ptr
<lisp::object
> nil
;
77 boost::shared_ptr
<lisp::object
> fn_equal(boost::shared_ptr
<lisp::object
> args
,
78 boost::shared_ptr
<lisp::object
> env
) {
79 boost::shared_ptr
<lisp::object
> first
= car(args
);
80 boost::shared_ptr
<lisp::object
> second
= car(cdr(args
));
81 if (name(first
) == name(second
))
87 boost::shared_ptr
<lisp::object
> fn_atom(boost::shared_ptr
<lisp::object
> args
, boost::shared_ptr
<lisp::object
> env
) {
88 if(car(args
)->which() == lisp::e_ATOM
)
94 boost::shared_ptr
<lisp::object
> eval(boost::shared_ptr
<lisp::object
> args
,
95 boost::shared_ptr
<lisp::object
> env
);
97 boost::shared_ptr
<lisp::object
> fn_cond(boost::shared_ptr
<lisp::object
> args
,
98 boost::shared_ptr
<lisp::object
> env
) {
99 while ((args
!= NULL
) && (args
->which() == lisp::e_CONS
)) {
100 boost::shared_ptr
<lisp::object
> list
= car(args
);
101 boost::shared_ptr
<lisp::object
> pred
= eval(car(list
), env
);
102 boost::shared_ptr
<lisp::object
> ret
= car(cdr(list
));
105 return eval(ret
,env
);
113 boost::shared_ptr
<lisp::object
> interleave (boost::shared_ptr
<lisp::object
> c1
,
114 boost::shared_ptr
<lisp::object
> c2
) {
116 boost::shared_ptr
<lisp::object
> nul
;
117 boost::shared_ptr
<lisp::object
> list
= make_cons(make_cons(car(c1
),make_cons(car(c2
),nul
)),nul
);
121 while ((c1
!= NULL
) && (c1
->which() == lisp::e_CONS
)) {
122 append(list
,make_cons(car(c1
),make_cons(car(c2
), nul
)));
130 boost::shared_ptr
<lisp::object
> replace_atom(boost::shared_ptr
<lisp::object
> sexp
,
131 boost::shared_ptr
<lisp::object
> with
) {
133 boost::shared_ptr
<lisp::object
> nul
;
135 if(sexp
->which() == lisp::e_CONS
) {
137 boost::shared_ptr
<lisp::object
> list
= make_cons(replace_atom(car(sexp
), with
), nul
);
140 while ((sexp
!= NULL
) && (sexp
->which() ==lisp:: e_CONS
)) {
141 append(list
,replace_atom(car(sexp
), with
));
148 boost::shared_ptr
<lisp::object
> tmp
= with
;
150 while ((tmp
!= NULL
) && (tmp
->which() == lisp::e_CONS
)) {
151 boost::shared_ptr
<lisp::object
> item
= car(tmp
);
152 boost::shared_ptr
<lisp::object
> atom
= car(item
);
153 boost::shared_ptr
<lisp::object
> replacement
= car(cdr(item
));
155 if (name(atom
) == name(sexp
))
165 boost::shared_ptr
<lisp::object
> fn_lambda (boost::shared_ptr
<lisp::object
>args
,
166 boost::shared_ptr
<lisp::object
>env
) {
167 boost::shared_ptr
<lisp::object
> lambda
= car(args
);
170 lisp::lambda
& lambda_object(boost::get
<lisp::lambda
>(*(boost::static_pointer_cast
<lisp::base_object
, lisp::object
>(lambda
))));
172 boost::shared_ptr
<lisp::object
> list
= interleave(lambda_object
.args
, args
);
173 boost::shared_ptr
<lisp::object
> sexp
= replace_atom(lambda_object
.sexp
,list
);
174 return eval(sexp
,env
);
177 boost::shared_ptr
<lisp::object
> fn_label (boost::shared_ptr
<lisp::object
> args
,
178 boost::shared_ptr
<lisp::object
> env
) {
179 boost::shared_ptr
<lisp::object
> nul
;
181 std::string
n(name(car(args
)));
182 boost::shared_ptr
<lisp::object
> a(new lisp::object(n
));
183 append(env
, make_cons(a
,
184 make_cons(car(cdr(args
)),
189 boost::shared_ptr
<lisp::object
> lookup(const std::string
& n
,
190 boost::shared_ptr
<lisp::object
> env
) {
191 boost::shared_ptr
<lisp::object
> nul
;
192 boost::shared_ptr
<lisp::object
>tmp
= env
;
194 while ((tmp
!= nul
) && (tmp
->which()) == lisp::e_CONS
) {
195 boost::shared_ptr
<lisp::object
> item
= car(tmp
);
196 boost::shared_ptr
<lisp::object
> nm
= car(item
);
197 boost::shared_ptr
<lisp::object
> val
= car(cdr(item
));
206 // I.O. I.O. It's off to port we go..
208 void print(std::ostream
& out
, boost::shared_ptr
<lisp::object
> sexp
) {
212 if(sexp
->which() == lisp::e_CONS
) {
214 print(out
, car(sexp
));
216 while ((sexp
!= NULL
) && (sexp
->which() == lisp::e_CONS
)) {
218 print(out
, car(sexp
));
222 } else if (sexp
->which() == lisp::e_ATOM
) {
224 } else if (sexp
->which() == lisp::e_LAMBDA
) {
226 out
<< (boost::get
<lisp::lambda
>(*sexp
)).args
;
227 out
<< (boost::get
<lisp::lambda
>(*sexp
)).sexp
;
233 boost::shared_ptr
<lisp::object
> next_token(std::istream
& in
) {
239 } while (isspace(c
));
240 // process first char
242 // if it is a paren, look no further
243 if ((c
== ')') || ( c
== '(')) {
246 // otherwise collect an atom
250 } while ((!isspace(c
)) && (c
!= ')'));
253 return boost::shared_ptr
<lisp::object
>(new lisp::object(tok
));
256 boost::shared_ptr
<lisp::object
> read_tail(std::istream
& in
) {
257 boost::shared_ptr
<lisp::object
> token(next_token(in
));
258 if (name(token
) == ")")
259 return boost::shared_ptr
<lisp::object
>();
260 else if (name(token
) == "(") {
261 boost::shared_ptr
<lisp::object
> car
= read_tail(in
);
262 boost::shared_ptr
<lisp::object
> cdr
= read_tail(in
);
263 return make_cons(car
, cdr
);
265 boost::shared_ptr
<lisp::object
> car
= token
;
266 boost::shared_ptr
<lisp::object
> cdr
= read_tail(in
);
267 return make_cons(car
, cdr
);
271 /* read gets the next token from the file, if it is a left parentheses
272 * it calls read_tail to parse the rest of the list, otherwise returns
273 * the token read. A list (LIST e1 ... en) is defined for each n to be
274 * (CONS e1 (CONS ... (CONS en NIL))) so read_tail will keep calling
275 * itself concatenating cons cells until it hits a right
278 boost::shared_ptr
<lisp::object
> read(std::istream
& in
) {
279 boost::shared_ptr
<lisp::object
> token
= next_token(in
);
280 if (name(token
) == "(")
281 return read_tail(in
);
287 boost::shared_ptr
<lisp::object
> init_env() {
289 boost::shared_ptr
<lisp::object
> nul
;
291 boost::shared_ptr
<lisp::object
> a_quote(new lisp::object(std::string("QUOTE")));
292 boost::shared_ptr
<lisp::object
> f_quote(new lisp::object(lisp::func(fn_quote
)));
294 boost::shared_ptr
<lisp::object
> a_car(new lisp::object(std::string("CAR")));
295 boost::shared_ptr
<lisp::object
> f_car(new lisp::object(lisp::func(fn_car
)));
297 boost::shared_ptr
<lisp::object
> a_cdr(new lisp::object(std::string("CDR")));
298 boost::shared_ptr
<lisp::object
> f_cdr(new lisp::object(lisp::func(fn_cdr
)));
300 boost::shared_ptr
<lisp::object
> a_cons(new lisp::object(std::string("CONS")));
301 boost::shared_ptr
<lisp::object
> f_cons(new lisp::object(lisp::func(fn_cons
)));
303 boost::shared_ptr
<lisp::object
> a_equal(new lisp::object(std::string("EQUAL")));
304 boost::shared_ptr
<lisp::object
> f_equal(new lisp::object(lisp::func(fn_equal
)));
306 boost::shared_ptr
<lisp::object
> a_atom(new lisp::object(std::string("ATOM")));
307 boost::shared_ptr
<lisp::object
> f_atom(new lisp::object(lisp::func(fn_atom
)));
309 boost::shared_ptr
<lisp::object
> a_cond(new lisp::object(std::string("COND")));
310 boost::shared_ptr
<lisp::object
> f_cond(new lisp::object(lisp::func(fn_cond
)));
312 boost::shared_ptr
<lisp::object
> a_lambda(new lisp::object(std::string("LAMBDA")));
313 boost::shared_ptr
<lisp::object
> f_lambda(new lisp::object(lisp::func(fn_lambda
)));
315 boost::shared_ptr
<lisp::object
> a_label(new lisp::object(std::string("LABEL")));
316 boost::shared_ptr
<lisp::object
> f_label(new lisp::object(lisp::func(fn_label
)));
319 boost::shared_ptr
<lisp::object
> env
= make_cons(make_cons(a_quote
,make_cons(f_quote
,nul
)),nul
);
322 append(env
,make_cons(a_car
, make_cons(f_car
,nul
)));
323 append(env
,make_cons(a_cdr
, make_cons(f_cdr
,nul
)));
324 append(env
,make_cons(a_cons
, make_cons(f_cons
,nul
)));
325 append(env
,make_cons(a_equal
, make_cons(f_equal
,nul
)));
326 append(env
,make_cons(a_atom
, make_cons(f_atom
,nul
)));
327 append(env
,make_cons(a_cond
, make_cons(f_cond
,nul
)));
328 append(env
,make_cons(a_lambda
, make_cons(f_lambda
,nul
)));
329 append(env
,make_cons(a_label
, make_cons(f_label
,nul
)));
331 boost::shared_ptr
<lisp::object
> a_tee(new lisp::object(std::string("#T")));
333 nil
= make_cons(nul
,nul
);
339 boost::shared_ptr
<lisp::object
> eval_fn (boost::shared_ptr
<lisp::object
> sexp
, boost::shared_ptr
<lisp::object
> env
) {
340 boost::shared_ptr
<lisp::object
> symbol
= car(sexp
);
341 boost::shared_ptr
<lisp::object
> args
= cdr(sexp
);
343 if (symbol
->which() == lisp::e_LAMBDA
)
344 return fn_lambda(sexp
,env
);
345 else if(symbol
->which() == lisp::e_FUNC
)
346 return ((boost::get
<lisp::func
>(*symbol
)).fn
)(args
, env
);
351 boost::shared_ptr
<lisp::object
> eval(boost::shared_ptr
<lisp::object
> sexp
, boost::shared_ptr
<lisp::object
> env
) {
353 boost::shared_ptr
<lisp::object
> nul
;
358 if (sexp
->which() == lisp::e_CONS
) {
359 if ((car(sexp
)->which() == lisp::e_ATOM
) && (name(car(sexp
)) == "LAMBDA")) {
360 boost::shared_ptr
<lisp::object
> largs
= car(cdr(sexp
));
361 boost::shared_ptr
<lisp::object
> lsexp
= car(cdr(cdr(sexp
)));
362 return make_lambda(largs
,lsexp
);
364 boost::shared_ptr
<lisp::object
> accum
= make_cons(eval(car(sexp
),env
), nul
);
367 while ((sexp
!= NULL
) && (sexp
->which() == lisp::e_CONS
)) {
368 append(accum
,eval(car(sexp
),env
));
371 return eval_fn(accum
,env
);
374 boost::shared_ptr
<lisp::object
> val
= lookup(name(sexp
),env
);
386 int main(int argc
, char *argv
[]) {
387 boost::shared_ptr
<lisp::object
> env
= init_env();
388 //std::istream& in(std::cin);
390 std::ostream
& out(std::cout
);
391 inf
.open(argv
[1], std::ifstream::in
);
396 print(out
, eval(read(inf
), env
));
398 } while (inf
.good());