chore: recoded ast system with ptr functions
This commit is contained in:
parent
d7ee0e3bb2
commit
662442121d
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
|||||||
export MAKEFLAGS += --silent -r -j
|
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 ldflags=-L$(bin)/$(profile)
|
||||||
export lib=ppc$(version-major)-
|
export lib=ppc$(version-major)-
|
||||||
export profile=release
|
export profile=release
|
||||||
|
@ -15,111 +15,52 @@ using namespace ppc::lang;
|
|||||||
using namespace ppc::messages;
|
using namespace ppc::messages;
|
||||||
|
|
||||||
namespace ppc::comp::tree::ast {
|
namespace ppc::comp::tree::ast {
|
||||||
class parser_t;
|
|
||||||
class group_parser_t;
|
|
||||||
struct ast_ctx_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;
|
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
|
||||||
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;
|
|
||||||
|
|
||||||
struct ast_ctx_t {
|
struct ast_ctx_t {
|
||||||
private:
|
private:
|
||||||
struct parser_proxy_t {
|
std::unordered_map<std::string, group_t> groups;
|
||||||
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;
|
|
||||||
public:
|
public:
|
||||||
msg_stack_t &messages;
|
msg_stack_t &messages;
|
||||||
std::vector<token_t> &tokens;
|
std::vector<token_t> &tokens;
|
||||||
std::set<loc_namespace_name_t> imports;
|
std::set<loc_namespace_name_t> imports;
|
||||||
loc_namespace_name_t nmsp;
|
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;
|
ast_ctx_t &operator=(const ast_ctx_t &other) = delete;
|
||||||
|
|
||||||
const parser_proxy_t parser;
|
template <class T>
|
||||||
const group_proxy_t group;
|
bool parse(const T &parser, size_t &i, data::map_t &out) {
|
||||||
|
return parser(*this, i, out);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(std::string parser, size_t &pi, data::map_t &out);
|
group_t &group(const std::string &name);
|
||||||
static data::map_t parse(msg_stack_t &messages, std::vector<token_t> &tokens);
|
|
||||||
|
|
||||||
~ast_ctx_t();
|
template <class T>
|
||||||
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens):
|
static data::map_t parse(const T &glob, msg_stack_t &messages, std::vector<token_t> &tokens) {
|
||||||
messages(messages),
|
ast_ctx_t ctx(messages, tokens);
|
||||||
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 {
|
|
||||||
data::map_t res;
|
data::map_t res;
|
||||||
out["$_name"] = _name;
|
size_t i = 0;
|
||||||
return parse(ctx, i, out);
|
|
||||||
|
if (!ctx.parse(glob, i, res)) throw message_t::error("Failed to compile.");
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~parser_t() = default;
|
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens);
|
||||||
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) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace conv {
|
namespace conv {
|
||||||
@ -132,4 +73,7 @@ namespace ppc::comp::tree::ast {
|
|||||||
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp);
|
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp);
|
||||||
loc_namespace_name_t map_to_nmsp(const data::map_t &map);
|
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;
|
||||||
}
|
}
|
@ -104,25 +104,28 @@ namespace ppc::comp::tree::ast {
|
|||||||
throw_ended(reason);
|
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;
|
data::map_t res;
|
||||||
if (parse(name, res)) {
|
if (parse(parser, res)) {
|
||||||
out.push_back(res);
|
out.push_back(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const std::string &name, data::map_t &out) {
|
template <class T>
|
||||||
return ctx.parse(name, i, out);
|
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);
|
throw_ended(message);
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
success = push_parse(name, out);
|
success = push_parse(parser, out);
|
||||||
}
|
}
|
||||||
catch (const message_t &msg) {
|
catch (const message_t &msg) {
|
||||||
ctx.messages.push(msg);
|
ctx.messages.push(msg);
|
||||||
@ -131,12 +134,13 @@ namespace ppc::comp::tree::ast {
|
|||||||
|
|
||||||
if (!success) err(message);
|
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);
|
throw_ended(message);
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
success = parse(name, out);
|
success = parse(parser, out);
|
||||||
}
|
}
|
||||||
catch (const message_t &msg) {
|
catch (const message_t &msg) {
|
||||||
ctx.messages.push(msg);
|
ctx.messages.push(msg);
|
||||||
|
@ -79,28 +79,19 @@ namespace ppc::comp::tree {
|
|||||||
NONE,
|
NONE,
|
||||||
IDENTIFIER,
|
IDENTIFIER,
|
||||||
OPERATOR,
|
OPERATOR,
|
||||||
INT,
|
LITERAL,
|
||||||
FLOAT,
|
|
||||||
CHAR,
|
|
||||||
STRING,
|
|
||||||
} kind;
|
} kind;
|
||||||
union data_t {
|
union data_t {
|
||||||
std::string *identifier;
|
std::string *identifier;
|
||||||
operator_t _operator;
|
operator_t _operator;
|
||||||
std::uint64_t int_literal;
|
std::vector<uint8_t> *literal;
|
||||||
double float_literal;
|
|
||||||
char char_literal;
|
|
||||||
std::vector<char> *string_literal;
|
|
||||||
} data;
|
} data;
|
||||||
public:
|
public:
|
||||||
ppc::location_t location;
|
ppc::location_t location;
|
||||||
|
|
||||||
bool is_identifier() const { return kind == IDENTIFIER; }
|
bool is_identifier() const { return kind == IDENTIFIER; }
|
||||||
bool is_operator() const { return kind == OPERATOR; }
|
bool is_operator() const { return kind == OPERATOR; }
|
||||||
bool is_int_lit() const { return kind == INT; }
|
bool is_literal() const { return kind == LITERAL; }
|
||||||
bool is_float_lit() const { return kind == FLOAT; }
|
|
||||||
bool is_char_lit() const { return kind == CHAR; }
|
|
||||||
bool is_string_lit() const { return kind == STRING; }
|
|
||||||
|
|
||||||
const auto &identifier() const {
|
const auto &identifier() const {
|
||||||
if (!is_identifier()) throw std::string { "Token is not an identifier." };
|
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." };
|
if (!is_operator()) throw std::string { "Token is not an operator." };
|
||||||
else return data._operator;
|
else return data._operator;
|
||||||
}
|
}
|
||||||
auto int_lit() const {
|
const auto &literal() const {
|
||||||
if (!is_int_lit()) throw std::string { "Token is not an int literal." };
|
if (!is_literal()) throw std::string { "Token is not a literal." };
|
||||||
else return data.int_literal;
|
else return *data.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_operator(operator_t op) const { return is_operator() && _operator() == op; }
|
bool is_operator(operator_t op) const { return is_operator() && _operator() == op; }
|
||||||
@ -139,21 +118,9 @@ namespace ppc::comp::tree {
|
|||||||
kind = OPERATOR;
|
kind = OPERATOR;
|
||||||
data._operator = op;
|
data._operator = op;
|
||||||
}
|
}
|
||||||
token_t(std::uint64_t val, location_t loc = location_t::NONE): location(loc) {
|
token_t(const std::vector<uint8_t> &val, location_t loc = location_t::NONE): location(loc) {
|
||||||
kind = INT;
|
kind = LITERAL;
|
||||||
data.int_literal = val;
|
data.literal = new std::vector<uint8_t> { 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 token_t &tok): location(tok.location) {
|
token_t(const token_t &tok): location(tok.location) {
|
||||||
kind = tok.kind;
|
kind = tok.kind;
|
||||||
@ -161,17 +128,14 @@ namespace ppc::comp::tree {
|
|||||||
case NONE: break;
|
case NONE: break;
|
||||||
case IDENTIFIER: data.identifier = new std::string { *tok.data.identifier }; break;
|
case IDENTIFIER: data.identifier = new std::string { *tok.data.identifier }; break;
|
||||||
case OPERATOR: data._operator = tok.data._operator; break;
|
case OPERATOR: data._operator = tok.data._operator; break;
|
||||||
case INT: data.int_literal = tok.data.int_literal; break;
|
case LITERAL: data.literal = new std::vector<uint8_t> { *tok.data.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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~token_t() {
|
~token_t() {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case IDENTIFIER: delete data.identifier; break;
|
case IDENTIFIER: delete data.identifier; break;
|
||||||
case STRING: delete data.string_literal; break;
|
case LITERAL: delete data.literal; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
24
src/compiler/treeifier/ast/ast.cc
Normal file
24
src/compiler/treeifier/ast/ast.cc
Normal 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);
|
||||||
|
}
|
0
src/compiler/treeifier/ast/parsers.cc
Normal file
0
src/compiler/treeifier/ast/parsers.cc
Normal file
@ -51,8 +51,7 @@ std::map<operator_t, op_data_t> bin_ops {
|
|||||||
{ (operator_t)-1, sizeof_data },
|
{ (operator_t)-1, sizeof_data },
|
||||||
};
|
};
|
||||||
|
|
||||||
class exp_parser_t : public parser_t {
|
map_t op_to_map(located_t<op_data_t> op) {
|
||||||
map_t op_to_map(located_t<op_data_t> op) const {
|
|
||||||
return {
|
return {
|
||||||
{ "$_name", "$_operator" },
|
{ "$_name", "$_operator" },
|
||||||
{ "ops", array_t() },
|
{ "ops", array_t() },
|
||||||
@ -61,7 +60,7 @@ class exp_parser_t : public parser_t {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
if (op_stack.empty()) return false;
|
||||||
|
|
||||||
auto map = op_to_map(op_stack.back());
|
auto map = op_to_map(op_stack.back());
|
||||||
@ -87,7 +86,7 @@ class exp_parser_t : public parser_t {
|
|||||||
|
|
||||||
return true;
|
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;
|
bool has_paren = false;
|
||||||
for (const auto &op : op_stack) {
|
for (const auto &op : op_stack) {
|
||||||
if (op.precedence == precedence_t::PAREN) {
|
if (op.precedence == precedence_t::PAREN) {
|
||||||
@ -105,7 +104,7 @@ class exp_parser_t : public parser_t {
|
|||||||
op_stack.pop_back();
|
op_stack.pop_back();
|
||||||
return true;
|
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 = {
|
map_t call = {
|
||||||
{ "$_name", "$_call" },
|
{ "$_name", "$_call" },
|
||||||
};
|
};
|
||||||
@ -133,7 +132,7 @@ class exp_parser_t : public parser_t {
|
|||||||
|
|
||||||
return true;
|
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()) {
|
while (!op_stack.empty()) {
|
||||||
auto &back_data = op_stack.back();
|
auto &back_data = op_stack.back();
|
||||||
if (data.assoc ?
|
if (data.assoc ?
|
||||||
@ -146,7 +145,32 @@ class exp_parser_t : public parser_t {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
bool last_val = false;
|
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.");
|
h.advance("Expected a value on the right side of the operator.");
|
||||||
continue;
|
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()) {
|
if (h.curr().is_operator()) {
|
||||||
auto op = h.curr()._operator();
|
auto op = h.curr()._operator();
|
||||||
if (last_val) {
|
if (last_val) {
|
||||||
@ -178,7 +202,7 @@ class exp_parser_t : public parser_t {
|
|||||||
if (call_args_n.size() == 0) break;
|
if (call_args_n.size() == 0) break;
|
||||||
h.advance("Expected an argument.");
|
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()++;
|
call_args_n.back()++;
|
||||||
last_val = false;
|
last_val = false;
|
||||||
}
|
}
|
||||||
@ -204,26 +228,25 @@ class exp_parser_t : public parser_t {
|
|||||||
}
|
}
|
||||||
else if (op == operator_t::COLON) {
|
else if (op == operator_t::COLON) {
|
||||||
h.advance("Expected a type.");
|
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 = {
|
map_t cast = {
|
||||||
{ "$_name", "$_cast" },
|
{ "$_name", "$_cast" },
|
||||||
{ "exp", res.back() },
|
{ "exp", res.back() },
|
||||||
};
|
};
|
||||||
|
|
||||||
res.pop_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);
|
res.push_back(cast);
|
||||||
}
|
}
|
||||||
else if (op == operator_t::DOT || op == operator_t::PTR_MEMBER) {
|
else if (op == operator_t::DOT || op == operator_t::PTR_MEMBER) {
|
||||||
h.advance("Expected an identifier.");
|
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 = {
|
map_t member_access = {
|
||||||
{ "$_name", "$_member" },
|
|
||||||
{ "exp", res.back() },
|
{ "exp", res.back() },
|
||||||
{ "is_ptr", op == operator_t::PTR_MEMBER },
|
{ "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(
|
member_access["location"] = conv::loc_to_map(
|
||||||
conv::map_to_loc(member_access["name"].map()["location"].string()).intersect(
|
conv::map_to_loc(member_access["name"].map()["location"].string()).intersect(
|
||||||
conv::map_to_loc(res.back().map()["location"].string())
|
conv::map_to_loc(res.back().map()["location"].string())
|
||||||
@ -278,24 +301,11 @@ class exp_parser_t : public parser_t {
|
|||||||
|
|
||||||
return h.submit(false);
|
return h.submit(false);
|
||||||
}
|
}
|
||||||
|
bool ast::parse_stat_exp(ast_ctx_t &ctx, size_t &i, map_t &res) {
|
||||||
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 {
|
|
||||||
tree_helper_t h(ctx, i);
|
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);
|
if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
|
||||||
|
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
||||||
return h.submit(false);
|
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");
|
|
||||||
};
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
class field_parser_t : public parser_t {
|
bool ast::parse_field(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
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;
|
bool type, defval;
|
||||||
|
|
||||||
@ -14,12 +13,12 @@ class field_parser_t : public parser_t {
|
|||||||
|
|
||||||
if (h.curr().is_operator(operator_t::COLON)) {
|
if (h.curr().is_operator(operator_t::COLON)) {
|
||||||
h.advance();
|
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;
|
type = true;
|
||||||
}
|
}
|
||||||
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
||||||
h.advance();
|
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;
|
type = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +34,3 @@ class field_parser_t : public parser_t {
|
|||||||
|
|
||||||
return h.submit(true);
|
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"); };
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
class arg_parser_t : public parser_t {
|
static bool parse_arg(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
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;
|
bool type, defval;
|
||||||
|
|
||||||
@ -14,12 +13,12 @@ class arg_parser_t : public parser_t {
|
|||||||
|
|
||||||
if (h.curr().is_operator(operator_t::COLON)) {
|
if (h.curr().is_operator(operator_t::COLON)) {
|
||||||
h.advance();
|
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;
|
type = true;
|
||||||
}
|
}
|
||||||
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
||||||
h.advance();
|
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;
|
type = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,16 +29,12 @@ class arg_parser_t : public parser_t {
|
|||||||
return h.submit(false);
|
return h.submit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public: arg_parser_t(): parser_t("$_func_arg") {}
|
bool ast::parse_func(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
||||||
};
|
|
||||||
|
|
||||||
class func_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);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
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.ended()) return false;
|
||||||
if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false;
|
if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false;
|
||||||
h.advance("Expected a closing paren or a parameter.");
|
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.");
|
h.advance("Expected a function body.");
|
||||||
break;
|
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)) {
|
if (h.curr().is_operator(operator_t::COMMA)) {
|
||||||
h.advance("Expected a parameter.");
|
h.advance("Expected a parameter.");
|
||||||
}
|
}
|
||||||
@ -60,14 +55,14 @@ class func_parser_t : public parser_t {
|
|||||||
|
|
||||||
if (h.curr().is_operator(operator_t::COLON)) {
|
if (h.curr().is_operator(operator_t::COLON)) {
|
||||||
h.advance("Expected a type.");
|
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);
|
if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
|
||||||
else if (h.curr().is_operator(operator_t::LAMBDA)) {
|
else if (h.curr().is_operator(operator_t::LAMBDA)) {
|
||||||
h.advance("Expected an expression.");
|
h.advance("Expected an expression.");
|
||||||
map_t exp;
|
map_t exp;
|
||||||
h.force_parse("$_exp", "Expected an expression.", exp);
|
h.force_parse(parse_exp, "Expected an expression.", exp);
|
||||||
content.push_back({
|
content.push_back({
|
||||||
{ "$_name", "$_return" },
|
{ "$_name", "$_return" },
|
||||||
{ "content", exp },
|
{ "content", exp },
|
||||||
@ -81,7 +76,7 @@ class func_parser_t : public parser_t {
|
|||||||
return h.submit(true);
|
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 {
|
else {
|
||||||
@ -91,11 +86,3 @@ class func_parser_t : public parser_t {
|
|||||||
|
|
||||||
return h.submit(true);
|
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());
|
|
||||||
};
|
|
||||||
|
@ -1,33 +1,29 @@
|
|||||||
#include "compiler/treeifier/ast.hh"
|
#include "compiler/treeifier/ast.hh"
|
||||||
#include "compiler/treeifier/ast/helper.hh"
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
// #include "./type.cc"
|
||||||
|
|
||||||
using namespace ppc::comp::tree::ast;
|
using namespace ppc::comp::tree::ast;
|
||||||
|
|
||||||
class nmsp_def_parser_t : public parser_t {
|
static bool nmsp_def(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
if (h.ended()) return false;
|
if (h.ended()) return false;
|
||||||
|
|
||||||
if (!h.curr().is_identifier("namespace")) return false;
|
if (!h.curr().is_identifier("namespace")) return false;
|
||||||
h.advance("Expected a namespace");
|
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)) {
|
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
||||||
return h.submit(false);
|
return h.submit(false);
|
||||||
}
|
}
|
||||||
return h.submit(true);
|
return h.submit(true);
|
||||||
}
|
}
|
||||||
|
static bool import(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) {
|
||||||
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 {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
if (h.ended()) return false;
|
if (h.ended()) return false;
|
||||||
|
|
||||||
if (!h.curr().is_identifier("import")) return false;
|
if (!h.curr().is_identifier("import")) return false;
|
||||||
h.advance("Expected a namespace");
|
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)) {
|
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
||||||
return h.submit(false);
|
return h.submit(false);
|
||||||
@ -36,18 +32,11 @@ class import_parser_t : public parser_t {
|
|||||||
return h.submit(true);
|
return h.submit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public: import_parser_t(): parser_t("$_import") { }
|
bool ast::parse_glob(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) {
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return true;
|
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());
|
ctx.nmsp = conv::map_to_nmsp(out["namespace"].map());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -59,7 +48,7 @@ class glob_parser_t : public parser_t {
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
map_t map;
|
map_t map;
|
||||||
if (!import_parser(ctx, h.i, map)) break;
|
if (!h.parse(import, map)) break;
|
||||||
imports.push_back(map);
|
imports.push_back(map);
|
||||||
auto nmsp = conv::map_to_nmsp(map);
|
auto nmsp = conv::map_to_nmsp(map);
|
||||||
|
|
||||||
@ -68,7 +57,7 @@ class glob_parser_t : public parser_t {
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (h.ended()) break;
|
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()));
|
ctx.messages.push(message_t::error("Invalid token.", h.loc()));
|
||||||
h.i++;
|
h.i++;
|
||||||
}
|
}
|
||||||
@ -78,11 +67,3 @@ class glob_parser_t : public parser_t {
|
|||||||
|
|
||||||
return h.submit();
|
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());
|
|
||||||
};
|
|
||||||
|
@ -13,7 +13,7 @@ using namespace std;
|
|||||||
static bool read_nmsp(ast_ctx_t &ctx, size_t &i, lang::loc_namespace_name_t &name) {
|
static bool read_nmsp(ast_ctx_t &ctx, size_t &i, lang::loc_namespace_name_t &name) {
|
||||||
tree_helper_t h(ctx, i);
|
tree_helper_t h(ctx, i);
|
||||||
map_t res;
|
map_t res;
|
||||||
if (!h.parse("$_nmsp", res)) return false;
|
if (!h.parse(parse_nmsp, res)) return false;
|
||||||
name = conv::map_to_nmsp(res);
|
name = conv::map_to_nmsp(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -40,8 +40,48 @@ static bool resolve_nmsp(ast_ctx_t &ctx, const lang::namespace_name_t &name, T b
|
|||||||
return false;
|
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);
|
tree_helper_t h(ctx, i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
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)) {
|
if (read_nmsp(ctx, h.i, name)) {
|
||||||
namespace_name_t actual;
|
namespace_name_t actual;
|
||||||
if (resolve_nmsp(ctx, name.strip_location(), named_parsers.begin(), named_parsers.end(), actual)) {
|
if (resolve_nmsp(ctx, name.strip_location(), named_parsers.begin(), named_parsers.end(), actual)) {
|
||||||
auto &parser = *this->named_parsers.find(actual)->second;
|
auto parser = parsers.find(this->named_parsers.find(actual)->second);
|
||||||
if (parser(ctx, i, out)) return true;
|
out["$_name"] = parser->first;
|
||||||
|
if (parser->second(ctx, i, out)) return true;
|
||||||
else throw message_t::error("Unexpected construct specifier.", h.res_loc());
|
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;
|
unordered_map<string, message_t> errors;
|
||||||
|
|
||||||
for (auto parser : parsers) {
|
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;
|
stringstream m;
|
||||||
|
|
||||||
return false;
|
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;
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
class identifier_parser_t : public parser_t {
|
bool ast::parse_identifier(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
if (h.ended()) return false;
|
||||||
@ -14,8 +13,3 @@ class identifier_parser_t : public parser_t {
|
|||||||
}
|
}
|
||||||
else return false;
|
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()); };
|
|
||||||
|
@ -1,26 +1,20 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
class nmsp_parser_t : public parser_t {
|
bool ast::parse_nmsp(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
if (h.ended()) return false;
|
||||||
|
|
||||||
auto &arr = (out["content"] = array_t()).array();
|
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) {
|
while (true) {
|
||||||
if (h.ended()) break;
|
if (h.ended()) break;
|
||||||
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) 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());
|
out["location"] = conv::loc_to_map(h.res_loc());
|
||||||
return h.submit(false);
|
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()); };
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
class type_parser_t : public parser_t {
|
bool ast::parse_type(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
if (h.ended()) return false;
|
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();
|
auto &nmsp_content = (out["namespace"].map()["content"] = array_t()).array();
|
||||||
size_t ptr_n = 0;
|
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) {
|
while (true) {
|
||||||
if (h.ended()) break;
|
if (h.ended()) break;
|
||||||
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
|
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
|
||||||
h.advance("Expected an identifier.");
|
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)) {
|
while (!h.ended() && h.curr().is_operator(operator_t::MULTIPLY)) {
|
||||||
@ -44,8 +43,3 @@ class type_parser_t : public parser_t {
|
|||||||
|
|
||||||
return h.submit(false);
|
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()); };
|
|
||||||
|
@ -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"); };
|
|
@ -1,4 +1,5 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
#include "compiler/treeifier/tokenizer.hh"
|
||||||
#include "compiler/treeifier/lexer.hh"
|
#include "compiler/treeifier/lexer.hh"
|
||||||
|
|
||||||
@ -7,12 +8,12 @@ using namespace messages;
|
|||||||
using namespace comp::tree;
|
using namespace comp::tree;
|
||||||
using namespace std::string_literals;
|
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 ? '\'' : '"';
|
char literal_char = is_char ? '\'' : '"';
|
||||||
|
|
||||||
bool escaping = false;
|
bool escaping = false;
|
||||||
|
|
||||||
std::vector<char> res;
|
std::vector<uint8_t> res;
|
||||||
location_t curr_char_loc = token.location;
|
location_t curr_char_loc = token.location;
|
||||||
curr_char_loc.length = 1;
|
curr_char_loc.length = 1;
|
||||||
curr_char_loc.start++;
|
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);
|
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);
|
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) {
|
switch (token.type) {
|
||||||
case lex::token_t::BIN_LITERAL:
|
case lex::token_t::BIN_LITERAL:
|
||||||
i += 2;
|
return parse_bin(msg_stack, 2, token.data);
|
||||||
radix = BINARY;
|
|
||||||
break;
|
|
||||||
case lex::token_t::OCT_LITERAL:
|
case lex::token_t::OCT_LITERAL:
|
||||||
i++;
|
return parse_oct(msg_stack, 1, token.data);
|
||||||
radix = OCTAL;
|
|
||||||
break;
|
|
||||||
case lex::token_t::DEC_LITERAL:
|
case lex::token_t::DEC_LITERAL:
|
||||||
radix = DECIMAL;
|
throw "no dec literals lol bozo."s;
|
||||||
break;
|
|
||||||
case lex::token_t::HEX_LITERAL:
|
case lex::token_t::HEX_LITERAL:
|
||||||
i += 2;
|
return parse_hex(msg_stack, 2, token.data);
|
||||||
radix = HEXADECIMAL;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw "WTF r u doing bro?"s;
|
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;
|
static std::vector<uint8_t> parse_float(msg_stack_t &msg_stack, const lex::token_t &token) {
|
||||||
res |= digit;
|
throw "no floats lol bozo"s;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
token_t token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) {
|
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::OCT_LITERAL:
|
||||||
case lex::token_t::DEC_LITERAL:
|
case lex::token_t::DEC_LITERAL:
|
||||||
case lex::token_t::HEX_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:
|
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:
|
case lex::token_t::STRING_LITERAL:
|
||||||
return { parse_string(msg_stack, false, in) };
|
return { parse_string(msg_stack, false, in), in.location };
|
||||||
case lex::token_t::CHAR_LITERAL: {
|
case lex::token_t::CHAR_LITERAL:
|
||||||
auto str = parse_string(msg_stack, true, in);
|
return { parse_string(msg_stack, true, in), in.location };
|
||||||
if (str.size() != 1) throw message_t(message_t::ERROR, "Char literal must consist of just one character.", in.location);
|
|
||||||
return str.front();
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw message_t(message_t::ERROR, "Token type not recognised.", in.location);
|
throw message_t(message_t::ERROR, "Token type not recognised.", in.location);
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
try {
|
try {
|
||||||
std::ifstream f { file, std::ios_base::in };
|
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 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;
|
std::cout << data::json::stringify(ast) << std::endl;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user