Skip to content

Instantly share code, notes, and snippets.

@megamen32
Created May 2, 2018 12:27
Show Gist options
  • Select an option

  • Save megamen32/4e28592bbcc0da19e784c690e35260ec to your computer and use it in GitHub Desktop.

Select an option

Save megamen32/4e28592bbcc0da19e784c690e35260ec to your computer and use it in GitHub Desktop.
CloseEnough
#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