This commit is contained in:
TopchetoEU 2022-10-09 16:34:02 +03:00
parent cca9bc2e07
commit 4d6ce93ae3
12 changed files with 115 additions and 127 deletions

View File

@ -17,9 +17,13 @@ namespace ppc::comp::tree::ast {
class parser_t;
class group_parser_t;
extern const parser_t &glob_parser;
extern const parser_t &identifier_parser;
extern const parser_t &nmsp_parser;
using parser_factory_t = parser_t *(*)();
using group_parser_factory_t = group_parser_t *(*)();
extern parser_factory_t glob_parser;
extern parser_factory_t identifier_parser;
extern parser_factory_t nmsp_parser;
extern group_parser_factory_t def_parser;
struct ast_ctx_t {
private:
@ -42,25 +46,34 @@ namespace ppc::comp::tree::ast {
std::unordered_map<std::string, const parser_t*> parsers;
std::set<const parser_t*> groups;
void add_parser(const parser_t *parser);
void add_parser(const group_parser_t *parser);
public:
msg_stack_t &messages;
std::vector<token_t> &tokens;
std::set<loc_namespace_name_t> imports;
loc_namespace_name_t nmsp;
void add_parser(const parser_t &parser);
void add_parser(const group_parser_t &parser);
void add_parser(parser_factory_t factory) { add_parser(factory()); }
void add_parser(group_parser_factory_t factory) { add_parser(factory()); }
ast_ctx_t &operator=(const ast_ctx_t &other) = delete;
const parser_proxy_t parser;
const group_proxy_t group;
ast_ctx_t &init() {
add_parser(glob_parser);
add_parser(identifier_parser);
add_parser(nmsp_parser);
add_parser(def_parser);
return *this;
}
bool parse(std::string parser, size_t &pi, data::map_t &out);
static bool parse(msg_stack_t &messages, std::vector<token_t> &tokens, data::map_t &out);
~ast_ctx_t();
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens):
messages(messages),
tokens(tokens),
@ -81,6 +94,7 @@ namespace ppc::comp::tree::ast {
return parse(ctx, i, out);
}
virtual ~parser_t() = default;
parser_t(const std::string &name): _name(name) { }
};
@ -93,6 +107,8 @@ namespace ppc::comp::tree::ast {
group_parser_t &add(parser_t &parser, const lang::namespace_name_t &name);
bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
group_parser_t(const std::string &name): parser_t(name) { }
};
namespace conv {

View File

@ -82,25 +82,25 @@ namespace ppc::comp::tree::ast {
throw_ended(reason);
}
bool push_parse(const parser_t &parser, data::array_t &out) {
bool push_parse(const std::string &name, data::array_t &out) {
data::map_t res;
if (parser(ctx, i, res)) {
if (parse(name, res)) {
out.push(res);
return true;
}
else return false;
}
bool parse(const parser_t &parser, data::map_t &out) {
return parser(ctx, i, out);
bool parse(const std::string &name, data::map_t &out) {
return ctx.parse(name, i, out);
}
void force_push_parse(const parser_t &parser, std::string message, data::array_t &out) {
void force_push_parse(const std::string &name, std::string message, data::array_t &out) {
advance(message);
bool success;
try {
success = push_parse(parser, out);
success = push_parse(name, out);
}
catch (const message_t &msg) {
ctx.messages.push(msg);
@ -109,12 +109,12 @@ namespace ppc::comp::tree::ast {
if (!success) err(message);
}
void force_parse(const parser_t &parser, std::string message, data::map_t &out) {
void force_parse(const std::string &name, std::string message, data::map_t &out) {
advance(message);
bool success;
try {
success = parse(parser, out);
success = parse(name, out);
}
catch (const message_t &msg) {
ctx.messages.push(msg);

View File

@ -129,37 +129,31 @@ namespace ppc::comp::tree {
bool is_identifier(std::string &&val) { return is_identifier() && identifier() == val; }
token_t() { kind = NONE; }
token_t(const std::string &identifier, location_t loc = location_t::NONE) {
token_t(const std::string &identifier, location_t loc = location_t::NONE): location(loc) {
kind = IDENTIFIER;
data.identifier = new std::string { identifier };
location = loc;
}
token_t(operator_t op, location_t loc = location_t::NONE) {
token_t(operator_t op, location_t loc = location_t::NONE): location(loc) {
kind = OPERATOR;
data._operator = op;
location = loc;
}
token_t(std::uint64_t val, location_t loc = location_t::NONE) {
token_t(std::uint64_t val, location_t loc = location_t::NONE): location(loc) {
kind = INT;
data.int_literal = val;
location = loc;
}
token_t(double val, location_t loc = location_t::NONE) {
token_t(double val, location_t loc = location_t::NONE): location(loc) {
kind = FLOAT;
data.float_literal = val;
location = loc;
}
token_t(char c, location_t loc = location_t::NONE) {
token_t(char c, location_t loc = location_t::NONE): location(loc) {
kind = CHAR;
data.char_literal = c;
location = loc;
}
token_t(const std::vector<char> &val, location_t loc = location_t::NONE) {
token_t(const std::vector<char> &val, location_t loc = location_t::NONE): location(loc) {
kind = STRING;
data.string_literal = new std::vector<char> { val };
location = loc;
}
token_t(const token_t &tok) {
token_t(const token_t &tok): location(tok.location) {
kind = tok.kind;
switch (kind) {
case NONE: break;
@ -170,7 +164,6 @@ namespace ppc::comp::tree {
case CHAR: data.char_literal = tok.data.char_literal; break;
case STRING: data.string_literal = new std::vector<char> { *tok.data.string_literal }; break;
}
location = tok.location;
}
~token_t() {

View File

@ -10,19 +10,20 @@ namespace ppc {
std::size_t start;
std::size_t length;
std::size_t code_start;
std::string filename;
const std::string &filename;
operator std::string() const { return to_string(); }
std::string to_string() const;
location_t intersect(location_t other) const;
location_t();
location_t(std::string filename);
location_t(const location_t &other): location_t(other.filename, other.line, other.start, other.code_start, other.length) { }
location_t(const std::string &filename);
location_t(std::size_t line, std::size_t start);
location_t(std::string filename, std::size_t line, std::size_t start);
location_t(const std::string &filename, std::size_t line, std::size_t start);
location_t(std::size_t line, std::size_t start, std::size_t code_start);
location_t(std::string filename, std::size_t line, std::size_t start, std::size_t code_start);
location_t(const std::string &filename, std::size_t line, std::size_t start, std::size_t code_start);
location_t(std::size_t line, std::size_t start, std::size_t code_start, std::size_t length);
location_t(std::string filename, std::size_t line, std::size_t start, std::size_t code_start, std::size_t length);
location_t(const std::string &filename, std::size_t line, std::size_t start, std::size_t code_start, std::size_t length);
};
}

View File

@ -14,14 +14,20 @@ namespace ppc::comp::tree::ast {
return *(const group_parser_t*)p;
}
void ast_ctx_t::add_parser(const parser_t &parser) {
if (parsers.find(parser.name()) != parsers.end()) throw "The parser '" + parser.name() + "' already exists.";
parsers[parser.name()] = &parser;
ast_ctx_t::~ast_ctx_t() {
for (auto pair : parsers) {
delete pair.second;
}
void ast_ctx_t::add_parser(const group_parser_t &parser) {
if (parsers.find(parser.name()) != parsers.end()) throw "The parser '" + parser.name() + "' already exists.";
parsers[parser.name()] = &parser;
groups.emplace(&parser);
}
void ast_ctx_t::add_parser(const parser_t *parser) {
if (parsers.find(parser->name()) != parsers.end()) throw "The parser '" + parser->name() + "' already exists.";
parsers[parser->name()] = parser;
}
void ast_ctx_t::add_parser(const group_parser_t *parser) {
if (parsers.find(parser->name()) != parsers.end()) throw "The parser '" + parser->name() + "' already exists.";
parsers[parser->name()] = parser;
groups.emplace(parser);
}
bool ast_ctx_t::parse(msg_stack_t &messages, std::vector<token_t> &tokens, data::map_t &out) {
@ -30,12 +36,15 @@ namespace ppc::comp::tree::ast {
size_t i = 0;
try {
return glob_parser(ctx, i, out);
return ctx.parse("$_glob", i, out);
}
catch (const message_t &msg) {
messages.push(msg);
return false;
}
}
bool ast_ctx_t::parse(std::string parser, size_t &pi, data::map_t &out) {
return this->parser[parser] (*this, pi, out);
}
}

View File

@ -5,7 +5,7 @@ namespace ppc::comp::tree::ast::conv {
return {
{ "location", conv::loc_to_map(loc.location) },
{ "content", loc },
{ "$_name", identifier_parser.name() },
{ "$_name", "$_identifier" },
};
}
located_t<std::string> map_to_identifier(const data::map_t &map) {
@ -17,20 +17,17 @@ namespace ppc::comp::tree::ast::conv {
{ "$_name", "$_loc" },
};
if (loc.filename != "") res["filename"] = loc.filename;
res["filename"] = loc.filename;
if (loc.start != -1u) res["start"] = (float)loc.start;
if (loc.start != -1u) res["line"] = (float)loc.line;
if (loc.code_start != -1u) res["code_start"] = (float)loc.code_start;
if (loc.length != -1u) res["length"] = (float)loc.length;
return res;
}
location_t map_to_loc(const data::map_t &map) {
location_t res;
location_t res(map["filename"].string());
if (map.has("filename")) {
if (map["filename"].is_string()) res.filename = map["filename"].string();
else throw "Expected key 'filename' to be a string.";
}
if (map.has("start")) {
if (map["start"].is_number()) res.start = (size_t)map["start"].number();
else throw "Expected key 'start' to be a number.";
@ -43,6 +40,10 @@ namespace ppc::comp::tree::ast::conv {
if (map["code_start"].is_number()) res.code_start = (size_t)map["code_start"].number();
else throw "Expected key 'code_start' to be a number.";
}
if (map.has("line")) {
if (map["line"].is_number()) res.line = (size_t)map["line"].number();
else throw "Expected key 'line' to be a number.";
}
return res;
}
@ -56,7 +57,7 @@ namespace ppc::comp::tree::ast::conv {
arr.push({
{ "location", loc_to_map(segment.location) },
{ "content", segment },
{ "$_name", nmsp_parser.name() },
{ "$_name", "$_nmsp" },
});
}

View File

@ -9,7 +9,7 @@ class nmsp_def_parser_t : public parser_t {
if (h.ended()) return false;
if (!h.curr().is_identifier("namespace")) return false;
h.force_parse(nmsp_parser, "Expected a namespace.", res);
h.force_parse("$_nmsp", "Expected a namespace.", res);
if (!h.curr().is_operator(operator_t::SEMICOLON)) h.err("Expected a semicolon.");
return h.submit(true);
@ -23,7 +23,7 @@ class import_parser_t : public parser_t {
if (h.ended()) return false;
if (!h.curr().is_identifier("import")) return false;
h.force_parse(nmsp_parser, "Expected a namespace.", res);
h.force_parse("$_nmsp", "Expected a namespace.", res);
if (!h.curr().is_operator(operator_t::SEMICOLON)) h.err("Expected a semicolon.");
return h.submit(true);
@ -32,22 +32,23 @@ class import_parser_t : public parser_t {
public: import_parser_t(): parser_t("$_import") { }
};
const parser_t &import_parser = import_parser_t();
const parser_t &nmsp_def_parser = nmsp_def_parser_t();
auto import_parser = import_parser_t();
auto nmsp_def_parser = nmsp_def_parser_t();
class glob_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const {
tree_helper_t h(ctx, res_i);
if (h.ended()) return true;
h.parse(nmsp_def_parser, (out["namespace"] = map_t()).map());
nmsp_def_parser(ctx, h.i, (out["namespace"] = map_t()).map());
ctx.nmsp = conv::map_to_nmsp(out["namespace"].map());
auto imports = (out["imports"] = array_t()).array();
auto &imports = (out["imports"] = array_t()).array();
auto &contents = (out["content"] = array_t()).array();
while (true) {
map_t map;
if (!import_parser(ctx, h.i, map)) break;
imports.push(map);
if (!h.parse(import_parser, map)) break;
auto nmsp = conv::map_to_nmsp(map);
if (!ctx.imports.emplace(nmsp).second) h.err("The namespace '" + nmsp.to_string() + "' is already imported.");
@ -62,4 +63,5 @@ public:
glob_parser_t(): parser_t("$_glob") { }
};
const parser_t &ppc::comp::tree::ast::glob_parser = glob_parser_t();
parser_factory_t ppc::comp::tree::ast::glob_parser = []() { return (parser_t*)new glob_parser_t(); };
group_parser_factory_t ppc::comp::tree::ast::def_parser = []() { return new group_parser_t("$_def"); };

View File

@ -29,17 +29,18 @@ static bool read_nmsp(ast_ctx_t &ctx, size_t &i, const lang::namespace_name_t &n
return equal_i != name.size();
}
bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
tree_helper_t h(ctx, i);
for (auto &pair : named_parsers) {
if (!read_nmsp(ctx, i, pair.first)) continue;
auto &parser = *pair.second;
return h.parse(parser, out);
return parser(ctx, i, out);
}
for (auto parser : parsers) {
try {
return h.parse(*parser, out);
return (*parser)(ctx, i, out);
}
catch (const message_t &err) {
ctx.messages.push(err);

View File

@ -18,4 +18,4 @@ class identifier_parser_t : public parser_t {
public: identifier_parser_t(): parser_t("$_identifier") { }
};
const parser_t &ppc::comp::tree::ast::identifier_parser = identifier_parser_t();
parser_factory_t ppc::comp::tree::ast::identifier_parser = []() { return (parser_t*)new identifier_parser_t(); };

View File

@ -8,12 +8,12 @@ class nmsp_parser_t : public parser_t {
auto &arr = (out["content"] = array_t()).array();
if (!h.push_parse(identifier_parser, arr)) return false;
if (!h.push_parse("$_identifier", arr)) return false;
while (true) {
if (h.ended()) break;
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
h.force_push_parse(identifier_parser, "Expected an identifier.", arr);
h.force_push_parse("$_identifier", "Expected an identifier.", arr);
}
out["location"] = conv::loc_to_map(h.res_loc());
@ -23,4 +23,4 @@ class nmsp_parser_t : public parser_t {
public: nmsp_parser_t(): parser_t("$_nmsp") { }
};
const parser_t &ppc::comp::tree::ast::nmsp_parser = nmsp_parser_t();
parser_factory_t ppc::comp::tree::ast::nmsp_parser = []() { return (parser_t*)new nmsp_parser_t(); };

View File

@ -153,26 +153,29 @@ int main(int argc, const char *argv[]) {
for (const auto &file : files) {
std::ifstream f { file, std::ios_base::in };
std::stringstream res;
try {
auto tokens = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f));
data::map_t ast;
if (!ast::ast_ctx_t::parse(msg_stack, tokens, ast)) throw msg_stack.peek();
for (auto tok : tokens) {
if (tok.is_identifier()) std::cout << "Identifier: \t" << tok.identifier();
if (tok.is_operator()) std::cout << "Operator: \t" << operator_stringify(tok._operator());
if (tok.is_float_lit()) std::cout << "Float: \t" << tok.float_lit();
if (tok.is_int_lit()) std::cout << "Int: \t" << tok.int_lit();
if (tok.is_char_lit()) std::cout << "Char: \t" << tok.char_lit();
if (tok.is_string_lit()) std::cout << "String: \t" << std::string { tok.string_lit().begin(), tok.string_lit().end() };
std::cout << std::endl;
if (tok.is_identifier()) res << "Identifier: \t" << tok.identifier();
if (tok.is_operator()) res << "Operator: \t" << operator_stringify(tok._operator());
if (tok.is_float_lit()) res << "Float: \t" << tok.float_lit();
if (tok.is_int_lit()) res << "Int: \t" << tok.int_lit();
if (tok.is_char_lit()) res << "Char: \t" << tok.char_lit();
if (tok.is_string_lit()) res << "String: \t" << std::string { tok.string_lit().begin(), tok.string_lit().end() };
res << '\n';
}
std::cout << std::endl << data::json::stringify(ast);
res << '\n' << data::json::stringify(ast);
}
catch (const messages::message_t &msg) {
msg_stack.push(msg);
}
std::cout << res.str() << std::endl;
}
msg_stack.print(std::cout, messages::message_t::DEBUG, true);

View File

@ -40,11 +40,7 @@ location_t location_t::intersect(location_t other) const {
if (a.start == -1u || b.start == -1u) return { };
if (a.start > b.start) {
location_t c = a;
a = b;
b = c;
}
if (a.start > b.start) return other.intersect(*this);
fix_location(a);
fix_location(b);
@ -59,61 +55,27 @@ location_t location_t::intersect(location_t other) const {
return a;
}
location_t::location_t() {
this->line = -1;
this->start = -1;
this->length = -1;
this->code_start = -1;
this->filename = "";
}
location_t::location_t(std::string filename) {
this->line = -1;
this->start = -1;
this->length = -1;
this->code_start = -1;
this->filename = filename;
}
location_t::location_t(std::size_t line, std::size_t start) {
this->line = line;
this->start = start;
this->length = -1;
this->code_start = -1;
this->filename = "";
}
location_t::location_t(std::string filename, std::size_t line, std::size_t start) {
this->line = line;
this->start = start;
this->length = -1;
this->code_start = -1;
this->filename = filename;
}
location_t::location_t(std::size_t line, std::size_t start, std::size_t code_start) {
this->line = line;
this->start = start;
this->length = -1;
std::string empty = "";
location_t::location_t():
location_t(empty, -1, -1, -1, -1) { }
location_t::location_t(const std::string &filename):
location_t(filename, -1, -1, -1, -1) { }
location_t::location_t(std::size_t line, std::size_t start):
location_t(empty, line, start, -1, -1) { }
location_t::location_t(const std::string &filename, std::size_t line, std::size_t start):
location_t(filename, line, start, -1, -1) { }
location_t::location_t(std::size_t line, std::size_t start, std::size_t code_start):
location_t(empty, line, start, code_start, -1) { }
location_t::location_t(const std::string &filename, std::size_t line, std::size_t start, std::size_t code_start):
location_t(filename, line, start, code_start, -1) { }
location_t::location_t(std::size_t line, std::size_t start, std::size_t code_start, std::size_t length):
location_t(empty, line, start, code_start, length) { }
location_t::location_t(const std::string &filename, std::size_t line, std::size_t start, std::size_t code_start, std::size_t length): filename(filename) {
this->length = length;
this->code_start = code_start;
this->filename = "";
}
location_t::location_t(std::string filename, std::size_t line, std::size_t start, std::size_t code_start) {
this->line = line;
this->start = start;
this->length = -1;
this->code_start = code_start;
this->filename = filename;
}
location_t::location_t(std::size_t line, std::size_t start, std::size_t code_start, std::size_t length) {
this->line = line;
this->start = start;
this->length = line;
this->code_start = code_start;
this->filename = "";
}
location_t::location_t(std::string filename, std::size_t line, std::size_t start, std::size_t code_start, std::size_t length) {
this->line = line;
this->start = start;
this->length = line;
this->code_start = code_start;
this->filename = filename;
}
const location_t location_t::NONE = { };