Skip to content

Instantly share code, notes, and snippets.

@y2q-actionman
Created December 13, 2012 15:11
Show Gist options
  • Save y2q-actionman/4277012 to your computer and use it in GitHub Desktop.
Save y2q-actionman/4277012 to your computer and use it in GitHub Desktop.
Lisp advent calender 2012 sample : 実例2-1
#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