Created
December 13, 2012 15:11
-
-
Save y2q-actionman/4277012 to your computer and use it in GitHub Desktop.
Lisp advent calender 2012 sample : 実例2-1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cassert> | |
#include <cstring> | |
class Cons; | |
enum class Tag { int_, cons, string }; | |
class Lisp_ptr { | |
public: | |
Lisp_ptr(int i) : tag_(Tag::int_), u_(i){} | |
Lisp_ptr(Cons* c) : tag_(Tag::cons), u_(static_cast<void*>(c)){} | |
Lisp_ptr(const char* s) : tag_(Tag::string), u_(static_cast<const void*>(s)){} | |
Tag tag() const { return tag_; } | |
template<typename T> | |
T get() const; | |
private: | |
Tag tag_; | |
union U { | |
U(void* p) : ptr_(p){} | |
U(const void* p) : cptr_(p){} | |
U(int i) : int_(i){} | |
void* ptr_; | |
const void* cptr_; | |
int int_; | |
} u_; | |
}; | |
template<> | |
int Lisp_ptr::get<int>() const { | |
assert(tag_ == Tag::int_); | |
return u_.int_; | |
} | |
template<> | |
Cons* Lisp_ptr::get<Cons*>() const { | |
assert(tag_ == Tag::cons); | |
return static_cast<Cons*>(u_.ptr_); | |
} | |
template<> | |
const char* Lisp_ptr::get<const char*>() const{ | |
assert(tag_ == Tag::string); | |
return static_cast<const char*>(u_.cptr_); | |
} | |
bool operator==(Lisp_ptr a, Lisp_ptr b){ | |
if(a.tag() != b.tag()) return false; | |
switch(a.tag()){ | |
case Tag::int_: return (a.get<int>() == b.get<int>()); | |
case Tag::cons: return (a.get<Cons*>() == b.get<Cons*>()); | |
case Tag::string: return (strcmp(a.get<const char*>(), b.get<const char*>()) == 0); | |
default: return false; | |
} | |
} | |
bool operator!=(const Lisp_ptr& a, const Lisp_ptr& b){ | |
return !(a == b); | |
} | |
struct Cons { | |
Lisp_ptr car; | |
Lisp_ptr cdr; | |
Cons(Lisp_ptr a, Lisp_ptr d) : car(a), cdr(d){}; | |
}; | |
constexpr auto NIL = static_cast<Cons*>(nullptr); | |
std::ostream& operator<<(std::ostream& o, Lisp_ptr p){ | |
switch(p.tag()){ | |
case Tag::int_: | |
o << p.get<int>(); | |
break; | |
case Tag::cons: | |
o << '('; | |
for(auto i = p; i.tag() == Tag::cons && i.get<Cons*>(); i = i.get<Cons*>()->cdr){ | |
o << i.get<Cons*>()->car << ' '; | |
} | |
o << "\b)"; | |
break; | |
case Tag::string: | |
o << p.get<const char*>(); | |
break; | |
} | |
return o; | |
} | |
/////////////////////////////////////////////////////////////// | |
Lisp_ptr make_cons_list(std::initializer_list<Lisp_ptr> ilist){ | |
Lisp_ptr head = NIL; | |
Lisp_ptr* next = &head; | |
for(auto p : ilist){ | |
auto c = new Cons{p, NIL}; | |
*next = c; | |
next = &(c->cdr); | |
} | |
return head; | |
} | |
/////////////////////////////////////////////////////////////// | |
template<typename Fun> | |
void do_list(Lisp_ptr lis, Fun fun){ | |
for(auto i = lis; i.tag() == Tag::cons && i.get<Cons*>(); i = i.get<Cons*>()->cdr){ | |
fun(i.get<Cons*>()->car); // ここで受け取った関数を呼ぶ | |
} | |
} | |
void printer(Lisp_ptr p){ | |
std::cout << p << std::endl; | |
} | |
int main(){ | |
Lisp_ptr lis1 = make_cons_list({1, 2, 3}); | |
do_list(lis1, printer); | |
do_list(lis1, | |
[](Lisp_ptr p) -> void { | |
std::cout << p << std::endl; | |
}); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment