Created
January 31, 2018 21:43
-
-
Save kdridi/28af890dec7cf6c85e4225258948093d to your computer and use it in GitHub Desktop.
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 <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