Skip to content

Instantly share code, notes, and snippets.

@megamen32
Created April 19, 2018 14:42
Show Gist options
  • Select an option

  • Save megamen32/106997e8bdaf79fdc5d19493d7461e32 to your computer and use it in GitHub Desktop.

Select an option

Save megamen32/106997e8bdaf79fdc5d19493d7461e32 to your computer and use it in GitHub Desktop.
Fully function Parser
#include <iostream>
#include <map>
#include <strstream>
#include <sstream>
#include <utility>
#include <vector>
#include <deque>
#include <queue>
enum Token : char {
plus = '+',
assign = '=',
ident,
ident_str = 's',
ident_number = 'i',
funcsym = 'f',
endsym = '\n',
number,
comma = ',',
lp = '(',
rp = ')'
};
std::map<Token, Token> TokenConvertMap = {{ident_str, ident},
{ident_number, ident},
{number, ident_number}};
bool operator==(enum Token lhs, enum Token rhs) {
if (char(rhs) == char(lhs)) { return true; }
for (auto &begin : TokenConvertMap) {
if ((int(begin.first) == int(lhs)) && (int(begin.second) == int(rhs))) {
return true;
}
}
return false;
}
bool operator!=(enum Token lhs, enum Token rhs) {
return !(lhs == rhs);
}
Token GetToken() {
char ch;
Token tok;
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:
tok = Token(ch);
break;
case 0:
return endsym;
default:
if (isdigit(ch)) {
double temp;
std::cin.putback(ch) >> temp;
tok = number;
break;
}
throw std::runtime_error(std::string("Parse error : ").append(std::to_string(ch)));
}
return tok;
}
std::ostream &operator<<(std::ostream &os, Token s) {
os << "\'" << char(s) << "\'";
return os;
}
bool expect(std::initializer_list<Token> tokens_to_expect) {
bool good = false;
auto tok = GetToken();
for (auto &&to_expect : tokens_to_expect) {
if (tok == to_expect) {
good = true;
break;
}
}
if (!good) {
std::cerr << "expected error: got " << tok << " candidates:";
for (auto &&to_expect : tokens_to_expect) {
std::cerr << to_expect << " ";
}
}
return good;
}
typedef std::string Str;
typedef std::stringstream Buf;
struct Leaf {
Token return_type;
Buf str;
Token last_tok;
Leaf(Token return_type, const std::string &what, Token last_tok = endsym) : return_type(return_type), str(what),
last_tok(last_tok) {}
};
Leaf Assign(Token tok, Token return_type, bool);
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();
}
template<typename T, typename ...Args>
Leaf error(T t, Args...args) {
return {endsym, to_str(t, args...)};
}
Leaf leaf(Token tok, Token return_type, bool get) {
if (get) {
tok = GetToken();
}
if (tok == ident_number) {
return {tok, "number", tok};
} else if (tok == ident_str) {
return {tok, "str", tok};
} else if (tok == funcsym) {
Buf buf;
auto it = leaf(tok, return_type, true);
std::queue<Token> 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 = Assign(tok, return_type, false);
if (type.return_type != types.front()) {
throw error("type mismatch,expected: ", types.front(), "got:", type.return_type);
}
types.pop();
tok = type.last_tok;
} while (tok == comma);
if (tok != rp) {
throw error("func error: expected:')' got '", tok, "'");
}
return {it.return_type, 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 Add(Token tok, Token return_type, bool get) {
auto lhs = leaf(tok, return_type, get);
tok=GetToken();
while (tok == plus) {
auto rhs = Add(tok, lhs.return_type, true);
if (lhs.return_type != rhs.return_type || number != lhs.return_type) {
throw error("add error:type mismatch expected 'number' got '", rhs.str.str(), "'");
}
lhs = {rhs.return_type, "add operation(" + lhs.str + '+' + rhs.str + ')',tok=rhs.last_tok};
}
return {lhs.return_type,lhs.str.str(),tok};
}
Leaf Assign(Token tok, Token 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");
}
return {rhs.return_type, "assign operation(" + rhs.str + "=" + lhs.str + ")"};
} else {
return lhs;
}
}
int main() {
auto list = {"ffiss(s,s)i(5)=i", "2+3=i+i", "i=fiss(s,s)", "i", "s=s", "i+i+i+i"
};
std::stringstream is;
std::for_each(list.begin(), list.end(), [&](auto it) { is << it << "\n"; });
std::cin.rdbuf(is.rdbuf());
try {
do {
auto tok = GetToken();
if (tok == endsym) { break; }
auto item = Assign(tok, endsym, false);
std::cout << item.str.str() << std::endl;
if (item.last_tok != endsym) {
error("expected end of expresion got '", item.last_tok, "'");
}
} while (true);
} catch (Leaf &ex) {
std::cerr << ex.str.str() << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment