Created
May 2, 2018 12:27
-
-
Save megamen32/4e28592bbcc0da19e784c690e35260ec to your computer and use it in GitHub Desktop.
CloseEnough
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 <map> | |
| #include <strstream> | |
| #include <sstream> | |
| #include <utility> | |
| #include <vector> | |
| #include <deque> | |
| #include <queue> | |
| #include <unordered_map> | |
| enum Token : char { | |
| plus = '+', | |
| assign = '=', | |
| ident_str = 's', | |
| ident_number = 'i', | |
| funcsym = 'f', | |
| endsym = '\n', | |
| number, | |
| comma = ',', | |
| lp = '(', | |
| rp = ')', | |
| array = 'a', | |
| }; | |
| typedef std::string Str; | |
| typedef std::stringstream Buf; | |
| template<typename T> | |
| Str to_str(T t) { | |
| Buf ss(""); | |
| ss << t; | |
| return ss.str(); | |
| } | |
| template<typename T, typename...Args> | |
| Str to_str(T t, Args...args) { | |
| Buf ss(""); | |
| ss << t; | |
| ss << to_str(args...); | |
| return ss.str(); | |
| } | |
| Token GetToken() { | |
| char ch; | |
| Token tok=endsym; | |
| if (!std::cin.good()) { | |
| return endsym; | |
| } | |
| try { | |
| std::cin.get(ch); | |
| } catch (std::runtime_error &ex) { | |
| std::cerr << "Can't read from input{" << ex.what() << "} stream, please restart app." << std::endl; | |
| } | |
| switch (ch) { | |
| case 'i': | |
| case 'j': | |
| case 'k': | |
| tok = ident_number; | |
| break; | |
| case 's': | |
| case 'r': | |
| tok = ident_str; | |
| break; | |
| case comma: | |
| case plus: | |
| case endsym: | |
| case assign: | |
| case lp: | |
| case rp: | |
| case funcsym: | |
| case array: | |
| tok = Token(ch); | |
| break; | |
| case 0: | |
| return endsym; | |
| default: | |
| std::cin.putback(ch); | |
| if (isdigit(ch)) { | |
| double temp; | |
| std::cin >> temp; | |
| tok = number; | |
| break; | |
| } | |
| //throw std::runtime_error(to_str("Parse error : ", ch)); | |
| Str buf; | |
| std::getline(std::cin, buf, ' '); | |
| } | |
| return tok; | |
| } | |
| std::ostream &operator<<(std::ostream &os, Token s) { | |
| if (int(s) != number) { | |
| os << "\'" << char(s) << "\'"; | |
| } else { | |
| os << "'lnumber'"; | |
| } | |
| return os; | |
| } | |
| struct Leaf { | |
| Str return_type; | |
| Buf str; | |
| Token last_tok; | |
| Leaf(Str return_type, const std::string &what, Token last_tok = endsym) : return_type(return_type), str(what), | |
| last_tok(last_tok) {} | |
| }; | |
| Leaf Assign(Token tok, Str return_type, bool); | |
| Leaf NumLiteral(Token tok, Str return_type, bool get); | |
| template<typename T, typename ...Args> | |
| auto error(T t, Args...args) { | |
| return std::runtime_error(to_str(t, args...)); | |
| } | |
| Leaf leaf(Token tok, Str return_type, bool get) { | |
| if (get) { | |
| tok = GetToken(); | |
| } | |
| if (tok == ident_number) { | |
| return {"number", "number", tok}; | |
| } else if (tok == ident_str) { | |
| return {"str", "str", tok}; | |
| } else { | |
| throw error("atom error."); | |
| } | |
| } | |
| template<typename T> | |
| std::string operator+(T lhs, Buf &rhs) { | |
| return to_str(lhs, rhs.str()); | |
| } | |
| Leaf Functor(Token tok, Str return_type, bool get) { | |
| if (tok == funcsym) { | |
| Buf buf; | |
| auto it = Functor(tok=GetToken(), return_type, false); | |
| std::queue<Str> types; | |
| Buf str; | |
| str << "func ["; | |
| do { | |
| tok = GetToken(); | |
| if (tok == lp) { break; } | |
| auto type = leaf(tok, return_type, false); | |
| str << '\'' << type.str.str() << '\''; | |
| types.push(type.return_type); | |
| } while (true); | |
| str << "]->(" << it.str.str() << ")"; | |
| do { | |
| tok = GetToken(); | |
| if (tok == rp) { break; } | |
| Leaf type = NumLiteral(tok, return_type, false); | |
| if (type.return_type != types.front()) { | |
| throw error("type mismatch,expected: ", types.front(), "got:", type.return_type); | |
| } | |
| types.pop(); | |
| tok = GetToken(); | |
| } while (tok == comma); | |
| if (tok != rp) { | |
| throw error("func error: expected:')' got '", tok, "'"); | |
| } | |
| return {it.return_type, str.str(), tok}; | |
| } else if (tok == array) { | |
| auto item = Functor(tok=GetToken(), return_type, false); | |
| const std::basic_string<char, std::char_traits<char>, std::allocator<char>> &string = | |
| "array \'" + item.return_type + '\''; | |
| return {string, string, item.last_tok}; | |
| } else { | |
| return leaf(tok, return_type, get); | |
| } | |
| } | |
| Leaf NumLiteral(Token tok, Str return_type, bool get) { | |
| if(get){ | |
| tok=GetToken(); | |
| } | |
| if (tok == number) { | |
| return {"number", "number", tok}; | |
| } else { | |
| return Functor(tok, return_type, false); | |
| } | |
| } | |
| Leaf Add(Token tok, Str return_type, bool get) { | |
| auto lhs = NumLiteral(tok, return_type, get); | |
| tok = GetToken(); | |
| while (tok == plus) { | |
| auto rhs = NumLiteral(tok, lhs.return_type, true); | |
| if (lhs.return_type != rhs.return_type || lhs.return_type != "number") { | |
| throw error("add error:type mismatch expected 'number' got '", rhs.str.str(), "' with return type:", | |
| rhs.return_type); | |
| } | |
| lhs = {rhs.return_type, "add operation(" + lhs.str + '+' + rhs.str + ')', tok = rhs.last_tok}; | |
| tok=GetToken(); | |
| } | |
| return {lhs.return_type, lhs.str.str(), tok}; | |
| } | |
| Leaf Assign(Token tok, Str return_type, bool get) { | |
| auto lhs = Add(tok, return_type, get); | |
| tok = lhs.last_tok; | |
| if (tok == assign) { | |
| auto rhs = Add(tok, lhs.return_type, true); | |
| if (lhs.return_type != rhs.return_type) { | |
| throw error("assign error:type mismatch ",lhs.return_type,"!=",rhs.return_type); | |
| } | |
| return {rhs.return_type, "assign operation(" + rhs.str + "=" + lhs.str + ")"}; | |
| } else { | |
| return lhs; | |
| } | |
| } | |
| int main() { | |
| auto list = {"aaaai=aaaai", "2+3=i+i","ffiss(s,s)i(5)=i", "i=fiss(s,s)", "i", "s=s", "i+i+i+i+50+1000" | |
| }; | |
| std::stringstream is; | |
| std::for_each(list.begin(), list.end(), [&](auto it) { is << it << "\n"; }); | |
| std::cin.rdbuf(is.rdbuf()); | |
| try { | |
| for (auto tok = GetToken(); tok != endsym; tok = GetToken()) { | |
| auto item = Assign(tok, "", false); | |
| std::cout << item.str.str() << std::endl; | |
| if (item.last_tok != endsym) { | |
| error("expected end of expression got '", item.last_tok, "'"); | |
| } | |
| } | |
| } catch (std::runtime_error &ex) { | |
| std::cerr << ex.what() << std::endl; | |
| } catch (...) { | |
| std::cerr << "Unknown error!" << std::endl; | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment