Created
December 13, 2012 15:01
-
-
Save y2q-actionman/4276951 to your computer and use it in GitHub Desktop.
Lisp advent calender 2012 sample : 実例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; | |
} | |
/////////////////////////////////////////////////////////////// | |
#include <initializer_list> | |
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; | |
} | |
int main(){ | |
{ | |
// (1 2 3) | |
Lisp_ptr lis1 = new Cons{1 , new Cons{2, new Cons{3, NIL}}}; | |
std::cout << "lis1: " << lis1 << '\n'; | |
// (1 (2 3) (4 5)) | |
Lisp_ptr lis2 = new Cons{1, | |
new Cons{new Cons{2, new Cons{3, NIL}}, | |
new Cons{new Cons{4, new Cons{5, NIL}}, | |
NIL}}}; | |
std::cout << "lis2: " << lis2 << '\n'; | |
} | |
{ | |
// (1 2 3) | |
Lisp_ptr lis1 = make_cons_list({1, 2, 3}); | |
std::cout << "lis1: " << lis1 << '\n'; | |
// (1 (2 3) (4 5)) | |
Lisp_ptr lis2 = make_cons_list({1, | |
make_cons_list({2, 3}), | |
make_cons_list({4, 5})}); | |
std::cout << "lis2: " << lis2 << '\n'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment