Added grammar generator.

This commit is contained in:
yhirose 2015-02-13 22:41:17 -05:00
parent 5976051070
commit 09ce72b25e

166
peglib.h
View File

@ -1018,46 +1018,22 @@ inline std::pair<size_t, size_t> line_info(const char* s, const char* ptr) {
return std::make_pair(no, col); return std::make_pair(no, col);
} }
inline std::string resolve_escape_sequence(const char*s, size_t l) { class GrammarGenerator
std::string r;
r.reserve(l);
for (auto i = 0u; i < l; i++) {
auto ch = s[i];
if (ch == '\\') {
i++;
switch (s[i]) {
case 'n': r += '\n'; break;
case 'r': r += '\r'; break;
case 't': r += '\t'; break;
case '\'': r += '\''; break;
case '"': r += '"'; break;
case '[': r += '['; break;
case ']': r += ']'; break;
case '\\': r += '\\'; break;
default: {
// TODO: Octal number support
assert(false);
break;
}
}
} else {
r += ch;
}
}
return r;
}
inline std::shared_ptr<Grammar> make_grammar(
const char* syntax, size_t syntax_len, std::string& start,
std::function<void (size_t, size_t, const std::string&)> log = nullptr)
{ {
Grammar peg = make_peg_grammar(); public:
static GrammarGenerator& instance() {
static GrammarGenerator instance;
return instance;
}
std::shared_ptr<Grammar> perform(
const char* syntax,
size_t syntax_len,
std::string& start,
std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
// Prepare output variables
auto grammar = std::make_shared<Grammar>(); auto grammar = std::make_shared<Grammar>();
start.clear(); start.clear();
// Setup actions
std::map<std::string, const char*> refs; std::map<std::string, const char*> refs;
peg["Definition"] = [&](const std::vector<Any>& v) { peg["Definition"] = [&](const std::vector<Any>& v) {
@ -1070,6 +1046,50 @@ inline std::shared_ptr<Grammar> make_grammar(
} }
}; };
peg["Primary"].actions = {
[&](const std::vector<Any>& v) {
return v[0];
},
[&](const char* s, size_t l, const std::vector<Any>& v) {
refs[v[0]] = s;
return ref(*grammar, v[0]);
},
[&](const std::vector<Any>& v) {
return v[1];
}
};
auto m = peg["Grammar"].parse_with_match(syntax, syntax_len);
if (!m.ret) {
if (log) {
auto line = line_info(syntax, m.ptr);
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
}
return nullptr;
}
for (const auto& x : refs) {
const auto& name = x.first;
auto ptr = x.second;
if (grammar->find(name) == grammar->end()) {
if (log) {
auto line = line_info(syntax, ptr);
log(line.first, line.second, "'" + name + "' is not defined.");
}
return nullptr;
}
}
return grammar;
}
private:
GrammarGenerator() : peg(make_peg_grammar()) {
initialize();
}
void initialize() {
peg["Expression"] = [&](const std::vector<Any>& v) { peg["Expression"] = [&](const std::vector<Any>& v) {
if (v.size() == 1) { if (v.size() == 1) {
return v[0].get<std::shared_ptr<Ope>>(); return v[0].get<std::shared_ptr<Ope>>();
@ -1130,19 +1150,6 @@ inline std::shared_ptr<Grammar> make_grammar(
} }
}; };
peg["Primary"].actions = {
[&](const std::vector<Any>& v) {
return v[0];
},
[&](const char* s, size_t l, const std::vector<Any>& v) {
refs[v[0]] = s;
return ref(*grammar, v[0]);
},
[&](const std::vector<Any>& v) {
return v[1];
}
};
peg["IdentCont"] = [](const char*s, size_t l) { peg["IdentCont"] = [](const char*s, size_t l) {
return std::string(s, l); return std::string(s, l);
}; };
@ -1150,46 +1157,62 @@ inline std::shared_ptr<Grammar> make_grammar(
peg["Literal"] = [](const std::vector<Any>& v) { peg["Literal"] = [](const std::vector<Any>& v) {
return lit(v[0]); return lit(v[0]);
}; };
peg["SQCont"] = [](const char*s, size_t l) { peg["SQCont"] = [this](const char*s, size_t l) {
return resolve_escape_sequence(s, l); return resolve_escape_sequence(s, l);
}; };
peg["DQCont"] = [](const char*s, size_t l) { peg["DQCont"] = [this](const char*s, size_t l) {
return resolve_escape_sequence(s, l); return resolve_escape_sequence(s, l);
}; };
peg["Class"] = [](const std::vector<Any>& v) { peg["Class"] = [](const std::vector<Any>& v) {
return cls(v[0]); return cls(v[0]);
}; };
peg["ClassCont"] = [](const char*s, size_t l) { peg["ClassCont"] = [this](const char*s, size_t l) {
return resolve_escape_sequence(s, l); return resolve_escape_sequence(s, l);
}; };
peg["DOT"] = []() { peg["DOT"] = []() {
return any(); return any();
}; };
auto m = peg["Grammar"].parse_with_match(syntax, syntax_len);
if (!m.ret) {
if (log) {
auto line = line_info(syntax, m.ptr);
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
}
return nullptr;
} }
for (const auto& x : refs) { std::string resolve_escape_sequence(const char*s, size_t l) {
const auto& name = x.first; std::string r;
auto ptr = x.second; r.reserve(l);
if (grammar->find(name) == grammar->end()) { for (auto i = 0u; i < l; i++) {
if (log) { auto ch = s[i];
auto line = line_info(syntax, ptr); if (ch == '\\') {
log(line.first, line.second, "'" + name + "' is not defined."); i++;
switch (s[i]) {
case 'n': r += '\n'; break;
case 'r': r += '\r'; break;
case 't': r += '\t'; break;
case '\'': r += '\''; break;
case '"': r += '"'; break;
case '[': r += '['; break;
case ']': r += ']'; break;
case '\\': r += '\\'; break;
default: {
// TODO: Octal number support
assert(false);
break;
} }
return nullptr;
} }
} else {
r += ch;
}
}
return r;
} }
return grammar; Grammar peg;
};
inline std::shared_ptr<Grammar> make_grammar(
const char* syntax, size_t syntax_len, std::string& start,
std::function<void (size_t, size_t, const std::string&)> log = nullptr)
{
return GrammarGenerator::instance().perform(syntax, syntax_len, start, log);
} }
inline std::shared_ptr<Grammar> make_grammar( inline std::shared_ptr<Grammar> make_grammar(
@ -1210,7 +1233,10 @@ public:
return grammar_ != nullptr; return grammar_ != nullptr;
} }
bool load_syntax(const char* s, size_t l, std::function<void (size_t, size_t, const std::string&)> log = nullptr) { bool load_syntax(
const char* s, size_t l,
std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
grammar_ = make_grammar(s, l, start_, log); grammar_ = make_grammar(s, l, start_, log);
return grammar_ != nullptr; return grammar_ != nullptr;
} }