Skip to content

Instantly share code, notes, and snippets.

@kdridi
Created January 31, 2018 21:43
Show Gist options
  • Save kdridi/28af890dec7cf6c85e4225258948093d to your computer and use it in GitHub Desktop.
Save kdridi/28af890dec7cf6c85e4225258948093d to your computer and use it in GitHub Desktop.
#include <criterion/criterion.h>
#include <tuple>
#include <stack>
#include <string>
#include <sstream>
#include <functional>
typedef enum e_tree
{
token_type,
token_name,
token_gate,
token_number,
token_link,
token_chipset,
} token;
struct tree
{
tree(token t, std::string n) : tree(t, n, nullptr, nullptr) {}
tree(token t, std::string n, tree* l, tree* r) : t(t), n(n), l(l), r(r) {}
token t;
std::string n;
tree* l;
tree* r;
void visit(std::function<void(std::size_t, token, std::string)> visitor)
{
visit(0, visitor);
}
private:
void visit(std::size_t depth, std::function<void(std::size_t, token, std::string)> visitor)
{
visitor(depth, t, n);
if (l != nullptr) l->visit(depth + 1, visitor);
if (r != nullptr) r->visit(depth + 1, visitor);
}
};
struct tree_stack : std::stack<tree*>
{
bool push_token(token t, std::string n)
{
push(new tree(t, n));
return true;
}
bool pull_infix()
{
if (size() < 3)
return false;
tree* r = top(); pop();
tree* m = top(); pop();
tree* l = top(); pop();
push(new tree(m->t, m->n, l, r));
delete m;
return true;
}
bool pull(token t, std::string n)
{
if (size() < 2)
return false;
tree* r = top(); pop();
tree* l = top(); pop();
push(new tree(t, n, l, r));
return true;
}
};
typedef std::tuple<std::string, std::stringstream*, tree_stack> request;
typedef std::pair<bool, request> response;
template<class p>
struct p_satisfy
{
response operator()(request req)
{
p predicate;
if (std::get<0>(req).empty() == true)
return std::make_pair(false, req);
if (predicate(std::get<0>(req).at(0)) == false)
return std::make_pair(false, req);
if (std::get<1>(req) != nullptr)
*(std::get<1>(req)) << std::get<0>(req).at(0);
return std::make_pair(true, std::make_tuple(std::get<0>(req).substr(1), std::get<1>(req), std::get<2>(req)));
}
};
template<class p1, class p2>
struct p_or
{
response operator()(request req)
{
p1 parse1;
response res1 = parse1(req);
if (res1.first == true)
return res1;
p2 parse2;
response res2 = parse2(req);
return res2;
}
};
template<class p1, class p2>
struct p_chain
{
response operator()(request req)
{
p1 parse1;
response res1 = parse1(req);
if (res1.first == false)
return std::make_pair(false, req);
p2 parse2;
response res2 = parse2(res1.second);
if (res2.first == false)
return std::make_pair(false, req);
return res2;
}
};
template<class p>
struct p_many
{
response operator()(request req)
{
p parse;
while (true)
{
response res = parse(req);
if (res.first == false)
break;
req = res.second;
}
return std::make_pair(true, req);
}
};
template<class p, token t>
struct p_push_token
{
response operator()(request req)
{
p parse;
std::stringstream* ss0 = std::get<1>(req);
std::stringstream* ss1 = new std::stringstream;
response res = parse(std::make_tuple(std::get<0>(req), ss1, std::get<2>(req)));
tree_stack stack = std::get<2>(res.second);
if (res.first == true)
{
// std::cout << "[" << ss1->str() << "]" << std::endl;
stack.push_token(t, ss1->str());
}
delete ss1;
return std::make_pair(res.first, std::make_tuple(std::get<0>(res.second), ss0, stack));
}
};
struct p_pull_infix
{
response operator()(request req)
{
tree_stack stack = std::get<2>(req);
if (stack.pull_infix())
return std::make_pair(true, std::make_tuple(std::get<0>(req), std::get<1>(req), stack));
else
return std::make_pair(true, std::make_tuple(std::get<0>(req), std::get<1>(req), std::get<2>(req)));
}
};
struct p_pull
{
p_pull(token t, std::string n) : t(t), n(n) {}
response operator()(request req)
{
tree_stack stack = std::get<2>(req);
if (stack.pull(t, n))
return std::make_pair(true, std::make_tuple(std::get<0>(req), std::get<1>(req), stack));
else
return std::make_pair(true, std::make_tuple(std::get<0>(req), std::get<1>(req), std::get<2>(req)));
}
token t;
std::string n;
};
struct p_pull_link : public p_pull { p_pull_link() : p_pull(token_link , "link" ) {} };
struct p_pull_chipset : public p_pull { p_pull_chipset() : p_pull(token_chipset, "chipset") {} };
struct p_pull_gate : public p_pull { p_pull_gate() : p_pull(token_gate , "gate" ) {} };
// =============================================================================
// UTILS
// =============================================================================
template <class...>
struct p_then;
template <class head>
struct p_then<head> : public head {};
template <class head, class...tail>
struct p_then<head, tail...> : public p_chain<p_then<head>, p_then<tail...>> {};
template<char c>
struct is_same
{ bool operator()(char ch) { return ch == c; } };
template<char c>
struct is_not_same
{ bool operator()(char ch) { return ch != c; } };
template<bool v>
struct is_always
{ bool operator()(char ch) { return v; } };
struct is_alpha
{ bool operator()(char ch) { return ((('a' <= ch) && (ch <= 'z')) || (('A' <= ch) && (ch <= 'Z'))); } };
struct is_digit
{ bool operator()(char ch) { return (('0' <= ch) && (ch <= '9')); } };
// =============================================================================
// COMBINATOR
// =============================================================================
struct p_any
: p_satisfy<is_always<true>> {};
template<char...chars>
struct p_char;
template<char head>
struct p_char<head>
: public p_satisfy<is_same<head>> {};
template<char head, char... tail>
struct p_char<head, tail...>
: public p_or<p_char<head>, p_char<tail...>> {};
template<char...chars>
struct p_string;
template<char head>
struct p_string<head>
: public p_char<head> {};
template<char head, char... tail>
struct p_string<head, tail...>
: public p_then<p_string<head>, p_string<tail...>> {};
template<char...chars>
struct p_not;
template<char head>
struct p_not<head>
: public p_satisfy<is_not_same<head>> {};
template<char head, char... tail>
struct p_not<head, tail...>
: public p_or<p_not<head>, p_not<tail...>> {};
template <class...p>
struct p_choice;
template <class head>
struct p_choice<head>
: public head {};
template <class head, class... tail>
struct p_choice<head, tail...>
: public p_or<p_choice<head>, p_choice<tail...>> {};
template <class...>
struct p_sep_by;
template <class p, class s>
struct p_sep_by<p, s>
: public p_then<p, p_many<p_then<s, p>>> {};
template <class p, class s, class f>
struct p_sep_by<p, s, f>
: public p_then<p, p_many<p_then<p_then<s, p>, f>>> {};
struct p_digit
: public p_satisfy<is_digit> {};
struct p_alpha
: public p_satisfy<is_alpha> {};
struct p_alpha_num
: public p_choice<p_digit, p_alpha> {};
template<class p>
struct p_many1
: public p_then<p, p_many<p>> {};
struct p_number
: public p_many1<p_digit> {};
struct p_spaces
: public p_many<p_char<' ', '\t', '\n', '\r'>> {};
template<class l, class m, class r>
struct p_between
: public p_then<l, p_then<m, r>> {};
template<class p>
struct p_token
: public p_between<p_spaces, p, p_spaces> {};
struct p_id
: p_then<p_alpha_num, p_many<p_alpha_num>> {};
// =============================================================================
// ARITHMETIC
// =============================================================================
struct p_space
: p_char<' ', '\t'> {};
struct p_comment
: public p_then<p_char<'#'>, p_many<p_not<'\n'>>> {};
struct p_line_separator
: public p_many1<p_then<p_many<p_choice<p_space, p_comment>>, p_char<'\n'>>> {};
template<class p>
struct p_header
: public p_between<p_char<'.'>, p, p_char<':'>> {};
template<class k, class v, class p>
struct p_key_value
: public p_then<p_many<p_space>, k, p_many1<p_space>, v, p> {};
template<token t>
struct p_chipsets_key
: public p_push_token<p_id, t> {};
struct p_chipsets_line
: public p_key_value<p_chipsets_key<token_type>, p_chipsets_key<token_name>, p_pull_chipset> {};
struct p_chipsets_lines
: public p_sep_by<p_chipsets_line, p_line_separator> {};
struct p_chipsets_header
: public p_header<p_string<'c', 'h', 'i', 'p', 's', 'e', 't', 's'>> {};
struct p_links_key
: public p_then
< p_many<p_space>
, p_push_token<p_id, token_name>
, p_many<p_space>
, p_char<':'>
, p_many<p_space>
, p_push_token<p_number, token_number>
, p_pull_gate
> {};
struct p_links_line
: public p_key_value<p_links_key, p_links_key, p_pull_link> {};
struct p_links_lines
: public p_sep_by<p_links_line, p_line_separator> {};
struct p_links_header
: public p_header<p_string<'l', 'i', 'n', 'k', 's'>> {};
struct p_configuration
: public p_then
< p_many<p_line_separator>
, p_chipsets_header, p_line_separator
, p_chipsets_lines, p_line_separator
, p_links_header, p_line_separator
, p_links_lines
, p_many<p_line_separator>
> {};
#include <string>
#include <fstream>
#include <streambuf>
#include <iostream>
/*/
#three inputs and gate
.chipsets:
input i0
input i1
input i2
4081 and0
output out
.links:
i0 : 1 and0:1
i1:1 and0:2
and0:3 and0:5
i2:1 and0:6
and0:4 out:1
/*/
int main(int argc, char const *argv[])
{
for (int index = 1; index < argc; ++index)
{
p_configuration parse;
std::ifstream t(argv[index]);
std::string str((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
response res = parse(std::make_tuple(str, nullptr, tree_stack{}));
std::cout << "success: " << res.first << std::endl;
std::cout << "remains: ~~~" << std::get<0>(res.second) << "~~~" << std::endl;
tree_stack stack = std::get<2>(res.second);
while (stack.empty() == false)
{
tree& t = *(stack.top()); stack.pop();
t.visit([](std::size_t depth, token t, std::string n) {
std::stringstream ss;
for (std::size_t index = 0; index < depth; ++index) ss << " ";
ss.str();
switch (t) {
default:
std::cout << ss.str() << "t: " << t << " n: [" << n << "]" << std::endl;
break;
}
});
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment