Created
December 13, 2012 14:52
-
-
Save y2q-actionman/4276865 to your computer and use it in GitHub Desktop.
Lisp advent calder 2012 sample : 準備
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; | |
} | |
int main(){ | |
// (1) というリストの表現 | |
Lisp_ptr list1 = new Cons{1, NIL}; | |
// 頭に 2 を入れて (2 1) | |
Lisp_ptr list2 = new Cons{2, list1}; | |
// 頭に 3 を入れて (3 2 1) | |
Lisp_ptr list3 = new Cons{3, list2}; | |
// めくってみる | |
for(auto p = list3; | |
p.tag() == Tag::cons && p.get<Cons*>(); | |
p = p.get<Cons*>()->cdr){ | |
std::cout << p.get<Cons*>()->car.get<int>() << std::endl; | |
} | |
// 3 2 1 が順に一行ずつ出力される | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment