chore: recoded ast system with ptr functions

This commit is contained in:
TopchetoEU 2022-10-27 14:31:59 +03:00
parent d7ee0e3bb2
commit 662442121d
18 changed files with 651 additions and 811 deletions

View File

@ -1,5 +1,5 @@
export MAKEFLAGS += --silent -r -j
export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow -DPROFILE_$(profile)
export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow -DPROFILE_$(profile) -fdiagnostics-color=always
export ldflags=-L$(bin)/$(profile)
export lib=ppc$(version-major)-
export profile=release

View File

@ -15,111 +15,52 @@ using namespace ppc::lang;
using namespace ppc::messages;
namespace ppc::comp::tree::ast {
class parser_t;
class group_parser_t;
struct ast_ctx_t;
using parser_func_t = bool (ast_ctx_t &ctx, size_t &res_i, data::map_t &out);
using parser_t = parser_func_t*;
using parser_adder_t = void (*)(ast_ctx_t &ctx);
class group_t {
private:
std::map<lang::namespace_name_t, std::string> named_parsers;
std::map<std::string, parser_t> parsers;
public:
group_t &insert(const std::string &name, parser_t parser, const std::string &relative_to, bool after);
group_t &add_last(const std::string &name, parser_t parser);
group_t &replace(const std::string &name, parser_t parser);
group_t &add_named(const std::string &name, parser_t parser, const lang::namespace_name_t &identifier);
extern const parser_adder_t glob_adder;
extern const parser_adder_t identifier_adder;
extern const parser_adder_t nmsp_adder;
extern const parser_adder_t type_adder;
extern const parser_adder_t exp_adder;
extern const parser_adder_t field_adder;
extern const parser_adder_t func_adder;
extern const parser_adder_t var_adder;
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
};
struct ast_ctx_t {
private:
struct parser_proxy_t {
private:
ast_ctx_t *parent;
public:
const parser_t &operator[](const std::string &name) const;
parser_proxy_t(ast_ctx_t *parent): parent(parent) { }
};
struct group_proxy_t {
private:
ast_ctx_t *parent;
public:
group_parser_t &operator[](const std::string &name);
group_parser_t &operator[](const std::string &name) const;
group_proxy_t(ast_ctx_t *parent): parent(parent) { }
};
std::unordered_map<std::string, const parser_t*> parsers;
std::set<group_parser_t*> groups;
std::unordered_map<std::string, group_t> groups;
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 parser_t *parser, const std::string &group);
void add_parser(const parser_t *parser, const std::string &group, const namespace_name_t &name);
void add_parser(parser_adder_t factory) { factory(*this); }
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(identifier_adder);
add_parser(nmsp_adder);
add_parser(glob_adder);
add_parser(type_adder);
add_parser(exp_adder);
add_parser(var_adder);
add_parser(field_adder);
add_parser(func_adder);
return *this;
template <class T>
bool parse(const T &parser, size_t &i, data::map_t &out) {
return parser(*this, i, out);
}
bool parse(std::string parser, size_t &pi, data::map_t &out);
static data::map_t parse(msg_stack_t &messages, std::vector<token_t> &tokens);
group_t &group(const std::string &name);
~ast_ctx_t();
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens):
messages(messages),
tokens(tokens),
parser(this),
group(this) { }
};
class parser_t {
private:
std::string _name;
protected:
virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0;
public:
const std::string &name() const { return _name; }
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
template <class T>
static data::map_t parse(const T &glob, msg_stack_t &messages, std::vector<token_t> &tokens) {
ast_ctx_t ctx(messages, tokens);
data::map_t res;
out["$_name"] = _name;
return parse(ctx, i, out);
size_t i = 0;
if (!ctx.parse(glob, i, res)) throw message_t::error("Failed to compile.");
return res;
}
virtual ~parser_t() = default;
parser_t(const std::string &name): _name(name) { }
};
class group_parser_t : public parser_t {
private:
std::map<lang::namespace_name_t, const parser_t*> named_parsers;
std::vector<const parser_t*> parsers;
public:
group_parser_t &add(const parser_t &parser);
group_parser_t &add(const 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) { }
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens);
};
namespace conv {
@ -132,4 +73,7 @@ namespace ppc::comp::tree::ast {
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp);
loc_namespace_name_t map_to_nmsp(const data::map_t &map);
}
parser_func_t parse_glob, parse_nmsp, parse_identifier, parse_type, parse_func, parse_field, parse_exp, parse_stat_exp;
parser_func_t parse_exp_var, parse_exp_str_lit, parse_exp_int_lit, parse_exp_float_lit;
}

View File

@ -104,25 +104,28 @@ namespace ppc::comp::tree::ast {
throw_ended(reason);
}
bool push_parse(const std::string &name, data::array_t &out) {
template <class T>
bool push_parse(const T &parser, data::array_t &out) {
data::map_t res;
if (parse(name, res)) {
if (parse(parser, res)) {
out.push_back(res);
return true;
}
else return false;
}
bool parse(const std::string &name, data::map_t &out) {
return ctx.parse(name, i, out);
template <class T>
bool parse(const T &parser, data::map_t &out) {
return ctx.parse(parser, i, out);
}
void force_push_parse(const std::string &name, std::string message, data::array_t &out) {
template <class T>
void force_push_parse(const T &parser, std::string message, data::array_t &out) {
throw_ended(message);
bool success;
try {
success = push_parse(name, out);
success = push_parse(parser, out);
}
catch (const message_t &msg) {
ctx.messages.push(msg);
@ -131,12 +134,13 @@ namespace ppc::comp::tree::ast {
if (!success) err(message);
}
void force_parse(const std::string &name, std::string message, data::map_t &out) {
template <class T>
void force_parse(const T &parser, std::string message, data::map_t &out) {
throw_ended(message);
bool success;
try {
success = parse(name, out);
success = parse(parser, out);
}
catch (const message_t &msg) {
ctx.messages.push(msg);

View File

@ -79,28 +79,19 @@ namespace ppc::comp::tree {
NONE,
IDENTIFIER,
OPERATOR,
INT,
FLOAT,
CHAR,
STRING,
LITERAL,
} kind;
union data_t {
std::string *identifier;
operator_t _operator;
std::uint64_t int_literal;
double float_literal;
char char_literal;
std::vector<char> *string_literal;
std::vector<uint8_t> *literal;
} data;
public:
ppc::location_t location;
bool is_identifier() const { return kind == IDENTIFIER; }
bool is_operator() const { return kind == OPERATOR; }
bool is_int_lit() const { return kind == INT; }
bool is_float_lit() const { return kind == FLOAT; }
bool is_char_lit() const { return kind == CHAR; }
bool is_string_lit() const { return kind == STRING; }
bool is_literal() const { return kind == LITERAL; }
const auto &identifier() const {
if (!is_identifier()) throw std::string { "Token is not an identifier." };
@ -110,21 +101,9 @@ namespace ppc::comp::tree {
if (!is_operator()) throw std::string { "Token is not an operator." };
else return data._operator;
}
auto int_lit() const {
if (!is_int_lit()) throw std::string { "Token is not an int literal." };
else return data.int_literal;
}
auto float_lit() const {
if (!is_float_lit()) throw std::string { "Token is not a float literal." };
else return data.float_literal;
}
auto char_lit() const {
if (!is_char_lit()) throw std::string { "Token is not a char literal." };
else return data.char_literal;
}
const auto &string_lit() const {
if (!is_string_lit()) throw std::string { "Token is not a string literal." };
else return *data.string_literal;
const auto &literal() const {
if (!is_literal()) throw std::string { "Token is not a literal." };
else return *data.literal;
}
bool is_operator(operator_t op) const { return is_operator() && _operator() == op; }
@ -139,21 +118,9 @@ namespace ppc::comp::tree {
kind = OPERATOR;
data._operator = op;
}
token_t(std::uint64_t val, location_t loc = location_t::NONE): location(loc) {
kind = INT;
data.int_literal = val;
}
token_t(double val, location_t loc = location_t::NONE): location(loc) {
kind = FLOAT;
data.float_literal = val;
}
token_t(char c, location_t loc = location_t::NONE): location(loc) {
kind = CHAR;
data.char_literal = c;
}
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 };
token_t(const std::vector<uint8_t> &val, location_t loc = location_t::NONE): location(loc) {
kind = LITERAL;
data.literal = new std::vector<uint8_t> { val };
}
token_t(const token_t &tok): location(tok.location) {
kind = tok.kind;
@ -161,17 +128,14 @@ namespace ppc::comp::tree {
case NONE: break;
case IDENTIFIER: data.identifier = new std::string { *tok.data.identifier }; break;
case OPERATOR: data._operator = tok.data._operator; break;
case INT: data.int_literal = tok.data.int_literal; break;
case FLOAT: data.float_literal = tok.data.float_literal; break;
case CHAR: data.char_literal = tok.data.char_literal; break;
case STRING: data.string_literal = new std::vector<char> { *tok.data.string_literal }; break;
case LITERAL: data.literal = new std::vector<uint8_t> { *tok.data.literal }; break;
}
}
~token_t() {
switch (kind) {
case IDENTIFIER: delete data.identifier; break;
case STRING: delete data.string_literal; break;
case LITERAL: delete data.literal; break;
default: break;
}
}

View File

@ -1,59 +0,0 @@
#include "compiler/treeifier/ast.hh"
namespace ppc::comp::tree::ast {
std::unordered_map<std::string, group_parser_t> parsers;
const parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const {
auto it = parent->parsers.find(name);
if (it == parent->parsers.end()) throw "The parser '" + name + "' doesn't exist.";
return *it->second;
}
group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
auto it = parent->parsers.find(name);
if (it == parent->parsers.end()) {
auto p = new group_parser_t(name);
parent->parsers[name] = p;
parent->groups.emplace(p);
return *p;
}
else if (parent->groups.find((group_parser_t*)it->second) == parent->groups.end()) {
throw "A parser '" + name + "' exists, but isn't a group."s;
}
else {
return *(group_parser_t*)it->second;
}
}
ast_ctx_t::~ast_ctx_t() {
for (auto pair : parsers) {
delete pair.second;
}
}
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 parser_t *parser, const std::string &group) {
add_parser(parser);
this->group[group].add(*parser);
}
void ast_ctx_t::add_parser(const parser_t *parser, const std::string &group, const namespace_name_t &name) {
add_parser(parser);
this->group[group].add(*parser, name);
}
data::map_t ast_ctx_t::parse(msg_stack_t &messages, std::vector<token_t> &tokens) {
ast_ctx_t ctx(messages, tokens);
ctx.init();
size_t i = 0;
data::map_t res;
if (!ctx.parse("$_glob", i, res)) throw message_t::error("Failed to compile.");
return res;
}
bool ast_ctx_t::parse(std::string parser, size_t &pi, data::map_t &out) {
return this->parser[parser] (*this, pi, out);
}
}

View File

@ -0,0 +1,24 @@
#include "compiler/treeifier/ast.hh"
using namespace ppc;
using namespace ppc::data;
using namespace ppc::lang;
using namespace ppc::comp::tree::ast;
group_t &ast_ctx_t::group(const std::string &name) {
if (groups.find(name) == groups.end()) return groups[name] = { };
else return groups[name];
}
ast_ctx_t::ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens): messages(messages), tokens(tokens) {
group("$_exp_val")
.add_last("$_var", parse_exp_var)
.add_last("$_int", parse_exp_int_lit);
// .add_last("$_float", parse_exp_float_lit)
// .add_last("$_string", parse_exp_str_lit);
group("$_stat")
.add_last("$_exp", parse_stat_exp);
group("$_def")
.add_last("$_func", parse_func)
.add_last("$_field", parse_field);
}

View File

View File

@ -51,17 +51,16 @@ std::map<operator_t, op_data_t> bin_ops {
{ (operator_t)-1, sizeof_data },
};
class exp_parser_t : public parser_t {
map_t op_to_map(located_t<op_data_t> op) const {
map_t op_to_map(located_t<op_data_t> op) {
return {
{ "$_name", "$_operator" },
{ "ops", array_t() },
{ "location", conv::loc_to_map(op.location) },
{ "op", op.name },
};
}
}
bool pop(std::vector<located_t<op_data_t>> &op_stack, array_t &res) const {
bool pop(std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
if (op_stack.empty()) return false;
auto map = op_to_map(op_stack.back());
@ -86,8 +85,8 @@ class exp_parser_t : public parser_t {
res.push_back(map);
return true;
}
bool pop_paren(std::vector<located_t<op_data_t>> &op_stack, array_t &res) const {
}
bool pop_paren(std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
bool has_paren = false;
for (const auto &op : op_stack) {
if (op.precedence == precedence_t::PAREN) {
@ -104,8 +103,8 @@ class exp_parser_t : public parser_t {
op_stack.pop_back();
return true;
}
bool pop_call(size_t n, location_t loc, std::vector<located_t<op_data_t>> &op_stack, array_t &res) const {
}
bool pop_call(size_t n, location_t loc, std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
map_t call = {
{ "$_name", "$_call" },
};
@ -132,8 +131,8 @@ class exp_parser_t : public parser_t {
res.push_back(call);
return true;
}
bool pop_until(const op_data_t &data, tree_helper_t &h, std::vector<located_t<op_data_t>> &op_stack, array_t &res) const {
}
bool pop_until(const op_data_t &data, tree_helper_t &h, std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
while (!op_stack.empty()) {
auto &back_data = op_stack.back();
if (data.assoc ?
@ -144,9 +143,34 @@ class exp_parser_t : public parser_t {
if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator.");
}
return true;
}
bool ast::parse_exp_var(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.curr().is_identifier()) {
out["content"] = h.curr().identifier();
out["location"] = conv::loc_to_map(h.loc());
return h.submit(true);
}
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
return false;
}
bool ast::parse_exp_int_lit(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.curr().is_literal()) {
auto &arr = out["content"].array({});
for (auto b : h.curr().literal()) arr.push_back((float)b);
out["location"] = conv::loc_to_map(h.loc());
return h.submit(true);
}
return false;
}
bool ast::parse_exp(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
bool last_val = false;
@ -164,7 +188,7 @@ class exp_parser_t : public parser_t {
h.advance("Expected a value on the right side of the operator.");
continue;
}
if (!last_val && h.push_parse("$_exp_val", res)) last_val = true;
if (!last_val && h.push_parse(ctx.group("$_exp_val"), res)) last_val = true;
if (h.curr().is_operator()) {
auto op = h.curr()._operator();
if (last_val) {
@ -178,7 +202,7 @@ class exp_parser_t : public parser_t {
if (call_args_n.size() == 0) break;
h.advance("Expected an argument.");
pop_until({ precedence_t::CALL_START, .assoc = true }, h, op_stack, res);
pop_until({ .precedence = precedence_t::CALL_START, .assoc = true }, h, op_stack, res);
call_args_n.back()++;
last_val = false;
}
@ -204,26 +228,25 @@ class exp_parser_t : public parser_t {
}
else if (op == operator_t::COLON) {
h.advance("Expected a type.");
pop_until({ precedence_t::PREFIX, .assoc = true }, h, op_stack, res);
pop_until({ .precedence = precedence_t::PREFIX, .assoc = true }, h, op_stack, res);
map_t cast = {
{ "$_name", "$_cast" },
{ "exp", res.back() },
};
res.pop_back();
h.force_parse("$_type", "Expected a type.", cast["type"].map({}));
h.force_parse(parse_type, "Expected a type.", cast["type"].map({}));
res.push_back(cast);
}
else if (op == operator_t::DOT || op == operator_t::PTR_MEMBER) {
h.advance("Expected an identifier.");
pop_until({ precedence_t::POSTFIX, .assoc = true }, h, op_stack, res);
pop_until({ .precedence = precedence_t::POSTFIX, .assoc = true }, h, op_stack, res);
map_t member_access = {
{ "$_name", "$_member" },
{ "exp", res.back() },
{ "is_ptr", op == operator_t::PTR_MEMBER },
};
h.force_parse("$_identifier", "Expected an identifier.", member_access["name"].map({}));
h.force_parse(parse_identifier, "Expected an identifier.", member_access["name"].map({}));
member_access["location"] = conv::loc_to_map(
conv::map_to_loc(member_access["name"].map()["location"].string()).intersect(
conv::map_to_loc(res.back().map()["location"].string())
@ -277,25 +300,12 @@ class exp_parser_t : public parser_t {
out = res.front().map();
return h.submit(false);
}
public: exp_parser_t(): parser_t("$_exp") { }
};
class exp_stat_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &i, map_t &res) const {
}
bool ast::parse_stat_exp(ast_ctx_t &ctx, size_t &i, map_t &res) {
tree_helper_t h(ctx, i);
if (!h.parse("$_exp", res)) return false;
if (!h.parse(parse_exp, res)) return false;
if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
return h.submit(false);
}
public: exp_stat_parser_t() : parser_t("$_exp_stat") { }
};
const parser_adder_t ppc::comp::tree::ast::exp_adder = [](ast_ctx_t &ctx) {
ctx.add_parser(new exp_parser_t());
ctx.add_parser(new exp_stat_parser_t(), "$_stat");
};
}

View File

@ -1,12 +1,11 @@
#include "compiler/treeifier/ast/helper.hh"
class field_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
bool ast::parse_field(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
if (!h.parse("$_identifier", out["name"].map({}))) return false;
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
bool type, defval;
@ -14,12 +13,12 @@ class field_parser_t : public parser_t {
if (h.curr().is_operator(operator_t::COLON)) {
h.advance();
h.force_parse("$_type", "Expected a type.", out["type"].map({}));
h.force_parse(parse_type, "Expected a type.", out["type"].map({}));
type = true;
}
if (h.curr().is_operator(operator_t::ASSIGN)) {
h.advance();
h.force_parse("$_exp", "Expected an expression.", out["value"].map({}));
h.force_parse(parse_exp, "Expected an expression.", out["value"].map({}));
type = true;
}
@ -34,9 +33,4 @@ class field_parser_t : public parser_t {
else return false;
return h.submit(true);
}
public: field_parser_t(): parser_t("$_field") { }
};
const parser_adder_t ppc::comp::tree::ast::field_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new field_parser_t(), "$_def"); };
}

View File

@ -1,12 +1,11 @@
#include "compiler/treeifier/ast/helper.hh"
class arg_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
static bool parse_arg(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
if (!h.parse("$_identifier", out["name"].map({}))) return false;
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
bool type, defval;
@ -14,12 +13,12 @@ class arg_parser_t : public parser_t {
if (h.curr().is_operator(operator_t::COLON)) {
h.advance();
h.force_parse("$_type", "Expected a type.", out["type"].map({}));
h.force_parse(parse_type, "Expected a type.", out["type"].map({}));
type = true;
}
if (h.curr().is_operator(operator_t::ASSIGN)) {
h.advance();
h.force_parse("$_exp", "Expected an expression.", out["value"].map({}));
h.force_parse(parse_exp, "Expected an expression.", out["value"].map({}));
type = true;
}
@ -28,18 +27,14 @@ class arg_parser_t : public parser_t {
}
return h.submit(false);
}
}
public: arg_parser_t(): parser_t("$_func_arg") {}
};
class func_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
bool ast::parse_func(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
if (!h.parse("$_identifier", out["name"].map({}))) return false;
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
if (h.ended()) return false;
if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false;
h.advance("Expected a closing paren or a parameter.");
@ -52,7 +47,7 @@ class func_parser_t : public parser_t {
h.advance("Expected a function body.");
break;
}
h.force_push_parse("$_func_arg", "Expected a parameter.", params);
h.force_push_parse(parse_arg, "Expected a parameter.", params);
if (h.curr().is_operator(operator_t::COMMA)) {
h.advance("Expected a parameter.");
}
@ -60,14 +55,14 @@ class func_parser_t : public parser_t {
if (h.curr().is_operator(operator_t::COLON)) {
h.advance("Expected a type.");
h.force_parse("$_type", "Expected a type", out["type"].map({}));
h.force_parse(parse_type, "Expected a type", out["type"].map({}));
}
if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
else if (h.curr().is_operator(operator_t::LAMBDA)) {
h.advance("Expected an expression.");
map_t exp;
h.force_parse("$_exp", "Expected an expression.", exp);
h.force_parse(parse_exp, "Expected an expression.", exp);
content.push_back({
{ "$_name", "$_return" },
{ "content", exp },
@ -81,7 +76,7 @@ class func_parser_t : public parser_t {
return h.submit(true);
}
h.force_push_parse("$_stat", "Expected an expression.", content);
h.force_push_parse(ctx.group("$_stat"), "Expected an expression.", content);
}
}
else {
@ -90,12 +85,4 @@ class func_parser_t : public parser_t {
}
return h.submit(true);
}
public: func_parser_t(): parser_t("$_func") { }
};
const parser_adder_t ppc::comp::tree::ast::func_adder = [](ast_ctx_t &ctx) {
ctx.add_parser(new func_parser_t(), "$_def");
ctx.add_parser(new arg_parser_t());
};
}

View File

@ -1,53 +1,42 @@
#include "compiler/treeifier/ast.hh"
#include "compiler/treeifier/ast/helper.hh"
// #include "./type.cc"
using namespace ppc::comp::tree::ast;
class nmsp_def_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const {
static bool nmsp_def(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
if (!h.curr().is_identifier("namespace")) return false;
h.advance("Expected a namespace");
h.force_parse("$_nmsp", "Expected a namespace.", res);
h.force_parse(parse_nmsp, "Expected a namespace.", res);
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
return h.submit(false);
}
return h.submit(true);
}
public: nmsp_def_parser_t(): parser_t("$_nmsp") { }
};
class import_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const {
}
static bool import(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
if (!h.curr().is_identifier("import")) return false;
h.advance("Expected a namespace");
h.force_parse("$_nmsp", "Expected a namespace.", res);
h.force_parse(parse_nmsp, "Expected a namespace.", res);
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
return h.submit(false);
}
return h.submit(true);
}
}
public: import_parser_t(): parser_t("$_import") { }
};
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 {
bool ast::parse_glob(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return true;
if (nmsp_def_parser(ctx, h.i, out["namespace"].map({}))) {
if (h.parse(nmsp_def, out["namespace"].map({}))) {
ctx.nmsp = conv::map_to_nmsp(out["namespace"].map());
}
else {
@ -59,7 +48,7 @@ class glob_parser_t : public parser_t {
while (true) {
map_t map;
if (!import_parser(ctx, h.i, map)) break;
if (!h.parse(import, map)) break;
imports.push_back(map);
auto nmsp = conv::map_to_nmsp(map);
@ -68,7 +57,7 @@ class glob_parser_t : public parser_t {
while (true) {
if (h.ended()) break;
if (!h.push_parse("$_def", contents)) {
if (!h.push_parse(ctx.group("$_def"), contents)) {
ctx.messages.push(message_t::error("Invalid token.", h.loc()));
h.i++;
}
@ -77,12 +66,4 @@ class glob_parser_t : public parser_t {
if (!h.ended()) h.err("Invalid token.");
return h.submit();
}
public:
glob_parser_t(): parser_t("$_glob") { }
};
const parser_adder_t ppc::comp::tree::ast::glob_adder = [](ast_ctx_t &ctx) {
ctx.add_parser(new glob_parser_t());
};
}

View File

@ -13,7 +13,7 @@ using namespace std;
static bool read_nmsp(ast_ctx_t &ctx, size_t &i, lang::loc_namespace_name_t &name) {
tree_helper_t h(ctx, i);
map_t res;
if (!h.parse("$_nmsp", res)) return false;
if (!h.parse(parse_nmsp, res)) return false;
name = conv::map_to_nmsp(res);
return true;
}
@ -40,8 +40,48 @@ static bool resolve_nmsp(ast_ctx_t &ctx, const lang::namespace_name_t &name, T b
return false;
}
group_t &group_t::insert(const std::string &name, parser_t parser, const std::string &relative_to, bool after) {
if (parsers.find(name) != parsers.end()) {
throw "The parser '" + name + "' is already in the group.";
}
bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
auto it = parsers.find(relative_to);
if (it == parsers.end()) {
throw "The parser '" + relative_to + "' isn't in the group.";
}
if (after) it++;
parsers.insert(it, { name, parser });
return *this;
}
group_t &group_t::replace(const std::string &name, parser_t parser) {
auto it = parsers.find(name);
if (parsers.find(name) == parsers.end()) {
throw "The parser '" + name + "' isn't in the group.";
}
it->second = parser;
return *this;
}
group_t &group_t::add_last(const std::string &name, parser_t parser) {
if (parsers.find(name) != parsers.end()) {
throw "The parser '" + name + "' is already in the group.";
}
parsers.emplace(name, parser);
return *this;
}
group_t &group_t::add_named(const std::string &name, parser_t parser, const lang::namespace_name_t &identifier) {
add_last(name, parser);
return *this;
}
bool group_t::operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
tree_helper_t h(ctx, i);
if (h.ended()) return false;
@ -50,8 +90,9 @@ bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
if (read_nmsp(ctx, h.i, name)) {
namespace_name_t actual;
if (resolve_nmsp(ctx, name.strip_location(), named_parsers.begin(), named_parsers.end(), actual)) {
auto &parser = *this->named_parsers.find(actual)->second;
if (parser(ctx, i, out)) return true;
auto parser = parsers.find(this->named_parsers.find(actual)->second);
out["$_name"] = parser->first;
if (parser->second(ctx, i, out)) return true;
else throw message_t::error("Unexpected construct specifier.", h.res_loc());
}
}
@ -59,25 +100,11 @@ bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
unordered_map<string, message_t> errors;
for (auto parser : parsers) {
if ((*parser)(ctx, i, out)) return true;
out["$_name"] = parser.first;
if ((*parser.second)(ctx, i, out)) return true;
}
stringstream m;
return false;
}
group_parser_t &group_parser_t::add(const parser_t &parser) {
parsers.push_back(&parser);
return *this;
}
group_parser_t &group_parser_t::add(const parser_t &parser, const lang::namespace_name_t &name) {
if (name.empty()) throw "Name can't be empty."s;
if (std::find(parsers.begin(), parsers.end(), &parser) != parsers.end()) {
throw "Parser '" + name.to_string() + "' already in group.";
}
named_parsers[name] = &parser;
return *this;
}

View File

@ -1,7 +1,6 @@
#include "compiler/treeifier/ast/helper.hh"
class identifier_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
bool ast::parse_identifier(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
@ -13,9 +12,4 @@ class identifier_parser_t : public parser_t {
return h.submit();
}
else return false;
}
public: identifier_parser_t(): parser_t("$_identifier") { }
};
const parser_adder_t ppc::comp::tree::ast::identifier_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new identifier_parser_t()); };
}

View File

@ -1,26 +1,20 @@
#include "compiler/treeifier/ast/helper.hh"
class nmsp_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
bool ast::parse_nmsp(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
auto &arr = (out["content"] = array_t()).array();
if (!h.push_parse("$_identifier", arr)) return false;
if (!h.push_parse(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", "Expected an identifier.", arr);
h.force_push_parse(parse_identifier, "Expected an identifier.", arr);
}
out["location"] = conv::loc_to_map(h.res_loc());
return h.submit(false);
}
public: nmsp_parser_t(): parser_t("$_nmsp") { }
};
const parser_adder_t ppc::comp::tree::ast::nmsp_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new nmsp_parser_t()); };
}

View File

@ -1,7 +1,6 @@
#include "compiler/treeifier/ast/helper.hh"
class type_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
bool ast::parse_type(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
tree_helper_t h(ctx, res_i);
if (h.ended()) return false;
@ -11,13 +10,13 @@ class type_parser_t : public parser_t {
auto &nmsp_content = (out["namespace"].map()["content"] = array_t()).array();
size_t ptr_n = 0;
if (!h.push_parse("$_identifier", nmsp_content)) return false;
if (!h.push_parse(parse_identifier, nmsp_content)) return false;
while (true) {
if (h.ended()) break;
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
h.advance("Expected an identifier.");
h.force_push_parse("$_identifier", "Expected an identifier.", nmsp_content);
h.force_push_parse(parse_identifier, "Expected an identifier.", nmsp_content);
}
while (!h.ended() && h.curr().is_operator(operator_t::MULTIPLY)) {
@ -43,9 +42,4 @@ class type_parser_t : public parser_t {
}
return h.submit(false);
}
public: type_parser_t(): parser_t("$_type") { }
};
const parser_adder_t ppc::comp::tree::ast::type_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new type_parser_t()); };
}

View File

@ -1,19 +0,0 @@
#include "compiler/treeifier/ast/helper.hh"
class var_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
tree_helper_t h(ctx, res_i);
if (h.curr().is_identifier()) {
out["content"] = h.curr().identifier();
out["location"] = conv::loc_to_map(h.loc());
return h.submit(true);
}
return false;
}
public: var_parser_t(): parser_t("$_var") { }
};
const parser_adder_t ppc::comp::tree::ast::var_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new var_parser_t(), "$_exp_val"); };

View File

@ -1,4 +1,5 @@
#include <string>
#include <algorithm>
#include "compiler/treeifier/tokenizer.hh"
#include "compiler/treeifier/lexer.hh"
@ -7,12 +8,12 @@ using namespace messages;
using namespace comp::tree;
using namespace std::string_literals;
static std::vector<char> parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) {
static std::vector<uint8_t> parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) {
char literal_char = is_char ? '\'' : '"';
bool escaping = false;
std::vector<char> res;
std::vector<uint8_t> res;
location_t curr_char_loc = token.location;
curr_char_loc.length = 1;
curr_char_loc.start++;
@ -52,96 +53,99 @@ static std::vector<char> parse_string(msg_stack_t &msg_stack, bool is_char, cons
if (is_char) throw message_t(message_t::ERROR, "Unterminated char literal.", token.location);
else throw message_t(message_t::ERROR, "Unterminated string literal.", token.location);
}
static token_t parse_int(msg_stack_t &msg_stack, const lex::token_t &token) {
enum radix_t {
BINARY,
OCTAL,
DECIMAL,
HEXADECIMAL,
} radix;
std::size_t i = 0;
static std::vector<uint8_t> parse_bin(msg_stack_t &msg_stack, size_t i, const std::string &data) {
std::vector<uint8_t> res;
int last_byte = 0;
int lastbyte_n = 0;
for (size_t j = data.length() - 1; j >= i; j--) {
if (lastbyte_n == 8) {
lastbyte_n = 0;
res.push_back(last_byte);
last_byte = 0;
}
last_byte <<= 1;
last_byte |= data[j] - '0';
lastbyte_n++;
}
res.push_back(last_byte);
std::reverse(res.begin(), res.end());
return res;
}
static std::vector<uint8_t> parse_hex(msg_stack_t &msg_stack, size_t i, const std::string &data) {
std::vector<uint8_t> res;
int last_byte = 0;
int lastbyte_n = 0;
for (size_t j = data.length() - 1; j >= i; j--) {
if (lastbyte_n == 8) {
lastbyte_n = 0;
res.push_back(last_byte);
last_byte = 0;
}
int digit = data[j] - '0';
if (data[j] >= 'a' && data[j] <= 'f') digit = data[j] - 'a' + 10;
if (data[j] >= 'A' && data[j] <= 'F') digit = data[j] - 'F' + 10;
last_byte <<= 4;
last_byte |= digit;
lastbyte_n += 4;
}
res.push_back(last_byte);
std::reverse(res.begin(), res.end());
return res;
}
static std::vector<uint8_t> parse_oct(msg_stack_t &msg_stack, size_t i, const std::string &data) {
std::vector<uint8_t> res;
int last_byte = 0;
int lastbyte_n = 0;
for (size_t j = data.length() - 1; j >= i; j--) {
if (lastbyte_n >= 8) {
lastbyte_n = 0;
res.push_back(last_byte);
last_byte >>= 8;
}
int digit = data[j] - '0';
last_byte <<= 3;
last_byte |= digit;
lastbyte_n += 3;
}
res.push_back(last_byte);
std::reverse(res.begin(), res.end());
return res;
}
static std::vector<uint8_t> parse_int(msg_stack_t &msg_stack, const lex::token_t &token) {
switch (token.type) {
case lex::token_t::BIN_LITERAL:
i += 2;
radix = BINARY;
break;
return parse_bin(msg_stack, 2, token.data);
case lex::token_t::OCT_LITERAL:
i++;
radix = OCTAL;
break;
return parse_oct(msg_stack, 1, token.data);
case lex::token_t::DEC_LITERAL:
radix = DECIMAL;
break;
throw "no dec literals lol bozo."s;
case lex::token_t::HEX_LITERAL:
i += 2;
radix = HEXADECIMAL;
break;
return parse_hex(msg_stack, 2, token.data);
default:
throw "WTF r u doing bro?"s;
}
uint64_t res = 0;
for (; i <= token.data.length() - 1; i++) {
char c = token.data[i];
int8_t digit;
switch (radix) {
case BINARY:
digit = c - '0';
res <<= 1;
res |= digit;
break;
case OCTAL:
digit = c - '0';
if (digit < 0 || digit > 7) {
throw message_t(message_t::ERROR, "Octal literals may contain numbers between 0 and 7.", token.location);
}
res <<= 3;
res |= digit;
break;
case 2:
digit = c - '0';
res *= 10;
res += digit;
break;
case 3:
if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
else if (c >= '0' && c <= '9') digit = c - '0';
else throw message_t(message_t::ERROR, "Invalid character '"s + c + "' in hex literal.", token.location);
res <<= 4;
res |= digit;
break;
}
}
return token_t(res, token.location);
}
static token_t parse_float(msg_stack_t &msg_stack, const lex::token_t &token) {
double whole = 0, fract = 0;
char c;
std::size_t i;
for (i = 0; i < token.data.length() && isdigit(c = token.data[i]); i++) {
if (c == '.') break;
int digit = c - '0';
whole *= 10;
whole += digit;
}
if (c == '.') {
i++;
for (; i < token.data.length() && isdigit(c = token.data[i]); i++) {
int digit = c - '0';
fract += digit;
fract /= 10;
}
}
return token_t(whole + fract, token.location);
static std::vector<uint8_t> parse_float(msg_stack_t &msg_stack, const lex::token_t &token) {
throw "no floats lol bozo"s;
}
token_t token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) {
@ -160,16 +164,13 @@ token_t token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) {
case lex::token_t::OCT_LITERAL:
case lex::token_t::DEC_LITERAL:
case lex::token_t::HEX_LITERAL:
return parse_int(msg_stack, in);
return { parse_int(msg_stack, in), in.location };
case lex::token_t::FLOAT_LITERAL:
return parse_float(msg_stack, in);
return { parse_float(msg_stack, in), in.location };
case lex::token_t::STRING_LITERAL:
return { parse_string(msg_stack, false, in) };
case lex::token_t::CHAR_LITERAL: {
auto str = parse_string(msg_stack, true, in);
if (str.size() != 1) throw message_t(message_t::ERROR, "Char literal must consist of just one character.", in.location);
return str.front();
}
return { parse_string(msg_stack, false, in), in.location };
case lex::token_t::CHAR_LITERAL:
return { parse_string(msg_stack, true, in), in.location };
default:
throw message_t(message_t::ERROR, "Token type not recognised.", in.location);
}

View File

@ -157,7 +157,7 @@ int main(int argc, const char *argv[]) {
try {
std::ifstream f { file, std::ios_base::in };
auto tokens = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f));
auto ast = ast_ctx_t::parse(msg_stack, tokens);
auto ast = ast_ctx_t::parse(ast::parse_glob, msg_stack, tokens);
std::cout << data::json::stringify(ast) << std::endl;
}